From 02d1b57a1bbe3ff22a5113ea0c1e48b29c04acbc Mon Sep 17 00:00:00 2001 From: Facundo-Pfeffer Date: Sun, 8 Mar 2026 15:19:27 -0700 Subject: [PATCH] Add a supporting figure for the constraint command. General documentation polishing, ensuring consistency throughout. --- source/user/manual/loading/pattern.rst | 13 +- .../manual/model/constraints/constrain.rst | 440 ++++++++++++++---- .../constrain-frame-skewed-support.png | Bin 0 -> 54164 bytes .../user/manual/model/constraints/index.rst | 3 +- source/user/manual/model/nodes/fix.rst | 12 +- source/user/manual/model/nodes/node.rst | 34 +- source/user/manual/modules/units.rst | 6 +- .../user/manual/numerics/algorithm/Newton.rst | 1 - source/user/manual/output/nodeDisp.rst | 11 +- source/user/manual/parameter/getParamTags.rst | 16 +- .../user/manual/parameter/getParamValue.rst | 21 +- source/user/manual/section/ElasticFrame.rst | 41 +- 12 files changed, 457 insertions(+), 141 deletions(-) create mode 100644 source/user/manual/model/constraints/figures/constrain-frame-skewed-support.png diff --git a/source/user/manual/loading/pattern.rst b/source/user/manual/loading/pattern.rst index 0b4e2ccd..0c9ab789 100644 --- a/source/user/manual/loading/pattern.rst +++ b/source/user/manual/loading/pattern.rst @@ -38,10 +38,11 @@ The following pattern types are available: .. toctree:: :maxdepth: 2 - pattern/plainPattern - pattern/uniformExcitationPattern - pattern/multiSupportPattern - pattern/DRM - pattern/H5DRM - timeSeries + plainPattern + uniformExcitationPattern + multiSupportPattern + DRM + H5DRM + +For time series types (Constant, Linear, Path, etc.), see :ref:`timeSeries ` in the Modeling section. diff --git a/source/user/manual/model/constraints/constrain.rst b/source/user/manual/model/constraints/constrain.rst index a15ac272..590bb56f 100644 --- a/source/user/manual/model/constraints/constrain.rst +++ b/source/user/manual/model/constraints/constrain.rst @@ -95,30 +95,24 @@ This example demonstrates the basic usage of ``constrain`` without rotation, cor The following example constrains node **5** to have the same degrees-of-freedom as node **100**. This works for both 2D and 3D problems: .. tabs:: - .. tab:: Tcl - - .. code-block:: none - - constrain 100 5 - .. tab:: Python .. code-block:: python model.constrain(100, 5) + .. tab:: Tcl + + .. code-block:: none + + constrain 100 5 + Constraint with Rotation ~~~~~~~~~~~~~~~~~~~~~~~~~ The following example constrains node **5** to node **100** with a rotation about the Y-axis. This requires a 3D model (ndm=3, ndf=6): .. tabs:: - .. tab:: Tcl - - .. code-block:: none - - constrain 100 5 -rotate {0 -0.6435 0} - .. tab:: Python .. code-block:: python @@ -127,104 +121,350 @@ The following example constrains node **5** to node **100** with a rotation abou # Negative sign rotates clockwise about Y-axis (right-hand rule) model.constrain(100, 5, rotate=[0, -angle, 0]) + .. tab:: Tcl + + .. code-block:: none + + constrain 100 5 -rotate {0 -0.6435 0} + Frame with Skewed Support ~~~~~~~~~~~~~~~~~~~~~~~~~~ This example demonstrates using ``constrain`` to model a frame with a skewed support in 3D, where the support is not aligned with the global coordinate system. +.. figure:: figures/constrain-frame-skewed-support.png + :width: 80% + :align: center + :alt: Frame with skewed support — geometry, nodes, and skewed support direction + + Frame with skewed support: geometry, dimensions (H, W), mid-span load P, and skewed support angle θ. + .. code-block:: python :linenos: import xara - from xara.units.english import inch, kip, ksi - from shps.rotor import exp - - # Geometry - H = 144.0 * inch - W = 144.0 * inch - - # Section properties - width = 12.0 * inch - height = 12.0 * inch - Iz = (width * height**3) / 12.0 - Iy = (height * width**3) / 12.0 - A = width * height - J = (width * height**3) / 3.0 - - # Material - E = 29000 * ksi - G = 11500 * ksi - nu = 0.30 - - # Load - P = -10.0 * kip - angle = 0.5 # Rotation angle in radians (about 28.6 degrees) - # Negative sign rotates clockwise about Y-axis (right-hand rule), - # rotating the support coordinate system clockwise from vertical - - # Compute rotation matrix for reaction transformation - R = exp([0.0, -angle, 0.0]) - - # Model (3D required for rotation) - model = xara.Model('basic', ndm=3, ndf=6) - - # Nodes - model.node(1, (0.0, 0.0, 0.0)) # Fixed support - model.node(2, (0.0, 0.0, H)) # Top-left - model.node(3, (W/2, 0.0, H)) # Load point - model.node(4, (W, 0.0, H)) # Top-right - model.node(5, (W, 0.0, 0.0)) # Skewed support - - # Fixed support at node 1 - model.fix(1, (1, 1, 1, 1, 1, 1)) - - # Ground node for skewed support - ground_node = 100 - model.node(ground_node, (W, 0.0, 0.0)) - model.fix(ground_node, (0, 1, 1, 0, 0, 0)) # Fixed in Y and Z, free in X - - # Apply rotated constraint: node 5 is constrained to ground_node with rotation - model.constrain((ground_node, 5), rotate=[0, -angle, 0]) - - # Frame section and elements - model.material('ElasticIsotropic', 1, E, nu) - model.section("ElasticFrame", 1, E=E, G=G, A=A, Iy=Iy, Iz=Iz, J=J) - model.geomTransf("Linear", 1, (0, 1, 0)) # Columns - model.geomTransf("Linear", 2, (0, 1, 0)) # Beams - - model.element('PrismFrame', 1, (1, 2), section=1, transform=1) - model.element('PrismFrame', 2, (2, 3), section=1, transform=2) - model.element('PrismFrame', 3, (3, 4), section=1, transform=2) - model.element('PrismFrame', 4, (4, 5), section=1, transform=1) - - # Load - model.timeSeries('Constant', 1) - model.pattern('Plain', 1, 1) - model.load(3, (0.0, 0.0, P, 0.0, 0.0, 0.0)) - - # Analysis - model.system('BandGeneral') - model.numberer('RCM') - model.constraints('Transformation') - model.integrator('LoadControl', 1.0) - model.algorithm('Newton') - model.test('Energy', 1e-8, 10) - model.analysis('Static') - model.analyze(1) - - # Results - model.reactions() - - # Reaction at fixed support (node 1) - Fz_jt1 = model.nodeReaction(1, 3) / kip - print(f"Reaction at node 1 (Z-direction): {Fz_jt1:.3f} kip") - - # Reaction at skewed support (node 5) - transform to rotated coordinate system - R4 = model.nodeReaction(5)[:3] # Get translational reactions (X, Y, Z) - r4 = R.T @ R4 / kip # Transform to rotated coordinate system - F3_jt4 = r4[2] # Z-component in rotated coordinate system - print(f"Reaction at skewed support (node 5, normal direction): {F3_jt4:.3f} kip") +from xara.units.english import inch, kip, ksi +from math import atan2 +import numpy as np +import veux +from shps.rotor import exp + + +# Geometry +H = 144.0 * inch +W = 144.0 * inch + +# Section properties +width = 12.0 * inch +height = 12.0 * inch +Iz = (width * height**3) / 12.0 +Iy = (height * width**3) / 12.0 +A = width * height +J = (width * height**3) / 3.0 + +# Material +E = 29000 * ksi +G = 11500 * ksi +nu = 0.30 + +k_penalty = 1.0e10 * kip / inch + +# Load +P = -10.0 * kip +angle = atan2(0.6, 0.8) # 0.6435011088 # radians + + + +Reference = { + (1, 2): 5.811, + (4, 2): 5.236 +} + +expected_Fz_jt1 = 5.811 +expected_F3_jt4 = 5.236 + + +def error(value, reference): + return abs(value - reference) / reference * 100.0 + + + +def run_penalty_2d(): + # Model + model = xara.Model('basic', ndm=2, ndf=3) + + # Nodes + model.node(1, (0.0, 0.0)) # Fixed support + model.node(2, (0.0, H)) # Top-left + model.node(3, (W/2, H)) # Load point + model.node(4, (W, H)) # Top-right + model.node(5, (W, 0.0)) # Skewed support + + # Fixed support at node 1 + model.fix(1, (1, 1, 1)) + + # Skewed support at node 5 using penalty method + cos_theta = 0.8 + sin_theta = 0.6 + + R = exp([0.0, 0.0, angle]) + ground_node = 100 + model.node(ground_node, (W, 0.0)) + model.fix(ground_node, (1, 1, 1)) + + k_penalty = 1.0e10 * kip / inch + model.uniaxialMaterial('Elastic', 1001, k_penalty) + + # Normal direction for constraint + nx, ny, = R[:2,0] + tx, ty = cos_theta, sin_theta + + model.element('zeroLength', 1001, (ground_node, 5), + mat=1001, + dir=2, + orient=(nx, ny, 0.0, tx, ty, 0.0)) + + # Frame section and elements + model.material('ElasticIsotropic', 1, E, nu) + model.section("ElasticFrame", 1, E=E, G=G, A=A, Iy=Iy, Iz=Iz, J=J) + model.geomTransf("Linear", 1) + + model.element('PrismFrame', 1, (1, 2), section=1, transform=1) + model.element('PrismFrame', 2, (2, 3), section=1, transform=1) + model.element('PrismFrame', 3, (3, 4), section=1, transform=1) + model.element('PrismFrame', 4, (4, 5), section=1, transform=1) + + # Load + model.timeSeries('Constant', 1) + model.pattern('Plain', 1, 1) + model.load(3, (0.0, P, 0.0)) + + # Analysis + model.system('BandGeneral') + model.numberer('RCM') + model.constraints('Transformation') + model.integrator('LoadControl', 1.0) + model.algorithm('Newton') + model.test('Energy', 1e-10, 10) + model.analysis('Static') + model.analyze(1) + + + # Results + + print("\n" + "="*60) + print("Model E: Skewed Support - Example 1-005e") + print("="*60) + + # Reactions + model.reactions() + Fz_jt1 = model.nodeReaction(1, 2)/kip + R4 = model.nodeReaction(ground_node)[:2] + r4 = R[:2,:2].T @ R4 / kip + F3_jt4 = r4[1] + + + # Verification + print("\n" + "-"*60) + print("Verification against Example 1-005e:") + print("-"*60) + + error_Fz = error(Fz_jt1, expected_Fz_jt1)*100 + error_F3 = error(F3_jt4, expected_F3_jt4)*100 + + print(f" Fz (jt. 1): {Fz_jt1:8.3f} kip (expected {expected_Fz_jt1:.3f}) Error: {error_Fz:.2f}%") + print(f" F3 (jt. 4): {F3_jt4:8.3f} kip (expected {expected_F3_jt4:.3f}) Error: {error_F3:.2f}%") + + if error_Fz < 1.0 and error_F3 < 1.0: + print("\nPASSED") + else: + print("\nFAILED") + + print("="*60) + + +def run_penalty_3d(): + # Model + + model = xara.Model('basic', ndm=3, ndf=6) + + # Nodes + model.node(1, (0.0, 0.0, 0.0)) # Fixed support + model.node(2, (0.0, 0.0, H)) # Top-left + model.node(3, (W/2, 0.0, H)) # Load point + model.node(4, (W, 0.0, H)) # Top-right + model.node(5, (W, 0.0, 0.0)) # Skewed support + + # Fixed support at node 1 + model.fix(1, (1, 1, 1, 1, 1, 1)) + + # Skewed support at node 5 using penalty method + + R = exp([0.0, -angle, 0.0]) + ground_node = 100 + model.node(ground_node, (W, 0.0, 0.0)) + model.fix(ground_node, (1, 1, 1, 1, 1, 1)) + + model.uniaxialMaterial('Elastic', 1001, k_penalty) + + # Normal direction for constraint + nx, ny, nz = R[:,0] # == R @ [1, 0, 0] == R*Ex + tx, ty, tz = R[:,1] + + model.element('zeroLength', 1001, (ground_node, 5), + mat=1001, + dir=3, + orient=(nx, ny, nz, tx, ty, tz)) + + # Frame section and elements + model.material('ElasticIsotropic', 1, E, nu) + model.section("ElasticFrame", 1, E=E, G=G, A=A, Iy=Iy, Iz=Iz, J=J) + model.geomTransf("Linear", 1, (0, 1, 0)) # Columns + model.geomTransf("Linear", 2, (0, 1, 0)) # Beams + + model.element('PrismFrame', 1, (1, 2), section=1, transform=1) + model.element('PrismFrame', 2, (2, 3), section=1, transform=2) + model.element('PrismFrame', 3, (3, 4), section=1, transform=2) + model.element('PrismFrame', 4, (4, 5), section=1, transform=1) + + # Load + model.timeSeries('Constant', 1) + model.pattern('Plain', 1, 1) + model.load(3, (0.0, 0.0, P, 0.0, 0.0, 0.0)) + + # Analysis + model.system('BandGeneral') + model.numberer('RCM') + model.integrator('LoadControl', 1.0) + model.algorithm('Newton') + model.test('Energy', 1e-8, 10) + model.analysis('Static') + model.analyze(1) + + + # Results + + print("\n" + "="*60) + print("Model E: Skewed Support - Example 1-005e") + print("="*60) + + # Reactions + model.reactions() + Fz_jt1 = model.nodeReaction(1, 3)/kip + R4 = model.nodeReaction(ground_node)[:3] + r4 = R.T @ R4 / kip + F3_jt4 = r4[2] + + + # Verification + print("\n" + "-"*60) + print("Verification against Example 1-005e:") + print("-"*60) + + error_Fz = error(Fz_jt1, expected_Fz_jt1)*100 + error_F3 = error(F3_jt4, expected_F3_jt4)*100 + + print(f" Fz (jt. 1): {Fz_jt1:8.3f} kip (expected {expected_Fz_jt1:.3f}) Error: {error_Fz:.2f}%") + print(f" F3 (jt. 4): {F3_jt4:8.3f} kip (expected {expected_F3_jt4:.3f}) Error: {error_F3:.2f}%") + + if error_Fz < 1.0 and error_F3 < 1.0: + print("\nPASSED") + else: + print("\nFAILED") + + +def run_constrain_3d(constraint_solver): + # Model + + model = xara.Model('basic', ndm=3, ndf=6) + + # Nodes + model.node(1, (0.0, 0.0, 0.0)) # Fixed support + model.node(2, (0.0, 0.0, H)) # Top-left + model.node(3, (W/2, 0.0, H)) # Load point + model.node(4, (W, 0.0, H)) # Top-right + model.node(5, (W, 0.0, 0.0)) # Skewed support + + # Fixed support at node 1 + model.fix(1, (1, 1, 1, 1, 1, 1)) + + # Skewed support at node 5 using penalty method + + R = exp([0.0, -angle, 0.0]) + ground_node = 100 + model.node(ground_node, (W, 0.0, 0.0)) + model.fix(ground_node, (0, 1, 1, 0, 0, 0)) + + + model.constrain((ground_node, 5), rotate=[0, -angle, 0]) + + # Frame section and elements + model.material('ElasticIsotropic', 1, E, nu) + model.section("ElasticFrame", 1, E=E, G=G, A=A, Iy=Iy, Iz=Iz, J=J) + model.geomTransf("Linear", 1, (0, 1, 0)) # Columns + model.geomTransf("Linear", 2, (0, 1, 0)) # Beams + + model.element('PrismFrame', 1, (1, 2), section=1, transform=1) + model.element('PrismFrame', 2, (2, 3), section=1, transform=2) + model.element('PrismFrame', 3, (3, 4), section=1, transform=2) + model.element('PrismFrame', 4, (4, 5), section=1, transform=1) + + # Load + model.timeSeries('Constant', 1) + model.pattern('Plain', 1, 1) + model.load(3, (0.0, 0.0, P, 0.0, 0.0, 0.0)) + + # Analysis + model.system('BandGeneral') + model.numberer('RCM') + model.constraints(constraint_solver) + model.integrator('LoadControl', 1.0) + model.algorithm('Newton') + model.test('Energy', 1e-8, 10) + model.analysis('Static') + model.analyze(1) + + + # Results + + print("\n" + "="*60) + print("Model E: Skewed Support - Example 1-005e") + print("="*60) + + # Reactions + model.reactions() + Fz_jt1 = model.nodeReaction(1, 3)/kip + R4 = model.nodeReaction(5)[:3] + r4 = R.T @ R4 / kip + F3_jt4 = r4[2] + print(f"R4: {R4}, r4: {r4}") + + + # Verification + print("\n" + "-"*60) + print("Verification against Example 1-005e:") + print("-"*60) + + error_Fz = error(Fz_jt1, expected_Fz_jt1)*100 + error_F3 = error(F3_jt4, expected_F3_jt4)*100 + + print(f" Fz (jt. 1): {Fz_jt1:8.3f} kip (expected {expected_Fz_jt1:.3f}) Error: {error_Fz:.2f}%") + print(f" F3 (jt. 4): {F3_jt4:8.3f} kip (expected {expected_F3_jt4:.3f}) Error: {error_F3:.2f}%") + + if error_Fz < 1.0 and error_F3 < 1.0: + print("\nPASSED") + else: + print("\nFAILED") + + print("="*60) + + +if __name__ == "__main__": + run_penalty_2d() + run_penalty_3d() + run_constrain_3d('Transformation') + run_constrain_3d('Auto') References ---------- diff --git a/source/user/manual/model/constraints/figures/constrain-frame-skewed-support.png b/source/user/manual/model/constraints/figures/constrain-frame-skewed-support.png new file mode 100644 index 0000000000000000000000000000000000000000..1814e9e861a9a725a8756a24042fc753282a2216 GIT binary patch literal 54164 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℘jF&5xlyIw*yt*pQxia=5 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 b{4!li(VYp$jef9*CY||DMLzzd?!*5B&Ji_S literal 0 HcmV?d00001 diff --git a/source/user/manual/model/constraints/index.rst b/source/user/manual/model/constraints/index.rst index b4a8a842..4ab8079e 100644 --- a/source/user/manual/model/constraints/index.rst +++ b/source/user/manual/model/constraints/index.rst @@ -3,7 +3,7 @@ Constraints *********** -*Multi-point constraints* are constraints that allow the user to define the relationship between the response of a set of the degrees-of-freedom at one node (the constrained node) in relation to the response of the degrees-of-freedom at another node (the retained node). +*Multi-point constraints* (MP_Constraints) are constraints that allow the user to define the relationship between the response of a set of the degrees-of-freedom at one node (the constrained node) in relation to the response of the degrees-of-freedom at another node (the retained node). In structural analysis MP_Constraints are used to enforce rigid-diaphragm constraints, equal constraints (response of degrees-of-freedom at two nodes move the same), or rotated constraints (response of degrees-of-freedom at two nodes related through a rotation matrix). @@ -12,7 +12,6 @@ In structural analysis MP_Constraints are used to enforce rigid-diaphragm constr constrain equalDOF - constrain diaphragm rigidLink diff --git a/source/user/manual/model/nodes/fix.rst b/source/user/manual/model/nodes/fix.rst index 0b0fdd79..adcd2aa3 100644 --- a/source/user/manual/model/nodes/fix.rst +++ b/source/user/manual/model/nodes/fix.rst @@ -4,6 +4,8 @@ fix ^^^ This command is used to construct a number of single-point homogeneous boundary constraints. +Each constrained degree of freedom is assigned a fixed boolean integer value (0 or 1). +Single-point constraints are enforced during the solution and reduce the number of free (unknown) degrees of freedom. .. tabs:: @@ -39,7 +41,15 @@ This command is used to construct a number of single-point homogeneous boundary | 1 constrained (or fixed)" -Example +Theory +------ + +Single-point constraints (SP_Constraints) set the value of selected degrees of freedom at a node. +For ``fix``, the value is homogeneous (zero): the specified DOFs are constrained to zero displacement (and zero rotation for rotational DOFs). +The constraint flags are a tuple of length :py:attr:`Model.ndf`: ``1`` means the DOF is fixed, ``0`` means it is free. +The resulting constrained equations are eliminated or transformed depending on the :ref:`constraint handler ` used in the analysis. + +Example ------- The following examples demonstrate the commands in a script to add homogeneous boundary conditions diff --git a/source/user/manual/model/nodes/node.rst b/source/user/manual/model/nodes/node.rst index af42974f..fec37f05 100644 --- a/source/user/manual/model/nodes/node.rst +++ b/source/user/manual/model/nodes/node.rst @@ -3,8 +3,9 @@ Node **** -This method is used to construct a ``Node`` which stores information about coordinates and mass at a single point. +This method is used to construct a ``Node`` which stores information about coordinates and mass at a single point. The assignment of mass is optional. +Each node has :py:attr:`Model.ndm` coordinates (position in space) and :py:attr:`Model.ndf` degrees of freedom (displacement and, in 2D/3D frame models, rotation). .. tabs:: @@ -14,7 +15,7 @@ The assignment of mass is optional. :param tag: integer tag identifying node :param coords: tuple of :py:attr:`Model.ndm` |float| coordinates - :param mass: tuple of :py:attr:`Model.ndf` nodal mass values + :param mass: tuple of :py:attr:`Model.ndf` lumped mass values per DOF (see Theory for units and interpretation) .. tab:: Tcl @@ -27,16 +28,31 @@ The assignment of mass is optional. $tag, |integer|, unique tag identifying node $coords, |listFloat|, **ndm** nodal coordinates - $mass, |listFloat|, optional **ndf** nodal mass values + $mass, |listFloat|, optional **ndf** lumped mass values per DOF (see Theory for units) +Theory +------ + +Nodes define the spatial discretization of the model: they carry coordinates (in the global system) and optional lumped mass. +The number of coordinates is **ndm** (number of dimensions); the number of degrees of freedom per node is **ndf** (typically ndm for trusses, ndm + rotational DOFs for frames). +See :ref:`nodeDisp` for the ordering of displacement components (u1, u2, u3, r1, r2, r3 in 3D). + +**Units.** xara does not assume or enforce any unit system. +All numeric inputs (coordinates, mass, forces, etc.) are unitless; the user must choose and maintain a consistent unit system throughout the model. +See :ref:`units` for predefined constants and supported systems. + +**Mass.** When the ``mass`` argument is provided, it is a tuple of **ndf** values: lumped mass (or rotational inertia) per degree of freedom, in the mass units of the chosen system (e.g. kg in SI, slug in fps). +For a 2D model with ndf=3, the first two values are translational mass for u1 and u2; the third is rotational inertia for r3. +A value of zero means no mass or inertia for that DOF. + Example ------- -The following example adds two nodes to a :class:`Model` with an ``ndm`` of ``2`` and a ``ndf`` of 3. -The two nodes to be added have node tags ``3`` and ``4``. -Node ``3`` is located at coordinates (168.0, 144.0) and node ``4`` at location ``(168.0,144.0)``. -Node ``4`` is assigned a mass of ``(10.0, 10.0, 0.)``. +The following example adds two nodes to a :class:`Model` with ``ndm=2`` and ``ndf=3``. +Node ``3`` is at coordinates (168.0, 0.0), node ``4`` at (168.0, 144.0). +Node ``4`` is assigned lumped mass ``(10.0, 10.0, 0.0)``: 10.0 for translational DOFs 1 and 2, and 0.0 for rotational DOF 3. +Units are those of the user's chosen system (e.g. kg in SI); see :ref:`units`. .. tabs:: @@ -45,8 +61,8 @@ Node ``4`` is assigned a mass of ``(10.0, 10.0, 0.)``. .. code-block:: python - model.node(3, (168.0, 0.0)) - model.node(4, (168.0, 0.0), mass=(10.0, 10.0, 0.0)) + model.node(3, (168.0, 0.0)) + model.node(4, (168.0, 144.0), mass=(10.0, 10.0, 0.0)) .. tab:: Tcl diff --git a/source/user/manual/modules/units.rst b/source/user/manual/modules/units.rst index 54e25bec..ddf21a0e 100644 --- a/source/user/manual/modules/units.rst +++ b/source/user/manual/modules/units.rst @@ -1,7 +1,11 @@ +.. _units: + Units ^^^^^ -The *xara.units* submodule contains predefined constants that can help with keeping track of units. +xara does not assume or enforce any unit system. +All model inputs (coordinates, mass, forces, stiffness, etc.) are numeric values; the user must choose a consistent unit system and apply it throughout the model. +The *xara.units* submodule contains predefined constants that can help with keeping track of units, ensuring consistency. Systems ======= diff --git a/source/user/manual/numerics/algorithm/Newton.rst b/source/user/manual/numerics/algorithm/Newton.rst index 69221706..d24582f1 100644 --- a/source/user/manual/numerics/algorithm/Newton.rst +++ b/source/user/manual/numerics/algorithm/Newton.rst @@ -105,5 +105,4 @@ The following examples demonstrate the command to create a Linear solution algor model.algorithm('Newton') - Code Developed by: |fmk| diff --git a/source/user/manual/output/nodeDisp.rst b/source/user/manual/output/nodeDisp.rst index 52695a2a..cd21730f 100644 --- a/source/user/manual/output/nodeDisp.rst +++ b/source/user/manual/output/nodeDisp.rst @@ -21,14 +21,18 @@ nodeDisp .. function:: nodeDisp $tag <$dof> - .. csv-table:: + .. csv-table:: :header: "Argument", "Type", "Description" :widths: 10, 10, 40 - tag, |integer|, tag identifying node whose displacements are sought - dof, |integer|, optional: specific dof at the node (1 through ndf) + $tag, |integer|, tag identifying node whose displacements are sought + $dof, |integer|, optional: specific dof at the node (1 through ndf) +After an analysis step, the displacement at each :ref:`node ` is updated in the domain. +``nodeDisp`` returns the current displacement (and rotation, when applicable) for the specified node and optional DOF. +Returned values are in the length and angle units of the user's chosen system (see :ref:`units`). + The components are ordered as follows for various combinations of dimension (:py:attr:`Model.ndm`) and degrees of freedom (:py:attr:`Model.ndf`): .. csv-table:: @@ -59,5 +63,4 @@ The following example is used to set the variable ``disp1`` to the nodal displac u1 = model.nodeDisp(tag,1) - Code developed by: |fmk| diff --git a/source/user/manual/parameter/getParamTags.rst b/source/user/manual/parameter/getParamTags.rst index 672dec2a..c66f9a23 100644 --- a/source/user/manual/parameter/getParamTags.rst +++ b/source/user/manual/parameter/getParamTags.rst @@ -1,8 +1,20 @@ +.. _getParamTags: getParamTags ^^^^^^^^^^^^ -.. py:method:: Model.getParamTags() +.. tabs:: - Return a list of tags for all parameters + .. tab:: Python + .. py:method:: Model.getParamTags() + + Return a list of tags for all parameters in the model. + + :returns: |list| — Tags of all defined parameters. + + .. tab:: Tcl + + .. function:: getParamTags + + This command takes no arguments and returns a list of parameter tags. diff --git a/source/user/manual/parameter/getParamValue.rst b/source/user/manual/parameter/getParamValue.rst index 2ec7ca6e..8c648db8 100644 --- a/source/user/manual/parameter/getParamValue.rst +++ b/source/user/manual/parameter/getParamValue.rst @@ -1,10 +1,25 @@ +.. _getParamValue: getParamValue ^^^^^^^^^^^^^ -.. py:method:: Model.getParamValue(tag) +.. tabs:: - Return the value of a parameter + .. tab:: Python - :param tag: Tag of the :ref:`Parameter` + .. py:method:: Model.getParamValue(tag) + Return the value of a parameter. + + :param |integer| tag: Tag of the :ref:`Parameter `. + :returns: |float| — Current value of the parameter. + + .. tab:: Tcl + + .. function:: getParamValue $paramTag + + .. csv-table:: + :header: "Argument", "Type", "Description" + :widths: 10, 10, 40 + + $paramTag, |integer|, tag of the parameter whose value is sought diff --git a/source/user/manual/section/ElasticFrame.rst b/source/user/manual/section/ElasticFrame.rst index 9a064a7d..22a6de68 100644 --- a/source/user/manual/section/ElasticFrame.rst +++ b/source/user/manual/section/ElasticFrame.rst @@ -57,22 +57,37 @@ The valid :ref:`eleResponse` queries are Formulation ----------- +The section relates axial force, shear forces, torsion, and bending moments to the corresponding deformations using linear elastic stiffness. +For 3D, the section stiffness includes axial (:math:`EA`), shear (:math:`GA`), torsional (:math:`GJ`), and flexural (:math:`EI_y`, :math:`EI_z`) contributions. +The local axes and sign conventions follow the :ref:`Frame ` cross-section documentation. + Examples -------- -The following is an excerpt from a Python script that creates a 3D model with an elastic frame section: +The following creates a 3D elastic frame section: + +.. tabs:: + + .. tab:: Python + + .. code-block:: Python + + model.section("ElasticFrame", 1, + E=29e3*ksi, # Traditional steel + G=11.2e3*ksi, + A=A, + Iy=Iy, + Iz=Iz, + J=J + ) -.. code-block:: Python + .. tab:: Tcl - model.section("ElasticFrame", 1, - E=29e3*ksi, - G=11.2e3*ksi, - A=A, - Iy=Iy, - Iz=Iz, - J=J - ) + .. code-block:: tcl + + # E, G in ksi; A, Iy, Iz, J from variables + section ElasticFrame 1 -E 29000 -G 11200 -A $A -Iy $Iy -Iz $Iz -J $J The following syntax is supported in 2D models for backwards compatibility: @@ -85,7 +100,9 @@ The following syntax is supported in 2D models for backwards compatibility: model.section("ElasticFrame", 1, E, A, I) + .. tab:: Tcl + + .. code-block:: tcl -References ----------- + section ElasticFrame 1 $E $A $I