(* by Nasser M. Abbasi, version: Nov 10, 2012 *)

Manipulate[
 gTick;
 Text@Module[{g1, wasHit = False},
   If[setIC,
    setIC = False;
    list@setIC[{initialBobX, initialBobSpeed, initialTheta, 
       initialThetaDot, r0, L0}];
    isRelaxedSpring = 
     If[Abs[initialBobX] <= $MachineEpsilon, True, False]
    ];
   
   If[runningState == "RUNNING" || runningState == "STEP",
    wasHit = solver@step[m0, L0, k, M0, delT, w, r0];
    If[wasHit,(*animate a hit on the edge unless last time it was no \
hit*)
     If[wasHitLastTime == True,
      wasHit = False,
      wasHitLastTime = True
      ],
     wasHitLastTime = False
     ];
    
    If[runningState == "STEP", runningState = "STOP", gTick += del]
    ];
   
   g1 = display@
     makeDisplay[plotType, m0, M0, L0, r0, wasHit, k, showPlots, 
      showCounters, trace, w];
   FinishDynamic[];
   g1
   ],
 (*---------- control layout ------------*)
 Text@Grid[{
    {Grid[{{
        Button[
         Style["run", 
          12], {If[Not[plotType == "velocity/acceleration"], 
           runningState = "RUNNING"]; gTick += del}, 
         ImageSize -> {55, 35}],
        Button[
         Style["stop", 
          12], {If[Not[plotType == "velocity/acceleration"], 
           runningState = "STOP"]; gTick += del}, 
         ImageSize -> {55, 35}]
        },
       {
        Button[
         Style["step", 
          12], {If[Not[plotType == "velocity/acceleration"], 
           runningState = "STEP"]; gTick += del}, 
         ImageSize -> {55, 35}],
        
        Button[
         Style["reset", 
          12],(*bring simulation back to initial conditions*)
         {
          setIC = True;
          runningState = "STOP";
          gTick += del
          }, ImageSize -> {55, 35}]
        }}, Spacings -> {0.5, .2}
      ]},
    
    {Style["simulation parameters", 12]},
    {Grid[
      {
       {"simulation speed",
        Manipulator[Dynamic[delT, {delT = #} &], {0.001, 0.05, 0.001},
          ImageSize -> Tiny, ContinuousAction -> False],
        Style[Dynamic@padIt2[delT, {3, 3}], 11]
        },
       {"pendulum mass",
        Manipulator[Dynamic[m0,
          {m0 = Chop@#;
            setIC = True;
            gTick += del
            } &], {1, 100, 1}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[m0, 3], 11]
        },
       {"pendulum length",
        Manipulator[Dynamic[L0,
          {L0 = Chop@#;
            setIC = True;
            gTick += del
            } &], {0.1, 2, 0.1}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[L0, {2, 1}], 11]
        },
       {"tube length",
        Manipulator[Dynamic[w,
          {(w = #) &,
           (
             w = Chop@#;
             If[initialBobX > (w/2 - r0),
                initialBobX = w/2 - r0
              ,
              If[initialBobX < (-w/2 + r0),
               initialBobX = -w/2 + r0
               ]
              ];
             setIC = True;
             gTick += del
             ) &
           }], {0.1, 1, 0.1}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[w, {1, 1}], 11]
        },
       
       {"bob mass",
        Manipulator[Dynamic[M0,
          {M0 = Chop@#;
            setIC = True;
            gTick += del
            } &], {1, 100, 1}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[M0, 3], 11]
        },
       
       {"spring stiffness",
        Manipulator[Dynamic[k,
          {k = Chop@#;
            setIC = True;
            gTick += del
            } &], {0, 500, .1}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[k, {4, 1}], 11]
        }
       }, Spacings -> {.6, .5}, Alignment -> Left, Frame -> True, 
      FrameStyle -> Directive[Thickness[.005], Gray]
      ]
     },
    {Style["initial conditions", 12]},
    {Grid[{
       {"angular velocity",
        Manipulator[Dynamic[initialThetaDot,
          {initialThetaDot = Chop@#;
            setIC = True;
            gTick += del
            } &], {-0.1, 0.1, .01}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt1[initialThetaDot, {2, 2}], 11]
        },
       {"angle (degree)",
        Manipulator[Dynamic[initialTheta,
          {initialTheta = Chop@#;
            setIC = True;
            gTick += del
            } &], {0, 2 Pi, 2 Pi/100.}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt2[initialTheta*180.0/Pi, {4, 1}], 11]
        },
       {"bob position",
        Manipulator[Dynamic[initialBobX,
          {(initialBobX = #) &,
           (
             initialBobX = Chop[#];
             If[initialBobX > (w/2 - r0),
                initialBobX = w/2 - r0
              ,
              If[initialBobX < (-w/2 + r0),
               initialBobX = -w/2 + r0
               ]
              ];
             setIC = True;
             gTick += del
             ) &
           }], {-0.47, 0.47, 0.01}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt1[initialBobX, {2, 2}], 11]
        },
       {
        Grid[{{
           Row[{"relax", Spacer[2],
             Checkbox[Dynamic[isRelaxedSpring,
               {isRelaxedSpring = #;
                 initialBobX = 0; 
                 setIC = True;
                 gTick += del
                 } &]]}],
           Row[{"trace", Spacer[2],
             Checkbox[Dynamic[trace,
               {trace = #;
                 If[#, list@clearTrace[]];
                 gTick += del
                 } &]]}]
           }}, Spacings -> {0.4, 0}], SpanFromLeft
        },
       {"bob speed",
        Manipulator[Dynamic[initialBobSpeed,
          {initialBobSpeed = Chop@#;
            setIC = True;
            gTick += del
            } &], {-0.1, 0.1, 0.01}, ImageSize -> Tiny, 
         ContinuousAction -> False],
        Style[Dynamic@padIt1[initialBobSpeed, {2, 2}], 11]
        }
       }, Spacings -> {.6, .3}, Alignment -> Left, Frame -> True, 
      FrameStyle -> Directive[Thickness[.005], Gray]
      ]
     },
    {Grid[{
       {Style["plot type", 12], 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" -> 
           Style["disk angular velocity", 12],
           "disk angle" -> Style["disk angle", 12],
           "bob position" -> Style["bob position", 12],
           "bob velocity" -> Style["bob velocity", 12]
          }, ImageSize -> All, ContinuousAction -> False, 
         Enabled -> Dynamic[showPlots]]
        ,
        PopupMenu[Dynamic[testCase, {testCase = #;
            runningState = "STOP";
            Which[testCase == 1,
             (
              isRelaxedSpring = False; delT = 0.01; m0 = 40; k = 1; 
              w = .7;
              initialThetaDot = 0.01; initialTheta = 45 Degree; 
              initialBobX = 0.3; initialBobSpeed = 0; M0 = 10; 
              trace = False;
              setIC = True;
              runningState = "STOP";
              plotType = "bob position"
              ),
             testCase == 2,
             (
              isRelaxedSpring = False; delT = 0.02; m0 = 16; k = 500; 
              w = 1;
              initialThetaDot = 0.01; initialTheta = 45 Degree; 
              initialBobX = -.2; initialBobSpeed = 0; M0 = 30; 
              trace = True;
              setIC = True;
              runningState = "STOP";
              plotType = "disk angular velocity"
              ),
             testCase == 3,
             (
              isRelaxedSpring = True; delT = 0.03; m0 = 50; k = 0.5; 
              M0 = 100; trace = False; w = .3;
              initialThetaDot = 0; initialTheta = 270 Degree; 
              initialBobX = .10; initialBobSpeed = 0.1;
              setIC = True;
              runningState = "STOP";
              plotType = "disk angular velocity"
              )
             ];
            gTick += del} &],
         { 
          1 -> Style["1", 12], 2 -> Style["2", 12], 3 -> 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 window size",
           Manipulator[Dynamic[xScale,
             {xScale = #;
               list@setSize[xScale];
               
               list@add[{0, initialBobX, initialBobSpeed, 
                  initialTheta, initialThetaDot}];
               setIC = True;
               gTick += del
               } &], {10, 1000, 1}, ImageSize -> Tiny, 
            ContinuousAction -> False, Enabled -> Dynamic[showPlots]],
           Style[Dynamic@padIt2[xScale, 4], 11]
           }
          }], SpanFromLeft
        }
       }, Frame -> True, FrameStyle -> Directive[Thickness[.005], Gray]
      ]
     }
    }, Spacings -> {0, {2 -> 0.7, 4 -> 0.7, 6 -> 0.5, 8 -> 0}}, 
   Alignment -> Center, Frame -> None],
 (*----control variables--*)
 {{m0, 25}, None},
 {{M0, 40}, None},
 {{L0, 0.5}, None},
 {{delT, 0.01}, None},
 {{k, 1}, None},
 {{w, .5}, None},
 
 {{initialThetaDot, 0.09}, None},
 {{initialTheta, 45 Degree}, None},
 {{initialBobX, 0.05}, None},
 {{initialBobSpeed, 0}, None},
 {{isRelaxedSpring, False}, None},
 {{plotType, "bob position"}, None},
 {{testCase, 1}, None},
 {{showPlots, False}, None},
 {{showCounters, True}, None},
 {{xScale, 400}, None},
 {{trace, False}, None},
 {{setIC, False}, None},
 
 (*----- refresh control ---*)
 {{gTick, 0}, ControlType -> None},
 {{del, $MachineEpsilon}, None},
 
 (*----- state variables for sim---*)
 {{runningState, "STOP"}, 
  None},(*"RUNNING","STEP","SUSPEND","STOP"*)
 {{wasHitLastTime, False}, None},
 {{r0, .03}, 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*),
     $r0_?numericStrictPositive,
     $L0_?numericStrictPositive] :=
    Module[{size, lists, r0, L0, self},
     (*lists has the structure {idx,{  {t,x,
     v,\[Theta],\[Omega],{xTrace,yTrace}}},...   ,....}*)
     
     self@getSize[] := size;
     self@setSize[n_] := ( size = n  ; 
       lists = {0, Table[Table[0, {6}], {n}]  });
     self@add[{time_?numericPositive,(* current time*)
         x_?numeric,(*bob position*)
         v_?numeric,(*bob speed*)
         \[Theta]_?numeric,(*disk angle*)
         \[Omega]_?numeric(*disk angular speed*)
         }
        ] := Module[{},
       lists[[1]]++;
       If[lists[[1]] > size, lists[[1]] = 1];
       lists[[ 2, lists[[1]], 1  ]] = time;
       lists[[ 2, lists[[1]], 2  ]] = x;
       lists[[ 2, lists[[1]], 3 ]] = v;
       lists[[ 2, lists[[1]], 4  ]] = \[Theta];
       lists[[ 2, lists[[1]], 5  ]] = \[Omega];
       lists[[ 2, lists[[1]], 
         6  ]] = {(L0 + r0) Sin[\[Theta]] + 
          x Cos[\[Theta]], -(L0 + r0) Cos[\[Theta]] + x Sin[\[Theta]]}
       ];
     
     self@
       setIC[{x_?numeric, 
         v_?numeric, \[Theta]_?numeric, \[Omega]_?numeric, 
         rr0_?numericStrictPositive, LL0_?numericStrictPositive}] := (
       list@clear[];
       r0 = rr0;
       L0 = LL0;
       list@add[{0, x, v, \[Theta], \[Omega]}]
       );
     
     self@getCurrent[] := lists[[   2, lists[[1]]  ]];
     self@clear[] := lists[[1]] = 0;
     self@getPositionList[] := 
      Module[{len = lists[[1]]}, lists[[ 2, 1 ;; len, {1, 2}]]  ] ;
     self@getSpeedList[] := 
      Module[{len = lists[[1]]}, lists[[ 2, 1 ;; len, {1, 3}]]  ] ;
     self@getThetaList[] := 
      Module[{len = lists[[1]]}, lists[[ 2, 1 ;; len, {1, 4}]]  ] ;
     self@getOmegaList[] := 
      Module[{len = lists[[1]]}, lists[[ 2, 1 ;; len, {1, 5}]]  ] ;
     self@getTraceData[] := 
      Module[{len = lists[[1]]}, lists[[ 2, 1 ;; len, 6]]  ] ;
     
     (*--- constructor---*)
     self@setSize[$size];
     r0 = $r0;
     L0 = $L0;
     self
     ];
   (*-----------------------------------------------------------*)
   solverClass[] :=
    Module[{solve, self},
     (*----------------------------------------------*)
     solve[M0_?numericStrictPositive,
       m0_?numericPositive,
       L0_?numericStrictPositive,
       eq1_,
       eq2_,
       t_,
       x_,
       \[Theta]_,
       w_?numericStrictPositive,
       delT_?
        numericStrictPositive(*time length to integrate over for \
NDSolve*),
       r0_?numericStrictPositive] := 
      Module[{wasHit = False, currentSolution, currentX, currentV, 
        current\[Theta], currentOmega, sol, 
        ic, $x, $v, $\[Theta], $\[Omega], simTime, trace, newV, 
        newOmega, eqq1, eqq2},
       
       {simTime, $x, $v, $\[Theta], $\[Omega], trace} = 
        list@getCurrent[];
       
       ic = {x[0] == $x, 
         x'[0] == $v, \[Theta][0] == 
          Mod[$\[Theta], 2 Pi], \[Theta]'[0] == $\[Omega]};
       currentSolution = 
        Quiet@NDSolve[
          Flatten@{eq1, eq2, ic}, {x, x', \[Theta], \[Theta]'}, {t, 0,
            delT}, Method -> {"BDF"}, MaxSteps -> Infinity];
       
       currentSolution = First@currentSolution;
       currentX = x[delT] /. currentSolution;
       currentV = x'[delT] /. currentSolution;
       current\[Theta] = \[Theta][delT] /. currentSolution;
       currentOmega = \[Theta]'[delT] /. currentSolution;
       
       (* if bob hits the edge of the disk or the base of the spring, 
       fix speed and reset things. Assume perfect elastic edge. 
       Solve such that the total moment of momuntum of the system \
before and after collision remain the same*)
       If[currentX > (w/2 - r0) || currentX < (-w/2 + r0),
        wasHit = True;
        eqq1 = newV == -currentV;
        eqq2 = (m0 L0^2/3) currentOmega + M0 (currentV) L0 + 
           M0 (L0^2 currentOmega) + 
           M0 currentX^2 currentOmega == (m0 L0^2/3) newOmega + 
           M0 (newV) L0 + M0 (L0^2 newOmega) + M0 currentX^2 newOmega;
        sol = {newV, newOmega} /. 
          NSolve[{eqq1, eqq2}, {newV, newOmega}];
        
        If[Length[sol] > 1,
         If[currentV > 0,
          sol = Select[sol, First[#] <= 0 &],
          sol = Select[sol, First[#] > 0 &]
          ]
         ];
        
        sol = First[sol];
        currentV = sol[[1]];
        currentOmega = sol[[2]]
        ];
       
       list@
        add[{simTime + delT, currentX, currentV, current\[Theta], 
          currentOmega}];
       wasHit
       ];
     (*----------------------------------------------*)
     self@step[
        m0_?numericPositive,(*pendulum mass*)
        L0_?numericStrictPositive,(*pendulum length*)
        k_?numericPositive,(*spring k*)
        M0_?numericStrictPositive,(*bob mass*)
        delT_?
         numericStrictPositive,(*time length to integrate over for \
NDSolve*)
        w_?numericPositive,
        r0_?numericStrictPositive
        ] := 
      Module[{eq1, eq2, t, x, \[Theta], current\[Theta], 
        wasHit = False, $x, $v, $\[Theta], $\[Omega], simTime, trace, 
        g = 9.81, solidPendulum, springAttached},
       {simTime, $x, $v, $\[Theta], $\[Omega], trace} = 
        list@getCurrent[];
       
       solidPendulum = Abs[m0] > $MachineEpsilon;
       springAttached = Abs[k] > $MachineEpsilon;
       
       If[solidPendulum,
        If[springAttached,
         eq1 = 
          g M0 Sin[\[Theta][t]] + k x[t] - 
            M0 x[t] Derivative[1][\[Theta]][t]^2 + 
            M0 ((x^\[Prime]\[Prime])[t] + 
               L0 (\[Theta]^\[Prime]\[Prime])[t]) == 0;
         eq2 = 
          1/2 g L0 m0 Sin[\[Theta][t]] - 
            g M0 (-L0 Sin[\[Theta][t]] - Cos[\[Theta][t]] x[t]) + 
            1/3 L0^2 m0 (\[Theta]^\[Prime]\[Prime])[t] + 
            1/2 M0 (4 x[t] Derivative[1][x][t] Derivative[
                 1][\[Theta]][t] + 
               2 x[t]^2 (\[Theta]^\[Prime]\[Prime])[t] + 
               2 L0 ((x^\[Prime]\[Prime])[t] + 
                  L0 (\[Theta]^\[Prime]\[Prime])[t])) == 0;
         wasHit = 
          solve[M0, m0, L0, eq1, eq2, t, x, \[Theta], w, delT, r0]
         ,
         eq1 = 
          g M0 Sin[\[Theta][t]] - 
            M0 x[t] Derivative[1][\[Theta]][t]^2 + 
            M0 ((x^\[Prime]\[Prime])[t] + 
               L0 (\[Theta]^\[Prime]\[Prime])[t]) == 0;
         eq2 = 
          1/2 g L0 m0 Sin[\[Theta][t]] - 
            g M0 (-L0 Sin[\[Theta][t]] - Cos[\[Theta][t]] x[t]) + 
            1/3 L0^2 m0 (\[Theta]^\[Prime]\[Prime])[t] + 
            1/2 M0 (4 x[t] Derivative[1][x][t] Derivative[
                 1][\[Theta]][t] + 
               2 x[t]^2 (\[Theta]^\[Prime]\[Prime])[t] + 
               2 L0 ((x^\[Prime]\[Prime])[t] + 
                  L0 (\[Theta]^\[Prime]\[Prime])[t])) == 0;
         wasHit = 
          solve[M0, m0, L0, eq1, eq2, t, x, \[Theta], w, delT, r0]
         ]
        ,
        If[springAttached,
         eq1 = 
          g M0 Sin[\[Theta][t]] + k x[t] - 
            M0 x[t] Derivative[1][\[Theta]][t]^2 + 
            M0 ((x^\[Prime]\[Prime])[t] + 
               L0 (\[Theta]^\[Prime]\[Prime])[t]) == 0;
         eq2 = -g M0 (-L0 Sin[\[Theta][t]] - Cos[\[Theta][t]] x[t]) + 
            1/2 M0 (4 x[t] Derivative[1][x][t] Derivative[
                 1][\[Theta]][t] + 
               2 x[t]^2 (\[Theta]^\[Prime]\[Prime])[t] + 
               2 L0 ((x^\[Prime]\[Prime])[t] + 
                  L0 (\[Theta]^\[Prime]\[Prime])[t])) == 0;
         wasHit = solve[M0, m0, L0, eq1, eq2, t, x, \[Theta], w, delT, r0]
         ,
         eq1 = 
          g M0 Sin[\[Theta][t]] - 
            M0 x[t] Derivative[1][\[Theta]][t]^2 + 
            M0 ((x^\[Prime]\[Prime])[t] + 
               L0 (\[Theta]^\[Prime]\[Prime])[t]) == 0;
         eq2 = -g M0 (-L0 Sin[\[Theta][t]] - Cos[\[Theta][t]] x[t]) + 
            1/2 M0 (4 x[t] Derivative[1][x][t] Derivative[
                 1][\[Theta]][t] + 
               2 x[t]^2 (\[Theta]^\[Prime]\[Prime])[t] + 
               2 L0 ((x^\[Prime]\[Prime])[t] + 
                  L0 (\[Theta]^\[Prime]\[Prime])[t])) == 0;
         wasHit = 
          solve[M0, m0, L0, eq1, eq2, t, x, \[Theta], w, delT, r0]
         ]
        ];
       
       wasHit
       ];
     
     self
     ];
   (*--------- displayClass ---------------------------------------*)

   
   displayClass[] := 
    Module[{makeCounters, makeDiskDiagram, makePlot, self},
     
     (*--------- private ---------------------------------------*)
     makeCounters[
       m0_?numericPositive,(*pendulum arm mass*)
       M0_?numericStrictPositive,(*bob mass*)
       L0_?numericStrictPositive,(*pendulum length mass*)
       k_?numericPositive] := 
      Module[{h1, h2, currentMomentOfInertia, x, 
        v, \[Theta], \[Omega], PE, KE, trace, g = 9.81, simTime, 
        angularMomentum, solidPendulum, springAttached},
       
       solidPendulum = Abs[m0] > $MachineEpsilon;
       springAttached = Abs[k] > $MachineEpsilon;
       {simTime, x, v, \[Theta], \[Omega], trace} = list@getCurrent[];
       
       If[solidPendulum,
        KE = 
         1/6 L0^2 m0 \[Omega]^2 + 
          1/2 M0 (x^2 \[Omega]^2 + (v + L0 \[Omega])^2);
        currentMomentOfInertia = m0*L0^2/3;
        angularMomentum = 
         m0 L0^2/3*\[Omega] + M0 (L0 v + (L0^2 + x^2) \[Omega]);
        If[springAttached,
         PE = -(1/2) g L0 m0 Cos[\[Theta]] + 1/2 k x^2 - 
           g M0 (L0 Cos[\[Theta]] - Sin[\[Theta]] x),
         PE = -(1/2) g L0 m0 Cos[\[Theta]] - 
           g M0 (L0 Cos[\[Theta]] - Sin[\[Theta]] x)
         ],
        KE = 1/2 M0 (x^2 \[Omega]^2 + (v + L0 \[Omega])^2);
        currentMomentOfInertia = 0;
        angularMomentum = M0 (L0 v + (L0^2 + x^2) \[Omega]);
        If[springAttached,
         PE = 1/2 k x^2 - g M0 (L0 Cos[\[Theta]] - Sin[\[Theta]] x),
         PE = -g M0 (L0 Cos[\[Theta]] - Sin[\[Theta]] x)
         ]
        ];
       
       h1 = Style[Grid[{
           {"\[Theta]", "\[Omega]", "bob position", "bob velocity", 
            Style["\[CapitalIota]", Italic]
            },
           {"(degree)", "(rad/sec)", "(meter)", "(meter/sec)", 
            "(kg \!\(\*SuperscriptBox[\(meter\), \(2\)]\))"
            },
           { padIt2[180./Pi*\[Theta], {5, 2}], 
            padIt1[\[Omega], {7, 5}], padIt1[x, {5, 4}], 
            padIt1[v, {6, 3}], padIt2[currentMomentOfInertia, {7, 4}]
            }
           },
          
          Frame -> {All, 
            None, { {{1, 2}, {1, 5}} -> True , {{3, 3}, {1, 5}} -> 
              True}},
          FrameStyle -> Gray,
          Spacings -> 1,
          ItemSize -> {{All, 2 ;; -1} -> 5},
          Alignment -> Center], 12];
       
       h2 = Style[Grid[{
           {"time (sec)", 
            Row[{Style["I", Italic], 
              "\[InvisibleSpace] \[InvisibleSpace]\[Omega] (joule second)"}], 
              Row[{"P.E. (", Style["J", Italic], ")"}], 
            Row[{"K.E. (", Style["J", Italic], ")"}], 
            Row[{"energy (", Style["J", Italic], ")"}]
            },
           { padIt2[Mod[simTime, 1000], {7, 4}], 
            padIt2[angularMomentum, {6, 4}], padIt1[PE, {7, 3}], 
            padIt1[KE, {6, 3}], padIt1[PE + KE, {6, 2}]
            }},
          Frame -> All,
          FrameStyle -> Gray,
          Spacings -> 1,
          ItemSize -> {{All, 2 ;; -1} -> 6},
          Alignment -> Center], 12];
       
       Grid[{{h1}, {h2}}, Spacings -> {0, .1}]
       ];
     (*---------------private----------------------------------*)
     
     makeDiskDiagram[k_?numericPositive,
       m0_?numericStrictPositive,
       M0_?numericStrictPositive,
       L0_?numericStrictPositive,
       r0_?numericStrictPositive,
       wasHit_?bool,
       {ContentSizeW_?numericStrictPositive, 
        ContentSizeH_?numericStrictPositive},
       trace_?bool,
       w_] := 
      Module[{a = 2 r0, b = 1.1 r0, x, y, splash, xx, 
        v, \[Theta], \[Omega], traceData, currentTrace, spring, pin, 
        bob, ext, simTime, frame0, frame1, frame2, frame3, frame4},
       
       {simTime, xx, v, \[Theta], \[Omega], currentTrace} = 
        list@getCurrent[];
       traceData = list@getTraceData[];
       
       If[wasHit,
        splash = {
          { Dotted, Red, 
           Rotate[  
            Line[{{L0 + r0, Sign[xx] w/2}, {L0 + r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]},
          { Dotted, Red, 
           Rotate[Line[{{L0 + r0, Sign[xx] w/2}, {L0 + 2 r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]},
          { Dotted, Red, 
           Rotate[Line[{{L0 + r0, Sign[xx] w/2}, {L0 + 3 r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]},
          { Dotted, Red, 
           Rotate[Line[{{L0 + r0, Sign[xx] w/2}, {L0 - r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]},
          { Dotted, Red, 
           Rotate[Line[{{L0 + r0, Sign[xx] w/2}, {L0 - 2 r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]},
          { Dotted, Red, 
           Rotate[Line[{{L0 + r0, Sign[xx] w/2}, {L0 - 3 r0, 
               Sign[xx] (w/2 + 2 r0)}}], -(Pi/2) + \[Theta], {0, 0}]}
          };
        If[xx < 0, xx = -w/2 + r0, xx = w/2 - r0]
        ,
        splash = Sequence @@ {};
        ];
       
       x = xx*Cos[\[Theta]];
       y = xx*Sin[\[Theta]];
       traceData = list@getTraceData[];
       bob = {Red, Opacity[M0/100], EdgeForm[Thin], 
         Disk[{L0 + r0, xx}, r0]};
       pin = {LightGray, EdgeForm[Thin], Disk[{0, 0}, b]};
       ext = 1.1 Sqrt[(L0 + 2 r0)^2 + (w/2)^2];
       If[k == 0,
        spring = Sequence @@ {},
        spring = Line@makeSpring[L0 + r0, -w/2, L0 + r0, xx, r0]
        ];
       
       frame0 = {Thin, LightGray, 
         Line[{ {L0, 0}, {L0 , -w/2}, {L0 + a, -w/2}, {L0 + a, 
            w/2}, {L0 + a, w/2}, {L0, w/2}, {L0, 0}}]};
       frame1 = {Blue, Opacity[m0/100], EdgeForm[Thin], 
         Polygon[{ {0, -b/2}, {L0 , -b/2}, {L0, b/2}, {0, b/2}}]};
       frame2 = {Black, Line[{ {L0 , -w/2}, {L0 + a, -w/2}}]};
       frame3 = {Black, Line[{ {L0 + a , w/2}, {L0, w/2}}]};
       frame4 = {Thin, Red, Line[{ {L0 + r0 , -w/2}, {L0 + r0, w/2}}]};
       
       Framed@Graphics[{
          Rotate[frame0, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[{White, frame1}, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[frame2, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[frame3, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[frame4, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[{Black, spring}, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[bob, -(Pi/2) + \[Theta], {0, 0}],
          Rotate[pin, -(Pi/2) + \[Theta], {0, 0}],
          splash,
          
          If[trace, {Thin, Darker@Red, Line[traceData]}, 
           Sequence @@ {}]
          },
         Axes -> False,
         PlotRange -> {{-ext, ext}, {-ext , ext}},
         ImageSize -> {ContentSizeW, 1.01 ContentSizeH},
         ImagePadding -> {{5, 5}, {5, 5}},
         ImageMargins -> 0,
         AspectRatio -> 1
         ]
       ];
     (*-------------------- private -----------------------------*)
     makePlot[plotType_String,
       w_?numericStrictPositive] := Module[{plotTitle, data},
       
       Which[plotType == "disk angular velocity",
        data = list@getOmegaList[];
        If[Length[data] == 0, data = {{0, 0}}];
        plotTitle = {{Style["\[Omega] (rad/sec)", 12], 
           None}, {Style["time"], 
           Style["disk angular velocity vs. time", 12]}};
        plotRange = {{data[[1, 1]], data[[-1, 1]]}, All}
        ,
        plotType == "disk angle",
        data = list@getThetaList[];
        data[[All, 2]] = Map[180.0/Pi*# &, data[[All, 2]]];
        If[Length[data] == 0, data = {{0, 0}}];
        plotTitle = {{Style["\[Theta] (deg)", 12], 
           None}, {Style["time"], Style["disk angle vs. time", 12]}};
        plotRange = {{data[[1, 1]], data[[-1, 1]]}, {0, 360}}
        ,
        plotType == "bob position",
        data = list@getPositionList[];
        If[Length[data] == 0, data = {{0, 0}}];
        plotTitle = {{Style[
            Row[{"position (", Style["m", Italic], ")"}], 12], 
           None}, {Style["time"], Style["bob position vs. time", 12]}};
        plotRange = {{data[[1, 1]], data[[-1, 1]]}, {-w/2, w/2}}
        ,
        plotType == "bob velocity",
        data = list@getSpeedList[];
        If[Length[data] == 0, data = {{0, 0}}];
        plotTitle = {{Style[
            Row[{"velocity (", Style["m/s", Italic], ")"}], 12], 
           None}, {Style["time"], Style["bob velocity vs. time", 12]}};
        plotRange = {{data[[1, 1]], data[[-1, 1]]}, 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[plotType_String,
        m0_?numericPositive,
        M0_?numericStrictPositive,
        L0_?numericStrictPositive,
        r0_?numericStrictPositive,
        wasHit_?bool,
        k_?numericPositive,
        showPlots_?bool,
        showCounters_?bool,
        trace_?bool,
        w_] :=
      If[showPlots,
       If[showCounters,
        Grid[{
          {makeCounters[m0, M0, L0, k]},
          {makePlot[plotType, w]},
          {makeDiskDiagram[k, m0, M0, L0, r0, 
            wasHit, {1.4 ContentSizeW, 0.515 ContentSizeH}, trace, w]}
          }, Spacings -> 0]
        ,
        Grid[{
          {makePlot[plotType, w]},
          {makeDiskDiagram[k, m0, M0, L0, r0, 
            wasHit, {1.4 ContentSizeW, 0.787 ContentSizeH}, trace, w]}
          }, Spacings -> 0]
        ],
       If[showCounters,
        Grid[{
          {makeCounters[m0, M0, L0, k]},
          {makeDiskDiagram[k, m0, M0, L0, r0, 
            wasHit, {1.4 ContentSizeW, 0.93 ContentSizeH}, trace, w]}
          }, Spacings -> 0]
        ,
        Grid[{
          {makeDiskDiagram[k, m0, M0, L0, r0, 
            wasHit, {1.4 ContentSizeW, 1.2 ContentSizeH}, trace, w]}
          }, 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[500, 0.02, 0.5];
   list@add[{0, 0.05, 0.0, Pi/4, 0.09}];
   solver = solverClass[];
   display = displayClass[];
   }
 ]