
.. 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:31, 18.89it/s]      1%|          | 6/600 [00:00<00:21, 28.20it/s]      2%|▏         | 10/600 [00:00<00:17, 32.82it/s]      2%|▏         | 14/600 [00:00<00:17, 33.95it/s]      3%|▎         | 18/600 [00:00<00:16, 34.80it/s]      4%|▎         | 22/600 [00:00<00:15, 36.28it/s]      4%|▍         | 26/600 [00:00<00:15, 37.29it/s]      5%|▌         | 30/600 [00:00<00:14, 38.11it/s]      6%|▌         | 34/600 [00:00<00:14, 38.54it/s]      6%|▋         | 38/600 [00:01<00:14, 38.74it/s]      7%|▋         | 42/600 [00:01<00:14, 38.97it/s]      8%|▊         | 46/600 [00:01<00:14, 37.29it/s]      8%|▊         | 50/600 [00:01<00:22, 24.18it/s]      9%|▉         | 54/600 [00:01<00:21, 25.71it/s]     10%|▉         | 58/600 [00:01<00:20, 26.21it/s]     10%|█         | 61/600 [00:01<00:20, 26.35it/s]     11%|█         | 64/600 [00:02<00:20, 26.13it/s]     11%|█         | 67/600 [00:02<00:19, 26.73it/s]     12%|█▏        | 70/600 [00:02<00:19, 27.09it/s]     12%|█▏        | 73/600 [00:02<00:19, 26.37it/s]     13%|█▎        | 76/600 [00:02<00:19, 26.78it/s]     13%|█▎        | 79/600 [00:02<00:19, 27.42it/s]     14%|█▎        | 82/600 [00:02<00:18, 28.10it/s]     14%|█▍        | 86/600 [00:02<00:17, 28.83it/s]     15%|█▍        | 89/600 [00:02<00:18, 27.70it/s]     15%|█▌        | 92/600 [00:03<00:18, 28.02it/s]     16%|█▌        | 96/600 [00:03<00:17, 28.13it/s]     17%|█▋        | 100/600 [00:03<00:17, 28.19it/s]     17%|█▋        | 104/600 [00:03<00:17, 28.30it/s]     18%|█▊        | 107/600 [00:03<00:17, 28.19it/s]     18%|█▊        | 110/600 [00:03<00:17, 28.57it/s]     19%|█▉        | 114/600 [00:03<00:16, 29.13it/s]     20%|█▉        | 118/600 [00:03<00:15, 30.16it/s]     20%|██        | 122/600 [00:04<00:16, 29.04it/s]     21%|██        | 126/600 [00:04<00:16, 29.07it/s]     22%|██▏       | 130/600 [00:04<00:15, 29.46it/s]     22%|██▏       | 133/600 [00:04<00:16, 29.02it/s]     23%|██▎       | 136/600 [00:04<00:16, 28.85it/s]     23%|██▎       | 140/600 [00:04<00:15, 29.37it/s]     24%|██▍       | 144/600 [00:04<00:15, 30.04it/s]     25%|██▍       | 148/600 [00:04<00:14, 30.65it/s]     25%|██▌       | 152/600 [00:05<00:14, 30.33it/s]     26%|██▌       | 156/600 [00:05<00:14, 31.03it/s]     27%|██▋       | 160/600 [00:05<00:14, 30.63it/s]     27%|██▋       | 164/600 [00:05<00:14, 30.90it/s]     28%|██▊       | 168/600 [00:05<00:14, 30.82it/s]     29%|██▊       | 172/600 [00:05<00:14, 30.45it/s]     29%|██▉       | 176/600 [00:05<00:13, 30.52it/s]     30%|███       | 180/600 [00:06<00:13, 30.55it/s]     31%|███       | 184/600 [00:06<00:13, 30.29it/s]     31%|███▏      | 188/600 [00:06<00:13, 30.17it/s]     32%|███▏      | 192/600 [00:06<00:13, 30.14it/s]     33%|███▎      | 196/600 [00:06<00:13, 30.87it/s]     33%|███▎      | 200/600 [00:06<00:12, 30.96it/s]     34%|███▍      | 204/600 [00:06<00:12, 30.95it/s]     35%|███▍      | 208/600 [00:06<00:12, 30.72it/s]     35%|███▌      | 212/600 [00:07<00:12, 30.92it/s]     36%|███▌      | 216/600 [00:07<00:12, 31.01it/s]     37%|███▋      | 220/600 [00:07<00:12, 30.67it/s]     37%|███▋      | 224/600 [00:07<00:12, 30.68it/s]     38%|███▊      | 228/600 [00:07<00:12, 30.73it/s]     39%|███▊      | 232/600 [00:07<00:12, 30.61it/s]     39%|███▉      | 236/600 [00:07<00:11, 30.63it/s]     40%|████      | 240/600 [00:07<00:11, 30.74it/s]     41%|████      | 244/600 [00:08<00:11, 30.56it/s]     41%|████▏     | 248/600 [00:08<00:11, 30.73it/s]     42%|████▏     | 252/600 [00:08<00:11, 31.06it/s]     43%|████▎     | 256/600 [00:08<00:10, 31.33it/s]     43%|████▎     | 260/600 [00:08<00:10, 31.53it/s]     44%|████▍     | 264/600 [00:08<00:10, 31.76it/s]     45%|████▍     | 268/600 [00:08<00:10, 31.88it/s]     45%|████▌     | 272/600 [00:08<00:10, 31.86it/s]     46%|████▌     | 276/600 [00:09<00:10, 32.00it/s]     47%|████▋     | 280/600 [00:09<00:10, 31.94it/s]     47%|████▋     | 284/600 [00:09<00:09, 31.99it/s]     48%|████▊     | 288/600 [00:09<00:09, 31.88it/s]     49%|████▊     | 292/600 [00:09<00:09, 31.28it/s]     49%|████▉     | 296/600 [00:09<00:09, 31.50it/s]     50%|█████     | 300/600 [00:09<00:09, 31.97it/s]     51%|█████     | 304/600 [00:09<00:09, 32.15it/s]     51%|█████▏    | 308/600 [00:10<00:09, 32.05it/s]     52%|█████▏    | 312/600 [00:10<00:08, 32.13it/s]     53%|█████▎    | 316/600 [00:10<00:08, 32.05it/s]     53%|█████▎    | 320/600 [00:10<00:08, 32.25it/s]     54%|█████▍    | 324/600 [00:10<00:08, 32.14it/s]     55%|█████▍    | 328/600 [00:10<00:08, 32.45it/s]     55%|█████▌    | 332/600 [00:10<00:08, 32.04it/s]     56%|█████▌    | 336/600 [00:10<00:08, 32.04it/s]     57%|█████▋    | 340/600 [00:11<00:08, 32.00it/s]     57%|█████▋    | 344/600 [00:11<00:08, 31.92it/s]     58%|█████▊    | 348/600 [00:11<00:07, 31.69it/s]     59%|█████▊    | 352/600 [00:11<00:07, 31.92it/s]     59%|█████▉    | 356/600 [00:11<00:07, 31.75it/s]     60%|██████    | 360/600 [00:11<00:07, 31.79it/s]     61%|██████    | 364/600 [00:11<00:07, 31.68it/s]     61%|██████▏   | 368/600 [00:11<00:07, 32.19it/s]     62%|██████▏   | 372/600 [00:12<00:07, 32.01it/s]     63%|██████▎   | 376/600 [00:12<00:06, 32.06it/s]     63%|██████▎   | 380/600 [00:12<00:06, 31.71it/s]     64%|██████▍   | 384/600 [00:12<00:06, 31.76it/s]     65%|██████▍   | 388/600 [00:12<00:06, 31.80it/s]     65%|██████▌   | 392/600 [00:12<00:06, 31.75it/s]     66%|██████▌   | 396/600 [00:12<00:06, 31.71it/s]     67%|██████▋   | 400/600 [00:13<00:06, 32.04it/s]     67%|██████▋   | 404/600 [00:13<00:06, 32.12it/s]     68%|██████▊   | 408/600 [00:13<00:05, 32.14it/s]     69%|██████▊   | 412/600 [00:13<00:05, 31.69it/s]     69%|██████▉   | 416/600 [00:13<00:05, 31.50it/s]     70%|███████   | 420/600 [00:13<00:05, 31.23it/s]     71%|███████   | 424/600 [00:13<00:05, 31.40it/s]     71%|███████▏  | 428/600 [00:13<00:05, 31.49it/s]     72%|███████▏  | 432/600 [00:14<00:05, 31.49it/s]     73%|███████▎  | 436/600 [00:14<00:05, 31.61it/s]     73%|███████▎  | 440/600 [00:14<00:05, 31.58it/s]     74%|███████▍  | 444/600 [00:14<00:04, 31.28it/s]     75%|███████▍  | 448/600 [00:14<00:04, 31.88it/s]     75%|███████▌  | 452/600 [00:14<00:04, 31.94it/s]     76%|███████▌  | 456/600 [00:14<00:04, 32.04it/s]     77%|███████▋  | 460/600 [00:14<00:04, 32.09it/s]     77%|███████▋  | 464/600 [00:15<00:04, 32.00it/s]     78%|███████▊  | 468/600 [00:15<00:04, 31.65it/s]     79%|███████▊  | 472/600 [00:15<00:04, 31.71it/s]     79%|███████▉  | 476/600 [00:15<00:03, 31.28it/s]     80%|████████  | 480/600 [00:15<00:03, 31.35it/s]     81%|████████  | 484/600 [00:15<00:03, 31.52it/s]     81%|████████▏ | 488/600 [00:15<00:03, 32.16it/s]     82%|████████▏ | 492/600 [00:15<00:03, 32.68it/s]     83%|████████▎ | 496/600 [00:16<00:03, 32.17it/s]     83%|████████▎ | 500/600 [00:16<00:03, 31.91it/s]     84%|████████▍ | 504/600 [00:16<00:02, 32.05it/s]     85%|████████▍ | 508/600 [00:16<00:02, 31.83it/s]     85%|████████▌ | 512/600 [00:16<00:02, 31.59it/s]     86%|████████▌ | 516/600 [00:16<00:02, 31.97it/s]     87%|████████▋ | 520/600 [00:16<00:02, 31.84it/s]     87%|████████▋ | 524/600 [00:16<00:02, 31.93it/s]     88%|████████▊ | 528/600 [00:17<00:02, 32.04it/s]     89%|████████▊ | 532/600 [00:17<00:02, 32.40it/s]     89%|████████▉ | 536/600 [00:17<00:01, 32.14it/s]     90%|█████████ | 540/600 [00:17<00:01, 31.81it/s]     91%|█████████ | 544/600 [00:17<00:01, 31.63it/s]     91%|█████████▏| 548/600 [00:17<00:01, 30.97it/s]     92%|█████████▏| 552/600 [00:17<00:01, 31.36it/s]     93%|█████████▎| 556/600 [00:17<00:01, 32.18it/s]     93%|█████████▎| 560/600 [00:18<00:01, 31.40it/s]     94%|█████████▍| 564/600 [00:18<00:01, 32.17it/s]     95%|█████████▍| 568/600 [00:18<00:01, 31.89it/s]     95%|█████████▌| 572/600 [00:18<00:00, 31.85it/s]     96%|█████████▌| 576/600 [00:18<00:00, 32.20it/s]     97%|█████████▋| 580/600 [00:18<00:00, 31.68it/s]     97%|█████████▋| 584/600 [00:18<00:00, 32.41it/s]     98%|█████████▊| 588/600 [00:18<00:00, 32.96it/s]     99%|█████████▊| 592/600 [00:19<00:00, 32.41it/s]     99%|█████████▉| 596/600 [00:19<00:00, 32.25it/s]    100%|██████████| 600/600 [00:19<00:00, 32.22it/s]    100%|██████████| 600/600 [00:19<00:00, 31.13it/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.076 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>`_
