# 3D Euler-Bernoulli Beam UEL I/O Definition ## Metadata - feature_id: uel-3d-euler-beam - source_requirement: `docs/requirements/uel-3d-euler-beam.md` - source_research: `docs/research/uel-3d-euler-beam-research.md` - source_formulation: `docs/formulations/uel-3d-euler-beam.md` - source_numerical_review: `docs/numerical-reviews/uel-3d-euler-beam.md` - status: ready-for-reference-model-planning - owner_agent: io-definition-agent - date: 2026-06-11 ## Scope and Compatibility Statement - input_format: Abaqus input file (`.inp`) plus Abaqus/Standard `UEL` call data - entry_point: Abaqus/Standard `UEL` - compatibility: only the keyword, argument, and CSV subset defined here is supported - solver_execution_policy: Abaqus jobs are run outside this repository by the user - result_policy: this repository validates externally generated ODB-extracted CSV artifacts and does not parse ODB files This interface contract deliberately avoids claiming full Abaqus input compatibility. It defines the first-scope two-node, small-displacement, linear elastic 3D Euler-Bernoulli beam `UEL` only. ## Abaqus/Standard UEL ABI Contract The Abaqus/Standard production wrapper must preserve the manual `UEL` signature and include convention: ```fortran SUBROUTINE UEL(RHS, AMATRX, SVARS, ENERGY, NDOFEL, 1 NRHS, NSVARS, PROPS, NPROPS, COORDS, MCRD, NNODE, 2 U, DU, V, A, JTYPE, TIME, DTIME, KSTEP, KINC, JELEM, 3 PARAMS, NDLOAD, JDLTYP, ADLMAG, PREDEF, NPREDF, 4 LFLAGS, MLVARX, DDLMAG, MDLOAD, PNEWDT, JPROPS, 5 NJPROP, PERIOD) INCLUDE 'ABA_PARAM.INC' DIMENSION RHS(MLVARX,*), AMATRX(NDOFEL,NDOFEL), 1 SVARS(*), ENERGY(8), PROPS(*), COORDS(MCRD,NNODE), 2 U(NDOFEL), DU(MLVARX,*), V(NDOFEL), A(NDOFEL), 3 TIME(2), PARAMS(*), JDLTYP(MDLOAD,*), 4 ADLMAG(MDLOAD,*), DDLMAG(MDLOAD,*), 5 PREDEF(2,NPREDF,NNODE), LFLAGS(*), JPROPS(*) ``` The wrapper must keep `aba_param.inc` / `ABA_PARAM.INC` as an Abaqus/Standard include, not a project-local replacement. The no-Abaqus kernel may use its own pure calculation interface, but that kernel interface is not defined in this document as source layout. ## Supported ABI Shape | argument or count | supported value | validation rule | | --- | --- | --- | | `NNODE` | `2` | reject anything else | | `NDOFEL` | `12` | reject anything else | | active DOFs per node | `1,2,3,4,5,6` | input keyword and kernel vector order must match | | `MCRD` | `>= 3` | read only `COORDS(1:3,1:2)` | | `NPROPS` | `9` | reject anything else | | `NJPROP` | `0` | first scope uses no integer properties | | `NSVARS` | `>= 1` | Abaqus `*USER ELEMENT` state-variable allocation must be positive; first scope leaves allocated `SVARS` entries unchanged | | `NRHS` | `1` | reject multi-RHS procedures | | `MLVARX` | `>= 12` | required for `RHS(1:12,1)` and `DU(1:12,1)` addressing | | `NDLOAD` | `0` | element-generated distributed loads are unsupported | | `MDLOAD` | any Abaqus value | no `JDLTYP`, `ADLMAG`, or `DDLMAG` entries are used because `NDLOAD=0` is required | | `NPREDF` | any Abaqus value | predefined fields are ignored; thermal and field coupling are unsupported | Unsupported shape values are fatal input-contract violations. They must not silently produce zero stiffness or zero residual. ## DOF Ordering and Kernel Mapping Abaqus element vector ordering is node-major: ```text 1 node 1 U1 2 node 1 U2 3 node 1 U3 4 node 1 UR1 5 node 1 UR2 6 node 1 UR3 7 node 2 U1 8 node 2 U2 9 node 2 U3 10 node 2 UR1 11 node 2 UR2 12 node 2 UR3 ``` The wrapper passes this global vector order directly to the beam kernel as `q_global`. The kernel then applies the formulation transform: ```text q_local = T*q_global K_global = T^T*k_local*T RHS = -K_global*q_global ``` No permutation is allowed between Abaqus `U(1:12)` and the kernel global vector. The local vector has the same node-major layout after projection to the local frame: ```text [u1, v1, w1, th1_1, th2_1, th3_1, u2, v2, w2, th1_2, th2_2, th3_2] ``` ## `PROPS` and `JPROPS` Schema The first-scope interface uses `PROPS` only. `JPROPS` is not used. | index | name | unit | required rule | semantic | | --- | --- | --- | --- | --- | | `PROPS(1)` | `E` | force / length^2 | finite and `> 0` | Young's modulus | | `PROPS(2)` | `G` | force / length^2 | finite and `> 0` | shear modulus for Saint-Venant torsion | | `PROPS(3)` | `A` | length^2 | finite and `> 0` | cross-sectional area | | `PROPS(4)` | `Iy` | length^4 | finite and `> 0` | second moment about local 2; couples local `w/th2` | | `PROPS(5)` | `Iz` | length^4 | finite and `> 0` | second moment about local 3; couples local `v/th3` | | `PROPS(6)` | `J` | length^4 | finite and `> 0` | Saint-Venant torsion constant | | `PROPS(7)` | `a_ref_1` | dimensionless direction component | finite | global approximate local 2 reference x-component | | `PROPS(8)` | `a_ref_2` | dimensionless direction component | finite | global approximate local 2 reference y-component | | `PROPS(9)` | `a_ref_3` | dimensionless direction component | finite | global approximate local 2 reference z-component | Orientation vector rules: - `a_ref = [PROPS(7), PROPS(8), PROPS(9)]` is a global direction vector, not a point coordinate. - The vector magnitude is arbitrary because the kernel normalizes its projection. - Reject `norm(a_ref) <= 1.0e-12`. - Reject `norm(a_ref - dot(a_ref,e1)*e1) / norm(a_ref) <= 1.0e-8`, where `e1` is the node 1 to node 2 beam axis. - The accepted local frame is `e1 = node1->node2`, `e2 = normalized projected a_ref`, and `e3 = cross(e1,e2)`. `JPROPS` policy: - `NJPROP` must be `0`. - No integer flags, versions, orientation modes, or diagnostics are accepted in first scope. - Any future `JPROPS` use requires a revised interface contract and new tests. ## Abaqus Input Keyword Subset The reference model plan should use this `.inp` subset. | keyword | support_status | required parameters | mapped concept | notes | | --- | --- | --- | --- | --- | | `*HEADING` | supported | none | model title | optional | | `*NODE` | supported | none | node label and global coordinates | at least 3 coordinates per node for UEL geometry | | `*ELEMENT` | supported | `TYPE=U1` or the approved user element type, optional `ELSET` | two-node UEL connectivity | connectivity order defines local axis 1 | | `*ELSET` | supported | `ELSET` | element set | needed for `*UEL PROPERTY` | | `*NSET` | supported | `NSET` | node set | recommended for BC/load/output selection | | `*USER ELEMENT` | supported | `TYPE=U1`, `NODES=2`, `COORDINATES=3`, `PROPERTIES=9`, `VARIABLES=1` | UEL declaration | omit `UNSYMM`; omit `I PROPERTIES`; `SVARS(1)` is unused | | `*UEL PROPERTY` | supported | `ELSET` | real property assignment | data order is `PROPS(1:9)` | | `*BOUNDARY` | supported | standard nodal DOF constraints | essential boundary conditions | DOFs 1-6 allowed | | `*CLOAD` | supported | standard nodal concentrated load | external nodal loads/moments | loads are assembled by Abaqus outside UEL | | `*STEP` | supported | optional `NAME` | analysis step | static only | | `*STATIC` | supported | default or direct static data | small-displacement static procedure | no dynamics | | `*OUTPUT` | supported | none | output request root | optional but required for external artifacts | | `*NODE OUTPUT` | supported | `NSET` recommended | nodal CSV extraction source | request `U`, optional `UR`, `RF`/reaction moments as available | | `*END STEP` | supported | none | step terminator | required | Unsupported in first scope: - `*DLOAD`, `*DSLOAD`, body forces, pressure loads, and distributed load generation - `*MASS`, density, modal, transient, damping, and dynamic procedures - `*BEAM SECTION`, `*BEAM GENERAL SECTION`, offsets, warping, and native beam section keywords for this UEL - `*ORIENTATION` as the source of UEL orientation; use `PROPS(7:9)` instead - material model keywords for UEL stiffness; use `*UEL PROPERTY` real values instead - nonlinear geometry, follower loads, thermal expansion, predefined field coupling, plasticity, damage, creep, and viscoelastic behavior ### Required `*USER ELEMENT` Shape The reference input deck should declare the user element with this logical content: ```text *USER ELEMENT, TYPE=U1, NODES=2, COORDINATES=3, PROPERTIES=9, VARIABLES=1 1, 2, 3, 4, 5, 6 ``` If the final reference model chooses a different `TYPE=Un` identifier to avoid conflicts, the same `NODES`, `COORDINATES`, `PROPERTIES`, `VARIABLES`, and active DOF contract still applies. ### Required `*UEL PROPERTY` Data Order ```text *UEL PROPERTY, ELSET= E, G, A, Iy, Iz, J, a_ref_1, a_ref_2 a_ref_3 ``` Line breaks may follow Abaqus input formatting rules, but the logical property order is fixed. ## Subroutine Parameter Contract | parameter | direction | first-scope responsibility | | --- | --- | --- | | `RHS(MLVARX,*)` | output | Initialize requested storage to zero every call; for supported residual requests, set `RHS(1:12,1) = -K_global*U(1:12)`. | | `AMATRX(NDOFEL,NDOFEL)` | output | Initialize all `12x12` entries to zero every call; for supported stiffness requests, set all entries to `K_global`. | | `SVARS(*)` | input/output | unused; require `NSVARS>=1` for Abaqus keyword compatibility; do not store diagnostics in first scope. | | `ENERGY(8)` | input/output | set `ENERGY(1:8)=0.0` every supported call; do not use as validation evidence in first scope. | | `NDOFEL` | input | must equal `12`. | | `NRHS` | input | must equal `1`. | | `NSVARS` | input | must be at least `1`. | | `PROPS(*)` | input | must contain the 9 real values defined above. | | `NPROPS` | input | must equal `9`. | | `COORDS(MCRD,NNODE)` | input | read `COORDS(1:3,1)` and `COORDS(1:3,2)` as original global node coordinates. | | `MCRD` | input | must be at least `3`. | | `NNODE` | input | must equal `2`. | | `U(NDOFEL)` | input | total current nodal DOF estimate; used for static residual. | | `DU(MLVARX,*)` | input | not used for first-scope static residual; may be used only by no-Abaqus tests to confirm it is ignored. | | `V(NDOFEL)` | input | ignored; dynamics out of scope. | | `A(NDOFEL)` | input | ignored; dynamics out of scope. | | `JTYPE` | input | not used except optional diagnostics; element type compatibility is enforced by `.inp` contract. | | `TIME(2)` | input | ignored for linear static stiffness/residual; may be copied to diagnostics only. | | `DTIME` | input | ignored; no time-step-dependent behavior. | | `KSTEP`, `KINC` | input | not used in calculations; may be used only for diagnostics. | | `JELEM` | input | element label for diagnostics and traceability. | | `PARAMS(*)` | input | ignored; no dynamic procedure parameters supported. | | `NDLOAD` | input | must equal `0`; distributed loads unsupported. | | `JDLTYP`, `ADLMAG`, `DDLMAG`, `MDLOAD` | input | ignored only after confirming `NDLOAD=0`. | | `PREDEF`, `NPREDF` | input | ignored; predefined fields unsupported. | | `LFLAGS(*)` | input | used to identify small-displacement static request and requested contribution. | | `MLVARX` | input | must be at least `12`. | | `PNEWDT` | input/output | do not modify for valid supported calls; invalid immutable inputs must fail explicitly rather than rely on cutback recovery. | | `JPROPS(*)`, `NJPROP` | input | require `NJPROP=0`; `JPROPS` ignored. | | `PERIOD` | input | ignored; not used in static analysis. | ## Supported `LFLAGS` Behavior The first-scope wrapper supports only small-displacement static calls: - require `LFLAGS(2)=0` - support `LFLAGS(3)=1`, `2`, or `5` - require `LFLAGS(1)=1` or `2` for static procedure calls - require `LFLAGS(4)=0` for general-step behavior, not perturbation-only output - require `NRHS=1` Contribution rules: | condition | `AMATRX` | `RHS` | policy | | --- | --- | --- | --- | | `LFLAGS(3)=1` | `K_global` | `-K_global*U` | primary static call | | `LFLAGS(3)=2` | `K_global` | zero | stiffness-only request | | `LFLAGS(3)=5` | zero | `-K_global*U` | residual-only request | | any other `LFLAGS(3)` | none | none | unsupported fatal diagnostic | Unsupported request examples include mass, damping, dynamics, half-step residuals, perturbation-only behavior, and large-displacement kinematics. ## Validation Rules and Diagnostics Invalid input must be caught before matrix assembly. The implementation may choose the exact Abaqus-compatible fatal-reporting mechanism later, but it must preserve these diagnostic identifiers and meanings in tests or logs where feasible. | id | condition | expected behavior | | --- | --- | --- | | `UEL3DEB-E001` | `NDOFEL /= 12` | fatal unsupported element DOF count | | `UEL3DEB-E002` | `NNODE /= 2` | fatal unsupported topology | | `UEL3DEB-E003` | `MCRD < 3` | fatal missing 3D coordinates | | `UEL3DEB-E004` | `NPROPS /= 9` | fatal wrong real property count | | `UEL3DEB-E005` | `NJPROP /= 0` | fatal unsupported integer properties | | `UEL3DEB-E006` | `NSVARS < 1` | fatal missing Abaqus state-variable allocation | | `UEL3DEB-E007` | `NRHS /= 1` | fatal unsupported RHS count | | `UEL3DEB-E008` | `MLVARX < 12` | fatal invalid RHS/DU leading dimension | | `UEL3DEB-E009` | any required coordinate, `U`, or `PROPS` value is NaN or infinite | fatal nonfinite input | | `UEL3DEB-E010` | `E`, `G`, `A`, `Iy`, `Iz`, or `J <= 0` | fatal nonpositive physical property | | `UEL3DEB-E011` | element length `L <= 1.0e-12*max(1,norm(X1),norm(X2))` | fatal zero or near-zero element length | | `UEL3DEB-E012` | `norm(a_ref) <= 1.0e-12` | fatal zero orientation reference | | `UEL3DEB-E013` | `norm(a_perp)/norm(a_ref) <= 1.0e-8` | fatal near-parallel orientation reference | | `UEL3DEB-E014` | `LFLAGS(2) /= 0` | fatal unsupported large-displacement or non-small-displacement request | | `UEL3DEB-E015` | unsupported `LFLAGS(3)` | fatal unsupported contribution request | | `UEL3DEB-E016` | `NDLOAD /= 0` | fatal unsupported element load input | | `UEL3DEB-E017` | `LFLAGS(1)` is not `1` or `2` | fatal unsupported non-static procedure request | | `UEL3DEB-E018` | `LFLAGS(4) /= 0` | fatal unsupported perturbation-output request | For valid supported calls, the wrapper should set deterministic outputs for the requested contribution and should not modify `PNEWDT`. ## Thin Wrapper Boundary The Abaqus ABI wrapper owns: - preserving the exact `UEL` signature and `ABA_PARAM.INC` include - validating argument counts, dimensions, request flags, and property values - extracting `X1`, `X2`, `U(1:12)`, and `PROPS(1:9)` - mapping `LFLAGS` to requested stiffness/residual operations - writing `AMATRX`, `RHS`, `SVARS`, `ENERGY`, and `PNEWDT` according to this contract - reporting diagnostics with `JELEM`, `KSTEP`, and `KINC` when available The no-Abaqus beam kernel conceptually owns: - local frame construction from `X1`, `X2`, and `a_ref` - local stiffness matrix assembly - local-to-global transformation - internal force and residual calculation - numerical status reporting for invalid geometry or properties This document does not prescribe Fortran module names, source files, helper APIs, or data structures. ## External CSV Extraction Schema All CSV files are externally generated from Abaqus results by the user. They must be placed under `references/uel-3d-euler-beam//extracted/` and declared in that model's `metadata.json`. ### Required Common Columns Every comparison CSV row must include: | column | type | rule | | --- | --- | --- | | `step` | string | Abaqus step name or stable step index | | `frame` | integer | frame or increment index | | `time` | float | step time or total time used by extraction | | `instance` | string | Abaqus instance name, or `ASSEMBLY` if not applicable | | `node_label` | integer | Abaqus node label for nodal files | | `quantity` | string | extracted output quantity, for example `U`, `UR`, `RF`, or `RM` | | `component` | string | component label listed below | | `coordinate_system` | string | must be `GLOBAL` for first-scope comparison | | `unit` | string | declared user-consistent unit | | `value` | float | numeric extracted value | The CSV schema uses long format, one component per row, to avoid ambiguity between translational and rotational quantities. ### `nodal_displacements.csv` Required for external solver-result comparison. Allowed component rows: | quantity | component | unit type | required | | --- | --- | --- | --- | | `U` | `U1`, `U2`, `U3` | length | yes | | `UR` | `UR1`, `UR2`, `UR3` | radian | optional unless the reference model compares rotations | Tolerance defaults: - displacement absolute tolerance: `1.0e-8` in declared length units - rotation absolute tolerance: `1.0e-8` radians unless the reference model narrows it - relative tolerance: reference model may add scale-aware relative tolerance when needed ### `reactions.csv` Required for external solver-result comparison at constrained nodes. Allowed component rows: | quantity | component | unit type | required | | --- | --- | --- | --- | | `RF` | `RF1`, `RF2`, `RF3` | force | yes for constrained translational DOFs | | `RM` | `RM1`, `RM2`, `RM3` | force*length | required when constrained rotational DOFs are part of the benchmark comparison | If the user's Abaqus extraction names rotational reactions differently, `metadata.json` must map the raw Abaqus variable/component name to the project component labels above. Tolerance defaults: - force and moment relative tolerance: `1.0e-6` - absolute tolerance: Reference Model Agent must define a scale-aware floor for each benchmark if the expected reaction can be near zero ### Optional Element-Level CSVs No element force, stress, strain, section force, or energy CSV is required or approved for first-scope external comparison. Such CSVs require a later `SVARS` or output-recovery contract. ## Reference Artifact Metadata Requirements Each external reference model must include metadata fields sufficient for `scripts/validate_reference_artifacts.py` plus feature-level declarations: - `feature_id`: `uel-3d-euler-beam` - Abaqus version and precision - compiler vendor/name/version used for the user subroutine build, when applicable - user subroutine source file hashes after implementation exists - `model.inp` path and hash - declared extracted CSV files and their schema version - ODB extraction provenance, including extraction script name/version if available - unit declarations for length, force, stress, moment, and rotation - coordinate system declaration: `GLOBAL` for nodal comparison CSVs ## Open Issues and Downstream Handoff ### Reference Model Agent - Use the keyword subset and property order in this document for `model.inp` examples. - Include no-Abaqus tests for exact `PROPS(1:9)` mapping, `NJPROP=0`, `NSVARS>=1`, `NDOFEL=12`, `NNODE=2`, and active DOF order. - Include negative tests for every `UEL3DEB-E###` validation rule that is practical in the no-Abaqus harness. - Define benchmark-specific CSV filenames and near-zero absolute reaction tolerances. - Keep external artifact generation outside this repository. ### Implementation Planning Agent - Preserve the Abaqus `UEL` signature exactly in the wrapper. - Keep the wrapper thin and route only validated arrays/scalars to a no-Abaqus beam kernel. - Implement deterministic zeroing for non-requested `AMATRX`/`RHS` in no-Abaqus drivers so tests are stable. - Do not implement `SVARS`, `ENERGY`, distributed loads, dynamics, `JPROPS`, or `*ORIENTATION` support in first scope. ### Reference Verification Agent - Validate only externally generated CSVs declared in metadata. - Match rows by `step`, `frame`, `instance`, `node_label`, `quantity`, `component`, `coordinate_system`, and `unit`. - Reject CSVs with missing units, missing coordinate systems, unsupported component labels, or undeclared files. - Compare first-scope external results using nodal displacement and reaction CSVs only.