
.. 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.74it/s]      1%|          | 6/600 [00:00<00:20, 29.67it/s]      2%|▏         | 11/600 [00:00<00:16, 35.09it/s]      3%|▎         | 16/600 [00:00<00:15, 37.13it/s]      3%|▎         | 20/600 [00:00<00:15, 37.60it/s]      4%|▍         | 24/600 [00:00<00:15, 37.77it/s]      5%|▍         | 28/600 [00:00<00:14, 38.25it/s]      5%|▌         | 32/600 [00:00<00:14, 38.69it/s]      6%|▌         | 37/600 [00:00<00:14, 39.21it/s]      7%|▋         | 41/600 [00:01<00:14, 39.18it/s]      8%|▊         | 45/600 [00:01<00:14, 37.06it/s]      8%|▊         | 49/600 [00:01<00:19, 28.67it/s]      9%|▉         | 53/600 [00:01<00:20, 26.11it/s]      9%|▉         | 56/600 [00:01<00:20, 26.03it/s]     10%|▉         | 59/600 [00:01<00:20, 26.12it/s]     10%|█         | 63/600 [00:01<00:19, 27.77it/s]     11%|█         | 66/600 [00:02<00:19, 27.36it/s]     12%|█▏        | 69/600 [00:02<00:19, 27.57it/s]     12%|█▏        | 72/600 [00:02<00:18, 27.84it/s]     12%|█▎        | 75/600 [00:02<00:18, 28.01it/s]     13%|█▎        | 78/600 [00:02<00:18, 28.04it/s]     14%|█▎        | 82/600 [00:02<00:17, 29.06it/s]     14%|█▍        | 85/600 [00:02<00:18, 27.99it/s]     15%|█▍        | 88/600 [00:02<00:18, 28.11it/s]     15%|█▌        | 91/600 [00:02<00:18, 27.93it/s]     16%|█▌        | 95/600 [00:03<00:17, 28.66it/s]     16%|█▋        | 99/600 [00:03<00:17, 28.56it/s]     17%|█▋        | 103/600 [00:03<00:16, 29.44it/s]     18%|█▊        | 106/600 [00:03<00:17, 28.78it/s]     18%|█▊        | 110/600 [00:03<00:16, 29.10it/s]     19%|█▉        | 113/600 [00:03<00:16, 29.23it/s]     20%|█▉        | 117/600 [00:03<00:16, 30.00it/s]     20%|██        | 120/600 [00:03<00:16, 29.44it/s]     20%|██        | 123/600 [00:04<00:16, 28.32it/s]     21%|██        | 127/600 [00:04<00:16, 28.36it/s]     22%|██▏       | 131/600 [00:04<00:16, 28.44it/s]     22%|██▎       | 135/600 [00:04<00:15, 29.48it/s]     23%|██▎       | 138/600 [00:04<00:15, 29.27it/s]     24%|██▎       | 142/600 [00:04<00:15, 29.23it/s]     24%|██▍       | 146/600 [00:04<00:15, 30.14it/s]     25%|██▌       | 150/600 [00:04<00:14, 30.27it/s]     26%|██▌       | 154/600 [00:05<00:14, 30.72it/s]     26%|██▋       | 158/600 [00:05<00:14, 31.01it/s]     27%|██▋       | 162/600 [00:05<00:14, 31.28it/s]     28%|██▊       | 166/600 [00:05<00:14, 30.20it/s]     28%|██▊       | 170/600 [00:05<00:14, 30.63it/s]     29%|██▉       | 174/600 [00:05<00:13, 30.59it/s]     30%|██▉       | 178/600 [00:05<00:13, 30.55it/s]     30%|███       | 182/600 [00:05<00:13, 31.70it/s]     31%|███       | 186/600 [00:06<00:13, 30.95it/s]     32%|███▏      | 190/600 [00:06<00:13, 31.25it/s]     32%|███▏      | 194/600 [00:06<00:12, 31.49it/s]     33%|███▎      | 198/600 [00:06<00:12, 31.57it/s]     34%|███▎      | 202/600 [00:06<00:12, 31.60it/s]     34%|███▍      | 206/600 [00:06<00:12, 31.84it/s]     35%|███▌      | 210/600 [00:06<00:12, 31.87it/s]     36%|███▌      | 214/600 [00:07<00:12, 32.15it/s]     36%|███▋      | 218/600 [00:07<00:11, 32.22it/s]     37%|███▋      | 222/600 [00:07<00:11, 32.30it/s]     38%|███▊      | 226/600 [00:07<00:11, 32.36it/s]     38%|███▊      | 230/600 [00:07<00:11, 32.38it/s]     39%|███▉      | 234/600 [00:07<00:11, 32.38it/s]     40%|███▉      | 238/600 [00:07<00:11, 32.26it/s]     40%|████      | 242/600 [00:07<00:11, 32.12it/s]     41%|████      | 246/600 [00:08<00:11, 32.08it/s]     42%|████▏     | 250/600 [00:08<00:10, 32.27it/s]     42%|████▏     | 254/600 [00:08<00:10, 32.23it/s]     43%|████▎     | 258/600 [00:08<00:10, 31.85it/s]     44%|████▎     | 262/600 [00:08<00:10, 32.05it/s]     44%|████▍     | 266/600 [00:08<00:10, 32.15it/s]     45%|████▌     | 270/600 [00:08<00:10, 31.98it/s]     46%|████▌     | 274/600 [00:08<00:10, 31.77it/s]     46%|████▋     | 278/600 [00:09<00:10, 31.78it/s]     47%|████▋     | 282/600 [00:09<00:09, 31.96it/s]     48%|████▊     | 286/600 [00:09<00:09, 31.75it/s]     48%|████▊     | 290/600 [00:09<00:09, 32.00it/s]     49%|████▉     | 294/600 [00:09<00:09, 32.40it/s]     50%|████▉     | 298/600 [00:09<00:09, 32.24it/s]     50%|█████     | 302/600 [00:09<00:09, 31.78it/s]     51%|█████     | 306/600 [00:09<00:09, 31.57it/s]     52%|█████▏    | 310/600 [00:10<00:09, 31.80it/s]     52%|█████▏    | 314/600 [00:10<00:08, 31.78it/s]     53%|█████▎    | 318/600 [00:10<00:08, 31.63it/s]     54%|█████▎    | 322/600 [00:10<00:08, 31.90it/s]     54%|█████▍    | 326/600 [00:10<00:08, 32.23it/s]     55%|█████▌    | 330/600 [00:10<00:08, 32.03it/s]     56%|█████▌    | 334/600 [00:10<00:08, 32.49it/s]     56%|█████▋    | 338/600 [00:10<00:08, 32.40it/s]     57%|█████▋    | 342/600 [00:10<00:07, 32.64it/s]     58%|█████▊    | 346/600 [00:11<00:07, 32.72it/s]     58%|█████▊    | 350/600 [00:11<00:07, 33.08it/s]     59%|█████▉    | 354/600 [00:11<00:07, 33.31it/s]     60%|█████▉    | 358/600 [00:11<00:07, 33.12it/s]     60%|██████    | 362/600 [00:11<00:07, 33.00it/s]     61%|██████    | 366/600 [00:11<00:07, 32.78it/s]     62%|██████▏   | 370/600 [00:11<00:07, 32.55it/s]     62%|██████▏   | 374/600 [00:11<00:06, 32.68it/s]     63%|██████▎   | 378/600 [00:12<00:06, 32.53it/s]     64%|██████▎   | 382/600 [00:12<00:06, 32.34it/s]     64%|██████▍   | 386/600 [00:12<00:06, 32.34it/s]     65%|██████▌   | 390/600 [00:12<00:06, 32.48it/s]     66%|██████▌   | 394/600 [00:12<00:06, 32.78it/s]     66%|██████▋   | 398/600 [00:12<00:06, 32.82it/s]     67%|██████▋   | 402/600 [00:12<00:06, 32.80it/s]     68%|██████▊   | 406/600 [00:12<00:05, 32.77it/s]     68%|██████▊   | 410/600 [00:13<00:05, 32.68it/s]     69%|██████▉   | 414/600 [00:13<00:05, 32.58it/s]     70%|██████▉   | 418/600 [00:13<00:05, 32.77it/s]     70%|███████   | 422/600 [00:13<00:05, 32.46it/s]     71%|███████   | 426/600 [00:13<00:05, 32.43it/s]     72%|███████▏  | 430/600 [00:13<00:05, 32.96it/s]     72%|███████▏  | 434/600 [00:13<00:05, 32.51it/s]     73%|███████▎  | 438/600 [00:13<00:04, 32.57it/s]     74%|███████▎  | 442/600 [00:14<00:04, 32.68it/s]     74%|███████▍  | 446/600 [00:14<00:04, 32.55it/s]     75%|███████▌  | 450/600 [00:14<00:04, 32.59it/s]     76%|███████▌  | 454/600 [00:14<00:04, 32.51it/s]     76%|███████▋  | 458/600 [00:14<00:04, 32.31it/s]     77%|███████▋  | 462/600 [00:14<00:04, 32.06it/s]     78%|███████▊  | 466/600 [00:14<00:04, 32.67it/s]     78%|███████▊  | 470/600 [00:14<00:04, 32.28it/s]     79%|███████▉  | 474/600 [00:15<00:03, 32.25it/s]     80%|███████▉  | 478/600 [00:15<00:03, 32.28it/s]     80%|████████  | 482/600 [00:15<00:03, 32.16it/s]     81%|████████  | 486/600 [00:15<00:03, 32.45it/s]     82%|████████▏ | 490/600 [00:15<00:03, 32.67it/s]     82%|████████▏ | 494/600 [00:15<00:03, 32.65it/s]     83%|████████▎ | 498/600 [00:15<00:03, 32.32it/s]     84%|████████▎ | 502/600 [00:15<00:03, 32.04it/s]     84%|████████▍ | 506/600 [00:16<00:02, 32.33it/s]     85%|████████▌ | 510/600 [00:16<00:02, 32.36it/s]     86%|████████▌ | 514/600 [00:16<00:02, 32.35it/s]     86%|████████▋ | 518/600 [00:16<00:02, 32.47it/s]     87%|████████▋ | 522/600 [00:16<00:02, 32.48it/s]     88%|████████▊ | 526/600 [00:16<00:02, 32.38it/s]     88%|████████▊ | 530/600 [00:16<00:02, 32.68it/s]     89%|████████▉ | 534/600 [00:16<00:02, 32.64it/s]     90%|████████▉ | 538/600 [00:17<00:01, 32.45it/s]     90%|█████████ | 542/600 [00:17<00:01, 32.68it/s]     91%|█████████ | 546/600 [00:17<00:01, 31.23it/s]     92%|█████████▏| 550/600 [00:17<00:01, 31.39it/s]     92%|█████████▏| 554/600 [00:17<00:01, 31.72it/s]     93%|█████████▎| 558/600 [00:17<00:01, 32.14it/s]     94%|█████████▎| 562/600 [00:17<00:01, 32.42it/s]     94%|█████████▍| 566/600 [00:17<00:01, 32.46it/s]     95%|█████████▌| 570/600 [00:18<00:00, 32.58it/s]     96%|█████████▌| 574/600 [00:18<00:00, 32.96it/s]     96%|█████████▋| 578/600 [00:18<00:00, 33.00it/s]     97%|█████████▋| 582/600 [00:18<00:00, 32.73it/s]     98%|█████████▊| 586/600 [00:18<00:00, 32.36it/s]     98%|█████████▊| 590/600 [00:18<00:00, 32.23it/s]     99%|█████████▉| 594/600 [00:18<00:00, 32.51it/s]    100%|█████████▉| 598/600 [00:18<00:00, 32.80it/s]    100%|██████████| 600/600 [00:18<00:00, 31.69it/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 9.445 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>`_
