.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/elements/combin14/example_spring_reference_geometry.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_spring_reference_geometry.py: SPRING — 2-node longitudinal spring stiffness ============================================== The 2-node 3D longitudinal spring carries an axial-only stiffness :math:`k` between two nodes connected by a unit direction vector :math:`\hat d = (l, m, n)`. No mass. Three translational DOFs per node, 6 DOFs per element. Local axial-only stiffness on the natural coordinate :math:`s \in [-1, +1]`: .. math:: K_\text{local} = k \begin{bmatrix} +1 & -1 \\ -1 & +1 \end{bmatrix}, embedded in 3D via the direction-cosine block :math:`T = \hat d\, \hat d^{\!\top}`: .. math:: K_e = k \begin{bmatrix} +T & -T \\ -T & +T \end{bmatrix}. References ---------- * Cook, R. D., Malkus, D. S., Plesha, M. E., Witt, R. J. (2002) *Concepts and Applications of Finite Element Analysis*, 4th ed., Wiley, §3.2. * Przemieniecki, J. S. (1968) *Theory of Matrix Structural Analysis*, McGraw-Hill, §3. Implementation: :class:`femorph_solver.elements.spring.Spring`. .. GENERATED FROM PYTHON SOURCE LINES 34-40 .. code-block:: Python from __future__ import annotations import numpy as np import pyvista as pv .. GENERATED FROM PYTHON SOURCE LINES 41-43 2-node spring, drawn along an arbitrary direction ------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 43-66 .. code-block:: Python # Pick a non-axial direction so the figure shows the rotation # from local to global axis. end_a = np.array([0.0, 0.0, 0.0]) end_b = np.array([1.0, 0.6, 0.4]) length = float(np.linalg.norm(end_b - end_a)) direction = (end_b - end_a) / length # Spring as a coil polyline along the I→J axis. n_turns = 8 n_pts = 240 t = np.linspace(0.0, 1.0, n_pts) axial = end_a + np.outer(t, end_b - end_a) # Build two perpendicular vectors to ``direction`` for the coil radius. ref = np.array([0.0, 0.0, 1.0]) if abs(direction[2]) < 0.9 else np.array([1.0, 0.0, 0.0]) e1 = np.cross(direction, ref) e1 /= np.linalg.norm(e1) e2 = np.cross(direction, e1) coil_radius = 0.05 * length phase = 2.0 * np.pi * n_turns * t coil = axial + coil_radius * np.outer(np.cos(phase), e1) + coil_radius * np.outer(np.sin(phase), e2) coil_pd = pv.lines_from_points(coil) .. GENERATED FROM PYTHON SOURCE LINES 67-68 Render .. GENERATED FROM PYTHON SOURCE LINES 68-86 .. code-block:: Python plotter = pv.Plotter(off_screen=True, window_size=(640, 360)) plotter.add_mesh( coil_pd, color="#1f77b4", line_width=2.5, label="k between nodes I and J (k = const)" ) plotter.add_points( np.vstack([end_a, end_b]), render_points_as_spheres=True, point_size=18, color="black", label="nodes I, J", ) plotter.add_axes(line_width=4, color="black") plotter.view_isometric() plotter.camera.zoom(1.1) plotter.add_legend(face=None, size=(0.30, 0.10), bcolor="white") plotter.show() .. image-sg:: /gallery/elements/combin14/images/sphx_glr_example_spring_reference_geometry_001.png :alt: example spring reference geometry :srcset: /gallery/elements/combin14/images/sphx_glr_example_spring_reference_geometry_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 87-93 Verify the global stiffness assembly ------------------------------------ Symbolic check that ``K_e = k [[+T, -T], [-T, +T]]`` matches what the Cook §3.2 derivation predicts on this direction vector. .. GENERATED FROM PYTHON SOURCE LINES 93-111 .. code-block:: Python k = 1.0e3 T = np.outer(direction, direction) K_e = np.block([[+k * T, -k * T], [-k * T, +k * T]]) # Sanity — moving the I node by -d (away from J along the axis) # stretches the spring by 1 m. ``K_e @ u`` returns the *external* # load that produces that displacement: pull on I in -d (force # magnitude k) and push on J in +d (force magnitude k). The # internal restoring force is the negative of those. u = np.zeros(6) u[0:3] = -direction f_ext = K_e @ u np.testing.assert_allclose(f_ext[0:3], -k * direction, atol=1e-12) np.testing.assert_allclose(f_ext[3:6], +k * direction, atol=1e-12) print(f"K_e on direction d = {direction.round(4)}:") print(f" k = {k:.0f} N/m") print(" external load to displace I by -d: F_I = -k d, F_J = +k d ✓") .. rst-class:: sphx-glr-script-out .. code-block:: none K_e on direction d = [0.8111 0.4867 0.3244]: k = 1000 N/m external load to displace I by -d: F_I = -k d, F_J = +k d ✓ .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.136 seconds) .. _sphx_glr_download_gallery_elements_combin14_example_spring_reference_geometry.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: example_spring_reference_geometry.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: example_spring_reference_geometry.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: example_spring_reference_geometry.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_