625 lines
27 KiB
Markdown
625 lines
27 KiB
Markdown
# 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`
|
||
- amended_on: `2026-08-18`
|
||
- source_formulation: `docs/linear-static-3d-euler-beam/formulation.md`
|
||
- reference_baseline: exact read-only artifacts under `reference/cantilever beam/`
|
||
- implementation_environment: C++17, MSVC, CMake, CTest, GoogleTest, Intel oneMKL, Intel oneTBB, HDF5
|
||
|
||
2026-08-18 amendment: the former node-station projection and mixed absolute-floor tolerance are
|
||
superseded by the direct element-endpoint identity and common family-scale row/RMS policy in
|
||
`2026-08-17-common-reference-tolerance-design.md` and ADR-022.
|
||
|
||
## 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` 출력
|
||
- 승인된 `reference/cantilever beam/` B33 bundle의 변위·반력·section resultant 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/linear-static-3d-euler-beam/requirements.md` |
|
||
| 1 | `research-evidence` | `docs/linear-static-3d-euler-beam/research.md` |
|
||
| 2 | `formulation-alignment` | `docs/linear-static-3d-euler-beam/formulation.md` |
|
||
| 3 | `numerical-review` | `docs/linear-static-3d-euler-beam/numerical-review.md` |
|
||
| 4 | `io-contract` | `docs/linear-static-3d-euler-beam/io.md` |
|
||
| 5 | `reference-model-contract` | `docs/linear-static-3d-euler-beam/reference-model.md` |
|
||
| 6 | `implementation-plan` | `docs/linear-static-3d-euler-beam/implementation-plan.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/linear-static-3d-euler-beam/build-test.md` |
|
||
| 26 | `reference-verification` | `docs/linear-static-3d-euler-beam/reference-comparison.md` |
|
||
| 27 | `physics-sanity` | `docs/linear-static-3d-euler-beam/physics-evaluation.md` |
|
||
| 28 | `release-readiness` | `docs/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/linear-static-3d-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` 오류로 거부한다.
|
||
`reference/cantilever beam/cantilever beam.inp`는 `TYPE=B33`으로 생성된 승인 reference
|
||
input이다. Reference artifact check는 비교 전에
|
||
이 element type을 다시 확인하며 B31로 되돌아간 입력이나 결과를 허용하지 않는다.
|
||
|
||
이 결정은 [[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` |
|
||
|
||
승인된 B33 reference의 `cantilever beam elemental forces.csv`는 `Frame`,
|
||
`Part Instance Name`, `Element Label`, `Node Label`, `SF1`, `SM1`, `SM2`, `SM3`을
|
||
기록한다.
|
||
따라서 이 파일의 comparison은 다음 규칙을 사용한다.
|
||
|
||
- Reference row key는 `(Step-1, frame 0, instance name, source element label,
|
||
endpoint source node label, component)`다.
|
||
단일 step invariant에 따라 CSV의 `Increment 1: Step Time = 1.000`을
|
||
`(Step-1, frame 0)`으로 정규화한다.
|
||
- 각 B33 element에는 input connectivity의 두 source node label과 일치하는 endpoint row가
|
||
정확히 두 개 있어야 하며, 각 row를 해당 HDF5 element endpoint에 직접 대응한다.
|
||
Missing, extra, duplicate 또는 connectivity mismatch는 tolerance 전에 실패한다.
|
||
- Comparator는 같은 source node의 인접 endpoint를 node station으로 축약하거나 대표값을
|
||
선택하거나 평균하지 않는다.
|
||
- 이 bundle에서 비교하는 mapping은 `SF1 -> N`, `SM1 -> My`, `SM2 -> Mz`,
|
||
`SM3 -> T`다. CSV에 없는 `SF2`와 `SF3`는 reference comparison 대상이 아니며,
|
||
FESA equilibrium end action의 transverse force는 unit/analytical test와 physics sanity로
|
||
검증한다.
|
||
|
||
### 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/<step-name>/frames/0/nodal/displacement
|
||
/steps/<step-name>/frames/0/nodal/reaction
|
||
/steps/<step-name>/frames/0/element/end_force_local
|
||
/steps/<step-name>/frames/0/element/section_resultant
|
||
/steps/<step-name>/frames/0/element/generalized_strain
|
||
/steps/<step-name>/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`로 기록하고 solver가 입력 파일만 보고 SI를 추론하지
|
||
않는다. 승인된 cantilever B33 reference에 한해서는 이 설계와 후속 Reference Model
|
||
Contract가 입력 수치의 단위계를 SI로 선언하고, reference verification이 동일한 입력으로
|
||
생성된 FESA 결과에 그 외부 단위 계약을 적용한다. 새 reference model도 승인된
|
||
Reference Model Contract에 단위계를 선언한다. 선택 `metadata.json`이 존재하면 그
|
||
단위 선언을 read-only 보조 자료로 계약과 대조한다.
|
||
|
||
- 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 <model.inp> --output <results.h5>
|
||
```
|
||
|
||
`--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
|
||
- 승인된 B33 CSV header/Frame 정규화와 element-endpoint direct identity 검사
|
||
- zero 및 near-zero reference row를 포함한 공통 family-scale 상대오차/RMS 검사
|
||
|
||
### 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 reference row relative error | `0.05` |
|
||
| near-zero threshold ratio | reference family scale의 `0.01` |
|
||
| reference family scale-relative RMS | `0.01` |
|
||
|
||
Reference row 판정은 같은 model, step/frame, quantity, component로 구성한 reference
|
||
family별 공통 규칙을 사용한다. Reference 값으로만 family scale을 계산한다.
|
||
|
||
```text
|
||
S = max(abs(reference_value_i))
|
||
near_zero_i = abs(reference_value_i) <= 0.01 * S
|
||
row_pass_i = abs(fesa_value_i - reference_value_i) / abs(reference_value_i) <= 0.05
|
||
if not near_zero_i
|
||
row_pass_i = abs(fesa_value_i - reference_value_i) <= 0.01 * S
|
||
if near_zero_i
|
||
relative_rms = sqrt(mean((fesa_value_i - reference_value_i)^2)) / S
|
||
family_pass = all(row_pass_i) and relative_rms <= 0.01
|
||
```
|
||
|
||
- Family는 displacement, rotation, force, moment 및 각 component를 섞지 않는다.
|
||
- Scale은 read-only Abaqus reference 값만 사용하며 FESA 결과로 조정하지 않는다.
|
||
- `S == 0`이면 모든 FESA 값이 정확히 0일 때만 통과한다. 하나라도 0이 아니면
|
||
`zero-reference-scale-nonzero-error`로 실패한다.
|
||
- 모든 row를 개별 판정하며 reference 값을 zero-clamp하거나 row를 제거하지 않는다.
|
||
- Missing/extra row, nonfinite value, schema 또는 identity mismatch는 tolerance 계산 전에
|
||
실패한다.
|
||
- Report는 family scale, max absolute error, max row relative error, scale-relative RMS,
|
||
worst row/component와 판정 reason을 기록한다. 독립적인 absolute-error gate는 없다.
|
||
|
||
### 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/`을 V0의 승인된 Abaqus B33 reference baseline으로 사용한다.
|
||
논리 model ID는 `cantilever-beam-b33`이다. 기존 `abaqus-cae-report-csv-v0`과 source
|
||
commit `2b34d0b` 기록은 2026-08-09 당시 inventory의 역사적 provenance이며, 2026-08-18
|
||
regenerated elemental-force CSV의 현재 readiness gate가 아니다. Input header가 기록한
|
||
generator는 `Abaqus/CAE Learning Edition 2024`다. 모델은 SI 단위계, global
|
||
Cartesian nodal output, beam local section-force output, `Step-1`, increment 1,
|
||
step time 1.0 계약으로 해석한다.
|
||
|
||
| Purpose | Approved artifact |
|
||
| --- | --- |
|
||
| analysis input | `reference/cantilever beam/cantilever beam.inp` |
|
||
| displacement | `reference/cantilever beam/cantilever beam displacements.csv` |
|
||
| reaction | `reference/cantilever beam/cantilever beam reactions.csv` |
|
||
| section resultant | `reference/cantilever beam/cantilever beam elemental forces.csv` |
|
||
| stress | N/A: beam stress reference comparison은 승인 범위에서 제외 |
|
||
|
||
이 기존 bundle의 space-containing filename과 CAE report header는 승인된 legacy alias로
|
||
그대로 지원하며 reference artifact를 rename하거나 rewrite하지 않는다. `README.md`는 이
|
||
baseline에 한해서 N/A다. `metadata.json`은 프로젝트 전역에서 선택 artifact이며 이
|
||
bundle에는 존재하지 않는다. 이 설계와 Step 5의 Reference Model Contract가 model ID,
|
||
provenance, units, coordinate system, schema, file inventory, tolerance와 stress N/A 사유를
|
||
기록한다. 이후 추가하는 reference model에는 canonical artifact 이름과 `README.md`를
|
||
요구하며, 선택 `metadata.json`이 존재하면 계약과 대조한다.
|
||
|
||
Reference verification은 build/test gate 통과 후 승인 input으로 FESA `results.h5`를
|
||
생성하고 다음을 직접 비교한다.
|
||
|
||
- nodal displacement: CSV `U1/U2/U3/UR1/UR2/UR3`과 HDF5 displacement
|
||
- nodal reaction: CSV `RF1/RF2/RF3/RM1/RM2/RM3`과 HDF5 reaction
|
||
- section resultant: CSV `SF1/SM1/SM2/SM3`과 element label 및 endpoint node label로
|
||
직접 대응한 HDF5 section resultant
|
||
- stress: 명시적 N/A
|
||
|
||
Artifact check는 네 파일의 존재, B33 element type, expected header, 유일한 row key,
|
||
finite value를 확인한다. 하나라도 충족하지 않으면 `needs-reference-artifacts` 또는
|
||
`schema-mismatch`로 분류하고 comparison을 시작하지 않는다. `metadata.json` 부재는 모든
|
||
bundle에서 허용되며, 현재 baseline의 `README.md` 부재도 승인된 legacy 예외로 차단하지
|
||
않는다.
|
||
|
||
Agent와 Harness는 Abaqus를 실행하거나 reference artifact를 생성·수정하지 않는다.
|
||
|
||
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가 승인된 cantilever B33 reference CSV와 component-scale
|
||
혼합 tolerance 안에서 일치한다.
|
||
6. Beam stress reference comparison은 명시적 N/A이고 stress output schema/test는
|
||
통과한다.
|
||
7. Physics sanity가 pass한다.
|
||
8. Release report에 지원 subset과 모든 V0 제한사항이 기록된다.
|