# Linear Static 3D Euler Beam End-to-End Design ## Metadata - feature_id: `linear-static-3d-euler-beam` - phase_name: `linear-static-3d-euler-beam` - status: `approved` - approved_by: user - approved_on: `2026-08-08` - source_formulation: `docs/formulations/3d-isoparametric-euler-beam-formulation.md` - implementation_environment: C++17, MSVC, CMake, CTest, GoogleTest, Intel oneMKL, Intel oneTBB, HDF5 ## 1. 목적 이 설계는 Abaqus `.inp` keyword subset을 읽어 2절점 3차원 Euler–Bernoulli beam의 단일 선형 정적 step을 해석하고, 변위·반력·요소 내력·축응력을 authoritative HDF5 파일 `results.h5`에 기록하는 FESA V0 파이프라인을 정의한다. 런타임 순서는 다음과 같이 고정한다. ```text .inp 입력 -> Domain 생성 -> 현재 step의 AnalysisModel 생성 -> DofManager 및 sparse pattern 생성 -> 요소강성 계산과 전역강성 조립 -> free/constrained partition -> MKL PARDISO factorization -> 전체 하중벡터 조립과 effective RHS 생성 -> PARDISO substitution -> 전체 변위벡터 복구 -> 반력·요소 내력·요소 축응력 복구 -> results.h5 기록 -> 정상 종료 ``` ## 2. 범위 ### 2.1 포함 범위 - 입력 파일당 하나의 `*STEP, *STATIC` - small displacement, small rotation, 선형 탄성 해석 - 2절점 직선 3D Euler–Bernoulli beam - 절점당 자유도 `[UX, UY, UZ, URX, URY, URZ]` - 축, 두 방향 굽힘, Saint-Venant 비틀림 - nodal concentrated load와 prescribed displacement - formulation의 constant local line-load equivalent nodal vector kernel - nonzero prescribed displacement를 포함한 자유/구속 partition - deterministic COO-to-CSR sparse assembly - MKL PARDISO factorization과 substitution의 분리 - oneTBB 기반 element-local 계산 - 변위, 반력, equilibrium end action, section resultant, axial `S11` 출력 - Abaqus B33 변위·반력·section resultant reference comparison ### 2.2 제외 범위 - Abaqus full compatibility - Abaqus B31/Timoshenko beam - 다중 analysis step과 step 간 load/BC propagation - instance translation/rotation, nested assembly, dependent/independent mesh 차이 - `I12 != 0`, taper, offset, release, curved beam, warping - distributed load용 Abaqus `*DLOAD` 입력과 Domain load object 생성 - 기하·재료비선형, dynamics, contact, thermal effects - transverse shear stress와 torsional shear stress recovery - beam stress에 대한 Abaqus reference comparison - reference artifact의 자동 생성, 수정 또는 Abaqus 실행 ## 3. Phase 구성 단일 Harness task `linear-static-3d-euler-beam`은 다음 29개 step으로 구성한다. 각 step은 하나의 gate 또는 하나의 C++ 모듈만 소유한다. ### 3.1 문서 및 계약 gate | Step | Name | Primary output | | ---: | --- | --- | | 0 | `requirements-baseline` | `docs/requirements/linear-static-3d-euler-beam.md` | | 1 | `research-evidence` | `docs/research/linear-static-3d-euler-beam-research.md` | | 2 | `formulation-alignment` | `docs/formulations/3d-isoparametric-euler-beam-formulation.md` | | 3 | `numerical-review` | `docs/numerical-reviews/linear-static-3d-euler-beam-review.md` | | 4 | `io-contract` | `docs/io-definitions/linear-static-3d-euler-beam-io.md` | | 5 | `reference-model-contract` | `docs/reference-models/linear-static-3d-euler-beam-reference-models.md` | | 6 | `implementation-plan` | `docs/implementation-plans/linear-static-3d-euler-beam.md` | ### 3.2 C++ TDD 구현 | Step | Name | Module responsibility | | ---: | --- | --- | | 7 | `cmake-test-foundation` | CMake, GoogleTest, CTest, dependency discovery | | 8 | `core-diagnostics` | IDs, source locations, diagnostics, status | | 9 | `dense-math-adapters` | MKL BLAS `Matrix` and `Vector` | | 10 | `domain-model` | Immutable model definitions and source identities | | 11 | `inp-syntax-parser` | Keyword/data/comment lexical and syntax parsing | | 12 | `inp-domain-mapping` | Part/Assembly/Instance semantic mapping | | 13 | `analysis-model` | Active single-step views into Domain | | 14 | `dof-manager` | DOFs, constraints, numbering, sparse pattern | | 15 | `analysis-state` | Displacement, forces, residual, step/frame state | | 16 | `euler-beam-element` | B33 element stiffness, transformation, load/recovery kernels | | 17 | `parallel-for-tbb` | oneTBB adapter for deterministic element-local work | | 18 | `sparse-assembly` | COO contribution collection and CSR finalization | | 19 | `essential-constraints` | Matrix partition and full/reduced vector mapping | | 20 | `mkl-pardiso-solver` | PARDISO adapter, factorization, substitution, diagnostics | | 21 | `load-assembly` | Nodal load vector and prescribed-displacement RHS | | 22 | `result-recovery` | Reactions, end actions, resultants, axial stress | | 23 | `hdf5-results-writer` | Versioned HDF5 schema and atomic finalization | | 24 | `linear-static-cli` | Analysis orchestration and `fesa.exe` entry point | ### 3.3 최종 gate | Step | Name | Primary output | | ---: | --- | --- | | 25 | `build-test-verification` | `docs/build-test-reports/linear-static-3d-euler-beam.md` | | 26 | `reference-verification` | `docs/reference-verifications/linear-static-3d-euler-beam-reference-verification.md` | | 27 | `physics-sanity` | `docs/physics-evaluations/linear-static-3d-euler-beam-physics-evaluation.md` | | 28 | `release-readiness` | `docs/releases/linear-static-3d-euler-beam-release.md` | ## 4. 아키텍처와 소유권 ### 4.1 Domain 계층 `Domain`은 parser가 만든 전체 모델을 소유하며 parsing 이후 가능한 한 불변으로 취급한다. 최소 semantic object는 다음과 같다. - `Node` - `EulerBeam3DDefinition` - `LinearElasticMaterial` - `GeneralBeamSection` - `NodeSet`, `ElementSet` - `BoundaryCondition`, `NodalLoad` - `StaticStepDefinition` Part 내부 source label은 변경하지 않는다. 외부 identity는 `SourceEntityId { instance_name, source_label }`로 유지하고, Domain은 별도의 stable internal index를 부여한다. 같은 part의 여러 identity instance는 허용하지만 instance transform data가 있으면 입력 오류로 처리한다. ### 4.2 AnalysisModel `AnalysisModel`은 단일 static step에 활성화된 element, load, boundary condition, material, section의 ID/reference view를 제공한다. Domain 객체를 복사하거나 수정하지 않는다. 두 번째 `*STEP`은 V0 unsupported diagnostic을 발생시킨다. ### 4.3 DofManager `DofManager`만 다음 정보를 소유한다. - node별 6개 DOF 정의 - full DOF index - constrained/free mapping - free equation numbering - element scatter map - sparse matrix pattern - full/reduced vector reconstruction Node와 Element에는 equation ID를 저장하지 않는다. ### 4.4 AnalysisState `AnalysisState`는 다음 해석 중 상태를 소유한다. - full displacement - external force - internal force - residual - constrained reaction - current step/frame identity - element recovery rows V0에서는 velocity, acceleration, temperature, iteration history를 할당하지 않는다. ### 4.5 요소 계약 `EulerBeam3D`는 `docs/formulations/3d-isoparametric-euler-beam-formulation.md`의 부호, DOF 순서, 2점 Gauss rule, transformation을 따른다. 구현 API는 다음 책임을 분리한다. ```cpp Matrix localStiffness() const; Matrix globalStiffness() const; Vector localEquivalentLoad(const ConstantLocalLineLoad& load) const; BeamRecovery recover(const Vector& globalElementDisplacement) const; ``` 요소는 equation ID를 소유하지 않는다. `BeamRecovery`는 endpoint equilibrium end action, endpoint section resultant, Gauss-point generalized strain/resultant, section-point `S11`을 구분한다. `localEquivalentLoad`는 정식화의 constant local line-load vector를 검증하기 위한 element kernel이지만 V0 `.inp` parser는 `*DLOAD`를 생성하지 않으므로 CLI 해석에서는 호출되지 않는다. ### 4.6 LinearSolver 계약 Solver core에는 MKL 타입을 노출하지 않는다. ```cpp class LinearSolver { public: virtual ~LinearSolver() = default; virtual Status factorize(const SparseMatrix& matrix) = 0; virtual Status solve(const Vector& rhs, Vector& solution) const = 0; }; ``` `MklPardisoSolver`는 factorization 상태를 소유하고 같은 matrix에 여러 RHS substitution을 수행할 수 있다. singularity와 invalid CSR은 구조화된 diagnostic으로 반환한다. V0는 constrained `Kff`를 real symmetric positive definite matrix로 factorize하며, positive-definite factorization 실패를 unconstrained, singular 또는 invalid model diagnostic으로 분류한다. ## 5. Matrix, Vector 및 SparseMatrix ### 5.1 Vector `Vector`는 연속된 `double` 데이터와 크기를 소유한다. copy/move semantics와 bounds-checked access를 제공한다. 다음 연산은 MKL CBLAS를 사용한다. - copy - `dot` - Euclidean norm - `scale` - `axpy` ### 5.2 Matrix `Matrix`는 연속된 row-major `double` 데이터, row count, column count를 소유한다. copy/move semantics와 bounds-checked access를 제공한다. matrix-vector와 matrix-matrix 연산은 `CBLAS_ROW_MAJOR`의 MKL CBLAS를 사용한다. beam의 3x3, 4x12, 12x12 dense 연산도 이 타입을 사용한다. MKL header와 MKL-specific type은 `.cpp` adapter 경계 밖으로 노출하지 않는다. ### 5.3 SparseMatrix `SparseMatrix`는 CSR 전용 별도 타입이며 `Matrix`를 상속하지 않는다. CSR row pointer, column index, values를 소유하고 0-based indexing을 사용한다. PARDISO adapter가 필요한 indexing과 descriptor 변환은 adapter 내부에서 수행한다. ## 6. 입력 계약 ### 6.1 지원 keyword - `*HEADING` - `*PART`, `*END PART` - `*NODE` - `*ELEMENT, TYPE=B33` - `*NSET`, `*ELSET`, including `GENERATE` - `*MATERIAL`, `*ELASTIC` - `*BEAM GENERAL SECTION, SECTION=GENERAL` - `*SECTION POINTS` - `*ASSEMBLY`, `*END ASSEMBLY` - `*INSTANCE`, `*END INSTANCE` - `*BOUNDARY` - `*CLOAD` - `*STEP`, `*STATIC`, `*END STEP` Keyword와 parameter는 case-insensitive이고 label identity는 원문 값을 보존한다. Comment line은 `**`로 시작한다. `*BOUNDARY`는 `target, first_dof, last_dof[, value]` 형식만 지원하고 DOF 범위는 1부터 6까지다. value가 없으면 0으로 해석한다. `*CLOAD`는 `target, dof, magnitude` 형식만 지원하고 DOF 범위는 1부터 6까지다. target은 source node label 또는 node set이며 assembly-level set의 `INSTANCE` parameter를 해석한다. ### 6.2 General beam section mapping `*BEAM GENERAL SECTION, SECTION=GENERAL`의 data는 `A, I11, I12, I22, J` 순서로 읽는다. - `MATERIAL` parameter는 필수이며 해당 `*MATERIAL`의 isotropic `*ELASTIC` data는 정확히 `E, nu`를 제공해야 한다. - `I12`는 0이어야 한다. - Abaqus first beam section axis `n1`을 FESA local `y`로 둔다. - `t x n1`을 FESA local `z`로 둔다. - `Iy = I11`, `Iz = I22`로 매핑한다. - `E`와 Poisson ratio `nu`로 `G = E / (2(1 + nu))`를 계산한다. - `E`, `G`, `A`, `Iy`, `Iz`, `J`는 양수여야 한다. - `coordinate_scale = max(1, norm(X1), norm(X2))`에 대해 `L > 1e-12 * coordinate_scale`이어야 한다. - guide vector는 0이 아니어야 하며 `norm(a_perp) > 1e-12 * max(1, norm(a))`이어야 한다. 이 축 계약은 Abaqus의 right-handed `(t, n1, n2)` section system 및 현재 formulation의 `(x, y, z)` system과 일치한다. ### 6.3 B33 의미 보존 Abaqus B31은 transverse shear deformation을 포함하는 Timoshenko beam이고 B33은 2절점 cubic Euler–Bernoulli beam이다. FESA V0는 `TYPE=B33`만 Euler 요소로 매핑한다. `TYPE=B31`은 `unsupported-element-formulation` 오류로 거부한다. 기존 B31 reference 결과를 tolerance 확대로 Euler reference인 것처럼 사용하지 않는다. 이 결정은 [[Abaqus Structural Element Families]], [[Beam and Frame Finite Elements]], [[Abaqus-Analysis-User-s-Guide-Volume-IV|Abaqus Analysis User's Guide Volume IV]]의 beam-family 구분을 따른다. ### 6.4 Instance 제한 - 같은 part의 여러 identity instance를 허용한다. - instance name과 source node/element/set label을 보존한다. - source identity를 stable Domain index로 deterministic하게 매핑한다. - translation 또는 rotation data가 있으면 `unsupported-instance-transform` 오류를 낸다. - nested assembly와 dependent/independent mesh semantics는 지원하지 않는다. ### 6.5 No-op allowlist 다음 keyword와 관련 data line은 구조화된 warning을 기록하고 해석에서는 사용하지 않는다. - `*PREPRINT` - `*RESTART` - `*TRANSVERSE SHEAR STIFFNESS` - `*OUTPUT, FIELD` - `*OUTPUT, HISTORY` - `*NODE OUTPUT` - `*ELEMENT OUTPUT` - `*CONTACT OUTPUT` - 위 output request에 속한 미지원 variable data 이 allowlist 밖의 미지원 keyword는 오류다. FESA의 기본 출력은 Abaqus output request와 무관하게 항상 생성된다. ## 7. 선형 정적 알고리즘 1. `AbaqusInputReader`가 syntax model과 source location을 만든다. 2. semantic mapper가 immutable `Domain`을 만든다. 3. `AnalysisModel`이 단일 static step의 active view를 만든다. 4. `DofManager`가 DOF, constraints, scatter map, sparse pattern을 만든다. 5. `ParallelFor`가 element-local global stiffness를 계산한다. 6. element internal index 순서로 COO contribution을 deterministic하게 reduce하고 CSR로 finalize한다. 7. free/constrained partition으로 `Kff`, `Kfc`, `Kcf`, `Kcc`를 만든다. 8. `MklPardisoSolver::factorize(Kff)`를 호출한다. 9. nodal load를 full `F`에 조립한다. 10. `rhs = Ff - Kfc * dc`를 만든다. 11. `solve(rhs, df)`로 substitution하고 full `d`를 복구한다. 12. `Rc = Kcf * df + Kcc * dc - Fc`로 reaction을 복구한다. 13. element displacement를 gather하여 end action, section resultant, strain, `S11`을 복구한다. 14. `ResultsWriter`가 임시 HDF5 파일을 완성한 뒤 최종 `results.h5`로 교체한다. 반력은 요소 끝력의 별도 합산 경로가 아니라 전체 조립 residual `K*d-F`에서 구한다. ## 8. 결과 복구 ### 8.1 변위와 반력 모든 node에 전역 성분 `[UX, UY, UZ, URX, URY, URZ]`를 기록한다. 반력은 동일한 6성분 순서로 기록하고 free DOF의 값은 수치 residual 검사에 사용한다. ### 8.2 요소 내력 다음 데이터를 서로 다른 dataset으로 유지한다. - equilibrium end action: `Kl*dl-fl_dist`, local `[FX,FY,FZ,MX,MY,MZ]` - section resultant: endpoint `xi=-1,+1`의 `[N,T,My,Mz]` - generalized strain/resultant: 두 Gauss point의 formulation 값 Abaqus internal-force CSV는 equilibrium end action이 아니라 section resultant와 비교한다. component mapping은 다음과 같다. | Abaqus | FESA local component | | --- | --- | | `SF1` | `FX` / `N` | | `SF3` | `FY` | | `SF2` | `FZ` | | `SM3` | `MX` / `T` | | `SM1` | `MY` | | `SM2` | `MZ` | ### 8.3 Axial stress General beam section은 section point에서 axial stress만 복구한다. ```text S11 = E * (epsilon0 + x2*kappa1 - x1*kappa2) ``` FESA 좌표로는 `x1=y`, `x2=z`, `kappa1=kappa_y`, `kappa2=kappa_z`다. `*SECTION POINTS`가 있으면 지정 순서대로 출력한다. 없으면 FESA-specific centroid point `(0,0)`을 만들고 `source=fesa-default`로 기록한다. Stress는 두 Gauss point에서 평가한다. Transverse shear stress와 torsional shear stress는 출력하지 않는다. 이 계약은 [[Abaqus Beam and Shell Section Definitions]]과 [[Abaqus-Analysis-User-s-Guide-Volume-IV|Abaqus Analysis User's Guide Volume IV]]의 general beam section output 제한을 따른다. ## 9. HDF5 schema v0 Authoritative output은 `results.h5` 하나다. 최소 schema는 다음과 같다. ```text /metadata /model/nodes /model/elements /steps//frames/0/nodal/displacement /steps//frames/0/nodal/reaction /steps//frames/0/element/end_force_local /steps//frames/0/element/section_resultant /steps//frames/0/element/generalized_strain /steps//frames/0/element/stress_s11 /diagnostics ``` `/metadata`에는 schema version, solver version, source input identity, unit-system label, coordinate convention, element formulation을 기록한다. Node/element group은 stable internal ID와 instance/source label mapping을 함께 저장한다. Abaqus `.inp` 자체에는 단위 선언이 없으므로 일반 solver run의 unit-system label은 `user-consistent-unspecified`로 기록한다. Reference comparison에서는 별도 `metadata.json`이 선언한 단위계를 authoritative unit label로 사용하며, solver가 입력 파일만 보고 SI를 추론하지 않는다. - displacement: `[node_count, 6]` - reaction: `[node_count, 6]` - end force: `[element_count, 2, 6]` - section resultant: `[element_count, 2, 4]`, `xi={-1,+1}` - generalized strain: `[element_count, 2, 4]`, two Gauss points - stress: flat row identity with element, Gauss point, section point, `(x1,x2)`, `S11` HDF5 API는 `Hdf5ResultsWriter` implementation 밖으로 노출하지 않는다. Writer failure 시 불완전한 최종 `results.h5`를 남기지 않는다. ## 10. CLI와 diagnostics ```powershell fesa.exe --output ``` `--output`을 생략하면 현재 작업 디렉터리에 `results.h5`를 생성한다. | Exit code | Meaning | | ---: | --- | | 0 | success | | 2 | CLI usage error | | 3 | input syntax or semantic mapping error | | 4 | model validation error | | 5 | factorization or substitution error | | 6 | HDF5 output error | 각 diagnostic은 `severity`, `code`, `file`, `line`, `keyword`, `entity_identity`, `message`를 가진다. CLI는 오류 diagnostic을 stderr에 deterministic한 순서로 출력한다. ## 11. TDD와 검증 ### 11.1 C++ step 규칙 각 production C++ step은 다음 순서를 같은 step 안에서 증명한다. 1. GoogleTest 작성 2. 관련 test target 실행과 요구사항을 재현하는 RED 실패 확인 3. 최소 production 구현 4. 관련 CTest GREEN 확인 5. 전체 MSVC x64 Debug build와 CTest VERIFY 새 경고를 허용하지 않으며 FESA target에만 MSVC `/W4 /WX`를 적용한다. Third-party GoogleTest target에는 FESA warning policy를 강제하지 않는다. ### 11.2 테스트 포트폴리오 - Matrix/Vector ownership, bounds, dimension mismatch, BLAS result checks - parser case-insensitivity, comments, set generation, wrapper nesting, allowlist diagnostics - B31 rejection, B33 acceptance, instance transform rejection, unknown keyword rejection - Domain duplicate label와 dangling reference validation - AnalysisModel active view와 Domain non-copy/non-mutation 검사 - DofManager numbering, constraints, scatter map, full/reduced reconstruction - Hermite interpolation, B matrix, 2-point Gauss vs closed-form stiffness - symmetry, rank 6, six rigid modes, positive deformation energy - local/global transform orthogonality와 energy invariance - deterministic parallel COO reduction과 CSR structure - nonzero prescribed displacement와 reaction recovery - PARDISO factorization/substitution 분리, repeated RHS, singular diagnostic - axial, torsion, y/z bending cantilever analytical cases - HDF5 schema, identity, component, metadata, atomic finalization - CLI `.inp -> results.h5` integration ### 11.3 수치 tolerance | Check | Criterion | | --- | --- | | matrix symmetry and Gauss/closed-form comparison | normalized `1e-12` | | rigid-mode and linear-system residual | normalized `1e-10` | | analytical solution tests | relative `1e-9` | | Abaqus B33 reference comparison | relative `1e-6` | | SI displacement and rotation absolute floor | `1e-9` | | SI force and moment absolute floor | `1e-3` | Reference row 판정은 `abs_error <= abs_tol OR rel_error <= rel_tol`을 사용한다. Reference metadata가 SI가 아니면 quantity별 absolute tolerance를 동일 차원으로 변환해야 하며 변환 근거를 verification report에 기록한다. ### 11.4 공통 build/test command GoogleTest checkout은 `C:/git/googletest`에 있고 승인 당시 revision은 `04ee1b4f2aefdffb0135d7cf2a2c519fe50dabe4`다. 절대경로를 production CMake에 하드코딩하지 않고 cache variable로 전달한다. ```powershell cmake -S . -B .harness/build -A x64 ` -DFESA_GTEST_SOURCE_DIR=C:/git/googletest ` "-DMKL_DIR=C:/Program Files (x86)/Intel/oneAPI/mkl/2026.1/lib/cmake/mkl" ` "-DTBB_DIR=C:/Program Files (x86)/Intel/oneAPI/tbb/2023.1/lib/cmake/tbb" ` "-DHDF5_DIR=C:/Program Files/HDF_Group/HDF5/2.1.1/cmake" cmake --build .harness/build --config Debug ctest --test-dir .harness/build -C Debug --show-only=json-v1 ctest --test-dir .harness/build -C Debug --output-on-failure ``` CTest discovery 결과는 한 개 이상의 test를 포함해야 한다. ## 12. Reference 및 release gate 기존 `reference/cantilever beam/` bundle은 Abaqus B31 결과이므로 수정하지 않고 V0 Euler verification에 사용하지 않는다. Reference Model Contract는 사람이 Abaqus에서 생성할 B33 bundle의 다음 artifact를 요구한다. - `model.inp` using `TYPE=B33` - `metadata.json` with Abaqus version, units, coordinate system, provenance, tolerances - `_displacements.csv` - `_reactions.csv` - `_internalforces.csv` - `README.md` - stress CSV: explicitly `not-applicable` for this feature Agent와 Harness는 Abaqus를 실행하거나 reference artifact를 생성·수정하지 않는다. B33 artifact가 없으면 reference-verification step은 `blocked`로 끝나며 사용자가 bundle을 준비한 후 해당 step을 `pending`으로 되돌려 재개한다. Reference comparison이 pass한 뒤에만 physics sanity를 수행한다. Physics sanity는 global force/moment equilibrium, reaction sign, displacement direction, symmetry, element section-force consistency, normalized residual을 검사한다. Release readiness는 모든 이전 gate evidence와 known limitations를 확인한다. ## 13. 완료 조건 다음 조건을 모두 만족해야 phase를 완료할 수 있다. 1. 요구조건, 연구, 정식화, 수치 검토, I/O, reference model, 구현 계획 문서가 승인 상태다. 2. 모든 production C++ 변경에 대응 테스트와 RED/GREEN/VERIFY evidence가 있다. 3. MSVC x64 Debug configure, build, CTest discovery, 전체 CTest가 성공한다. 4. `fesa.exe`가 승인된 B33 single-step input에서 `results.h5`를 생성한다. 5. HDF5 변위·반력·내력 rows가 Abaqus B33 reference CSV와 tolerance 안에서 일치한다. 6. Beam stress reference comparison은 명시적 N/A이고 stress output schema/test는 통과한다. 7. Physics sanity가 pass한다. 8. Release report에 지원 subset과 모든 V0 제한사항이 기록된다.