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 00000000..1814e9e8 Binary files /dev/null and b/source/user/manual/model/constraints/figures/constrain-frame-skewed-support.png differ 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