Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf80780863 | |||
| 7845ebec68 | |||
| 95ca95180a | |||
| 5b01642cbc | |||
| c88de37a83 | |||
| 4c47b2766a | |||
| 7179cfc243 | |||
| 6cc5ee6e25 | |||
| 656cc5afc4 | |||
| 3ce43c8670 |
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -5,15 +5,19 @@
|
||||
{
|
||||
"step": 0,
|
||||
"name": "requirements-baseline",
|
||||
"status": "pending",
|
||||
"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": "pending",
|
||||
"status": "completed",
|
||||
"summary": "3D Euler beam research evidence added",
|
||||
"allowed_paths": [
|
||||
"docs/research/euler-beam-3d-research.md"
|
||||
]
|
||||
@@ -21,7 +25,8 @@
|
||||
{
|
||||
"step": 2,
|
||||
"name": "formulation-spec",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"summary": "3D Euler beam formulation contract added",
|
||||
"allowed_paths": [
|
||||
"docs/formulations/euler-beam-3d-formulation.md"
|
||||
]
|
||||
@@ -29,7 +34,8 @@
|
||||
{
|
||||
"step": 3,
|
||||
"name": "numerical-review",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"summary": "3D Euler beam numerical review added",
|
||||
"allowed_paths": [
|
||||
"docs/numerical-reviews/euler-beam-3d-review.md"
|
||||
]
|
||||
@@ -37,7 +43,8 @@
|
||||
{
|
||||
"step": 4,
|
||||
"name": "io-reference-contract",
|
||||
"status": "pending",
|
||||
"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"
|
||||
@@ -46,7 +53,8 @@
|
||||
{
|
||||
"step": 5,
|
||||
"name": "implementation-plan",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"summary": "3D Euler beam implementation plan added",
|
||||
"allowed_paths": [
|
||||
"docs/implementation-plans/euler-beam-3d-implementation-plan.md"
|
||||
]
|
||||
@@ -54,7 +62,8 @@
|
||||
{
|
||||
"step": 6,
|
||||
"name": "model-beam-topology",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"summary": "beam2 model topology added with unit test",
|
||||
"allowed_paths": [
|
||||
"src/fesa/model/element.hpp",
|
||||
"src/fesa/model/element.cpp",
|
||||
@@ -64,7 +73,8 @@
|
||||
{
|
||||
"step": 7,
|
||||
"name": "local-stiffness-kernel",
|
||||
"status": "pending",
|
||||
"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"
|
||||
@@ -73,7 +83,8 @@
|
||||
{
|
||||
"step": 8,
|
||||
"name": "global-transform-recovery",
|
||||
"status": "pending",
|
||||
"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"
|
||||
@@ -82,7 +93,8 @@
|
||||
{
|
||||
"step": 9,
|
||||
"name": "build-test-report",
|
||||
"status": "pending",
|
||||
"status": "completed",
|
||||
"summary": "3D Euler beam build/test report added",
|
||||
"allowed_paths": [
|
||||
"docs/build-test-reports/euler-beam-3d-build-test.md"
|
||||
]
|
||||
@@ -90,10 +102,12 @@
|
||||
{
|
||||
"step": 10,
|
||||
"name": "release-readiness-note",
|
||||
"status": "pending",
|
||||
"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"
|
||||
}
|
||||
|
||||
+31
-2
@@ -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", "-"],
|
||||
cwd=self._root, capture_output=True, text=True, input=prompt, 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")
|
||||
|
||||
+66
-1
@@ -1,5 +1,6 @@
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -294,16 +295,80 @@ class ExecuteRunnerSafetyTests(unittest.TestCase):
|
||||
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", "exec", "--dangerously-bypass-approvals-and-sandbox", "--json", "-"],
|
||||
["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__":
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -9,6 +9,7 @@ namespace fesa::model {
|
||||
enum class ElementTopology {
|
||||
truss2,
|
||||
bar2,
|
||||
beam2,
|
||||
unknown
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user