%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.14%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22marimo%3E%3D0.21.1%22%2C%0A%23%20%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.16%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0Aasync%20with%20app.setup(hide_code%3DTrue)%3A%0A%20%20%20%20%23%20Setup%20cell%20for%20marimo%20notebook%2C%20can%20be%20ignored%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20sys%0A%0A%20%20%20%20%23%20Import%20packages%20if%20running%20on%20marimo%20playground%0A%20%20%20%20if%20sys.executable%20%3D%3D%20%22%2Fhome%2Fpyodide%2Fthis.program%22%3A%0A%20%20%20%20%20%20%20%20import%20micropip%0A%0A%20%20%20%20%20%20%20%20await%20micropip.install(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%22pint_pandas%3C%3D0.7%22%2C%20%22typing_extensions%3E%3D4.15.0%22%2C%20%22poincare%3E%3D1.1.2%22%2C%20%22matplotlib%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20verbose%3DFalse%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Asymptotic%20behaviour%20in%20Poincare%0A%20%20%20%20Poincare%20contains%20a%20number%20of%20features%20to%20%20characterize%20the%20asymptotic%20behaviour%20of%20the%20system%2C%20including%20the%20search%20for%20steady%20states%2C%20bistability%20and%20limit%20cycles%20for%20different%20parameter%20values.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Steady%20States%20and%20parameter%20sweeps%0A%20%20%20%20To%20find%20steady%20states%2C%20we%20must%20first%20create%20an%20instance%20of%20the%20%60SteadyState%60%20class.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20from%20poincare%20import%20(%0A%20%20%20%20%20%20%20%20Derivative%2C%0A%20%20%20%20%20%20%20%20Parameter%2C%0A%20%20%20%20%20%20%20%20Simulator%2C%0A%20%20%20%20%20%20%20%20SteadyState%2C%0A%20%20%20%20%20%20%20%20System%2C%0A%20%20%20%20%20%20%20%20Variable%2C%0A%20%20%20%20%20%20%20%20assign%2C%0A%20%20%20%20%20%20%20%20initial%2C%0A%20%20%20%20)%0A%0A%20%20%20%20steady%20%3D%20SteadyState(t_end%3D1000)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20Derivative%2C%0A%20%20%20%20%20%20%20%20Parameter%2C%0A%20%20%20%20%20%20%20%20Simulator%2C%0A%20%20%20%20%20%20%20%20System%2C%0A%20%20%20%20%20%20%20%20Variable%2C%0A%20%20%20%20%20%20%20%20assign%2C%0A%20%20%20%20%20%20%20%20initial%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20steady%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20solver%20can%20be%20changed%20from%20the%20default%20LSODA%20by%20passing%20a%20%60solver%60%20attribute%20in%20a%20way%20similar%20to%20%60Simulator.solve()%60%20(see%20above).%20The%20%60SteadyState.solve()%60%20method%20runs%20the%20simulator%20until%20it%20finds%20a%20steady%20states%20(the%20derivatives%20are%20small%20enough)%20or%20it%20reaches%20%60t_end%60.%20Since%20%20the%20default%20for%20%60t_end%60%20is%20%60np.inf%60%2C%20not%20changing%20it%20may%20result%20in%20the%20%60Simulator.solve()%60%20running%20indefinitely.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Parameter%2C%20Simulator%2C%20System%2C%20Variable%2C%20assign%2C%20initial%2C%20steady)%3A%0A%20%20%20%20%23%20Create%20a%20system%0A%20%20%20%20class%20Pitchfork(System)%3A%0A%20%20%20%20%20%20%20%20x%3A%20Variable%20%3D%20initial(default%3D1)%0A%0A%20%20%20%20%20%20%20%20r%3A%20Parameter%20%3D%20assign(default%3D1)%0A%0A%20%20%20%20%20%20%20%20eq%20%3D%20x.derive()%20%3C%3C%20r%20*%20x%20-%20x**3%0A%0A%20%20%20%20%23%20Create%20a%20Simulator%20for%20Pitchfork%0A%20%20%20%20sim%20%3D%20Simulator(Pitchfork)%0A%20%20%20%20%23%20Find%20steady%20state%0A%20%20%20%20steady.solve(sim%2C%20values%3D%7BPitchfork.r%3A%202%7D)%0A%20%20%20%20return%20Pitchfork%2C%20sim%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20It%20outputs%20an%20%5Bxarray%5D(https%3A%2F%2Fdocs.xarray.dev%2Fen%2Fstable%2F)%20%60Dataset%60%20%20with%20the%20steady%20state%20reached%20for%20each%20variable%20and%20the%20time%20at%20which%20it%20terminated.%20%600%60%20in%20the%20event%20column%20indicates%20it%20terminated%20correctly%2C%20if%20it%20reaches%20%60t_end%60%20without%20terminating%20it%20outputs%20%60NA%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20%60SteadyState.sweep()%60%20method%20allows%20for%20parameter%20sweeps%2C%20finding%20the%20steady%20state%20with%20each%20parameter%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Pitchfork%2C%20np%2C%20sim%2C%20steady)%3A%0A%20%20%20%20steady.sweep(sim%2C%20variable%3DPitchfork.r%2C%20values%3Dnp.linspace(-10%2C%2010%2C%20100))%5B%0A%20%20%20%20%20%20%20%20%22x%22%0A%20%20%20%20%5D.to_dataframe().plot()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Since%20%60values%60%20only%20takes%20the%20values%20of%20the%20parameter%20to%20sweep%2C%20changes%20to%20initial%20conditions%20or%20values%20for%20other%20parameters%20in%20a%20sweep%20must%20be%20done%20at%20simulator%20creation%20level%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Pitchfork%2C%20Simulator%2C%20np%2C%20steady)%3A%0A%20%20%20%20sim_p%20%3D%20Simulator(Pitchfork(x%3D-1))%0A%20%20%20%20steady.sweep(sim_p%2C%20variable%3DPitchfork.r%2C%20values%3Dnp.linspace(-10%2C%2010%2C%20100))%5B%0A%20%20%20%20%20%20%20%20%22x%22%0A%20%20%20%20%5D.to_dataframe().plot()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20We%20can%20also%20use%20%60StadyState.sweep_up_and_down()%60%2C%20which%20sweeps%20first%20up%20and%20then%20down%20through%20%60values%60%20setting%20the%20steady%20state%20found%20in%20each%20run%20as%20initial%20conditions%20for%20the%20next.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Derivative%2C%0A%20%20%20%20Parameter%2C%0A%20%20%20%20Simulator%2C%0A%20%20%20%20System%2C%0A%20%20%20%20Variable%2C%0A%20%20%20%20assign%2C%0A%20%20%20%20initial%2C%0A%20%20%20%20np%2C%0A%20%20%20%20steady%2C%0A)%3A%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20class%20BiasedDouble(System)%3A%0A%20%20%20%20%20%20%20%20x%3A%20Variable%20%3D%20initial(default%3D-2)%0A%20%20%20%20%20%20%20%20v%3A%20Derivative%20%3D%20x.derive(initial%3D0)%0A%0A%20%20%20%20%20%20%20%20c%3A%20Parameter%20%3D%20assign(default%3D1)%0A%0A%20%20%20%20%20%20%20%20eq%20%3D%20v.derive()%20%3C%3C%20-v%20-%20x**3%20%2B%202%20*%20x%20%2B%20c%0A%0A%20%20%20%20sim_2%20%3D%20Simulator(BiasedDouble)%0A%20%20%20%20uad%20%3D%20steady.sweep_up_and_down(%0A%20%20%20%20%20%20%20%20sim_2%2C%20variable%3DBiasedDouble.c%2C%20values%3Dnp.linspace(-3%2C%203%2C%2030)%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Make%20bistability%20plot%0A%20%20%20%20uad.sel(direction%3D%22up%22)%5B%22x%22%5D.plot()%0A%20%20%20%20uad.sel(direction%3D%22down%22)%5B%22x%22%5D.plot()%0A%20%20%20%20plt.title(%22%22)%0A%20%20%20%20return%20BiasedDouble%2C%20plt%2C%20sim_2%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Poincare%20also%20allows%20for%20the%20search%20of%20bistability%20with%20different%20parameters%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BiasedDouble%2C%20np%2C%20sim_2%2C%20steady)%3A%0A%20%20%20%20steady.bistability(sim_2%2C%20variable%3DBiasedDouble.c%2C%20values%3Dnp.arange(-3%2C%203.1%2C%201))%5B%0A%20%20%20%20%20%20%20%20%22x%22%0A%20%20%20%20%5D%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%60SteadyState.bistability()%60%20works%20by%20sweeping%20up%20and%20down%20and%20checking%20if%20the%20difference%20between%20the%20up%20and%20down%20value%20is%20either%20greater%20than%20the%20absolute%20tolerance%20or%20greater%20then%20the%20sum%20of%20the%20results%20times%20the%20relative%20tolerance.%20These%20can%20be%20changed%20manually%20by%20passing%20%60atol%60%20and%20%60rtol%60%20respectively%20as%20parameters%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(BiasedDouble%2C%20np%2C%20sim_2%2C%20steady)%3A%0A%20%20%20%20steady.bistability(%0A%20%20%20%20%20%20%20%20sim_2%2C%0A%20%20%20%20%20%20%20%20variable%3DBiasedDouble.c%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.arange(-3%2C%203.1%2C%201)%2C%0A%20%20%20%20%20%20%20%20atol%3D0.1%2C%0A%20%20%20%20%20%20%20%20rtol%3D0.01%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Limit%20cycle%20analysis%0A%20%20%20%20If%20systems%20seem%20to%20stabilize%20around%20a%20limit%20cycle%20instead%20of%20reaching%20a%20steady%20state%2C%20we%20can%20use%20the%20%60Oscillations%60%20class%20to%20find%20it's%20period%20and%20amplitude.%20By%20default%20it%20uses%20the%20%5BAutoperiod%5D(https%3A%2F%2Fepubs.siam.org%2Fdoi%2Fepdf%2F10.1137%2F1.9781611972757.40)%20method%20with%20an%20implementation%20based%20on%20the%20one%20in%20the%20%5BPeriodicity%20Detection%5D(https%3A%2F%2Fpypi.org%2Fproject%2Fperiodicity-detection%2F)%20package.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20from%20poincare%20import%20Oscillations%0A%0A%20%20%20%20osc%20%3D%20Oscillations()%0A%20%20%20%20return%20(osc%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20It%20allows%20for%20parameter%20sweeps%20using%20the%20%60Oscillations.sweep()%60%20method%2C%20which%20takes%20a%20simulator%20for%20the%20%60System%60%20as%20its%20first%20argument%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Derivative%2C%0A%20%20%20%20Parameter%2C%0A%20%20%20%20Simulator%2C%0A%20%20%20%20System%2C%0A%20%20%20%20Variable%2C%0A%20%20%20%20assign%2C%0A%20%20%20%20initial%2C%0A%20%20%20%20np%2C%0A%20%20%20%20osc%2C%0A)%3A%0A%20%20%20%20from%20symbolite%20import%20real%0A%0A%20%20%20%20from%20poincare%20import%20Independent%0A%0A%20%20%20%20%23%20Create%20a%20System%20wich%20represents%20a%20sinusodally%20forced%20harmonic%20oscillator%0A%20%20%20%20class%20ForcedDampedOscillator(System)%3A%0A%20%20%20%20%20%20%20%20t%20%3D%20Independent()%0A%20%20%20%20%20%20%20%20%23%20Define%20new%20external%20variables%20for%20the%20sysyem%0A%20%20%20%20%20%20%20%20x%3A%20Variable%20%3D%20initial(default%3D1)%0A%20%20%20%20%20%20%20%20vx%3A%20Derivative%20%3D%20x.derive(initial%3D0)%0A%0A%20%20%20%20%20%20%20%20spring_constant%3A%20Parameter%20%3D%20assign(default%3D2)%0A%20%20%20%20%20%20%20%20damp_rate%3A%20Parameter%20%3D%20assign(default%3D0.3)%0A%20%20%20%20%20%20%20%20omega%3A%20Parameter%20%3D%20assign(default%3D0.5)%0A%20%20%20%20%20%20%20%20force%3A%20Parameter%20%3D%20assign(default%3D0.2%20*%20real.sin(omega%20*%20t))%0A%0A%20%20%20%20%20%20%20%20%23%20Apply%20the%20models%20to%20the%20external%20systems%20variables%0A%20%20%20%20%20%20%20%20oscillator%20%3D%20vx.derive()%20%3C%3C%20-spring_constant%20*%20x%20%2B%20force%20%2B%200.2%0A%20%20%20%20%20%20%20%20dampening%20%3D%20vx.derive()%20%3C%3C%20-damp_rate%20*%20vx%0A%0A%20%20%20%20%23%20Create%20a%20simulator%20for%20the%20system%0A%20%20%20%20sim_3%20%3D%20Simulator(ForcedDampedOscillator)%0A%0A%20%20%20%20%23%20Sweep%20parameters%0A%20%20%20%20result_3%20%3D%20osc.sweep(%0A%20%20%20%20%20%20%20%20sim_3%2C%0A%20%20%20%20%20%20%20%20T_min%3D1.5%2C%0A%20%20%20%20%20%20%20%20T_max%3D20%2C%0A%20%20%20%20%20%20%20%20rel_time%3D100%2C%0A%20%20%20%20%20%20%20%20parameter%3DForcedDampedOscillator.omega%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.linspace(1%2C%202%2C%2020)%2C%0A%20%20%20%20)%0A%20%20%20%20result_3%0A%20%20%20%20return%20ForcedDampedOscillator%2C%20result_3%2C%20sim_3%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Besides%20the%20simulator%2C%20%60Oscillations.sweep()%60%20takes%20the%20following%20required%20keyword%20arguments%3A%0A%20%20%20%20-%20%60T_min%60%2F%60T_max%60%3A%20minimum%20of%20maximum%20of%20range%20in%20which%20periods%20are%20expected%20to%20be%20found.%0A%20%20%20%20-%20%60rel_time%60%3A%20upper%20bound%20for%20the%20system's%20relaxation%20time%20%2C%20after%20which%20it%20is%20expected%20to%20be%20close%20enough%20to%20it's%20limit%20cycle.%0A%20%20%20%20-%20%60parameter%60%3A%20parameter%20to%20sweep%20in.%0A%20%20%20%20-%20%60values%60%3A%20iterable%20of%20values%20which%20%60parameter%60%20will%20take.%0A%0A%20%20%20%20To%20determine%20%60T_min%60%2C%20%60T_max%60%20and%20%60T_r%60%20it%20is%20generally%20a%20reasonable%20first%20estimate%20to%20assume%20monotonicity%20with%20respect%20to%20the%20parameter%2C%20so%20we%20can%20simulate%20in%20it's%20maximum%20and%20minimum%20value%20and%20use%20the%20largest%20(or%20smallest%20for%20%60T_min%60)%20result%20obtained.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20output%20is%20a%20pandas%20%60DataFrame%60%20which%20contains%20period%2C%20amplitude%20and%20mean%20quadratic%20difference%20between%20consecutive%20periods%20indexed%20by%20the%20swept%20parameter's%20value.%20We%20can%20plot%20the%20results%20for%20period%20and%20amplitude%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plt%2C%20result_3)%3A%0A%20%20%20%20result_3.sel(quantity%3D%22period%22).to_dataframe().plot(style%3D%22--.%22%2C%20title%3D%22period%22)%0A%20%20%20%20plt.legend()%0A%20%20%20%20plt.show()%0A%20%20%20%20result_3.sel(quantity%3D%22amplitude%22).to_dataframe().plot(%0A%20%20%20%20%20%20%20%20style%3D%22--.%22%2C%20title%3D%22amplitude%22%0A%20%20%20%20)%0A%20%20%20%20plt.legend()%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20And%20get%20an%20idea%20of%20how%20accurate%20the%20estimate%20is%20by%20plotting%20the%20mean%20quadratic%20difference%20between%20periods%20relative%20to%20the%20amplitude%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20result_3)%3A%0A%20%20%20%20relative%20%3D%20result_3.sel(quantity%3D%22difference_rms%22)%20%2F%20result_3.sel(%0A%20%20%20%20%20%20%20%20quantity%3D%22amplitude%22%0A%20%20%20%20)%0A%20%20%20%20relative.to_dataframe().plot()%0A%20%20%20%20plt.hlines(%0A%20%20%20%20%20%20%20%201%2C%0A%20%20%20%20%20%20%20%20np.min(relative.coords%5B%22omega%22%5D)%2C%0A%20%20%20%20%20%20%20%20np.max(relative.coords%5B%22omega%22%5D)%2C%0A%20%20%20%20%20%20%20%20linestyles%3D%22--%22%2C%0A%20%20%20%20%20%20%20%20colors%3D%22maroon%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20If%20the%20method%20fails%20to%20find%20or%20confirm%20a%20period%20it%20will%20raise%20warnings%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ForcedDampedOscillator%2C%20np%2C%20osc%2C%20sim_3)%3A%0A%20%20%20%20result_4%20%3D%20osc.sweep(%0A%20%20%20%20%20%20%20%20sim_3%2C%0A%20%20%20%20%20%20%20%20T_min%3D2%2C%0A%20%20%20%20%20%20%20%20T_max%3D35%2C%0A%20%20%20%20%20%20%20%20rel_time%3D100%2C%0A%20%20%20%20%20%20%20%20parameter%3DForcedDampedOscillator.omega%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.linspace(0.2%2C%203%2C%2020)%2C%0A%20%20%20%20)%0A%20%20%20%20result_4.head(3)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20We%20can%20try%20changing%20the%20minimum%20amount%20of%20periods%20it%20simulates%20after%20relaxation%20%60T_after_rel%60%20or%20the%20minimum%20amount%20of%20timesteps%20in%20%20each%20period%20%60timesteps_in_T%60%20to%20get%20a%20better%20result%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ForcedDampedOscillator%2C%20np%2C%20osc%2C%20sim_3)%3A%0A%20%20%20%20result_5%20%3D%20osc.sweep(%0A%20%20%20%20%20%20%20%20sim_3%2C%0A%20%20%20%20%20%20%20%20T_min%3D2%2C%0A%20%20%20%20%20%20%20%20T_max%3D35%2C%0A%20%20%20%20%20%20%20%20rel_time%3D100%2C%0A%20%20%20%20%20%20%20%20parameter%3DForcedDampedOscillator.omega%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.linspace(0.2%2C%203%2C%2020)%2C%0A%20%20%20%20%20%20%20%20T_after_rel%3D15%2C%0A%20%20%20%20%20%20%20%20timesteps_in_T%3D5%2C%0A%20%20%20%20)%0A%20%20%20%20result_5.head(3)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20If%20the%20System%20has%20more%20than%20one%20variable%20%60Oscillations.sweep%60%2C%20will%20by%20default%20look%20at%20all%20of%20them%2C%20finding%20a%20period%20and%20amplitude%20for%20each%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Parameter%2C%20Simulator%2C%20System%2C%20Variable%2C%20assign%2C%20initial%2C%20np%2C%20osc)%3A%0A%20%20%20%20class%20LotkaVolterra(System)%3A%0A%20%20%20%20%20%20%20%20prey%3A%20Variable%20%3D%20initial(default%3D10)%0A%20%20%20%20%20%20%20%20predator%3A%20Variable%20%3D%20initial(default%3D1)%0A%20%20%20%20%20%20%20%20prey_birth_rate%3A%20Parameter%20%3D%20assign(default%3D1)%0A%20%20%20%20%20%20%20%20prey_death_rate%3A%20Parameter%20%3D%20assign(default%3D1)%0A%20%20%20%20%20%20%20%20predator_death_rate%3A%20Parameter%20%3D%20assign(default%3D1)%0A%20%20%20%20%20%20%20%20predator_birth_rate%3A%20Parameter%20%3D%20assign(default%3D1)%0A%20%20%20%20%20%20%20%20k%3A%20Parameter%20%3D%20assign(default%3D1)%0A%20%20%20%20%20%20%20%20birth_prey%20%3D%20prey.derive()%20%3C%3C%20prey_birth_rate%20*%20prey%0A%20%20%20%20%20%20%20%20death_prey%20%3D%20prey.derive()%20%3C%3C%20-prey_death_rate%20*%20prey%20*%20predator%0A%20%20%20%20%20%20%20%20birth_predator%20%3D%20predator.derive()%20%3C%3C%20predator_birth_rate%20*%20prey%20*%20predator%0A%20%20%20%20%20%20%20%20death_predator%20%3D%20predator.derive()%20%3C%3C%20-predator_death_rate%20*%20predator%0A%0A%20%20%20%20sim_4%20%3D%20Simulator(LotkaVolterra)%0A%20%20%20%20result_6%20%3D%20osc.sweep(%0A%20%20%20%20%20%20%20%20sim_4%2C%0A%20%20%20%20%20%20%20%20T_min%3D5%2C%0A%20%20%20%20%20%20%20%20T_max%3D20%2C%0A%20%20%20%20%20%20%20%20rel_time%3D100%2C%0A%20%20%20%20%20%20%20%20parameter%3DLotkaVolterra.prey_birth_rate%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.linspace(1%2C%203%2C%2020)%2C%0A%20%20%20%20%20%20%20%20T_after_rel%3D10%2C%0A%20%20%20%20%20%20%20%20timesteps_in_T%3D10%2C%0A%20%20%20%20)%0A%20%20%20%20result_6%0A%20%20%20%20return%20LotkaVolterra%2C%20sim_4%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_()%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20Or%20we%20can%20specifically%20pass%20a%20list%20%60variables%60%20specifying%20which%20should%20be%20considered%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(LotkaVolterra%2C%20np%2C%20osc%2C%20sim_4)%3A%0A%20%20%20%20result_7%20%3D%20osc.sweep(%0A%20%20%20%20%20%20%20%20sim_4%2C%0A%20%20%20%20%20%20%20%20T_min%3D5%2C%0A%20%20%20%20%20%20%20%20T_max%3D20%2C%0A%20%20%20%20%20%20%20%20rel_time%3D100%2C%0A%20%20%20%20%20%20%20%20parameter%3DLotkaVolterra.prey_birth_rate%2C%0A%20%20%20%20%20%20%20%20values%3Dnp.linspace(1%2C%203%2C%2020)%2C%0A%20%20%20%20%20%20%20%20T_after_rel%3D10%2C%0A%20%20%20%20%20%20%20%20timesteps_in_T%3D10%2C%0A%20%20%20%20%20%20%20%20variables%3D%5BLotkaVolterra.prey%5D%2C%0A%20%20%20%20)%0A%20%20%20%20result_7%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
a4f5803d300d3ea181d9039d2a5715cd