add uncommitted files
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "abaqus-subset-completion",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "abaqus-input-contract",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "part-and-assembly-set-resolution",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "single-instance-semantic-validation",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "material-section-and-shear-defaults",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 4,
|
||||
"name": "step-bc-load-and-noop-directives",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
# Step 0: Abaqus Input Contract
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/io/abaqus/`
|
||||
- `/reference/cantilever beam/cantilever beam.inp`
|
||||
|
||||
## 작업
|
||||
|
||||
production parser를 수정하기 전에 `docs/ABAQUS_INPUT_SUBSET.md`를 normative contract로
|
||||
작성하고 valid/invalid fixture matrix를 등록한다.
|
||||
|
||||
문서에 각 keyword의 허용 scope, parameter, data line, diagnostic을 정확히 정의한다.
|
||||
|
||||
- `*NODE`, `*ELEMENT,TYPE=B31`
|
||||
- `*PART/*END PART`, `*ASSEMBLY/*END ASSEMBLY`,
|
||||
`*INSTANCE/*END INSTANCE`
|
||||
- `*NSET`, `*ELSET`, `GENERATE`, nested set, `INSTANCE=`
|
||||
- `*MATERIAL`, `*ELASTIC`, `*BEAM GENERAL SECTION`
|
||||
- optional `*TRANSVERSE SHEAR STIFFNESS`
|
||||
- `*BOUNDARY`, `*CLOAD`, `*STEP`, `*STATIC`, `*END STEP`
|
||||
- no-op `*HEADING`, `*PREPRINT`, `*RESTART`, `*OUTPUT`
|
||||
|
||||
`tests/fixtures/abaqus/valid`와 `invalid`에 최소 한 규칙당 fixture를 정의하고
|
||||
data-driven contract test를 먼저 실패시킨다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R AbaqusInputContract --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 문서와 fixture manifest를 먼저 작성한다.
|
||||
2. 아직 미구현인 계약 테스트가 실패하는 것을 확인한다.
|
||||
3. 이 step에서는 parser behavior를 확장하지 않는다.
|
||||
4. index summary에 계약 문서와 미통과 fixture 범위를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- Abaqus 전체 문법 지원을 약속하지 마라. 이유: 명시된 subset만 대상이다.
|
||||
- unknown keyword ignore 규칙을 만들지 마라. 이유: 조용한 모델 손실을 유발한다.
|
||||
- reference 원본을 고치지 마라. 이유: golden provenance를 보존해야 한다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Step 1: Part and Assembly Set Resolution
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/ABAQUS_INPUT_SUBSET.md`
|
||||
- `/include/fesa/io/abaqus/`
|
||||
- `/include/fesa/model/entity_set.hpp`
|
||||
- `/tests/fixtures/abaqus/`
|
||||
|
||||
## 작업
|
||||
|
||||
Part 및 Assembly scope의 `NSET/ELSET`을 결정적으로 해석한다.
|
||||
|
||||
```cpp
|
||||
struct ResolvedSet final {
|
||||
std::string scope_name;
|
||||
std::string set_name;
|
||||
std::vector<std::int64_t> sorted_unique_labels;
|
||||
};
|
||||
struct SetResolutionResult final {
|
||||
std::vector<ResolvedSet> sets;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
[[nodiscard]] SetResolutionResult resolve_sets(const ParsedDeck&);
|
||||
```
|
||||
|
||||
- explicit member, `GENERATE`, nested reference, forward reference, duplicate member,
|
||||
empty set, cycle, unknown set/entity, invalid range를 실패 테스트로 먼저 작성한다.
|
||||
- Part와 Assembly의 같은 set 이름을 별도 scope로 허용한다.
|
||||
- Assembly `INSTANCE=`는 활성 단일 Instance의 Part-local label만 lift한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "SetResolution|PartSet|AssemblySet" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. scope collision과 cycle 테스트의 실패를 확인한다.
|
||||
2. graph resolution과 canonical sorted-unique 결과를 구현한다.
|
||||
3. source diagnostic과 deterministic order를 assertion한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- Part와 Assembly set namespace를 합치지 마라. 이유: 이름 충돌 의미가 달라진다.
|
||||
- cycle을 recursion overflow로 발견하지 마라. 이유: 명시적 cycle diagnostic이 필요하다.
|
||||
- 여러 Instance key를 지원하지 마라. 이유: Phase 1 단일 Instance 범위다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 2: Single Instance Semantic Validation
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/ABAQUS_INPUT_SUBSET.md`
|
||||
- `/include/fesa/io/abaqus/parser.hpp`
|
||||
- `/include/fesa/io/abaqus/semantic_mapper.hpp`
|
||||
- `/include/fesa/io/abaqus/set_resolver.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
flat/hierarchical organization과 Phase 1 단일 Instance 제한을 semantic validation으로
|
||||
완성한다.
|
||||
|
||||
```cpp
|
||||
struct ActiveInputView final {
|
||||
bool flat;
|
||||
std::string part_name;
|
||||
std::string instance_name;
|
||||
std::span<const DeckRecord> part_records;
|
||||
std::span<const DeckRecord> assembly_records;
|
||||
};
|
||||
[[nodiscard]] ActiveInputResult select_active_input(const ParsedDeck&);
|
||||
```
|
||||
|
||||
- flat input은 Part/Assembly가 없어야 한다.
|
||||
- hierarchical input은 여러 Part를 허용하지만 Assembly와 Instance는 각각 정확히
|
||||
하나여야 한다.
|
||||
- missing Part, transform data, instance-local node/element, mixed organization,
|
||||
wrong `INSTANCE=`를 먼저 실패 테스트로 작성한다.
|
||||
- unreferenced Part가 Domain entity를 만들지 않는지 검증한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "SingleInstance|ActiveInput|SemanticScope" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 각 미지원 organization의 실패 테스트를 확인한다.
|
||||
2. selection/validation만 구현하고 좌표 변환 코드는 만들지 않는다.
|
||||
3. source location과 활성 Part 결과를 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- transformation data를 0으로 간주해 무시하지 마라. 이유: 계약상 명시적 오류다.
|
||||
- unreferenced Part를 Domain에 병합하지 마라. 이유: 사용자 요구와 다르다.
|
||||
- future multi-instance abstraction을 만들지 마라. 이유: 실제 두 번째 구현이 없다.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Step 3: Material, Section, and Shear Defaults
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/ABAQUS_INPUT_SUBSET.md`
|
||||
- `/include/fesa/io/abaqus/semantic_mapper.hpp`
|
||||
- `/include/fesa/model/material.hpp`
|
||||
- `/include/fesa/model/beam_section.hpp`
|
||||
- `/include/fesa/model/domain_builder.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
전역 material과 Part-local Beam section/ELSET assignment를 complete-deck resolution으로
|
||||
semantic model에 연결한다.
|
||||
|
||||
- `*ELASTIC`의 \(E,\nu\)에서 \(G=E/[2(1+\nu)]\)를 계산한다.
|
||||
- general section의 \(A,I_y,I_{yz},I_z,J\), orientation을 읽되 \(I_{yz}=0\)만
|
||||
허용한다.
|
||||
- explicit transverse stiffness를 \(A_{sy},A_{sz}\)로 변환한다.
|
||||
- 생략 시 \(A_{sy}=A_{sz}=5A/6\), `SCF=0`,
|
||||
`ShearPropertySource::phase1_default`를 적용한다.
|
||||
- nonzero `SCF`, missing/duplicate material/section assignment, invalid properties를
|
||||
실패 테스트로 먼저 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "MaterialMapping|BeamSection|ShearDefault" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. material이 Part 뒤에 정의된 forward-resolution 테스트를 먼저 실패시킨다.
|
||||
2. explicit/default shear 두 경로를 최소 구현한다.
|
||||
3. HDF5에 저장할 source enum까지 Domain에 보존되는지 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 임의 단면에 대한 Abaqus 보편 기본값이라고 문서화하지 마라. 이유: FESA Phase 1 가정이다.
|
||||
- nonzero \(I_{yz}\)를 버리지 마라. 이유: 조용한 정식화 변경이다.
|
||||
- orientation을 자동 생성하지 마라. 이유: mandatory 입력 계약이다.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Step 4: Step, BC, Load, and No-op Directives
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/ABAQUS_INPUT_SUBSET.md`
|
||||
- `/include/fesa/io/abaqus/`
|
||||
- `/reference/cantilever beam/cantilever beam.inp`
|
||||
- `/include/fesa/model/step_definition.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
단일 `*STEP/*STATIC`, Assembly set 기반 `*BOUNDARY/*CLOAD`와 명시적 no-op directive
|
||||
처리를 완성한다.
|
||||
|
||||
- `*BOUNDARY`는 DOF 1~6의 0/비영 값을 지원한다.
|
||||
- `*CLOAD`는 force/moment component 1~6을 누적한다.
|
||||
- 중복 동일 BC는 canonicalize하고 충돌 prescribed value는 거부한다.
|
||||
- `*HEADING`, `*PREPRINT`, `*RESTART`, `*OUTPUT`과 소유 data는 명시적으로
|
||||
consume하되 Domain behavior를 만들지 않는다.
|
||||
- 여러 step, `nlgeom` nonzero, unsupported output/keyword option을 실패시킨다.
|
||||
- 제공된 cantilever가 11 nodes, 10 elements, 6 fixed DOFs, node 11의
|
||||
\(F_z=-10000\)으로 정규화되는 통합 테스트를 먼저 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "StepMapping|Boundary|Cload|SuppliedCantilever" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 제공 샘플을 복사/변경하지 않고 public parser로 실패를 확인한다.
|
||||
2. 문서화된 keyword만 구현한다.
|
||||
3. expected Domain과 source diagnostic을 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- no-op 목록을 general ignore로 확장하지 마라. 이유: 모델 정의 손실을 숨긴다.
|
||||
- 여러 step/load history를 추가하지 마라. 이유: Phase 1 범위 밖이다.
|
||||
- reference input을 rewrite하지 마라. 이유: 검증 원본을 보존해야 한다.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "beam-reference-qualification",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "comparison-metric-and-entity-matching",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "reference-csv-adapters",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "cantilever-reference-comparison",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "qualification-report",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# Step 0: Comparison Metric and Entity Matching
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/include/fesa/results/result_database.hpp`
|
||||
- `/include/fesa/model/entity_origin.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
CSV와 독립적인 reference comparison metric, entity position과 report를 구현한다.
|
||||
|
||||
```cpp
|
||||
enum class ReferenceQuantity {
|
||||
displacement,
|
||||
reaction,
|
||||
internal_force,
|
||||
centroid_stress
|
||||
};
|
||||
struct Tolerance final { double relative; double absolute_scale; };
|
||||
struct ResultPosition final {
|
||||
std::string instance_name;
|
||||
std::int64_t entity_label;
|
||||
std::optional<std::int64_t> end_node_label;
|
||||
};
|
||||
struct ComparisonSample final {
|
||||
ReferenceQuantity quantity;
|
||||
ResultPosition position;
|
||||
std::vector<double> reference;
|
||||
std::vector<double> actual;
|
||||
Tolerance tolerance;
|
||||
};
|
||||
struct ComparisonReport final {
|
||||
bool passed;
|
||||
double maximum_normalized_error;
|
||||
std::vector<Diagnostic> failures;
|
||||
};
|
||||
[[nodiscard]] ComparisonReport compare_samples(
|
||||
std::span<const ComparisonSample>);
|
||||
```
|
||||
|
||||
각 scalar는 \(e_n=|a-r|/(a_{scale}+r_{tol}|r|)\)이며 \(e_n\le1\)만 통과한다.
|
||||
nonfinite, duplicate position, component mismatch, unknown origin, invalid element-node
|
||||
pair를 실패 테스트로 먼저 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "ComparisonMetric|EntityMatching" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. near-zero와 큰 값의 실패 테스트를 먼저 실행한다.
|
||||
2. report에 quantity/entity/component/reference/actual/error를 기록한다.
|
||||
3. unit-free metric과 명시 tolerance만 사용한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- NaN 비교를 통과시키지 마라. 이유: 수치 실패를 숨긴다.
|
||||
- 모든 물리량에 하나의 absolute scale을 강제하지 마라. 이유: 규모가 다르다.
|
||||
- CSV parsing을 이 파일에 넣지 마라. 이유: 다음 adapter 경계다.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Step 1: Reference CSV Adapters
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/include/fesa/validation/comparison.hpp`
|
||||
- `/reference/cantilever beam/cantilever beam displacements.csv`
|
||||
- `/reference/cantilever beam/cantilever beam reactions.csv`
|
||||
|
||||
## 작업
|
||||
|
||||
네 물리량의 명시적 CSV schema를 읽어 canonical reference row로 변환한다.
|
||||
|
||||
```cpp
|
||||
struct ReferenceRow final {
|
||||
ReferenceQuantity quantity;
|
||||
ResultPosition position;
|
||||
std::vector<double> values;
|
||||
};
|
||||
struct ReferenceCsvReadResult final {
|
||||
std::vector<ReferenceRow> rows;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
[[nodiscard]] ReferenceCsvReadResult read_reference_csv(
|
||||
ReferenceQuantity,
|
||||
const std::filesystem::path&,
|
||||
std::string_view single_instance_name);
|
||||
```
|
||||
|
||||
- displacement/reaction은 제공된 whitespace 포함 Abaqus header를 읽는다.
|
||||
- internal force schema:
|
||||
`Part Instance Name, Element Label, Node Label, SF-SF1..SF-SF3,
|
||||
SM-SM1..SM-SM3`
|
||||
- stress schema:
|
||||
`Part Instance Name, Element Label, Node Label, Sxx`
|
||||
- 단일 Instance에서는 Instance 열 생략을 허용하고 request 이름으로 보완한다.
|
||||
- `tests/fixtures/reference`에 synthetic internalforce/stress CSV를 먼저 만들고,
|
||||
6개 내력 component와 centroid stress row를 실패 테스트로 고정한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "ReferenceCsv|InternalForceCsv|StressCsv" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. four-schema parser test 실패를 확인한다.
|
||||
2. header/value trim과 선택적 UTF-8 BOM만 허용한다.
|
||||
3. missing column, duplicate row, invalid number를 진단한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- metadata.json을 요구하지 마라. 이유: 승인된 reference 계약과 다르다.
|
||||
- unknown column으로 필수 column 누락을 숨기지 마라. 이유: 잘못된 비교를 만든다.
|
||||
- 내력/응력 파일이 없다는 이유로 adapter 구현을 생략하지 마라. 이유: 필수 루틴이다.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Step 2: Cantilever Reference Comparison
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/reference/cantilever beam/cantilever beam.inp`
|
||||
- `/reference/cantilever beam/cantilever beam displacements.csv`
|
||||
- `/reference/cantilever beam/cantilever beam reactions.csv`
|
||||
- `/include/fesa/analysis/run_solver.hpp`
|
||||
- `/include/fesa/io/hdf5/reader.hpp`
|
||||
- `/include/fesa/validation/reference_csv.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
제공된 계층형 캔틸레버를 production pipeline으로 해석하고 현재 존재하는 변위와
|
||||
반력만 Abaqus 2024 결과와 비교한다.
|
||||
|
||||
- `tests/reference/cantilever_reference_test.cpp`와 reference compare CLI를 먼저
|
||||
작성한다.
|
||||
- comparison request는 Instance `Part-1-1`, relative tolerance `1e-5`,
|
||||
displacement absolute scale `1e-10`, reaction absolute scale `1e-8`을 명시한다.
|
||||
- HDF5 결과와 CSV를 public adapter로 읽어 `(Instance,Node Label)`로 join한다.
|
||||
- 요청하지 않은 internal force/stress 파일을 검색하거나 pass로 보고하지 않는다.
|
||||
- equilibrium과 finite result도 함께 assertion한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R CantileverReference --output-on-failure
|
||||
.\out\build\windows-debug\Debug\fesa.exe solve "reference\cantilever beam\cantilever beam.inp" --output out\cantilever-beam.h5
|
||||
.\out\build\windows-debug\Debug\fesa-reference-compare.exe --results out\cantilever-beam.h5 --instance Part-1-1 --displacements "reference\cantilever beam\cantilever beam displacements.csv" --reactions "reference\cantilever beam\cantilever beam reactions.csv" --relative-tolerance 1e-5 --displacement-absolute-scale 1e-10 --reaction-absolute-scale 1e-8
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. reference test가 실제 오차를 보고하며 실패하는 것을 확인한다.
|
||||
2. discrepancy마다 가장 작은 analytical test를 추가한 뒤 근거 있는 kernel만 수정한다.
|
||||
3. tolerance를 넓혀 결함을 숨기지 않는다.
|
||||
4. 전체 테스트와 최대 정규화 오차를 index summary에 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- reference `.inp` 또는 CSV를 수정하지 마라. 이유: 원본 golden을 보존해야 한다.
|
||||
- 미제공 내력/응력 Abaqus 검증을 통과했다고 주장하지 마라. 이유: 증거가 없다.
|
||||
- test-only parser/solver 경로를 만들지 마라. 이유: production pipeline 검증이다.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Step 3: Qualification Report
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/formulation/timoshenko-beam-3d.md`
|
||||
- `/docs/HDF5_SCHEMA.md`
|
||||
- `/tests/unit/elements/`
|
||||
- `/tests/reference/`
|
||||
- `/tests/fixtures/reference/`
|
||||
|
||||
## 작업
|
||||
|
||||
`docs/VALIDATION.md`에 Phase 1의 실제 검증 증거와 제한을 기록한다.
|
||||
|
||||
- analytical: axial, torsion, bending y/z, biaxial, shear-dominant, rigid body,
|
||||
rotated frame, slenderness sweep
|
||||
- physics: equilibrium, symmetry, reaction, nonzero prescribed DOF
|
||||
- determinism: tested thread counts와 repeated runs
|
||||
- Abaqus: 현재 cantilever displacement/reaction의 tolerance와 maximum error
|
||||
- contract-only: synthetic internal-force/stress CSV schema와 component mapping
|
||||
- 미제공 Abaqus internal-force/stress는 `not yet Abaqus-qualified`라고 명시한다.
|
||||
|
||||
보고서 수치를 새 test output에서 수집하며 수동 추정값을 쓰지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
ctest --preset windows-debug -R "Reference|Beam3D2|Determinism" --output-on-failure
|
||||
```
|
||||
|
||||
모든 실행이 통과하고 보고서의 test 이름, tolerance, 최대오차와 disposition이 실제
|
||||
출력과 일치해야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 전체 suite를 새로 실행한다.
|
||||
2. 결과를 benchmark/quantity별 표에 기록한다.
|
||||
3. synthetic coverage와 Abaqus-backed qualification을 명확히 분리한다.
|
||||
4. index summary에 보고서 경로와 test counts를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 실행하지 않은 결과를 보고서에 쓰지 마라. 이유: 검증 증거가 아니다.
|
||||
- Abaqus 내력/응력 qualification을 추론하지 마라. 이유: CSV가 아직 없다.
|
||||
- 실패 테스트를 제외하거나 disable하지 마라. 이유: release gate를 약화한다.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "deterministic-parallel-assembly",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "canonical-contribution-order",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "tbb-element-evaluation",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "thread-count-determinism",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 0: Canonical Contribution Order
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/assembly/`
|
||||
- `/src/fesa/assembly/`
|
||||
- `/include/fesa/model/entity_origin.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
serial assembly를 변경하지 않고 병렬 계산이 사용할 canonical contribution record와
|
||||
merge contract를 분리한다.
|
||||
|
||||
```cpp
|
||||
struct MatrixContribution final {
|
||||
std::size_t row;
|
||||
std::size_t column;
|
||||
ElementId element;
|
||||
std::uint16_t local_order;
|
||||
double value;
|
||||
};
|
||||
[[nodiscard]] std::vector<MatrixContribution> canonicalize_contributions(
|
||||
std::span<const MatrixContribution>);
|
||||
[[nodiscard]] SymmetricCsr merge_contributions(
|
||||
std::size_t order,
|
||||
std::span<const MatrixContribution> canonical);
|
||||
```
|
||||
|
||||
- 입력 순열, 같은 row/column의 여러 element, cancellation, signed zero를 포함해
|
||||
결과 CSR이 bit-for-bit 같은 테스트를 먼저 작성한다.
|
||||
- 정렬 key는 row, column, stable element identity, local order다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "CanonicalContribution|DeterministicMerge" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. shuffled contribution 테스트의 실패를 확인한다.
|
||||
2. stable total order와 단일 merge 구현만 추가한다.
|
||||
3. serial oracle의 CSR과 bitwise 비교한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- tolerance 기반으로 assembly 값을 같다고 처리하지 마라. 이유: bitwise 재현성 계약이다.
|
||||
- parallel code를 추가하지 마라. 이유: 다음 step의 책임이다.
|
||||
- unordered concurrent accumulation을 준비하지 마라. 이유: 결정성을 깨뜨린다.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Step 1: TBB Element Evaluation
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/cmake/FesaDependencies.cmake`
|
||||
- `/include/fesa/assembly/assembler.hpp`
|
||||
- `/include/fesa/assembly/contribution.hpp`
|
||||
- `/include/fesa/elements/beam/beam3d2.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
oneTBB로 독립적인 요소 계산만 병렬화하고 contribution merge는 canonical serial
|
||||
순서를 사용한다.
|
||||
|
||||
```cpp
|
||||
struct AssemblyOptions final {
|
||||
std::size_t max_threads;
|
||||
std::size_t grain_size;
|
||||
};
|
||||
[[nodiscard]] EquationSystem assemble_parallel(
|
||||
const Domain&,
|
||||
const DofManager&,
|
||||
AssemblyOptions);
|
||||
```
|
||||
|
||||
- fixed Beam chain/branched Domain에서 serial과 parallel의 row offsets, column indices,
|
||||
values, force vector를 bit-for-bit 비교하는 실패 테스트를 먼저 작성한다.
|
||||
- worker는 thread-local contribution을 생성하고 공유 CSR values에 쓰지 않는다.
|
||||
- `max_threads=1`과 2 이상을 명시적으로 제한할 수 있어야 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "ParallelAssembly|TbbElementEvaluation" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. parallel API 부재로 실패하는 테스트를 확인한다.
|
||||
2. element evaluation 범위에만 TBB를 적용한다.
|
||||
3. serial/parallel bitwise 결과와 TSAN 대신 구조적 race 회피 설계를 검토한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 공유 CSR value에 atomic add하지 마라. 이유: 합산 순서가 비결정적이다.
|
||||
- PARDISO 호출을 TBB task 안에 넣지 마라. 이유: oversubscription 위험이 있다.
|
||||
- 성능을 위해 tolerance를 완화하지 마라. 이유: 검증 결정성이 우선이다.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Step 2: Thread Count Determinism
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/assembly/assembler.hpp`
|
||||
- `/tests/unit/assembly/`
|
||||
- `/tests/integration/assembly/`
|
||||
|
||||
## 작업
|
||||
|
||||
thread count와 반복 실행이 assembly 및 최종 선형 정적 결과를 바꾸지 않는 통합
|
||||
검증과 측정용 benchmark를 추가한다.
|
||||
|
||||
- `tests/integration/assembly/thread_count_determinism_test.cpp`
|
||||
- `tests/performance/assembly_benchmark.cpp`
|
||||
- thread counts 1, 2, available concurrency에서 CSR, RHS, displacement, reaction을
|
||||
bit-for-bit 비교한다.
|
||||
- 최소 10회 반복으로 scheduling 변화 회귀를 확인한다.
|
||||
- benchmark는 serial/parallel 시간과 element count를 출력하되 speedup을 assertion하지
|
||||
않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R ThreadCountDeterminism --output-on-failure
|
||||
.\out\build\windows-debug\Debug\fesa_assembly_benchmark.exe
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 다양한 thread count 통합 테스트를 먼저 실행한다.
|
||||
2. 차이가 있으면 canonical key/merge 원인을 고치고 tolerance 비교로 대체하지 않는다.
|
||||
3. benchmark output을 기록하고 전체 테스트를 실행한다.
|
||||
4. index summary에 tested thread counts를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- benchmark에서 속도 향상을 pass 조건으로 만들지 마라. 이유: 환경 의존적이다.
|
||||
- MKL thread 수를 assembly test와 중첩해 키우지 마라. 이유: 측정이 오염된다.
|
||||
- release 성능 목표를 임의로 만들지 마라. 이유: 문서화된 측정만 요구된다.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "domain-and-input-skeleton",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "semantic-domain-and-origin-types",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "domain-validation",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "abaqus-scoped-syntax-parser",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "active-instance-domain-normalization",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# Step 0: Semantic Domain and Origin Types
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/core/entity_id.hpp`
|
||||
- `/include/fesa/core/vec3.hpp`
|
||||
- `/include/fesa/core/diagnostic.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
정규화된 solver semantic model의 값 타입과 불변 조회 계약을 만든다.
|
||||
|
||||
- `include/fesa/model/` 아래 `ids.hpp`, `entity_origin.hpp`, `node.hpp`,
|
||||
`material.hpp`, `beam_section.hpp`, `beam_element.hpp`, `entity_set.hpp`,
|
||||
`step_definition.hpp`, `domain.hpp`를 만든다.
|
||||
- 핵심 타입:
|
||||
|
||||
```cpp
|
||||
struct EntityOrigin final {
|
||||
std::string part_name;
|
||||
std::string instance_name;
|
||||
std::int64_t local_label;
|
||||
};
|
||||
struct Node final { NodeId id; EntityOrigin origin; Vec3 position; };
|
||||
struct BeamElement final {
|
||||
ElementId id;
|
||||
EntityOrigin origin;
|
||||
std::array<NodeId, 2> nodes;
|
||||
MaterialId material;
|
||||
SectionId section;
|
||||
};
|
||||
```
|
||||
|
||||
- `BeamSection`은 \(A,I_y,I_z,J,A_{sy},A_{sz}\), orientation과 recovery point를
|
||||
가진다. 전단값 출처는 `enum class ShearPropertySource { input, phase1_default };`
|
||||
로 표현한다.
|
||||
- flat mesh는 빈 `part_name/instance_name`, 계층형 mesh는 실제 이름을 사용한다.
|
||||
- 먼저 값 보존과 origin 조회가 실패하는 테스트를 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "ModelTypes|EntityOrigin" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 테스트를 먼저 작성하고 compile failure를 확인한다.
|
||||
2. 저장과 읽기에 필요한 최소 API만 구현한다.
|
||||
3. `model` public header에 Abaqus/MKL/TBB/HDF5 타입이 없는지 확인한다.
|
||||
4. focused 및 전체 테스트를 실행하고 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- parser record를 `Domain`에 저장하지 마라. 이유: syntax/semantic 경계를 깨뜨린다.
|
||||
- 여러 Instance container를 만들지 마라. 이유: Phase 1은 단일 Instance다.
|
||||
- equation 번호를 Node/Element에 저장하지 마라. 이유: DofManager 책임이다.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Step 1: Domain Validation
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/model/`
|
||||
- `/tests/unit/model/`
|
||||
|
||||
이전 step의 타입 이름과 필드를 변경하지 말고 builder validation을 추가하라.
|
||||
|
||||
## 작업
|
||||
|
||||
`DomainBuilder`가 모든 semantic entity를 검증한 뒤 불변 `Domain` 하나를 생성하게
|
||||
한다.
|
||||
|
||||
```cpp
|
||||
struct DomainBuildResult final {
|
||||
std::optional<Domain> domain;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
|
||||
class DomainBuilder final {
|
||||
public:
|
||||
void add_node(Node);
|
||||
void add_material(IsotropicElastic);
|
||||
void add_section(BeamSection);
|
||||
void add_beam_element(BeamElement);
|
||||
void add_node_set(NodeSet);
|
||||
void add_element_set(ElementSet);
|
||||
void set_step(StepDefinition);
|
||||
[[nodiscard]] DomainBuildResult build() &&;
|
||||
};
|
||||
```
|
||||
|
||||
- 중복 internal ID, 중복 origin, missing reference, invalid \(E,\nu,A,I,J,A_s\),
|
||||
nonfinite 값, zero-length element, invalid orientation, section/material 누락,
|
||||
충돌 BC를 각각 실패 테스트로 먼저 작성한다.
|
||||
- 내부 dense lookup과 origin lookup을 만들되 public mutable access는 제공하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "DomainBuilder|DomainValidation" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 각 거부 조건의 실패 테스트를 먼저 확인한다.
|
||||
2. 하나의 오류가 다른 오류를 숨기지 않도록 가능한 진단을 수집한다.
|
||||
3. valid Domain test와 전체 CTest를 실행한다.
|
||||
4. index summary에 검증 규칙과 생성 파일을 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 잘못된 입력값을 자동 보정하지 마라. 이유: explicit diagnostic 계약을 위반한다.
|
||||
- solver 또는 parser validation을 이 builder에 넣지 마라. 이유: 모듈 책임이 다르다.
|
||||
- mutable Domain accessor를 추가하지 마라. 이유: 해석 중 모델 불변성을 깨뜨린다.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Step 2: Abaqus Scoped Syntax Parser
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/core/source_location.hpp`
|
||||
- `/include/fesa/core/diagnostic.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
Abaqus keyword를 해석하지 않고 scope가 보존된 syntax tree로 읽는 parser를 만든다.
|
||||
|
||||
```cpp
|
||||
struct DeckRecord final {
|
||||
std::string keyword;
|
||||
std::map<std::string, std::string, std::less<>> parameters;
|
||||
std::vector<std::vector<std::string>> data;
|
||||
SourceLocation source;
|
||||
};
|
||||
struct ParsedPart final {
|
||||
std::string name;
|
||||
std::vector<DeckRecord> records;
|
||||
SourceLocation source;
|
||||
};
|
||||
struct ParsedInstance final {
|
||||
std::string name;
|
||||
std::string part_name;
|
||||
std::vector<std::vector<std::string>> transform_data;
|
||||
SourceLocation source;
|
||||
};
|
||||
struct ParsedAssembly final {
|
||||
std::string name;
|
||||
std::vector<ParsedInstance> instances;
|
||||
std::vector<DeckRecord> records;
|
||||
SourceLocation source;
|
||||
};
|
||||
struct ParsedDeck final {
|
||||
std::vector<DeckRecord> global_records;
|
||||
std::vector<ParsedPart> parts;
|
||||
std::optional<ParsedAssembly> assembly;
|
||||
};
|
||||
[[nodiscard]] ParseDeckResult parse_deck(const std::filesystem::path&);
|
||||
```
|
||||
|
||||
- flat fixture와 단일 Part/Assembly/Instance fixture를 먼저 만든다.
|
||||
- case-insensitive keyword, comment, blank line, comma field, UTF-8, source line,
|
||||
scope 종료 오류를 테스트한다.
|
||||
- 이 step은 syntax만 파싱하며 active Part를 선택하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "AbaqusParser|ScopedDeck" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. parser test를 작성하고 실패를 확인한다.
|
||||
2. `io/abaqus`에 lexer/parser만 최소 구현한다.
|
||||
3. source location과 scope tree를 assertion한다.
|
||||
4. 전체 테스트 후 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- Domain을 생성하지 마라. 이유: 다음 semantic normalization step의 책임이다.
|
||||
- unknown keyword를 일반적으로 무시하지 마라. 이유: 명시적 입력 계약을 훼손한다.
|
||||
- Instance 변환을 적용하지 마라. 이유: Phase 1에서 거부할 syntax 정보로 보존한다.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Step 3: Active Instance Domain Normalization
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/specs/2026-07-29-abaqus-assembly-reference-design.md`
|
||||
- `/include/fesa/model/domain_builder.hpp`
|
||||
- `/include/fesa/io/abaqus/deck_record.hpp`
|
||||
- `/include/fesa/io/abaqus/parser.hpp`
|
||||
- `/tests/fixtures/abaqus/minimal_cantilever.inp`
|
||||
- `/tests/fixtures/abaqus/minimal_part_instance_cantilever.inp`
|
||||
|
||||
## 작업
|
||||
|
||||
flat 또는 단일 무변환 Instance 입력을 동일한 `Domain`으로 변환한다.
|
||||
|
||||
```cpp
|
||||
[[nodiscard]] DomainBuildResult map_deck_to_domain(const ParsedDeck& deck);
|
||||
```
|
||||
|
||||
- 먼저 두 fixture가 동등한 활성 절점·요소·재료·단면·하중·BC를 만드는 통합
|
||||
테스트를 작성한다.
|
||||
- 계층형 deck은 정확히 하나의 Assembly와 Instance를 요구한다.
|
||||
- transform data가 있거나 Part reference가 없으면 source diagnostic을 반환한다.
|
||||
- Instance가 참조하지 않는 Part는 Domain에 포함하지 않는다.
|
||||
- origin에는 실제 Part/Instance/local label을 보존한다.
|
||||
- 전단강성이 없으면 \(A_{sy}=A_{sz}=5A/6\), `SCF=0`,
|
||||
`ShearPropertySource::phase1_default`를 사용한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "DeckToDomain|ActiveInstance" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. public parser와 mapper를 사용하는 실패 테스트를 확인한다.
|
||||
2. syntax record를 복제해 Domain에 저장하지 않고 semantic 값으로 변환한다.
|
||||
3. unreferenced Part exclusion과 provenance를 assertion한다.
|
||||
4. focused/full test 후 index summary를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 여러 Instance를 평탄화하지 마라. 이유: Phase 1 범위 밖이다.
|
||||
- 변환 좌표를 조용히 무시하지 마라. 이유: 잘못된 해석 모델을 만든다.
|
||||
- 테스트에서 Domain을 직접 구성하지 마라. 이유: production 경로를 우회한다.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "equation-and-linear-solve",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "symmetric-csr-assembly",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "essential-bc-elimination",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "pardiso-linear-solver",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
# Step 0: Symmetric CSR Assembly
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/model/domain.hpp`
|
||||
- `/include/fesa/fem/dof_manager.hpp`
|
||||
- `/include/fesa/elements/beam/beam3d2.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
Beam local contribution으로부터 deterministic serial symmetric CSR과 full load vector를
|
||||
조립한다.
|
||||
|
||||
```cpp
|
||||
struct SymmetricCsr final {
|
||||
std::size_t order;
|
||||
std::vector<std::int32_t> row_offsets;
|
||||
std::vector<std::int32_t> column_indices;
|
||||
std::vector<double> values;
|
||||
};
|
||||
struct EquationSystem final {
|
||||
SymmetricCsr stiffness;
|
||||
std::vector<double> force;
|
||||
};
|
||||
[[nodiscard]] EquationSystem assemble_serial(
|
||||
const Domain&,
|
||||
const DofManager&);
|
||||
```
|
||||
|
||||
- sparsity pattern builder와 numeric contribution merge를 분리한다.
|
||||
- `(row,column,element-origin,local-order)`의 안정된 순서로 합산한다.
|
||||
- hand-calculated 2-element system, duplicate contribution, external ID 순서 변화,
|
||||
CSR invariant를 실패 테스트로 먼저 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "SparsePattern|SerialAssembly|SymmetricCsr" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. expected CSR 구조와 값을 고정한 실패 테스트를 실행한다.
|
||||
2. pattern과 numeric assembly를 최소 구현한다.
|
||||
3. row offset, sorted column, upper/lower storage 계약을 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 공유 CSR에 병렬 누적하지 마라. 이유: 이 phase는 serial oracle을 만든다.
|
||||
- PARDISO를 호출하지 마라. 이유: backend step의 책임이다.
|
||||
- element formulation을 assembly에 복제하지 마라. 이유: 모듈 경계를 깨뜨린다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 1: Essential BC Elimination
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/assembly/symmetric_csr.hpp`
|
||||
- `/include/fesa/assembly/equation_system.hpp`
|
||||
- `/include/fesa/fem/dof_manager.hpp`
|
||||
- `/include/fesa/model/step_definition.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
0과 비영 지정변위를 지원하는 essential-BC elimination과 full-vector 복원을 구현한다.
|
||||
|
||||
```cpp
|
||||
struct ReducedSystem final {
|
||||
SymmetricCsr stiffness;
|
||||
std::vector<double> force;
|
||||
std::vector<std::size_t> free_to_full;
|
||||
std::vector<double> prescribed_full;
|
||||
};
|
||||
[[nodiscard]] ConstraintResult eliminate_essential_bcs(
|
||||
const EquationSystem& original,
|
||||
const DofManager& dofs,
|
||||
std::span<const PrescribedDof> prescribed);
|
||||
[[nodiscard]] std::vector<double> recover_reaction(
|
||||
const EquationSystem& original,
|
||||
std::span<const double> full_displacement);
|
||||
```
|
||||
|
||||
- 작은 hand calculation으로 RHS shift, 0/비영 prescribed value, all constrained,
|
||||
충돌 조건, \(r=Ku-f\) 반력 복원을 먼저 테스트한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "EssentialBc|ConstraintElimination|Reaction" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 비영 지정값 테스트의 실패를 먼저 확인한다.
|
||||
2. 원래 EquationSystem을 보존한 채 reduced system을 생성한다.
|
||||
3. 복원 변위와 원래 평형식 반력을 assertion한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- penalty나 큰 수를 사용하지 마라. 이유: 승인된 elimination 정책과 다르다.
|
||||
- 반력을 reduced matrix에서 계산하지 마라. 이유: 원래 \(K,u,f\)가 필요하다.
|
||||
- MPC/Lagrange multiplier를 추가하지 마라. 이유: 범위 밖이다.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Step 2: PARDISO Linear Solver
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/cmake/FesaDependencies.cmake`
|
||||
- `/include/fesa/assembly/symmetric_csr.hpp`
|
||||
- `/include/fesa/core/diagnostic.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
MKL PARDISO를 RAII adapter 뒤에 격리하고 symmetric positive-definite reduced system을
|
||||
푼다.
|
||||
|
||||
```cpp
|
||||
struct LinearSolveResult final {
|
||||
std::vector<double> solution;
|
||||
double relative_residual;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
class LinearSolver {
|
||||
public:
|
||||
virtual ~LinearSolver() = default;
|
||||
[[nodiscard]] virtual LinearSolveResult solve(
|
||||
const SymmetricCsr&,
|
||||
std::span<const double> rhs) = 0;
|
||||
};
|
||||
class PardisoLinearSolver final : public LinearSolver {
|
||||
public:
|
||||
PardisoLinearSolver();
|
||||
~PardisoLinearSolver() override;
|
||||
[[nodiscard]] LinearSolveResult solve(
|
||||
const SymmetricCsr&,
|
||||
std::span<const double>) override;
|
||||
};
|
||||
```
|
||||
|
||||
- 3x3 SPD, repeated solve, invalid CSR, dimension mismatch, singular matrix를 먼저
|
||||
테스트한다.
|
||||
- `mtype=2`, LP64 index, `iparm[34]=1`, matrix checker, analysis/factor/solve/release
|
||||
phase를 사용한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "Pardiso|LinearSolver" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. adapter test의 link/behavior 실패를 확인한다.
|
||||
2. 모든 MKL handle/workspace를 RAII로 해제한다.
|
||||
3. 해와 상대잔차를 독립 계산으로 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- MKL 타입을 `LinearSolver` public contract에 노출하지 마라. 이유: backend 격리다.
|
||||
- singular system을 임의 regularization하지 마라. 이유: 모델 오류를 숨긴다.
|
||||
- PARDISO 실행 중 TBB task를 중첩하지 마라. 이유: oversubscription 정책 위반이다.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "fem-and-beam-kernel",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "quadrature-and-shape-functions",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "dof-manager",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "beam-local-frame",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "timoshenko-stiffness-kernel",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Step 0: Quadrature and Shape Functions
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/core/vec3.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
특정 analysis에 종속되지 않는 1D Gauss quadrature와 2절점 선형 shape function을
|
||||
`fem` 모듈에 구현한다.
|
||||
|
||||
```cpp
|
||||
struct GaussPoint1D final { double xi; double weight; };
|
||||
[[nodiscard]] std::span<const GaussPoint1D> gauss_rule_1d(int order);
|
||||
[[nodiscard]] std::array<double, 2> line2_shape(double xi);
|
||||
[[nodiscard]] std::array<double, 2> line2_shape_derivative(double xi);
|
||||
[[nodiscard]] double line2_jacobian(double length);
|
||||
```
|
||||
|
||||
- partition of unity, endpoint interpolation, derivative sum zero, 1점/2점 적분의
|
||||
정확도, length/2 Jacobian, invalid order/length를 실패 테스트로 먼저 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "Quadrature|ShapeFunction|Jacobian" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 수학 invariant 테스트의 실패를 확인한다.
|
||||
2. 고정 크기 값 타입과 최소 함수만 구현한다.
|
||||
3. tolerance 근거를 테스트 이름 또는 주석에 명시한다.
|
||||
4. 전체 CTest와 index 갱신을 수행한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- Beam stiffness를 이 step에 구현하지 마라. 이유: 수학 primitive 경계를 유지한다.
|
||||
- runtime quadrature registry를 만들지 마라. 이유: 1점과 2점만 필요하다.
|
||||
- 잘못된 길이에 임의 epsilon을 더하지 마라. 이유: model 오류를 숨긴다.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Step 1: DOF Manager
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/model/domain.hpp`
|
||||
- `/include/fesa/model/step_definition.hpp`
|
||||
- `/include/fesa/fem/`
|
||||
|
||||
## 작업
|
||||
|
||||
절점당 6자유도와 constrained/free equation numbering을 전담하는 `DofManager`를
|
||||
구현한다.
|
||||
|
||||
```cpp
|
||||
enum class NodeDof : std::uint8_t { ux, uy, uz, rx, ry, rz };
|
||||
struct DofAddress final { NodeId node; NodeDof dof; };
|
||||
class DofManager final {
|
||||
public:
|
||||
[[nodiscard]] static DofManager build(const Domain&);
|
||||
[[nodiscard]] std::size_t full_dof_count() const noexcept;
|
||||
[[nodiscard]] std::size_t free_equation_count() const noexcept;
|
||||
[[nodiscard]] std::optional<std::size_t> equation(DofAddress) const;
|
||||
[[nodiscard]] std::array<std::size_t, 12> element_full_dofs(
|
||||
const BeamElement&) const;
|
||||
[[nodiscard]] std::vector<double> reconstruct_full(
|
||||
std::span<const double> reduced) const;
|
||||
};
|
||||
```
|
||||
|
||||
- external label 순서와 무관한 deterministic numbering, 비영 지정값, full/reduced
|
||||
reconstruction, invalid DOF를 실패 테스트로 먼저 고정한다.
|
||||
- equation ID를 Node/Element에 쓰지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "DofManager|EquationNumbering" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 실패 테스트를 먼저 실행한다.
|
||||
2. Domain 읽기 전용 view만 사용해 numbering을 구현한다.
|
||||
3. constrained/free mapping과 reconstruction을 직접 assertion한다.
|
||||
4. 전체 테스트와 index 갱신을 수행한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- sparse matrix pattern을 소유하지 마라. 이유: assembly 책임이다.
|
||||
- Node/Element에 equation ID를 저장하지 마라. 이유: 아키텍처 규칙 위반이다.
|
||||
- MPC나 penalty 자유도를 추가하지 마라. 이유: Phase 1 범위 밖이다.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Step 2: Beam Local Frame
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/core/vec3.hpp`
|
||||
- `/include/fesa/model/beam_section.hpp`
|
||||
- `/include/fesa/model/beam_element.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
두 절점과 mandatory orientation vector로 오른손 직교 Beam 국부 기저와 12x12
|
||||
좌표변환을 계산한다.
|
||||
|
||||
```cpp
|
||||
struct BeamFrame final { Vec3 ex; Vec3 ey; Vec3 ez; };
|
||||
struct BeamFrameResult final {
|
||||
std::optional<BeamFrame> frame;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
[[nodiscard]] BeamFrameResult make_beam_frame(
|
||||
const Vec3& first,
|
||||
const Vec3& second,
|
||||
const Vec3& orientation);
|
||||
[[nodiscard]] Matrix12 beam_transformation(const BeamFrame&);
|
||||
```
|
||||
|
||||
- 축 방향 정규화, Gram-Schmidt, 오른손성, 직교성, 회전 불변성을 테스트한다.
|
||||
- zero length, zero orientation, orientation parallel to element axis를 실패시킨다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "BeamFrame|BeamTransformation" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 축 정렬 및 임의 회전 테스트의 실패를 확인한다.
|
||||
2. tolerance를 scale-aware하게 적용한다.
|
||||
3. \(R R^T=I\), determinant \(+1\), 변환 energy invariant를 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- orientation을 자동 추측하지 마라. 이유: 입력 계약에서 필수다.
|
||||
- degenerate vector를 임의 축으로 대체하지 마라. 이유: 모델 오류를 숨긴다.
|
||||
- element stiffness를 추가하지 마라. 이유: 다음 kernel step의 책임이다.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Step 3: Timoshenko Stiffness Kernel
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/include/fesa/fem/`
|
||||
- `/include/fesa/model/material.hpp`
|
||||
- `/include/fesa/model/beam_section.hpp`
|
||||
- `/docs/formulation/timoshenko-beam-3d.md`가 있으면 전체
|
||||
|
||||
## 작업
|
||||
|
||||
먼저 `docs/formulation/timoshenko-beam-3d.md`에 자유도 순서, 변형률, 부호,
|
||||
constitutive matrix, Jacobian과 선택적 감차적분 식을 작성한다. 그 식으로 실제
|
||||
2절점 3D isoparametric Timoshenko Beam stiffness를 구현한다.
|
||||
|
||||
```cpp
|
||||
struct Beam3D2Input final {
|
||||
std::array<Vec3, 2> coordinates;
|
||||
IsotropicElastic material;
|
||||
BeamSection section;
|
||||
};
|
||||
struct Beam3D2Contribution final {
|
||||
Matrix12 local_stiffness;
|
||||
Matrix12 global_stiffness;
|
||||
BeamFrame frame;
|
||||
};
|
||||
[[nodiscard]] BeamKernelResult compute_beam3d2(const Beam3D2Input&);
|
||||
```
|
||||
|
||||
- 축·굽힘·비틀림은 2점, 전단은 1점 Gauss 적분한다.
|
||||
- \(G=E/[2(1+\nu)]\)를 사용한다.
|
||||
- 먼저 대칭성, 강체운동 zero energy, 축/비틀림/굽힘 해석해, shear-dominant,
|
||||
세장비 sweep과 좌표회전 invariant 테스트를 실패시킨다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "Beam3D2|Timoshenko|RigidBody" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 정식화 문서를 production code보다 먼저 확정한다.
|
||||
2. 실패 테스트를 실행해 가짜 matrix로 통과하지 않음을 확인한다.
|
||||
3. 최소 kernel을 구현하고 focused/full test를 실행한다.
|
||||
4. 식과 코드의 DOF/component 순서를 대조하고 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 닫힌형 가짜 stiffness를 임시로 넣지 마라. 이유: 파이프라인 수치 신뢰성을 훼손한다.
|
||||
- shear term을 2점 적분하지 마라. 이유: 승인된 selective integration과 다르다.
|
||||
- 비선형, 워핑, offset 또는 \(I_{yz}\)를 추가하지 마라. 이유: Phase 1 밖이다.
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"phases": [
|
||||
{
|
||||
"dir": "solver-bootstrap",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "domain-and-input-skeleton",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "fem-and-beam-kernel",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "equation-and-linear-solve",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "results-and-pipeline",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "abaqus-subset-completion",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "deterministic-parallel-assembly",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "result-contract-completion",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "beam-reference-qualification",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"dir": "internal-release",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "internal-release",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "release-checklist",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "cmake-install-package",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "install-tree-smoke-test",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "phase1-scale-benchmark",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 4,
|
||||
"name": "release-evidence-gate",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# Step 0: Release Checklist
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/VALIDATION.md`
|
||||
- `/docs/HDF5_SCHEMA.md`
|
||||
- `/docs/ABAQUS_INPUT_SUBSET.md`
|
||||
- `/CMakePresets.json`
|
||||
|
||||
## 작업
|
||||
|
||||
packaging 전에 `docs/BUILDING.md`, `docs/INPUT_FORMAT.md`,
|
||||
`docs/RELEASE_CHECKLIST.md`를 작성한다.
|
||||
|
||||
체크리스트는 다음 증거 위치와 command를 포함해야 한다.
|
||||
|
||||
- MSVC v143 x64, C++20 및 dependency versions
|
||||
- Debug/Release configure, build, zero-warning, nonzero CTest count
|
||||
- flat 및 단일 무변환 Instance example
|
||||
- HDF5 schema inspection
|
||||
- 현재 Abaqus displacement/reaction comparison
|
||||
- synthetic internal-force/stress adapter coverage
|
||||
- deterministic thread-count test
|
||||
- 100k-DOF scale measurement
|
||||
- runtime DLL inventory와 clean install-tree smoke test
|
||||
|
||||
PRD section 8 각 항목에 고유 checklist ID를 부여한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
문서의 모든 command가 현재 target/preset 이름과 일치하고 미제공 Abaqus
|
||||
내력·응력을 qualification 완료로 표시하지 않아야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. PRD release criterion을 하나씩 checklist에 매핑한다.
|
||||
2. 현재 test/target 이름을 CMake에서 재확인한다.
|
||||
3. 증거가 없는 항목은 pass로 쓰지 않고 미실행 상태로 둔다.
|
||||
4. index summary에 세 문서와 checklist ID 범위를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- installer나 외부 고객 SDK를 약속하지 마라. 이유: 내부 배포 범위다.
|
||||
- evidence 없는 checkbox를 완료 표시하지 마라. 이유: release gate를 왜곡한다.
|
||||
- per-model metadata 파일을 다시 요구하지 마라. 이유: 승인된 검증 계약과 다르다.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Step 1: CMake Install Package
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/BUILDING.md`
|
||||
- `/docs/RELEASE_CHECKLIST.md`
|
||||
- `/CMakeLists.txt`
|
||||
- `/CMakePresets.json`
|
||||
|
||||
## 작업
|
||||
|
||||
`cmake --install`로 내부 배포용 install tree를 만든다.
|
||||
|
||||
- `cmake/install.cmake`, `cmake/FESAConfig.cmake.in`을 추가한다.
|
||||
- install tree에 `fesa.exe`, `fesa_core` static library, public headers,
|
||||
CMake package config, required runtime DLL inventory, example input,
|
||||
`HDF5_SCHEMA.md`, `INPUT_FORMAT.md`, `VALIDATION.md`를 포함한다.
|
||||
- absolute build path가 install config에 남지 않는 실패 검사부터 작성한다.
|
||||
- Phase 1 public ABI compatibility를 약속하지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --preset windows-release
|
||||
cmake --build --preset windows-release
|
||||
ctest --preset windows-release --output-on-failure
|
||||
cmake --install out\build\windows-release --config Release --prefix out\package\fesa
|
||||
Get-ChildItem -Recurse out\package\fesa
|
||||
```
|
||||
|
||||
install tree가 build source tree 밖에서 사용 가능한 상대 경로와 명시적 runtime inventory를
|
||||
가져야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. install manifest 검사 실패를 먼저 확인한다.
|
||||
2. 최소 install/export rule을 구현한다.
|
||||
3. package tree와 CMake config의 절대 경로 누출을 확인한다.
|
||||
4. index summary에 install manifest를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- registry write나 MSI installer를 추가하지 마라. 이유: 배포 범위 밖이다.
|
||||
- dependency를 package 중 다운로드하지 마라. 이유: 사전 설치 정책 위반이다.
|
||||
- Debug/Release binary를 혼합하지 마라. 이유: runtime 불일치 위험이 있다.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Step 2: Install-tree Smoke Test
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/BUILDING.md`
|
||||
- `/docs/RELEASE_CHECKLIST.md`
|
||||
- `/cmake/FESAConfig.cmake.in`
|
||||
- `/cmake/install.cmake`
|
||||
|
||||
## 작업
|
||||
|
||||
source/build tree를 참조하지 않는 clean install consumer와 CLI smoke test를 만든다.
|
||||
|
||||
- `tests/install/consumer/CMakeLists.txt`, `tests/install/consumer/main.cpp`,
|
||||
`tests/install/install_tree_smoke.cmake`를 만든다.
|
||||
- installed `FESAConfig.cmake`로 작은 consumer를 configure/link한다.
|
||||
- installed CLI의 `--version`, example solve, 생성 HDF5 public inspection을 실행한다.
|
||||
- source include path나 build library path를 숨긴 상태에서 먼저 실패를 확인한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --preset windows-release
|
||||
cmake --build --preset windows-release
|
||||
ctest --preset windows-release -R InstallTreeSmoke --output-on-failure
|
||||
ctest --preset windows-release --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 설치 전 smoke test 실패를 확인한다.
|
||||
2. install tree만 사용하도록 test working directory와 environment를 격리한다.
|
||||
3. consumer link, CLI solve, HDF5 open을 모두 확인한다.
|
||||
4. 전체 Release test와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- source directory include를 fallback으로 넣지 마라. 이유: packaging 결함을 숨긴다.
|
||||
- PATH의 개발용 `fesa.exe`를 실행하지 마라. 이유: installed binary 검증이 아니다.
|
||||
- external dependency installer를 만들지 마라. 이유: inventory만 제공한다.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Step 3: Phase 1 Scale Benchmark
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/RELEASE_CHECKLIST.md`
|
||||
- `/include/fesa/analysis/run_solver.hpp`
|
||||
- `/tests/performance/assembly_benchmark.cpp`
|
||||
|
||||
## 작업
|
||||
|
||||
약 100,000 DOF의 deterministic Beam chain 모델로 메모리와 시간을 측정하는
|
||||
`tests/performance/phase1_scale_benchmark.cpp`를 만든다.
|
||||
|
||||
- model generation, parsing/Domain build, assembly, PARDISO solve, recovery, HDF5 write
|
||||
시간을 구분해 출력한다.
|
||||
- peak working set 또는 Windows에서 재현 가능한 memory metric을 기록한다.
|
||||
- benchmark는 finite result, equilibrium, expected DOF count와 정상 종료만 assertion한다.
|
||||
- 임의 성능 기준이나 speedup을 pass 조건으로 만들지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-release
|
||||
.\out\build\windows-release\Release\fesa_phase1_scale_benchmark.exe
|
||||
ctest --preset windows-release --output-on-failure
|
||||
```
|
||||
|
||||
출력에 모델 크기, 각 stage 시간, memory metric, thread 설정, solver 설정이 포함되어야
|
||||
한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 작은 model에서 benchmark correctness test를 먼저 실패시킨다.
|
||||
2. 동일 generator로 목표 크기를 실행한다.
|
||||
3. 측정값과 환경을 release checklist에 기록한다.
|
||||
4. index summary에 결과 위치와 실제 DOF count를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- benchmark를 unit test timeout에 묶지 마라. 이유: 머신 성능에 따라 달라진다.
|
||||
- 결과 정확성 검사를 생략하지 마라. 이유: 빠른 오답은 성능 증거가 아니다.
|
||||
- 실제 측정 없이 목표 시간을 만들지 마라. 이유: 요구사항에 근거가 없다.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Step 4: Release Evidence Gate
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/VALIDATION.md`
|
||||
- `/docs/BUILDING.md`
|
||||
- `/docs/INPUT_FORMAT.md`
|
||||
- `/docs/RELEASE_CHECKLIST.md`
|
||||
- `/docs/HDF5_SCHEMA.md`
|
||||
|
||||
## 작업
|
||||
|
||||
새 실행 증거로 PRD section 8의 내부 배포 수용 조건을 모두 판정한다.
|
||||
|
||||
- Debug와 Release configure/build/test를 각각 실행한다.
|
||||
- test count가 0이 아닌지 확인한다.
|
||||
- Harness Python self-test를 실행한다.
|
||||
- reference, determinism, install-tree, HDF5 inspection, scale benchmark 결과를
|
||||
checklist ID에 연결한다.
|
||||
- 현재 검증 범위가 Abaqus displacement/reaction이며 내력/응력은 synthetic adapter
|
||||
coverage임을 release note에 명시한다.
|
||||
- 하나라도 증거가 없거나 실패하면 release를 완료 처리하지 말고 `blocked` 또는
|
||||
`error`로 기록한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
uv run --with pytest python -m pytest -v -rs
|
||||
cmake --preset windows-debug
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
cmake --preset windows-release
|
||||
cmake --build --preset windows-release
|
||||
ctest --preset windows-release --output-on-failure
|
||||
.\out\build\windows-release\Release\fesa_phase1_scale_benchmark.exe
|
||||
cmake --install out\build\windows-release --config Release --prefix out\package\fesa
|
||||
```
|
||||
|
||||
모든 명령이 종료 코드 0이고 release checklist의 각 criterion이 해당 출력 또는
|
||||
validation report 항목으로 추적되어야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 위 명령을 생략 없이 새로 실행한다.
|
||||
2. warning, test count, reference maximum error, benchmark와 install manifest를 기록한다.
|
||||
3. 성공한 경우에만 step/phase를 `completed`로 갱신한다.
|
||||
4. 미제공 외부 데이터가 필요하면 범위를 확대하지 말고 정확한 blocker를 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 실패 테스트를 disable하거나 제외하지 마라. 이유: release 증거를 조작한다.
|
||||
- 구현되지 않은 Abaqus 내력/응력 qualification을 선언하지 마라. 이유: golden이 없다.
|
||||
- 자동 push하지 마라. 이유: 사용자가 `--push`를 명시한 경우에만 허용된다.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "result-contract-completion",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "beam-element-end-recovery",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "complete-result-contract",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "self-contained-hdf5",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 0: Beam Element-end Recovery
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/formulation/timoshenko-beam-3d.md`
|
||||
- `/include/fesa/elements/beam/beam3d2.hpp`
|
||||
- `/include/fesa/model/beam_section.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
요소 양 끝 절점에서 section strain/resultant, 도심 응력과 선택 회복점 축응력을
|
||||
계산한다.
|
||||
|
||||
```cpp
|
||||
struct BeamSectionResult final {
|
||||
double xi;
|
||||
NodeId end_node;
|
||||
std::array<double, 6> section_strain;
|
||||
std::array<double, 6> section_force;
|
||||
double centroid_sigma_xx;
|
||||
std::vector<double> sigma_xx;
|
||||
};
|
||||
[[nodiscard]] std::vector<BeamSectionResult> recover_beam3d2(
|
||||
const Beam3D2Input&,
|
||||
std::span<const double, 12> element_displacement,
|
||||
std::span<const std::array<double, 2>> recovery_points);
|
||||
```
|
||||
|
||||
- component 순서는 \(N,V_y,V_z,T,M_y,M_z\)다.
|
||||
- `centroid_sigma_xx=N/A`; 회복점은 axial+bending \(\sigma_{xx}\)만 계산한다.
|
||||
- 순수 축/비틀림/각 축 굽힘/이축 굽힘, 양 끝 부호, 회복점 순서를 먼저 테스트한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "BeamRecovery|CentroidStress|SectionForce" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. hand-calculated recovery test 실패를 확인한다.
|
||||
2. stiffness와 같은 frame/부호 convention을 재사용한다.
|
||||
3. 도심에서 bending contribution이 0인지 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- point shear/torsional stress를 출력하지 마라. 이유: 단면 형상 정보가 부족하다.
|
||||
- Abaqus column 이름을 element kernel에 넣지 마라. 이유: validation adapter 책임이다.
|
||||
- 절점별 내력 부호를 임의 절댓값으로 바꾸지 마라. 이유: 평형 검증을 깨뜨린다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Step 1: Complete Result Contract
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/results/result_database.hpp`
|
||||
- `/include/fesa/elements/beam/beam3d2.hpp`
|
||||
- `/include/fesa/model/entity_origin.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
ResultDatabase에 element-end Beam 결과, local frame, model provenance와 diagnostics를
|
||||
추가한다.
|
||||
|
||||
```cpp
|
||||
struct BeamElementFrame final {
|
||||
ElementId element;
|
||||
EntityOrigin origin;
|
||||
BeamFrame local_frame;
|
||||
std::array<BeamSectionResult, 2> end_results;
|
||||
};
|
||||
struct ElementFrame final {
|
||||
std::vector<BeamElementFrame> beams;
|
||||
};
|
||||
```
|
||||
|
||||
- `ResultFrame`에 `ElementFrame element`를 추가한다.
|
||||
- node/element origin, field coordinate system, component labels와 ordering을 명시한다.
|
||||
- duplicate element/end node, wrong connectivity, nonfinite result, mismatched recovery
|
||||
point count를 실패 테스트로 먼저 작성한다.
|
||||
- LinearStaticAnalysis가 production recovery를 호출해 ResultDatabase를 채우게 한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "CompleteResultContract|ElementFrame" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. result validation과 analysis integration test 실패를 확인한다.
|
||||
2. 의미 타입과 orchestration만 수정한다.
|
||||
3. element-end/node connectivity와 origin 보존을 assertion한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- CSV-specific field를 ResultDatabase에 넣지 마라. 이유: 결과 semantic 모델을 오염시킨다.
|
||||
- history/velocity를 빈 구조로 추가하지 마라. 이유: Phase 1에서 사용하지 않는다.
|
||||
- recovery를 analysis 코드에 복제하지 마라. 이유: element kernel 계약을 재사용해야 한다.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Step 2: Self-contained HDF5
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/HDF5_SCHEMA.md`
|
||||
- `/include/fesa/results/result_database.hpp`
|
||||
- `/include/fesa/io/hdf5/`
|
||||
|
||||
## 작업
|
||||
|
||||
HDF5 schema와 reader/writer를 완성해 파일 하나로 모델·설정·전체 Phase 1 결과를
|
||||
재구성할 수 있게 한다.
|
||||
|
||||
- model: coordinates, connectivity, Part/Instance/local labels, sets, materials,
|
||||
sections, orientation, applied shear values와 input/default source
|
||||
- analysis: single step, BC, load, solver settings
|
||||
- results: nodal displacement/reaction, Beam local frame, 양 끝 section
|
||||
strain/force, centroid `Sxx`, recovery-point `Sxx`, diagnostics
|
||||
- `docs/HDF5_SCHEMA.md`의 dataset rank/type/component/coordinate attribute를 먼저
|
||||
갱신한다.
|
||||
- public reader만으로 모든 항목을 재구성하는 실패 통합 테스트를 작성한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R SelfContainedHdf5 --output-on-failure
|
||||
h5ls -r .\out\build\windows-debug\Testing\Temporary\fesa-self-contained.h5
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. complete schema round-trip test 실패를 확인한다.
|
||||
2. schema version 호환성 규칙을 문서와 코드에 함께 반영한다.
|
||||
3. public reader와 h5ls로 구조를 독립 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 원본 `.inp` 경로만 저장하고 모델 데이터를 생략하지 마라. 이유: 자기완결 계약이다.
|
||||
- HDF5 object를 result model에 노출하지 마라. 이유: adapter 경계를 깨뜨린다.
|
||||
- schema를 무버전 변경하지 마라. 이유: reader 호환성을 잃는다.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "results-and-pipeline",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "result-database",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "minimal-hdf5-schema",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "linear-static-analysis",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"name": "cli-pipeline-integration",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# Step 0: Result Database
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/model/domain.hpp`
|
||||
- `/include/fesa/core/diagnostic.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
HDF5와 독립적인 최소 Phase 1 result semantic model을 만든다.
|
||||
|
||||
```cpp
|
||||
struct NodalFrame final {
|
||||
std::vector<NodeId> node_ids;
|
||||
std::vector<std::array<double, 6>> displacement;
|
||||
std::vector<std::array<double, 6>> reaction;
|
||||
};
|
||||
struct ResultFrame final {
|
||||
double step_time;
|
||||
NodalFrame nodal;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
struct ResultStep final {
|
||||
std::string name;
|
||||
std::vector<ResultFrame> frames;
|
||||
};
|
||||
struct ResultDatabase final {
|
||||
std::string schema_version;
|
||||
std::vector<ResultStep> steps;
|
||||
};
|
||||
```
|
||||
|
||||
- size mismatch, duplicate node, nonfinite field, duplicate step/frame을 실패 테스트로
|
||||
먼저 작성한다.
|
||||
- 이 step에는 element result를 미리 만들지 않는다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "ResultDatabase|NodalFrame" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 유효/무효 result model 테스트를 먼저 실행한다.
|
||||
2. 불변 읽기 계약에 필요한 최소 저장만 구현한다.
|
||||
3. HDF5 include가 없는지 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- HDF5 handle을 result model에 넣지 마라. 이유: semantic/adaptor 경계를 깨뜨린다.
|
||||
- velocity, acceleration, temperature를 추가하지 마라. 이유: Phase 1에서 사용하지 않는다.
|
||||
- 빈 element output hierarchy를 만들지 마라. 이유: 필요한 phase에서만 실체화한다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 1: Minimal HDF5 Schema
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/results/result_database.hpp`
|
||||
- `/include/fesa/model/domain.hpp`
|
||||
- `/cmake/FesaDependencies.cmake`
|
||||
|
||||
## 작업
|
||||
|
||||
먼저 `docs/HDF5_SCHEMA.md`에 schema `1.0.0`의 최소 group/dataset/attribute 계약을
|
||||
작성하고 HDF5 writer/reader round trip을 구현한다.
|
||||
|
||||
```cpp
|
||||
struct Hdf5ReadResult final {
|
||||
std::optional<ResultDatabase> database;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
[[nodiscard]] std::vector<Diagnostic> write_hdf5(
|
||||
const std::filesystem::path&,
|
||||
const Domain&,
|
||||
const ResultDatabase&);
|
||||
[[nodiscard]] Hdf5ReadResult read_hdf5_results(
|
||||
const std::filesystem::path&);
|
||||
```
|
||||
|
||||
- schema/version, node origin `(part,instance,local label)`, dense ID map, 좌표,
|
||||
connectivity, shear property source, nodal displacement/reaction을 round trip한다.
|
||||
- 먼저 public reader로 모든 값을 재확인하는 실패 테스트를 작성한다.
|
||||
- 모든 `hid_t`는 move-only RAII wrapper로 관리한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "Hdf5|ResultRoundTrip" --output-on-failure
|
||||
h5ls -r .\out\build\windows-debug\Testing\Temporary\fesa-round-trip.h5
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. schema 문서를 writer보다 먼저 작성한다.
|
||||
2. round-trip test 실패를 확인한 뒤 최소 adapter를 구현한다.
|
||||
3. HDF5 도구와 public reader 결과를 모두 확인한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- global HDF5 handle을 만들지 마라. 이유: 수명과 오류 경계를 훼손한다.
|
||||
- reference CSV 기능을 추가하지 마라. 이유: validation phase 책임이다.
|
||||
- schema에 빈 미래 분석 결과를 넣지 마라. 이유: 현재 계약만 저장한다.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Step 2: Linear Static Analysis
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/model/domain.hpp`
|
||||
- `/include/fesa/fem/dof_manager.hpp`
|
||||
- `/include/fesa/assembly/`
|
||||
- `/include/fesa/constraints/`
|
||||
- `/include/fesa/solvers/linear/`
|
||||
- `/include/fesa/results/result_database.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
기존 production 모듈을 조율하는 `LinearStaticAnalysis` lifecycle을 구현한다.
|
||||
|
||||
```cpp
|
||||
struct AnalysisRunResult final {
|
||||
bool succeeded;
|
||||
std::optional<ResultDatabase> results;
|
||||
std::vector<Diagnostic> diagnostics;
|
||||
};
|
||||
class LinearStaticAnalysis final {
|
||||
public:
|
||||
[[nodiscard]] AnalysisRunResult run(const Domain&) const;
|
||||
};
|
||||
```
|
||||
|
||||
- parser나 HDF5를 호출하지 않고 이미 검증된 Domain을 입력받는다.
|
||||
- DofManager, pattern/assembly, BC elimination, PARDISO, full reconstruction,
|
||||
reaction recovery, nodal ResultDatabase 순서로 실행한다.
|
||||
- hand-check 가능한 한 요소 Domain으로 변위, 반력, residual을 먼저 테스트한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "LinearStaticAnalysis|StaticEquilibrium" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. analysis test가 연결 누락으로 실패하는 것을 확인한다.
|
||||
2. orchestration만 구현하고 수치 kernel을 복제하지 않는다.
|
||||
3. \(Ku-f-r\) 평형과 finite result를 검사한다.
|
||||
4. 전체 테스트와 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- CLI option parsing을 analysis에 넣지 마라. 이유: application 경계를 깨뜨린다.
|
||||
- nonlinear loop나 여러 step을 추가하지 마라. 이유: Phase 1 범위 밖이다.
|
||||
- test-only solver 경로를 만들지 마라. 이유: production pipeline을 검증해야 한다.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Step 3: CLI Pipeline Integration
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/include/fesa/io/abaqus/parser.hpp`
|
||||
- `/include/fesa/io/abaqus/semantic_mapper.hpp`
|
||||
- `/include/fesa/analysis/linear_static_analysis.hpp`
|
||||
- `/include/fesa/io/hdf5/writer.hpp`
|
||||
- `/src/fesa/cli/main.cpp`
|
||||
|
||||
## 작업
|
||||
|
||||
flat minimal fixture를 입력부터 HDF5까지 실행하는 public application 경로를 연결한다.
|
||||
|
||||
```cpp
|
||||
struct AnalysisRequest final {
|
||||
std::filesystem::path input_path;
|
||||
std::filesystem::path output_path;
|
||||
};
|
||||
[[nodiscard]] AnalysisRunResult run_solver(const AnalysisRequest&);
|
||||
```
|
||||
|
||||
CLI 계약:
|
||||
|
||||
```text
|
||||
fesa solve <model.inp> --output <results.h5>
|
||||
fesa --version
|
||||
```
|
||||
|
||||
- 먼저 `MinimalCantileverPipeline` 통합 테스트를 작성한다.
|
||||
- test는 `run_solver` 또는 CLI와 public HDF5 reader만 사용한다.
|
||||
- 성공 파일의 ID, finite displacement, reaction/equilibrium diagnostic과 schema path,
|
||||
실패 입력의 nonzero exit 및 source diagnostic을 검증한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R MinimalCantileverPipeline --output-on-failure
|
||||
.\out\build\windows-debug\Debug\fesa.exe solve tests\fixtures\abaqus\minimal_cantilever.inp --output out\minimal-cantilever.h5
|
||||
h5ls -r out\minimal-cantilever.h5
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. end-to-end test 실패를 확인한다.
|
||||
2. parser→Domain→analysis→writer만 조율한다.
|
||||
3. command와 public reader로 산출물을 재검증한다.
|
||||
4. 이 milestone을 수치 자격 완료로 표시하지 말고 index를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- hierarchical sample의 전체 keyword를 우회 처리하지 마라. 이유: 다음 input phase다.
|
||||
- fake stiffness/result를 쓰지 마라. 이유: 실제 pipeline 검증을 무효화한다.
|
||||
- CLI에 solver 내부 구현을 넣지 마라. 이유: core/library 재사용성을 훼손한다.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"project": "FESA",
|
||||
"phase": "solver-bootstrap",
|
||||
"steps": [
|
||||
{
|
||||
"step": 0,
|
||||
"name": "cmake-project-scaffold",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 1,
|
||||
"name": "dependency-smoke-tests",
|
||||
"status": "pending"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"name": "core-ids-and-diagnostics",
|
||||
"status": "pending"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
# Step 0: CMake Project Scaffold
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
먼저 아래 파일을 모두 읽고 저장소 계약을 파악하라.
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/HARNESS.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/.harness/config.example.json`
|
||||
|
||||
## 작업
|
||||
|
||||
C++20/MSVC x64 프로젝트의 최소 실행 가능한 build/test 뼈대를 만든다.
|
||||
|
||||
- `CMakeLists.txt`, `CMakePresets.json`, `cmake/FesaDependencies.cmake`,
|
||||
`.harness/config.json`, `tests/CMakeLists.txt`를 만든다.
|
||||
- 실제 target은 `fesa_core` 정적 라이브러리와 `fesa` CLI 두 개만 만든다.
|
||||
- `include/fesa/core/version.hpp`, `src/fesa/core/version.cpp`,
|
||||
`src/fesa/cli/main.cpp`에 다음 계약을 구현한다.
|
||||
|
||||
```cpp
|
||||
namespace fesa {
|
||||
[[nodiscard]] std::string_view version() noexcept;
|
||||
}
|
||||
```
|
||||
|
||||
- CLI는 이 step에서 `fesa --version`만 처리한다.
|
||||
- 먼저 `VersionCommand` CTest를 등록해 실패를 확인한 뒤 최소 구현한다.
|
||||
- `windows-debug`, `windows-release` configure/build/test preset을 정의한다.
|
||||
- build 산출물은 `out/build/<preset>` 아래에만 둔다.
|
||||
- MSVC가 아니거나 x64가 아니면 configure 단계에서 명확히 실패시킨다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
uv run --with pytest python -m pytest -v -rs
|
||||
cmake --preset windows-debug
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R VersionCommand --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
`fesa --version`은 비어 있지 않은 FESA 버전을 출력하고 종료 코드 0을 반환해야 한다.
|
||||
CTest는 0개가 아니어야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. 테스트가 구현 전 실패하는 것을 확인한다.
|
||||
2. Acceptance Criteria 명령을 새로 실행한다.
|
||||
3. MSVC/C++20/x64와 산출물 경로를 확인한다.
|
||||
4. 성공 시 index의 step을 `completed`로 바꾸고 생성 파일을 summary에 기록한다.
|
||||
5. 도구가 없으면 자동 설치하지 말고 `blocked`와 정확한 누락 항목을 기록한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 외부 패키지를 다운로드하지 마라. 이유: 사전 설치 의존성 정책을 위반한다.
|
||||
- MKL, TBB, HDF5 기능을 구현하지 마라. 이유: 다음 step의 독립 범위다.
|
||||
- 빈 미래 모듈을 만들지 마라. 이유: Phase 1 최소 실체화 원칙을 위반한다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Step 1: Dependency Smoke Tests
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/HARNESS.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/CMakeLists.txt`
|
||||
- `/CMakePresets.json`
|
||||
- `/cmake/FesaDependencies.cmake`
|
||||
- `/.harness/config.json`
|
||||
- `/tests/CMakeLists.txt`
|
||||
|
||||
이전 step의 CMake target과 preset을 그대로 확장하라.
|
||||
|
||||
## 작업
|
||||
|
||||
사전 설치된 oneMKL, oneTBB, HDF5 C API, GoogleTest/GoogleMock을 CMake imported
|
||||
target으로 찾고 링크 계약을 검증한다.
|
||||
|
||||
- `tests/unit/dependencies/dependency_smoke_test.cpp`를 먼저 작성한다.
|
||||
- 테스트는 MKL의 작은 vector 연산, TBB의 제한된 parallel loop, HDF5 임시 파일
|
||||
생성·닫기, GoogleTest 실행을 확인한다.
|
||||
- `FesaDependencies.cmake`는 `MKL::MKL`, TBB imported target, HDF5 C target,
|
||||
GoogleTest target을 제공해야 한다.
|
||||
- oneMKL은 LP64, dynamic link, TBB threading 조합을 사용한다.
|
||||
- runtime DLL 또는 architecture 불일치는 configure diagnostic으로 보고한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --preset windows-debug
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R DependencySmoke --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
네 의존성을 실제 호출하는 smoke test가 통과해야 하며 새 MSVC 경고가 없어야 한다.
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. smoke test를 먼저 추가하고 link 또는 실행 실패를 확인한다.
|
||||
2. dependency discovery와 target link만 최소 수정한다.
|
||||
3. 전체 configure/build/test를 새로 실행한다.
|
||||
4. 성공 시 정확한 imported target과 탐색 파일을 summary에 기록한다.
|
||||
5. 패키지나 MSVC가 없으면 세 차례 임의 수정하지 말고 `blocked`로 종료한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- FetchContent, vcpkg, Conan 또는 다운로드를 추가하지 마라. 이유: ADR-002 위반이다.
|
||||
- vendor 절대경로를 public header에 노출하지 마라. 이유: backend 격리를 깨뜨린다.
|
||||
- solver 기능을 구현하지 마라. 이유: 이 step은 build dependency 계약만 다룬다.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Step 2: Core IDs and Diagnostics
|
||||
|
||||
## 읽어야 할 파일
|
||||
|
||||
- `/AGENTS.md`
|
||||
- `/docs/PRD.md`
|
||||
- `/docs/ARCHITECTURE.md`
|
||||
- `/docs/ADR.md`
|
||||
- `/docs/superpowers/plans/2026-07-29-fesa-phase-1.md`
|
||||
- `/CMakeLists.txt`
|
||||
- `/tests/CMakeLists.txt`
|
||||
- `/include/fesa/core/version.hpp`
|
||||
|
||||
## 작업
|
||||
|
||||
외부 라이브러리에 의존하지 않는 `core` 값 타입을 TDD로 구현한다.
|
||||
|
||||
- 생성 파일:
|
||||
`include/fesa/core/entity_id.hpp`, `vec3.hpp`, `source_location.hpp`,
|
||||
`diagnostic.hpp`, `status.hpp`와 대응 테스트
|
||||
- 인터페이스:
|
||||
|
||||
```cpp
|
||||
template<class Tag>
|
||||
class EntityId final {
|
||||
public:
|
||||
explicit constexpr EntityId(std::int64_t value);
|
||||
[[nodiscard]] constexpr std::int64_t value() const noexcept;
|
||||
auto operator<=>(const EntityId&) const = default;
|
||||
};
|
||||
|
||||
struct Vec3 final { double x; double y; double z; };
|
||||
struct SourceLocation final {
|
||||
std::filesystem::path file;
|
||||
std::size_t line;
|
||||
std::size_t column;
|
||||
};
|
||||
enum class DiagnosticStage { io, syntax, semantic, model, equation, solver, results, validation };
|
||||
enum class Severity { warning, error };
|
||||
struct Diagnostic final {
|
||||
DiagnosticStage stage;
|
||||
Severity severity;
|
||||
std::string code;
|
||||
std::string message;
|
||||
std::optional<SourceLocation> source;
|
||||
};
|
||||
```
|
||||
|
||||
- typed ID의 잘못된 암시 변환, 음수 ID, nonfinite vector와 diagnostic source 보존을
|
||||
실패 테스트로 먼저 고정한다.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
```powershell
|
||||
cmake --build --preset windows-debug
|
||||
ctest --preset windows-debug -R "Core|Diagnostic|EntityId" --output-on-failure
|
||||
ctest --preset windows-debug --output-on-failure
|
||||
```
|
||||
|
||||
## 검증 절차
|
||||
|
||||
1. production header 전에 실패하는 GoogleTest를 작성한다.
|
||||
2. 최소 값 타입만 구현한다.
|
||||
3. focused test와 전체 CTest를 실행한다.
|
||||
4. `core`가 MKL, TBB, HDF5, Abaqus header를 include하지 않는지 확인한다.
|
||||
5. index와 summary를 갱신한다.
|
||||
|
||||
## 금지사항
|
||||
|
||||
- 단위 변환 시스템을 만들지 마라. 이유: FESA는 일관 단위계만 사용한다.
|
||||
- 범용 reflection이나 serialization을 만들지 마라. 이유: 요구되지 않았다.
|
||||
- equation ID를 정의하지 마라. 이유: `DofManager` 단계의 책임이다.
|
||||
Reference in New Issue
Block a user