.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/chaos/chaos_metrics/plot_bifurcation_diagram.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_chaos_chaos_metrics_plot_bifurcation_diagram.py: Bifurcation Diagrams for Continuous Flows: the Duffing Oscillator ====================================================================== Bifurcation diagrams aren't only for discrete maps -- they're just as useful for continuous, periodically-forced flows, via a *stroboscopic* Poincare section: sampling the state once per forcing period turns the continuous flow into an effective discrete map. The flow swept here is the forced, damped Duffing oscillator, .. math:: \ddot{x} + \delta \dot{x} + \alpha x + \beta x^3 = \gamma \cos(\omega t), with fixed damping :math:`\delta=0.3`, linear stiffness :math:`\alpha=-1`, cubic stiffness :math:`\beta=1`, and forcing frequency :math:`\omega=1.2` (so the double-well potential and forcing frequency are held fixed while only the forcing amplitude :math:`\gamma` is swept). This example sweeps :math:`\gamma` and, for each value, plots the surviving stroboscopic samples, using :func:`physicskit.chaos.visualizers.bifurcation.stroboscopic_bifurcation_sampler` -- the same :func:`~physicskit.chaos.visualizers.bifurcation.plot_bifurcation_diagram` used for the :doc:`Logistic Map ` works here completely unchanged. A companion plot below sweeps the same :math:`\gamma` range with :func:`physicskit.chaos.visualizers.divergence.trajectory_divergence` and :func:`physicskit.chaos.utils.metrics.lyapunov_exponent_from_divergence` to estimate the largest Lyapunov exponent at each amplitude, turning the bifurcation diagram's purely qualitative "band looks chaotic" into the quantitative :math:`\lambda_{\max} > 0` criterion, on the same :math:`\gamma` axis. .. GENERATED FROM PYTHON SOURCE LINES 33-45 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from physicskit.chaos.systems.continuous import Duffing from physicskit.chaos.utils.metrics import lyapunov_exponent_from_divergence from physicskit.chaos.visualizers.bifurcation import ( plot_bifurcation_diagram, stroboscopic_bifurcation_sampler, ) from physicskit.chaos.visualizers.divergence import trajectory_divergence .. GENERATED FROM PYTHON SOURCE LINES 46-50 Build the stroboscopic sampler ---------------------------------- The forcing period is ``2*pi / omega``; sampling the state once per forcing period is what turns the continuous flow into an effective discrete map. .. GENERATED FROM PYTHON SOURCE LINES 50-65 .. code-block:: Python omega = 1.2 period = 2.0 * np.pi / omega sampler = stroboscopic_bifurcation_sampler( lambda gamma: Duffing(delta=0.3, alpha=-1.0, beta=1.0, gamma=gamma, omega=omega), state0=np.array([0.1, 0.0]), sample_period=period, n_transient_periods=60, n_keep_periods=20, component=0, dt=0.15, rtol=1e-6, atol=1e-8, ) .. GENERATED FROM PYTHON SOURCE LINES 66-77 Sweep the forcing amplitude -------------------------------- As ``gamma`` increases, watch the single-point regular response give way to period-doubled cycles, and eventually a chaotic band -- the same period-doubling route to chaos as the Logistic Map, now in a physically driven mechanical oscillator. (Looser tolerances than the sampler's defaults keep this parameter sweep fast -- it calls the integrator once per `gamma` value below.) Each `gamma` value is fully independent of every other, so this sweep is also embarrassingly parallel: ``n_jobs`` runs it across a thread pool (real speedup here, since `solve_ivp` releases the GIL while it integrates), and ``show_progress`` displays a `tqdm` bar. .. GENERATED FROM PYTHON SOURCE LINES 77-86 .. code-block:: Python gamma_values = np.linspace(0.2, 0.5, 150) fig, ax = plt.subplots(figsize=(9, 5)) plot_bifurcation_diagram(gamma_values, sampler, n_jobs=4, show_progress=True, marker=".", markersize=1.0, ax=ax) ax.set_xlabel(r"forcing amplitude $\gamma$") ax.set_ylabel("x (stroboscopic samples)") ax.set_title("Duffing oscillator: bifurcation diagram vs. forcing amplitude") plt.show() .. image-sg:: /api/gallery/chaos/chaos_metrics/images/sphx_glr_plot_bifurcation_diagram_001.png :alt: Duffing oscillator: bifurcation diagram vs. forcing amplitude :srcset: /api/gallery/chaos/chaos_metrics/images/sphx_glr_plot_bifurcation_diagram_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none sweeping: 0%| | 0/150 [00:00 0$ lines up with the bifurcation diagram's chaotic band") fig_lyap.tight_layout() plt.show() .. image-sg:: /api/gallery/chaos/chaos_metrics/images/sphx_glr_plot_bifurcation_diagram_002.png :alt: $\lambda_{max} > 0$ lines up with the bifurcation diagram's chaotic band :srcset: /api/gallery/chaos/chaos_metrics/images/sphx_glr_plot_bifurcation_diagram_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 23.611 seconds) .. _sphx_glr_download_api_gallery_chaos_chaos_metrics_plot_bifurcation_diagram.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_bifurcation_diagram.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_bifurcation_diagram.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_bifurcation_diagram.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_