I am very interested in your subject of chaos and the double pendulum. Your implementation with OOP was a surprise but I figured it out and I was able to learn a lot about UpValues, Upset, DelayedUpset etc...
However, I do not understand what is the exact advantage of using your OOP paradigm. I did the same using ParametricNDSolve and implemented your formulas without any problem.
Manipulate[
Quiet@Module[{T1, T2, V1, V2, L, lkeq,
ans, \[Theta]1Eff, \[Theta]2Eff, pendulum, butterfly, g = 9.8,
m = 1, r1 = 1, r2 = 0.5},
SeedRandom[13];
(*Lagrangian setup*)
T1 = 1/2 m*r1^2*\[Theta]1'[t]^2;
V1 = -m*g*r1*Cos[\[Theta]1[t]];
T2 = 1/
2 m*(r1^2*\[Theta]1'[t]^2 + r2^2*\[Theta]2'[t]^2 +
2 r1*r2*\[Theta]1'[t]*\[Theta]2'[t]*r1*r2*
Cos[\[Theta]1[t] - \[Theta]2[t]]);
V2 = -m*g*(r1*Cos[\[Theta]1[t]] + r2*Cos[\[Theta]2[t]]);
L = T1 + T2 - (V1 + V2);
(*Lagrange equation of motion*)
lkeq = {D[D[L, \[Theta]1'[t]], t] - D[L, \[Theta]1[t]] == 0,
D[D[L, \[Theta]2'[t]], t] - D[L, \[Theta]2[t]] == 0};
(*Numerical solve parametric differential equation:
parameter is the initial angular displacement increment*)
ans = ParametricNDSolve[{lkeq, {\[Theta]1[0] ==
th1 + \[Epsilon], \[Theta]2[0] ==
th2 + \[Epsilon], \[Theta]1'[0] == 0, \[Theta]2'[0] ==
0}}, {\[Theta]1, \[Theta]2}, {t, 0, time}, {\[Epsilon]},
MaxSteps -> \[Infinity], PrecisionGoal -> \[Infinity]];
\[Theta]1Eff[\[Epsilon]_, tr_] := \[Theta]1[\[Epsilon]][tr] /.
ans;
\[Theta]2Eff[\[Epsilon]_, tr_] := \[Theta]2[\[Epsilon]][tr] /. ans;
butterfly = 10^-pwr;
pendulum[\[Epsilon]_, col_: Black] := {col,
Line[{{0,
0}, {r1*Sin[\[Theta]1Eff[\[Epsilon], tr]], -r1*
Cos[\[Theta]1Eff[\[Epsilon], tr]]}}],
Line[{{r1*Sin[\[Theta]1Eff[\[Epsilon], tr]], -r1*
Cos[\[Theta]1Eff[\[Epsilon], tr]]}, {(r1*
Sin[\[Theta]1Eff[\[Epsilon], tr]] +
r2*Sin[\[Theta]2Eff[\[Epsilon], tr]]), (-r1*
Cos[\[Theta]1Eff[\[Epsilon], tr]] -
r2*Cos[\[Theta]2Eff[\[Epsilon], tr]])}}]};
(*-----graphics display--------*)
Graphics[
Map[pendulum[butterfly*#1, Hue[#1]] &, RandomReal[{-1, 1}, n]],
PlotRange -> {{-1.8, 1.8}, {-1.8, 1.8}}]],
(*-----controls--------*)
{{tr, 0, Style["time", 12]}, 0, time,
Animator, AnimationRunning -> False, AnimationRepetitions -> 1,
AnimationRate -> .025},
Row[{Style["\nnumber of pendulums", 12],
Control[{{n, 6, ""}, Range[12]}]}],
Style["\ninitial angular base displacemenents",
12], {{th1, 2., "\[Theta]1"}, -3.14,
3.14}, {{th2, 2.5, "\[Theta]2"}, -3.14, 3.14},
Row[{Style[
"\ninitial angular displacement difference\n\[Theta]2-\[Theta]1: \
10^-", 12], Control[{{pwr, 12, ""}, Range[3, 16]}]}], {{time, 50},
None},
(*-----options--------*)
TrackedSymbols :> Manipulate,
AutorunSequencing -> {}, ControlPlacement -> Left]
I further more could introduce a variable number of pendulums and a variable "butterfly" value. All this using plain functional programming. Your method is very elegant and smart but what exactly can one do more,faster or better with OOP?