.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/elements/combin14/example_combin14.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_gallery_elements_combin14_example_combin14.py: .. _ref_combin14_example: COMBIN14 — two springs in series ================================ Three co-linear nodes joined by two COMBIN14 springs of stiffness ``k1`` and ``k2``. With the far end fixed and a tip load ``F`` the free-end displacement is ``F / k_eq`` where ``k_eq = k1 · k2 / (k1 + k2)``. .. GENERATED FROM PYTHON SOURCE LINES 12-20 .. code-block:: Python from __future__ import annotations import numpy as np import pyvista as pv import femorph_solver .. GENERATED FROM PYTHON SOURCE LINES 21-25 Problem data ------------ Two springs. ``k1`` at half the stiffness of ``k2``; their series combination sits in between. .. GENERATED FROM PYTHON SOURCE LINES 25-31 .. code-block:: Python k1 = 1000.0 # N/m k2 = 2000.0 # N/m F = 50.0 # N tip load k_eq = k1 * k2 / (k1 + k2) .. GENERATED FROM PYTHON SOURCE LINES 32-37 Build the model --------------- Three nodes along x. COMBIN14 only carries an axial spring force; the transverse DOFs have zero stiffness and the solver's zero-pivot guard pins them automatically (equivalent to MAPDL's auto-constrain warning). .. GENERATED FROM PYTHON SOURCE LINES 37-61 .. code-block:: Python m = femorph_solver.Model() m.et(1, "COMBIN14") m.r(1, k1) m.r(2, k2) m.n(1, 0.0, 0.0, 0.0) m.n(2, 1.0, 0.0, 0.0) m.n(3, 2.0, 0.0, 0.0) m.real(1) m.e(1, 2) m.real(2) m.e(2, 3) m.d(1, "ALL") # clamp node 1 # Restrain transverse translations on the free nodes so the DOFs the # solver actually keeps are just UX at nodes 2 and 3. for nn in (2, 3): m.d(nn, "UY") m.d(nn, "UZ") m.f(3, "FX", F) .. rst-class:: sphx-glr-script-out .. code-block:: none /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:38: DeprecationWarning: Model.et(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).et(et_id, name)` for line-by-line APDL deck porting, or the native `Model.assign("HEX8", material)` for new code. m.et(1, "COMBIN14") /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:40: DeprecationWarning: Model.r(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).r(real_id, *values)` for line-by-line APDL deck porting, or the native `Model.assign(element, material, real=[...])` for new code. m.r(1, k1) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:41: DeprecationWarning: Model.r(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).r(real_id, *values)` for line-by-line APDL deck porting, or the native `Model.assign(element, material, real=[...])` for new code. m.r(2, k2) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:43: DeprecationWarning: Model.n(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).n(num, x, y, z)` for line-by-line APDL deck porting, or the native `Model.from_grid(pv_grid)` for new code. m.n(1, 0.0, 0.0, 0.0) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:44: DeprecationWarning: Model.n(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).n(num, x, y, z)` for line-by-line APDL deck porting, or the native `Model.from_grid(pv_grid)` for new code. m.n(2, 1.0, 0.0, 0.0) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:45: DeprecationWarning: Model.n(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).n(num, x, y, z)` for line-by-line APDL deck porting, or the native `Model.from_grid(pv_grid)` for new code. m.n(3, 2.0, 0.0, 0.0) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:47: DeprecationWarning: Model.real(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).real(real_id)` for line-by-line APDL deck porting, or the native `Model.assign("HEX8", material, real=[...])` for new code. m.real(1) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:48: DeprecationWarning: Model.e(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).e(*node_nums)` for line-by-line APDL deck porting, or the native `Model.from_grid(pv_grid)` for new code. m.e(1, 2) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:49: DeprecationWarning: Model.real(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).real(real_id)` for line-by-line APDL deck porting, or the native `Model.assign("HEX8", material, real=[...])` for new code. m.real(2) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:50: DeprecationWarning: Model.e(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).e(*node_nums)` for line-by-line APDL deck porting, or the native `Model.from_grid(pv_grid)` for new code. m.e(2, 3) /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:52: DeprecationWarning: Model.d(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).d(node, label, value)` for line-by-line APDL deck porting, or the native `Model.fix(nodes=..., where=..., dof=...)` for new code. m.d(1, "ALL") # clamp node 1 /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:56: DeprecationWarning: Model.d(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).d(node, label, value)` for line-by-line APDL deck porting, or the native `Model.fix(nodes=..., where=..., dof=...)` for new code. m.d(nn, "UY") /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:57: DeprecationWarning: Model.d(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).d(node, label, value)` for line-by-line APDL deck porting, or the native `Model.fix(nodes=..., where=..., dof=...)` for new code. m.d(nn, "UZ") /home/runner/_work/solver/solver/examples/elements/combin14/example_combin14.py:59: DeprecationWarning: Model.f(...) is a MAPDL-dialect shortcut and has moved off the Model public surface. Use `APDL(model).f(node, label, value)` for line-by-line APDL deck porting, or the native `Model.apply_force(node, fx=..., fy=..., fz=...)` for new code. m.f(3, "FX", F) .. GENERATED FROM PYTHON SOURCE LINES 62-68 Static solve + analytical comparison ------------------------------------ With both springs in equilibrium the tip displacement must equal ``F / k_eq``. Because the springs are in series the force is the same in each and we can check the intermediate displacement too (``u2 = F / k1``). .. GENERATED FROM PYTHON SOURCE LINES 68-80 .. code-block:: Python res = m.solve() dof = m.dof_map() u2 = res.displacement[np.where((dof[:, 0] == 2) & (dof[:, 1] == 0))[0][0]] u3 = res.displacement[np.where((dof[:, 0] == 3) & (dof[:, 1] == 0))[0][0]] print(f"u at node 2 = {u2:.6e} m (expected {F / k1:.6e})") print(f"u at node 3 = {u3:.6e} m (expected {F / k_eq:.6e})") assert np.isclose(u2, F / k1, rtol=1e-12) assert np.isclose(u3, F / k_eq, rtol=1e-12) .. rst-class:: sphx-glr-script-out .. code-block:: none u at node 2 = 5.000000e-02 m (expected 5.000000e-02) u at node 3 = 7.500000e-02 m (expected 7.500000e-02) .. GENERATED FROM PYTHON SOURCE LINES 81-86 Visualise the deformation ------------------------- Build a point_data displacement vector and warp the mesh. Because the real deflection is ~7.5 cm on a 2 m baseline a modest exaggeration makes the difference between the two springs visible. .. GENERATED FROM PYTHON SOURCE LINES 86-107 .. code-block:: Python grid = m.grid.copy() displacement = np.zeros((grid.n_points, 3), dtype=np.float64) for i, nn in enumerate(grid.point_data["ansys_node_num"]): rows = np.where(dof[:, 0] == int(nn))[0] for r in rows: displacement[i, int(dof[r, 1])] = res.displacement[r] grid.point_data["displacement"] = displacement warped = grid.warp_by_vector("displacement", factor=1.0) plotter = pv.Plotter(off_screen=True) plotter.add_mesh(grid, style="wireframe", color="gray", line_width=3) plotter.add_mesh( warped, scalars=np.linalg.norm(displacement, axis=1), line_width=6, render_points_as_spheres=True, point_size=14, scalar_bar_args={"title": "|u| [m]"}, ) plotter.add_axes() plotter.show() .. image-sg:: /gallery/elements/combin14/images/sphx_glr_example_combin14_001.png :alt: example combin14 :srcset: /gallery/elements/combin14/images/sphx_glr_example_combin14_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.167 seconds) .. _sphx_glr_download_gallery_elements_combin14_example_combin14.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: example_combin14.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: example_combin14.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: example_combin14.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_