.. 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: SPRING — two springs in series ================================ Three co-linear nodes joined by two SPRING 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-22 .. code-block:: Python from __future__ import annotations import numpy as np import pyvista as pv from vtkmodules.util.vtkConstants import VTK_LINE import femorph_solver from femorph_solver import ELEMENTS .. GENERATED FROM PYTHON SOURCE LINES 23-27 Problem data ------------ Two springs. ``k1`` at half the stiffness of ``k2``; their series combination sits in between. .. GENERATED FROM PYTHON SOURCE LINES 27-33 .. 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 34-39 Build the model --------------- Three nodes along x. SPRING only carries an axial spring force; the transverse DOFs have zero stiffness and the solver's zero-pivot guard pins them automatically. .. GENERATED FROM PYTHON SOURCE LINES 39-62 .. code-block:: Python points = np.array( [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0]], dtype=np.float64, ) cells = np.array([2, 0, 1, 2, 1, 2], dtype=np.int64) cell_types = np.array([VTK_LINE, VTK_LINE], dtype=np.uint8) grid = pv.UnstructuredGrid(cells, cell_types, points) # Two real-constant ids: cell 0 uses real-id 1 (k1), cell 1 uses real-id 2 (k2). grid.cell_data["ansys_real_constant"] = np.array([1, 2], dtype=np.int32) m = femorph_solver.Model.from_grid(grid) m.assign(ELEMENTS.SPRING, real=(k1,), real_id=1) m.assign(ELEMENTS.SPRING, real=(k2,), real_id=2) m.fix(nodes=[1], dof="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.fix(nodes=[nn], dof="UY") m.fix(nodes=[nn], dof="UZ") m.apply_force(3, fx=F) .. GENERATED FROM PYTHON SOURCE LINES 63-69 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 69-81 .. 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 82-87 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 87-108 .. 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.169 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 `_