.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/astro/nbody/plot_02_figure_eight_choreography.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_astro_nbody_plot_02_figure_eight_choreography.py: The figure-eight three-body choreography ============================================ For two centuries after Newton, every known periodic three-body solution demanded either a special mass ratio (Lagrange's equilateral triangle) or a rigidly symmetric configuration (Euler's collinear solutions). Moore found something qualitatively different in 1993: three *equal* masses chasing one another endlessly around a single figure-eight curve, a genuine *choreography* with no distinguished body -- proven to exist by Chenciner and Montgomery in 2000. :func:`~physicskit.astro.nbody.figure_eight_initial_conditions` returns exactly this initial condition; this example integrates it with :class:`~physicskit.astro.nbody.NBodySystem`, checks that the configuration is genuinely periodic by finding the time at which body 1 first returns closest to its own starting point, and checks that energy and angular momentum stay conserved over one full period. .. GENERATED FROM PYTHON SOURCE LINES 21-27 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from physicskit.astro.nbody import NBodySystem, figure_eight_initial_conditions from physicskit.astro.visualizers import animate_nbody_trajectories, plot_nbody_trajectories .. GENERATED FROM PYTHON SOURCE LINES 28-30 Integrate one and a bit periods ------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 30-43 .. code-block:: Python positions0, velocities0, masses = figure_eight_initial_conditions() dt, n_steps = 0.002, 3500 # generously more than one period, found below system = NBodySystem(positions0, velocities0, masses) E0 = system.total_energy() L0 = system.total_angular_momentum() history = system.simulate(dt, n_steps) E1 = system.total_energy() L1 = system.total_angular_momentum() print(f"energy: E0={E0:.8f}, E1={E1:.8f}, relative drift={abs((E1 - E0) / E0):.2e}") print(f"angular momentum: L0_z={L0[2]:.8f}, L1_z={L1[2]:.8f}") .. rst-class:: sphx-glr-script-out .. code-block:: none energy: E0=-1.28704684, E1=-1.28704909, relative drift=1.75e-06 angular momentum: L0_z=0.00000000, L1_z=-0.00000000 .. GENERATED FROM PYTHON SOURCE LINES 44-50 Finding the period numerically ------------------------------------ Rather than trust a hardcoded literature value, find the period directly: track body 1's distance back to its own initial position after a short initial exclusion window, and take the time of its first sharp local minimum. .. GENERATED FROM PYTHON SOURCE LINES 50-66 .. code-block:: Python t = np.arange(n_steps + 1) * dt dist_to_start = np.linalg.norm(history[:, 0, :] - positions0[0], axis=1) search = t > 1.0 # skip the initial departure from the starting point i_period = np.argmin(dist_to_start[search]) + np.argmax(search) T_period = t[i_period] print(f"\nnumerically found period: T = {T_period:.6f} (return distance = {dist_to_start[i_period]:.2e})") fig0, ax0 = plt.subplots(figsize=(6, 3.5)) ax0.plot(t, dist_to_start) ax0.axvline(T_period, color="firebrick", ls="--", label=f"period T={T_period:.4f}") ax0.set_xlabel("t") ax0.set_ylabel("|body 1 - its own start|") ax0.set_title("Finding the choreography's period") ax0.legend() fig0.tight_layout() .. image-sg:: /api/gallery/astro/nbody/images/sphx_glr_plot_02_figure_eight_choreography_001.png :alt: Finding the choreography's period :srcset: /api/gallery/astro/nbody/images/sphx_glr_plot_02_figure_eight_choreography_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none numerically found period: T = 6.326000 (return distance = 3.54e-04) .. GENERATED FROM PYTHON SOURCE LINES 67-72 The choreography itself ----------------------------- All three equal masses trace the *same* figure-eight curve, each lagging the next by exactly a third of the period -- no body plays a distinguished role. .. GENERATED FROM PYTHON SOURCE LINES 72-80 .. code-block:: Python n_steps_one_period = int(round(T_period / dt)) fig1, ax1 = plot_nbody_trajectories(history[: n_steps_one_period + 1]) ax1.set_title("The figure-eight choreography, one full period") fig1.tight_layout() anim = animate_nbody_trajectories(history[: n_steps_one_period + 1], trail=n_steps_one_period, title="Figure-eight choreography") plt.show() .. rst-class:: sphx-glr-horizontal * .. image-sg:: /api/gallery/astro/nbody/images/sphx_glr_plot_02_figure_eight_choreography_002.png :alt: The figure-eight choreography, one full period :srcset: /api/gallery/astro/nbody/images/sphx_glr_plot_02_figure_eight_choreography_002.png :class: sphx-glr-multi-img * .. container:: sphx-glr-animation .. raw:: html .. rst-class:: sphx-glr-timing **Total running time of the script:** (4 minutes 4.384 seconds) .. _sphx_glr_download_api_gallery_astro_nbody_plot_02_figure_eight_choreography.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_figure_eight_choreography.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_figure_eight_choreography.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_figure_eight_choreography.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_