
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "_gallery/CatenaryCase/run_catenary.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download__gallery_CatenaryCase_run_catenary.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr__gallery_CatenaryCase_run_catenary.py:


Catenary
========

This case simulates a rod hanging under its own weight, forming a catenary
curve. The rod is fixed at both ends and is allowed to settle into its
equilibrium position.

.. GENERATED FROM PYTHON SOURCE LINES 9-20

.. code-block:: Python


    from collections import defaultdict
    import numpy as np

    import elastica as ea

    from post_processing import (
        plot_video,
        plot_catenary,
    )








.. GENERATED FROM PYTHON SOURCE LINES 21-24

Simulation Setup
----------------
We define a simulator class that inherits from the necessary mixins.

.. GENERATED FROM PYTHON SOURCE LINES 24-35

.. code-block:: Python



    class CatenarySimulator(
        ea.BaseSystemCollection, ea.Constraints, ea.Forcing, ea.Damping, ea.CallBacks
    ):
        pass


    catenary_sim = CatenarySimulator()
    final_time = 30








.. GENERATED FROM PYTHON SOURCE LINES 36-39

Rod Setup
---------
We set up the rod parameters. This rod is affected by a gravity force.

.. GENERATED FROM PYTHON SOURCE LINES 39-80

.. code-block:: Python


    n_elem = 500
    time_step = 1e-4
    total_steps = int(final_time / time_step)
    rendering_fps = 20
    step_skip = int(1.0 / (rendering_fps * time_step))

    start = np.zeros((3,))
    direction = np.array([1.0, 0.0, 0.0])
    normal = np.array([0.0, 0.0, 1.0])

    # catenary parameters
    base_length = 1.0
    base_radius = 0.01
    base_area = np.pi * (base_radius**2)
    volume = base_area * base_length
    mass = 0.2
    density = mass / volume
    E = 1e4
    poisson_ratio = 0.5
    shear_modulus = E / (poisson_ratio + 1.0)

    base_rod = ea.CosseratRod.straight_rod(
        n_elem,
        start,
        direction,
        normal,
        base_length,
        base_radius,
        density,
        youngs_modulus=E,
        shear_modulus=shear_modulus,
    )

    catenary_sim.append(base_rod)

    # Add gravity
    catenary_sim.add_forcing_to(base_rod).using(
        ea.GravityForces, acc_gravity=-9.80665 * normal
    )








.. GENERATED FROM PYTHON SOURCE LINES 81-82

Damping is added to the system to help it reach a steady state.

.. GENERATED FROM PYTHON SOURCE LINES 82-91

.. code-block:: Python


    # add damping
    damping_constant = 0.3
    catenary_sim.dampen(base_rod).using(
        ea.AnalyticalLinearDamper,
        damping_constant=damping_constant,
        time_step=time_step,
    )








.. GENERATED FROM PYTHON SOURCE LINES 92-95

Boundary Conditions
-------------------
We fix both ends of the rod using the `FixedConstraint`.

.. GENERATED FROM PYTHON SOURCE LINES 95-103

.. code-block:: Python


    # fix catenary ends
    catenary_sim.constrain(base_rod).using(
        ea.FixedConstraint,
        constrained_position_idx=(0, -1),
        constrained_director_idx=(0, -1),
    )








.. GENERATED FROM PYTHON SOURCE LINES 104-107

Callback
--------
We define a callback class to record the rod state during the simulation.

.. GENERATED FROM PYTHON SOURCE LINES 107-140

.. code-block:: Python



    # Add call backs
    class CatenaryCallBack(ea.CallBackBaseClass):
        """
        Call back function for catenary case
        """

        def __init__(self, step_skip: int, callback_params: dict) -> None:
            super().__init__()
            self.every = step_skip
            self.callback_params = callback_params

        def make_callback(
            self, system: ea.typing.RodType, time: np.float64, current_step: int
        ) -> None:

            if current_step % self.every == 0:

                self.callback_params["time"].append(time)
                self.callback_params["step"].append(current_step)
                self.callback_params["position"].append(system.position_collection.copy())
                self.callback_params["radius"].append(system.radius.copy())
                self.callback_params["internal_force"].append(system.internal_forces.copy())

                return


    recorded_history: dict[str, list] = defaultdict(list)
    catenary_sim.collect_diagnostics(base_rod).using(
        CatenaryCallBack, step_skip=step_skip, callback_params=recorded_history
    )








.. GENERATED FROM PYTHON SOURCE LINES 141-144

Finalize and Run
----------------
We finalize the simulator, create the time-stepper, and run.

.. GENERATED FROM PYTHON SOURCE LINES 144-155

.. code-block:: Python


    catenary_sim.finalize()
    timestepper: ea.typing.StepperProtocol = ea.PositionVerlet()

    dt = final_time / total_steps
    time = 0.0
    for i in range(total_steps):
        time = timestepper.step(catenary_sim, time, dt)
    position = np.array(recorded_history["position"])
    b = np.min(position[-1][2])








.. GENERATED FROM PYTHON SOURCE LINES 156-160

Post-processing
---------------
Finally, we can save a video of the simulation and plot the final
shape of the catenary.

.. GENERATED FROM PYTHON SOURCE LINES 160-171

.. code-block:: Python


    # plotting the videos
    filename_video = "catenary.mp4"
    plot_video(
        recorded_history,
        video_name=filename_video,
        fps=rendering_fps,
        xlim=[0, base_length],
        ylim=[-0.5 * base_length, 0.5 * base_length],
    )





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    plot video
      0%|          | 0/600 [00:00<?, ?it/s]      0%|          | 2/600 [00:00<00:30, 19.46it/s]      1%|          | 6/600 [00:00<00:20, 29.44it/s]      2%|▏         | 10/600 [00:00<00:17, 33.62it/s]      2%|▏         | 14/600 [00:00<00:16, 36.03it/s]      3%|▎         | 18/600 [00:00<00:15, 36.99it/s]      4%|▎         | 22/600 [00:00<00:15, 37.05it/s]      4%|▍         | 26/600 [00:00<00:15, 37.44it/s]      5%|▌         | 30/600 [00:00<00:14, 38.15it/s]      6%|▌         | 34/600 [00:00<00:14, 38.31it/s]      6%|▋         | 38/600 [00:01<00:14, 38.50it/s]      7%|▋         | 42/600 [00:01<00:14, 37.94it/s]      8%|▊         | 46/600 [00:01<00:15, 35.51it/s]      8%|▊         | 50/600 [00:01<00:21, 25.66it/s]      9%|▉         | 53/600 [00:01<00:21, 25.19it/s]      9%|▉         | 56/600 [00:01<00:21, 24.99it/s]     10%|▉         | 59/600 [00:01<00:21, 25.63it/s]     10%|█         | 62/600 [00:01<00:20, 26.27it/s]     11%|█         | 65/600 [00:02<00:20, 26.15it/s]     12%|█▏        | 69/600 [00:02<00:19, 27.61it/s]     12%|█▏        | 72/600 [00:02<00:18, 27.89it/s]     12%|█▎        | 75/600 [00:02<00:19, 26.85it/s]     13%|█▎        | 79/600 [00:02<00:18, 28.60it/s]     14%|█▎        | 82/600 [00:02<00:18, 28.52it/s]     14%|█▍        | 85/600 [00:02<00:18, 27.68it/s]     15%|█▍        | 88/600 [00:02<00:18, 27.70it/s]     15%|█▌        | 91/600 [00:03<00:18, 27.89it/s]     16%|█▌        | 94/600 [00:03<00:17, 28.43it/s]     16%|█▌        | 97/600 [00:03<00:17, 28.16it/s]     17%|█▋        | 100/600 [00:03<00:18, 27.66it/s]     17%|█▋        | 103/600 [00:03<00:18, 27.39it/s]     18%|█▊        | 106/600 [00:03<00:18, 26.95it/s]     18%|█▊        | 110/600 [00:03<00:17, 28.60it/s]     19%|█▉        | 113/600 [00:03<00:17, 27.33it/s]     20%|█▉        | 117/600 [00:03<00:16, 28.43it/s]     20%|██        | 121/600 [00:04<00:16, 29.14it/s]     21%|██        | 124/600 [00:04<00:16, 28.86it/s]     21%|██        | 127/600 [00:04<00:16, 28.42it/s]     22%|██▏       | 131/600 [00:04<00:15, 29.36it/s]     22%|██▏       | 134/600 [00:04<00:16, 28.33it/s]     23%|██▎       | 138/600 [00:04<00:15, 29.45it/s]     24%|██▎       | 141/600 [00:04<00:15, 29.02it/s]     24%|██▍       | 144/600 [00:04<00:15, 28.59it/s]     24%|██▍       | 147/600 [00:04<00:15, 28.46it/s]     25%|██▌       | 150/600 [00:05<00:15, 28.80it/s]     26%|██▌       | 154/600 [00:05<00:14, 30.32it/s]     26%|██▋       | 158/600 [00:05<00:14, 29.65it/s]     27%|██▋       | 162/600 [00:05<00:14, 30.15it/s]     28%|██▊       | 166/600 [00:05<00:14, 30.00it/s]     28%|██▊       | 170/600 [00:05<00:14, 30.31it/s]     29%|██▉       | 174/600 [00:05<00:13, 30.49it/s]     30%|██▉       | 178/600 [00:06<00:13, 30.82it/s]     30%|███       | 182/600 [00:06<00:13, 30.93it/s]     31%|███       | 186/600 [00:06<00:13, 31.20it/s]     32%|███▏      | 190/600 [00:06<00:13, 30.87it/s]     32%|███▏      | 194/600 [00:06<00:13, 30.73it/s]     33%|███▎      | 198/600 [00:06<00:12, 31.27it/s]     34%|███▎      | 202/600 [00:06<00:12, 30.89it/s]     34%|███▍      | 206/600 [00:06<00:12, 31.35it/s]     35%|███▌      | 210/600 [00:07<00:12, 31.20it/s]     36%|███▌      | 214/600 [00:07<00:12, 30.54it/s]     36%|███▋      | 218/600 [00:07<00:12, 30.45it/s]     37%|███▋      | 222/600 [00:07<00:12, 30.68it/s]     38%|███▊      | 226/600 [00:07<00:12, 30.45it/s]     38%|███▊      | 230/600 [00:07<00:12, 30.64it/s]     39%|███▉      | 234/600 [00:07<00:11, 31.79it/s]     40%|███▉      | 238/600 [00:07<00:11, 31.61it/s]     40%|████      | 242/600 [00:08<00:11, 31.41it/s]     41%|████      | 246/600 [00:08<00:11, 31.36it/s]     42%|████▏     | 250/600 [00:08<00:11, 31.52it/s]     42%|████▏     | 254/600 [00:08<00:10, 31.64it/s]     43%|████▎     | 258/600 [00:08<00:10, 31.76it/s]     44%|████▎     | 262/600 [00:08<00:10, 31.64it/s]     44%|████▍     | 266/600 [00:08<00:10, 32.16it/s]     45%|████▌     | 270/600 [00:08<00:10, 31.59it/s]     46%|████▌     | 274/600 [00:09<00:10, 31.64it/s]     46%|████▋     | 278/600 [00:09<00:10, 31.31it/s]     47%|████▋     | 282/600 [00:09<00:10, 31.17it/s]     48%|████▊     | 286/600 [00:09<00:09, 31.70it/s]     48%|████▊     | 290/600 [00:09<00:09, 31.96it/s]     49%|████▉     | 294/600 [00:09<00:09, 31.89it/s]     50%|████▉     | 298/600 [00:09<00:09, 31.93it/s]     50%|█████     | 302/600 [00:09<00:09, 31.57it/s]     51%|█████     | 306/600 [00:10<00:09, 31.42it/s]     52%|█████▏    | 310/600 [00:10<00:09, 31.20it/s]     52%|█████▏    | 314/600 [00:10<00:09, 30.86it/s]     53%|█████▎    | 318/600 [00:10<00:09, 30.98it/s]     54%|█████▎    | 322/600 [00:10<00:08, 31.00it/s]     54%|█████▍    | 326/600 [00:10<00:08, 31.41it/s]     55%|█████▌    | 330/600 [00:10<00:08, 31.67it/s]     56%|█████▌    | 334/600 [00:10<00:08, 31.59it/s]     56%|█████▋    | 338/600 [00:11<00:08, 31.12it/s]     57%|█████▋    | 342/600 [00:11<00:08, 31.41it/s]     58%|█████▊    | 346/600 [00:11<00:08, 31.45it/s]     58%|█████▊    | 350/600 [00:11<00:07, 31.56it/s]     59%|█████▉    | 354/600 [00:11<00:07, 31.35it/s]     60%|█████▉    | 358/600 [00:11<00:07, 31.24it/s]     60%|██████    | 362/600 [00:11<00:07, 31.31it/s]     61%|██████    | 366/600 [00:12<00:07, 31.51it/s]     62%|██████▏   | 370/600 [00:12<00:07, 32.21it/s]     62%|██████▏   | 374/600 [00:12<00:07, 31.97it/s]     63%|██████▎   | 378/600 [00:12<00:06, 31.92it/s]     64%|██████▎   | 382/600 [00:12<00:06, 31.86it/s]     64%|██████▍   | 386/600 [00:12<00:06, 32.14it/s]     65%|██████▌   | 390/600 [00:12<00:06, 31.69it/s]     66%|██████▌   | 394/600 [00:12<00:06, 31.40it/s]     66%|██████▋   | 398/600 [00:13<00:06, 31.33it/s]     67%|██████▋   | 402/600 [00:13<00:06, 30.99it/s]     68%|██████▊   | 406/600 [00:13<00:06, 31.22it/s]     68%|██████▊   | 410/600 [00:13<00:06, 31.22it/s]     69%|██████▉   | 414/600 [00:13<00:05, 31.21it/s]     70%|██████▉   | 418/600 [00:13<00:05, 31.25it/s]     70%|███████   | 422/600 [00:13<00:05, 31.67it/s]     71%|███████   | 426/600 [00:13<00:05, 31.93it/s]     72%|███████▏  | 430/600 [00:14<00:05, 32.16it/s]     72%|███████▏  | 434/600 [00:14<00:05, 32.10it/s]     73%|███████▎  | 438/600 [00:14<00:05, 32.25it/s]     74%|███████▎  | 442/600 [00:14<00:04, 31.87it/s]     74%|███████▍  | 446/600 [00:14<00:04, 31.80it/s]     75%|███████▌  | 450/600 [00:14<00:04, 31.80it/s]     76%|███████▌  | 454/600 [00:14<00:04, 32.12it/s]     76%|███████▋  | 458/600 [00:14<00:04, 32.17it/s]     77%|███████▋  | 462/600 [00:15<00:04, 32.31it/s]     78%|███████▊  | 466/600 [00:15<00:04, 32.15it/s]     78%|███████▊  | 470/600 [00:15<00:04, 31.91it/s]     79%|███████▉  | 474/600 [00:15<00:03, 32.74it/s]     80%|███████▉  | 478/600 [00:15<00:03, 31.81it/s]     80%|████████  | 482/600 [00:15<00:03, 31.45it/s]     81%|████████  | 486/600 [00:15<00:03, 31.22it/s]     82%|████████▏ | 490/600 [00:15<00:03, 31.44it/s]     82%|████████▏ | 494/600 [00:16<00:03, 31.64it/s]     83%|████████▎ | 498/600 [00:16<00:03, 31.37it/s]     84%|████████▎ | 502/600 [00:16<00:03, 31.33it/s]     84%|████████▍ | 506/600 [00:16<00:02, 31.50it/s]     85%|████████▌ | 510/600 [00:16<00:02, 31.63it/s]     86%|████████▌ | 514/600 [00:16<00:02, 31.61it/s]     86%|████████▋ | 518/600 [00:16<00:02, 31.62it/s]     87%|████████▋ | 522/600 [00:16<00:02, 32.00it/s]     88%|████████▊ | 526/600 [00:17<00:02, 32.37it/s]     88%|████████▊ | 530/600 [00:17<00:02, 31.75it/s]     89%|████████▉ | 534/600 [00:17<00:02, 31.66it/s]     90%|████████▉ | 538/600 [00:17<00:01, 31.31it/s]     90%|█████████ | 542/600 [00:17<00:01, 32.03it/s]     91%|█████████ | 546/600 [00:17<00:01, 31.80it/s]     92%|█████████▏| 550/600 [00:17<00:01, 31.45it/s]     92%|█████████▏| 554/600 [00:17<00:01, 32.31it/s]     93%|█████████▎| 558/600 [00:18<00:01, 32.47it/s]     94%|█████████▎| 562/600 [00:18<00:01, 32.54it/s]     94%|█████████▍| 566/600 [00:18<00:01, 32.60it/s]     95%|█████████▌| 570/600 [00:18<00:00, 32.87it/s]     96%|█████████▌| 574/600 [00:18<00:00, 31.83it/s]     96%|█████████▋| 578/600 [00:18<00:00, 31.80it/s]     97%|█████████▋| 582/600 [00:18<00:00, 32.36it/s]     98%|█████████▊| 586/600 [00:18<00:00, 32.97it/s]     98%|█████████▊| 590/600 [00:19<00:00, 32.91it/s]     99%|█████████▉| 594/600 [00:19<00:00, 33.10it/s]    100%|█████████▉| 598/600 [00:19<00:00, 32.84it/s]    100%|██████████| 600/600 [00:19<00:00, 31.04it/s]




.. GENERATED FROM PYTHON SOURCE LINES 172-177

.. video:: ../../../examples/CatenaryCase/catenary.mp4
   :width: 720
   :autoplay:
   :muted:
   :loop:

.. GENERATED FROM PYTHON SOURCE LINES 179-180

plotting the catenary positions after simulation.

.. GENERATED FROM PYTHON SOURCE LINES 180-185

.. code-block:: Python

    plot_catenary(
        recorded_history,
        xlim=(0, base_length),
        ylim=(b, 0.0),
    )



.. image-sg:: /_gallery/CatenaryCase/images/sphx_glr_run_catenary_001.png
   :alt: Catenary Final Shape
   :srcset: /_gallery/CatenaryCase/images/sphx_glr_run_catenary_001.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (1 minutes 10.619 seconds)


.. _sphx_glr_download__gallery_CatenaryCase_run_catenary.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: run_catenary.ipynb <run_catenary.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: run_catenary.py <run_catenary.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: run_catenary.zip <run_catenary.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
