12 Commits

Author SHA1 Message Date
김경종 cf80780863 docs: close euler beam kernel phase 2026-06-12 18:12:37 +09:00
김경종 7845ebec68 feat(euler-beam-3d): add global transform recovery 2026-06-12 18:10:35 +09:00
김경종 95ca95180a feat(euler-beam-3d): add local beam kernel 2026-06-12 18:02:05 +09:00
김경종 5b01642cbc feat(euler-beam-3d): add beam topology 2026-06-12 17:59:44 +09:00
김경종 c88de37a83 docs: complete euler beam planning gates 2026-06-12 17:58:23 +09:00
김경종 4c47b2766a feat(euler-beam-3d): step 0 requirements-baseline 2026-06-12 17:51:35 +09:00
김경종 7179cfc243 fix: allow harness codex command override 2026-06-12 17:43:50 +09:00
김경종 6cc5ee6e25 fix: support harness codex model override 2026-06-12 17:38:16 +09:00
김경종 656cc5afc4 fix: use utf-8 for harness codex prompts 2026-06-12 17:35:22 +09:00
김경종 3ce43c8670 fix: resolve codex shim for harness runner 2026-06-12 17:33:23 +09:00
김경종 2bab84beb6 fix: pass harness prompts through stdin 2026-06-12 17:30:25 +09:00
김경종 13cf2af899 docs: add 3d euler beam phase 2026-06-12 17:26:01 +09:00
43 changed files with 2767 additions and 978 deletions
@@ -0,0 +1,75 @@
# 3D Euler-Bernoulli Beam Kernel Build/Test Report
## Metadata
- feature_id: euler-beam-3d
- source_implementation_plan: docs/implementation-plans/euler-beam-3d-implementation-plan.md
- status: pass-for-reference-verification
- owner_agent: build-test-executor-agent
- date: 2026-06-12
## Changed Files Observed
- `docs/research/euler-beam-3d-research.md`
- `docs/formulations/euler-beam-3d-formulation.md`
- `docs/numerical-reviews/euler-beam-3d-review.md`
- `docs/io-definitions/euler-beam-3d-io.md`
- `docs/reference-models/euler-beam-3d-reference-models.md`
- `docs/implementation-plans/euler-beam-3d-implementation-plan.md`
- `src/fesa/model/element.hpp`
- `tests/unit/model_element_test.cpp`
- `src/fesa/elements/euler_beam_3d.hpp`
- `src/fesa/elements/euler_beam_3d.cpp`
- `tests/unit/euler_beam_3d_local_stiffness_test.cpp`
- `tests/unit/euler_beam_3d_transform_recovery_test.cpp`
- `phases/euler-beam-3d/index.json`
## Execution Environment
- os: Windows, MSVC toolchain through Visual Studio 17 2022
- generator: Visual Studio 17 2022
- platform: x64
- config: Debug
- build_dir: build/msvc-debug
- active_override_env_vars: `HARNESS_VALIDATION_COMMANDS`
- command_discovery_path: `HARNESS_VALIDATION_COMMANDS` with absolute CMake and CTest executable paths
## Command Log Summary
| order | command | exit_code | evidence_tail |
| --- | --- | --- | --- |
| 1 | `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "model_element_test\|euler_beam_3d_(local_stiffness\|transform_recovery)_test"` | 0 | 3/3 tests passed: `euler_beam_3d_local_stiffness_test`, `euler_beam_3d_transform_recovery_test`, `model_element_test`. |
| 2 | `python -m unittest discover -s scripts -p "test_*.py"` | 0 | Ran 104 tests, OK. |
| 3 | `python scripts/validate_workspace.py` with absolute CMake/CTest commands in `HARNESS_VALIDATION_COMMANDS` | 0 | Configure/build succeeded; CTest passed 23/23 tests; validation succeeded. |
## Validation Results
| validation_stage | result | evidence |
| --- | --- | --- |
| harness self-test | pass | `Ran 104 tests ... OK`. |
| configure | pass | CMake generated `build/msvc-debug` with Visual Studio 17 2022 x64. |
| build | pass | `fesa_core` and all unit/integration test executables built in Debug. |
| CTest | pass | Full validation passed 23/23 tests. |
| feature-specific tests | pass | 3/3 feature tests passed with the step 9 CTest filter. |
## Failure Classification
- classification: N/A
- primary_failure: N/A
- first_failed_command: N/A
- evidence_tail: all required commands passed.
## Failed Test Inventory
| test_name | label | command | failure_summary |
| --- | --- | --- | --- |
| N/A | N/A | N/A | No failing tests. |
## Scope Boundary
This report only records build/test evidence for the kernel increment. It does not approve reference verification, physics sanity, or release readiness. No Abaqus reference solver was run and no reference CSV artifacts were generated or modified.
## No-Change Assertion
- source_files_modified: false in this report step.
- test_files_modified: false in this report step.
- cmake_files_modified: false.
- reference_artifacts_modified: false.
- notes: the report documents observed implementation changes from earlier steps but does not add new code.
## Open Issues
- Full solver release still requires parser integration, section/property mapping, assembly/static solver integration, HDF5 output, stored Abaqus reference artifacts, reference comparison, and physics sanity evidence.
@@ -0,0 +1,210 @@
# 3D Euler-Bernoulli Beam Kernel Formulation
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- source_research: docs/research/euler-beam-3d-research.md
- status: ready-for-numerical-review
- owner_agent: formulation-agent
- date: 2026-06-12
## Scope and Assumptions
- analysis_type: linear static kernel only.
- element_type: two-node straight prismatic 3D Euler-Bernoulli beam.
- deformation: small displacement and small rotation.
- linearity: linear elastic.
- material_model_boundary: constant `E` and `G`.
- section_model_boundary: constant `A`, `J`, `Iy`, `Iz`.
- coordinate_system: local Cartesian beam basis and global Cartesian basis.
- units: user-consistent.
## Primary Variables and DOFs
- nodal_variables: displacement vector and rotation vector at each node.
- dof_ordering: `[u1, v1, w1, rx1, ry1, rz1, u2, v2, w2, rx2, ry2, rz2]`.
- local_axis_convention:
- local `x` is the normalized vector from node 1 to node 2.
- local `y` is the normalized projection of the user orientation vector onto the plane normal to local `x`.
- local `z = x cross y`.
- sign_convention: internal local end force vector is `f_local = K_local * u_local` in the same DOF order.
## Strong Form and Boundary Conditions
The kernel is an element-level direct-stiffness implementation of the linear Euler-Bernoulli frame equations. For a prismatic member in local coordinate `x`:
- axial equilibrium uses constant axial stiffness `EA`.
- torsional equilibrium uses constant torsional stiffness `GJ`.
- bending in local `x-y` uses flexural rigidity `EIz`.
- bending in local `x-z` uses flexural rigidity `EIy`.
Essential and natural boundary conditions are not applied by this kernel. They are downstream solver assembly concerns.
## Weak or Variational Form
The element stiffness represents the second variation of strain energy:
```text
U = 1/2 integral_0^L [
EA * (du/dx)^2
+ GJ * (drx/dx)^2
+ EIz * (d2v/dx2)^2
+ EIy * (d2w/dx2)^2
] dx
```
The element internal force is the derivative of this energy with respect to the nodal DOFs:
```text
f_local = K_local * u_local
```
External load vectors are out of scope for this increment.
## Discretization
- axial interpolation: linear two-node interpolation for `u`.
- torsion interpolation: linear two-node interpolation for `rx`.
- bending interpolation: cubic Hermite interpolation for each transverse displacement and corresponding nodal rotation.
- nodal_layout: node 1 at local coordinate `x=0`, node 2 at `x=L`.
- partition_of_unity_check: axial and torsion linear shape functions sum to one.
- kronecker_delta_check: axial, torsion, and Hermite bending shape functions recover the nodal displacement/rotation DOFs.
## Kinematics
- axial strain: `epsilon_x = du/dx`.
- torsion rate: `kappa_x = drx/dx`.
- bending curvature for local `x-y` bending: curvature associated with `v` and rotations `rz`.
- bending curvature for local `x-z` bending: curvature associated with `w` and rotations `ry`.
- strain_measure: infinitesimal strain and small rotation curvature measures only.
## Constitutive Contract
- axial force result: `N = EA * du/dx`.
- torsional moment result: `Mx = GJ * drx/dx`.
- bending moment about local `z`: uses `EIz`.
- bending moment about local `y`: uses `EIy`.
- material_state_variables: none.
## Element Equations
Let:
```text
a = E*A/L
t = G*J/L
by = E*Iy
bz = E*Iz
cy1 = 12*by/L^3
cy2 = 6*by/L^2
cy3 = 4*by/L
cy4 = 2*by/L
cz1 = 12*bz/L^3
cz2 = 6*bz/L^2
cz3 = 4*bz/L
cz4 = 2*bz/L
```
`K_local` is a 12x12 symmetric matrix initialized to zero, with these nonzero entries before symmetric mirroring:
```text
K(0,0)= a K(0,6)=-a K(6,6)= a
K(3,3)= t K(3,9)=-t K(9,9)= t
K(1,1)= cz1 K(1,5)= cz2 K(1,7)=-cz1 K(1,11)= cz2
K(5,5)= cz3 K(5,7)=-cz2 K(5,11)= cz4
K(7,7)= cz1 K(7,11)=-cz2 K(11,11)= cz3
K(2,2)= cy1 K(2,4)=-cy2 K(2,8)=-cy1 K(2,10)=-cy2
K(4,4)= cy3 K(4,8)= cy2 K(4,10)= cy4
K(8,8)= cy1 K(8,10)= cy2 K(10,10)= cy3
```
The implementation must mirror upper-triangular entries to the lower triangle.
## Mapping and Numerical Integration
- reference_coordinates: local beam coordinate `x in [0,L]`.
- isoparametric_mapping: straight member mapping only.
- jacobian: `dx/dxi = L/2` if a parent coordinate is introduced; the direct closed-form stiffness does not require runtime quadrature.
- determinant_checks: `L > 0` and finite.
- gauss_points_and_weights: not used by the closed-form kernel.
- integration_policy: analytical closed-form.
## Transformation
Let `R` be the 3x3 matrix whose rows are local basis vectors expressed in global coordinates:
```text
R = [ x_local^T
y_local^T
z_local^T ]
```
For each node, the same `R` maps global translational and rotational components to local components. The 12x12 transform `T` is block diagonal:
```text
u_local = T * u_global
K_global = T^T * K_local * T
```
Global end-force recovery uses the same convention:
```text
u_local = T * u_global
f_local = K_local * u_local
f_global = T^T * f_local
```
## Output Recovery
- displacement: input only for this kernel.
- reaction: not recovered by this kernel; downstream assembly/constraints own reactions.
- element_force: local and global element end forces recover from stiffness times displacement.
- strain: out of scope.
- stress: out of scope.
- nodal_extrapolation: not applicable.
## Invalid Input Handling
- `length <= 0`, nonfinite length, or near-zero geometry length must throw `std::invalid_argument`.
- nonpositive or nonfinite `E`, `G`, `A`, `J`, `Iy`, or `Iz` must throw `std::invalid_argument`.
- zero orientation vector or orientation parallel to local `x` must throw `std::invalid_argument`.
## Unit Test Tolerance
- representative coefficient checks: absolute tolerance `1.0e-10` for the planned deterministic values.
- symmetry checks: absolute tolerance `1.0e-10`.
- rigid mode force norm checks: absolute tolerance `1.0e-9` for simple test magnitudes.
## Algorithm Pseudocode
```text
validate length and section constants
compute named stiffness coefficients
initialize 12x12 local matrix to zero
fill upper triangular axial, torsion, and bending terms
mirror upper triangular terms
for global operations:
compute normalized local x from node2 - node1
project orientation onto plane normal to local x and normalize as local y
compute local z = x cross y
build block diagonal T from R
compute K_global = T^T * K_local * T
recover forces with u_local = T*u_global, f_local = K_local*u_local, f_global = T^T*f_local
```
## Numerical Risks
- rigid_body_modes: the unconstrained local/global stiffness should produce near-zero force for six rigid body modes; tests should include at least rigid translation in this increment.
- patch_test: future solver-level patch tests require parser/assembly integration.
- symmetry: local and global matrices must remain symmetric.
- positive_definiteness: constrained systems may become positive definite; the isolated element is positive semidefinite.
- hourglass: not applicable to this closed-form beam kernel.
- shear_locking: excluded by Euler-Bernoulli assumptions and no shear deformation terms.
- volumetric_locking: not applicable.
- distortion: curved or offset geometry is out of scope.
- singular_jacobian: represented by zero or near-zero length.
## Open Issues and Downstream Handoff
### Numerical Review Agent
- Confirm signs for the local `w` and `ry` bending block.
- Confirm the transformation convention and invalid orientation handling are implementation-ready.
### I/O Definition Agent
- Define future orientation input mapping and unsupported cases without claiming parser support in this kernel increment.
### Reference Model Agent
- Define future axial, torsion, bending, and skew-oriented reference models without generating artifacts.
### Implementation Planning Agent
- Transcribe the matrix entries and transformation convention into C++ tests before production implementation.
@@ -0,0 +1,127 @@
# 3D Euler-Bernoulli Beam Kernel Implementation Plan
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- source_research: docs/research/euler-beam-3d-research.md
- source_formulation: docs/formulations/euler-beam-3d-formulation.md
- source_numerical_review: docs/numerical-reviews/euler-beam-3d-review.md
- source_io_definition: docs/io-definitions/euler-beam-3d-io.md
- source_reference_models: docs/reference-models/euler-beam-3d-reference-models.md
- status: ready-for-implementation
- owner_agent: implementation-planning-agent
- date: 2026-06-12
## Readiness Check
| input | required_status | observed_status | decision |
| --- | --- | --- | --- |
| requirement | sufficient draft | draft, kernel scope explicit | proceed |
| research | ready-for-formulation | ready-for-formulation | proceed |
| formulation | ready-for-numerical-review | ready-for-numerical-review | proceed |
| numerical_review | pass-for-implementation-planning | pass-for-implementation-planning | proceed |
| io_definition | ready-for-implementation-planning or explicit future scope | ready-for-implementation-planning | proceed |
| reference_models | planned artifacts or future gate | needs-reference-artifacts | proceed for kernel only |
## Implementation Scope
- included_behavior:
- semantic `beam2` model topology.
- local 12x12 stiffness for a two-node 3D Euler-Bernoulli beam.
- local end-force recovery as `K_local * u_local`.
- local/global basis construction, global stiffness transform, and global end-force recovery.
- excluded_behavior:
- parser integration, assembly, solver integration, HDF5 output, reference CSV generation, reference comparison, stress recovery, distributed loads, mass, geometric stiffness, releases, offsets, warping, shear deformation, nonlinear and dynamic behavior.
- non_goals:
- no external linear algebra dependency.
- no CMake edits unless the existing source/test globs fail to pick up new files.
## Work Breakdown
| task_id | order | purpose | upstream_trace | depends_on | expected_test_first |
| --- | --- | --- | --- | --- | --- |
| EB3D-TASK-001 | 1 | Add `ElementTopology::beam2` semantic topology. | EB3D-REQ-001, EB3D-REQ-002 | none | EB3D-TEST-001 |
| EB3D-TASK-002 | 2 | Add local stiffness and local end-force kernel. | EB3D-REQ-004, EB3D-REQ-005, EB3D-REQ-007, EB3D-REQ-009 | EB3D-TASK-001 | EB3D-TEST-002 |
| EB3D-TASK-003 | 3 | Add global transform and global end-force recovery. | EB3D-REQ-006, EB3D-REQ-008, EB3D-REQ-010, EB3D-REQ-011 | EB3D-TASK-002 | EB3D-TEST-003 |
| EB3D-TASK-004 | 4 | Record build/test evidence. | project validation policy | EB3D-TASK-003 | N/A |
| EB3D-TASK-005 | 5 | Record release-readiness note with limitations. | EB3D-REQ-012 through EB3D-REQ-015 | EB3D-TASK-004 | N/A |
## TDD Test Plan
| test_id | order | test_type | red_condition | green_condition | linked_task | command |
| --- | --- | --- | --- | --- | --- | --- |
| EB3D-TEST-001 | 1 | unit | compile fails because `ElementTopology::beam2` is missing | model element test passes with `beam2` and existing topologies preserved | EB3D-TASK-001 | `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test` |
| EB3D-TEST-002 | 2 | unit | compile fails because `euler_beam_3d.hpp` API is missing | local stiffness entries, symmetry, `K*u`, and invalid inputs pass | EB3D-TASK-002 | `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test` |
| EB3D-TEST-003 | 3 | unit | compile fails because global transform API is missing | identity transform, rotated symmetry, rigid translation, axial force, and invalid orientation pass | EB3D-TASK-003 | `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test` |
## CMake/CTest Plan
- target_candidates: existing FESA library target and unit-test executable pattern.
- add_test_needs: only if existing test globs do not register new tests.
- labels: unit.
- msvc_config: Debug.
- expected_feature_commands:
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test`
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test`
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test`
- workspace_validation: `python scripts/validate_workspace.py`.
## Candidate Files and Ownership
| file_candidate | purpose | owner_boundary | notes |
| --- | --- | --- | --- |
| `src/fesa/model/element.hpp` | add semantic topology enum value | model semantic layer | No equation IDs or section constants. |
| `src/fesa/model/element.cpp` | only if topology string/conversion exists | model semantic layer | Preserve existing behavior. |
| `tests/unit/model_element_test.cpp` | topology unit test | test-first for model change | Must be edited before production enum change. |
| `src/fesa/elements/euler_beam_3d.hpp` | kernel declarations and small value types | element kernel layer | C++17 standard library only. |
| `src/fesa/elements/euler_beam_3d.cpp` | local/global stiffness and recovery implementation | element kernel layer | No parser, assembly, or HDF5 code. |
| `tests/unit/euler_beam_3d_local_stiffness_test.cpp` | local kernel tests | test-first for local kernel | Covers representative entries and invalid inputs. |
| `tests/unit/euler_beam_3d_transform_recovery_test.cpp` | transform/recovery tests | test-first for global transform | Covers identity, rotation, rigid translation, axial force, invalid orientation. |
## Acceptance Traceability Matrix
| requirement_id | task_id | test_id | reference_model_id | acceptance_criterion | status |
| --- | --- | --- | --- | --- | --- |
| EB3D-REQ-001 | EB3D-TASK-001 | EB3D-TEST-001 | N/A | semantic topology exists for two-node beam | planned |
| EB3D-REQ-002 | EB3D-TASK-002 | EB3D-TEST-002 | N/A | local DOF order matches formulation entries | planned |
| EB3D-REQ-004 | EB3D-TASK-002 | EB3D-TEST-002 | N/A | section constants are used and invalid constants rejected | planned |
| EB3D-REQ-005 | EB3D-TASK-002 | EB3D-TEST-002 | N/A | local 12x12 stiffness entries match formulation | planned |
| EB3D-REQ-006 | EB3D-TASK-003 | EB3D-TEST-003 | `eb3d-skew-transform` future | global stiffness uses documented transform | planned |
| EB3D-REQ-007 | EB3D-TASK-002 | EB3D-TEST-002 | N/A | local end forces equal `K*u` | planned |
| EB3D-REQ-008 | EB3D-TASK-003 | EB3D-TEST-003 | `eb3d-skew-transform` future | global end forces use consistent transform | planned |
| EB3D-REQ-009 | EB3D-TASK-002/003 | EB3D-TEST-002/003 | N/A | local and global stiffness matrices are symmetric | planned |
| EB3D-REQ-010 | EB3D-TASK-003 | EB3D-TEST-003 | N/A | rigid global translation has near-zero end forces | planned |
| EB3D-REQ-011 | EB3D-TASK-003 | EB3D-TEST-003 | `eb3d-skew-transform` future | transform and recovery conventions are consistent | planned |
| EB3D-REQ-012 | EB3D-TASK-002/003 | EB3D-TEST-002/003 | N/A | excluded behaviors are not implemented | planned |
| EB3D-REQ-013 | EB3D-TASK-004 | N/A | all future models | no `reference/` artifacts are modified | planned |
| EB3D-REQ-014 | EB3D-TASK-005 | N/A | N/A | no full Abaqus compatibility claim | planned |
| EB3D-REQ-015 | EB3D-TASK-005 | N/A | N/A | kernel completion remains separate from full solver release | planned |
## Validation Commands
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Risks and Downstream Handoff
### Implementation Agent
- Follow `RED -> GREEN -> VERIFY` for each production change.
- Keep matrix storage row-major with index `row * 12 + col`.
- Throw `std::invalid_argument` for invalid length, section constants, and orientation.
### Build/Test Executor Agent
- Record CTest and workspace validation evidence after the C++ steps.
### Correction Agent
- Compile failures are likely missing CMake glob registration or signature mismatch.
- Test failures are likely sign convention, transform convention, or tolerance mistakes.
### Reference Verification Agent
- No reference comparison is expected until future HDF5 and reference artifact work is approved.
## Open Issues
- Exact parser keyword subset and HDF5 schema are future integration work.
- Reference artifacts remain unavailable by design in this kernel phase.
@@ -1,139 +0,0 @@
# Abaqus Input Parser I/O Definition
## Metadata
- feature_id: abaqus-input-parser
- status: ready-for-implementation-planning
- owner_agent: io-definition-agent
- date: 2026-06-12
## Abaqus Input Scope
FESA supports only the Abaqus input keyword subset listed here. This document
does not claim full Abaqus compatibility.
| keyword | support_status | level | required_parameters | mapped_internal_concept | unsupported-case behavior |
| --- | --- | --- | --- | --- | --- |
| `*HEADING` | supported | model | none | model title metadata | accepted; title storage may be deferred |
| `*NODE` | supported | model | none | node id and global coordinates | malformed rows are errors |
| `*ELEMENT` | supported | model | `TYPE` | element id, topology, connectivity | missing/unsupported `TYPE` is an error |
| `*NSET` | supported | model | `NSET` | named node set | missing name is an error |
| `*ELSET` | supported | model | `ELSET` | named element set | missing name is an error |
| `*MATERIAL` | supported | model | `NAME` | material identity | missing name is an error |
| `*ELASTIC` | supported | model | none | linear elastic constants | malformed rows are errors |
| section keyword | supported | model | `ELSET`, `MATERIAL` | property assignment | unsupported section type is an error |
| `*STEP` | supported | history | optional `NAME` | analysis step | malformed parameters are errors |
| `*STATIC` | supported | history | none | static procedure marker | unsupported procedures are errors |
| `*BOUNDARY` | supported | model/history | none | prescribed nodal dof values | malformed rows are errors |
| `*CLOAD` | supported | history | none | concentrated nodal load | malformed rows are errors |
| `*OUTPUT` | supported | history | none | output request root | unsupported options warn or error by context |
| `*NODE OUTPUT` | supported | history | none | nodal output request | unsupported quantities warn or error by context |
| `*ELEMENT OUTPUT` | supported | history | none | element output request | unsupported quantities warn or error by context |
Initial V0 element names are two-node line/bar types only: `T2D2`, `T3D2`,
`C3D2`, and `B31`.
## Syntax Policy
- Keywords and parameter names are case-insensitive.
- Keyword lines begin with `*`.
- Comment lines begin with `**` and are ignored.
- Blank lines are ignored.
- Fields are comma-separated. Leading and trailing whitespace around fields is
ignored.
- Empty required fields are parse errors.
- Unsupported keywords are errors unless this contract explicitly marks them as
ignored-with-warning.
- Diagnostics must include severity, a stable code, a human-readable message,
and enough line context to locate the input row.
- Include files are out of scope for this parser phase.
## Model Data Mapping
- Nodes map an Abaqus node label to a FESA node id and three global coordinate
components. Missing trailing coordinate components are interpreted as `0.0`
only when the keyword-specific test documents that behavior.
- Elements map an Abaqus element label, supported element type, and connectivity
labels to a FESA element. Section assignment supplies material/property
linkage in a later parser slice.
- Node sets and element sets preserve deterministic membership order.
- Materials map by Abaqus `NAME`. Linear elastic data maps to the semantic
material contract used by solver implementation.
- Section keywords bind an element set to a material and create the semantic
property assignment needed by the solver.
- The global coordinate system is assumed. Units are user-consistent and are not
converted by the parser.
## History Data Mapping
- `*STEP` begins an ordered analysis step. If no name is provided, the parser
assigns a deterministic step name or id.
- `*STATIC` marks the step as a linear static procedure for V0.
- `*BOUNDARY` maps node id, dof range, and value to prescribed boundary
conditions.
- `*CLOAD` maps node id, dof component, and magnitude to concentrated loads.
- Output request keywords define requested quantities when semantic storage
exists; unsupported quantities must not be silently accepted.
## Internal Model Contract
- `Domain` owns model definition data created from the input file.
- Parsed model objects should be treated as immutable after parsing where
practical.
- `AnalysisStep` owns step-local boundary conditions and loads.
- The parser must not store equation ids on nodes or elements.
- Parser diagnostics are part of the result; callers do not need to inspect
partial `Domain` state to detect failure.
## Output HDF5 Schema
The parser itself does not write HDF5. Solver output remains authoritative in
`results.h5` and follows the project HDF5 contract:
| quantity | dataset_path | location | component policy |
| --- | --- | --- | --- |
| displacement | `/steps/<step>/frames/<frame>/field_outputs/U` | nodal | `U1`, `U2`, `U3` as applicable |
| reaction | `/steps/<step>/frames/<frame>/field_outputs/RF` | nodal | `RF1`, `RF2`, `RF3` as applicable |
| internal force | `/steps/<step>/frames/<frame>/field_outputs/element_forces` | element | feature-specific |
| stress | `/steps/<step>/frames/<frame>/field_outputs/S` | integration point or element | feature-specific |
Required metadata includes schema version, model id, source input identity,
coordinate system, units policy, solver version, step/frame identity, and row
identity fields.
## FESA HDF5 To Reference CSV Comparison Schema
Reference comparison reads `results.h5` and matches deterministic rows against
Abaqus-generated CSV files under `reference/<model-id>/`. This parser phase does
not generate or modify those reference artifacts.
Common row identity:
- sort order: step, frame, entity id, location, component
- node id and element id are Abaqus labels preserved by the parser
- component names follow the HDF5 component policy
CSV files remain:
- `<model-id>_displacements.csv`
- `<model-id>_reactions.csv`
- `<model-id>_internalforces.csv`
- `<model-id>_stresses.csv`
## Validation Rules
- Duplicate node, element, material, property, set, or step labels are errors.
- Missing references are errors.
- Unsupported keywords are errors unless explicitly documented otherwise.
- Malformed numeric fields are errors.
- Parser unit tests must cover valid subset mapping and invalid subset
diagnostics before production parser changes.
- Workspace validation remains `python scripts/validate_workspace.py`.
## Downstream Handoff
Implementation planning should split work into mesh keyword parsing,
diagnostics, set/section mapping, material/history mapping, and integration
validation. Reference model work may later use this subset to prepare
`reference/<model-id>/model.inp`, but this phase must not create or modify
Abaqus reference CSV artifacts.
+94
View File
@@ -0,0 +1,94 @@
# 3D Euler-Bernoulli Beam I/O Definition
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- source_formulation: docs/formulations/euler-beam-3d-formulation.md
- source_numerical_review: docs/numerical-reviews/euler-beam-3d-review.md
- source_research: docs/research/euler-beam-3d-research.md
- status: ready-for-implementation-planning
- owner_agent: io-definition-agent
- date: 2026-06-12
## Abaqus Input Scope
- input_format: Abaqus input file (`.inp`) in a future parser integration phase.
- compatibility_disclaimer: FESA will support only the keyword subset defined for this feature; full Abaqus compatibility is not claimed.
- kernel_increment_status: no parser, HDF5 writer, or reference comparison implementation is included in the current kernel phase.
| keyword | support_status | level | required_parameters | mapped_internal_concept | notes |
| --- | --- | --- | --- | --- | --- |
| `*NODE` | future-supported | model | none | node id and global coordinates | Required for future beam geometry. |
| `*ELEMENT` | future-supported | model | `TYPE` | two-node beam topology | Candidate Abaqus-equivalent type: `B31`; exact subset remains future parser work. |
| `*MATERIAL` | future-supported | model | `NAME` | material identity | Required before solver integration. |
| `*ELASTIC` | future-supported | model | none | `E`, Poisson ratio or `E,G` derivation policy | Future contract must define `G` source. |
| beam section keyword | future-supported | model | section assignment | `A`, `J`, `Iy`, `Iz` | Exact Abaqus keyword subset is not implemented in this kernel phase. |
| orientation data | future-supported | model | orientation vector | local axis construction | Must define nonparallel orientation vector. |
| `*BOUNDARY` | future-supported | history | DOF range | constrained DOFs | DOF numbers `1..6` map to `ux,uy,uz,rx,ry,rz`. |
| `*CLOAD` | future-supported | history | node, DOF, magnitude | concentrated load | Distributed loads are out of this kernel increment. |
| `*STEP` / procedure | future-supported | history | procedure data | linear static step | Solver integration gate. |
| output keywords | future-supported | history | output variables | HDF5 field/history requests | Authoritative output remains `results.h5`. |
## Syntax Policy
- case_insensitivity: future parser should treat Abaqus keyword names case-insensitively.
- comma_separated_fields: future parser should follow the existing parser subset policy when this feature is integrated.
- comment_lines: lines beginning with `**`.
- unsupported_keywords: unsupported with a clear diagnostic unless a future I/O contract explicitly marks them ignored-with-warning.
- ascii_assumption: input text policy follows the parser project contract.
## Model Data Mapping
- nodes: node label and three global Cartesian coordinates.
- elements: two node labels and semantic topology `beam2`.
- material: linear elastic constants sufficient to obtain `E` and `G`.
- section: constants `A`, `J`, `Iy`, `Iz` assigned to the beam element set.
- coordinates: global Cartesian coordinates plus a local orientation vector.
- units: user-consistent and recorded in future metadata.
## History Data Mapping
- boundary_conditions: Abaqus DOF numbers map as `1=ux`, `2=uy`, `3=uz`, `4=rx`, `5=ry`, `6=rz`.
- loads: future `*CLOAD` concentrated nodal loads may use the same DOF numbering.
- output_requests: future nodal displacement, reaction, and element internal force requests must map to HDF5 datasets.
## Internal Model Contract
- element_type: two-node 3D Euler-Bernoulli beam semantic model, not an Abaqus compatibility claim.
- connectivity: exactly two distinct nodes.
- orientation: nonzero vector not parallel to the beam axis.
- section_constants: positive finite `A`, `J`, `Iy`, `Iz`.
- material_constants: positive finite `E` and `G`.
- unsupported_cases: shear deformation, warping, releases, offsets, distributed loads, mass, geometric stiffness, nonlinear kinematics, dynamics, and thermal coupling.
## Output HDF5 Schema
This kernel phase does not write HDF5. Future solver integration should extend authoritative `results.h5` output with:
| quantity | dataset_path | shape | dtype | required_attributes | location | notes |
| --- | --- | --- | --- | --- | --- | --- |
| displacement | `/steps/<step>/frames/<frame>/nodal/displacement` | `<nnode, 6>` | float64 | component names, units, coordinate system | nodal | Components `ux,uy,uz,rx,ry,rz`. |
| reaction | `/steps/<step>/frames/<frame>/nodal/reaction` | `<nnode, 6>` | float64 | component names, units, coordinate system | nodal | Requires constraints/assembly. |
| internal force | `/steps/<step>/frames/<frame>/element/internal_force` | `<nelem, 12>` | float64 | component names, units, coordinate system, element ids | element end | Components match beam local/global recovery contract. |
| stress | `/steps/<step>/frames/<frame>/element/stress` | TBD | float64 | component names, units, location | TBD | Placeholder only; stress recovery is not approved in this kernel increment. |
## FESA HDF5 to Reference CSV Comparison Schema
Future reference comparison must read FESA HDF5 rows and compare them to Abaqus-generated CSV files under `reference/<model-id>/`.
Required future CSV mappings:
- `<model-id>_displacements.csv`: step, frame, node id, `ux`, `uy`, `uz`, and future rotational components if approved for comparison.
- `<model-id>_reactions.csv`: step, frame, node id, force and moment reaction components.
- `<model-id>_internalforces.csv`: step, frame, element id, end location, component, value.
- `<model-id>_stresses.csv`: not required until stress recovery is approved.
## Validation Rules
- Reject elements whose connectivity does not contain exactly two distinct nodes.
- Reject missing or nonpositive `E`, `G`, `A`, `J`, `Iy`, or `Iz`.
- Reject missing, zero, or parallel orientation vectors when global transform construction is required.
- Reject unsupported beam keywords with a clear diagnostic in future parser work.
- Do not generate or modify Abaqus reference CSV files in this kernel phase.
## Open Issues and Downstream Handoff
### Reference Model Agent
- Future `model.inp` files must stay within the subset documented here or record open parser issues.
### Implementation Planning Agent
- Current implementation may add only kernel-level C++ tests and source files. Parser/HDF5 work remains out of scope.
### Reference Verification Agent
- Use HDF5 as authoritative FESA output when future reference comparison is implemented.
@@ -0,0 +1,76 @@
# 3D Euler-Bernoulli Beam Kernel Numerical Review
## Metadata
- feature_id: euler-beam-3d
- source_formulation: docs/formulations/euler-beam-3d-formulation.md
- status: pass-for-implementation-planning
- owner_agent: numerical-review-agent
- date: 2026-06-12
## Review Verdict
- verdict: pass-for-implementation-planning
- reason: the formulation has a bounded kernel scope, explicit DOF order, closed-form local stiffness, unambiguous transform convention, and concrete invalid-input behavior.
## Critical Findings
- No blocking numerical defects were found for kernel implementation planning.
- The formulation is not a full solver release contract. Parser, assembly, HDF5 output, reference comparison, and physics sanity remain downstream gates.
## Numerical Risk Assessment
- rigid_body_modes: expected six zero-energy modes for the unconstrained element. Implementation tests must include at least rigid global translation and local/global force consistency.
- patch_test: solver-level patch testing is blocked until assembly and parser integration exist.
- symmetry: local stiffness is symmetric by construction; global stiffness remains symmetric if `K_global = T^T K_local T` is used consistently.
- positive_definiteness: isolated element stiffness is positive semidefinite, not positive definite. Positive definiteness requires enough constraints in a solver model.
- hourglass: not applicable to closed-form Euler-Bernoulli beam stiffness.
- shear_locking: Timoshenko shear terms are excluded, so shear locking is not introduced by this kernel increment.
- volumetric_locking: not applicable.
- distortion: curved geometry and offsets are out of scope; zero or near-zero length must be rejected.
- singular_jacobian: zero length is the relevant singular mapping case.
- conditioning: very slender elements or large stiffness ratios can be ill-conditioned; tests should use moderate deterministic values.
- convergence: not applicable to this linear element kernel.
## Consistency Checks
- units: pass. `EA/L`, `GJ/L`, `EI/L^3`, `EI/L^2`, and `EI/L` have the expected force/displacement or moment/rotation dimensions for the matching DOF pairs.
- dimensions: pass. The element vector is 12x1 and stiffness is 12x12.
- signs: pass for the documented DOF order; local `v-rz` and `w-ry` coupling signs are explicitly stated.
- dof_ordering: pass. The formulation keeps node 1 DOFs followed by node 2 DOFs.
- coordinate_transforms: pass. `u_local = T*u_global`, `K_global = T^T*K_local*T`, and `f_global = T^T*f_local` are mutually consistent.
- matrix_vector_dimensions: pass.
- integration_weights: not applicable because the kernel uses closed-form stiffness.
- output_locations: pass for element end forces only; stress/strain recovery is explicitly out of scope.
## Verification Readiness
- unit_tests:
- model topology accepts `ElementTopology::beam2`.
- local stiffness representative entries match named coefficients.
- local stiffness is symmetric within `1.0e-10`.
- local force recovery equals `K*u`.
- invalid length and nonpositive section constants throw `std::invalid_argument`.
- axis-aligned transform produces global stiffness equal to local stiffness.
- rotated global stiffness remains symmetric.
- rigid global translation produces near-zero global end forces.
- simple axial extension produces equal and opposite axial end forces.
- parallel orientation vector throws `std::invalid_argument`.
- patch_tests: future solver integration gate.
- mms_or_mes: not required for this closed-form kernel increment.
- benchmark_reference_comparison: future gate after reference artifacts exist.
- missing_evidence: no missing evidence blocks kernel implementation.
## Required Revisions
### Formulation Agent
- None before implementation planning.
### Research Agent
- None before implementation planning.
### Reference Model Agent
- Future reference model artifacts remain required before release readiness, but they are not required for this kernel implementation.
## Downstream Handoff
### Implementation Planning Agent
- Use the verification readiness list as the minimum C++ TDD checklist.
- Keep tests deterministic and avoid ill-conditioned constants.
### Reference Model Agent
- Define future solution-verification models separately from these kernel-only unit tests.
@@ -0,0 +1,136 @@
# 3D Euler-Bernoulli Beam Reference Models
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- source_research: docs/research/euler-beam-3d-research.md
- source_formulation: docs/formulations/euler-beam-3d-formulation.md
- source_numerical_review: docs/numerical-reviews/euler-beam-3d-review.md
- source_io_definition: docs/io-definitions/euler-beam-3d-io.md
- status: needs-reference-artifacts
- owner_agent: reference-model-agent
- date: 2026-06-12
## Reference Strategy
- verification_scope: future solver-level verification after parser, assembly, solve, HDF5 output, and comparison tooling exist.
- code_verification: current kernel unit tests cover local stiffness, transformation, and force recovery without external reference artifacts.
- solution_verification: future cantilever and skew-orientation models will compare displacement, reaction, and internal force quantities.
- benchmark_reference_comparison: future Abaqus-generated CSV files under `reference/<model-id>/` are required before release readiness.
- excluded_validation_scope: physical experiment validation is not in scope.
## Model Inventory
| model_id | category | purpose | status | required_artifacts |
| --- | --- | --- | --- | --- |
| `eb3d-axial-cantilever` | analytical | axial bar-as-beam displacement, reaction, and axial end force | needs-reference-artifacts | `model.inp`, `metadata.json`, displacement, reaction, internal force CSV, README |
| `eb3d-torsion-cantilever` | analytical | torsional rotation, reaction moment, and torsional end moment | needs-reference-artifacts | `model.inp`, `metadata.json`, displacement/rotation, reaction, internal force CSV, README |
| `eb3d-bend-y-cantilever` | analytical | bending response using `EIy` | needs-reference-artifacts | `model.inp`, `metadata.json`, displacement, reaction, internal force CSV, README |
| `eb3d-bend-z-cantilever` | analytical | bending response using `EIz` | needs-reference-artifacts | `model.inp`, `metadata.json`, displacement, reaction, internal force CSV, README |
| `eb3d-skew-transform` | regression | skew-oriented beam transform and component mapping | needs-reference-artifacts | `model.inp`, `metadata.json`, displacement, reaction, internal force CSV, README |
## Model Records
### `eb3d-axial-cantilever`
- category: analytical.
- verified_requirements: EB3D-REQ-005, EB3D-REQ-007, future solver I/O requirements.
- analysis_type: linear static.
- element_type: two-node 3D Euler-Bernoulli beam, Abaqus-equivalent candidate `B31`.
- expected_physical_quantities: axial displacement, support reaction, element axial end force.
- artifact_status: needs-reference-artifacts.
### `eb3d-torsion-cantilever`
- category: analytical.
- verified_requirements: EB3D-REQ-005, EB3D-REQ-007.
- analysis_type: linear static.
- expected_physical_quantities: twist, reaction moment about beam axis, torsional end moment.
- artifact_status: needs-reference-artifacts.
### `eb3d-bend-y-cantilever`
- category: analytical.
- verified_requirements: EB3D-REQ-005, EB3D-REQ-007.
- analysis_type: linear static.
- expected_physical_quantities: transverse displacement, support reaction, bending end forces using `EIy`.
- artifact_status: needs-reference-artifacts.
### `eb3d-bend-z-cantilever`
- category: analytical.
- verified_requirements: EB3D-REQ-005, EB3D-REQ-007.
- analysis_type: linear static.
- expected_physical_quantities: transverse displacement, support reaction, bending end forces using `EIz`.
- artifact_status: needs-reference-artifacts.
### `eb3d-skew-transform`
- category: regression.
- verified_requirements: EB3D-REQ-006, EB3D-REQ-008, EB3D-REQ-011.
- analysis_type: linear static.
- expected_physical_quantities: transformed displacement, reaction, and internal force components.
- artifact_status: needs-reference-artifacts.
## Abaqus Input Requirements
- input_file: `reference/<model-id>/model.inp`.
- supported_keyword_subset: must follow docs/io-definitions/euler-beam-3d-io.md when future parser work is approved.
- model_data: nodes, one or more beam elements, material, section, orientation, and units.
- history_data: linear static step, boundary conditions, concentrated loads or moments, and output requests.
- unsupported_keyword_policy: unsupported unless explicitly added by a future I/O contract.
## Artifact Bundle Contract
```text
reference/
<model-id>/
model.inp
metadata.json
<model-id>_displacements.csv
<model-id>_reactions.csv
<model-id>_internalforces.csv
README.md
```
`<model-id>_stresses.csv` is not required until stress recovery is approved. No artifact in this bundle is created or modified in the current phase.
## Metadata JSON Contract
Future `metadata.json` files must include:
- `feature_id`
- `model_id`
- `artifact_status`
- `input_file`
- Abaqus version/source and generation owner
- generation date
- source documents
- units and coordinate system
- analysis type and element types
- material and section values
- boundary and load summaries
- output requests
- reference CSV schema version
- reference CSV files
- tolerance policy
- limitations
## Coverage Matrix
| requirement_id | model_id | compared_quantity | fesa_hdf5_dataset | reference_csv | tolerance | verification_method | status |
| --- | --- | --- | --- | --- | --- | --- | --- |
| EB3D-REQ-005 | `eb3d-axial-cantilever` | displacement/internal force | `/steps/<step>/frames/<frame>/nodal/displacement`, `/element/internal_force` | displacement/internal force CSV | TBD | hdf5-to-reference-csv | needs-reference-artifacts |
| EB3D-REQ-006 | `eb3d-skew-transform` | displacement/reaction/internal force | displacement, reaction, internal force HDF5 datasets | displacement/reaction/internal force CSV | TBD | hdf5-to-reference-csv | needs-reference-artifacts |
| EB3D-REQ-007 | `eb3d-torsion-cantilever` | rotation/reaction/internal force | displacement, reaction, internal force HDF5 datasets | displacement/reaction/internal force CSV | TBD | hdf5-to-reference-csv | needs-reference-artifacts |
| EB3D-REQ-008 | `eb3d-skew-transform` | global end force | `/steps/<step>/frames/<frame>/element/internal_force` | internal force CSV | TBD | hdf5-to-reference-csv | needs-reference-artifacts |
| EB3D-REQ-011 | `eb3d-skew-transform` | transform consistency | displacement and internal force datasets | displacement/internal force CSV | TBD | hdf5-to-reference-csv | needs-reference-artifacts |
## Artifact Acceptance Checklist
- No files under `reference/` are created or modified in this phase.
- Every future model must document provenance before use as verification evidence.
- Required CSV files keep the model status at `needs-reference-artifacts` until generated through an approved reference phase.
- Stress CSV files remain out of scope until stress recovery is approved.
## Open Issues and Downstream Handoff
### I/O Definition Agent
- Finalize the exact beam section and orientation keyword subset before creating `model.inp` files.
### Implementation Planning Agent
- Kernel TDD may proceed without reference artifacts because this phase only implements element-level matrix and recovery routines.
### Reference Verification Agent
- Do not compare results until authoritative HDF5 output and approved CSV artifacts exist.
+131
View File
@@ -0,0 +1,131 @@
# 3D Euler-Bernoulli Beam Kernel Release Readiness Note
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- source_formulation: docs/formulations/euler-beam-3d-formulation.md
- source_numerical_review: docs/numerical-reviews/euler-beam-3d-review.md
- source_io_definition: docs/io-definitions/euler-beam-3d-io.md
- source_reference_model: docs/reference-models/euler-beam-3d-reference-models.md
- source_implementation_plan: docs/implementation-plans/euler-beam-3d-implementation-plan.md
- source_build_test_report: docs/build-test-reports/euler-beam-3d-build-test.md
- source_reference_verification_report: N/A
- source_physics_evaluation_report: N/A
- status: not-release-ready-kernel-increment-complete
- owner_agent: release-agent
- date: 2026-06-12
## Release Scope
| item | included | excluded | notes |
| --- | --- | --- | --- |
| analysis_type | element kernel calculations | full linear static solve | Solver integration is not complete. |
| element_type | two-node straight prismatic 3D Euler-Bernoulli beam kernel | Timoshenko beams, curved beams, offsets, releases, warping | Kernel scope only. |
| material_model | positive finite `E` and `G` constants supplied to the kernel | material parser or library integration | No material database integration. |
| section_model | positive finite `A`, `J`, `Iy`, `Iz` constants supplied to the kernel | beam section parser/property integration | Future I/O phase required. |
| output_quantities | local/global stiffness and local/global end forces returned in memory | HDF5 results, reference CSV views, stress recovery | Authoritative output path is future work. |
## Completed Kernel Increment
- Added semantic `ElementTopology::beam2`.
- Added local 12x12 Euler-Bernoulli beam stiffness for axial, torsion, and two bending planes.
- Added local end-force recovery as `K_local * u_local`.
- Added local axis construction from two nodes plus an orientation vector.
- Added global stiffness transformation using `K_global = T^T K_local T`.
- Added global end-force recovery using the same transformation convention.
- Added unit tests for topology, local stiffness entries, local symmetry, local force recovery, invalid local inputs, identity transform, rotated symmetry, rigid translation, axial extension, parallel orientation, and zero orientation.
## Missing For Full Feature Release
- Parser implementation for the approved Abaqus subset.
- Beam section/property semantic model integration.
- Material-to-section mapping for `E`, `G`, `A`, `J`, `Iy`, and `Iz`.
- Assembler and static solver integration.
- HDF5 result emission for beam displacement, reaction, and internal force quantities.
- Stored Abaqus reference artifacts under `reference/<model-id>/`.
- Reference comparison report.
- Physics sanity report.
- Final release report with all upstream gates passing.
## Gate Evidence Inventory
| gate | source | expected_status | observed_status | verdict |
| --- | --- | --- | --- | --- |
| requirements | docs/requirements/euler-beam-3d.md | sufficient for kernel | draft with explicit kernel scope | pass for kernel |
| research | docs/research/euler-beam-3d-research.md | ready-for-formulation | ready-for-formulation | pass |
| formulation | docs/formulations/euler-beam-3d-formulation.md | ready-for-numerical-review | ready-for-numerical-review | pass |
| numerical_review | docs/numerical-reviews/euler-beam-3d-review.md | pass-for-implementation-planning | pass-for-implementation-planning | pass |
| io_definition | docs/io-definitions/euler-beam-3d-io.md | future integration contract | ready-for-implementation-planning | pass for planning |
| reference_model | docs/reference-models/euler-beam-3d-reference-models.md | artifacts present for release | needs-reference-artifacts | fail for release |
| implementation | source and tests | implemented kernel | implemented kernel | pass for kernel |
| build_test | docs/build-test-reports/euler-beam-3d-build-test.md | pass | pass-for-reference-verification | pass |
| reference_verification | docs/reference-verifications/euler-beam-3d-reference-verification.md | pass-for-physics-evaluation | missing | fail for release |
| physics_evaluation | docs/physics-evaluations/euler-beam-3d-physics-evaluation.md | pass-for-release-agent | missing | fail for release |
## Acceptance Traceability
| requirement_id | release_disposition |
| --- | --- |
| EB3D-REQ-001 through EB3D-REQ-011 | Implemented and unit-tested at kernel level. Full solver evidence deferred. |
| EB3D-REQ-012 | Excluded behaviors remain out of scope. |
| EB3D-REQ-013 | No reference artifacts were created or modified. |
| EB3D-REQ-014 | No full Abaqus compatibility claim is made. |
| EB3D-REQ-015 | Kernel completion is explicitly separate from full solver release readiness. |
## Validation Evidence
| command_or_report | expected | observed | notes |
| --- | --- | --- | --- |
| `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "model_element_test\|euler_beam_3d_(local_stiffness\|transform_recovery)_test"` | pass | pass, 3/3 tests | Feature-specific CTest filter passed. |
| `python -m unittest discover -s scripts -p "test_*.py"` | pass | pass, 104 tests | Harness self-test passed. |
| `python scripts/validate_workspace.py` | pass | pass, 23/23 CTests | Used absolute CMake/CTest commands through `HARNESS_VALIDATION_COMMANDS`. |
## Known Limitations
| limitation | category | user_impact | disposition |
| --- | --- | --- | --- |
| No parser support for beam input yet. | input | Users cannot run beam `.inp` models end-to-end. | deferred |
| No section/property model integration. | model | Constants must be supplied directly to the kernel API. | deferred |
| No assembly/static solver integration. | solver | Beam elements do not contribute to a global system yet. | deferred |
| No HDF5 result output for beam quantities. | output | No official solver output exists for beam results. | deferred |
| No reference artifacts or comparison report. | verification | Full solver correctness against Abaqus is not established. | blocker for release |
| No stress or strain recovery. | physics/output | Stress CSV and stress HDF5 datasets are not available. | deferred |
| No shear deformation, warping, releases, offsets, mass, geometric stiffness, nonlinear, dynamic, or thermal behavior. | physics | Feature is limited to the approved Euler-Bernoulli kernel. | documented |
## Release Notes Draft
### Feature Summary
- Kernel increment for a two-node 3D Euler-Bernoulli beam element is complete.
### Verification Scope
- Unit-tested local stiffness, local end forces, global transform, global end forces, and invalid geometry/section handling.
### Main Limitations
- This is not an end-to-end solver feature. Parser, assembly, HDF5 output, reference comparison, and physics sanity remain future gates.
### Artifacts
- docs/build-test-reports/euler-beam-3d-build-test.md
- docs/requirements/euler-beam-3d.md
- docs/formulations/euler-beam-3d-formulation.md
- docs/reference-models/euler-beam-3d-reference-models.md
## Release Verdict
- verdict: not-release-ready-kernel-increment-complete
- reason: kernel implementation and build/test validation are complete, but full feature release lacks parser integration, HDF5 output, reference artifacts, reference verification, and physics sanity evidence.
## Handoff Recommendation
| target_agent | reason | required_input |
| --- | --- | --- |
| Coordinator Agent | Decide next phase sequencing. | This release note and phase index. |
| I/O Definition Agent | Finalize exact Abaqus beam subset and section/orientation keywords. | Current I/O contract and kernel API behavior. |
| Reference Model Agent | Generate approved future reference artifact contracts and then artifacts in an explicit phase. | Reference model contract. |
| Implementation Agent | Integrate kernel into parser/model/assembly only after upstream contracts are approved. | Implementation plan and build/test report. |
## No-Change Assertion
- source_files_modified: false in this release note step.
- test_files_modified: false in this release note step.
- cmake_files_modified: false.
- reference_artifacts_modified: false.
- tolerance_policies_modified: false.
## Open Issues
- Full solver release remains blocked until the missing gates listed above are completed.
+201
View File
@@ -0,0 +1,201 @@
# 3D Euler-Bernoulli Beam Kernel Requirements
## Metadata
- feature_id: euler-beam-3d
- title: Kernel-first 3D Euler-Bernoulli beam element
- status: draft
- owner_agent: requirement-agent
- date: 2026-06-12
## Purpose
Define the first implementable requirements baseline for a two-node, straight, prismatic, small-displacement 3D Euler-Bernoulli beam element kernel. This increment is limited to element-level stiffness and end-force recovery so downstream formulation, numerical review, and C++ implementation can proceed without claiming full solver readiness.
## Assumptions
- The element is a two-node straight beam with nonzero length.
- The element uses small-displacement, small-rotation, linear elastic kinematics.
- Each node has six mechanical DOFs in this order: `ux, uy, uz, rx, ry, rz`.
- The element displacement vector order is node 1 DOFs followed by node 2 DOFs, each in `ux, uy, uz, rx, ry, rz` order.
- Section and material constants are constant over the element: `E`, `G`, `A`, `J`, `Iy`, `Iz`.
- `Iy` and `Iz` are second moments of area about the element local principal bending axes, and `J` is the torsional constant about the local beam axis.
- Units are user-consistent; the kernel does not perform unit conversion in this increment.
- The local element basis is right-handed and orthonormal. The local `x` axis follows node 1 to node 2; the source of local `y` and `z` orientation for parser or solver integration remains open.
- Boundary conditions, global equation numbering, sparse assembly, linear solve, HDF5 writing, and reference comparison are downstream solver concerns, not kernel responsibilities in this increment.
## In Scope
- Two-node, straight, prismatic 3D Euler-Bernoulli beam element kernel.
- Six mechanical DOFs per node in `ux, uy, uz, rx, ry, rz` order.
- Linear elastic section constants: `E`, `G`, `A`, `J`, `Iy`, `Iz`.
- Local 12x12 stiffness matrix support.
- Global 12x12 stiffness matrix support when a valid local-to-global transformation is supplied.
- Local and global element end-force recovery from compatible 12-entry nodal displacement vectors.
- Kernel-level verification hooks for stiffness symmetry, rigid body modes, and local/global transformation consistency.
## Out Of Scope
- Shear deformation, Timoshenko beam behavior, shear correction factors, and shear locking treatment.
- Warping DOFs, warping stiffness, restrained warping, or bimoment recovery.
- End releases, offsets, rigid links, eccentric sections, or joint constraints.
- Distributed loads, equivalent nodal load vectors, body forces, or pressure loads.
- Mass matrix, damping matrix, geometric stiffness, buckling, nonlinear kinematics, dynamics, or thermal coupling.
- Abaqus reference CSV generation or modification.
- Full Abaqus compatibility claims.
- Parser integration, end-to-end assembly, solver execution, HDF5 result output, reference comparison, physics sanity, or release readiness.
## Analysis Definition
- analysis_type: linear static kernel only
- element_type: two-node 3D Euler-Bernoulli beam
- nodes_per_element: 2
- dofs_per_node: 6
- dof_order: `ux, uy, uz, rx, ry, rz`
- element_vector_size: 12
- material_model: linear elastic constants `E` and `G`
- section_model: constant section constants `A`, `J`, `Iy`, `Iz`
- coordinate_system: local Cartesian beam frame and global Cartesian frame
- loads: not in this increment
- boundary_conditions: not in this increment
- official_solver_output: not in this increment
## Input Requirements
- The kernel must receive or derive two distinct node positions sufficient to determine element length and local `x` direction.
- The kernel must receive positive finite constants for `E`, `G`, `A`, `J`, `Iy`, and `Iz`.
- The kernel must receive a valid right-handed orthonormal local basis or equivalent transformation data before producing a global stiffness matrix or global end-force vector.
- The kernel must receive 12-entry nodal displacement vectors ordered as node 1 then node 2, with each node using `ux, uy, uz, rx, ry, rz`.
## Output Requirements
- The kernel must produce a local 12x12 stiffness matrix in the documented element DOF order.
- The kernel must produce a global 12x12 stiffness matrix in the documented global DOF order when supplied with a valid local-to-global transformation.
- The kernel must recover local element end forces from a compatible local nodal displacement vector.
- The kernel must recover global element end forces from a compatible global nodal displacement vector when supplied with the same transformation used for the global stiffness matrix.
- This increment must not write `results.h5` and must not create deterministic CSV views or Abaqus reference CSV files.
## Verification Quantities
| quantity | required_for_kernel | verification intent | downstream owner |
| --- | --- | --- | --- |
| displacement DOFs | yes | Confirm 12-entry vectors use the required `ux, uy, uz, rx, ry, rz` per-node ordering. | Implementation Planning Agent |
| reactions / end forces | yes | Confirm local and global end-force recovery is consistent with the corresponding stiffness matrix and displacement vector. | Formulation Agent; Implementation Planning Agent |
| stiffness symmetry | yes | Confirm local and global 12x12 stiffness matrices are symmetric within the formulation-defined numeric tolerance. | Numerical Review Agent; Implementation Planning Agent |
| rigid body modes | yes | Confirm an unconstrained isolated element has six zero-energy rigid body modes within the formulation-defined numeric tolerance. | Formulation Agent; Numerical Review Agent |
| local/global transformation consistency | yes | Confirm transformed stiffness and force recovery are mutually consistent for the same basis and displacement vector. | Formulation Agent; Implementation Planning Agent |
| stress | no | Stress recovery is not part of this kernel increment. | Future requirements |
| strain | no | Strain recovery is not part of this kernel increment. | Future requirements |
| energy or residual | downstream hook | Strain energy consistency may be added as a kernel verification hook after formulation review. | Numerical Review Agent |
## Tolerance Policy
- absolute_tolerance: needs-downstream-decision by Numerical Review Agent and Implementation Planning Agent
- relative_tolerance: needs-downstream-decision by Numerical Review Agent and Implementation Planning Agent
- norm_based_tolerance: needs-downstream-decision by Numerical Review Agent and Implementation Planning Agent
- Units: user-consistent structural units; no unit conversion in this increment.
- Coordinate system: local and global Cartesian frames with a right-handed orthonormal element basis.
- Rule: any numerical kernel test added later must state the tolerance source and whether it checks component-wise values, matrix norms, eigenvalue/residual norms, or force vector norms.
## Reference Artifact Requirements
Reference artifacts are not required for kernel completion in this increment.
Future end-to-end solver verification may use a bundle under `reference/<model-id>/`, but this requirements baseline does not authorize creating, modifying, or regenerating Abaqus reference CSV files.
| artifact | kernel increment status | future solver-release status |
| --- | --- | --- |
| `model.inp` | not required | required after parser and assembly scope is approved |
| `metadata.json` | not required | required with provenance for approved reference artifacts |
| `<model-id>_displacements.csv` | not required | required for reference comparison |
| `<model-id>_reactions.csv` | not required | required for reaction/end-force comparison |
| `<model-id>_internalforces.csv` | not required | required when internal force comparison scope is approved |
| `<model-id>_stresses.csv` | not required | not required until stress recovery is in scope |
## Must Requirements
| id | requirement |
| --- | --- |
| EB3D-REQ-001 | The beam kernel must model only a two-node, straight, prismatic, small-displacement 3D Euler-Bernoulli beam element in this increment. |
| EB3D-REQ-002 | The beam kernel must use six mechanical DOFs per node ordered as `ux, uy, uz, rx, ry, rz`. |
| EB3D-REQ-003 | The beam kernel must use a 12-entry element vector ordered as all node 1 DOFs followed by all node 2 DOFs. |
| EB3D-REQ-004 | The beam kernel must accept linear elastic constants `E` and `G` and section constants `A`, `J`, `Iy`, and `Iz`. |
| EB3D-REQ-005 | The beam kernel must produce a local 12x12 stiffness matrix in the documented local DOF order. |
| EB3D-REQ-006 | The beam kernel must produce a global 12x12 stiffness matrix when supplied with a valid right-handed orthonormal local-to-global transformation. |
| EB3D-REQ-007 | The beam kernel must recover local element end forces from a compatible local nodal displacement vector. |
| EB3D-REQ-008 | The beam kernel must recover global element end forces from a compatible global nodal displacement vector and the same transformation convention used for global stiffness. |
| EB3D-REQ-009 | The local and global stiffness matrices must be symmetric within the formulation-defined tolerance. |
| EB3D-REQ-010 | The unconstrained isolated element stiffness must preserve six rigid body modes within the formulation-defined tolerance. |
| EB3D-REQ-011 | The local and global stiffness and end-force recovery paths must be mutually consistent under the same transformation. |
| EB3D-REQ-012 | The kernel increment must not include shear deformation, warping, end releases, offsets, distributed loads, mass matrix, geometric stiffness, nonlinear kinematics, dynamics, or thermal coupling. |
| EB3D-REQ-013 | The kernel increment must not create, modify, or regenerate Abaqus reference CSV files. |
| EB3D-REQ-014 | The requirements and downstream implementation must not claim full Abaqus compatibility for this feature. |
| EB3D-REQ-015 | The kernel completion criteria must be separate from full solver release readiness. |
## Requirement Verification Matrix
| id | source | priority | verification_method | acceptance_criteria | tolerance | downstream_agents | status |
| --- | --- | --- | --- | --- | --- | --- | --- |
| EB3D-REQ-001 | user step scope | must | formulation review; C++ unit tests in later implementation steps | Formulation and implementation address only the scoped Euler-Bernoulli beam kernel and do not add excluded behaviors. | not numeric | Formulation Agent; Implementation Planning Agent | draft |
| EB3D-REQ-002 | user step scope | must | unit test; code review | Tests or implementation checks demonstrate the exact per-node DOF order `ux, uy, uz, rx, ry, rz`. | not numeric | Implementation Planning Agent | draft |
| EB3D-REQ-003 | user step scope | must | unit test; code review | Tests or implementation checks demonstrate the 12-entry node 1 then node 2 vector order. | not numeric | Implementation Planning Agent | draft |
| EB3D-REQ-004 | user step scope | must | input validation test in later implementation steps | Nonpositive or nonfinite constants are rejected or diagnosed according to the downstream implementation contract. | not numeric for this baseline | I/O Definition Agent; Implementation Planning Agent | draft |
| EB3D-REQ-005 | user step scope | must | formulation review; local stiffness unit test | Local stiffness is 12x12, uses the documented local DOF order, and matches formulation-specified benchmark values. | formulation-defined | Formulation Agent; Numerical Review Agent; Implementation Planning Agent | draft |
| EB3D-REQ-006 | user step scope | must | transformation unit test | Global stiffness is 12x12 and matches the formulation-specified transformation of the local matrix. | formulation-defined | Formulation Agent; Implementation Planning Agent | draft |
| EB3D-REQ-007 | user step scope | must | local force recovery unit test | Local end-force output is consistent with the local stiffness matrix and local displacement vector. | formulation-defined | Formulation Agent; Implementation Planning Agent | draft |
| EB3D-REQ-008 | user step scope | must | global force recovery unit test | Global end-force output is consistent with global stiffness, global displacement, and the local/global transformation convention. | formulation-defined | Formulation Agent; Implementation Planning Agent | draft |
| EB3D-REQ-009 | user verification notes | must | matrix symmetry unit test | Local and global stiffness matrices satisfy symmetry checks within the selected matrix tolerance. | needs-downstream-decision | Numerical Review Agent; Implementation Planning Agent | draft |
| EB3D-REQ-010 | user verification notes | must | rigid body mode unit test; numerical review | Six rigid body modes produce zero or tolerance-bounded internal force/energy for an unconstrained isolated element. | needs-downstream-decision | Formulation Agent; Numerical Review Agent | draft |
| EB3D-REQ-011 | user verification notes | must | transformation consistency unit test | Stiffness transformation and end-force transformation use one consistent convention for the same local basis. | formulation-defined | Formulation Agent; Implementation Planning Agent | draft |
| EB3D-REQ-012 | user exclusions | must | scope review; code review | No excluded behavior appears in requirements, formulation, or kernel implementation for this increment. | not numeric | Coordinator Agent; Implementation Planning Agent | draft |
| EB3D-REQ-013 | user forbidden list | must | git diff review | No file under `reference/` and no Abaqus reference CSV is created or modified in this increment. | not numeric | Reference Model Agent; Coordinator Agent | draft |
| EB3D-REQ-014 | ADR-003; user verification notes | must | documentation review; I/O contract review | Documentation states this is a limited feature subset and does not claim full Abaqus compatibility. | not numeric | I/O Definition Agent; Coordinator Agent | draft |
| EB3D-REQ-015 | project acceptance gates | must | release gate review | Kernel completion can be marked separately, while full solver release remains blocked until parser, assembly, HDF5 output, reference comparison, physics sanity, and release readiness gates pass. | not numeric | Release Agent; Coordinator Agent | draft |
## Acceptance Criteria
### This Documentation Step
- `docs/requirements/euler-beam-3d.md` exists and contains metadata, assumptions, non-goals, must requirements, verification quantities, acceptance criteria, and open issues.
- The document does not create source, test, or reference artifact files.
- The document does not claim full Abaqus compatibility.
- Every `must` requirement has an acceptance criterion or downstream verification hook in the Requirement Verification Matrix.
- The following validation commands pass:
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
### Kernel Completion
Kernel completion may be claimed only after downstream implementation steps provide C++ tests and implementation evidence for:
- local 12x12 stiffness matrix generation;
- global 12x12 stiffness matrix transformation;
- local and global end-force recovery;
- DOF ordering;
- stiffness symmetry;
- six rigid body modes;
- local/global transformation consistency.
Kernel completion does not require Abaqus reference CSV files, `results.h5`, parser integration, global sparse assembly, or release readiness.
### Full Solver Release Readiness
Full solver release readiness is not in scope for this increment. It requires later evidence for:
- parser and I/O contract approval for the beam feature;
- Domain, AnalysisModel, DofManager, assembly, constraints, solve, and ResultsWriter integration;
- HDF5 result schema coverage;
- approved reference artifacts under `reference/<model-id>/`;
- FESA `results.h5` to Abaqus reference CSV comparison;
- physics sanity review;
- release readiness review with known limitations.
## Open Issues
- Parser integration: define the approved Abaqus keyword subset, beam section mapping, orientation input, and unsupported keyword diagnostics before parser work starts.
- Reference artifact availability: no Abaqus reference CSV files are required or generated in this kernel increment; approved reference artifacts are still needed for later solver-level verification.
- Full end-to-end assembly: global sparse assembly, boundary condition application, reaction recovery, solve flow, and HDF5 output are not covered by this kernel baseline.
- Local orientation convention: downstream formulation and I/O contract must define how local `y` and `z` axes are supplied, derived, validated, and reported.
- Tolerance values: downstream numerical review must select tolerances for matrix symmetry, rigid body mode residuals, transformation consistency, and force recovery.
## Downstream Handoff
### Research Agent
- Confirm authoritative Euler-Bernoulli 3D beam references and benchmark cases for stiffness, transformation, and rigid body checks.
### Formulation Agent
- Define local stiffness, transformation convention, end-force recovery convention, rigid body mode checks, and edge cases for invalid geometry or constants.
### Numerical Review Agent
- Review stiffness symmetry, rank/rigid body modes, sign conventions, transformation convention, conditioning risks, and numerical tolerances.
### I/O Definition Agent
- Define future parser and semantic model mapping for beam geometry, section constants, material constants, and local orientation without claiming full Abaqus compatibility.
### Reference Model Agent
- Define future reference model bundles only after parser and end-to-end solver scope is approved; do not generate reference CSV files in this increment.
### Implementation Planning Agent
- Plan C++ tests before production code for local stiffness, global transformation, end-force recovery, DOF order, symmetry, rigid body modes, and invalid inputs.
+81
View File
@@ -0,0 +1,81 @@
# 3D Euler-Bernoulli Beam Kernel Research Brief
## Metadata
- feature_id: euler-beam-3d
- source_requirement: docs/requirements/euler-beam-3d.md
- status: ready-for-formulation
- owner_agent: research-agent
- date: 2026-06-12
## Research Questions
- What theory is sufficient for a straight, prismatic, two-node 3D Euler-Bernoulli beam kernel?
- Which terms must appear in the local stiffness matrix for axial, torsion, and two uncoupled bending planes?
- Which implementation checks can verify the kernel without running Abaqus or creating reference CSV artifacts?
- Which input cases must be rejected before matrix construction?
## Source Inventory
| source_type | title | author_or_org | URL_or_identifier | access_date | reliability_tier | notes |
| --- | --- | --- | --- | --- | --- | --- |
| textbook | Concepts and Applications of Finite Element Analysis | Cook, Malkus, Plesha, Witt | ISBN 978-0-471-35605-9 | 2026-06-12 | Tier 2 | Beam element stiffness and coordinate transformation background. |
| textbook | A First Course in the Finite Element Method | Daryl L. Logan | ISBN 978-1-305-63511-1 | 2026-06-12 | Tier 2 | Direct-stiffness beam and frame examples. |
| textbook | Matrix Structural Analysis | William McGuire, Richard H. Gallagher, Ronald D. Ziemian | ISBN 978-0-471-12379-7 | 2026-06-12 | Tier 2 | Space-frame element local stiffness and transformation conventions. |
| project requirement | 3D Euler-Bernoulli Beam Kernel Requirements | FESA | docs/requirements/euler-beam-3d.md | 2026-06-12 | Tier 1 project contract | Defines approved kernel scope and exclusions. |
## Extracted Facts
- Verified fact: a 3D straight prismatic Euler-Bernoulli beam frame element can be assembled from one axial response, one torsional response, and two uncoupled cubic-Hermite bending responses in the element local frame.
- Verified fact: for a local element axis `x`, bending displacement in local `y` couples with rotation about local `z` and uses `EIz`; bending displacement in local `z` couples with rotation about local `y` and uses `EIy`.
- Verified fact: a two-node space-frame element with six DOFs per node has a 12-entry vector. The FESA requirement fixes per-node order as `ux, uy, uz, rx, ry, rz`.
- Verified fact: the unconstrained element local stiffness is symmetric positive semidefinite and has six rigid body modes before constraints are applied.
- Project contract: no shear deformation, warping, end releases, offsets, mass, geometric stiffness, nonlinear kinematics, parser integration, HDF5 output, or reference artifact generation is allowed in this kernel increment.
## Candidate Benchmarks
| benchmark_id | source | benchmark_type | physics | target_quantities | artifact_needs | applicability |
| --- | --- | --- | --- | --- | --- | --- |
| EB3D-BENCH-001 | project/formulation | code verification | local matrix algebra | symmetry of all `K(i,j)` | C++ unit test only | Does not verify solver assembly. |
| EB3D-BENCH-002 | direct stiffness theory | analytical | axial extension | `EA/L` terms and equal/opposite axial end forces | C++ unit test only | Axis-aligned local response. |
| EB3D-BENCH-003 | direct stiffness theory | analytical | torsion | `GJ/L` terms and equal/opposite torsional end moments | C++ unit test only | Saint-Venant torsion constant assumed supplied. |
| EB3D-BENCH-004 | beam theory | analytical | bending in local `x-y` | `12EIz/L^3`, `6EIz/L^2`, `4EIz/L`, `2EIz/L` terms | C++ unit test only | Euler-Bernoulli small-displacement bending. |
| EB3D-BENCH-005 | beam theory | analytical | bending in local `x-z` | `12EIy/L^3`, `6EIy/L^2`, `4EIy/L`, `2EIy/L` terms | C++ unit test only | Euler-Bernoulli small-displacement bending. |
| EB3D-BENCH-006 | matrix structural analysis | invariant | rigid body motion | local end forces are near zero for rigid translations/rotations | C++ unit test only | Numerical tolerance needed. |
| EB3D-BENCH-007 | matrix structural analysis | invariant | coordinate transform | axis-aligned global stiffness equals local stiffness when basis is identity | C++ unit test only | Does not validate parser orientation input. |
## Verification Relevance
- code_verification: local stiffness entries, symmetry, end-force recovery as `K*u`, invalid input handling, and transformation invariants can be checked by deterministic C++ unit tests.
- solution_verification: future cantilever axial, torsion, and bending reference models can compare displacements, reactions, and internal forces after parser/assembly/HDF5 integration exists.
- validation: no physical experiment validation is in scope for this kernel increment.
- reference_comparison: future reference comparison requires Abaqus-generated artifacts under `reference/<model-id>/`; this phase only defines the contract and must not create those files.
## Applicability Limits
- linear_or_nonlinear: linear only.
- deformation: small displacement and small rotation.
- element_type: straight two-node prismatic Euler-Bernoulli beam.
- material_model: constant linear elastic `E` and `G`.
- geometry: nonzero length, no offsets, no curved beams.
- boundary_conditions: not applied inside the kernel.
- loads: no distributed or equivalent nodal load vector in this increment.
- coordinate_system: right-handed local Cartesian basis and global Cartesian basis.
- units: user-consistent; no conversion.
## Risks and Open Issues
- Orientation vector parallel or nearly parallel to the beam axis must be rejected because the local `y` direction is undefined.
- Zero or near-zero length must be rejected before stiffness coefficient computation.
- Nonpositive or nonfinite `E`, `G`, `A`, `J`, `Iy`, or `Iz` must be rejected.
- Very slender beams can produce ill-conditioned local stiffness matrices; kernel tests should avoid relying on a condition-number estimate as a pass/fail criterion.
- Exact parser keyword mapping for future beam input remains open and belongs to the I/O contract, not the kernel implementation.
## Downstream Handoff
### Formulation Agent
- Define the local stiffness matrix with named axial, torsion, `EIz`, and `EIy` coefficients.
- Define the local-to-global transform convention so global stiffness and force recovery are unambiguous.
### Numerical Review Agent
- Review symmetry, rigid body modes, sign convention, coefficient dimensions, and invalid geometry handling.
### Reference Model Agent
- Future reference models should include axial cantilever, torsion cantilever, two bending cantilevers, and one skew transform case.
### Implementation Planning Agent
- Unit tests should cover representative local entries, symmetry, `K*u` force recovery, invalid constants, axis-aligned transform identity, rotated symmetry, rigid translation, and axial end forces.
-65
View File
@@ -1,65 +0,0 @@
{
"project": "FESA Structural Solver",
"phase": "abaqus-input-parser",
"steps": [
{
"step": 0,
"name": "io-contract",
"status": "completed",
"allowed_paths": [
"docs/io-definitions/abaqus-input-parser-io.md"
],
"summary": "Abaqus input parser I/O contract added"
},
{
"step": 1,
"name": "mesh-keyword-parser",
"status": "completed",
"allowed_paths": [
"src/fesa/io/abaqus/",
"tests/unit/abaqus_input_parser_*_test.cpp"
],
"summary": "Mesh keyword parser maps NODE and ELEMENT data into Domain"
},
{
"step": 2,
"name": "syntax-diagnostics",
"status": "pending",
"allowed_paths": [
"src/fesa/io/abaqus/",
"tests/unit/abaqus_input_parser_*_test.cpp"
]
},
{
"step": 3,
"name": "sets-and-section-properties",
"status": "pending",
"allowed_paths": [
"src/fesa/io/abaqus/",
"src/fesa/model/",
"tests/unit/abaqus_input_parser_*_test.cpp",
"tests/unit/model_*_test.cpp"
]
},
{
"step": 4,
"name": "material-step-load-parser",
"status": "pending",
"allowed_paths": [
"src/fesa/io/abaqus/",
"src/fesa/model/",
"tests/unit/abaqus_input_parser_*_test.cpp",
"tests/unit/model_*_test.cpp"
]
},
{
"step": 5,
"name": "integration-validation-report",
"status": "pending",
"allowed_paths": [
"tests/integration/",
"docs/build-test-reports/abaqus-input-parser.md"
]
}
]
}
-65
View File
@@ -1,65 +0,0 @@
# Step 0: io-contract
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/SOLVER_AGENT_DESIGN.md`
- `/docs/io-definitions/README.md`
## Task
Create the feature-level I/O contract for the Abaqus input parser at
`/docs/io-definitions/abaqus-input-parser-io.md`.
The contract must explicitly state that FESA supports only the documented
Abaqus keyword subset, not full Abaqus compatibility. Keep this document at a
semantic level. Do not design C++ APIs and do not implement parser code in this
step.
Required scope:
- Model data keywords: `*HEADING`, `*NODE`, `*ELEMENT`, `*NSET`, `*ELSET`,
`*MATERIAL`, `*ELASTIC`, and section keywords needed for V0 bar/truss use.
- History data keywords: `*STEP`, `*STATIC`, `*BOUNDARY`, `*CLOAD`,
`*OUTPUT`, `*NODE OUTPUT`, and `*ELEMENT OUTPUT`.
- Syntax policy for comments beginning with `**`, case-insensitive keywords,
comma-separated parameters and data, blank lines, unsupported keywords, and
parse diagnostics.
- Internal semantic mapping to `Domain`, nodes, elements, sets, materials,
properties, `AnalysisStep`, boundary conditions, loads, and output requests.
- HDF5 and reference CSV comparison schema summary consistent with existing
PRD/architecture documents. Do not create or modify reference artifacts.
## Tests To Write First
No C++ tests are required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
1. Run the acceptance criteria commands.
2. Confirm the contract does not claim full Abaqus compatibility.
3. Confirm every supported keyword has purpose, data requirements, mapping, and
unsupported-case behavior.
4. Update `phases/abaqus-input-parser/index.json` step 0:
- success: `"status": "completed"`, `"summary": "Abaqus input parser I/O contract added"`
- error after three attempts: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not implement parser code.
- Do not design C++ APIs.
- Do not run Abaqus, Nastran, or any reference solver.
- Do not generate or modify Abaqus reference CSV files.
-83
View File
@@ -1,83 +0,0 @@
# Step 1: mesh-keyword-parser
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/io-definitions/abaqus-input-parser-io.md`
- `/src/fesa/model/domain.hpp`
- `/src/fesa/model/node.hpp`
- `/src/fesa/model/element.hpp`
- `/tests/unit/model_domain_test.cpp`
Review step 0 output before implementing. Keep this step limited to parser API
and mesh keyword mapping.
## Task
Add the first C++ parser slice under `/src/fesa/io/abaqus/`.
Required behavior:
- Provide a small `InputParser` that accepts an in-memory `.inp` string and
returns a parse result containing `fesa::model::Domain` and
`fesa::core::Status`.
- Parse `*HEADING` as accepted but not yet stored.
- Parse `*NODE` data lines into `Domain::add_node`.
- Parse `*ELEMENT, TYPE=<type>` data lines into `Domain::add_element`.
- Support only two-node line/bar element names needed by the current model:
`T2D2`, `T3D2`, `B31`, and `C3D2`.
- Map `T2D2`, `T3D2`, and `C3D2` to `ElementTopology::truss2`; map `B31` to
`ElementTopology::bar2`.
- Use `PropertyId{0}` for elements in this first mesh-only slice because
section parsing is introduced later.
- Treat keywords and parameter names case-insensitively.
- Skip blank lines and comment lines that begin with `**`.
Keep implementation C++17/MSVC-compatible. Do not introduce external
libraries, regex-heavy parser frameworks, JavaScript, TypeScript, or npm
fallbacks.
## Tests To Write First
Add `/tests/unit/abaqus_input_parser_mesh_test.cpp` before production code.
The test must first fail because `fesa/io/abaqus/input_parser.hpp` does not
exist, then pass after implementation. It should verify:
- a small input with `*HEADING`, `*NODE`, and `*ELEMENT, TYPE=T3D2` returns
`Status::is_ok() == true`;
- the returned `Domain` contains the expected node ids and 3D coordinates;
- the returned `Domain` contains the expected element id, topology,
connectivity, and `PropertyId{0}`;
- keyword and parameter casing are accepted case-insensitively.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R abaqus_input_parser_mesh_test
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
1. Run the targeted CTest after writing the test and before production code;
confirm the failure is due to the missing parser API.
2. Implement the minimum code needed for the test to pass.
3. Run all acceptance criteria commands.
4. Confirm C++ production changes have a related C++ test file.
5. Update `phases/abaqus-input-parser/index.json` step 1:
- success: `"status": "completed"`, `"summary": "Mesh keyword parser maps NODE and ELEMENT data into Domain"`
- error after three attempts: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not add set, material, section, load, boundary condition, output request,
include-file, or HDF5 behavior in this step.
- Do not mutate reference artifacts.
-63
View File
@@ -1,63 +0,0 @@
# Step 2: syntax-diagnostics
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/io-definitions/abaqus-input-parser-io.md`
- `/src/fesa/io/abaqus/input_parser.hpp`
- `/src/fesa/io/abaqus/input_parser.cpp`
- `/tests/unit/abaqus_input_parser_mesh_test.cpp`
Review completed step summaries in `/phases/abaqus-input-parser/index.json`.
## Task
Add structured diagnostics for parser syntax and unsupported subset behavior.
Required behavior:
- Unsupported keywords produce `Status::is_ok() == false` with an error
diagnostic code and message that identifies the keyword.
- Malformed `*NODE` and `*ELEMENT` data lines produce error diagnostics.
- Missing required `TYPE` on `*ELEMENT` produces an error diagnostic.
- Unsupported element types produce an error diagnostic and do not add that
element.
- Diagnostics must include enough context in the message to locate the line
number.
- Existing valid mesh parser behavior remains unchanged.
## Tests To Write First
Extend `/tests/unit/abaqus_input_parser_mesh_test.cpp` or add
`/tests/unit/abaqus_input_parser_diagnostics_test.cpp` before production code.
Test:
- unsupported keyword failure;
- malformed node row failure;
- missing element `TYPE` failure;
- unsupported element type failure.
Run the targeted CTest and confirm the new tests fail for missing behavior
before implementation.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R abaqus_input_parser
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
Update step 2 status with summary or a concrete error/blocked reason.
## Forbidden
- Do not add new semantic model fields except what diagnostics require.
- Do not add material, section, step, boundary, or load parsing.
-62
View File
@@ -1,62 +0,0 @@
# Step 3: sets-and-section-properties
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/io-definitions/abaqus-input-parser-io.md`
- `/src/fesa/model/domain.hpp`
- `/src/fesa/model/element.hpp`
- `/src/fesa/model/property.hpp`
- `/src/fesa/io/abaqus/input_parser.hpp`
- `/src/fesa/io/abaqus/input_parser.cpp`
Review completed parser tests and phase summaries first.
## Task
Extend the model and parser only as needed to represent set membership and
section-to-property assignment for V0 bar/truss models.
Required behavior:
- Parse `*NSET, NSET=<name>` node membership rows.
- Parse `*ELSET, ELSET=<name>` element membership rows.
- Parse one V0 section keyword that assigns a material name to an element set.
Prefer the smallest section subset compatible with the current V0 element
path.
- Preserve deterministic member ordering as read, unless the I/O contract
explicitly states otherwise.
- Keep `Domain` as the owner of model definition data. Do not store equation ids
on nodes or elements.
## Tests To Write First
Add focused C++ tests before production code:
- a model test for any new set/section semantic model API;
- a parser test proving `*NSET`, `*ELSET`, and the selected section keyword map
into the semantic model.
Run targeted CTest and confirm the tests fail before implementation.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "(model_|abaqus_input_parser_)"
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
Update step 3 status with summary or a concrete error/blocked reason.
## Forbidden
- Do not parse materials beyond names needed for section linkage.
- Do not add loads, boundary conditions, or analysis steps.
- Do not generate or modify reference artifacts.
-65
View File
@@ -1,65 +0,0 @@
# Step 4: material-step-load-parser
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/io-definitions/abaqus-input-parser-io.md`
- `/src/fesa/model/material.hpp`
- `/src/fesa/model/analysis_step.hpp`
- `/src/fesa/model/boundary_condition.hpp`
- `/src/fesa/model/load.hpp`
- `/src/fesa/io/abaqus/input_parser.hpp`
- `/src/fesa/io/abaqus/input_parser.cpp`
Review completed parser and model tests first.
## Task
Extend the parser for the V0 material and history data subset.
Required behavior:
- Parse `*MATERIAL, NAME=<name>` and `*ELASTIC` data into the internal material
representation. If the current `Material` model cannot store elastic data,
add the smallest semantic extension with tests.
- Parse `*STEP` and `*STATIC` into ordered `AnalysisStep` definitions.
- Parse `*BOUNDARY` rows into step boundary conditions using existing
`DofComponent` mapping.
- Parse `*CLOAD` rows into step concentrated loads using existing
`DofComponent` mapping.
- Parse `*OUTPUT`, `*NODE OUTPUT`, and `*ELEMENT OUTPUT` only to the extent
documented in the I/O contract. If semantic storage is not yet present, record
an explicit ignored-with-warning diagnostic rather than inventing output model
APIs.
## Tests To Write First
Add focused C++ tests before production code:
- model tests for any new material or output request semantic fields;
- parser tests for material/elastic, step/static, boundary, and cload rows.
Run targeted CTest and confirm the tests fail before implementation.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "(model_|abaqus_input_parser_)"
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
Update step 4 status with summary or a concrete error/blocked reason.
## Forbidden
- Do not implement analysis execution, assembly, HDF5 writing, or reference
comparison in this step.
- Do not mutate reference artifacts.
-55
View File
@@ -1,55 +0,0 @@
# Step 5: integration-validation-report
## Read First
Read these files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/io-definitions/abaqus-input-parser-io.md`
- `/src/fesa/io/abaqus/input_parser.hpp`
- `/tests/unit/abaqus_input_parser_mesh_test.cpp`
- existing parser/model tests added by prior steps
Review all completed step summaries in `/phases/abaqus-input-parser/index.json`.
## Task
Add an integration-level parser test and a build/test report.
Required behavior:
- Add a small integration test that parses a V0 Abaqus `.inp` string containing
the supported parser subset and validates the resulting `Domain` and
`AnalysisStep` data.
- Keep the test in memory; do not create or modify Abaqus reference CSV
artifacts.
- Write `/docs/build-test-reports/abaqus-input-parser.md` with command evidence,
exit codes, and known limitations.
## Tests To Write First
Add `/tests/integration/abaqus_input_parser_integration_test.cpp` before any
final integration adjustments. Confirm it fails for the missing integrated
behavior, then make it pass with the minimum implementation-owned changes.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R abaqus_input_parser
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Procedure
1. Run the acceptance criteria commands.
2. Confirm no reference artifacts were generated or modified.
3. Update step 5 status with summary or a concrete error/blocked reason.
## Forbidden
- Do not claim reference comparison, physics sanity, or release readiness.
- Do not generate, restore, or modify Abaqus reference CSV files.
+113
View File
@@ -0,0 +1,113 @@
{
"project": "FESA Structural Solver",
"phase": "euler-beam-3d",
"steps": [
{
"step": 0,
"name": "requirements-baseline",
"status": "completed",
"summary": "3D Euler beam kernel requirements baseline added",
"allowed_paths": [
"docs/requirements/euler-beam-3d.md"
],
"started_at": "2026-06-12T17:44:12+0900",
"completed_at": "2026-06-12T17:50:31+0900"
},
{
"step": 1,
"name": "research-evidence",
"status": "completed",
"summary": "3D Euler beam research evidence added",
"allowed_paths": [
"docs/research/euler-beam-3d-research.md"
]
},
{
"step": 2,
"name": "formulation-spec",
"status": "completed",
"summary": "3D Euler beam formulation contract added",
"allowed_paths": [
"docs/formulations/euler-beam-3d-formulation.md"
]
},
{
"step": 3,
"name": "numerical-review",
"status": "completed",
"summary": "3D Euler beam numerical review added",
"allowed_paths": [
"docs/numerical-reviews/euler-beam-3d-review.md"
]
},
{
"step": 4,
"name": "io-reference-contract",
"status": "completed",
"summary": "3D Euler beam I/O and reference model contracts added",
"allowed_paths": [
"docs/io-definitions/euler-beam-3d-io.md",
"docs/reference-models/euler-beam-3d-reference-models.md"
]
},
{
"step": 5,
"name": "implementation-plan",
"status": "completed",
"summary": "3D Euler beam implementation plan added",
"allowed_paths": [
"docs/implementation-plans/euler-beam-3d-implementation-plan.md"
]
},
{
"step": 6,
"name": "model-beam-topology",
"status": "completed",
"summary": "beam2 model topology added with unit test",
"allowed_paths": [
"src/fesa/model/element.hpp",
"src/fesa/model/element.cpp",
"tests/unit/model_element_test.cpp"
]
},
{
"step": 7,
"name": "local-stiffness-kernel",
"status": "completed",
"summary": "local 3D Euler beam stiffness and local end-force kernel added",
"allowed_paths": [
"src/fesa/elements/",
"tests/unit/euler_beam_3d_*_test.cpp"
]
},
{
"step": 8,
"name": "global-transform-recovery",
"status": "completed",
"summary": "global transform and global end-force recovery added for 3D Euler beam",
"allowed_paths": [
"src/fesa/elements/",
"tests/unit/euler_beam_3d_*_test.cpp"
]
},
{
"step": 9,
"name": "build-test-report",
"status": "completed",
"summary": "3D Euler beam build/test report added",
"allowed_paths": [
"docs/build-test-reports/euler-beam-3d-build-test.md"
]
},
{
"step": 10,
"name": "release-readiness-note",
"status": "completed",
"summary": "3D Euler beam release readiness note added",
"allowed_paths": [
"docs/releases/euler-beam-3d-release.md"
]
}
],
"created_at": "2026-06-12T17:44:12+0900"
}
+63
View File
@@ -0,0 +1,63 @@
# Step 0: requirements-baseline
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/requirements/README.md`
## Task
Create `/docs/requirements/euler-beam-3d.md` for a kernel-first 3D Euler-Bernoulli beam feature.
Scope the first implementable increment narrowly:
- two-node, straight, prismatic, small-displacement 3D Euler-Bernoulli beam element
- six mechanical DOFs per node in this order: `ux, uy, uz, rx, ry, rz`
- linear elastic section constants: `E`, `G`, `A`, `J`, `Iy`, `Iz`
- local and global 12x12 stiffness matrix support
- local and global element end-force recovery from nodal displacement vectors
- no shear deformation, warping, end releases, offsets, distributed loads, mass matrix, geometric stiffness, nonlinear kinematics, dynamics, or thermal coupling in this increment
- no Abaqus reference CSV generation in this increment
- no full Abaqus compatibility claim
The document must contain:
- metadata: `feature_id: euler-beam-3d`, owner agent, status
- explicit assumptions and non-goals
- `must` requirements with stable IDs such as `EB3D-REQ-001`
- verification quantities: displacement DOFs, reactions/end forces, stiffness symmetry, rigid body modes, local/global transformation consistency
- acceptance criteria that distinguish kernel completion from full solver release readiness
- open issues for parser integration, reference artifact availability, and full end-to-end assembly
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
- Still run the harness validation commands in the acceptance criteria.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the requirements do not claim full Abaqus compatibility.
2. Confirm each `must` requirement has an acceptance criterion or a downstream verification hook.
3. Update `phases/euler-beam-3d/index.json` step 0:
- success: `"status": "completed"`, `"summary": "3D Euler beam kernel requirements baseline added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not create or modify reference CSV files.
- Do not modify source or test files.
+60
View File
@@ -0,0 +1,60 @@
# Step 1: research-evidence
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/research/README.md`
## Task
Create `/docs/research/euler-beam-3d-research.md`.
Summarize the evidence needed to implement the approved kernel-first 3D Euler-Bernoulli beam increment. The document must be implementation-oriented and must include:
- supported theory: straight prismatic Euler-Bernoulli beam, axial, torsion, and two uncoupled bending planes
- assumptions and applicability limits
- local DOF ordering and sign convention used by the planned matrix
- source reliability classification
- benchmark-style checks that do not require external reference solver execution:
- local stiffness symmetry
- axial-only response
- torsion-only response
- bending about local `y`
- bending about local `z`
- rigid body translation/rotation zero internal forces in local coordinates
- global transform identity for an axis-aligned beam
- risks: orientation vector parallel to element axis, near-zero length, nonpositive section constants, ill-conditioning for very slender elements
If internet access or a FEM wiki is used, cite sources briefly. Do not include long copyrighted excerpts.
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the research document ties each source or theory point to a planned implementation check.
2. Confirm unresolved items are listed as risks or open issues instead of silently assumed.
3. Update `phases/euler-beam-3d/index.json` step 1:
- success: `"status": "completed"`, `"summary": "3D Euler beam research evidence added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not modify source, test, reference, or I/O contract files.
+60
View File
@@ -0,0 +1,60 @@
# Step 10: release-readiness-note
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ADR.md`
- `/docs/releases/README.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/io-definitions/euler-beam-3d-io.md`
- `/docs/reference-models/euler-beam-3d-reference-models.md`
- `/docs/build-test-reports/euler-beam-3d-build-test.md`
## Task
Create `/docs/releases/euler-beam-3d-release.md`.
This is a readiness note, not a release approval. It must state:
- status: `not-release-ready-kernel-increment-complete` unless all upstream gates and reference artifacts somehow exist
- completed scope: local/global stiffness and end-force kernel for two-node 3D Euler-Bernoulli beam
- missing for full feature release:
- parser implementation for the approved Abaqus subset
- section/property semantic model integration
- assembler/static solver integration
- HDF5 result emission for beam quantities
- stored Abaqus reference artifacts
- reference comparison report
- physics sanity report
- known limitations from requirements
- next recommended phase or phase dependencies
Do not change source or tests in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the note does not claim full release readiness.
2. Confirm all missing gates are explicit.
3. Update `phases/euler-beam-3d/index.json` step 10:
- success: `"status": "completed"`, `"summary": "3D Euler beam release readiness note added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not create or modify reference artifacts.
- Do not modify source, tests, requirements, formulations, or I/O contracts.
+63
View File
@@ -0,0 +1,63 @@
# Step 2: formulation-spec
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/research/euler-beam-3d-research.md`
- `/docs/formulations/README.md`
## Task
Create `/docs/formulations/euler-beam-3d-formulation.md`.
The formulation must define the implementation contract for the C++ kernel. Include:
- local coordinate system: local `x` from node 1 to node 2; local `y` from the user orientation vector projected normal to local `x`; local `z = x cross y`
- local DOF order: `[u1, v1, w1, rx1, ry1, rz1, u2, v2, w2, rx2, ry2, rz2]`
- section constants: `E`, `G`, `A`, `J`, `Iy`, `Iz`
- local 12x12 stiffness matrix terms for:
- axial: `EA/L`
- torsion: `GJ/L`
- bending in local `x-y` using `EIz`
- bending in local `x-z` using `EIy`
- transformation matrix convention and global stiffness equation `K_global = T^T K_local T`
- end-force recovery equation `f_local = K_local u_local`
- validation tolerances for unit tests, using deterministic double comparisons
- singular and invalid input handling:
- zero or near-zero length throws `std::invalid_argument`
- nonpositive `E`, `G`, `A`, `J`, `Iy`, or `Iz` throws `std::invalid_argument`
- orientation vector parallel to beam axis throws `std::invalid_argument`
Use compact matrices and named scalar coefficients so the implementation step can transcribe directly.
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the matrix is symmetric by construction.
2. Confirm local/global transformation convention is unambiguous.
3. Update `phases/euler-beam-3d/index.json` step 2:
- success: `"status": "completed"`, `"summary": "3D Euler beam formulation contract added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not modify requirements, source, tests, or reference artifacts.
+56
View File
@@ -0,0 +1,56 @@
# Step 3: numerical-review
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/research/euler-beam-3d-research.md`
- `/docs/formulations/euler-beam-3d-formulation.md`
- `/docs/numerical-reviews/README.md`
## Task
Create `/docs/numerical-reviews/euler-beam-3d-review.md`.
Review the formulation for implementation readiness. The review must include:
- dimension and units check for each stiffness coefficient
- symmetry and rigid body mode expectations
- local axis construction risks
- positive semi-definite local stiffness expectation before constraints
- test obligations before production code
- known numerical limits for slender beams and very small section constants
- pass/fail verdict for kernel implementation planning
If the formulation is not ready, mark the document status as `needs-upstream-decision` and update this phase step as blocked with a concrete reason.
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the review does not change requirements or formulation.
2. Confirm implementation-owned risks are turned into concrete tests.
3. Update `phases/euler-beam-3d/index.json` step 3:
- success: `"status": "completed"`, `"summary": "3D Euler beam numerical review added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not modify requirements, formulation, source, tests, or reference artifacts.
+68
View File
@@ -0,0 +1,68 @@
# Step 4: io-reference-contract
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/formulations/euler-beam-3d-formulation.md`
- `/docs/numerical-reviews/euler-beam-3d-review.md`
- `/docs/io-definitions/README.md`
- `/docs/reference-models/README.md`
## Task
Create two documents:
- `/docs/io-definitions/euler-beam-3d-io.md`
- `/docs/reference-models/euler-beam-3d-reference-models.md`
The I/O contract must describe the planned Abaqus subset without claiming it is implemented in this kernel increment:
- element keyword mapping candidate: two-node beam topology equivalent to Abaqus `B31`
- section keyword candidate: beam section constants sufficient for `A`, `J`, `Iy`, `Iz`, `E`, and `G`
- orientation data requirement for constructing local axes
- boundary/load DOFs: `1..6` map to `ux, uy, uz, rx, ry, rz`
- HDF5 output quantities expected after solver integration: nodal displacement, reaction, element internal force, stress placeholders if stress recovery is later approved
- unsupported input cases and diagnostics
The reference model contract must list required future models without generating artifacts:
- axial cantilever bar-as-beam
- torsion cantilever
- bending cantilever about local `y`
- bending cantilever about local `z`
- skew-oriented beam transform check
For each future model, specify expected files under `reference/<model-id>/` and which CSV quantities are required. State that Abaqus reference CSVs must not be generated or modified in this phase.
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm reference artifacts are specified, not created.
2. Confirm unsupported parser or solver paths are explicit open issues.
3. Update `phases/euler-beam-3d/index.json` step 4:
- success: `"status": "completed"`, `"summary": "3D Euler beam I/O and reference model contracts added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not create or modify files under `/reference/`.
- Do not modify source or tests.
+75
View File
@@ -0,0 +1,75 @@
# Step 5: implementation-plan
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/PRD.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/SOLVER_AGENT_DESIGN.md`
- `/docs/implementation-plans/README.md`
- `/docs/requirements/euler-beam-3d.md`
- `/docs/research/euler-beam-3d-research.md`
- `/docs/formulations/euler-beam-3d-formulation.md`
- `/docs/numerical-reviews/euler-beam-3d-review.md`
- `/docs/io-definitions/euler-beam-3d-io.md`
- `/docs/reference-models/euler-beam-3d-reference-models.md`
- `/src/fesa/model/element.hpp`
- `/tests/unit/model_element_test.cpp`
## Task
Create `/docs/implementation-plans/euler-beam-3d-implementation-plan.md`.
The implementation plan must be ready for C++ TDD work and must include:
- readiness check for requirements, research, formulation, numerical review, I/O, reference model contract
- explicit kernel-first implementation scope
- tasks matching the remaining phase steps:
- model beam topology
- local stiffness kernel
- global transform and end-force recovery
- build/test report
- release readiness note
- test IDs and RED/GREEN conditions for each production change
- candidate files:
- `src/fesa/model/element.hpp`
- `src/fesa/model/element.cpp`
- `tests/unit/model_element_test.cpp`
- `src/fesa/elements/euler_beam_3d.hpp`
- `src/fesa/elements/euler_beam_3d.cpp`
- `tests/unit/euler_beam_3d_local_stiffness_test.cpp`
- `tests/unit/euler_beam_3d_transform_recovery_test.cpp`
- CTest commands:
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test`
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test`
- `ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test`
- acceptance traceability from requirements to tests
Do not create C++ files in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm every production file named in the plan has a related test.
2. Confirm the plan does not ask Implementation Agent to change requirements, formulation, I/O contracts, reference artifacts, or tolerance policies.
3. Update `phases/euler-beam-3d/index.json` step 5:
- success: `"status": "completed"`, `"summary": "3D Euler beam implementation plan added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not modify source, tests, reference artifacts, or CMake files.
+79
View File
@@ -0,0 +1,79 @@
# Step 6: model-beam-topology
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/implementation-plans/euler-beam-3d-implementation-plan.md`
- `/src/fesa/model/element.hpp`
- `/src/fesa/model/element.cpp`
- `/tests/unit/model_element_test.cpp`
## Task
Use TDD to add a semantic model topology for a two-node 3D beam.
Required production behavior:
- Add `beam2` to `fesa::model::ElementTopology`.
- Preserve existing `truss2`, `bar2`, and `unknown` behavior.
- Do not store equation IDs on `Element`.
- Do not add section constants to `Element` in this step.
## Tests To Write First
Modify `/tests/unit/model_element_test.cpp` first.
Add a failing assertion that constructs an element with:
- id `ElementId{10}`
- topology `ElementTopology::beam2`
- node ids `{NodeId{1}, NodeId{2}}`
- property id `PropertyId{7}`
The test must verify:
- `element.topology() == ElementTopology::beam2`
- `element.node_ids().size() == 2`
- existing `bar2` behavior still works or the test still covers it
RED command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test
```
Expected RED: compile failure because `ElementTopology::beam2` is not defined.
Then implement the minimal enum addition.
GREEN command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test
```
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R model_element_test
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm the test failed before editing production code.
2. Confirm no unrelated model refactor was made.
3. Update `phases/euler-beam-3d/index.json` step 6:
- success: `"status": "completed"`, `"summary": "beam2 model topology added with unit test"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not create parser code.
- Do not add beam stiffness code in this step.
+110
View File
@@ -0,0 +1,110 @@
# Step 7: local-stiffness-kernel
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/formulations/euler-beam-3d-formulation.md`
- `/docs/numerical-reviews/euler-beam-3d-review.md`
- `/docs/implementation-plans/euler-beam-3d-implementation-plan.md`
Also read any files created by previous steps in this phase.
## Task
Use TDD to create the local 12x12 stiffness kernel for the 3D Euler-Bernoulli beam.
Create:
- `/src/fesa/elements/euler_beam_3d.hpp`
- `/src/fesa/elements/euler_beam_3d.cpp`
- `/tests/unit/euler_beam_3d_local_stiffness_test.cpp`
Required API:
```cpp
namespace fesa::elements {
using Vector12 = std::array<double, 12>;
using Matrix12 = std::array<double, 144>;
struct EulerBeam3DSection {
double young_modulus;
double shear_modulus;
double area;
double torsion_constant;
double second_moment_y;
double second_moment_z;
};
Matrix12 euler_beam_3d_local_stiffness(double length, const EulerBeam3DSection& section);
Vector12 euler_beam_3d_local_end_forces(double length,
const EulerBeam3DSection& section,
const Vector12& local_displacements);
} // namespace fesa::elements
```
Implementation rules:
- Matrix storage is row-major: index `(row, col)` is `row * 12 + col`.
- Validate `length > 0` and all section constants are positive; throw `std::invalid_argument` otherwise.
- Use only C++17 standard library.
- Do not introduce an external linear algebra dependency.
- Do not edit CMake files; source and test globs should pick up new files.
## Tests To Write First
Create `/tests/unit/euler_beam_3d_local_stiffness_test.cpp` before production code.
Test behavior:
- For `L = 2.0`, `E = 210.0`, `G = 80.0`, `A = 3.0`, `J = 4.0`, `Iy = 5.0`, `Iz = 6.0`, verify representative matrix entries:
- axial: `K(0,0) = EA/L`, `K(0,6) = -EA/L`, `K(6,6) = EA/L`
- torsion: `K(3,3) = GJ/L`, `K(3,9) = -GJ/L`, `K(9,9) = GJ/L`
- local `x-y` bending uses `EIz`: `K(1,1) = 12*E*Iz/L^3`, `K(1,5) = 6*E*Iz/L^2`, `K(5,5) = 4*E*Iz/L`
- local `x-z` bending uses `EIy`: `K(2,2) = 12*E*Iy/L^3`, `K(2,4) = -6*E*Iy/L^2`, `K(4,4) = 4*E*Iy/L`
- Verify all entries are symmetric within `1.0e-10`.
- Verify `euler_beam_3d_local_end_forces` returns `K * u` for a displacement vector with at least three nonzero components.
- Verify invalid length and nonpositive section constants throw `std::invalid_argument`.
RED command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test
```
Expected RED: test executable missing or compile failure because the header/API does not exist.
Then implement the minimal API.
GREEN command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test
```
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_local_stiffness_test
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm RED failed before production code was added.
2. Confirm no parser, assembly, or results writer code was changed.
3. Update `phases/euler-beam-3d/index.json` step 7:
- success: `"status": "completed"`, `"summary": "local 3D Euler beam stiffness and local end-force kernel added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not add shear deformation or Timoshenko terms.
- Do not modify reference artifacts.
+97
View File
@@ -0,0 +1,97 @@
# Step 8: global-transform-recovery
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/ARCHITECTURE.md`
- `/docs/ADR.md`
- `/docs/formulations/euler-beam-3d-formulation.md`
- `/docs/numerical-reviews/euler-beam-3d-review.md`
- `/docs/implementation-plans/euler-beam-3d-implementation-plan.md`
- `/src/fesa/elements/euler_beam_3d.hpp`
- `/src/fesa/elements/euler_beam_3d.cpp`
- `/tests/unit/euler_beam_3d_local_stiffness_test.cpp`
## Task
Use TDD to add local/global transformation and global end-force recovery to the 3D Euler-Bernoulli beam kernel.
Extend the API in `/src/fesa/elements/euler_beam_3d.hpp`:
```cpp
using Vector3 = std::array<double, 3>;
struct EulerBeam3DGeometry {
Vector3 node1;
Vector3 node2;
Vector3 orientation;
};
Matrix12 euler_beam_3d_global_stiffness(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section);
Vector12 euler_beam_3d_global_end_forces(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section,
const Vector12& global_displacements);
```
Implementation rules:
- local `x` is normalized `node2 - node1`
- local `y` is the normalized projection of `orientation` onto the plane normal to local `x`
- local `z = x cross y`
- use the same 3x3 rotation block for translational and rotational DOFs
- compute `K_global = T^T K_local T`
- compute global end forces by transforming global displacements to local, recovering local forces, then transforming forces back to global
- throw `std::invalid_argument` for zero-length element, zero orientation vector, or orientation parallel to the beam axis
## Tests To Write First
Create `/tests/unit/euler_beam_3d_transform_recovery_test.cpp` before production code.
Test behavior:
- Axis-aligned beam from `(0,0,0)` to `(2,0,0)` with orientation `(0,1,0)` gives global stiffness equal to local stiffness.
- A rotated beam preserves stiffness symmetry.
- A rigid global translation vector produces near-zero global end forces.
- A simple global axial extension on the axis-aligned beam produces equal and opposite axial end forces.
- Parallel orientation vector throws `std::invalid_argument`.
RED command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test
```
Expected RED: test executable missing or compile failure because the transform API does not exist.
Then implement the minimal API.
GREEN command:
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R euler_beam_3d_transform_recovery_test
```
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "euler_beam_3d_(local_stiffness|transform_recovery)_test"
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Confirm RED failed before production code was added.
2. Confirm local stiffness tests still pass.
3. Update `phases/euler-beam-3d/index.json` step 8:
- success: `"status": "completed"`, `"summary": "global transform and global end-force recovery added for 3D Euler beam"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not add assembly or solver integration in this step.
- Do not modify reference artifacts.
+57
View File
@@ -0,0 +1,57 @@
# Step 9: build-test-report
## Read These Files First
Read the following files before editing:
- `/AGENTS.md`
- `/docs/build-test-reports/README.md`
- `/docs/implementation-plans/euler-beam-3d-implementation-plan.md`
- `/src/fesa/elements/euler_beam_3d.hpp`
- `/src/fesa/elements/euler_beam_3d.cpp`
- `/tests/unit/euler_beam_3d_local_stiffness_test.cpp`
- `/tests/unit/euler_beam_3d_transform_recovery_test.cpp`
## Task
Create `/docs/build-test-reports/euler-beam-3d-build-test.md`.
The report must record:
- feature id
- changed files observed for this phase
- command log summary with exit codes and short evidence tails
- validation results for:
- harness self-test
- CMake configure/build
- CTest
- feature-specific tests
- failure classification if anything failed
- explicit statement that this report does not approve reference verification or release readiness
Do not change source or tests in this step.
## Tests To Write First
- No C++ test is required in this documentation-only step.
## Acceptance Criteria
```powershell
ctest --test-dir build/msvc-debug --output-on-failure -C Debug -R "model_element_test|euler_beam_3d_(local_stiffness|transform_recovery)_test"
python -m unittest discover -s scripts -p "test_*.py"
python scripts/validate_workspace.py
```
## Verification Notes
1. Record actual command exit codes and concise output evidence.
2. If validation fails for an environment reason, mark the report `needs-environment-fix` and update this phase step as blocked.
3. Update `phases/euler-beam-3d/index.json` step 9:
- success: `"status": "completed"`, `"summary": "3D Euler beam build/test report added"`
- failure after retries: `"status": "error"`, `"error_message": "<specific error>"`
- blocked: `"status": "blocked"`, `"blocked_reason": "<specific reason>"`
## Forbidden
- Do not modify source, tests, requirements, formulations, I/O contracts, or reference artifacts.
+1 -1
View File
@@ -5,7 +5,7 @@
"status": "completed"
},
{
"dir": "abaqus-input-parser",
"dir": "euler-beam-3d",
"status": "pending"
}
]
+31 -2
View File
@@ -12,6 +12,7 @@ import fnmatch
import json
import os
import re
import shutil
import subprocess
import sys
import threading
@@ -24,6 +25,12 @@ from typing import Optional
ROOT = Path(__file__).resolve().parent.parent
def configure_output_encoding():
for stream in (sys.stdout, sys.stderr):
if hasattr(stream, "reconfigure"):
stream.reconfigure(encoding="utf-8", errors="replace")
@contextlib.contextmanager
def progress_indicator(label: str):
"""터미널 진행 표시기. with 문으로 사용하며 .elapsed 로 경과 시간을 읽는다."""
@@ -373,8 +380,9 @@ class StepExecutor:
prompt = preamble + step_file.read_text(encoding="utf-8")
result = subprocess.run(
["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "--json", prompt],
cwd=self._root, capture_output=True, text=True, timeout=1800,
self._codex_exec_command(),
cwd=self._root, capture_output=True, text=True, input=prompt,
encoding="utf-8", errors="replace", timeout=1800,
)
if result.returncode != 0:
@@ -395,6 +403,26 @@ class StepExecutor:
# --- 헤더 & 검증 ---
@staticmethod
def _codex_command() -> str:
override = os.environ.get("HARNESS_CODEX_COMMAND", "").strip()
if override:
return override
return (
shutil.which("codex.cmd")
or shutil.which("codex.exe")
or shutil.which("codex")
or "codex"
)
def _codex_exec_command(self) -> list[str]:
cmd = [self._codex_command(), "exec"]
model = os.environ.get("HARNESS_CODEX_MODEL", "").strip()
if model:
cmd.extend(["-m", model])
cmd.extend(["--dangerously-bypass-approvals-and-sandbox", "--json", "-"])
return cmd
def _print_header(self):
print(f"\n{'='*60}")
print(f" Harness Step Executor")
@@ -550,6 +578,7 @@ class StepExecutor:
def main():
configure_output_encoding()
parser = argparse.ArgumentParser(description="Harness Step Executor")
parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-mvp)")
parser.add_argument("--push", action="store_true", help="Push branch after completion")
+89
View File
@@ -1,5 +1,6 @@
import importlib.util
import json
import os
import subprocess
import sys
import tempfile
@@ -281,6 +282,94 @@ class ExecuteRunnerSafetyTests(unittest.TestCase):
self.assertEqual(cm.exception.code, 1)
def test_invoke_codex_passes_prompt_through_stdin(self):
execute = load_execute()
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
write_phase(root)
executor = make_executor(execute, root)
step = {"step": 1, "name": "Docs"}
long_preamble = "x" * 40000
def fake_run(cmd, **kwargs):
return subprocess.CompletedProcess(cmd, 0, '{"event":"done"}\n', "")
with patch.object(execute.subprocess, "run", side_effect=fake_run) as run_mock:
with patch.object(executor, "_codex_command", return_value="codex.cmd"):
with patch.dict(os.environ, {"HARNESS_CODEX_MODEL": ""}):
executor._invoke_codex(step, long_preamble)
cmd = run_mock.call_args.args[0]
kwargs = run_mock.call_args.kwargs
self.assertEqual(
cmd,
["codex.cmd", "exec", "--dangerously-bypass-approvals-and-sandbox", "--json", "-"],
)
self.assertEqual(kwargs["input"], long_preamble + "# Step 1\n")
self.assertEqual(kwargs["cwd"], str(root))
self.assertEqual(kwargs["encoding"], "utf-8")
self.assertEqual(kwargs["errors"], "replace")
def test_codex_command_prefers_windows_cmd_or_exe_shim(self):
execute = load_execute()
def fake_which(name):
return {
"codex.cmd": "C:/tools/codex.cmd",
"codex.exe": "C:/tools/codex.exe",
"codex": "C:/tools/codex",
}.get(name)
with patch.object(execute.shutil, "which", side_effect=fake_which):
self.assertEqual(execute.StepExecutor._codex_command(), "C:/tools/codex.cmd")
def test_codex_command_uses_env_override_first(self):
execute = load_execute()
with patch.dict(os.environ, {"HARNESS_CODEX_COMMAND": "C:/app/codex.exe"}):
self.assertEqual(execute.StepExecutor._codex_command(), "C:/app/codex.exe")
def test_codex_exec_command_uses_model_env_override(self):
execute = load_execute()
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
write_phase(root)
executor = make_executor(execute, root)
with patch.object(executor, "_codex_command", return_value="codex.cmd"):
with patch.dict(os.environ, {"HARNESS_CODEX_MODEL": "gpt-5"}):
self.assertEqual(
executor._codex_exec_command(),
[
"codex.cmd",
"exec",
"-m",
"gpt-5",
"--dangerously-bypass-approvals-and-sandbox",
"--json",
"-",
],
)
def test_configure_output_encoding_sets_utf8_replace(self):
execute = load_execute()
class Stream:
def __init__(self):
self.calls = []
def reconfigure(self, **kwargs):
self.calls.append(kwargs)
stdout = Stream()
stderr = Stream()
with patch.object(execute.sys, "stdout", stdout):
with patch.object(execute.sys, "stderr", stderr):
execute.configure_output_encoding()
self.assertEqual(stdout.calls, [{"encoding": "utf-8", "errors": "replace"}])
self.assertEqual(stderr.calls, [{"encoding": "utf-8", "errors": "replace"}])
if __name__ == "__main__":
unittest.main()
+16 -42
View File
@@ -30,15 +30,14 @@ class ValidateWorkspaceTests(unittest.TestCase):
(root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8")
build_dir = root / "build" / "msvc-debug"
with patch.dict(os.environ, {}, clear=True):
with patch.object(validate_workspace.shutil, "which", return_value="C:\\tools\\cmake.exe"):
self.assertEqual(
validate_workspace.discover_commands(root),
[
f'cmake -S "{root}" -B "{build_dir}" -G "Visual Studio 17 2022" -A x64',
f'cmake --build "{build_dir}" --config Debug',
f'ctest --test-dir "{build_dir}" --output-on-failure -C Debug',
],
)
self.assertEqual(
validate_workspace.discover_commands(root),
[
f'cmake -S "{root}" -B "{build_dir}" -G "Visual Studio 17 2022" -A x64',
f'cmake --build "{build_dir}" --config Debug',
f'ctest --test-dir "{build_dir}" --output-on-failure -C Debug',
],
)
def test_msvc_debug_configure_preset_is_preferred_when_present(self):
validate_workspace = load_validate_workspace()
@@ -61,39 +60,14 @@ class ValidateWorkspaceTests(unittest.TestCase):
encoding="utf-8",
)
with patch.dict(os.environ, {}, clear=True):
with patch.object(validate_workspace.shutil, "which", return_value="C:\\tools\\cmake.exe"):
self.assertEqual(
validate_workspace.discover_commands(root),
[
"cmake --preset msvc-debug",
f'cmake --build "{root / "out" / "msvc-debug"}" --config Debug',
f'ctest --test-dir "{root / "out" / "msvc-debug"}" --output-on-failure -C Debug',
],
)
def test_cmake_commands_use_common_install_path_when_tools_are_not_on_path(self):
validate_workspace = load_validate_workspace()
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp) / "project"
root.mkdir()
(root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8")
common_bin = Path(tmp) / "CMake" / "bin"
common_bin.mkdir(parents=True)
(common_bin / "cmake.exe").write_text("", encoding="utf-8")
(common_bin / "ctest.exe").write_text("", encoding="utf-8")
build_dir = root / "build" / "msvc-debug"
with patch.dict(os.environ, {}, clear=True):
with patch.object(validate_workspace, "COMMON_CMAKE_BIN", common_bin):
with patch.object(validate_workspace.shutil, "which", return_value=None):
self.assertEqual(
validate_workspace.discover_commands(root),
[
f'"{common_bin / "cmake.exe"}" -S "{root}" -B "{build_dir}" -G "Visual Studio 17 2022" -A x64',
f'"{common_bin / "cmake.exe"}" --build "{build_dir}" --config Debug',
f'"{common_bin / "ctest.exe"}" --test-dir "{build_dir}" --output-on-failure -C Debug',
],
)
self.assertEqual(
validate_workspace.discover_commands(root),
[
"cmake --preset msvc-debug",
f'cmake --build "{root / "out" / "msvc-debug"}" --config Debug',
f'ctest --test-dir "{root / "out" / "msvc-debug"}" --output-on-failure -C Debug',
],
)
def test_no_cmake_project_has_no_validation_commands(self):
validate_workspace = load_validate_workspace()
+6 -21
View File
@@ -32,17 +32,6 @@ def _cmake_config() -> tuple[str, str, str, Path]:
return generator, platform, config, build_dir
def _tool_command(tool_name: str) -> str:
if shutil.which(tool_name) is not None:
return tool_name
exe = COMMON_CMAKE_BIN / f"{tool_name}.exe"
if exe.exists():
return f'"{exe}"'
return tool_name
def _read_presets(root: Path) -> dict:
presets_file = root / "CMakePresets.json"
if not presets_file.exists():
@@ -64,15 +53,13 @@ def _preset_binary_dir(root: Path, preset: dict) -> Path:
def load_preset_commands(root: Path) -> list[str]:
payload = _read_presets(root)
config = os.environ.get("HARNESS_CMAKE_CONFIG", DEFAULT_CONFIG)
cmake = _tool_command("cmake")
ctest = _tool_command("ctest")
for preset in payload.get("configurePresets", []):
if isinstance(preset, dict) and preset.get("name") == PRESET_NAME:
build_dir = _preset_binary_dir(root, preset)
return [
f"{cmake} --preset {PRESET_NAME}",
f'{cmake} --build "{build_dir}" --config {config}',
f'{ctest} --test-dir "{build_dir}" --output-on-failure -C {config}',
f"cmake --preset {PRESET_NAME}",
f'cmake --build "{build_dir}" --config {config}',
f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}',
]
return []
@@ -84,12 +71,10 @@ def load_cmake_commands(root: Path) -> list[str]:
generator, platform, config, build_dir = _cmake_config()
if not build_dir.is_absolute():
build_dir = root / build_dir
cmake = _tool_command("cmake")
ctest = _tool_command("ctest")
return [
f'{cmake} -S "{root}" -B "{build_dir}" -G "{generator}" -A {platform}',
f'{cmake} --build "{build_dir}" --config {config}',
f'{ctest} --test-dir "{build_dir}" --output-on-failure -C {config}',
f'cmake -S "{root}" -B "{build_dir}" -G "{generator}" -A {platform}',
f'cmake --build "{build_dir}" --config {config}',
f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}',
]
+261
View File
@@ -0,0 +1,261 @@
#include <fesa/elements/euler_beam_3d.hpp>
#include <cmath>
#include <cstddef>
#include <stdexcept>
namespace fesa::elements {
namespace {
constexpr int matrix_size = 12;
constexpr double geometry_tolerance = 1.0e-12;
std::size_t index(int row, int column)
{
return static_cast<std::size_t>(row * matrix_size + column);
}
void require_positive_finite(double value, const char* name)
{
if (!std::isfinite(value) || value <= 0.0) {
throw std::invalid_argument(name);
}
}
void validate_section(double length, const EulerBeam3DSection& section)
{
require_positive_finite(length, "Euler beam length must be positive and finite");
require_positive_finite(section.young_modulus, "Euler beam Young modulus must be positive and finite");
require_positive_finite(section.shear_modulus, "Euler beam shear modulus must be positive and finite");
require_positive_finite(section.area, "Euler beam area must be positive and finite");
require_positive_finite(section.torsion_constant, "Euler beam torsion constant must be positive and finite");
require_positive_finite(section.second_moment_y, "Euler beam Iy must be positive and finite");
require_positive_finite(section.second_moment_z, "Euler beam Iz must be positive and finite");
}
void set_symmetric(Matrix12& matrix, int row, int column, double value)
{
matrix[index(row, column)] = value;
matrix[index(column, row)] = value;
}
Vector3 subtract(const Vector3& lhs, const Vector3& rhs)
{
return {
lhs[0] - rhs[0],
lhs[1] - rhs[1],
lhs[2] - rhs[2]
};
}
double dot(const Vector3& lhs, const Vector3& rhs)
{
return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
}
double norm(const Vector3& vector)
{
return std::sqrt(dot(vector, vector));
}
Vector3 scale(const Vector3& vector, double scalar)
{
return {
vector[0] * scalar,
vector[1] * scalar,
vector[2] * scalar
};
}
Vector3 normalize(const Vector3& vector, const char* message)
{
const double vector_norm = norm(vector);
if (!std::isfinite(vector_norm) || vector_norm <= geometry_tolerance) {
throw std::invalid_argument(message);
}
return scale(vector, 1.0 / vector_norm);
}
Vector3 cross(const Vector3& lhs, const Vector3& rhs)
{
return {
lhs[1] * rhs[2] - lhs[2] * rhs[1],
lhs[2] * rhs[0] - lhs[0] * rhs[2],
lhs[0] * rhs[1] - lhs[1] * rhs[0]
};
}
double geometry_length(const EulerBeam3DGeometry& geometry)
{
return norm(subtract(geometry.node2, geometry.node1));
}
std::array<Vector3, 3> local_basis(const EulerBeam3DGeometry& geometry)
{
const auto axis = subtract(geometry.node2, geometry.node1);
const auto local_x = normalize(axis, "Euler beam geometry length must be positive and finite");
const double orientation_along_x = dot(geometry.orientation, local_x);
const auto projected_orientation = subtract(
geometry.orientation,
scale(local_x, orientation_along_x));
const auto local_y = normalize(
projected_orientation,
"Euler beam orientation must be nonzero and not parallel to the element axis");
const auto local_z = cross(local_x, local_y);
return {local_x, local_y, local_z};
}
Matrix12 transform_matrix(const EulerBeam3DGeometry& geometry)
{
const auto basis = local_basis(geometry);
Matrix12 transform{};
for (int block_offset : {0, 3, 6, 9}) {
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
transform[index(block_offset + row, block_offset + column)] =
basis[static_cast<std::size_t>(row)][static_cast<std::size_t>(column)];
}
}
}
return transform;
}
Vector12 multiply(const Matrix12& matrix, const Vector12& vector)
{
Vector12 result{};
for (int row = 0; row < matrix_size; ++row) {
for (int column = 0; column < matrix_size; ++column) {
result[static_cast<std::size_t>(row)] +=
matrix[index(row, column)] * vector[static_cast<std::size_t>(column)];
}
}
return result;
}
Vector12 multiply_transpose(const Matrix12& matrix, const Vector12& vector)
{
Vector12 result{};
for (int row = 0; row < matrix_size; ++row) {
for (int column = 0; column < matrix_size; ++column) {
result[static_cast<std::size_t>(row)] +=
matrix[index(column, row)] * vector[static_cast<std::size_t>(column)];
}
}
return result;
}
Matrix12 multiply(const Matrix12& lhs, const Matrix12& rhs)
{
Matrix12 result{};
for (int row = 0; row < matrix_size; ++row) {
for (int column = 0; column < matrix_size; ++column) {
for (int inner = 0; inner < matrix_size; ++inner) {
result[index(row, column)] += lhs[index(row, inner)] * rhs[index(inner, column)];
}
}
}
return result;
}
Matrix12 multiply_transpose_left(const Matrix12& lhs, const Matrix12& rhs)
{
Matrix12 result{};
for (int row = 0; row < matrix_size; ++row) {
for (int column = 0; column < matrix_size; ++column) {
for (int inner = 0; inner < matrix_size; ++inner) {
result[index(row, column)] += lhs[index(inner, row)] * rhs[index(inner, column)];
}
}
}
return result;
}
} // namespace
Matrix12 euler_beam_3d_local_stiffness(double length, const EulerBeam3DSection& section)
{
validate_section(length, section);
const double length2 = length * length;
const double length3 = length2 * length;
const double axial = section.young_modulus * section.area / length;
const double torsion = section.shear_modulus * section.torsion_constant / length;
const double eiy = section.young_modulus * section.second_moment_y;
const double cy1 = 12.0 * eiy / length3;
const double cy2 = 6.0 * eiy / length2;
const double cy3 = 4.0 * eiy / length;
const double cy4 = 2.0 * eiy / length;
const double eiz = section.young_modulus * section.second_moment_z;
const double cz1 = 12.0 * eiz / length3;
const double cz2 = 6.0 * eiz / length2;
const double cz3 = 4.0 * eiz / length;
const double cz4 = 2.0 * eiz / length;
Matrix12 stiffness{};
set_symmetric(stiffness, 0, 0, axial);
set_symmetric(stiffness, 0, 6, -axial);
set_symmetric(stiffness, 6, 6, axial);
set_symmetric(stiffness, 3, 3, torsion);
set_symmetric(stiffness, 3, 9, -torsion);
set_symmetric(stiffness, 9, 9, torsion);
set_symmetric(stiffness, 1, 1, cz1);
set_symmetric(stiffness, 1, 5, cz2);
set_symmetric(stiffness, 1, 7, -cz1);
set_symmetric(stiffness, 1, 11, cz2);
set_symmetric(stiffness, 5, 5, cz3);
set_symmetric(stiffness, 5, 7, -cz2);
set_symmetric(stiffness, 5, 11, cz4);
set_symmetric(stiffness, 7, 7, cz1);
set_symmetric(stiffness, 7, 11, -cz2);
set_symmetric(stiffness, 11, 11, cz3);
set_symmetric(stiffness, 2, 2, cy1);
set_symmetric(stiffness, 2, 4, -cy2);
set_symmetric(stiffness, 2, 8, -cy1);
set_symmetric(stiffness, 2, 10, -cy2);
set_symmetric(stiffness, 4, 4, cy3);
set_symmetric(stiffness, 4, 8, cy2);
set_symmetric(stiffness, 4, 10, cy4);
set_symmetric(stiffness, 8, 8, cy1);
set_symmetric(stiffness, 8, 10, cy2);
set_symmetric(stiffness, 10, 10, cy3);
return stiffness;
}
Vector12 euler_beam_3d_local_end_forces(double length,
const EulerBeam3DSection& section,
const Vector12& local_displacements)
{
const auto stiffness = euler_beam_3d_local_stiffness(length, section);
return multiply(stiffness, local_displacements);
}
Matrix12 euler_beam_3d_global_stiffness(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section)
{
const double length = geometry_length(geometry);
const auto local_stiffness = euler_beam_3d_local_stiffness(length, section);
const auto transform = transform_matrix(geometry);
return multiply_transpose_left(transform, multiply(local_stiffness, transform));
}
Vector12 euler_beam_3d_global_end_forces(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section,
const Vector12& global_displacements)
{
const double length = geometry_length(geometry);
const auto transform = transform_matrix(geometry);
const auto local_displacements = multiply(transform, global_displacements);
const auto local_forces = euler_beam_3d_local_end_forces(length, section, local_displacements);
return multiply_transpose(transform, local_forces);
}
} // namespace fesa::elements
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <array>
namespace fesa::elements {
using Vector12 = std::array<double, 12>;
using Matrix12 = std::array<double, 144>;
using Vector3 = std::array<double, 3>;
struct EulerBeam3DSection {
double young_modulus;
double shear_modulus;
double area;
double torsion_constant;
double second_moment_y;
double second_moment_z;
};
struct EulerBeam3DGeometry {
Vector3 node1;
Vector3 node2;
Vector3 orientation;
};
Matrix12 euler_beam_3d_local_stiffness(double length, const EulerBeam3DSection& section);
Vector12 euler_beam_3d_local_end_forces(double length,
const EulerBeam3DSection& section,
const Vector12& local_displacements);
Matrix12 euler_beam_3d_global_stiffness(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section);
Vector12 euler_beam_3d_global_end_forces(const EulerBeam3DGeometry& geometry,
const EulerBeam3DSection& section,
const Vector12& global_displacements);
} // namespace fesa::elements
-214
View File
@@ -1,214 +0,0 @@
#include <fesa/io/abaqus/input_parser.hpp>
#include <algorithm>
#include <array>
#include <cctype>
#include <stdexcept>
#include <string>
#include <vector>
namespace fesa::io::abaqus {
namespace {
enum class Section {
none,
heading,
node,
element
};
struct ElementSection {
model::ElementTopology topology = model::ElementTopology::unknown;
};
std::string trim(std::string_view text)
{
auto first = text.begin();
auto last = text.end();
while (first != last && std::isspace(static_cast<unsigned char>(*first)) != 0) {
++first;
}
while (first != last && std::isspace(static_cast<unsigned char>(*(last - 1))) != 0) {
--last;
}
return std::string(first, last);
}
std::string lower(std::string text)
{
std::transform(text.begin(), text.end(), text.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
return text;
}
std::vector<std::string> split_commas(std::string_view line)
{
std::vector<std::string> fields;
std::size_t start = 0;
while (start <= line.size()) {
const auto comma = line.find(',', start);
const auto end = comma == std::string_view::npos ? line.size() : comma;
fields.push_back(trim(line.substr(start, end - start)));
if (comma == std::string_view::npos) {
break;
}
start = comma + 1;
}
return fields;
}
bool parse_int(const std::string& text, int& value)
{
try {
std::size_t parsed = 0;
value = std::stoi(text, &parsed);
return parsed == text.size();
} catch (const std::invalid_argument&) {
return false;
} catch (const std::out_of_range&) {
return false;
}
}
bool parse_double(const std::string& text, double& value)
{
try {
std::size_t parsed = 0;
value = std::stod(text, &parsed);
return parsed == text.size();
} catch (const std::invalid_argument&) {
return false;
} catch (const std::out_of_range&) {
return false;
}
}
model::ElementTopology topology_for_type(const std::string& raw_type)
{
const auto type = lower(raw_type);
if (type == "t2d2" || type == "t3d2" || type == "c3d2") {
return model::ElementTopology::truss2;
}
if (type == "b31") {
return model::ElementTopology::bar2;
}
return model::ElementTopology::unknown;
}
std::string parameter_value(const std::vector<std::string>& fields, const std::string& key)
{
const auto expected_key = lower(key);
for (std::size_t i = 1; i < fields.size(); ++i) {
const auto equals = fields[i].find('=');
if (equals == std::string::npos) {
continue;
}
const auto field_key = lower(trim(std::string_view{fields[i]}.substr(0, equals)));
if (field_key == expected_key) {
return trim(std::string_view{fields[i]}.substr(equals + 1));
}
}
return {};
}
void parse_node_line(model::Domain& domain, const std::vector<std::string>& fields)
{
if (fields.size() != 4) {
return;
}
int id = 0;
std::array<double, 3> coordinates{};
if (!parse_int(fields[0], id) ||
!parse_double(fields[1], coordinates[0]) ||
!parse_double(fields[2], coordinates[1]) ||
!parse_double(fields[3], coordinates[2])) {
return;
}
domain.add_node(model::Node{core::NodeId{id}, coordinates});
}
void parse_element_line(model::Domain& domain,
const ElementSection& element_section,
const std::vector<std::string>& fields)
{
if (element_section.topology == model::ElementTopology::unknown) {
return;
}
if (fields.size() != 3) {
return;
}
int id = 0;
int first_node = 0;
int second_node = 0;
if (!parse_int(fields[0], id) || !parse_int(fields[1], first_node) || !parse_int(fields[2], second_node)) {
return;
}
domain.add_element(model::Element{
core::ElementId{id},
element_section.topology,
{core::NodeId{first_node}, core::NodeId{second_node}},
core::PropertyId{0}
});
}
} // namespace
ParseResult InputParser::parse(std::string_view input) const
{
ParseResult result{model::Domain{}, core::Status::ok()};
Section section = Section::none;
ElementSection element_section{};
std::size_t start = 0;
while (start <= input.size()) {
const auto newline = input.find('\n', start);
const auto end = newline == std::string_view::npos ? input.size() : newline;
auto line = input.substr(start, end - start);
if (!line.empty() && line.back() == '\r') {
line.remove_suffix(1);
}
const auto cleaned = trim(line);
if (cleaned.empty() || cleaned.rfind("**", 0) == 0) {
if (newline == std::string_view::npos) {
break;
}
start = newline + 1;
continue;
}
if (cleaned.front() == '*') {
const auto keyword_fields = split_commas(std::string_view{cleaned}.substr(1));
const auto keyword = keyword_fields.empty() ? std::string{} : lower(keyword_fields[0]);
if (keyword == "heading") {
section = Section::heading;
} else if (keyword == "node") {
section = Section::node;
} else if (keyword == "element") {
section = Section::element;
const auto type = parameter_value(keyword_fields, "type");
element_section.topology = topology_for_type(type);
} else {
section = Section::none;
}
} else if (section == Section::node) {
parse_node_line(result.domain, split_commas(cleaned));
} else if (section == Section::element) {
parse_element_line(result.domain, element_section, split_commas(cleaned));
}
if (newline == std::string_view::npos) {
break;
}
start = newline + 1;
}
return result;
}
} // namespace fesa::io::abaqus
-20
View File
@@ -1,20 +0,0 @@
#pragma once
#include <fesa/core/status.hpp>
#include <fesa/model/domain.hpp>
#include <string_view>
namespace fesa::io::abaqus {
struct ParseResult {
model::Domain domain;
core::Status status;
};
class InputParser {
public:
ParseResult parse(std::string_view input) const;
};
} // namespace fesa::io::abaqus
+1
View File
@@ -9,6 +9,7 @@ namespace fesa::model {
enum class ElementTopology {
truss2,
bar2,
beam2,
unknown
};
@@ -1,80 +0,0 @@
#include <fesa/io/abaqus/input_parser.hpp>
#include <string>
namespace {
int fail()
{
return 1;
}
} // namespace
int main()
{
fesa::io::abaqus::InputParser parser;
const std::string input = R"inp(
** mesh parser smoke case
*HeAdInG
small truss model
*NoDe
1, 0.0, 0.0, 0.0
2, 1.5, 0.0, 0.0
*ElEmEnT, TyPe=t3d2
10, 1, 2
)inp";
const auto result = parser.parse(input);
if (!result.status.is_ok()) {
return fail();
}
const auto& domain = result.domain;
if (domain.nodes().size() != 2 || domain.elements().size() != 1) {
return fail();
}
const auto* first_node = domain.find_node(fesa::core::NodeId{1});
if (first_node == nullptr || first_node->coordinates()[0] != 0.0 ||
first_node->coordinates()[1] != 0.0 || first_node->coordinates()[2] != 0.0) {
return fail();
}
const auto* second_node = domain.find_node(fesa::core::NodeId{2});
if (second_node == nullptr || second_node->coordinates()[0] != 1.5 ||
second_node->coordinates()[1] != 0.0 || second_node->coordinates()[2] != 0.0) {
return fail();
}
const auto* element = domain.find_element(fesa::core::ElementId{10});
if (element == nullptr ||
element->topology() != fesa::model::ElementTopology::truss2 ||
element->node_ids().size() != 2 ||
element->node_ids()[0].value != 1 ||
element->node_ids()[1].value != 2 ||
element->property_id().value != 0) {
return fail();
}
const std::string beam_input = R"inp(
*NODE
1, 0.0, 0.0, 0.0
2, 0.0, 2.0, 0.0
*ELEMENT, TYPE=B31
20, 1, 2
)inp";
const auto beam_result = parser.parse(beam_input);
const auto* beam = beam_result.domain.find_element(fesa::core::ElementId{20});
if (!beam_result.status.is_ok() ||
beam == nullptr ||
beam->topology() != fesa::model::ElementTopology::bar2 ||
beam->node_ids().size() != 2 ||
beam->property_id().value != 0) {
return fail();
}
return 0;
}
@@ -0,0 +1,125 @@
#include <fesa/elements/euler_beam_3d.hpp>
#include <cmath>
#include <cstddef>
#include <stdexcept>
namespace {
constexpr double tolerance = 1.0e-10;
bool close(double actual, double expected, double tol = tolerance)
{
return std::abs(actual - expected) <= tol;
}
double entry(const fesa::elements::Matrix12& matrix, int row, int column)
{
return matrix[static_cast<std::size_t>(row * 12 + column)];
}
fesa::elements::Vector12 multiply(const fesa::elements::Matrix12& matrix,
const fesa::elements::Vector12& vector)
{
fesa::elements::Vector12 result{};
for (int row = 0; row < 12; ++row) {
for (int column = 0; column < 12; ++column) {
result[static_cast<std::size_t>(row)] +=
entry(matrix, row, column) * vector[static_cast<std::size_t>(column)];
}
}
return result;
}
bool throws_invalid_length(const fesa::elements::EulerBeam3DSection& section)
{
try {
(void)fesa::elements::euler_beam_3d_local_stiffness(0.0, section);
} catch (const std::invalid_argument&) {
return true;
}
return false;
}
bool throws_invalid_section(fesa::elements::EulerBeam3DSection section)
{
section.second_moment_z = 0.0;
try {
(void)fesa::elements::euler_beam_3d_local_stiffness(2.0, section);
} catch (const std::invalid_argument&) {
return true;
}
return false;
}
} // namespace
int main()
{
const double length = 2.0;
const fesa::elements::EulerBeam3DSection section{
210.0,
80.0,
3.0,
4.0,
5.0,
6.0
};
const auto stiffness = fesa::elements::euler_beam_3d_local_stiffness(length, section);
if (!close(entry(stiffness, 0, 0), 315.0) ||
!close(entry(stiffness, 0, 6), -315.0) ||
!close(entry(stiffness, 6, 6), 315.0)) {
return 1;
}
if (!close(entry(stiffness, 3, 3), 160.0) ||
!close(entry(stiffness, 3, 9), -160.0) ||
!close(entry(stiffness, 9, 9), 160.0)) {
return 2;
}
if (!close(entry(stiffness, 1, 1), 1890.0) ||
!close(entry(stiffness, 1, 5), 1890.0) ||
!close(entry(stiffness, 5, 5), 2520.0)) {
return 3;
}
if (!close(entry(stiffness, 2, 2), 1575.0) ||
!close(entry(stiffness, 2, 4), -1575.0) ||
!close(entry(stiffness, 4, 4), 2100.0)) {
return 4;
}
for (int row = 0; row < 12; ++row) {
for (int column = 0; column < 12; ++column) {
if (!close(entry(stiffness, row, column), entry(stiffness, column, row))) {
return 5;
}
}
}
fesa::elements::Vector12 displacement{};
displacement[0] = 0.1;
displacement[5] = 0.2;
displacement[8] = -0.05;
const auto expected_forces = multiply(stiffness, displacement);
const auto recovered_forces =
fesa::elements::euler_beam_3d_local_end_forces(length, section, displacement);
for (std::size_t index = 0; index < expected_forces.size(); ++index) {
if (!close(recovered_forces[index], expected_forces[index])) {
return 6;
}
}
if (!throws_invalid_length(section)) {
return 7;
}
if (!throws_invalid_section(section)) {
return 8;
}
return 0;
}
@@ -0,0 +1,151 @@
#include <fesa/elements/euler_beam_3d.hpp>
#include <cmath>
#include <cstddef>
#include <stdexcept>
namespace {
constexpr double tolerance = 1.0e-9;
bool close(double actual, double expected, double tol = tolerance)
{
return std::abs(actual - expected) <= tol;
}
double entry(const fesa::elements::Matrix12& matrix, int row, int column)
{
return matrix[static_cast<std::size_t>(row * 12 + column)];
}
fesa::elements::EulerBeam3DSection section()
{
return fesa::elements::EulerBeam3DSection{
210.0,
80.0,
3.0,
4.0,
5.0,
6.0
};
}
bool matrices_close(const fesa::elements::Matrix12& lhs, const fesa::elements::Matrix12& rhs)
{
for (std::size_t index = 0; index < lhs.size(); ++index) {
if (!close(lhs[index], rhs[index])) {
return false;
}
}
return true;
}
bool symmetric(const fesa::elements::Matrix12& matrix)
{
for (int row = 0; row < 12; ++row) {
for (int column = 0; column < 12; ++column) {
if (!close(entry(matrix, row, column), entry(matrix, column, row))) {
return false;
}
}
}
return true;
}
bool throws_parallel_orientation()
{
const fesa::elements::EulerBeam3DGeometry geometry{
{0.0, 0.0, 0.0},
{2.0, 0.0, 0.0},
{1.0, 0.0, 0.0}
};
try {
(void)fesa::elements::euler_beam_3d_global_stiffness(geometry, section());
} catch (const std::invalid_argument&) {
return true;
}
return false;
}
bool throws_zero_orientation()
{
const fesa::elements::EulerBeam3DGeometry geometry{
{0.0, 0.0, 0.0},
{2.0, 0.0, 0.0},
{0.0, 0.0, 0.0}
};
try {
(void)fesa::elements::euler_beam_3d_global_stiffness(geometry, section());
} catch (const std::invalid_argument&) {
return true;
}
return false;
}
} // namespace
int main()
{
const auto beam_section = section();
const fesa::elements::EulerBeam3DGeometry axis_aligned{
{0.0, 0.0, 0.0},
{2.0, 0.0, 0.0},
{0.0, 1.0, 0.0}
};
const auto local = fesa::elements::euler_beam_3d_local_stiffness(2.0, beam_section);
const auto global_identity =
fesa::elements::euler_beam_3d_global_stiffness(axis_aligned, beam_section);
if (!matrices_close(global_identity, local)) {
return 1;
}
const fesa::elements::EulerBeam3DGeometry rotated{
{0.0, 0.0, 0.0},
{0.0, 2.0, 0.0},
{1.0, 0.0, 0.0}
};
const auto rotated_stiffness =
fesa::elements::euler_beam_3d_global_stiffness(rotated, beam_section);
if (!symmetric(rotated_stiffness)) {
return 2;
}
fesa::elements::Vector12 rigid_translation{};
rigid_translation[0] = 0.2;
rigid_translation[1] = -0.1;
rigid_translation[2] = 0.3;
rigid_translation[6] = 0.2;
rigid_translation[7] = -0.1;
rigid_translation[8] = 0.3;
const auto rigid_forces =
fesa::elements::euler_beam_3d_global_end_forces(rotated, beam_section, rigid_translation);
for (double force : rigid_forces) {
if (!close(force, 0.0)) {
return 3;
}
}
fesa::elements::Vector12 axial_extension{};
axial_extension[6] = 0.1;
const auto axial_forces = fesa::elements::euler_beam_3d_global_end_forces(
axis_aligned,
beam_section,
axial_extension);
if (!close(axial_forces[0], -31.5) ||
!close(axial_forces[6], 31.5) ||
!close(axial_forces[0] + axial_forces[6], 0.0)) {
return 4;
}
if (!throws_parallel_orientation()) {
return 5;
}
if (!throws_zero_orientation()) {
return 6;
}
return 0;
}
+15 -1
View File
@@ -8,5 +8,19 @@ int main()
{fesa::core::NodeId{1}, fesa::core::NodeId{2}},
fesa::core::PropertyId{3}
};
return element.node_ids().size() == 2 ? 0 : 1;
const fesa::model::Element beam{
fesa::core::ElementId{10},
fesa::model::ElementTopology::beam2,
{fesa::core::NodeId{1}, fesa::core::NodeId{2}},
fesa::core::PropertyId{7}
};
if (element.topology() != fesa::model::ElementTopology::bar2) {
return 1;
}
if (beam.topology() != fesa::model::ElementTopology::beam2) {
return 1;
}
return beam.node_ids().size() == 2 ? 0 : 1;
}