(*by Nasser M. Abbasi, version: 8/8/2012*) Manipulate[ gTick; Module[{g1, wasHit = False, r0 = 0.2(*bob radius, fixed*), L0 = R0/2.0(*relaxed length of the spring*)}, If[setIC, setIC = False; If[initialBobX > R0, initialBobX = R0]; simulationTime = 0; list@setIC[{initialBobX, initialBobSpeed, initialTheta, initialThetaDot, 2 m0 initialBobSpeed initialThetaDot}]; isRelaxedSpring = If[Abs[initialBobX - R0/2] <= $MachineEpsilon, True, False] ]; If[runningState == "RUNNING" || runningState == "STEP", wasHit = solver@step[m0, R0, L0, k, M0, delT, wallType]; (*this logic below so that we do not animate a hit on the edge \ unless last time it was no hit*) If[wasHit, If[wasHitLastTime == True, wasHit = False, wasHitLastTime = True ] , wasHitLastTime = False ]; simulationTime = Mod[simulationTime + delT, 1000]; If[runningState == "STEP", runningState = "STOP", gTick += del] ]; (*all done, display the animation on the screen*) g1 = display@ makeDisplay[simulationTime, plotType, m0, M0, R0, r0, wasHit, k, showPlots, showCounters, showCoriolisForce, trace]; FinishDynamic[]; g1 ], (*---------- control layout ------------*) Grid[{ {Grid[{{ Button[ Text[Style["run", 12]], {If[ Not[plotType == "velocity/acceleration"], runningState = "RUNNING"]; gTick += del}, ImageSize -> {55, 35}], Button[ Text[Style["stop", 12]], {If[ Not[plotType == "velocity/acceleration"], runningState = "STOP"]; gTick += del}, ImageSize -> {55, 35}] }, { Button[ Text[Style["step", 12]], {If[ Not[plotType == "velocity/acceleration"], runningState = "STEP"]; gTick += del}, ImageSize -> {55, 35}], Button[ Text[Style["reset", 12]],(*bring simulation back to initial conditions*) \ { setIC = True; runningState = "STOP"; gTick += del }, ImageSize -> {55, 35}] }}, Spacings -> {0.5, .2} ]}, {Text@Style["simulation parameters", 12]}, {Grid[ { {"simulation speed", Manipulator[Dynamic[delT, {delT = #} &], {0.01, 5, 0.01}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[delT, {3, 2}], 11] }, {"disk mass", Manipulator[Dynamic[M0, {M0 = #; setIC = True; gTick += del } &], {1, 500, 1}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[M0, 3], 11] }, {"disk radius", Manipulator[Dynamic[R0, {R0 = #; setIC = True; gTick += del } &], {1, 4, 0.1}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[R0, {2, 1}], 11] }, {"bob mass", Manipulator[Dynamic[m0, {m0 = #; setIC = True; gTick += del } &], {0, 99, 0.1}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[m0, {3, 1}], 11] }, {"spring stiffness", Manipulator[Dynamic[k, {k = #; setIC = True; gTick += del } &], {0.1, 9, .1}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[k, {2, 1}], 11] }, {Grid[{{"disk edge", RadioButtonBar[Dynamic[wallType, {wallType = #; setIC = True; gTick += del } &], {"elastic" -> "elastic", "inelastic" -> "inelastic"}] }}], SpanFromLeft } }, Spacings -> {.6, .5}, Alignment -> Left, Frame -> True, FrameStyle -> Directive[Thickness[.005], Gray] ] }, {Text@Style["initial conditions", 12]}, {Grid[{ {"angular velocity", Manipulator[Dynamic[initialThetaDot, {initialThetaDot = #; setIC = True; gTick += del } &], {-0.1, 0.1, .01}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt1[initialThetaDot, {2, 2}], 11] }, {"angle (degree)", Manipulator[Dynamic[initialTheta, {initialTheta = #; setIC = True; gTick += del } &], {0, 2 Pi, 2 Pi/100.}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[initialTheta*180.0/Pi, {4, 1}], 11] }, {"bob position", Manipulator[Dynamic[initialBobX, {initialBobX = #; setIC = True; gTick += del } &], {0, 4, 0.1}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt2[initialBobX, {2, 1}], 11] }, { Grid[{{ Row[{"relax", Spacer[2], Checkbox[Dynamic[isRelaxedSpring, {isRelaxedSpring = #; initialBobX = R0/2; setIC = True; gTick += del } &]]}], Row[{"trace", Spacer[2], Checkbox[Dynamic[trace, {trace = #; If[#, list@clearTrace[]]; gTick += del } &]]}], Row[{"show coriolis force", Spacer[2], Checkbox[Dynamic[showCoriolisForce, {showCoriolisForce = #; gTick += del } &]]}] }}, Spacings -> {0.4, 0}], SpanFromLeft }, {"bob speed", Manipulator[Dynamic[initialBobSpeed, {initialBobSpeed = #; setIC = True; gTick += del } &], {-0.1, 0.1, 0.01}, ImageSize -> Tiny, ContinuousAction -> False], Text@Style[Dynamic@padIt1[initialBobSpeed, {2, 2}], 11] } }, Spacings -> {.6, .3}, Alignment -> Left, Frame -> True, FrameStyle -> Directive[Thickness[.005], Gray] ] }, {Grid[{ {Text@Style["plot type", 12], Text@Style["test case", 12]}, { PopupMenu[Dynamic[plotType, {plotType = #; If[plotType == "velocity/acceleration", { If[runningState == "RUNNING", runningState = "SUSPEND_RUNNING" ] }, { If[runningState == "SUSPEND_RUNNING", runningState = "RUNNING"] } ]; gTick += del} &], { "disk angular velocity" -> Text@Style["disk angular velocity", 12], "disk angle" -> Text@Style["disk angle", 12], "bob position" -> Text@Style["bob position", 12], "bob velocity" -> Text@Style["bob velocity", 12], "Coriolis force" -> Text@Style["Coriolis force", 12] }, ImageSize -> All, ContinuousAction -> False, Enabled -> Dynamic[showPlots]] , PopupMenu[Dynamic[testCase, {testCase = #; runningState = "STOP"; Which[testCase == 1, ( isRelaxedSpring = False; delT = 1; m0 = 40; k = 1; R0 = 3.9; initialThetaDot = 0.09; initialTheta = 206 Degree; initialBobX = 0.5; initialBobSpeed = 0; M0 = 10; trace = True; setIC = True; runningState = "STOP"; plotType = "bob position" ), testCase == 2, ( isRelaxedSpring = False; delT = 5; m0 = 16; k = 3; R0 = 2; initialThetaDot = 0.01; initialTheta = 45 Degree; initialBobX = 1.4; initialBobSpeed = 0; M0 = 100; trace = True; setIC = True; runningState = "STOP"; plotType = "disk angular velocity" ), testCase == 3, ( isRelaxedSpring = True; delT = 5; m0 = 50; k = 0.5; M0 = 100; R0 = 3; trace = False; initialThetaDot = 0; initialTheta = 270 Degree; initialBobX = 1.5; initialBobSpeed = 0.1; setIC = True; runningState = "STOP"; plotType = "disk angular velocity" ) ]; gTick += del} &], { 1 -> Text@Style["1", 12], 2 -> Text@Style["2", 12], 3 -> Text@Style["3", 12] }, ImageSize -> All, ContinuousAction -> False] }, {Grid[{ { Row[{"show plot ", Spacer[4], Checkbox[ Dynamic[showPlots, {showPlots = #; gTick += del} &]]}], Spacer[12], Row[{"show counters ", Spacer[4], Checkbox[ Dynamic[ showCounters, {showCounters = #; gTick += del} &]]}], SpanFromLeft } } ], SpanFromLeft }, {Grid[{ {"plot x-scale", Manipulator[Dynamic[xScale, {xScale = #; list@setSize[xScale]; setIC = True; gTick += del } &], {10, 1000, 1}, ImageSize -> Tiny, ContinuousAction -> False, Enabled -> Dynamic[showPlots]], Text@Style[Dynamic@padIt2[xScale, 4], 11] } }], SpanFromLeft } }, Frame -> True, FrameStyle -> Directive[Thickness[.005], Gray] ] } }, Spacings -> {0, {2 -> 1, 4 -> 1, 6 -> 0.5, 8 -> 0}}, Alignment -> Center, Frame -> None], (*----control variables--*) {{m0, 40}, None}, {{M0, 10}, None}, {{R0, 3.9}, None}, {{delT, 1}, None}, {{k, 1}, None}, {{initialThetaDot, 0.09}, None}, {{initialTheta, 45 Degree}, None}, {{initialBobX, 1.5}, None}, {{initialBobSpeed, 0}, None}, {{isRelaxedSpring, False}, None}, {{plotType, "bob position"}, None}, {{testCase, 1}, None}, {{wallType, "elastic"}, None}, {{showPlots, False}, None}, {{showCounters, True}, None}, {{xScale, 400}, None}, {{showCoriolisForce, False}, None}, {{trace, True}, None}, {{setIC, False}, None}, (*----- refresh control ---*) {{gTick, 0}, ControlType -> None}, {{del, $MachineEpsilon}, None}, (*----- state variables for sim---*) {{runningState, "STOP"}, None},(*"RUNNING","STEP","SUSPEND","STOP"*) {{simulationTime, 0}, None}, {{wasHitLastTime, False}, None}, TrackedSymbols :> {gTick}, ControlPlacement -> Left, SynchronousUpdating -> False, SynchronousInitialization -> True, ContinuousAction -> False, Alignment -> Center, ImageMargins -> 0, FrameMargins -> 0, Paneled -> True, Frame -> False, Initialization :> { (*definitions used for parameter checking*) integerStrictPositive = (IntegerQ[#] && # > 0 &); integerPositive = (IntegerQ[#] && # >= 0 &); numericStrictPositive = (Element[#, Reals] && # > 0 &); numericPositive = (Element[#, Reals] && # >= 0 &); numericStrictNegative = (Element[#, Reals] && # < 0 &); numericNegative = (Element[#, Reals] && # <= 0 &); bool = (Element[#, Booleans] &); numeric = (Element[#, Reals] &); integer = (Element[#, Integers] &); (* This list object is used to store and the manage the time \ series generated during running of the simulation so that display \ object can use it to make plots and the animation *) listClass[$size_?integer(*maximum size of the list*)] := Module[{size, lists, self}, (*lists are in this order x,v,\[Theta],\[Omega],force, trace*) self@getSize[] := size; self@setSize[n_] := ( size = n; lists = Table[{0, Table[0, {n}]}, {6}] ); self@ add[{x_?numeric,(*bob position*) v_?numeric,(*bob speed*) \[Theta]_? numeric,(*disk angle*) \[Omega]_? numeric,(*disk angular speed*) force_?numeric(* coriolis force*)} ] := Module[{}, MapThread[Function[{e, idx}, lists[[idx, 1]]++; If[lists[[idx, 1]] > size, lists[[idx, 1]] = 1]; lists[[ idx, 2, lists[[idx, 1]] ]] = e ], {{x, v, \[Theta], \[Omega], force, {x*Cos[\[Theta]], x*Sin[\[Theta]]}}, Range[1, Length[lists]]} ] ]; self@ setIC[{x_?numeric, v_?numeric, \[Theta]_?numeric, \[Omega]_?numeric, force_?numeric}] := ( list@clear[]; list@add[{x, v, \[Theta], \[Omega], force}] ); self@getCurrent[] := lists[[ #, 2, lists[[#, 1]] ]] & /@ Range[1, Length[lists]]; self@clear[] := (lists[[#, 1]] = 0) & /@ Range[1, Length[lists]]; self@clearTrace[] := lists[[6, 1]] = 0; self@getPositionList[] := Module[{len = lists[[1, 1]]}, lists[[ 1, 2, 1 ;; len]] ] ; self@getSpeedList[] := Module[{len = lists[[2, 1]]}, lists[[ 2, 2, 1 ;; len]] ] ; self@getThetaList[] := Module[{len = lists[[3, 1]]}, lists[[ 3, 2, 1 ;; len]] ] ; self@getOmegaList[] := Module[{len = lists[[4, 1]]}, lists[[ 4, 2, 1 ;; len]] ] ; self@getCoriolisForceList[] := Module[{len = lists[[5, 1]]}, lists[[ 5, 2, 1 ;; len]] ] ; self@getTraceData[] := Module[{len = lists[[6, 1]]}, lists[[ 6, 2, 1 ;; len]] ] ; (*--- constructor---*) self@setSize[$size]; self ]; (*-----------------------------------------------------------*) solverClass[] := Module[{self}, (* uses NDSolve to integrate equations of motion for given time \ step*) self@step[m0_?numericPositive,(*bob mass*) R0_?numericStrictPositive,(*disk radius*) L0_?numericStrictPositive,(*relaxed spring length, measured from the origin*) k_?numericStrictPositive,(*spring k*) M0_?numericStrictPositive,(*disk mass*) delT_?numericStrictPositive,(*time length to integrate over \ for NDSolve*) wallType_String(* wall type is either elastic or inelastic*) ] := Module[{ic, eq1, eq2, t, x, \[Theta], maxDistance = R0, minDistance = 0, currentSolution, currentX, currentV, current\[Theta], currentOmega, wasHit = False, $currentX, $currentV, $current\[Theta], \ $currentOmega, $force, trace}, {$currentX, $currentV, $current\[Theta], $currentOmega, $force, trace} = list@getCurrent[]; currentX = $currentX; currentV = $currentV; If[ Abs[m0] <= $MachineEpsilon, currentSolution = First@NDSolve[{\[Theta]''[t] == 0, \[Theta][0] == Mod[$current\[Theta], 2 Pi], \[Theta]'[ 0] == $currentOmega}, {\[Theta], \[Theta]'}, {t, 0, delT}, MaxSteps -> Infinity]; current\[Theta] = (\[Theta] /. currentSolution)[delT]; currentOmega = (\[Theta]' /. currentSolution)[delT] , eq1 = (x^\[Prime]\[Prime])[t] == (-k (x[t] - L0))/m0 + x[t] \[Theta]'[t]^2; eq2 = \[Theta]''[t] == (-4 m0 x[t] x'[t] \[Theta]'[t])/( M0 R0^2 + 2 m0 x[t]^2); ic = {x[0] == $currentX, x'[0] == $currentV, \[Theta][0] == Mod[$current\[Theta], 2 Pi], \[Theta]'[0] == $currentOmega}; currentSolution = First@Quiet@ NDSolve[ Flatten@{eq1, eq2, ic}, {x, x', \[Theta], \[Theta]'}, {t, 0, delT}, MaxSteps -> Infinity]; currentX = (x /. currentSolution)[delT]; currentV = (x' /. currentSolution)[delT]; current\[Theta] = (\[Theta] /. currentSolution)[delT]; currentOmega = (\[Theta]' /. currentSolution)[delT]; (* if bob hits the edge of the disk or the base of the spring, fix speed and reset things*) If[currentX > maxDistance || currentX < minDistance, currentV = 0; If[wallType == "elastic", If[currentX > maxDistance, wasHit = True]; currentV = -$currentV ]; currentX = $currentX; current\[Theta] = $current\[Theta]; currentOmega = $currentOmega ] ]; (*save current solution in the list object so that display can \ use it*) list@add[{currentX, currentV, current\[Theta], currentOmega, 2 m0 currentOmega currentV}]; wasHit ]; self ]; (*--------- displayClass ---------------------------------------*) displayClass[] := Module[{makeCounters, makeDiskDiagram, makePlot, self}, (*--------- private ---------------------------------------*) makeCounters[simulationTime_?numericPositive, m0_?numericPositive, M0_?numericStrictPositive, R0_?numericStrictPositive, k_?numericStrictPositive] := Module[{h1, h2, currentMomentOfInertia, x, v, \[Theta], \[Omega], currentCoriolisForce, PE, KE, trace}, {x, v, \[Theta], \[Omega], currentCoriolisForce, trace} = list@getCurrent[]; currentMomentOfInertia = M0/2*R0^2 + m0*x^2; PE = 0.5*k*(x - R0/2)^2; KE = 1/4 M0 R0^2 \[Omega]^2 + 1/2 m0 (v^2 + x^2 \[Omega]^2); h1 = Text@Style[Grid[{ {Text["disk \[Theta]"], Text["disk \[Omega]"], Text["bob position"], Text["bob velocity"], Text[Style["\[CapitalIota]", Italic]], Text["energy"] }, {Text["(degree)"], Text["(rad/sec)"], Text["(meter)"], Text["(meter/sec)"], Text["(kg \!\(\*SuperscriptBox[\(meter\), \(2\)]\))"], Text[Row[{"(", Style["J", Italic], ")"}]] }, { padIt2[180./Pi*\[Theta], {5, 2}], padIt2[\[Omega], {7, 6}], padIt2[x, {3, 2}], padIt1[v, {6, 3}], padIt2[currentMomentOfInertia, {5, 2}], padIt2[PE + KE, {4, 3}] } }, Frame -> {All, None, { {{1, 2}, {1, 6}} -> True , {{3, 3}, {1, 6}} -> True}}, FrameStyle -> Gray, Spacings -> 1, ItemSize -> {{All, 2 ;; -1} -> 5}, Alignment -> Center], 12]; h2 = Text@Style[Grid[{ {Text["time (sec)"], Text["\[CapitalIota]\[InvisibleSpace] \[InvisibleSpace]\ \[Omega] (joule second)"], Text@Row[{"Coriolis force (", Style["N", Italic], ")"}], Text@Row[{"P.E. (", Style["J", Italic], ")"}], Text@Row[{"K.E. (", Style["J", Italic], ")"}] }, { padIt2[simulationTime, {5, 2}], padIt2[currentMomentOfInertia*\[Omega], {6, 4}], padIt1[currentCoriolisForce, {5, 4}], padIt2[PE, {5, 4}], padIt2[KE, {5, 4}] }}, Frame -> All, FrameStyle -> Gray, Spacings -> 1, ItemSize -> {{All, 2 ;; -1} -> 6}, Alignment -> Center], 12]; Grid[{{h1}, {h2}}, Spacings -> {0, .1}] ]; (*---------------private----------------------------------*) makeDiskDiagram[m0_?numericPositive, R0_?numericStrictPositive, r_?numericStrictPositive, wasHit_?bool, {w_?numericStrictPositive, h_?numericStrictPositive}, showCoriolisForce_?bool, trace_?bool] := Module[{x, y, splash, xx, v, \[Theta], \[Omega], force, traceData, currentTrace}, {xx, v, \[Theta], \[Omega], force, currentTrace} = list@getCurrent[]; force = force/(4*1.25) + 0.25*Sign[force]; x = xx*Cos[\[Theta]]; y = xx*Sin[\[Theta]]; traceData = list@getTraceData[]; splash = If[wasHit, { { Dotted, Red, Rotate[Line[{{R0, 0}, {1.2 R0, 0}}], \[Theta], {0, 0}]}, {Dotted, Red, Rotate[Line[{{R0, 0}, {1.2 R0, .2 R0}}], \[Theta], {0, 0}]}, {Dotted, Red, Rotate[Line[{{R0, 0}, {1.2 R0, .1 R0}}], \[Theta], {0, 0}]}, {Dotted, Red, Rotate[Line[{{R0, 0}, {1.2 R0, -.2 R0}}], \[Theta], {0, 0}]}, {Dotted, Red, Rotate[Line[{{R0, 0}, {1.2 R0, -.1 R0}}], \[Theta], {0, 0}]} }, Sequence @@ {} ]; Graphics[{ {EdgeForm[{Thick, Blue}], FaceForm@RGBColor[.75, .97, .97], Disk[{0, 0}, R0 ]}, If[showCoriolisForce && Abs[force] > $MachineEpsilon, {Dotted, Black, Rotate[Arrow[{{xx, Sign[force]* r}, {xx, (force + Sign[force]*r)}}], \[Theta], {0, 0}]}, Sequence @@ {} ], If[trace, {Dotted, Darker@Red, Line[traceData]}, Sequence @@ {}], If[m0 <= $MachineEpsilon, Sequence @@ {}, { Red, Disk[{x, y}, r]}], {Black, Line@makeSpring[0, 0, (xx - r) Cos[\[Theta]], (xx - r) Sin[\[Theta]], 0.8*r]}, (*relaxed position indicator*) {Dashed, Gray, Rotate[Line[{{R0/2, -r}, {R0/2, -2 r}}], \[Theta], {0, 0}]}, {Dashed, Gray, Rotate[Line[{{R0/2, r}, {R0/2, 2 r}}], \[Theta], {0, 0}]}, (* inertial frames*) {Gray, Dashed, Rotate[Line[{{-R0, 0}, {0, 0}}], \[Theta], {0, 0}]}, {Gray, Dashed, Rotate[Line[{{0, -R0}, {0, R0}}], \[Theta], {0, 0}]}, splash }, ImageSize -> {w, h}, ImagePadding -> {{10, 10}, {10, 10}}, PlotRange -> {{-R0 - r, R0 + r}, {-R0 - r, R0 + r}}, ImageMargins -> 1, AspectRatio -> 1 ] ]; (*-------------------- private -----------------------------*) makePlot[plotType_String, R0_?numericStrictPositive] := Module[{plotTitle, data, n = list@getSize[]}, Which[plotType == "disk angular velocity", data = list@getOmegaList[]; If[Length[data] == 0, data = {0}]; plotTitle = {{Text@Style["\[Omega] (rad/sec)", 12], None}, {Text@Style["time"], Text@Style["disk angular velocity vs. time", 12]}}; plotRange = {{1, n}, All} , plotType == "disk angle", data = 180.0/Pi*list@getThetaList[]; If[Length[data] == 0, data = {0}]; plotTitle = {{Text@Style["\[Theta] (deg)", 12], None}, {Text@Style["time"], Text@Style["disk angle vs. time", 12]}}; plotRange = {{1, n}, {0, 360}} , plotType == "bob position", data = list@getPositionList[]; If[Length[data] == 0, data = {0}]; plotTitle = {{Text@ Style[Row[{"position (", Style["m", Italic], ")"}], 12], None}, {Text@Style["time"], Text@Style["bob position vs. time", 12]}}; plotRange = {{1, n}, {0, R0}} , plotType == "bob velocity", data = list@getSpeedList[]; If[Length[data] == 0, data = {0}]; plotTitle = {{Text@ Style[Row[{"velocity (", Style["m/s", Italic], ")"}], 12], None}, {Text@Style["time"], Text@Style["bob velocity vs. time", 12]}}; plotRange = {{1, n}, All} , plotType == "Coriolis force", data = list@getCoriolisForceList[]; If[Length[data] == 0, data = {0}]; plotTitle = {{Text@ Style[Row[{"Coriolis force (", Style["N", Italic], ")"}], 12], None}, {Text@Style["time"], Text@Style["Coriolis force vs. time", 12]}}; plotRange = {{1, n}, All} ]; ListPlot[ data, PlotRange -> plotRange, AxesOrigin -> {0, 0}, Joined -> True, Frame -> True, GridLines -> Automatic, ImageSize -> {330, 160}, ImagePadding -> {{60, 10}, {30, 25}}, ImageMargins -> {{2, 1}, {1, 1}}, Axes -> False, FrameLabel -> plotTitle, PlotStyle -> Red, AspectRatio -> 0.27] ]; (*------- public ----------------------------------*) self@makeDisplay[simulationTime_?numericPositive, plotType_String, m0_?numericPositive, M0_?numericStrictPositive, R0_?numericStrictPositive, r0_?numericStrictPositive, wasHit_?bool, k_?numericStrictPositive, showPlots_?bool, showCounters_?bool, showCoriolisForce_?bool, trace_?bool] := If[showPlots, If[showCounters, Grid[{ {makeCounters[simulationTime, m0, M0, R0, k]}, {makePlot[plotType, R0]}, {makeDiskDiagram[m0, R0, r0, wasHit, {1.4 ContentSizeW, 0.515 ContentSizeH}, showCoriolisForce, trace]} }, Spacings -> 0] , Grid[{ {makePlot[plotType, R0]}, {makeDiskDiagram[m0, R0, r0, wasHit, {1.4 ContentSizeW, 0.787 ContentSizeH}, showCoriolisForce, trace]} }, Spacings -> 0] ], If[showCounters, Grid[{ {makeCounters[simulationTime, m0, M0, R0, k]}, {makeDiskDiagram[m0, R0, r0, wasHit, {1.4 ContentSizeW, 0.93 ContentSizeH}, showCoriolisForce, trace]} }, Spacings -> 0] , Grid[{ {makeDiskDiagram[m0, R0, r0, wasHit, {1.4 ContentSizeW, 1.2 ContentSizeH}, showCoriolisForce, trace]} }, Spacings -> 0] ] ]; self ]; (*--------------------------------------------*) (* helper function for formatting *) (*--------------------------------------------*) padIt1[v_?numeric, f_List] := AccountingForm[Chop[v] , f, NumberSigns -> {"-", "+"}, NumberPadding -> {"0", "0"}, SignPadding -> True]; (*--------------------------------------------*) (* helper function for formatting *) (*--------------------------------------------*) padIt2[v_?numeric, f_List] := AccountingForm[Chop[v] , f, NumberSigns -> {"", ""}, NumberPadding -> {"0", "0"}, SignPadding -> True]; padIt2[v_?numeric, f_Integer] := AccountingForm[Chop[v] , f, NumberSigns -> {"", ""}, NumberPadding -> {"0", "0"}, SignPadding -> True]; (*This function is called to make spring, based on code by Arpad Kosa from WRI demo*)(*at Wolfram web site \ modified by me.This returns a Line which is the spring*) (*szel, larger number means bigger spring width*) makeSpring[xFirst_?numeric, yFirst_?numeric, xEnd_?numeric, yEnd_?numeric, szel_?numeric] := Module[{hx, veghossz, hossz, hy, dh, tbl}, hx = xEnd - xFirst; If[Abs[hx] <= $MachineEpsilon, hx = 10^-6]; hy = yEnd - yFirst; If[Abs[hy] <= $MachineEpsilon, hy = 10^-6]; veghossz = 0.03; hossz = Sqrt[hx^2 + hy^2]; dh = (hossz - 2*veghossz)/20; tbl = Table[If[ OddQ[i], {xFirst + hx*(i*dh + veghossz)/hossz + hy*szel/hossz, yFirst + hy*(i*dh + veghossz)/hossz - hx*szel/hossz}, {xFirst + hx*(i*dh + veghossz)/hossz - hy*szel/hossz, yFirst + hy*(i*dh + veghossz)/hossz + hx*szel/hossz}], {i, 2, 18}]; {{xFirst, yFirst}}~ Join~{{xFirst + hx*(dh + veghossz)/hossz, yFirst + hy*(dh + veghossz)/hossz}}~Join~tbl~ Join~{{xFirst + hx*(19*dh + veghossz)/hossz, yFirst + hy*(19*dh + veghossz)/hossz}}~Join~{{xEnd, yEnd}} ]; (*--- constant parameters size and width of display ---*) ContentSizeW = 260; ContentSizeH = 405; (* objects used by the simulation. These must be here in the initialization section *) list = listClass[400]; list@add[{1.5, 0.0, Pi/4, 0.09, 0.0}]; solver = solverClass[]; display = displayClass[]; } ]