modify documents

This commit is contained in:
KOKO\Mimi
2026-09-06 00:52:59 +09:00
parent 97e4d7a971
commit ac84235b7a
17 changed files with 2912 additions and 1195 deletions
+279 -308
View File
@@ -1,375 +1,346 @@
# Architecture Decision Records
# FESA Architecture Decision Records
## 철학
FESA의 architecture decision은 solver correctness, verification traceability, implementation testability를 우선한다. Harness는 제품이 아니라 C++/MSVC 기반 FEM 구조해석 솔버 개발을 통제하는 운영 인프라이다.
## 목적과 기록 범위
---
FESA는 유한요소법 기반 구조해석 솔버를 단계적으로 구축한다. 이 문서는 그 과정에서
프로젝트 전반에 적용되는 결정의 이유와 트레이드오프를 관리한다. 제품 목표는
[PRD](PRD.md), 공통 책임과 의존성은 [ARCHITECTURE](ARCHITECTURE.md)를 따른다.
### ADR-001: FESA는 구조해석 솔버 프로젝트이고 Harness는 운영 인프라로 둔다
**결정**: 저장소의 주 목적은 유한요소법 기반 구조해석 솔버 개발이다. Harness는 승인된 Step 계획, 독립 세션 실행, PreToolUse guardrail, Stop MSVC build/test 검증을 제공하는 보조 계층으로 유지한다.
특정 요소·재료·하중·해석 절차의 정식화, 수치 기준과 구현 선택은
`docs/<feature-id>/ADR.md`에 기록한다. 해당 Feature의 목적·범위·acceptance 요약은
같은 폴더의 `PRD.md`, 상세 전문 계약은 requirements·formulation·I/O 등의 소유 문서에 둔다.
공통 ADR에 기능 목록, 진행 상태와 개별 실행 결과를 누적하지 않는다.
**이유**: 기존 문서가 Harness 중심이면 agent가 solver architecture, FEM verification, Abaqus/HDF5 계약보다 운영 스크립트에 과도하게 맞춰 행동한다.
## 기존 결정의 보존과 읽는 방법
**트레이드오프**: Harness 문서의 비중은 낮아지지만, `docs/HARNESS_WORKFLOW.md`의 실행 계약과 `.codex/hooks.json`의 검증 정책은 계속 필수 운영 규칙으로 유지한다.
개정 전 ADR-001~023의 전체 원문은
[원문 보존본](archive/pre-generalization/ADR.md)에 있다. 아래 기존 ID 항목은 그 결정의
공통 부분을 요약한 것이며 번호 재사용, 새 physics 승인 또는 기존 세부 계약의 폐기가 아니다.
구체적인 적용 범위는 원문의 같은 ID와 해당 Feature의 승인된 최신 계약을 함께 확인한다.
### ADR-002: C++17/MSVC/CMake/CTest를 기본 구현 환경으로 둔다
**결정**: 기본 solver 구현과 validation은 C++17 이상, Visual Studio 17 2022 또는
Visual Studio 18 2026 generator, x64 platform, Debug config, CMake, CTest로 수행한다.
`.harness/config.json`이 없으면 CMake가 설치된 두 승인 generator 중 하나를 자동
선택할 수 있으며, build/test evidence에는 실제 generator와 compiler version을 기록한다.
- 과거 결정을 소급 수정하거나 모든 과거 상태를 일괄 `Accepted`로 표시하지 않는다.
- 일부만 대체된 결정은 유지되는 부분과 대체된 부분을 구분한다.
- 현재 선택된 toolchain, 외부 형식과 구현별 계약은 [AGENTS.md](../AGENTS.md) 및 승인된
설정·Feature 계약을 따른다. 문서 일반화만으로 이를 교체하지 않는다.
- 기존 결정 번호는 다른 의미로 재사용하지 않는다. 후속 결정은 마지막 번호 다음으로 추가한다.
- ADR-024~027은 현재 agent·skill·Feature 문서 운영 계약을 기록한다. 새 해석 기능이나
외부 실행 권한을 승인하는 결정이 아니다.
**이유**: FESA의 목표 환경은 Windows/MSVC 기반 C++이다. CMake/CTest는 solver source tree가 추가되거나 확장될 때 가장 일관된 build/test entry point다. VS17과 VS18을
승인하면 현재 지원되는 MSVC 개발 환경에서 같은 C++17/x64/Debug 계약을 검증할 수 있다.
## 프로젝트 공통 결정
**트레이드오프**: FESA solver source는 CMake/CTest를 기본으로 유지한다. Generator별
compiler 차이는 각 build/test report에 명시하고, 두 generator 중 하나에서만 관찰되는
실패를 다른 generator의 성공으로 숨기지 않는다. Harness 자체는 `.harness/config.json`에
solution과 test command를 명시한 직접 MSBuild 프로젝트도 검증할 수 있지만, 이는 FESA
제품이 solution-only workflow를 지원한다는 의미가 아니다.
### ADR-001: Solver 제품과 개발 운영 인프라를 분리한다
### ADR-003: Abaqus `.inp` full compatibility가 아니라 기능별 keyword subset을 지원한다
**결정**: FESA parser는 Abaqus keyword/data/comment line 규칙을 따르되, 기능별로 승인된 keyword subset만 지원한다. 미지원 keyword는 명확한 diagnostic을 남긴다.
**결정**: 프로젝트의 제품은 구조해석 솔버다. Agent·skill·Harness는 소스, 문서와
검증 evidence를 관리하는 개발 운영 영역이며 solver runtime의 의존성이 아니다.
**이유**: full Abaqus compatibility는 초기 solver 범위와 검증 비용을 과도하게 키운다. 기능별 subset은 요구조건, I/O contract, reference validation을 추적 가능하게 만든다.
**이유**: 개발 자동화의 편의가 물리적 의미, 사용자 요구와 수치 검증을 대신하지 않게 한다.
**트레이드오프**: 사용자는 기존 Abaqus input file을 그대로 사용할 수 없을 수 있다. 대신 지원 범위와 실패 원인이 명확해진다.
**트레이드오프**: Solver의 완료 evidence와 자동화 자체의 correctness를 별도로 관리해야 한다.
현재 운영 역할과 검증 범위는 ADR-024·026에서 보완한다.
### ADR-004: Domain, AnalysisModel, DofManager, AnalysisState를 분리한다
**결정**: `Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과
`StepDefinition` 입력 모델 정의를 `std::unique_ptr`로 단독 소유하고 const access와
stable collection index를 제공한다. `AnalysisModel`은 Domain 수명 안에서 stable index와
const reference만 사용하는 non-owning current-step view다. `DofManager`는 equation
numbering과 constrained/free mapping을 전담하고, `AnalysisState`는 해석 중 변하는
물리량을 소유한다.
### ADR-002: 구현·검증 환경은 명시된 프로젝트 baseline으로 관리한다
**이유**: 모델 정의, step activation, equation system, transient/nonlinear state가 섞이면 parser, assembler, solver, result writer가 강하게 결합된다. 분리된 상태 모델은 선형 정적 해석에서 시작해 비선형, 동적, thermal coupling으로 확장하기 쉽다.
**결정**: 현재 FESA의 C++ 언어·compiler·platform·build/test baseline을 프로젝트 지침과
설정으로 명시하고 실제 실행 환경을 evidence에 기록한다. 재사용 Harness가 다른
backend를 처리할 수 있다는 사실을 FESA 제품 지원으로 간주하지 않는다.
**트레이드오프**: 초기 class 수가 늘어난다. V0에서는 interface를 얇게 유지하고 실제 선형 정적 frame에 필요한 state만 구현한다.
**이유**: 개발 환경의 암묵적 차이가 build와 numerical regression 판정을 흐리지 않게 한다.
### ADR-005: 공식 결과 파일은 HDF5로 하고 reference 결과는 Abaqus CSV로 둔다
**상태**: HDF5 authoritative output 결정은 유지하며 reference bundle governance 부분은 ADR-019로 대체됨.
**트레이드오프**: 새 환경은 별도의 compatibility와 실행 evidence가 필요하다. 원문의
기술 선택 이력은 유지하며, 현재 preset·명령 선택은 ADR-026의 구성 경계를 따른다.
**결정**: FESA solver의 authoritative result output은 `results.h5` HDF5이다. Abaqus reference results는 기능별 reference model contract가 지정한 `reference/<model-id>/` 아래 CSV 파일로 저장하며, verification은 FESA HDF5 rows와 Abaqus reference CSV rows를 documented IDs, components, units, coordinate system, step/frame identity, tolerance 기준으로 비교한다. 신규 reference는 canonical 파일명을 사용하고, 승인된 기존 bundle의 legacy alias는 해당 기능 계약에 정확한 경로를 기록한 경우에만 허용한다.
### ADR-003: 외부 입력은 승인된 subset의 의미로 지원한다
**이유**: 구조해석 결과는 step/frame, field/history, node/element/integration point location, units, coordinate system, schema version을 함께 가져야 한다. HDF5는 이 계층 구조와 metadata를 안정적으로 표현한다.
**결정**: 외부 형식의 syntax와 semantic mapping을 구분하고 지원·미지원 범위를 명시한다.
미지원 모델 의미는 fail-closed로 진단하며 무해하다고 계약된 항목만 warning/no-op으로 둔다.
**트레이드오프**: reference comparison은 FESA HDF5 dataset identity와 Abaqus CSV row identity를 모두 관리해야 한다. FESA HDF5에서 추출한 deterministic CSV view는 디버깅/검토용 보조 artifact로 허용하지만, 공식 solver output이나 reference artifact로 취급하지 않는다.
**이유**: Parser가 읽을 수 있다는 사실과 물리적으로 해석할 수 있다는 사실은 다르다.
### ADR-006: 해석 알고리즘과 수치 backend는 Strategy와 Adapter 경계 뒤에 둔다
**결정**: `Analysis`, `LinearSolver`, `TimeIntegrator`, `ConvergenceCriteria`는 Strategy로 구성하고, MKL, TBB, HDF5 API는 adapter 계층 뒤에 둔다. `Vector`는 contiguous `double`, `Matrix`는 row-major contiguous `double`을 소유하고 dense 연산은 MKL CBLAS를 사용한다. `SparseMatrix`는 이들과 상속 관계가 없는 0-based CSR 전용 타입이며, PARDISO factorization과 substitution은 `LinearSolver` 경계 뒤에서 분리한다.
**트레이드오프**: 기존 외부 모델을 수정해야 할 수 있지만 silent approximation과 과도한
호환성 약속을 피할 수 있다. 실제 입력 형식의 선택은 기존 승인 계약을 유지한다.
**이유**: 선형 정적, 비선형 정적, 동적, frequency, heat transfer 해석은 공통 흐름을 공유하지만 알고리즘과 backend가 다르다. 외부 API를 core에 노출하면 테스트 double, backend 교체, dependency review가 어려워진다.
### ADR-004: 모델 정의, 실행 view, equation과 mutable state를 분리한다
**트레이드오프**: 단일 기능만 구현할 때는 adapter가 다소 장황해 보일 수 있다. Row-major dense storage와 CSR sparse storage를 따로 유지해야 하지만 backend 의존성과 dense/sparse 의미가 core 모델에 섞이지 않는다.
**결정**: 모델 owner, non-owning 실행 view, DOF/equation owner와 procedure state를
구분한다. View는 원본보다 오래 살지 않으며 승인된 procedure에 필요한 state만 둔다.
### ADR-007: Analysis base는 최소 실행 계약만 제공한다
**결정**: `Analysis` base는 virtual `Analysis::Run(const AnalysisRequest&)`만 제공하고
linear-static-specific protected hook을 정의하지 않는다. 승인된 선형 정적 순서인
`parse input -> initialize Domain -> build AnalysisModel -> build DOF map/sparse pattern ->
assemble stiffness -> partition constraints -> factorize Kff -> assemble load -> form effective
RHS -> substitute -> reconstruct displacement -> recover results -> write HDF5`는
`LinearStaticAnalysis::Run()`의 private lifecycle로 유지한다. 강성행렬 factorization은
하중벡터 조립보다 먼저 수행하고 factorization과 substitution을 하나의 불투명한 solve
호출로 합치지 않는다.
**이유**: Parsing, model activation, numerical solve와 recovery의 수명이 섞이지 않게 한다.
**이유**: 현재 여덟 단계는 linear static equation, state와 failure taxonomy에 특화되어
있다. 최소 base contract는 이 순서의 검증 가능성을 보존하면서 승인되지 않은 dynamic,
eigenvalue 또는 nonlinear procedure에 같은 protected hook과 사용하지 않는 state를
강제하지 않는다. Factorization과 substitution 분리는 동일 강성행렬에 여러 RHS를 적용할
수 있고 각 실패 단계를 구조화된 diagnostic으로 분류하게 한다.
**트레이드오프**: 명시적인 연결과 lifetime 관리가 필요하지만 모델 복사와 분산된
equation numbering, 미래 state의 불필요한 할당을 줄인다.
**트레이드오프**: Procedure 사이의 lifecycle code는 base Template Method로 자동 재사용되지
않는다. 두 번째 procedure가 승인되면 실제로 같은 단계만 focused collaborator로 추출하되,
linear-static hook 사이에 조건문으로 새 physics를 삽입하지 않는다.
### ADR-005: Authoritative result와 reference·debug artifact를 구분한다
### ADR-008: Sparse assembly는 deterministic COO-to-CSR 경로로 시작한다
**결정**: 초기 assembly는 element-local contribution을 COO triplet으로 수집한 뒤 CSR로 finalize한다. MKL PARDISO backend는 CSR input contract를 받는다.
**결정**: 공식 결과의 물리 identity와 versioned 저장 계약을 유지한다. Reference와
debug view를 공식 결과로 대체하지 않는다. 기존 HDF5 선택은 유지하며 보조 형식의 존재가
공식 형식 변경을 뜻하지 않는다.
**이유**: CSR은 MKL PARDISO와 잘 맞고, COO-to-CSR 경로는 구현과 테스트가 명확하다. deterministic reduction은 reference comparison의 재현성을 지킨다.
**이유**: 결과 검토 도구나 비교 편의를 위해 authoritative quantity와 파일 의미가 바뀌는 것을 막는다.
**트레이드오프**: 대규모 모델에서는 메모리와 변환 비용이 생길 수 있다. 성능 문제가 실제로 확인되면 typed batch assembly 또는 kernel 분리를 추가한다.
**트레이드오프**: 물리 identity와 저장 mapping을 함께 관리해야 한다.
원문의 reference naming 규칙은 ADR-019로 대체되었고, 파일명·경로의 후속 결정은
보존본 ADR-023에 있다. 이를 문서 정리 과정에서 과거 값으로 되돌리지 않는다.
### ADR-009: TBB 병렬화는 element-local computation부터 적용한다
**결정**: 첫 oneTBB 적용 지점은 element-local matrix/residual 계산이다. 전역 sparse write는 thread-local buffer 또는 deterministic reduction으로 제한한다.
### ADR-006: 알고리즘과 backend를 명시적인 interface 뒤에 둔다
**이유**: element-local 계산은 독립성이 높고 병렬화 효과가 명확하다. 전역 sparse matrix에 직접 병렬 write하면 재현성, race, ordering 문제가 생긴다.
**결정**: 승인된 analysis와 numerical·parallel·output backend의 계약을 implementation과
분리한다. Vendor/OS 타입과 resource lifecycle은 private adapter에 둔다.
**트레이드오프**: 초기 병렬화 범위가 제한된다. MKL 내부 thread와 TBB task arena의 oversubscription 정책을 별도로 문서화해야 한다.
**이유**: 해석의 물리 의미가 특정 library API와 오류 처리에 종속되지 않게 한다.
### ADR-010: Abaqus reference artifact는 사람이 생성하거나 명시 승인된 절차로만 갱신한다
**상태**: Artifact read-only 및 실행 제한은 유지하며 metadata/provenance/naming 계약은 ADR-019로 대체됨.
**트레이드오프**: Adapter와 계약 테스트 비용이 생긴다. 실제 사용 사례가 없는 Strategy,
factory, 공통 base나 future capability를 미리 도입하지 않는다.
**결정**: Agent는 Abaqus, Nastran 또는 reference solver를 직접 실행하지 않는다. reference artifact 생성, 수정, 복원은 명시 승인된 phase에서만 수행한다. 모든 bundle의 provenance, generator/version, units, coordinate system, step/frame identity, schema, tolerance와 limitations는 승인된 기능별 Reference Model Contract에 기록한다. `metadata.json`은 선택 reference artifact이며, 부재만으로 bundle을 불완전하다고 판정하지 않는다. 파일이 존재하면 read-only 보조 자료로 inventory하고 계약 및 실제 artifact와 일치하는지 확인하며, 충돌은 숨기지 않고 upstream 계약 문제로 보고한다. 승인된 `cantilever-beam-b33` legacy baseline의 space-containing filename과 `README.md` N/A 예외는 유지한다.
### ADR-007: 해석 procedure가 자신의 lifecycle을 소유한다
**이유**: reference 결과는 solver correctness의 기준이다. 생성 절차가 불명확하면 구현 결함과 reference artifact 오류를 구분할 수 없다.
**결정**: 공통 analysis 경계는 최소 실행 계약만 제공한다. 구체적인 state, assembly,
solve, 반복·종료와 recovery 순서는 procedure별 승인 계약으로 정의한다.
**트레이드오프**: Reference Model Contract가 필수 provenance의 단일 source of truth가 되어 별도 JSON 파일 없이도 bundle을 사용할 수 있다. 선택 `metadata.json`이 계약과 중복될 수 있으므로 존재 시 일관성 검사가 필요하다. Legacy filename과 `README.md` 예외는 일반 artifact 규칙을 복잡하게 하지만 exact path와 source commit을 고정하고 read-only로 취급해 감사 가능성을 유지한다.
**이유**: 서로 다른 해석의 의미를 하나의 고정된 Template Method나 조건문에 강제하지 않는다.
### ADR-011: 구형 단일 검증 진입점 계약을 폐기한다
**트레이드오프**: Procedure 사이의 일부 코드가 중복될 수 있다. 승인된 연산 순서는
보존하며 실제 공통 책임이 확인된 경우에만 collaborator로 분리한다.
**상태**: ADR-012로 대체됨.
### ADR-008: Local contribution과 global assembly를 분리한다
**결정**: 삭제된 legacy validation entry point, legacy Python test discovery, 환경 변수 기반 command override를 Harness의 기본 검증 계약으로 사용하지 않는다.
**결정**: Local 계산은 명시된 ordering으로 contribution을 반환하고, 전역 조립은 지정된
pattern·scatter와 deterministic reduction을 사용한다.
### ADR-012: Harness는 계획, 실행, Hook 검증의 세 계층으로 운영한다
**이유**: 요소 수식과 전역 연결 오류를 분리해 검증하고 scheduling에 의존하지 않게 한다.
**결정**: 계획은 `.agents/skills/harness`, Step 실행과 Git 상태 관리는 `scripts/execute.py`, 도구 호출 전 정책과 종료 전 검증은 `.codex/hooks.json`에 연결된 `scripts/hooks/`가 담당한다. C++ production 변경은 관련 테스트 파일이 있어야 하며, 실제 RED 실패와 GREEN 성공은 같은 Step 안에서 확인한다. Stop은 `.harness/config.json` 또는 자동 감지 결과로 전체 MSVC build/test를 검증한다. Harness Python 변경은 `uv run --with pytest python -m pytest -v -rs`로 검증한다.
**트레이드오프**: Buffer와 변환 비용이 생긴다. 기존 저장·조립 방식의 교체는 별도 evidence와
계약 검토가 필요하며 이 요약은 비결정적인 경로를 허용하지 않는다.
**이유**: 테스트 파일 존재 검사, TDD 실행 증거, 전체 build/test는 서로 다른 책임이다. 이를 분리하면 Hook이 보장하는 범위를 과장하지 않으면서 Step 종료 시 green 상태를 강제할 수 있다.
### ADR-009: 병렬화는 소유권이 명확한 독립 작업에 적용한다
**트레이드오프**: PreToolUse만으로 구현 전 RED 실행을 증명할 수 없으므로 Implementation report에 RED/GREEN 명령과 결과를 기록해야 한다. C/C++가 없는 저장소는 Stop이 통과하므로 Harness Python 검증은 별도 acceptance command로 유지한다.
**결정**: Worker는 자신의 local output에만 기록하고 공유 결과의 reduction과 diagnostic
선택은 결정적으로 수행한다.
### ADR-013: V0 선형 정적 해석은 단일 step B33 Euler beam으로 제한한다
**이유**: Race와 부동소수 누적 순서가 물리 검토·회귀 비교를 흔들지 않게 한다.
**결정**: 첫 end-to-end 제품 기능은 입력 파일당 하나의 `*STEP, *STATIC`을 해석하는 2절점 3D Euler–Bernoulli beam이다. Abaqus `TYPE=B33`만 이 요소로 매핑하고 B31은 `unsupported-element-formulation`으로 거부한다. `*PART/*ASSEMBLY/*INSTANCE`는 여러 identity instance와 stable source identity를 지원하지만 instance transform, nested assembly, 다중 step은 지원하지 않는다. Output-request keyword는 승인 allowlist에서 warning 후 no-op 처리하고 FESA 기본 HDF5 결과는 항상 생성한다.
**트레이드오프**: 병렬화 범위와 throughput이 제한될 수 있다. Backend thread와 task
정책은 실제 측정과 검증을 통해 정하며 승인된 ordering을 보존한다.
**이유**: B31은 transverse shear deformation을 포함하므로 Euler–Bernoulli 정식화와 의미가 다르다. 단일 step과 identity instance로 범위를 제한하면 parser wrapper, source identity, assembly, 해법 및 결과 복구를 end-to-end로 검증하면서 의미를 왜곡하지 않는다.
### ADR-010: 외부 reference는 명시적인 소유권과 권한 아래 유지한다
**트레이드오프**: 기존 Abaqus 모델 중 B31, instance transform, 다중 step 또는 `*DLOAD`를 사용하는 입력은 거부된다. 이후 기능은 별도 요구조건과 formulation/reference gate를 거쳐 추가한다.
**결정**: 저장된 reference는 read-only다. 생성·수정·복원과 외부 solver 실행은 명시적으로
승인된 범위에서만 다루며, 구현을 통과시키기 위해 artifact를 보정하지 않는다.
### ADR-014: B33 cantilever baseline은 component-scale 혼합 tolerance로 비교한다
**이유**: 검증 기준과 구현 결과가 서로를 정당화하는 순환을 방지한다.
**상태**: Artifact inventory와 component mapping의 역사적 결정은 유지하며 tolerance와
node-station projection 결정은 ADR-022로 대체됨.
**트레이드오프**: 필요한 artifact가 없으면 적절한 owner나 환경 조치가 필요하다.
원문의 추가 metadata·provenance·naming 조건은 ADR-019로 대체되었다.
**결정**: `reference/cantilever beam/`의 B33 input, displacement CSV, reaction CSV, elemental-force CSV를 V0 reference baseline으로 사용한다. Displacement와 reaction은 node identity로, section resultant는 CSV node station과 정규화된 FESA element endpoint로 비교한다. 같은 model, step/frame, quantity, component에 대해 `reference_scale = max(abs(reference rows))`를 계산하고 모든 row에 `absolute_floor + 1e-6 * reference_scale`을 적용한다. SI displacement/rotation absolute floor는 `1e-9`, force/moment floor는 `1e-3`이다. Beam stress는 출력하되 Abaqus stress reference comparison은 N/A다.
### ADR-012: 계획, 실행과 Hook 검증의 책임을 분리한다
**이유**: 자유단 moment처럼 이론적으로 0인 값에는 행별 상대오차가 정의되지 않으며 Abaqus 결과에 작은 수치 잔차가 남을 수 있다. Component scale을 사용하면 전체 물리량 크기에 비해 작은 잔차를 허용하면서 각 row를 결정적으로 판정할 수 있다.
**결정**: Planning은 할당된 계획 파일, Executor는 실행 상태와 Git 처리, Hook은 등록된
guardrail과 종료 검증을 담당한다. 테스트 파일 존재는 RED 관찰의 증거가 아니다.
**트레이드오프**: 큰 component scale은 zero row의 허용폭을 넓힌다. 이를 완화하기 위해 quantity와 component를 섞지 않고 Abaqus 값만 scale에 사용하며, 모든 row의 absolute/normalized error와 worst row를 보고하고 누락·추가·nonfinite row를 tolerance 전에 실패시킨다.
**이유**: 자동화 각 계층이 보장하는 범위를 명확히 하여 검증 누락과 과장된 통과 판정을 막는다.
### ADR-015: 외부 CMake target을 FESA 경계로 정규화하고 Windows runtime closure를 명시한다
**트레이드오프**: Implementation은 실제 명령·결과를 별도 evidence로 남겨야 한다.
원문의 전체 Stop 검증 설명은 ADR-026의 조건별 검증 범위와 함께 읽고, 계획·실행의
권한은 ADR-024의 현행 운영 계약을 따른다.
**결정**: MKL, TBB, HDF5 CONFIG package가 제공하는 target은 dependency module에서
`Fesa::MKL`, `Fesa::TBB`, `Fesa::HDF5`로 정규화한다. Product target은 이 경계만
`PRIVATE` link하고 public header에 vendor/Win32 type을 노출하지 않는다. Approved Windows
환경에서는 packaged shared HDF5 C target을 우선하며, CLI와 test executable 옆에 TBB,
MKL, OpenMP, Intel math runtime, HDF5를 포함한 실제 runtime DLL closure를 POST_BUILD로
stage한다.
### ADR-015: Build dependency와 runtime closure를 명시한다
**이유**: Package version이나 shared/static variant에 따라 imported target 이름과 숨은
runtime dependency가 달라질 수 있다. Configure와 link 성공만 확인하면 GoogleTest
discovery 또는 배포된 CLI가 `0xc0000135`로 실패할 수 있다. FESA-owned target과 명시적
runtime closure는 module code와 실행 환경을 package 세부사항에서 분리한다.
**결정**: 외부 dependency를 프로젝트가 소유한 target 경계로 정규화하고 public API에
vendor type을 노출하지 않는다. 실행에 필요한 dynamic dependency도 검증 범위에 포함한다.
**트레이드오프**: Windows staging CMake가 길어지고 새 dynamic dependency마다 runtime
audit가 필요하다. 대신 개인 설치 경로를 source에 하드코딩하거나 developer `PATH`에
의존하지 않고 build tree executable을 재현 가능하게 실행할 수 있다.
**이유**: Configure·link 성공만으로 실제 실행 환경의 완전성을 증명할 수 없다.
### ADR-016: 결정론과 failure atomicity를 correctness contract로 취급한다
**트레이드오프**: Backend 추가마다 build 및 runtime 검토가 필요하다. 구체적인 package
선택·staging 구현은 현재 설정과 기존 승인 계약에 유지한다.
**결정**: Parallel element 계산은 index별 독립 buffer만 쓰고, COO tuple ordering과
floating-point sum은 join 이후 고정된 serial 순서로 수행한다. Result recovery, solver
output, HDF5 writer는 candidate를 완성·검증한 뒤 caller-owned state 또는 final file에
commit한다. HDF5는 same-directory temporary file을 checked close/reopen한 후에만 atomic
finalization한다.
### ADR-016: 결정론과 failure preservation을 correctness로 취급한다
**이유**: Reference comparison과 물리 검토는 row identity와 작은 수치 차이에 민감하다.
Thread scheduling 또는 중간 실패가 sparse bytes, result order, 이전 output을 바꾸면 같은
입력에 대한 evidence를 신뢰할 수 없다.
**결정**: Ordering과 reduction을 명시하고, state·result·final output은 검증된 candidate를
통해 반영한다. 실패 시 계약된 기존 유효 상태와 최종 결과를 보존한다.
**트레이드오프**: Serial reduction과 candidate copy가 throughput과 memory를 더 사용할 수
있다. 성능 최적화는 동일한 ordering, failure preservation, reference 결과를 증명할 때만
대체할 수 있으며, nondeterministic global sparse write는 허용하지 않는다.
**이유**: 재현 가능한 결과와 실패 후 신뢰할 수 있는 상태가 검증의 전제이기 때문이다.
### ADR-017: Essential constraint는 stable elimination으로 적용하고 reaction은 full residual로 정의한다
**트레이드오프**: Buffer, candidate와 검증 비용이 증가한다. 성능 개선은 같은 보존
경계와 결과 의미를 입증해야 하며 correctness를 약화하는 예외로 처리하지 않는다.
**결정**: V0는 DofManager의 stable free/constrained order로 full stiffness를
`Kff/Kfc/Kcf/Kcc`로 분할하고 `Kff * df = Ff - Kfc * dc`를 푼 뒤 full displacement를
복구한다. 모든 DOF가 constrained인 모델의 `0 x 0 Kff`는 유효한 trivial factorization과
empty substitution이다. Recovery의 full residual `r = K*d - F`를 reaction vector로
보존하며 constrained entry는 physical reaction, free entry는 equilibrium evidence다.
### ADR-017: 제약 적용과 reaction 의미를 equation 계약으로 정의한다
**이유**: Equation numbering과 prescribed displacement를 한 owner가 관리하면 nonzero
constraint, no/all/mixed constraint가 같은 수식과 stable order를 사용한다. Full residual은
element end action을 별도로 합산하는 경로보다 조립·하중·해법 전체의 equilibrium을 직접
검증한다.
**결정**: DOF mapping, 제약 적용, 해 복구, residual과 reaction의 의미를 명시적인
수학 계약으로 묶는다. Node/Element에 equation 번호를 분산 저장하지 않는다.
**트레이드오프**: Full K와 네 partition을 유지하는 메모리 비용이 있고 reaction vector의
free entry가 정확한 0이라고 가정할 수 없다. V0에는 penalty, MPC, Lagrange multiplier를
혼합하지 않으며, 추가 constraint policy는 별도 formulation과 equation/output 계약을
요구한다.
**이유**: 서로 다른 space나 enforcement 방식의 값을 같은 물리량으로 오인하지 않게 한다.
### ADR-018: Kernel 존재와 제품 노출을 분리하고 계층형 검증을 요구한다
**트레이드오프**: 새 constraint 방식은 equation과 output의 영향을 함께 검토해야 한다.
원문에 있는 기존 elimination·full-residual 결정은 해당 기능 범위에서 계속 유지되며,
이 공통 요약이 다른 방식을 기존 구현에 적용할 권한을 주지 않는다.
**결정**: Local element/load/recovery kernel이 존재해도 syntax, semantic Domain mapping,
analysis orchestration, mandatory HDF5와 diagnostic 계약이 연결되지 않으면 CLI 지원으로
간주하지 않는다. 검증은 unit, integration, reference comparison, physics sanity를 서로
대체할 수 없는 계층으로 유지한다. Reference가 가능하지 않은 quantity는 명시적 N/A와
analytical/schema/physics 대체 evidence를 요구한다.
### ADR-018: Kernel 존재와 제품 노출을 구분하고 계층형 검증을 요구한다
**이유**: Unit test는 수식과 validation을, integration test는 lifetime과 호출 순서를,
reference comparison은 외부 solver와의 수치 일치를, physics sanity는 공통-mode 오류와
model adequacy를 검출한다. 한 계층의 성공만으로 parser exposure 또는 물리 correctness를
추론하면 지원 범위와 검증 강도가 과장된다.
**결정**: 입력 의미, 내부 해석, 결과·진단과 필수 검증이 연결되어야 제품 기능으로 다룬다.
Local test, integration, reference 비교와 독립 물리 검토는 서로를 대체하지 않는다.
**트레이드오프**: 작은 기능도 여러 계약과 evidence를 함께 준비해야 하므로 개발 속도가
느려진다. 대신 `*DLOAD`처럼 kernel은 있지만 입력에 노출되지 않은 기능, stress처럼
mandatory output이지만 Abaqus reference가 N/A인 기능을 정확하게 표현할 수 있다.
**이유**: 부분 구현이나 외부 수치 일치만으로 제품 지원과 correctness가 과장되는 것을 막는다.
### ADR-019: Abaqus는 입력 형식과 외부 수치 reference이며 FESA 내부 동작 계약이 아니다
**결정**: FESA는 Abaqus와 독립적인 솔버다. 기능별 승인 `.inp` subset을 입력으로
사용하고, 기능이 blocking으로 선언한 FESA HDF5 quantity만 기존 Abaqus CSV와 승인
tolerance로 비교한다. Abaqus 요소 정식화, 적분, stabilization, 내부 상태와 결과 생성
절차를 재현하거나 동등하게 구현하지 않는다. Exact numerical equality는 허용되지만
내부 동작 동등성의 evidence가 아니다.
Reference case readiness에는 선언된 `.inp`, 실제 비교에 필요한 CSV, deterministic
source-ID/component matching과 tolerance만 필요하다. 기존 path와 filename을 그대로
사용하며 canonical naming, legacy-alias 승인, bundle `README.md`, `metadata.json`, Abaqus
version/provenance, 중복 units/coordinates/model/step/frame/material/section 정보와 CSV schema
version은 요구하지 않는다. Reference artifact는 계속 read-only이며 누락, 추가, 중복,
nonfinite required row는 tolerance 전에 실패한다.
**이유**: Reference comparison의 목적은 FESA의 독립 정식화가 승인된 observable quantity를
충분히 가깝게 계산하는지 판정하는 것이다. 수치 비교에 사용되지 않는 artifact
거버넌스가 formulation review나 implementation planning을 차단하면 제품 검증보다 문서
형식 준수가 우선된다. 같은 정보는 `.inp`, CSV header와 feature contract에서 직접 얻을
수 있다.
**트레이드오프**: Reference 생성 환경을 사후에 완전히 재구성하는 감사 기능은 줄어든다.
대신 비교 대상과 source-row/component mapping, tolerance, artifact immutability는 유지해
false match와 결과 보정을 방지한다. 더 강한 provenance가 필요한 기능은 해당 요구조건이
명시적으로 추가할 수 있으나 프로젝트 기본 gate로 자동 승격하지 않는다.
### ADR-020: MITC4 displacement reference는 고정 절대오차로 판정한다
**상태**: S4 artifact 선택과 U blocking/UR warning-only 분류는 유지하며 고정 절대오차
결정은 ADR-022로 대체됨.
**결정**: Full-integration FESA-MITC4의 sole S4 reference comparison은 matched global
`U1/U2/U3` row에 고정 절대오차 `1.0e-5`를 적용해 pass/fail을 판정한다.
`UR1/UR2/UR3`도 고정 절대오차 `1.0e-5`로 비교하지만 초과는 deterministic warning만
생성한다. Reference scale은 보고용 통계로 남을 수 있으나 MITC4 row tolerance 또는
normalized error의 분모를 결정하지 않는다. ADR-014의 B33 component-scale 혼합
tolerance는 변경하지 않는다.
**이유**: Abaqus S4는 FESA-MITC4와 동일한 요소 정식화가 아니므로 B33에서 승인한 매우
엄격한 component-scale tolerance를 그대로 재사용하는 것은 독립 솔버의 observable
displacement 검증 목적에 맞지 않는다. 고정 절대오차는 현재 사용자 단위계에서 승인된
차이를 명시적으로 제한하면서 zero clamp나 row omission 없이 모든 displacement row를
동일하게 판정한다.
**트레이드오프**: Model scale이 크게 달라지면 고정 절대오차의 상대적 엄격도가 달라질 수
있다. 따라서 이 값은 현재 승인된 MITC4 S4 case의 기능 완료 기준이며 개발 완료 후
별도 reference-verification evidence와 함께 재점검한다.
### ADR-021: Semantic definition과 runtime solver contract를 분리한다
**결정**: Domain-owned semantic definition과 analysis-time numerical object를 다음
dependency 방향으로 분리한다.
```text
Domain owns ElementDefinition / ElementProperty / Material / StepDefinition
AnalysisModel is a non-owning stable-index view into Domain
ElementFactory creates runtime Element candidates from compatible definitions
DofManager -> ElementDofLayout
SparseAssembler -> ElementStiffnessContribution
ResultRecovery -> ElementResultBundle
LoadAssembler -> ordered LoadContribution
EssentialConstraintPolicy -> ConstraintDefinition
Analysis <- LinearStaticAnalysis
```
`Domain`의 polymorphic semantic collection은 `std::unique_ptr` 단독 ownership과 stable
vector position을 사용한다. `ElementDefinition`은 source identity, connectivity와
property/material identity를 제공하고 runtime `Element`는 DOF layout, stiffness와 result
recovery를 제공한다. `ElementFactory`가 definition/property/material compatibility를
중앙에서 검사하며 unknown 또는 incompatible 조합은 fail-closed diagnostic으로 거부한다.
Consumer는 B33/MITC4 concrete type branch를 분산시키지 않고 runtime contract를 사용한다.
Linear-static candidate가 runtime `Element`를 `std::unique_ptr`로 소유하고 consumer는 그
수명에 한정된 non-owning view만 사용한다.
`Material` base에는 identity, source location과 lifetime 이외의 future capability를
추가하지 않는다. 현재 isotropic linear elasticity가 실제로 요구하는 data는 concrete
material에 둔다. Density, anisotropy, plastic state, temperature와 rate dependency는
optional field 또는 no-op virtual method로 미리 할당하지 않는다. `ElementProperty`도
현재 beam/shell 의미를 각 concrete type에 둔다.
`Load`는 ordered `LoadContribution`을 생성하고 global full-DOF accumulation은
`LoadAssembler`가 단독 소유한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고
`EssentialConstraintPolicy`가 prescribed-displacement elimination과 reconstruction을
소유한다. Distributed/body load와 MPC/penalty/Lagrange-multiplier enforcement는 이번
결정으로 구현된 기능이 아니다.
Abaqus Domain mapper, result recovery와 HDF5 writer는 기존 public facade를 유지하면서
각각 topology/material-property/step-final-assembly, equilibrium/beam/shell/atomic-state,
RAII/model-result-dataset/self-check/atomic-finalization 책임으로 private implementation을
나눈다.
**이유**: Semantic identity와 runtime kernel을 같은 concrete record에 두면 DofManager,
SparseAssembler, ResultRecovery, parser와 output이 B33/MITC4 storage를 함께 알아야 한다.
Definition/factory/runtime contract와 contribution/policy 경계를 분리하면 stable source
identity와 deterministic reduction owner를 유지하면서 실제 두 element 구현을 공통
consumer로 연결할 수 있다. Focused facade 분할은 외부 계약을 바꾸지 않고 큰 translation
unit의 서로 다른 failure-atomicity 책임을 검토 가능하게 한다.
**트레이드오프**: Base object, factory와 contribution record가 늘고 checked compatibility에
한 단계의 indirection이 생긴다. 대신 `std::shared_ptr`, speculative `Clone()`, global
registry와 future-only material/analysis capability는 도입하지 않는다. B33/MITC4의 승인된
formulation, 연산·reduction 순서, sign, units, coordinates와 result identity가 이
리팩터링보다 우선하며 HDF5 schema, reference artifact와 ADR-014/ADR-020 tolerance는
변경하지 않는다. MITC3, solid, dynamic과 plastic behavior는 별도 feature gate 전까지
구현된 것으로 간주하지 않는다.
### ADR-022: 외부 reference comparison은 공통 family-scale 정책을 사용한다
운영 상수, 검증 순서, report schema와 변경 관리는 `docs/TOLERANCE.md`를 따른다.
**결정**: B33, MITC4와 이후 기능의 외부 reference comparison은 동일한 무차원 수치
정책을 사용한다. 같은 model/case, step/frame, logical quantity, unit dimension, coordinate
system과 blocking behavior의 component family에 대해 reference-only scale
`S=max(abs(reference))`를 계산한다. `abs(reference)<=0.01*S`인 행은
`abs(fesa-reference)<=0.01*S`, 나머지 행은 `abs(fesa-reference)/abs(reference)<=0.05`를
만족해야 한다. 모든 행과 함께 family scale-relative RMS `RMS(error)/S<=0.01`도
통과해야 한다. 독립 absolute-error gate는 두지 않으며 `S=0`이면 모든 FESA 값도 exact
zero일 때만 통과한다.
B33 family는 translation, rotation, reaction force, reaction moment, section force와
section moment로 구분한다. 2026-08-18에 다시 생성된 elemental-force CSV의
`Element Label`과 `Node Label`을 사용해 `(instance, element, endpoint node, component)`를
HDF5 endpoint에 직접 대응하고 node-station collapse나 평균을 사용하지 않는다. MITC4는
translation `U1/U2/U3` family를 blocking으로, rotation `UR1/UR2/UR3` family를
warning-only로 유지한다.
**이유**: Feature별 absolute floor와 fixed absolute tolerance는 모델 단위와 크기에 따라
서로 다른 엄격도를 만들었다. 개별 component scale은 물리적으로 zero-like인 MITC4
`U1/U2` residue를 자체 scale로 만들어 잘못 실패시킨다. 동일 차원의 family scale,
near-zero 대체 분기와 relative RMS를 결합하면 zero row의 불안정한 raw relative error를
피하면서 모든 행과 전체 오차 수준을 함께 검사할 수 있다. B33의 element-endpoint identity는
reference와 HDF5가 제공하는 실제 source identity를 보존한다.
**트레이드오프**: Family 최대값이 작은 component의 허용폭을 결정하므로 행별 relative
gate와 family RMS gate를 모두 유지해야 한다. Reference family 전체가 zero이면 별도
절대 scale이 없으므로 exact-zero만 허용하는 엄격한 fail-closed 정책이 된다. 기존 B33과
MITC4 verification report 및 comparator schema는 새 정책에 맞춰 다시 생성해야 하지만
reference artifact, HDF5 schema, element formulation과 blocking/warning 분류는 변경하지
않는다.
### ADR-023: Nonlinear Static은 prepared dispatch와 accepted-frame evidence로 분리한다
**결정**: CLI는 하나의 `.inp` operand만 받고 input lexical sibling
`<stem>_results.h5`와 `<stem>_log.txt`를 유도한다. `--output`은 지원하지 않는다.
`PrepareAnalysisInput()`이 syntax/semantic map을 한 번만 수행하고, prepared Domain의
procedure identity가 linear static 또는 separate nonlinear full-Newton procedure를 선택한다.
Nonlinear procedure는 trial/committed state, unsymmetric tangent solver와 iteration log를
독립적으로 소유하며 log close 뒤에만 schema-v1 HDF5 writer가 accepted frames를 atomic publish한다.
schema-v1 `/global/equilibrium`의 six values는 global origin `[0,0,0]`에서 current `X+u`
force arm과 spatial physical nodal moments를 쓴 applied-plus-constrained-reaction balance
error다. Accepted free generalized residual과 constrained-reaction resultant는 distinct
projections이며 result dataset을 서로 대체하지 않는다. Nonlinear reference portfolio는 fine
primary `shellNL-meshfine`, coarse companion `shellNL`, linear control `shell`을 분리한다.
External U is blocking, UR is warning-only, local RF/RM is review-only, and RM3/stress is excluded;
the factor-one internal global force/moment balance and accepted free residual remain blocking.
**이유**: Input parse, linear lifecycle, nonlinear trial state와 writer finalization을 한
procedure에 섞으면 output lifetime과 failure atomicity를 검증할 수 없다. Applied-plus-reaction
balance, constrained reaction과 free residual을 구분하면 nonzero prescribed translation/rotation
case에서도 force arm, mask와 rotation-coordinate conversion의 의미가 보존된다.
**트레이드오프**: Nonlinear path는 linear procedure보다 state/backend/writer 수가 늘고 fine
reference run 시간이 길다. 대신 HDF5 authoritative output, immutable CSV artifact와 external
solver internal-algorithm non-equivalence 원칙을 유지하며 local support-force distribution을
blocking tolerance로 위장하지 않는다.
**트레이드오프**: 작은 기능도 여러 종류의 evidence가 필요하다. Reference N/A는 이유와
승인된 대체 근거를 기록하며, 모든 기능에 동일한 benchmark 목록을 강제하지 않는다.
### ADR-019: 외부 solver의 관찰 가능한 의미와 내부 동등성을 구분한다
**결정**: 외부 제품의 공개 입력 의미와 승인된 출력량은 reference로 사용할 수 있지만
비공개 알고리즘·상태·결과 생성 절차를 추정하거나 동등성을 주장하지 않는다.
수치적 exact equality는 허용되지만 내부 동등성의 증거가 아니다.
필요한 source identity·component와 비교 artifact를 사용하며 기존 path와 값을 보존한다.
Canonical naming이나 중복 metadata·provenance를 기본 readiness gate로 추가하지 않는다.
이는 ADR-005·010의 관련 부수 조건을 대체하며 artifact immutability는 유지한다.
**이유**: 물리·수치 검증보다 외부 제품의 비공개 동작 추정이나 문서 형식 맞추기가 앞서지 않게 한다.
**트레이드오프**: 더 강한 provenance가 필요한 경우 별도 명시적 요구가 필요하다.
기본 비교에서도 누락·추가·중복·nonfinite 값과 잘못된 identity는 거부한다.
### ADR-021: Semantic definition과 runtime numerical contract를 분리한다
**결정**: 모델 정의는 identity와 입력 의미를 소유하고, runtime numerical object는
승인된 evaluation·contribution·recovery 계약을 제공한다. 생성 경계가 호환성을 검사한다.
**이유**: Parser와 global consumer가 모든 concrete element/material storage를 알 필요가
없도록 하면서 source identity와 명시적 소유권을 유지한다.
**트레이드오프**: Indirection과 compatibility 검증이 필요하다. Speculative cloning,
global registry와 future-only capability를 도입하지 않는다. 원문 리팩터링의 구현별
설명은 보존본에 있으며 당시 tolerance 참조는 후속 ADR-022와 함께 읽는다.
### ADR-022: 외부 reference comparison에 승인된 공통 정책을 적용한다
**결정**: 외부 reference의 family, scale, near-zero·row·RMS·zero-scale 판정과 보고·변경
관리는 [TOLERANCE](TOLERANCE.md)를 따른다. 기능별 비교량과 identity는 해당 Numerical
Review 및 I/O 계약으로 정의한다. 이 문서는 수치 상수와 판정식을 중복 유지하지 않는다.
**이유**: 기능마다 임의의 scale이나 오차 기준을 적용하거나 구현 결과에 맞춰 기준을
완화하는 일을 방지한다.
**트레이드오프**: 변경 시 관련 comparator와 evidence를 함께 재검증해야 한다.
ADR-014·020의 과거 수치 정책을 대체하지만 artifact 선택·identity·판정 영향 중 유지되는
부분은 원문과 후속 계약을 확인한다. 이번 일반화는 tolerance 변경이 아니다.
## 기능별·대체된 결정의 이관 기록
다음 ID는 프로젝트 공통 결정으로 다시 정의하지 않는다. 원문은
[보존본 ADR](archive/pre-generalization/ADR.md)의 같은 ID에 있으며, 향후 해당
`docs/<feature-id>/ADR.md`를 작성할 때 원래 ID·범위·revision과 대체 관계를 연결한다.
아직 작성하지 않은 Feature ADR을 존재하거나 승인된 문서처럼 링크하지 않는다.
| 기존 ID | 보존할 범위와 상태 | 이관 또는 조회 대상 |
| --- | --- | --- |
| ADR-011 | 구형 검증 진입점 폐기 이력; ADR-012로 대체됨 | 프로젝트 운영 이력 |
| ADR-013 | 최초 end-to-end 기능의 입력·해석 범위 결정 | `linear-static-3d-euler-beam` Feature ADR |
| ADR-014 | 최초 reference baseline 및 비교 계약 이력; tolerance와 projection은 ADR-022로 대체됨 | `linear-static-3d-euler-beam` Feature ADR |
| ADR-020 | 요소 확장의 reference 선택·판정 구분 이력; 수치 정책은 ADR-022로 대체됨 | `linear-static-mitc4-shell` Feature ADR |
| ADR-023 | 별도 procedure, accepted-frame 결과와 CLI 경로 결정 | `nonlinear-static-newton-raphson` Feature ADR; 공통 외부 경로의 후속 결정 근거로도 보존 |
원문의 결정 당시 상태를 현재 release verdict로 해석하지 않는다. 후속 Feature가 범위를
확장했거나 evidence가 stale인 경우 해당 승인 계약과 workflow 상태를 따로 확인한다.
## 공통 개발 운영 결정
### ADR-024: Coordinator가 evidence 기반 workflow와 유한 correction을 소유한다
**상태**: 현재 [agent 운영 계약](SOLVER_AGENT_DESIGN.md)의 기록.
ADR-012의 계획·실행·검증 계층을 보완하며 specialist의 계약 소유권을 변경하지 않는다.
**결정**: Coordinator만 상태를 전이하고 specialist는 할당된 전문 판단과 산출물을
반환한다. 승인된 scope 안의 일반 작업에는 반복 승인 gate를 추가하지 않고 critical
decision만 사용자에게 요청한다. 계획 요청 자체는 실행 권한이 아니다.
동일 normalized `retry_key`의 correction은 한 번으로 제한하고 이후 Implementation
rerun을 한 번 수행한다. Executor transport attempt와 이를 혼용하지 않는다.
필수 evidence가 누락·실패·stale이면 통과시키지 않는다.
**이유**: 일상적인 handoff의 승인 병목을 줄이면서 제품 의미와 외부 권한을 사람이
통제하고, 같은 실패를 무한 반복하지 않게 한다.
**트레이드오프**: Owner, revision, evidence와 실패 signature를 명확히 기록해야 한다.
Release readiness가 외부 게시나 배포 권한을 주지는 않는다.
### ADR-025: 프로젝트 기준과 Feature 문서의 원본·소유권을 분리한다
**상태**: 현재 [Feature 문서 관리](FEATURE_DOCUMENTATION.md) 계약의 기록.
**결정**: 프로젝트 PRD·ARCHITECTURE·ADR에는 공통 기준만 둔다. Coordinator는
Feature의 `FEATURED_AGENTS.md`, `PRD.md`, `ADR.md`, `coordination.md`와 문서
목록·링크를 관리하고 specialist는 자신의 전문 본문과 상세 문서를 소유한다.
상태 원본은 `coordination.md`, 상세 요구사항 원본은 `requirements.md`다.
`FEATURED_AGENTS.md`는 자동 로드되는 프로젝트 지침이 아니므로 dispatch와 Harness
step의 입력에 명시한다. 기본·상세 문서는 같은 Feature/revision과 evidence로 연결한다.
일반 Feature 작업에서 프로젝트 기준을 편집하지 않으며 공통 기준 변경은 별도 요청으로 다룬다.
**이유**: 기능 진행 정보가 공통 지침에 누적되거나 요약과 전문 계약이 서로 다른 원본이
되는 것을 방지한다.
**트레이드오프**: 문서 목록과 상대 링크를 관리해야 한다. 대신 원문 복제를 줄이고
upstream 변경의 영향과 stale evidence를 추적할 수 있다.
### ADR-026: Harness의 구성, Git 소유권과 검증 범위를 신뢰 경계로 관리한다
**상태**: 현재 [Harness skill](../.agents/skills/harness/SKILL.md)과
[프로젝트 지침](../AGENTS.md)의 실행 계약 기록. ADR-002의 구체적 실행 구성과
ADR-012의 운영 설명을 보완한다.
**결정**: 명령은 승인된 계획과 프로젝트 설정·preset·실제 metadata에 대조해 선택한다.
Config와 preset은 실행 가능한 입력이며 Hook이나 `shell=False`만으로 side effect가
격리되었다고 보지 않는다.
범위 밖 사용자 변경은 보존해야 하며, Executor는 branch·step 선택·timestamp·path-scoped
commit을 소유한다. 이 결정 당시 구현은 시작 전 clean 검사를 수행하고 비-phase 변경과
phase metadata를 분리했지만, Step의 소스·테스트 소유 경로를 커밋 시점에 검증하지 않았다.
해당 한계와 실패 분류·기록 보존의 후속 보완은 ADR-027을 따른다.
실행 중 동시 편집을 피하고 범위 밖 변경 발견 시 완료 대신 Coordinator로 반환한다.
Transport attempt는 최대 2회이며 구현이나 상위 계약 실패를
transport 문제로 반복하지 않는다. 권한 확대·원격·파괴 작업에는 명시적 승인이 필요하다.
PreToolUse의 파일 존재 검사는 RED evidence가 아니다. Stop의 문서 전용 생략은
유효한 동일 session/turn의 기록된 편집 대상이 모두 저장소 내부 Markdown인 조건에
한정된다. 기록 누락·손상이나 비문서 기록이면 정상 검증 경로를 따르며, shell 쓰기의
완전한 추적을 보장하지 않는다. 생략·미실행을 build/test 통과로 표시하지 않는다.
**이유**: 자동화가 관련 없는 변경을 commit하거나 검증 범위·권한을 과장하는 것을 방지한다.
**트레이드오프**: 실행 전 상태 검사와 명시적인 evidence가 필요하다. 문서 작업의 정적
검토와 production 변경의 필수 실행 검증을 구분하며, 오래된 운영 문서가 현재 계약을
덮어쓰지 않도록 실제 source와 대조한다.
### ADR-027: Harness의 Step 결과와 커밋 범위를 명시적 계약으로 검증한다
**상태**: 사용자 승인된 Harness 보완 계획(실패 상태 보존, 파일 소유권 검증, 환경 오류
분류)에 따른 결정. ADR-026의 실행 경계를 보완하며 solver·Hook·sandbox 권한을 변경하지 않는다.
**결정**: 프로세스 종료 코드와 Step 보고를 함께 판정한다. 명시적 `error/blocked`는
nonzero에서도 사유를 보존하고 자동 재시도하지 않는다. 인식된 sandbox helper 환경 오류는
종료 코드 0에서도 차단한다. 실제 wrapper timeout으로 결과가 미보고된 경우만 최초 포함
최대 두 번 시도하며, 단순 종료 코드 124나 미분류 nonzero를 transport로 추정하지 않는다.
Executor 소유 `attempt_history`는 원래 보고·프로세스 진단·판정을 재시도와 재개 때 보존한다.
Planning은 Step마다 정확한 상대 파일 목록 `owned_paths`를 작성한다. Executor는 신뢰된
목록으로 매 시도 후·stage 전·commit 전의 변경과 staged 경로를 검증하고 rename 양쪽
경로를 확인한다. 범위 위반 시 사용자 변경을 보존하고 재시도·커밋·다음 Step을 중단한다.
기존 완료 이력은 필드 없이 읽되 pending Step은 실행 전에 승인 목록을 보완해야 한다.
구체적인 schema와 복구 절차는 [Harness skill](../.agents/skills/harness/SKILL.md)과
[동작 과정](HARNESS_WORKFLOW.md)을 따른다.
**이유**: 실패를 재시도로 덮어쓰거나 실행 중 나타난 미승인 파일을 자동 커밋하는 일을 막는다.
**트레이드오프**: 실행할 기존 계획의 파일 목록을 준비해야 하고 실패 이력이 누적된다.
경로 검사는 filesystem sandbox나 동시 writer에 대한 원자적 격리가 아니다. 구현·metadata
커밋도 단일 transaction이 아니므로 뒤쪽 커밋 실패 시 앞선 커밋을 보존하고 오류로 반환한다.
## 후속 ADR 작성 기준
프로젝트 전체의 dependency 방향, 공통 identity·수명·결과 의미, 기술 baseline,
검증 정책 또는 agent 권한이 바뀌면 공통 ADR을 추가한다. 하나의 구현 항목에만
적용되는 선택은 Feature ADR에 기록한다.
각 결정에는 ID, 적용 범위, 상태, 결정, 이유, 트레이드오프, 근거와 영향받는 계약을 둔다.
기존 결정을 변경하면 명시적인 대체·보완 관계와 승인 근거를 남기며 과거 원문과 실패
evidence를 소급 수정하지 않는다. Feature 기록의 형식과 owner는
[FEATURE_DOCUMENTATION](FEATURE_DOCUMENTATION.md)을 따른다.
+213 -456
View File
@@ -1,506 +1,263 @@
# 아키텍처
# FESA 구조해석 솔버 아키텍처
## 목표
FESA의 아키텍처 목표는 Abaqus `.inp` subset을 내부 semantic model로 변환하고, 유한요소 equation system을 구성해 구조해석 결과를 HDF5로 저장하며, reference comparison과 physics sanity가 가능한 C++17/MSVC 솔버 구조를 제공하는 것이다.
## 목적과 적용 범위
FESA의 element formulation과 numerical path는 Abaqus와 독립적이다. Abaqus `.inp`는
승인된 입력 형식이고 Abaqus CSV는 기능별 blocking quantity의 외부 수치 reference다.
Abaqus 내부 적분, stabilization, state 또는 recovery 동작은 FESA architecture contract가
아니다.
FESA는 유한요소법 기반 구조해석 솔버를 단계적으로 구축한다. 이 문서는
[PRD](PRD.md)의 제품 목표를 공통 책임, 의존성, 데이터와 수명 경계로 연결한다.
특정 요소·재료·하중의 정식화, 해석 알고리즘, 코드 목록 또는 구현 완료 현황은 다루지 않는다.
핵심 품질 속성:
- FEM formulation traceability
- explicit I/O contracts
- sparse linear algebra backend isolation
- deterministic verification
- incremental feature addition
- Harness 기반 TDD
구체적인 API, 수식, 실행 순서와 결과 schema는 `docs/<feature-id>/`의 승인된
정식화·I/O·구현 계약에서 정의한다. 아래의 책임 모델은 아직 없는 클래스, 공통 base,
state field 또는 디렉토리를 미리 만들라는 지시가 아니다. 기존 구현의 승인된 의미를
일반적인 설명에 맞추어 변경하지 않는다.
현재 승인된 V0 end-to-end 기능은 `linear-static-3d-euler-beam`이다. 상세 계약의
source of truth는
`docs/superpowers/specs/2026-08-08-linear-static-3d-euler-beam-design.md`이며, 이 문서는
그 계약을 전체 solver architecture의 모듈과 데이터 흐름에 배치한다. 아래에 나타난
비선형, 동적, thermal 및 다른 element 계층은 장기 확장 경계이며 V0 지원 범위가 아니다.
설계 결정과 변경 근거는 [ADR](ADR.md), 코드 규약은 [CODINGSTYLE](CODINGSTYLE.md)을
따른다. 현재 프로젝트의 기술 선택은 [AGENTS.md](../AGENTS.md)와 실행 가능한
build/configuration에서 확인한다.
## 현재 구현된 디렉토리 구조
```text
include/fesa/ # backend-neutral public C++ API
src/
fesa/
analysis/ # Analysis lifecycle, V0 LinearStaticAnalysis
app/ # CLI application and main
assembly/ # deterministic stiffness/load assembly, ParallelFor adapter
constraints/ # essential-constraint elimination and reconstruction
core/ # source identity, status, diagnostics
elements/ # current B33/MITC4 kernels and recovery
fem/ # DOF/equation numbering and sparse pattern
io/
abaqus/ # .inp syntax reader and semantic Domain mapper
hdf5/ # private HDF5 writer and atomic finalization
math/ # owning Vector, row-major Matrix, 0-based CSR SparseMatrix
model/ # concrete V0 semantic records and immutable Domain
results/ # recovery records, full residual, ResultsWriter boundary
solvers/
linear/ # LinearSolver interface and MKL PARDISO adapter
tests/
unit/ # local contracts and failure paths
integration/ # analysis orchestration and CLI contracts
reference/ # HDF5-to-Abaqus projection and comparison
reference/
<case-dir>/ # declared read-only Abaqus input/required CSV pair
.agents/
skills/ # Harness and review skills
.codex/
hooks.json # PreToolUse/Stop hook registration
agents/ # FESA workflow custom agents
skills/ # FESA solver workflow skills
docs/ # Product, architecture, ADR, workflow artifacts
scripts/
execute.py # Phase step executor
hooks/ # PreToolUse/Stop hook implementations
msvc_harness/ # MSVC project discovery and validation adapters
phases/ # Optional generated phase plans
```
## 아키텍처 원칙
`materials/`, `properties/`, `loads/`와 checked `ElementFactory`는 승인된 C++ modular
refactoring의 target boundary이며 후속 implementation Step에서 추가한다. 이
documentation-only Step 시점에는 현재 구현 디렉토리로 표시하지 않는다. Density,
plasticity, anisotropy, nonlinear/dynamic analysis, MPC/penalty, history output과 production
validation module은 계속 장기 확장 경계이며 별도 승인 기능이 필요하다.
- 물리·수치 의미는 외부 파일 형식과 vendor API보다 독립적인 계약으로 유지한다.
- 모델 정의, 현재 실행 view, equation 구성, mutable state와 결과의 소유권을 구분한다.
- Local physics 계산과 global topology, assembly, constraint, solve 책임을 분리한다.
- Identity, units, coordinates, ordering과 failure 의미를 경계마다 명시한다.
- Candidate를 완성·검증한 뒤 계약된 state나 authoritative output에 반영한다.
- 병렬화와 최적화에서도 결정적인 ordering과 failure preservation을 유지한다.
- 실제 승인된 사용 사례에 필요한 최소 확장만 도입한다.
## Harness Execution Layer
Harness는 solver core와 분리된 세 계층의 개발 운영 인프라다.
- 계획 계층: `.agents/skills/harness`가 사용자 승인 전 Step 초안을 만들고, 승인 후 `phases/` 파일을 생성한다.
- 실행 계층: `scripts/execute.py`가 `feat-<phase-name>` 브랜치에서 Step마다 독립 Codex 세션을 실행하고 상태와 커밋을 관리한다.
- 검증 계층: `.codex/hooks.json`이 `scripts/hooks/pre_tool_use.py`와 `scripts/hooks/stop_validation.py`를 연결한다. Stop 검증은 `scripts/msvc_harness/`를 통해 MSVC build와 test를 실행한다.
Runner는 `git add -A`를 사용하므로 clean worktree 또는 별도 Git worktree가 실행 전제다. 전체 동작 계약은 `docs/HARNESS_WORKFLOW.md`, 설치와 `.harness/config.json` 설정은 `docs/HARNESS.md`를 source of truth로 삼는다.
## CMake target과 dependency graph
Root CMake project는 C++17, extension off, CMake 3.25 이상을 요구하고
`cmake/FesaDependencies.cmake`, `src/fesa`, `tests`를 차례로 구성한다.
## Solver runtime과 개발 운영 영역
```text
MKL CONFIG package ─> Fesa::MKL ─┐
TBB CONFIG package ─> Fesa::TBB ─┼─> fesa_solver (STATIC) ─> fesa_cli
HDF5 CONFIG package ─> Fesa::HDF5 ─┘ │
├─> fesa_unit_tests
approved local GoogleTest source ─> GTest targets ├─> fesa_integration_tests
└─> fesa_reference_tests
Solver runtime
입력 adapter → semantic model → analysis procedure → recovery/results → 출력 adapter
│
├─ DOF / equation / sparse pattern
├─ element / material / load contribution
├─ assembly / constraint policy
└─ numerical backend
개발 운영 영역
사용자 요구 → Coordinator → 담당 specialist → 산출물과 evidence → gate 판정
│
└─ 할당된 계획 / Harness / 코드·테스트·문서 변경
```
- `FESA_GTEST_SOURCE_DIR`는 네트워크 fetch 대신 승인된 local GoogleTest source checkout을 가리키는 필수 cache path다.
- MKL, TBB, HDF5는 CONFIG package로 탐지한다. Package search가 설치를 찾지 못하면 `MKL_DIR`, `TBB_DIR`, `HDF5_DIR`를 configure 때 지정한다.
- Package별 imported target 이름은 `Fesa::MKL`, `Fesa::TBB`, `Fesa::HDF5`로 정규화한다. Product module은 vendor target 이름을 직접 선택하지 않는다.
- HDF5 package가 shared와 static C target을 모두 제공하면 approved Windows environment에서는 shared target을 우선한다. Static archive의 숨은 compiler-runtime 요구가 link interface 밖으로 새는 것을 피하기 위한 결정이다.
- `fesa_solver`는 외부 dependency를 `PRIVATE`으로 link하고 `/W4 /WX`를 사용한다. 따라서 public header는 MKL/TBB/HDF5/Win32 type을 포함하지 않아야 한다.
- Test executable은 unit, integration, reference 경계를 분리하며 `fesa_tests` target은 세 executable을 build하는 aggregate target이다. Reference target에만 source/build root compile definition을 제공한다.
첫 흐름은 해석 데이터의 전달을, 두 번째는 개발 작업과 검증의 흐름을 나타낸다.
Agent, prompt, phase 파일과 Harness는 solver runtime API나 물리 모델의 일부가 아니다.
개발 운영 영역은 저장소의 변경과 검증을 통제하며 solver가 실행 중 이를 호출하지 않는다.
### Windows runtime closure
## 공통 책임과 의존성
Configure 성공은 executable이 GoogleTest discovery 또는 CLI 실행 시 필요한 DLL을 찾는다는
뜻이 아니다. `fesa_cli`와 세 test executable의 POST_BUILD 단계는 TBB, MKL thread/core/default
dispatch, OpenMP, `libmmd.dll`, HDF5를 포함한 imported-target runtime DLL을 executable 옆에
복사한다. 새 dynamic backend를 도입할 때는 link 성공뿐 아니라 clean environment에서의
post-build discovery/실행까지 runtime closure로 다뤄야 한다. 개인 설치 absolute path를
CMake source에 기록하지 말고 config package와 imported target metadata를 확장한다.
아래 명칭은 책임 경계이며 반드시 각각 하나의 클래스나 독립 library를 뜻하지 않는다.
실제 타입과 파일 배치는 승인된 Feature와 현재 코드 구조에서 결정한다.
## 모듈 경계
- `core`는 외부 라이브러리에 의존하지 않는다.
- `io/abaqus`는 syntax와 semantic mapping만 담당하고 해석 알고리즘을 알지 않는다.
- `model`은 Abaqus keyword 문자열이 아니라 solver semantic model을 가지며 `Domain`과
non-owning `AnalysisModel`의 수명 경계를 소유한다.
- `materials`와 `properties`는 Domain이 소유하는 semantic identity와 현재 승인된
isotropic elasticity 및 beam/shell property data만 제공한다.
- `elements`는 Domain-owned `ElementDefinition`, runtime numerical `Element`, checked
`ElementFactory`와 element-local stiffness/recovery contract를 제공한다.
- `fem`의 `DofManager`는 DOF, equation ordering, scatter와 sparse pattern을 소유한다.
- `assembly`는 runtime element contribution과 ordered load contribution을 stable full-DOF
space에 조립한다. Contribution producer는 global storage를 직접 갱신하지 않는다.
- `loads`는 semantic target과 magnitude를 소유하고 ordered `LoadContribution`을 생성한다.
- `constraints`는 `ConstraintDefinition` 생성과 V0 essential BC elimination 및 full/reduced
vector 변환을 분리한다. MPC와 penalty는 현재 범위가 아니다.
- `solvers`는 `LinearSolver` 뒤에 MKL PARDISO 세부 구현을 감춘다. TBB는 `assembly/ParallelFor`, HDF5는 `results/ResultsWriter` 경계 뒤에 각각 격리된다.
- `analysis`는 step/history data를 받아 procedure를 실행하고 solver backend와 result writer를 조율한다.
- `results`는 full residual과 B33/MITC4 rows를 복구하고 backend-neutral writer contract를
제공한다. HDF5 schema 구현은 `io/hdf5`가 담당한다.
- test helper는 production parser/solver 내부 상태를 우회하지 않는다.
| 경계 | 소유하는 책임 | 소유하지 않는 책임 |
| --- | --- | --- |
| Core identity/diagnostic | Source identity, 공통 상태와 진단의 의미 | 파일 문법, 물리 정식화, vendor resource |
| Input adapter | 외부 syntax와 지원 semantics의 검증·mapping | 해석 알고리즘과 acceptance 변경 |
| Model definition | Topology, 재료·property·하중·제약·step 정의와 stable identity | Equation 번호, 해석 중 mutable solution |
| Active model view | 현재 procedure/step에 필요한 모델의 non-owning 참조 | 원본 모델 복사나 수명 소유 |
| Element/material | 승인된 local ordering의 물리 응답과 recovery 계약 | Global equation numbering, 직접 sparse write, 파일 저장 |
| Load definition/evaluation | Target·magnitude·configuration 의미와 ordered contribution | Global vector의 공유 누적 |
| DOF/equation | 활성 DOF, full/free/constrained mapping, numbering, scatter와 sparse pattern | 요소 정식화, 수치 factorization |
| Assembly | Local contribution을 지정된 global structure에 결정적으로 누적 | Physics 재해석, equation 번호의 분산 생성 |
| Constraint policy | 승인된 제약의 equation 적용과 해 복구 의미 | Input syntax나 별도 물리 모델의 임의 도입 |
| Analysis procedure | 필요한 state·해법·반복/종료·commit·recovery lifecycle | Vendor handle이나 concrete storage API의 공개 |
| Numerical backend | 행렬·벡터 연산, 해법 resource와 backend failure translation | Source label의 물리 의미, 입력 모델 해석 |
| Results/recovery | 계산 결과의 물리량·위치·identity와 state 반영 | 저장 파일 layout이나 reference 데이터 보정 |
| Output adapter | 승인 schema로의 serialization, self-check와 finalization | 물리량 정의와 acceptance 판정 변경 |
## 승인된 리팩터링 dependency와 ownership
의존성은 consumer가 명시된 contract를 사용하는 방향으로 둔다. Input/output과 vendor
adapter가 core 계약에 의존하며, public core가 concrete adapter나 vendor/OS 타입에
의존하지 않는다. Interface와 implementation의 의존성 방향을 역전하지 않는다.
다음 graph는 C++ object-oriented modular refactoring의 구현 방향을 고정한다. `owns`는
단독 수명 소유권을, 나머지 화살표는 왼쪽 consumer가 오른쪽 contract를 사용한다는
뜻이다. 이 graph는 기존 B33/MITC4 물리 기능을 늘리지 않는다.
Numerical consumer가 요소 종류별 concrete storage를 직접 분기하지 않도록 승인된
evaluation/contribution contract를 사용한다. Definition과 runtime object의 호환성은
지정된 생성 경계에서 검사한다. 이를 위해 speculative registry, 공유 소유권 또는
사용하지 않는 polymorphic capability를 추가하지 않는다.
```text
Domain owns ElementDefinition / ElementProperty / Material / StepDefinition
AnalysisModel is a non-owning stable-index view into Domain
ElementFactory creates runtime Element candidates from compatible definitions
DofManager -> ElementDofLayout
SparseAssembler -> ElementStiffnessContribution
ResultRecovery -> ElementResultBundle
LoadAssembler -> ordered LoadContribution
EssentialConstraintPolicy -> ConstraintDefinition
Analysis <- LinearStaticAnalysis
```
## 데이터 계약
승인된 B33/MITC4 formulation, operation/reduction order, sign, units, coordinates와 row
identity는 이 ownership 리팩터링보다 우선한다. HDF5 schema, reference artifact와
ADR-014/ADR-020 tolerance도 변경하지 않는다.
### Identity
`Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과 `StepDefinition` base
object를 `std::unique_ptr`로 단독 소유하고 const access를 제공한다. Collection position은
기존 stable `EntityIndex` 의미를 유지한다. `AnalysisModel`과 solver consumer는 ownership을
가져오지 않고 Domain 수명 안에서 stable index 또는 const reference만 사용한다.
`std::shared_ptr`, speculative `Clone()`과 global registry는 이 계약에 포함되지 않는다.
다음 개념을 같은 정수나 row 위치라는 이유로 서로 대체하지 않는다.
`ElementDefinition`은 source identity, source element type, connectivity와
property/material identity를 보존하는 semantic object다. Runtime `Element`는 active
`ElementDofLayout`, `ElementStiffnessContribution`과 `ElementResultBundle`을 제공하는
numerical kernel이다. `ElementFactory`만 compatible definition/property/material 조합을
검사해 runtime candidate를 만들며 unknown 또는 incompatible 조합을 기존
`Status`/`Result<T>` diagnostic으로 fail-closed 처리한다. `DofManager`,
`SparseAssembler`와 `ResultRecovery`는 B33/MITC4 concrete storage가 아니라 위 runtime
contract를 소비한다. Linear-static candidate는 runtime `Element`를
`std::vector<std::unique_ptr<Element>>`로 소유하고, consumer에는 그 owner 수명 안에서만
유효한 non-owning `ElementView`를 제공한다.
- Source identity: 외부 입력에서 의미가 있는 label과 instance/scope
- Internal identity/index: 검증된 모델 내부의 안정된 식별 또는 위치
- DOF identity: Entity의 물리 자유도와 component
- Equation index: 특정 procedure의 equation ordering
- Result identity: Entity, quantity, location, component, step/frame과 coordinate 의미
`Material` base는 identity, source location과 수명 의미만 공유한다. 현재 concrete
isotropic linear elasticity에 필요한 capability만 사용하며 density, anisotropy, plastic
state, temperature 또는 rate dependency를 optional field나 no-op method로 미리 추가하지
않는다. `ElementProperty`도 beam/shell이 실제 사용하는 data만 각 concrete type에 둔다.
Renumbering, filtering, 병렬 scheduling과 serialization 뒤에도 필요한 대응 관계를
보존한다. Reference matching은 row 순서가 아니라 계약된 source identity와 component를
사용한다. 특정 typed wrapper나 result-key 클래스를 이 문서만으로 새로 만들지 않는다.
`Load`는 semantic target과 magnitude를 소유하고 source order가 보존된
`LoadContribution`을 생성한다. Global vector의 deterministic accumulation은
`LoadAssembler`만 수행한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고
`EssentialConstraintPolicy`가 prescribed displacement의 stable elimination과
reconstruction을 수행한다. Future distributed/body load와 MPC enforcement는 구현된
기능이 아니며 별도 승인 계약 없이 이 경계에 branch나 optional state를 추가하지 않는다.
### Units, coordinates와 result meaning
책임이 큰 facade는 외부 계약을 유지한 채 private implementation만 다음 owner로 나눈다.
입력 값의 단위계를 임의로 추론하거나 결과에 맞춰 변환하지 않는다. 필요한 dimension,
좌표계, component 순서, 변환과 부호는 정식화 및 I/O 계약으로 고정한다.
서로 다른 위치나 정의의 recovery quantity를 같은 결과로 취급하지 않는다.
Averaging, extrapolation 또는 station 변환은 별도 승인된 의미가 있을 때만 수행한다.
- Abaqus Domain mapping: topology, material/property, step/load/boundary mapping과 final
Domain assembly
- Result recovery: global equilibrium, beam recovery, shell recovery와 atomic state commit
- HDF5 writing: RAII/primitives, model datasets, result datasets, self-check와 atomic
finalization
### 모델, view와 state의 수명
이 분할은 parser diagnostic, `ResultsWriter` boundary, HDF5 schema 또는 final-file
atomicity를 변경하지 않는다.
## V0 입력 경계
V0 parser는 keyword와 parameter를 case-insensitive하게 해석하되 source label의 원문을
보존한다. 지원하는 model/procedure 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`
Part 내부 label은 `SourceEntityId { instance_name, source_label }`로 보존하고 Domain은
별도 stable internal index를 부여한다. 같은 part의 여러 identity instance는 허용하지만
translation/rotation data와 nested assembly는 구조화된 unsupported diagnostic으로
거부한다. 입력 파일당 하나의 static step만 허용하고 두 번째 step은 오류다.
`*PREPRINT`, `*RESTART`, `*TRANSVERSE SHEAR STIFFNESS`, `*OUTPUT, FIELD`,
`*OUTPUT, HISTORY`, `*NODE OUTPUT`, `*ELEMENT OUTPUT`, `*CONTACT OUTPUT` 및 그에 속한
미지원 output variable data는 warning 후 no-op 처리한다. 이 allowlist 밖의 미지원
model-affecting keyword는 오류다. FESA output은 Abaqus output request에 좌우되지 않는다.
## V0 beam과 section 계약
`EulerBeam3D`는 2절점과 절점당 `[UX, UY, UZ, URX, URY, URZ]` 6 DOF를 사용하며 축,
두 방향 Euler–Bernoulli 굽힘과 Saint-Venant 비틀림을 제공한다. Beam tangent를 local
`x`, Abaqus first section axis `n1`을 local `y`, `t x n1`을 local `z`로 둔다.
`*BEAM GENERAL SECTION`의 `A, I11, I12, I22, J`는 `Iy=I11`, `Iz=I22`로 매핑하고
V0는 `I12=0`만 허용한다. `E`, `G`, `A`, `Iy`, `Iz`, `J`는 양수여야 하며 zero-length
element와 tangent에 평행한 guide vector를 scale-aware tolerance로 거부한다.
요소 API는 stiffness, transformation, load와 recovery 책임을 분리한다.
```cpp
Matrix localStiffness() const;
Matrix globalStiffness() const;
Vector localEquivalentLoad(const ConstantLocalLineLoad& load) const;
BeamRecovery recover(const Vector& globalElementDisplacement) const;
```
`localEquivalentLoad`는 formulation의 constant local line-load kernel을 unit test하기
위한 계약이다. V0 parser는 `*DLOAD`나 distributed-load Domain object를 생성하지 않으므로
CLI pipeline에서는 이 kernel을 호출하지 않는다. Stiffness와 recovery는 formulation의
2점 Gauss rule과 부호 규약을 따른다.
## 핵심 객체 모델
```text
Domain
├── owns nodes, sets and source identity
├── owns unique_ptr<ElementDefinition / ElementProperty / Material>
├── owns StepDefinition with Load / BoundaryCondition definitions
└── owns source path/identity and mapping warnings
AnalysisModel
├── non-owning stable-index view into Domain
├── stable active element/BC/load definition indices
└── reachable material/property indices
ElementFactory
└── creates checked runtime Element candidates
Element
├── exposes ElementDofLayout
├── produces ElementStiffnessContribution
└── recovers ElementResultBundle
DofManager
├── owns node x [UX,UY,UZ,URX,URY,URZ] full-DOF numbering
├── owns stable free/constrained order and prescribed values
├── owns element scatter maps
└── owns full-space CSR structural pattern
AnalysisState
├── displacement U
├── external force Fext
├── internal force Fint
├── residual R and full-index reaction
├── StepFrameIdentity
└── endpoint, Gauss and S11 recovery rows
Analysis
└── LinearStaticAnalysis
Vector
Matrix
SparseMatrix
```
위 abstract boundary는 현재 B33/MITC4, isotropic linear elasticity, beam/shell property,
concentrated nodal load, prescribed displacement와 linear static procedure를 연결하는 데
필요한 최소 계약이다. MITC3, solid, dynamic, frequency, heat-transfer와 plastic behavior는
구현된 기능이 아니며 승인된 사용 사례 전에 future-only method나 state를 base에 추가하지
않는다.
## 상태 관리
- `Domain`은 입력 파일에서 만들어진 전체 모델 정의를 `std::unique_ptr`로 단독 소유한다.
파싱 이후에는 가능한 한 불변으로 취급하고 stable collection index를 바꾸지 않는다.
- `LinearStaticAnalysis`가 `Domain`을 소유하고, 그 뒤에 `AnalysisModel`, `DofManager`, `AnalysisState`, stiffness/RHS를 순서대로 만든다. 재사용 시에는 역순으로 해제하여 이전 Domain을 가리키는 view를 남기지 않는다.
- `AnalysisModel`은 현재 step에서 활성화되는 해석 객체들의 실행 view이다. `Domain`을 복사하지 않으므로 Domain이 반드시 더 오래 살아야 한다.
- `DofManager`는 자유도와 방정식 번호를 전담한다. `Node` 또는 `Element` 내부에 equation id를 분산 저장하지 않는다.
- `AnalysisState`는 V0 frame에 필요한 다섯 full-DOF vector와 recovery rows만 소유한다. Velocity, acceleration, temperature, iteration history, nonlinear element state는 해당 procedure가 승인될 때 별도 계약으로 추가한다.
- Result recovery는 모든 candidate vector/row를 검증한 뒤 state에 반영한다. 실패한 recovery가 앞선 유효 state를 부분적으로 덮어쓰지 않아야 한다.
## 데이터 흐름
```text
Abaqus input file
-> syntax parse and semantic mapping
-> immutable Domain 생성
-> 단일 step AnalysisModel view 생성
-> ElementFactory가 compatible definition에서 runtime Element candidate 생성
-> DofManager가 ElementDofLayout으로 DOF/scatter map/sparse pattern 생성
-> ElementStiffnessContribution의 deterministic COO-to-CSR 조립
-> ConstraintDefinition의 stable essential-constraint partition 생성
-> LinearSolver::factorize(Kff)
-> ordered LoadContribution의 full nodal load vector 조립
-> effective RHS = Ff - Kfc * dc
-> LinearSolver::solve(rhs, df) substitution
-> full displacement 복구
-> full residual/reaction = K*d - F 및 ElementResultBundle 복구
-> ResultsWriter로 derived `<stem>_results.h5` atomic finalization
```
### 승인된 Nonlinear Static 경로
`PrepareAnalysisInput()`은 input syntax와 semantic Domain을 정확히 한 번 만든다.
`ExecutePreparedAnalysis()`는 sole static step의 procedure identity로 linear static 또는
nonlinear static executor를 선택하며 두 procedure의 mutable state를 공유하지 않는다.
Nonlinear executor는 committed/trial `NonlinearAnalysisState`, full unsymmetric CSR tangent
solver와 closed-before-finalization Newton iteration log를 소유한다. Completion 뒤
`FinalizePreparedAnalysisResult()`가 selected backend-neutral writer로 only accepted frames를
atomic finalization한다.
Nonlinear schema v1의 factor-one `/global/equilibrium`은 raw full-residual sum이 아니라
global origin `[0,0,0]`에서 current `X+u` force arm과 independently spatialized applied and
masked constrained-reaction moments를 합한 applied-plus-reaction balance error다. Accepted
free residual은 generalized residual의 free mask projection이고 constrained-reaction resultant는
별도 review summary다. 어느 quantity도 다른 quantity의 substitute가 아니다.
강성행렬 factorization은 하중벡터 조립보다 먼저 수행한다. 반력은 element end action의
별도 합이 아니라 조립된 전체 residual에서 구한다. Constrained component는 physical
reaction이고 free component는 equilibrium residual evidence로 full-index vector에 남긴다.
- `Domain`은 전체 모델 정의를 소유하며 검증 이후 가능한 한 불변으로 취급한다.
- `AnalysisModel`은 Domain을 복사하지 않는 non-owning 실행 view다. Domain은 모든
view와 그에 의존하는 계산보다 오래 살아야 한다.
- `DofManager`는 DOF/equation mapping과 sparse pattern을 전담한다. Node나 Element에
equation 번호를 분산 저장하지 않는다.
- Analysis owner는 해당 procedure가 실제로 사용하는 mutable state와 workspace만 소유한다.
재사용·재시도·해제 시 dependent object를 남기지 않는다.
- Trial/committed 구분이 필요한 procedure는 update 실패와 commit 시점을 별도 계약으로
정의한다. 모든 procedure나 material에 이 state를 일괄 추가하지 않는다.
- Recovery와 output은 유효한 candidate를 검증한 뒤 반영한다. 기존 state와 최종 파일의
보존 범위는 성공 경로뿐 아니라 실패 경로에서도 검증한다.
## 해석 실행 흐름
`Analysis` base는 procedure-specific protected hook을 정의하지 않고 최소 실행 계약인
`Analysis::Run(const AnalysisRequest&)`만 제공한다. 다음 여덟 단계의 순서와 fail-fast
경계는 `LinearStaticAnalysis::Run()`의 private lifecycle이며 다른 procedure에 강제되지
않는다.
공통적으로 외부 입력의 의미를 검증하고 실행 모델을 구성한 뒤, 선택된 procedure가
equation과 state를 관리하여 결과를 복구·저장한다. 이것은 책임 수준의 설명이며 모든
procedure에 동일한 반복문이나 고정된 단계 목록을 강제하는 Template Method가 아니다.
| 순서 | Private stage | 주요 작업과 생성되는 소유 객체 | 순서/실패 불변식 |
| --- | --- | --- | --- |
| 1 | `Initialize(request)` | `.inp` syntax read, semantic map, owned immutable `Domain`, sorted warnings | 이전 run의 dependent object를 역순으로 제거하고 parse/map 실패를 input category로 반환한다. |
| 2 | `BuildAnalysisModel()` | non-owning `AnalysisModel` view | Domain을 복사하지 않으며 Domain lifetime 안에서만 사용한다. |
| 3 | `BuildDofMapAndSparsePattern()` | `DofManager`, zero-initialized `AnalysisState` | Stable full/free/constrained numbering과 structural pattern을 한 소유자에게 둔다. |
| 4 | `AssembleAndPartitionStiffness()` | full CSR K와 `Kff/Kfc/Kcf/Kcc` | Element-local buffer를 deterministic하게 reduce하고 structural zero와 stable order를 보존한다. |
| 5 | `Factorize()` | retained `Kff` factorization | 모든 load assembly보다 먼저 호출한다. Valid fully constrained model의 `0 x 0 Kff`는 trivial success다. |
| 6 | `AssembleLoadsAndEffectiveRhs()` | full F와 `Ff-Kfc*dc` | Semantic load source order와 finite sum을 보존하며 solver를 호출하지 않는다. |
| 7 | `SubstituteAndReconstruct()` | free solution과 full displacement | Factorization을 재수행하지 않고 substitution한 뒤 prescribed value를 stable order로 복구한다. |
| 8 | `RecoverAndWriteResults()` | full residual/reaction, B33/MITC4 rows, final HDF5 | Recovery candidate를 원자적으로 commit하고 writer 성공 뒤에만 최종 output을 교체한다. |
각 procedure 계약은 다음을 명시한다.
비선형 정적 및 동적 해석은 V0 범위가 아니며 별도 ADR과 formulation을 승인한 뒤 이
lifecycle과 state/equation 계약을 별도 procedure에 정의한다. LinearStaticAnalysis의
private stage 사이에 조용히 반복·증분·시간 적분 동작을 삽입하지 않는다.
1. 입력 준비와 procedure 선택의 경계, 원본 모델의 owner와 lifetime
2. 필요한 DOF, state, equation, workspace와 초기화 조건
3. Contribution, constraint, factorization/solve와 update의 순서
4. 해당하는 경우 increment, iteration, convergence와 종료 조건
5. 성공 candidate의 commit, recovery와 결과 frame의 의미
6. 실패 category, rollback·재사용 조건과 final output의 보존 범위
## 설계 패턴
- Strategy/Adapter Pattern: `Analysis::Run(const AnalysisRequest&)`, `LinearSolver`,
`ParallelFor`, `ResultsWriter`가 현재 승인된 public 실행/backend 경계다. Vendor API는
concrete adapter implementation 안에만 둔다.
- Procedure-owned lifecycle: `Analysis`는 protected Template Method hook을 공유하지 않고
`LinearStaticAnalysis`가 승인된 여덟 단계 lifecycle을 private하게 소유한다.
- Syntax/Semantic separation: `AbaqusInputReader`는 syntax record를 만들고 `AbaqusDomainMapper`가 승인된 keyword 의미를 concrete Domain record로 변환한다.
- Runtime Polymorphism: backend와 승인된 analysis/element/material/property/load/boundary
경계에만 사용한다. Factory compatibility는 중앙에서 fail-closed로 검사하며 global
registry 또는 future-only capability를 추가하지 않는다.
- RAII: MKL handle, HDF5 file/dataset, temporary solver workspace의 수명과 오류 처리를 wrapper에 묶는다.
정적·동적, 선형·비선형, eigen 또는 contact 계열은 실제 요구와 승인된 계약으로
정의한다. 이 구분을 명시하는 것은 해당 기능이 이미 지원된다는 뜻이 아니다.
기존 절차에 조건문으로 새 physics를 끼워 넣거나, 간결한 공통 그림을 근거로 승인된
연산 순서·reaction·residual·commit 의미를 바꾸지 않는다.
## Sparse Matrix Policy
- Assembly는 element마다 index-addressed contribution buffer를 만들고, join 뒤 COO tuple을 stable order로 정렬해 한 thread에서 순서대로 합산한 후 CSR로 finalize한다.
- `SparseMatrix`는 0-based CSR 데이터를 소유하는 별도 타입이며 dense `Matrix`를
상속하지 않는다. MKL PARDISO backend는 adapter 경계에서 필요한 descriptor와 indexing을
변환한다.
- CSR row offset, sorted-unique column, dimensions, finite values를 construction boundary에서 검증하며 structural zero를 삭제하지 않는다.
- Parallel worker는 global sparse matrix나 shared reduction accumulator를 직접 갱신하지 않는다. Worker별 failure slot과 contribution만 쓰고, deterministic reduction은 join 뒤에 수행한다.
- Matrix symmetry와 factorization/substitution failure는 solver adapter가 구조화된 solver diagnostic으로 번역한다. 승인되지 않은 regularization이나 fallback으로 singularity를 숨기지 않는다.
현재 개별 procedure의 구체적인 실행 계약은 해당 Feature의 formulation·I/O·구현 문서를
확인한다. 기존 프로젝트 문서의 실행 순서와 객체 배치는
[개정 전 아키텍처](archive/pre-generalization/ARCHITECTURE.md)에 이력으로 보존한다.
## Dense Math Policy
## Local 계산, assembly와 constraint
- `Vector`는 contiguous `double` 데이터와 크기를 소유하고 copy, dot, Euclidean norm,
scale, axpy를 MKL CBLAS adapter로 수행한다.
- `Matrix`는 row-major contiguous `double` 데이터와 dimensions를 소유하고
matrix-vector 및 matrix-matrix 연산에 `CBLAS_ROW_MAJOR`를 사용한다.
- 두 타입은 copy/move semantics와 bounds-checked access를 제공한다.
- MKL header와 MKL-specific type은 adapter implementation 밖으로 노출하지 않는다.
Local kernel은 승인된 geometry, material/property, DOF/state와 요청된 계산 범위를 받아
local ordering이 명시된 contribution 또는 recovery 값을 만든다. Global numbering,
공유 matrix 갱신, 파일 lookup, 전체 convergence 판정이나 최종 저장을 수행하지 않는다.
## Parallel Policy
- `ParallelFor`는 `[0,count)` index-addressed 독립 작업만 노출하며 `SerialParallelFor`와 `TbbParallelFor`가 같은 observable contract를 가진다.
- 첫 oneTBB 적용 지점은 element-local stiffness 계산이다. 각 callback은 자기 index의 output slot만 쓴다.
- 전역 sparse write와 부동소수 reduction은 parallel callback 밖의 deterministic 단계로 제한한다.
- MKL 내부 thread와 TBB element loop가 oversubscription을 만들지 않도록 thread count와 task arena 정책을 명시한다.
DOF owner가 지정한 pattern과 scatter를 assembly가 사용한다. Contribution 생성과
누적 순서를 명시하고 병렬 worker는 소유한 buffer에만 기록한다. Join 이후 reduction과
diagnostic 선택은 결정적으로 수행한다. Hash iteration이나 실행 scheduling을
authoritative ordering으로 사용하지 않는다.
## HDF5 Result 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
```
Constraint 방식, full/reduced space, prescribed value, residual과 reaction의 정의는
선택된 procedure의 수학 계약에 포함한다. 서로 다른 enforcement 방식의 결과 의미를
같다고 가정하지 않는다. 특수 차원·빈 시스템·singularity의 처리는 계약에 따라 검증하며
임의의 regularization, zero clamp 또는 fallback으로 실패를 숨기지 않는다.
Schema requirements:
- schema version, units, coordinate system, solver version, source input identity를 metadata에 기록한다.
- field output과 history output을 구분한다.
- reference comparison을 위한 row identity는 node id, element id, integration point id, step/frame id를 포함한다.
- FESA solver는 input lexical sibling `<stem>_results.h5`를 authoritative output으로 쓰며,
같은 directory의 `<stem>_log.txt`는 procedure log다.
- Abaqus reference results는 기능 문서가 선언한 기존 CSV 파일이다. Directory/file
naming, README, metadata 또는 provenance는 architecture readiness 조건이 아니다.
- Verification은 기능이 요구하는 source identity와 component를 결정적으로 대응시키고
승인 tolerance를 적용한다. Missing/extra/duplicate/nonfinite required row는 숫자 비교
전에 실패한다. 단일 step/final-frame 기능은 별도 CSV step/frame 열을 요구하지 않는다.
- FESA HDF5에서 추출한 deterministic CSV view는 optional debugging/review artifact이며 공식 solver output 또는 reference artifact가 아니다.
- Writer는 final과 같은 directory의 임시 HDF5에 전체 schema를 쓴 뒤 flush, checked close,
read-only reopen/self-check를 수행한다. Existing final은 `ReplaceFileW`, 새 final은
`MoveFileExW(..., MOVEFILE_WRITE_THROUGH)`로 완료하며 실패 시 temporary artifact를
정리하고 불완전한 파일을 정상 `<stem>_results.h5`로 노출하지 않는다.
## Numerical backend와 실행 환경
## V0 결과 복구와 reference normalization
Math storage, index convention, matrix capability, resource lifetime과 오류 변환은
backend-neutral 계약으로 노출한다. Vendor header, handle과 OS 타입은 private adapter에
격리한다. Dense와 sparse의 의미가 다르면 하나의 storage hierarchy로 억지로 합치지 않는다.
- Nodal displacement와 reaction은 global `[UX, UY, UZ, URX, URY, URZ]` 순서다.
- Equilibrium end action은 local `[FX,FY,FZ,MX,MY,MZ]`, endpoint section resultant는
`[N,T,My,Mz]`, generalized strain/resultant는 두 Gauss point에 기록한다.
- General beam section stress는 section point의 axial `S11`만 복구한다. Section point가
없으면 centroid `(0,0)`을 `source=fesa-default`로 기록한다.
- 승인된 `reference/cantilever beam/cantilever beam elemental forces.csv`는 각 B33
element의 두 endpoint에 `Element Label`, `Node Label`과 `SF1/SM1/SM2/SM3`을 제공한다.
`(instance, element label, endpoint node label, component)` identity로 HDF5
`[element,endpoint,N/T/My/Mz]`에 직접 대응하고 `SF1 -> N`, `SM1 -> My`, `SM2 -> Mz`,
`SM3 -> T`로 비교한다. External reference comparison은 node-station collapse나 평균을
사용하지 않는다.
- Reference tolerance는 같은 model/case, step/frame, logical quantity, unit dimension,
coordinate system과 blocking behavior의 component family에서 Abaqus-only scale
`S=max(abs(reference))`를 구한다. `abs(reference)<=0.01*S`인 행은 absolute error
`<=0.01*S`, 그 외 행은 relative error `<=0.05`로 판정하며 family scale-relative RMS
`RMS(error)/S<=0.01`도 통과해야 한다. 독립 absolute-error gate는 사용하지 않고
zero-scale family는 FESA도 exact zero일 때만 통과한다. 전체 판정 과정과 report/change
management contract는 `docs/TOLERANCE.md`를 따른다.
- Beam stress는 HDF5 schema와 unit/analytical test로 검증하지만 Abaqus reference
comparison은 N/A다.
Build dependency는 프로젝트가 소유한 target 경계에서 정규화하고, 새로운 dynamic
dependency는 link뿐 아니라 실제 실행에 필요한 runtime closure까지 확인한다.
개인 설치 절대 경로를 소스 계약으로 고정하지 않는다. Thread와 workspace 정책은
실제 workload와 재현성 evidence에 근거하여 관리한다.
## CLI와 diagnostics
현재 target graph와 dependency 선택은 [CMakeLists.txt](../CMakeLists.txt),
[dependency 설정](../cmake/FesaDependencies.cmake),
[solver target](../src/fesa/CMakeLists.txt), [test target](../tests/CMakeLists.txt)과
[CMakePresets.json](../CMakePresets.json)을 확인한다. 이 참조는 다른 toolchain이나
backend를 자동 승인하지 않으며 FESA의 현재 검증 baseline은 프로젝트 지침을 따른다.
```powershell
fesa.exe <model.inp>
```
## 입력, 결과와 진단
CLI는 input과 같은 lexical sibling directory에 `<stem>_results.h5`와
`<stem>_log.txt`를 유도하고 `--output`을 거부한다. Exit code는
`0=success`, `2=usage`, `3=input syntax/semantic mapping`, `4=model validation`,
`5=factorization/substitution`, `6=HDF5 output`으로 고정한다. Diagnostic은 `severity`,
`code`, `file`, `line`, `keyword`, `entity_identity`, `message`를 가지며 stderr에
deterministic한 순서로 출력한다.
Input adapter는 지원되는 외부 syntax, scope, default와 model/history 의미를
검증된 semantic model로 mapping한다. 의미상 무해하다고 계약된 항목만 warning/no-op으로
처리할 수 있으며 나머지 미지원 semantics는 fail-closed로 진단한다.
## 기능 확장 플레이북
Results/recovery가 물리량의 의미를, output adapter가 저장 layout을 소유한다.
Authoritative output과 diagnostic log, debug view, reference artifact를 구분한다.
공식 형식, 파일명, schema version, mandatory dataset과 backward compatibility는
현재 프로젝트·Feature I/O 계약을 따른다. 일반화 때문에 기존의 필수 결과를 optional로
바꾸거나 다른 파일 형식으로 대체하지 않는다.
다음 표는 코드 위치만이 아니라 함께 바뀌어야 하는 계약 경계를 나타낸다. 한 열만
구현하고 다른 열을 생략하면 internal utility 또는 실험 kernel일 수는 있어도 제품 기능은
아니다.
Output은 계약된 임시 candidate에 기록하고 검증·close를 완료한 뒤 최종 결과로 반영한다.
실패 frame이나 불완전한 파일을 정상 결과처럼 공개하지 않는다. 내부 state의 commit과
외부 파일의 finalization은 서로 다른 경계이므로 각각의 failure contract를 정의한다.
| 기능 유형 | 시작 전에 고정할 것 | 주요 구현 경계 | 함께 검증할 것 | 피해야 할 shortcut |
| --- | --- | --- | --- | --- |
| 새 element/material | DOF, interpolation, constitutive law, integration, local axes/sign, feature-approved validity boundary | Domain record와 mapper, element kernel, DofManager scatter/pattern, SparseAssembler, ResultRecovery | feature-required invariants/tests and blocking reference quantities | 서로 다른 물리를 같다고 주장, source ID와 internal index 혼용, 검증 전 범용 hierarchy 추가 |
| 새 load/constraint | Abaqus target grammar, application order, units, follower 여부, prescribed-value 의미 | Syntax/mapper, Domain target, full-space LoadAssembler 또는 constraint partition, diagnostics | set/direct target ambiguity, multi-instance identity, nonfinite sum, `Ff-Kfc*dc`, reaction | Element load kernel 존재를 parser 지원으로 간주, penalty를 elimination에 몰래 혼합 |
| 새 analysis procedure | governing equation, state variables, increment/time lifecycle, tangent/residual, convergence와 output frame | 별도 Analysis implementation, procedure-specific state/equation owner, solver interface extension | orchestration order, failure atomicity, restart/frame identity, numerical benchmark | V0 hook 사이에 조건문으로 반복/시간 적분 삽입, 사용하지 않는 future state 선할당 |
| 새 numerical backend | matrix/index contract, lifecycle, reusable state, failure taxonomy, thread/runtime policy | 기존 `LinearSolver` 또는 `ParallelFor` interface의 concrete adapter, CMake normalized target | empty/dimension/extreme-scale input, repeated call, failed-output preservation, clean runtime discovery | Vendor type을 public header에 노출, silent fallback/regularization, absolute install path 고정 |
| 새 output/reference quantity | 물리 정의, location, sign, units, coordinates, stable row identity, mandatory 여부, tolerance | Result record/recovery, AnalysisState, ResultsWriter/HDF5 schema, comparator projection | schema dtype/shape, ordering, nonfinite rejection, identity inventory, reference N/A 대체 evidence | 서로 다른 result identity 혼합, station mismatch 평균, output request로 mandatory result 제거 |
Diagnostic은 실패 단계, 안정된 code와 메시지, 가능한 source location/entity를 제공한다.
정확한 category, field와 CLI exit code는 I/O 계약을 따른다. Backend 오류를 그대로
누출하거나 내부 failure classification을 새 public exit code로 임의 승격하지 않는다.
모든 확장은 PRD의 제품 완료 정의와 요구조건→정식화→I/O→구현→reference→physics gate를
따른다. 기존 feature contract에 없는 범위를 편의상 “Abaqus compatible”이라고 넓히지 않는다.
## 검증과 reference 경계
## MITC4 확장 경계
검증 coverage와 비교량의 논리적 정의는 Numerical Review, 물리량의 저장·외부 대응은
I/O, 실행 evidence는 Implementation, 독립 물리 판단은 Physics Evaluation이 소유한다.
각 단계는 상위 계약을 결과에 맞춰 수정하지 않는다.
MITC4가 구현될 때 Abaqus `S4`와 `S4R` source type은 같은 FESA formulation을 선택한다.
Source type은 metadata/diagnostic identity로 보존하지만 FESA integration 또는 hourglass
경로를 선택하지 않는다. 6-DOF embedding의 비물리 drilling coordinate에는 physical
rotational stiffness block의 positive minimum diagonal에 `1e-3`을 곱한 고정 numerical
stabilization만 둔다. Drilling calibration, artificial-energy policy와 별도 drilling result
dataset은 이 기능 범위가 아니다.
- Source identity, location과 component 일치 여부를 수치 tolerance보다 먼저 확인한다.
- Missing, extra, duplicate와 nonfinite required value를 숨기지 않는다.
- 외부 reference 판정은 [TOLERANCE](TOLERANCE.md)의 공통 정책을 적용한다. 물리 평형,
정식화와 수렴의 검증 기준은 각자의 계약을 따른다.
- Reference artifact의 naming이나 보조 metadata를 맞추기 위해 파일을 변경하지 않는다.
- 공개 입력 의미나 관찰 가능한 결과 비교를 외부 solver의 내부 동작 동등성으로 해석하지 않는다.
Full-integration FESA-MITC4의 reference comparison은 `reference/shell/` S4의 기존 input 및
displacement CSV만 사용한다. Global `U1/U2/U3` translation family만 blocking이고
`UR1/UR2/UR3` rotation family는 warning-only evidence다. 두 family 모두 ADR-022의 공통
family-scale row/RMS 정책을 사용한다. S4R은
같은 kernel을 선택하는 source mapping과 metadata를 unit/integration tests로 검증하며
`reference/shellR/` artifact는 acceptance comparison에 포함하지 않는다.
구현 존재, 특정 revision의 검증 통과와 현재 release readiness는 별도로 확인한다.
Architecture 문서의 그림이나 모듈명이 기능의 완료 증거를 대신하지 않는다.
Approved nonlinear MITC4 verification은 `reference/shellNL-meshfine/` fine primary,
`reference/shellNL/` coarse companion과 `reference/shell/` linear control을 각각 독립
copied-input directory에서 실행한다. Factor-one global force/moment balance와 accepted free
residual은 blocking internal evidence다. External `U1/U2/U3`는 blocking, `UR1/UR2/UR3`는
warning-only이며 local nodal `RF1/RF2/RF3/RM1/RM2`는 deterministic review-only evidence다;
`RM3`와 stress는 nonlinear numerical comparison에서 제외한다.
## 개발 운영 인프라
공통 agent 상태 전이는 [SOLVER_AGENT_DESIGN](SOLVER_AGENT_DESIGN.md), skill의 역할은
[SOLVER_SKILL_DESIGN](SOLVER_SKILL_DESIGN.md)을 따른다. 실제 실행 절차는
[Harness skill](../.agents/skills/harness/SKILL.md)과 현재 agent/skill profile을 읽는다.
| Owner | 책임 |
| --- | --- |
| Coordinator | Feature 문서 목록·상태, dispatch, evidence gate, revision·retry budget과 closure |
| Specialist | 할당된 stage의 전문 판단, 기본·상세 산출물과 공통 handoff |
| Planning Agent | 할당된 implementation plan과 phase/index/step 계획 파일 |
| Executor | 현재 step 선택, branch, transport attempt, timestamp, path-scoped commit과 phase 진행 |
| Implementation Agent | 선택된 step의 코드·테스트·보고서와 result payload |
| Hook | 도구 호출 전 guardrail과 설정된 종료 검증; TDD 관찰이나 완전한 sandbox의 대체가 아님 |
Coordinator만 workflow를 전이한다. Specialist의 outcome은 전이 요청이고, Harness의
step 상태는 별개의 실행 상태다. Executor transport attempt는 최대 2회이며 동일
`retry_key`의 correction 1회와 뒤따르는 Implementation rerun은 Coordinator가 관리한다.
두 budget을 혼용하거나 실패 문구만 바꿔 반복하지 않는다.
승인된 scope와 할당된 작업 안의 일반 계획·문서·local 실행에는 반복 승인 gate를
추가하지 않는다. 계획 요청만으로 실행을 시작하지 않으며 외부 solver, 원격·파괴 작업과
sandbox 권한 확대에는 해당 명시적 권한이 필요하다.
Project config, preset과 실행 command는 검토해야 하는 실행 입력이다. Hook 통과나
구조화된 argument list만으로 그 side effect가 격리되었다고 간주하지 않는다.
Executor는 시작 전 선택된 phase 제어 파일 밖의 변경을 거부하며 모든 pending Step의
Planning 소유 `owned_paths`를 검증한다. 매 시도 후와 stage/commit 경계에서 신뢰된 목록과
변경·staged 경로를 대조하고 구현 변경과 phase metadata를 분리한다. 범위 밖 변경은
보존하고 재시도·커밋·다음 Step을 중단한다. 이 검사는 동시 writer의 원자적 격리나 여러
커밋의 단일 transaction을 보장하지 않는다. 실행 중 동시 편집을 피한다.
종료 코드와 Step 보고 상태를 함께 판정하며 명시적 실패를 transport 재시도로 덮어쓰지
않는다. 실제 wrapper timeout이고 결과 미보고일 때만 최초 포함 최대 두 번 시도한다.
환경·실패 진단과 원래 보고는 Executor 소유 `attempt_history`에 남기고 재개 때 보존한다.
등록된 Hook을 수동 실행하여 검증 evidence를 대신하지 않는다.
문서 전용 Stop 생략은 기록된 동일 session/turn의 허용된 편집 대상이 모두 저장소 내부
Markdown인 조건에 한정된다. 기록이 없거나 불완전한 읽기 전용 작업과 shell 쓰기까지
안전하게 분류한다고 가정하지 않는다. 생략은 build/test 통과가 아니다.
사용자가 실행을 제외한 문서 작업은 정적 검토와 미실행 항목을 보고한다.
## 문서와 아키텍처의 변경
프로젝트 공통 원칙의 변경은 공통 ADR로, 구현 항목별 선택은 해당 Feature ADR로
기록한다. Feature PRD는 범위와 acceptance 요약을, requirements·formulation·I/O는
전문 계약의 원본을 소유한다. 관리 문서와 기본·상세 산출물은
[FEATURE_DOCUMENTATION](FEATURE_DOCUMENTATION.md)의 소유권과 링크 규칙을 따른다.
Public dependency, identity, 수명, result meaning이나 lifecycle 변경은 영향받는
계약과 evidence를 함께 검토한다. 상위 계약 변경으로 영향받는 evidence는 stale 처리하며,
문서 정리만으로 기존 기능의 재검증이나 release 승인을 완료한 것으로 표시하지 않는다.
개정 전 구현 설명은 [보존본](archive/pre-generalization/ARCHITECTURE.md)에 남긴다.
해당 설명을 Feature 문서로 이관할 때 원래 범위와 승인 revision을 확인한다.
현재 문서는 과거 구현 상세를 삭제하여 계약을 없애거나 미래 API를 선결정하지 않는다.
+1 -1
View File
@@ -26,7 +26,7 @@
## Language와 Toolchain
- Production language는 C++17 이상이며 MSVC x64를 지원해야 한다.
- 승인된 build 기준은 CMake, Visual Studio generator와 Debug configuration이다.
- 승인된 build 기준은 CMake, MSVC x64와 Debug configuration이다. Generator와 명령은 현재 `CMakePresets.json` 및 선택된 Harness 설정을 따르며, 저장소 preset은 MSVC/Ninja를 사용한다.
- C++ compiler extension에 의존하지 않는다.
- MKL, TBB, HDF5와 Win32 type은 public solver core header에 노출하지 않는다.
- Standard library와 RAII를 manual lifetime management보다 우선한다.
+61 -20
View File
@@ -2,8 +2,15 @@
## Requirements
Windows, Python 3.10 이상, Codex CLI가 필요하다. CMake 프로젝트에는 Visual Studio의
Desktop development with C++ 워크로드와 MSBuild, CMake/CTest를 설치한다.
Windows와 Codex CLI가 필요하다. Executor는 Python 3.10 이상을 사용하며, 이 저장소의
계약 테스트는 표준 `tomllib`을 사용하므로 검증 환경은 Python 3.11 이상으로 준비한다.
FESA는 Visual Studio의 Desktop development with C++ 워크로드, CMake/CTest와 Ninja를
사용한다. MSVC x64 developer 환경과 dependency 경로는 [AGENTS.md](../AGENTS.md)의
최소 검증 진입점을 따른다.
역할·승인·상태 전이는 [Agent 계약](SOLVER_AGENT_DESIGN.md)과
[Harness skill](../.agents/skills/harness/SKILL.md)을 따른다. 이 문서는 설치·실행 참고이며
solver Feature의 9개 stage와 evidence gate를 대신하지 않는다.
## 프로젝트 자동 감지
@@ -19,27 +26,44 @@ CMake metadata, 하나의 `.sln`, 하나의 `.vcxproj` 순서다. C/C++가 아
Copy-Item .harness/config.example.json .harness/config.json
```
계획을 승인해 phase 파일을 만든 뒤 Executor를 실행한다.
승인된 Feature와 Coordinator dispatch에 따라 Planning Agent가 할당된 phase 파일을
작성한다. 일반 계획 파일 작성에 반복 승인을 요구하지 않는다. 실행까지 할당된 경우에만
다음 명령을 사용하며, 계획 작성 요청만으로 Executor를 시작하지 않는다.
```powershell
python scripts/execute.py <phase-name>
python scripts/execute.py <phase-name> --push
```
`--push`는 해당 원격 push를 사용자가 명시적으로 승인했을 때만 추가한다. 실행 전
Git top-level은 Harness root와 같고 선택된 phase 제어 파일 밖의 worktree는 clean이어야
한다. 실행 중 동시 편집과 커밋 범위의 한계는 [동작 과정](HARNESS_WORKFLOW.md)을 따른다.
모든 `pending` Step에는 승인된 정확한 상대 파일 목록인 `owned_paths`가 필요하다.
누락된 기존 phase는 Planning의 할당된 준비 작업에서 목록을 보완한 뒤 실행한다.
`[]`는 구현 파일 변경이 없음을 뜻하며 완료 이력에는 목록을 소급 추가하지 않는다.
Executor는 실행 후와 staging/commit 경계에서 소유권을 검사하며 범위 밖 변경은
보존하고 중단한다. 상세 schema와 제한은 [Harness skill](../.agents/skills/harness/SKILL.md)을 따른다.
Executor가 시작하는 Codex 세션은 기본적으로 `workspace-write` sandbox를 사용한다.
Windows native sandbox에서 MSVC compiler-id의 `cl.exe`가 정지하는 것이 재현되고 같은
명령이 sandbox 밖에서 정상 완료되는 경우에만, 사용자 승인을 받은 격리된 clean
worktree에서 다음처럼 해당 실행에 한정해 fallback을 지정할 수 있다.
linked Git worktree에서 다음처럼 해당 실행에 한정해 fallback을 지정할 수 있다.
```powershell
$env:FESA_HARNESS_CODEX_SANDBOX = "danger-full-access"
python scripts/execute.py <phase-name>
Remove-Item Env:FESA_HARNESS_CODEX_SANDBOX
$env:FEM_HARNESS_CODEX_SANDBOX = "danger-full-access"
python scripts/execute.py <phase-name> --approve-danger-full-access
Remove-Item Env:FEM_HARNESS_CODEX_SANDBOX
```
허용값은 `workspace-write`와 `danger-full-access`뿐이다. 후자는 Codex Step에 workspace
밖의 파일 접근 권한도 부여하므로 일반 기본값으로 설정하지 않는다. 어느 모드에서도
`.codex/hooks.json`의 PreToolUse와 Stop hook은 자동으로 실행된다.
`.codex/hooks.json`의 등록된 hook을 비활성화하지 않는다. 환경변수만으로 권한이 승인되지
않으며 Executor는 승인 flag가 없거나 primary/dirty worktree인 권한 상승 실행을 거부한다.
Stop은 유효한 동일 session/turn 편집 기록의 대상이 모두 저장소 내부 `.md`일 때만
build/test를 생략한다. 기록 누락·손상 또는 비문서 편집은 정상 검증 경로를 따른다.
Shell 쓰기나 편집 기록 없는 읽기 전용 요청도 자동 생략을 보장하지 않는다. 문서 작업에서
사용자가 실행을 제외하면 수동으로 Hook·build/test를 실행하지 않고 미검증 사실을 보고한다.
## Harness Python 검증
@@ -47,7 +71,7 @@ Remove-Item Env:FESA_HARNESS_CODEX_SANDBOX
다음 명령으로 실행한다.
```powershell
uv run --with pytest python -m pytest -v -rs
uv run --with pytest python -B -m pytest -v -rs
```
## CMake preset 설정
@@ -62,21 +86,25 @@ uv run --with pytest python -m pytest -v -rs
"projectType": "cmake",
"cmake": {
"sourceDir": ".",
"binaryDir": "out/build/windows-debug",
"configurePreset": "windows-debug",
"buildPreset": "windows-debug",
"testPreset": "windows-debug"
"binaryDir": ".harness/build-ninja-msvc-debug",
"configurePreset": "windows-msvc-ninja-debug",
"buildPreset": "windows-msvc-ninja-debug",
"testPreset": "windows-msvc-ninja-debug"
}
}
```
```powershell
cmake --preset windows-debug
cmake --build --preset windows-debug
ctest --preset windows-debug --output-on-failure
cmake --preset windows-msvc-ninja-debug
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
ctest --preset windows-msvc-ninja-debug --output-on-failure
```
Preset을 쓰지 않는 경우에는 같은 격리된 build directory를 명시한다.
위 예시는 현재 [CMakePresets.json](../CMakePresets.json)과
[config 예시](../.harness/config.example.json)에 맞춘다. Preset 파일이 존재하는 것만으로
Stop이 그 preset을 선택하지는 않는다. 아래는 preset을 쓰지 않는 adapter의 명령 형태이며,
FESA에서는 dependency 경로와 승인된 build 구성을 함께 확인한다.
```powershell
cmake -S . -B .harness/build -A x64
@@ -87,6 +115,9 @@ ctest --test-dir .harness/build -C Debug --output-on-failure
## 직접 MSBuild 설정
다음은 재사용 가능한 Harness adapter의 예시다. FESA 제품 검증은 CMake/CTest를 사용하며
이 예시로 solution-only MSBuild 검증을 대체 승인하지 않는다.
`projectType`을 `msbuild`로 설정하면 `msbuild.solution`, `configuration`, `platform`을
지정한다. 직접 MSBuild 프로젝트에서는 `msbuild.testCommand`가 필수이며, 테스트 실행
파일과 인수를 JSON 배열로 적는다.
@@ -129,11 +160,21 @@ MSBuild.exe MyProject.sln /m /p:Configuration=Debug /p:Platform=x64
## 실패 복구
Executor는 명시적 `error/blocked`를 비정상 종료에서도 보존하며 자동 재시도하지 않는다.
인식된 sandbox helper 환경 오류는 종료 코드 0에서도 Step과 상위 phase를 `blocked`로
기록한다. 실제 wrapper timeout으로 결과를 받지 못했을 때만 최초 포함 최대 두 번 시도한다.
원인 미분류 nonzero와 `completed`/nonzero 불일치는 `error`다. 환경 차단은 종료 코드 2,
일반 실패는 1이며 preflight 실패는 branch/state 변경 전에 반환한다.
- Visual Studio C++ workload가 없으면 Installer에서 Desktop development with C++를 설치한 뒤 다시 실행한다.
- solution 또는 project가 여러 개라서 모호하면 `projectType`과 `msbuild.solution`을 명시한다.
- MSVC가 아닌 컴파일러가 감지되면 MSVC Developer Command Prompt에서 실행하거나 toolchain을 MSVC로 전환한다.
- CTest가 0개 테스트를 보고하면 `enable_testing()`과 테스트 등록을 확인한다.
- 직접 MSBuild 구성에 test command가 없으면 `msbuild.testCommand` 배열을 추가한다.
- timeout 또는 명령 실패 시 Stop 응답의 stage, 안전한 argv 배열, 작업 디렉터리,
종료 코드와 출력 tail을 확인하고 해당 명령을 단독으로 다시 실행한다. Harness는
별도의 로그 파일을 만들지 않는다.
종료 코드와 출력 tail을 확인한다. 실행이 할당된 범위에서만 재현 명령을 수행하며
문서 작업의 검증 제외 지시를 덮어쓰지 않는다. Stop은 별도의 빌드 로그 파일을 만들지 않는다.
- 실패 분류와 재시작 결정은 Coordinator가 기록한다. Planning Agent는 명시적으로 할당된
복구 작업에서만 현재 실패 Step의 status를 `pending`으로 바꾸고, Executor가 재시작 시
오래된 outcome 필드와 timestamp를 정리하되 `attempt_history`는 보존한다. 실패 evidence를 먼저 보존하며
상세 절차는 [Harness skill](../.agents/skills/harness/SKILL.md)의 Recovery and handoff를 따른다.
+148 -69
View File
@@ -4,47 +4,57 @@
Codex 세션에서 Step을 실행하고, MSVC로 C++ 프로젝트를 검증하는 전체 과정을
설명한다. 설치 및 설정 예시는 [Harness 운영 가이드](HARNESS.md)를 참고한다.
Feature의 9개 정규 stage와 Coordinator의 gate 전이는
[Agent 계약](SOLVER_AGENT_DESIGN.md), 역할별 절차는
[Harness skill](../.agents/skills/harness/SKILL.md), 문서 소유권은
[Feature 문서 관리](FEATURE_DOCUMENTATION.md)를 따른다. Harness는 그중 할당된
구현 계획·Step 실행을 지원하며, solver workflow 전체를 대신하지 않는다.
## 1. 핵심 구조
Harness Framework는 다음 세 계층으로 구성된다.
1. **계획 계층**: 요구사항을 분석하고 사용자가 승인할 실행 가능한 Step으로 변환한다.
1. **계획 계층**: 승인된 요구사항과 Coordinator dispatch를 실행 가능한 Step으로 변환한다.
2. **실행 계층**: Step Executor가 Step마다 독립 Codex 세션을 실행하고 상태와 Git
커밋을 관리한다.
3. **검증 계층**: PreToolUse 훅이 편집 전 정책을 검사하고, Stop 훅이 종료 전 MSVC
빌드와 테스트를 실행한다.
빌드와 테스트를 실행한다. 유효한 문서 전용 편집 기록이면 조건부로 생략한다.
전체 흐름은 다음과 같다.
```text
사용자 요구사항
↓
프로젝트 탐색 및 요구사항 논의
Feature의 선행 계약·gate 확인
↓
Step 초안 작성
Coordinator의 bounded Planning dispatch
↓
사용자 승인
Planning Agent의 자기완결적 Step 작성
↓
phases/index.json, task index, stepN.md 생성
↓
Step Executor 시작
실행까지 할당된 경우 Step Executor 시작
↓
각 Step을 독립 Codex 세션에서 실행
├─ 도구 호출 전: PreToolUse 정책 검사
└─ 응답 종료 전: Stop MSVC 빌드·테스트
└─ 응답 종료 전: Stop 검증 또는 문서 전용 조건부 생략
↓
성공: 커밋 후 다음 Step
실패: 수정 또는 최대 3회 재시도
차단: 사용자 개입을 기다리며 중단
transport 실패: 최초 포함 최대 2회 시도
구현 실패·차단: Coordinator로 반환
```
자연어 요구사항만으로 Executor가 자동 시작되지는 않는다. 계획을 사용자가 승인하고
phase 파일을 생성한 다음 `scripts/execute.py`를 실행해야 구현 루프가 시작된다.
자연어 요구사항이나 계획 요청만으로 Executor가 자동 시작되지는 않는다. 승인된 Feature와
dispatch 안의 일반 계획 파일 작성·할당된 실행에 반복 승인 gate를 추가하지 않는다.
권한 상승, 원격·파괴 작업, licensed reference solver 실행은 별도 명시적 승인이 필요하다.
## 2. 요구사항 탐색과 구체화
예를 들어 사용자가 다음 요구사항을 전달했다고 가정한다.
아래 Calculator 예시는 Harness Step 구조를 설명하기 위한 것으로 FESA 제품 요구사항이나
새 기능 구현 지시가 아니다.
> CMake 기반 C++20 라이브러리에 `divide()` 함수를 추가하고, 0으로 나누면 예외를
> 발생시키며 GoogleTest 테스트를 작성한다.
@@ -54,8 +64,10 @@ phase 파일을 생성한 다음 `scripts/execute.py`를 실행해야 구현 루
- `docs/PRD.md`
- `docs/ARCHITECTURE.md`
- `docs/ADR.md`
- Coordinator dispatch와 `docs/<feature-id>/`의 승인된 선행 계약
- 해당 Feature의 `FEATURED_AGENTS.md`, `PRD.md`, `ADR.md`
- 관련 제품 코드와 테스트
- `.harness/config.json`
- `.harness/config.json`이 있으면 그 설정, 없으면 preset·metadata·프로젝트 지침과 감지 기본값
이 탐색을 통해 다음 조건을 구체화한다.
@@ -66,9 +78,9 @@ phase 파일을 생성한 다음 `scripts/execute.py`를 실행해야 구현 루
- 수정할 모듈과 범위 밖 항목
- 실행 가능한 Acceptance Criteria 명령
요구사항에 결정되지 않은 부분이 있으면 구현 전에 사용자와 논의한다. 위 예에서는
예외 타입, 정수 또는 부동소수점 연산 여부, public API와 ABI 변경 허용 여부가 이에
해당한다.
필수 계약이 없으면 Coordinator를 통해 해당 owner로 반환한다. 예외 타입, 수치 타입,
public API·ABI처럼 승인된 의미를 바꾸는 선택은 critical decision 기준에 따라 사용자에게
올린다. 이미 승인된 계약 안의 파일 배치나 테스트 분해는 담당자가 결정한다.
## 3. 요구사항을 Step으로 분해
@@ -80,7 +92,9 @@ phase 파일을 생성한 다음 `scripts/execute.py`를 실행해야 구현 루
- 하나의 모듈 또는 명확한 한 가지 책임만 다룬다.
- 다른 대화 내용을 참조하지 않아도 실행할 수 있도록 자기완결적으로 작성한다.
- 먼저 읽을 문서와 이전 Step의 관련 파일을 명시한다.
- Feature 관리 문서와 승인된 선행 계약의 정확한 경로·revision을 명시한다.
- 클래스와 함수 시그니처 수준으로 작업 범위를 설명한다.
- 수정할 소스·테스트·보고서 파일과 수정하지 않을 upstream 파일을 명시한다.
- 실제 실행 가능한 빌드·테스트 명령을 Acceptance Criteria로 사용한다.
- 성공, 오류, 사용자 개입 필요 상태의 판정 기준을 적는다.
- 범위 밖 기능과 기존 테스트 회귀를 명시적으로 금지한다.
@@ -130,9 +144,10 @@ Step 1: 제품 코드를 구현해 테스트 통과
즉, 테스트가 구현보다 먼저 작성되는 순서는 지키되 각 Step은 최종적으로 green
상태여야 한다.
## 4. 사용자 승인 후 생성되는 파일
## 4. 할당된 계획 산출물
Step 초안을 사용자가 승인한 뒤에만 다음 파일을 생성한다.
Planning Agent는 Coordinator가 할당한 다음 파일을 생성한다. 기존 산출물을 재개할 때는
덮어쓰지 않고 승인된 변경 범위만 갱신한다. Step 번호는 0부터 연속으로 둔다.
```text
phases/
@@ -171,7 +186,8 @@ phases/
{
"step": 0,
"name": "division-api",
"status": "pending"
"status": "pending",
"owned_paths": ["include/calculator.hpp", "src/calculator.cpp", "tests/calculator_test.cpp"]
}
]
}
@@ -179,13 +195,24 @@ phases/
상태별 기록은 다음과 같이 나뉜다.
`owned_paths`는 Planning이 작성하는 정확한 저장소 상대 파일 목록이다. Step 본문의 소유
파일과 일치해야 하며 source/header/test/build/report를 필요한 만큼 명시한다. 디렉터리,
glob, 절대 경로, 경로 이탈, Git 내부와 `phases/` 제어 경로는 허용하지 않는다. 연결된
파일·디렉터리 경로도 지원하지 않는다. `[]`는 구현 파일 변경 없음이며 누락과 다르다.
기존 완료 Step은 필드 없이 읽을 수 있지만 모든 pending Step은 실행 전에 목록이 필요하다.
기존 phase를 일괄 변환하거나 Markdown에서 파일 권한을 자동 추출하지 않는다.
| 상태 | Codex가 기록 | Executor가 기록 |
|---|---|---|
| `completed` | `summary` | `completed_at` |
| `error` | `error_message` | `failed_at` |
| `blocked` | `blocked_reason` | `blocked_at` |
Executor는 task의 `created_at`과 Step의 `started_at`도 기록한다. `summary`는 다음
Executor는 task의 `created_at`과 Step의 `started_at`, `attempt_history`도 기록한다.
History에는 단조 증가하는 `attempt`, `recorded_at`, `exit_code`(프로세스 미기동은 null),
`reported_status`, `reported_reason`, 로컬 `classification`·판정 `reason`과 `diagnostic`을 보존한다.
진단은 stderr 우선, 없으면 stdout의 마지막 4,000자이며 raw output 전체의 대체가 아니다.
Implementation은 `owned_paths`·history·timestamp를 수정할 수 없다. `summary`는 다음
독립 Codex 세션이 이전 Step의 핵심 산출물과 결정을 이해할 수 있도록 한 줄로
작성한다.
@@ -206,13 +233,13 @@ Step은 독립 Codex 실행의 전체 작업 지시서이므로 이전 대화만
## 5. Step Executor 시작
계획 파일을 생성한 뒤 다음 명령으로 실행한다.
계획 파일이 준비되고 실행까지 할당된 경우 다음 명령으로 실행한다.
```powershell
python scripts/execute.py add-division
```
완료된 브랜치를 원격 저장소에 자동 push하려면 `--push`를 추가한다.
완료된 브랜치의 원격 push를 사용자가 명시적으로 승인한 경우에만 `--push`를 추가한다.
```powershell
python scripts/execute.py add-division --push
@@ -220,16 +247,19 @@ python scripts/execute.py add-division --push
[Step Executor](../scripts/execute.py)는 시작할 때 다음 작업을 수행한다.
1. phase 디렉터리와 task index가 존재하는지 검사한다.
2. 이전 실행에서 `error` 또는 `blocked`로 끝난 Step이 있는지 검사한다.
3. `feat-{phase-name}` 브랜치를 생성하거나 checkout한다.
4. `AGENTS.md`와 `docs/*.md`를 guardrail로 읽는다.
5. task의 `created_at`이 없으면 기록한다.
6. 첫 번째 `pending` Step부터 순차 실행한다.
1. phase 경로와 top-level/phase index schema, Step 번호·이름·상태를 검사한다.
2. 현재 첫 미완료 Step이 `error` 또는 `blocked`이면 복구 결정 전까지 중단한다.
3. 모든 pending Step의 `owned_paths`, Implementation Agent profile, Git top-level,
sandbox 승인 조건과 clean 상태를 검사한다.
기본 모드는 선택된 phase 제어 파일 allowlist 밖의 변경을 허용하지 않는다.
4. `feat-{phase-name}` 브랜치를 생성하거나 checkout한다.
5. `AGENTS.md`와 `docs/*.md`를 guardrail로 읽는다.
6. task/Step timestamp와 재개 상태를 정리하고 첫 번째 `pending` Step부터 순차 실행한다.
`AGENTS.md`와 모든 `docs/*.md` 내용은 각 Codex 프롬프트에 직접 삽입된다. 따라서
이 문서들은 참고 자료가 아니라 실제 실행 입력이다. 서로 충돌하거나 placeholder가
남아 있으면 Codex도 그 모순을 입력으로 받는다.
이 문서들도 실행 입력에 포함된다. 역할·승인·상태 전이에서는 Agent 계약과 Harness skill의
권한 경계를 따르며, 설치 예시를 Feature의 요구사항으로 사용하지 않는다. Feature 관리
문서는 자동으로 로드되지 않으므로 dispatch와 Step의 필수 입력 경로에 명시해야 한다.
## 6. Step마다 독립 Codex 세션 실행
@@ -237,24 +267,29 @@ Executor는 각 Step을 다음 형태의 독립 프로세스로 실행한다.
```text
codex exec
--disable unified_exec
--json
--model <implementation-agent profile model>
--config model_reasoning_effort="<profile effort>"
--sandbox <workspace-write|danger-full-access>
--dangerously-bypass-hook-trust
--cd <repository-root>
-
```
기본값은 `workspace-write`다. `FESA_HARNESS_CODEX_SANDBOX` 환경 변수는
기본값은 `workspace-write`다. `FEM_HARNESS_CODEX_SANDBOX` 환경 변수는
`workspace-write` 또는 `danger-full-access`만 허용한다. Windows native sandbox에서
MSVC compiler-id의 `cl.exe` 정지가 재현되고 동일 명령이 sandbox 밖에서 통과하는
환경에서는, 사용자 승인을 받은 격리된 clean worktree 실행에 한해서
`danger-full-access` fallback을 사용할 수 있다. 이 override는 hook trust 또는 hook
등록을 끄지 않으며 PreToolUse와 Stop 검증은 동일하게 실행된다.
환경에서는, 해당 실행 직전 사용자 승인을 받은 clean linked Git worktree 실행에 한해서
`danger-full-access` fallback을 사용할 수 있다. Executor의
`--approve-danger-full-access` flag도 필요하며 환경변수만으로 승인되지 않는다.
이 override는 등록된 hook을 비활성화하지 않는다.
Codex에 전달하는 프롬프트는 다음 내용의 조합이다.
```text
AGENTS.md와 docs 문서
Implementation Agent profile의 역할·수정 경계
+ AGENTS.md와 docs 문서
+ 이전에 완료된 Step의 summary
+ 이전 시도의 오류(재시도인 경우)
+ Executor 공통 작업 규칙
@@ -341,11 +376,19 @@ calculator.test.cpp
적용되지만 경로 기반 TDD 검사는 적용되지 않는다. 따라서 이 훅은 완전한 TDD
증명기가 아니라 테스트 우선 편집을 유도하는 guardrail이다.
PreToolUse는 허용된 편집 도구의 대상 경로를 `.harness/hook-state/`에 기록한다.
이 ignored 기록은 Stop의 문서 전용 판정 입력일 뿐 RED나 실제 편집 성공의 증거가 아니다.
## 8. Codex 종료 전 Stop 검증
Codex가 Step 작업을 끝내고 응답을 종료하려 하면
[Stop 훅](../scripts/hooks/stop_validation.py)이 실행된다. Stop 훅은 변경 파일만이
아니라 발견된 C/C++ 프로젝트 전체를 빌드하고 테스트한다.
[Stop 훅](../scripts/hooks/stop_validation.py)이 실행된다. 유효한 동일 session/turn 기록에서
편집 대상이 모두 저장소 내부 `.md`이면 build/test를 생략한다. 기록 누락·손상 또는 비문서
편집이면 정상 검증 경로에서 발견된 C/C++ 프로젝트 전체를 빌드하고 테스트한다.
Shell 쓰기는 완전히 추적되지 않으며, 편집 기록 없는 읽기 전용 요청도 자동 생략을
보장하지 않는다. 사용자가 문서 작업의 실행을 제외하면 수동 Hook·build/test를 실행하지
않고 정적 검토 범위와 미실행 항목을 보고한다. Hook state를 조작해 생략을 만들지 않는다.
### 8.1 저장소 루트와 재진입 방지
@@ -497,8 +540,10 @@ Harness는 별도 빌드 로그 파일을 생성하지 않는다.
### 11.1 Stop 검증 성공
빌드와 테스트가 모두 성공하면 Stop 훅은 출력 없이 종료한다. Codex가 정상 종료하면
Executor가 task index를 다시 읽는다.
빌드와 테스트가 모두 성공하거나 문서 전용 생략 조건을 충족하면 Stop 훅은 출력 없이
종료한다. 생략은 build/test 통과 evidence가 아니다. Codex가 정상 종료하면 Executor는
branch/HEAD, 제어 파일과 현재 Step 외 상태의 변경 여부를 검사하고 task index를 읽는다.
Codex 종료 코드가 0이 아니면 `completed` 기록만으로 성공 처리하지 않는다.
Codex가 Step을 다음처럼 기록한 경우:
@@ -507,6 +552,7 @@ Codex가 Step을 다음처럼 기록한 경우:
"step": 0,
"name": "division-api",
"status": "completed",
"owned_paths": ["include/calculator.hpp", "src/calculator.cpp", "tests/calculator_test.cpp"],
"summary": "divide API와 0 나누기 테스트를 추가함"
}
```
@@ -520,32 +566,45 @@ Stop 훅은 Codex hook protocol에 따라 다음 형태의 응답을 출력한
```json
{
"continue": false,
"stopReason": "build failed ...",
"systemMessage": "build failed ..."
"decision": "block",
"reason": "build failed ..."
}
```
Codex 프로세스에 대한 훅 자체의 종료 코드는 0이지만 `continue: false`가 Codex의
응답 종료를 막는다. Codex는 같은 세션에서 오류를 확인하고 수정을 계속한다.
훅 자체의 종료 코드는 0이지만 `decision: block`이 종료 차단 이유를 전달한다.
수정은 할당된 역할·Step·retry budget 안에서만 수행하며, Hook 실패가 상위 계약 변경이나
무제한 반복 권한을 주지 않는다.
### 11.3 Executor 재시도
Codex 프로세스가 끝났는데 Step 상태가 `completed` 또는 `blocked`가 아니면 Executor가
새 Codex 세션으로 재시도한다.
Executor는 branch/HEAD·제어 파일·결과 형식과 변경 경로의 소유권을 먼저 검증한 뒤
Step 보고와 프로세스 종료 코드를 함께 판정한다.
| 결과 | 처리 | 자동 재시도 |
| --- | --- | --- |
| 인식된 sandbox helper 환경 오류(종료 코드 무관), CLI 미설치 | Step과 상위 phase `blocked`, 종료 2 | 없음 |
| 명시적 `blocked` 또는 `error`(종료 코드 무관) | 원래 사유 보존, 각각 종료 2 또는 1 | 없음 |
| `completed` + 종료 0 | 소유권·staged 경로 검증 후 커밋 | 없음 |
| `completed` + nonzero | `error`, 종료 1 | 없음 |
| 결과 미보고 + Executor wrapper의 실제 `TimeoutExpired` | transport timeout | 최초 포함 최대 2회 |
| 결과 미보고 + 종료 0, 원인 미분류 nonzero | `error`, 종료 1 | 없음 |
종료 코드 124만으로 timeout을 추정하지 않는다. Wrapper가 실제 timeout을 관찰했을 때만
raw output에 `transportFailure: "timeout"`을 기록한다. 제어·소유권 위반은 이 재시도보다
우선하여 중단한다. 실패 결과를 `pending`으로 덮어쓰지 않고 원래 보고와 프로세스 진단을
Executor 소유 history에 구분해 남긴다.
```text
첫 번째 시도 실패
첫 번째 transport 시도 실패
→ 오류를 다음 프롬프트에 삽입
→ 두 번째 독립 Codex 실행
→ 다시 실패하면 세 번째 독립 Codex 실행
→ 세 번째도 실패하면 error 기록 후 종료
→ 두 번째도 실패하면 error 기록 후 종료
```
즉, 실패 복구에는 두 층이 있다.
1. Stop 훅이 같은 Codex 세션에서 수정하도록 요구한다.
2. 세션 자체가 성공하지 못하면 Executor가 새 세션으로 최대 3회 재시도한다.
Coordinator의 workflow correction은 별도 budget이다. 정규화된
`feature_id|failing_gate|failure_classification|contract_revision`별로 Correction을 최대
한 번, 그 뒤 Implementation rerun을 한 번만 허용한다. 계약·환경·물리 실패를 transport
재시도로 숨기거나 문구만 바꾸어 새 retry key를 만들지 않는다.
### 11.4 사용자 개입 필요
@@ -553,16 +612,21 @@ Codex 프로세스가 끝났는데 Step 상태가 `completed` 또는 `blocked`
`blocked`로 기록한다. Executor는 `blocked_at`과 top-level 상태를 갱신하고 종료 코드
2로 중단한다.
재개하려면 원인을 해결하고 해당 Step을 `pending`으로 되돌린 뒤
`blocked_reason`을 제거하고 다시 실행한다. `error`도 같은 방식으로 `pending`으로
되돌리고 `error_message`를 제거한 뒤 재실행한다.
재개 전 Coordinator가 원인 분류, 실패 evidence, retry key와 허용된 다음 작업을
`coordination.md`에 보존한다. Coordinator는 phase 파일을 직접 편집하지 않는다.
명시적으로 할당받은 Planning Agent가 Executor가 중단된 상태에서 phase index의 현재
실패/차단 Step status만 `pending`으로 변경한다. 다른 Step, top-level 상태와 timestamp는
변경하지 않는다. Executor가 재시작 시 오래된 outcome 필드·timestamp를 정리하되
`attempt_history`는 유지한다. 기존 Step에 `owned_paths`가 없으면 승인 목록을 작성하는
별도 Planning 할당이 필요하며 status 복구 권한만으로 목록을 추가·확대하지 않는다.
이는 할당된 파일 편집 절차이며 자동 복구 명령이나 추가 correction 허용이 아니다.
## 12. Git 커밋과 phase 완료
Step이 성공하면 제품 변경과 Harness metadata를 분리해 다음 형식으로 커밋한다.
```text
feat(add-division): step 0 — division-api
feat(add-division): step 0 - division-api
chore(add-division): step 0 output
```
@@ -577,9 +641,21 @@ chore(add-division): step 0 output
- 최종 metadata 커밋
- `--push` 사용 시 `origin/feat-{phase-name}`으로 push
커밋 과정은 `git add -A`를 사용한다. 실행 전에 작업 트리에 관련 없는 사용자
변경사항이 남아 있으면 그 변경도 Step 커밋에 포함될 수 있다. 따라서 깨끗한
worktree 또는 별도 Git worktree에서 실행하는 것이 안전하다.
Executor는 신뢰된 `owned_paths` snapshot으로 매 시도 후와 staging 직전의 변경 경로를
검사한다. tracked/untracked, staged/unstaged, 생성·수정·삭제와 rename 양쪽 경로가 대상이다.
Windows 경로 구분자·대소문자 alias를 정규화하며 디렉터리·링크 대체도 다시 검사한다.
범위 밖 변경이 있으면 index를 정리하기 전에 중단하고 해당 경로와 사용자 파일을 보존한다.
검사 후 검증된 경로 snapshot에 한정해 index만 정리하고
`git --literal-pathspecs add -A -- <선택 경로>`를 사용한다. 저장소 전체 index를 reset하지 않는다.
Commit 직전에는 `git diff --cached --name-only --no-renames -z`의 실제 staged 경로도
선택된 커밋 그룹과 대조한다. 구현 커밋에 phase metadata가 섞이는 것도 거부한다.
범위 위반 시 추가 stage/commit·재시도·다음 Step을 중단하며 파일을 되돌리거나 allowlist를
자동 확대하지 않는다. staging 후 발견한 위반은 당시 index를 남기므로 재개 전 검토가 필요하다.
동시 writer에 대한 원자적 격리는 보장하지 않으므로 실행 중 동시 편집을 피한다. 구현·metadata
커밋도 단일 transaction이 아니다. 구현 커밋 후 metadata 커밋이 실패하면 기존 커밋을
되돌리지 않고 Step을 `error`로 기록해 Coordinator에 반환한다.
## 13. 요구사항 종류별 동작
@@ -589,7 +665,9 @@ worktree 또는 별도 Git worktree에서 실행하는 것이 안전하다.
| 기존 C++ 구현 또는 header 수정 | 대응 테스트 파일 존재 여부 검사 | 전체 빌드·테스트 |
| 테스트 파일 추가 | TDD 차단 없이 허용 | 모든 테스트가 성공해야 종료 |
| `main.cpp` 수정 | TDD 대응 테스트 검사 면제 | 전체 빌드·테스트 |
| 문서, JSON, Python 수정 | C++ TDD 검사 없음 | C++ 프로젝트가 있으면 전체 검증 |
| 유효한 동일 session/turn 기록의 내부 `.md` 편집만 있음 | C++ TDD 검사 없이 경로 기록 | build/test 생략, 통과 evidence 아님 |
| JSON, Python 또는 다른 비문서 편집 | C++ TDD 검사 없음 | C++ 프로젝트가 있으면 전체 검증 |
| 편집 기록 없음·손상 또는 shell 쓰기 | 완전한 편집 추적을 보장하지 않음 | 문서 전용 자동 생략을 보장하지 않음 |
| 위험한 Git 또는 삭제 명령 | 즉시 차단 | 도달하지 않음 |
| C++ 파일은 있지만 build metadata 없음 | 편집은 허용될 수 있음 | orphan 프로젝트 오류 |
| 직접 MSBuild인데 `testCommand` 없음 | 편집은 허용될 수 있음 | 설정 오류로 종료 차단 |
@@ -597,18 +675,19 @@ worktree 또는 별도 Git worktree에서 실행하는 것이 안전하다.
## 14. 적용 전 준비사항
이 저장소는 대상 C++ 프로젝트에 맞게 채워 사용하는 템플릿이다. 실행 전 다음을
확인한다.
FESA는 실제 구조해석 솔버 프로젝트이며 Harness는 재사용 가능한 개발 운영 인프라다.
일반 Feature 실행 전에 다음을 확인한다.
1. `AGENTS.md`의 프로젝트명, toolset, C++ 표준, 테스트 프레임워크, CRITICAL 규칙을
실제 값으로 교체한다.
2. `docs/PRD.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md`의 placeholder와 예시를 실제
프로젝트 정보로 교체한다.
1. `AGENTS.md`, 공통 PRD·ARCHITECTURE·ADR와 승인된 Feature 범위를 읽는다.
2. Feature 관리 문서·선행 계약·revision과 Planning/Implementation dispatch를 확인한다.
일반 Feature 작업에서 프로젝트 공통 문서를 템플릿처럼 다시 작성하지 않는다.
3. 기본 자동 감지로 충분하지 않을 때만 `.harness/config.example.json`을 참고해
`.harness/config.json`을 만든다.
4. CMake 또는 MSBuild metadata와 테스트 실행 방법을 확인한다.
5. `phases/`가 없다면 요구사항 논의와 계획 승인을 거쳐 task 파일을 먼저 만든다.
6. Executor 실행 전에 Git working tree가 깨끗한지 확인한다.
4. FESA의 CMake/MSVC x64 Debug·CTest 명령과 dependency 경로를 확인한다. 다른 저장소에
Harness를 적용할 때만 그 프로젝트의 승인된 adapter를 선택한다.
5. phase 파일이 없다면 Planning Agent가 할당된 파일을 작성한다. 실행 권한은 별도로 확인한다.
6. 시작 전 clean 범위와 실행 중 동시 편집 여부를 확인한다. 권한 상승은 clean linked
worktree, native sandbox 실패 증거와 해당 실행 직전 승인·flag가 모두 필요하다.
특히 `AGENTS.md`와 `docs/*.md`는 각 Codex 실행에 그대로 주입된다. C++ 프로젝트에서
TypeScript 예시나 미완성 placeholder가 남아 있으면 실제 작업 지시와 충돌할 수 있다.
+129 -160
View File
@@ -1,179 +1,148 @@
# PRD: FESA 구조해석 솔버
## 목표
FESA는 Abaqus `.inp` keyword subset을 입력으로 받아 자체 유한요소 정식화로 구조해석을
수행하고, step/frame 단위 결과를 input lexical sibling `<stem>_results.h5` HDF5로 저장하며, 기능이 지정한 Abaqus
reference CSV 수치와 비교 가능한 C++17/MSVC 솔버를 제공한다. Abaqus의 요소 알고리즘,
적분법, stabilization 또는 내부 결과 생성 절차를 재현하는 것은 목표가 아니다.
## 제품 정의
이 프로젝트의 성공 기준은 단순 실행 성공이 아니다. 기능 구현은 요구조건, 정식화,
I/O 계약, C++ build/test와 기능별 blocking reference comparison을 통과해야 완료된다.
Physics sanity와 release readiness는 구현 완료 뒤 별도 배포 판단을 제공하며 Abaqus 내부
동작 동등성을 요구하지 않는다.
FESA는 유한요소법 기반 구조해석 솔버를 단계적으로 구축하는 프로젝트이다. 물리적으로
설명 가능하고 재현 가능한 해석 결과를 제공하며, 새로운 기능을 요구사항부터 독립 검증까지
추적 가능한 단위로 확장하는 것을 목표로 한다.
## 사용자
- Solver developer: C++17/MSVC/CMake/CTest 환경에서 요소, 재료, 해석 절차, solver backend를 구현한다.
- Verification reviewer: reference artifact, tolerance, physics sanity, release readiness를 검토한다.
- Analyst preparing Abaqus-compatible input subsets: FESA가 지원하는 제한된 `.inp` subset에 맞춰 입력 모델을 준비한다.
- Codex agent workflow operator: project-local agent와 skill을 사용해 요구조건부터 release까지의 gate를 운영한다.
이 문서는 특정 요소, 재료, 하중 또는 해석 절차의 명세가 아니라 모든 Feature에 적용되는
제품 기준이다. 개별 지원 범위, 입력 옵션, 수식, 수치 기준과 검증 사례는
`docs/<feature-id>/`의 승인 계약으로 정의한다. 특정 기능의 코드가 존재한다는 사실과
그 기능의 검증 완료 또는 현재 release readiness는 서로 다른 상태다.
## 핵심 기능
1. Abaqus `.inp` keyword subset parser와 내부 `Domain` semantic model 생성
2. `AnalysisModel`, `DofManager`, `AnalysisState` 기반의 step별 equation system 구성
3. 선형 정적 해석을 시작점으로 하는 `Analysis` procedure 계층
4. Stable source identity를 보존하는 concrete V0 node, B33 element, material, section, boundary, load record
5. sparse matrix pattern 생성, 전역 행렬/벡터 조립, 제약조건 적용
6. `LinearSolver`, `ParallelFor`, `ResultsWriter` interface를 통한 MKL PARDISO, oneTBB, HDF5 backend 격리
7. HDF5 기반 versioned step/frame field-result 저장과 향후 history-output 확장 경계
8. FESA HDF5 rows와 `reference/<model-id>/` 아래 Abaqus reference CSV rows의 직접 비교
9. CMake/MSVC/x64/Debug, CTest 기반 개발 검증
현재 선택된 기술 스택과 외부 형식은 [프로젝트 지침](../AGENTS.md) 및 승인된 계약을
따른다. 공통 문서의 일반화는 기존 지원 범위, 파일 형식, 수치 정책 또는 호환성을 변경하는
승인이 아니다.
Element/material 계층의 일반적인 runtime polymorphism, iterative solver, history output은 장기 확장 방향이다. 현재 제품 계약으로 간주하지 않으며, 실제 사용 사례와 성능·수명 요구가 승인되기 전에 추상 base class를 미리 추가하지 않는다.
## 대상 사용자
## 사용자 관점 제품 흐름
- Solver 개발자: 요소, 재료, 하중, 제약, 해석 절차와 수치 backend를 구현한다.
- 해석 사용자: 문서화된 입력 범위로 모델을 구성하고 결과와 진단을 해석한다.
- 검증 담당자: 수학적 일관성, 물리적 타당성, reference 비교와 회귀 evidence를 검토한다.
- Maintainer와 workflow 운영자: 요구사항, 결정, 구현과 검증의 추적성 및 변경 범위를 관리한다.
1. 사용자는 승인된 Abaqus `.inp` subset으로 모델과 단일 analysis step을 기술한다.
2. FESA는 syntax를 읽은 뒤 semantic mapping과 model validation을 수행한다. 지원하지 않는 모델 의미는 구조화된 diagnostic과 안정된 exit code로 거부한다.
3. 해석 procedure는 active model view, DOF/equation map과 sparse system을 만들고, essential constraint elimination을 적용해 선형계를 factorize하고 substitution한다.
4. FESA는 full displacement를 복구하고 equilibrium residual/reaction과 element 결과를 계산한다.
5. 성공 시 output request와 무관한 mandatory 결과, metadata와 diagnostic을 versioned lexical sibling `<stem>_results.h5`에 기록한다. 실패 시 불완전한 최종 결과 파일을 정상 결과처럼 남기지 않는다.
6. 검증 workflow는 기능이 지정한 HDF5 quantity를 기존 Abaqus CSV의 source identity와
component에 대응시켜 tolerance를 판정하고, 별도로 equilibrium과 물리적 타당성을
검토한다. Reference bundle naming이나 provenance는 수치 비교 gate가 아니다.
## 제품 목표
Parser keyword, element kernel, solver backend 또는 output dataset 중 하나만 추가된 상태는 end-to-end 제품 기능이 아니다. 같은 기능의 입력 의미부터 외부 결과와 검증까지 연결되어야 한다.
1. 해석의 물리·수치 의미를 입력부터 결과까지 보존한다.
2. 작은 Feature를 end-to-end로 완성한 뒤 검증된 기반 위에서 지원 범위를 확장한다.
3. 모델 의미, 계산 상태, 수치 backend와 저장 형식의 책임을 구분한다.
4. 같은 입력과 승인된 실행 조건에서 source identity, 조립·결과·진단 순서를 재현한다.
5. 잘못되거나 지원하지 않는 모델 의미를 조용히 근사하지 않고 명확히 진단한다.
6. 요구사항, 설계 결정, 구현, 테스트와 검증 결과를 같은 Feature와 contract revision으로 연결한다.
## V0 범위
- 선형 정적 해석 파이프라인 구현
- 승인된 첫 end-to-end 기능: 2절점 3D Euler–Bernoulli beam, Abaqus `TYPE=B33`
- 입력 파일당 하나의 `*STEP, *STATIC`
- 절점당 자유도 `[UX, UY, UZ, URX, URY, URZ]`
- 축, 두 방향 굽힘, Saint-Venant 비틀림 및 선형 등방 탄성
- 최소 Abaqus keyword subset:
- `*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`
- `*PREPRINT`, `*RESTART`, `*TRANSVERSE SHEAR STIFFNESS`, `*OUTPUT, FIELD`,
`*OUTPUT, HISTORY`, `*NODE OUTPUT`, `*ELEMENT OUTPUT`, `*CONTACT OUTPUT`과 그에 속한
미지원 variable data는 warning 후 no-op 처리
- 같은 part의 여러 identity instance와 stable source label mapping
- nonzero prescribed displacement를 포함한 free/constrained partition
- formulation의 constant local line-load equivalent nodal vector kernel. V0 parser와 CLI는
`*DLOAD`를 지원하거나 이 kernel을 호출하지 않음
- deterministic COO-to-CSR stiffness assembly
- MKL PARDISO 기반 sparse direct solver
- stiffness factorization과 load-vector substitution 분리
- displacements, reactions, equilibrium end actions, section resultants, generalized results,
axial `S11` output
- HDF5 result schema v0
- `fesa.exe <model.inp>` CLI with lexical sibling result/log names
- 승인된 `reference/cantilever beam/` B33 결과와 displacement, reaction, section resultant
comparison; beam stress reference comparison은 N/A
Harness와 agent·skill은 이 목표를 달성하기 위한 개발 운영 인프라다. 운영 스크립트나
문서 체계 자체를 구조해석 솔버의 제품 기능으로 간주하지 않는다.
## 승인된 Nonlinear Static 확장
## 문서와 계약의 역할
- `*STATIC, NLGEOM=YES` 단일 step은 parse/map을 정확히 한 번 수행한 뒤 linear static과
분리된 full-Newton procedure로 dispatch한다. Nonlinear path는 별도 mutable state,
unsymmetric tangent solver, iteration log writer와 schema-v1 HDF5 writer를 사용한다.
- CLI는 정확히 하나의 `<model.inp>`만 받고 `<stem>_results.h5`와 `<stem>_log.txt`를 같은
lexical sibling directory에 유도한다. `--output`은 지원하지 않는다.
- Nonlinear HDF5 schema v1은 committed accepted frame만 기록한다. factor-zero는 metadata
baseline이며 accepted frame이 아니고, successful factor-one row는 unique
`load_factor=1.0` accepted frame이다.
- Factor-one `/global/equilibrium`은 global origin에서 current `X+u` arm과 spatial physical
moment를 사용한 applied-plus-constrained-reaction balance error다. Accepted free residual과
constrained-reaction resultant는 그 dataset의 대체 quantity가 아니다.
- `shellNL-meshfine`는 primary nonlinear case, `shellNL`은 companion, `shell`은 linear
regression control이다. `U1/U2/U3`는 blocking, `UR1/UR2/UR3`는 warning-only이며 local
`RF/RM`은 review-only (`RM3` 및 stress 제외)로 비교한다.
| 문서 | 소유하는 내용 |
| --- | --- |
| 이 PRD | 제품 목적, 공통 요구사항, 품질 속성과 완료 기준 |
| [ARCHITECTURE](ARCHITECTURE.md) | 공통 책임, 의존성, 수명과 확장 경계 |
| [ADR](ADR.md) | 프로젝트 전반의 설계 결정과 변경 이력 |
| Feature `PRD.md` | 해당 요구의 목적·범위·제외·acceptance 요약과 상세 요구사항 링크 |
| Feature `requirements.md` | Requirement Agent가 소유하는 검증 가능한 요구사항과 verification matrix |
| Feature `ADR.md` | 해당 Feature의 결정·이유·영향·owner와 승인 근거 |
| Feature 전문 산출물 | 연구, 정식화, 수치/reference 검토, I/O, 구현·검증, 물리 검토와 release evidence |
## 신규 기능의 제품 완료 정의
Feature 문서의 생성·재개, Coordinator 관리 문서와 상세 문서 분리는
[FEATURE_DOCUMENTATION](FEATURE_DOCUMENTATION.md)을 따른다. Feature PRD가
`requirements.md`와 별도의 요구사항 원본을 만들거나 공통 기준을 묵시적으로 덮어쓰지 않는다.
공통 기준 자체의 변경은 별도로 승인된 프로젝트 문서 작업으로 다룬다.
새로운 element, load, constraint, material, analysis procedure 또는 output quantity는 다음 조건을 모두 만족할 때 FESA 제품 기능으로 취급한다.
## 공통 기능 요구사항
1. 지원 범위와 제외 범위, 실패 category, solver output의 units/coordinates/identity,
blocking reference quantity와 tolerance가 요구조건과 I/O 계약에 명시되어 있다.
2. 필요한 FEM 정식화와 recovery/sign convention이 검토되었고, 수치 위험과 검증 문제를 numerical review가 다룬다.
3. Syntax와 semantic mapping이 내부 모델에 안정된 source identity로 연결되며 잘못된 입력을 fail-closed로 거부한다. Kernel만 제공하는 기능은 parser/CLI 지원 여부를 별도로 표시한다.
4. DOF, sparse pattern, assembly, constraint, solver lifecycle과 mutable state ownership이 기존 아키텍처에 연결되거나 승인된 새 procedure 경계를 가진다.
5. Mandatory HDF5 schema와 diagnostic, CLI 실패 의미가 정의되고 failure path가 기존 state 또는 최종 output을 오염시키지 않는다.
6. Unit test가 local 수식과 validation을, integration test가 orchestration과 외부 계약을,
required reference comparison이 기능별 blocking quantity의 외부 수치 acceptance를
각각 증명한다. Reference가 N/A이면 그 이유와 대체 evidence를 명시한다.
아래 `FESA-PRD-GEN-*`는 공통 원칙을 위한 추적 ID다. 기존 `FESA-PRD-001`부터
`FESA-PRD-019`까지의 의미를 바꾸어 재사용하지 않으며, 그 원문과 적용 범위는
[개정 전 PRD](archive/pre-generalization/PRD.md)에 보존한다. Feature의 상세 요구사항은
별도 `FEM-REQ-<FEATURE>-###` ID와 해당 공통 기준을 연결한다.
## 기능 요구조건
| ID | 요구조건 | Acceptance Criteria | Verification Method |
| --- | --- | --- | --- |
| FESA-PRD-001 | FESA는 Abaqus `.inp` full compatibility가 아니라 승인된 keyword subset만 지원해야 한다. | 지원/미지원 keyword가 문서화되고, 미지원 keyword는 구조화된 diagnostic을 남긴다. | I/O contract review, parser unit test |
| FESA-PRD-002 | FESA는 입력 모델을 `Domain`으로 변환해야 한다. | nodes, elements, materials, properties, sets, loads, boundary conditions, step definitions가 semantic model에 보존된다. | parser integration test |
| FESA-PRD-003 | FESA는 현재 step의 실행 view를 `AnalysisModel`로 구성해야 한다. | active elements, loads, boundary conditions, properties/materials가 Domain 복사 없이 참조 또는 id view로 연결된다. | analysis model unit test |
| FESA-PRD-004 | FESA는 equation numbering과 constraint/free mapping을 `DofManager`에 집중해야 한다. | Node/Element 내부에 equation id를 분산 저장하지 않는다. | code review, DofManager unit test |
| FESA-PRD-005 | FESA는 해석 중 변하는 물리량을 `AnalysisState`에 저장해야 한다. | V0 displacement, external/internal force, residual, constrained reaction, step/frame identity와 element recovery rows가 출력에 연결되고 velocity, acceleration, temperature, iteration history는 할당하지 않는다. | state unit test, integration test |
| FESA-PRD-006 | FESA는 solver 결과를 derived HDF5 authoritative output `<stem>_results.h5`로 저장해야 한다. | V0 step/frame field results, metadata, diagnostics가 schema version과 함께 저장된다. | HDF5 schema test |
| FESA-PRD-007 | FESA는 기능이 지정한 Abaqus reference CSV quantity와 비교 가능한 deterministic source-row/component mapping을 제공해야 한다. | Required source IDs/components는 일대일 대응되고 missing/extra/duplicate/nonfinite row는 tolerance 전에 실패한다. Canonical naming, README, metadata, provenance 또는 CSV schema version은 요구하지 않는다. | reference comparison report |
| FESA-PRD-008 | FESA의 production C++ 변경은 테스트를 먼저 작성하고 실패를 확인한 뒤 구현해야 한다. | 관련 C++ test file, RED 실패와 후속 GREEN 성공 증거가 있고 Stop의 전체 MSVC build/test가 통과한다. | implementation report, Hook guardrail, CTest |
| FESA-PRD-009 | FESA는 외부 라이브러리 API를 solver core에 직접 노출하지 않아야 한다. | MKL, TBB, HDF5 의존은 adapter module에 제한된다. | architecture review, dependency review |
| FESA-PRD-010 | FESA 기능 구현 완료는 build/test와 기능별 blocking reference comparison 통과를 요구해야 한다. | Required CTest가 통과하고 선언된 blocking quantity가 승인 tolerance 안에 있다. Physics sanity와 release readiness는 별도 후속 gate다. | build/test report, reference verification report |
| FESA-PRD-011 | V0는 입력 파일당 하나의 linear static step과 Abaqus B33 3D Euler beam만 해석해야 한다. | 단일 B33 model은 해석되고, B31과 두 번째 step은 구조화된 unsupported diagnostic으로 거부된다. | parser/semantic unit test, CLI integration test |
| FESA-PRD-012 | V0는 Part/Assembly/Instance wrapper와 source identity를 보존해야 한다. | 여러 identity instance의 node/element/set label이 stable internal ID로 deterministic하게 매핑되고 transform 또는 nested assembly는 거부된다. | semantic mapping unit test |
| FESA-PRD-013 | Output-request allowlist는 해석 의미를 변경하지 않아야 한다. | 승인 keyword와 variable data는 warning 후 no-op이고, allowlist 밖 model-affecting keyword는 오류이며 기본 결과는 output request와 무관하게 생성된다. | parser diagnostic test, HDF5 integration test |
| FESA-PRD-014 | 선형 정적 pipeline은 stiffness factorization과 load substitution을 분리해야 한다. | `Kff` factorization이 load vector assembly보다 먼저 수행되고, `rhs=Ff-Kfc*dc` substitution으로 full displacement를 복구한다. | orchestration test, solver-adapter test |
| FESA-PRD-015 | FESA는 V0 결과와 diagnostic을 안정된 외부 계약으로 출력해야 한다. | CLI가 `0=success`, `2=usage`, `3=input`, `4=model`, `5=solver`, `6=HDF5` exit code를 사용하고 diagnostic field가 계약과 일치하며 HDF5가 displacement, reaction, end force, section resultant, generalized strain/resultant, axial `S11`을 포함하고 실패 시 불완전한 최종 파일을 남기지 않는다. | CLI integration test, HDF5 schema/atomicity test |
| FESA-PRD-016 | Dense와 sparse math storage 및 backend 경계를 분리해야 한다. | `Vector`는 contiguous, `Matrix`는 row-major contiguous storage와 MKL CBLAS를 사용하고 `SparseMatrix`는 별도 0-based CSR 타입이며 MKL 타입이 public core API에 노출되지 않는다. | math unit test, dependency review |
| FESA-PRD-017 | 모든 외부 reference comparison은 승인된 공통 family-scale tolerance를 사용해야 한다. | 각 matched row가 near-zero 대체 조건 또는 상대오차 `0.05`를 통과하고 각 family의 scale-relative RMS가 `0.01` 이하이며 missing/extra/duplicate/nonfinite row는 comparison 전에 실패한다. | reference comparison unit/integration test, verification report |
| FESA-PRD-018 | 승인된 B33 reference artifact는 현재 경로의 read-only baseline으로 유지해야 한다. | `reference/cantilever beam/` 파일을 rename, rewrite 또는 보정하지 않고 기능이 선언한 exact path에서 읽는다. | artifact inventory, Git diff review |
| FESA-PRD-019 | B33 beam section과 local axis를 Abaqus 의미에 맞게 매핑해야 한다. | `n1 -> local y`, `t x n1 -> local z`, `Iy=I11`, `Iz=I22`, `I12=0`을 적용하고 nonpositive property, zero-length element, tangent-parallel guide vector를 구조화된 model diagnostic으로 거부한다. | section-mapping unit test, element geometry test |
| ID | 요구사항 | 확인할 evidence |
| --- | --- | --- |
| FESA-PRD-GEN-001 | 지원·미지원 범위와 관찰 가능한 동작을 Feature 계약으로 명시해야 한다. | 범위·제외·입력/출력 계약 및 양성·음성 검증 |
| FESA-PRD-GEN-002 | 입력을 일관된 semantic model로 변환하고 잘못된 참조·중복·비유한 값·미지원 조합을 진단해야 한다. | Mapping·validation 계약과 실패 경로 테스트 |
| FESA-PRD-GEN-003 | Source identity, internal index, DOF, equation과 result identity를 구분하고 필요한 대응 관계를 보존해야 한다. | Identity mapping과 재정렬·누락·중복 검사 |
| FESA-PRD-GEN-004 | 모델 정의, 실행 view, equation 구성과 mutable state의 소유권·수명을 분리해야 한다. | Architecture·lifetime 검토와 관련 테스트 |
| FESA-PRD-GEN-005 | 요소·재료·하중·제약의 수학적 계약을 검토한 뒤 local 계산과 전역 해석을 연결해야 한다. | 정식화, Numerical Review, local·integration evidence |
| FESA-PRD-GEN-006 | 해석 절차마다 필요한 state, 해법, 종료 조건, commit과 recovery 의미를 정의해야 한다. | Procedure 계약과 성공·실패 lifecycle 검증 |
| FESA-PRD-GEN-007 | 결과의 물리량, location, units, coordinates, component, entity와 step/frame 의미를 식별할 수 있어야 한다. | I/O·result schema 계약과 mapping 검증 |
| FESA-PRD-GEN-008 | 실패한 candidate가 유효한 state나 최종 결과를 부분적으로 오염시키지 않도록 계약된 보존 범위를 지켜야 한다. | State commit·복구·출력 실패 검증 |
| FESA-PRD-GEN-009 | 외부 형식과 vendor/OS API를 adapter 뒤에 격리하고 solver core에 노출하지 않아야 한다. | Public dependency와 adapter 경계 검토 |
| FESA-PRD-GEN-010 | Production 동작 변경은 관련 테스트의 기대 실패를 관찰한 뒤 구현하고 지정된 검증 evidence를 남겨야 한다. | RED/GREEN, focused/full 검증 명령과 실제 결과 |
| FESA-PRD-GEN-011 | 기능에 필요한 독립 검증과 reference 비교를 수행하고 승인된 identity·수치 정책을 유지해야 한다. | 검증 matrix, 사전검사, reference 또는 명시적 N/A와 대체 근거 |
| FESA-PRD-GEN-012 | 기능 완료는 같은 계약 revision의 필수 evidence와 미해결 항목을 추적하여 판정해야 한다. | 요구사항부터 물리 검토·release readiness까지의 gate 기록 |
## 비기능 요구조건
- MSVC x64 Debug 환경에서 configure, build, CTest를 검증한다.
- reference test 결과는 deterministic해야 한다.
- HDF5 schema는 versioned contract로 관리한다.
- 모든 외부 reference comparison은 동일 logical quantity와 unit dimension의 component
family별 Abaqus-only maximum scale을 사용한다. Near-zero ratio는 `0.01`, 일반 행
상대오차는 `0.05`, family scale-relative RMS는 `0.01`이며 독립 absolute-error gate는
사용하지 않는다.
- B33 section resultant는 source element label과 endpoint node label로 직접 대응한다.
MITC4 `U1/U2/U3`만 blocking이고 `UR1/UR2/UR3` 초과는 warning-only다.
- parser, solver, HDF5 writer는 실패 원인을 구조화된 diagnostic으로 보고한다.
- oneMKL, oneTBB, HDF5는 CMake에서 명시 탐지하고 실패 원인을 분류한다.
- 대규모 모델 성능 최적화보다 V0의 명확성, 테스트 가능성, 검증 traceability를 우선한다.
요구사항 단계는 acceptance intent와 필요한 물리적 관찰을 정한다. Numerical Review는
기존 승인 정책 안에서 논리적 비교량·identity/component·판정 구분을 구체화하고, I/O는 이를
외부 syntax와 결과 schema에 대응시킨다. 구현 담당자가 누락된 상위 계약을 임의로 정하지 않는다.
## Acceptance Gates
1. Requirements approved: 기능 범위, 제외 범위, 입력, 출력, tolerance, 검증 물리량이 정의되어 있다.
2. Research evidence complete: 정식화와 benchmark 근거가 신뢰도와 한계와 함께 정리되어 있다.
3. Formulation reviewed: 약형, shape function, B matrix, constitutive contract, 수치적분, output recovery가 검토되어 있다.
4. I/O contract approved: Abaqus keyword subset, internal model mapping, HDF5 result contract,
required reference quantity의 최소 source-ID/component matching이 승인되어 있다.
5. Tests fail before implementation: C++/integration/reference test를 제품 코드보다 먼저 작성하고 같은 Step 안에서 RED 실패와 후속 GREEN 성공을 확인한다.
6. CMake/CTest pass: MSVC/x64/Debug 기준 configure, build, test가 통과한다.
7. Reference comparison pass: 기능이 blocking으로 선언한 FESA `<stem>_results.h5` quantity가
선언된 Abaqus CSV와 source identity/component별로 대응되고 승인된 tolerance 안에 있다.
8. Physics sanity pass: equilibrium, reaction consistency, displacement direction, symmetry, section-force consistency와 normalized residual이 검토되어 있다.
9. Release readiness pass: acceptance traceability, known limitations, release notes draft가 준비되어 있다.
## 품질 속성
## 제외 사항
- Abaqus full parser 호환
- Abaqus B31/Timoshenko beam
- 다중 analysis step과 step 간 load/BC propagation
- instance translation/rotation, nested assembly 및 dependent/independent mesh semantics
- `I12 != 0`, taper, offset, release, curved beam, warping
- Abaqus `*DLOAD` 입력과 Domain distributed-load object
- 승인된 fixed-load-factor nonlinear-static 범위를 벗어난 기하·재료비선형, dynamics,
contact, thermal effects
- transverse shear stress와 torsional shear stress recovery
- beam stress에 대한 Abaqus reference comparison
- Abaqus, Nastran 또는 reference solver 직접 실행 자동화
- Agent가 Abaqus reference CSV 파일을 임의 생성 또는 수정하는 작업
- GUI 또는 postprocessor
- Visual Studio `.sln`/`.vcxproj` 전용 MSBuild workflow
- plasticity와 shell end-to-end 구현
| 속성 | 공통 기준 |
| --- | --- |
| Correctness | 실행 성공이나 유한한 결과만으로 판단하지 않고 수학적 계약과 기능별 검증으로 설명한다. |
| Determinism | 승인된 실행 조건에서 identity, numbering, reduction, 결과와 diagnostic 순서를 재현한다. |
| Traceability | 요구사항·결정·코드·테스트·artifact·verdict를 Feature ID와 revision으로 연결한다. |
| Extensibility | 실제 사용 사례에 필요한 최소 경계를 추가하며, 지원하지 않는 physics나 미래 state를 선할당하지 않는다. |
| Diagnosability | 실패 단계와 관련 source/entity, 원인과 재개에 필요한 정보를 제공한다. |
| Safety | 미지원 의미는 fail-closed로 처리하고, reference와 관련 없는 사용자 변경을 보존한다. |
| Maintainability | 사람이 계약과 수식을 대조할 수 있는 단순한 코드와 중복 없는 문서를 유지한다. |
| Performance | 정확성·재현성을 보존하고 측정된 병목과 승인된 요구를 근거로 최적화한다. |
특정 모델 크기, 성능 목표와 환경별 보장은 해당 요구와 evidence가 있을 때 Feature 계약으로
정한다. 수치 검증 기준은 적용되는 공통 정책과 승인된 Feature 계약을 따르며 외부 reference
기준을 기능마다 임의로 정하지 않는다. 이 표는 검증되지 않은 성능이나 모든 platform의
동등성을 약속하지 않는다.
## 검증과 완료 기준
검증은 서로 다른 오류를 확인하는 계층으로 구성한다. Numerical Review가 Feature에 맞는
unit, analytical/benchmark, integration, convergence, invariant 및 외부 reference coverage를
정의한다. 한 계층의 성공이 다른 필수 계층을 대신하지 않는다.
- 외부 reference 비교는 identity와 component를 대응시키고 missing, extra, duplicate,
nonfinite 값을 거부한 뒤 [TOLERANCE](TOLERANCE.md)를 적용한다.
- 물리 평형, 수렴과 정식화 검증의 기준을 외부 reference tolerance와 혼용하지 않는다.
- Reference artifact는 read-only로 취급하며 구현 결과에 맞추어 생성·보정하지 않는다.
- 비교가 N/A인 경우 이유와 계약이 요구하는 대체 evidence를 명시한다.
- 실패·미실행·stale evidence를 통과로 표시하지 않는다. 과거 통과 기록을 현재 검증으로
소급 적용하지 않는다.
정규 Feature workflow는 다음과 같다.
`requirements → research → formulation → numerical-review → io-definition →
implementation-planning → implementation → physics-evaluation → release-readiness`
구현 gate는 TDD, 지정된 전체 build/test와 필수 reference evidence가 갖추어졌을 때
통과한다. Feature closure에는 그 뒤의 독립 물리 검토와 release-readiness 감사도 필요하다.
Release readiness는 내부 완료 권고이며 외부 publish, push, tag, deploy 또는 package 권한이 아니다.
Owner, 공통 handoff, outcome, stale 처리와 유한 correction은
[SOLVER_AGENT_DESIGN](SOLVER_AGENT_DESIGN.md)을 따른다. Skill의 적용 경계는
[SOLVER_SKILL_DESIGN](SOLVER_SKILL_DESIGN.md), 실행 절차는 각 현재 `SKILL.md`를 따른다.
문서만 수정하는 작업을 solver Feature 전체 workflow로 확대하지 않는다.
## 단계적 확장과 비목표
새 Feature는 입력 의미부터 결과와 검증까지 연결되는 작은 단위로 정의한다. Kernel,
parser 또는 dataset 하나가 존재한다는 이유만으로 제품 노출을 선언하지 않는다.
공통 문서에 구현 항목별 목록이나 진행 상태를 누적하지 않고 해당 Feature 문서에서 관리한다.
다음은 별도 승인 없이 목표로 삼지 않는다.
- 특정 외부 solver의 전체 호환성이나 비공개 알고리즘·내부 상태·결과 생성 절차의 동등성
- 아직 요구되거나 검증되지 않은 요소·재료·해석 절차·입출력 형식의 지원
- GUI, 모델러, mesher 또는 범용 전후처리기로의 제품 범위 확대
- 외부 solver 실행, reference 갱신, 원격 게시 또는 파괴적 작업의 자동 승인
외부 제품의 공개 입력 의미, 출력 정의와 검증 사례는 승인된 범위의 reference로 사용할 수
있다. 수치 결과의 exact equality는 허용되지만 내부 동작 동등성을 증명하지 않는다.
## 개정 이력의 보존
이 개정은 프로젝트 공통 기준과 구현 항목별 계약의 문서 경계를 정리한다. 기존 기능의
요구사항을 폐기하거나 수치 acceptance를 변경하지 않는다. 기능별 설명과 기존 ID의 원문은
[개정 전 PRD](archive/pre-generalization/PRD.md)에 보존하며, 향후 Feature PRD로 이관할 때
원래 범위·revision·근거를 함께 연결한다. 보존본의 오래된 지원·검증 상태보다 해당 Feature의
승인된 최신 계약과 evidence를 확인한다.
+375
View File
@@ -0,0 +1,375 @@
# Architecture Decision Records
## 철학
FESA의 architecture decision은 solver correctness, verification traceability, implementation testability를 우선한다. Harness는 제품이 아니라 C++/MSVC 기반 FEM 구조해석 솔버 개발을 통제하는 운영 인프라이다.
---
### ADR-001: FESA는 구조해석 솔버 프로젝트이고 Harness는 운영 인프라로 둔다
**결정**: 저장소의 주 목적은 유한요소법 기반 구조해석 솔버 개발이다. Harness는 승인된 Step 계획, 독립 세션 실행, PreToolUse guardrail, Stop MSVC build/test 검증을 제공하는 보조 계층으로 유지한다.
**이유**: 기존 문서가 Harness 중심이면 agent가 solver architecture, FEM verification, Abaqus/HDF5 계약보다 운영 스크립트에 과도하게 맞춰 행동한다.
**트레이드오프**: Harness 문서의 비중은 낮아지지만, `docs/HARNESS_WORKFLOW.md`의 실행 계약과 `.codex/hooks.json`의 검증 정책은 계속 필수 운영 규칙으로 유지한다.
### ADR-002: C++17/MSVC/CMake/CTest를 기본 구현 환경으로 둔다
**결정**: 기본 solver 구현과 validation은 C++17 이상, Visual Studio 17 2022 또는
Visual Studio 18 2026 generator, x64 platform, Debug config, CMake, CTest로 수행한다.
`.harness/config.json`이 없으면 CMake가 설치된 두 승인 generator 중 하나를 자동
선택할 수 있으며, build/test evidence에는 실제 generator와 compiler version을 기록한다.
**이유**: FESA의 목표 환경은 Windows/MSVC 기반 C++이다. CMake/CTest는 solver source tree가 추가되거나 확장될 때 가장 일관된 build/test entry point다. VS17과 VS18을
승인하면 현재 지원되는 MSVC 개발 환경에서 같은 C++17/x64/Debug 계약을 검증할 수 있다.
**트레이드오프**: FESA solver source는 CMake/CTest를 기본으로 유지한다. Generator별
compiler 차이는 각 build/test report에 명시하고, 두 generator 중 하나에서만 관찰되는
실패를 다른 generator의 성공으로 숨기지 않는다. Harness 자체는 `.harness/config.json`에
solution과 test command를 명시한 직접 MSBuild 프로젝트도 검증할 수 있지만, 이는 FESA
제품이 solution-only workflow를 지원한다는 의미가 아니다.
### ADR-003: Abaqus `.inp` full compatibility가 아니라 기능별 keyword subset을 지원한다
**결정**: FESA parser는 Abaqus keyword/data/comment line 규칙을 따르되, 기능별로 승인된 keyword subset만 지원한다. 미지원 keyword는 명확한 diagnostic을 남긴다.
**이유**: full Abaqus compatibility는 초기 solver 범위와 검증 비용을 과도하게 키운다. 기능별 subset은 요구조건, I/O contract, reference validation을 추적 가능하게 만든다.
**트레이드오프**: 사용자는 기존 Abaqus input file을 그대로 사용할 수 없을 수 있다. 대신 지원 범위와 실패 원인이 명확해진다.
### ADR-004: Domain, AnalysisModel, DofManager, AnalysisState를 분리한다
**결정**: `Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과
`StepDefinition` 입력 모델 정의를 `std::unique_ptr`로 단독 소유하고 const access와
stable collection index를 제공한다. `AnalysisModel`은 Domain 수명 안에서 stable index와
const reference만 사용하는 non-owning current-step view다. `DofManager`는 equation
numbering과 constrained/free mapping을 전담하고, `AnalysisState`는 해석 중 변하는
물리량을 소유한다.
**이유**: 모델 정의, step activation, equation system, transient/nonlinear state가 섞이면 parser, assembler, solver, result writer가 강하게 결합된다. 분리된 상태 모델은 선형 정적 해석에서 시작해 비선형, 동적, thermal coupling으로 확장하기 쉽다.
**트레이드오프**: 초기 class 수가 늘어난다. V0에서는 interface를 얇게 유지하고 실제 선형 정적 frame에 필요한 state만 구현한다.
### ADR-005: 공식 결과 파일은 HDF5로 하고 reference 결과는 Abaqus CSV로 둔다
**상태**: HDF5 authoritative output 결정은 유지하며 reference bundle governance 부분은 ADR-019로 대체됨.
**결정**: FESA solver의 authoritative result output은 `results.h5` HDF5이다. Abaqus reference results는 기능별 reference model contract가 지정한 `reference/<model-id>/` 아래 CSV 파일로 저장하며, verification은 FESA HDF5 rows와 Abaqus reference CSV rows를 documented IDs, components, units, coordinate system, step/frame identity, tolerance 기준으로 비교한다. 신규 reference는 canonical 파일명을 사용하고, 승인된 기존 bundle의 legacy alias는 해당 기능 계약에 정확한 경로를 기록한 경우에만 허용한다.
**이유**: 구조해석 결과는 step/frame, field/history, node/element/integration point location, units, coordinate system, schema version을 함께 가져야 한다. HDF5는 이 계층 구조와 metadata를 안정적으로 표현한다.
**트레이드오프**: reference comparison은 FESA HDF5 dataset identity와 Abaqus CSV row identity를 모두 관리해야 한다. FESA HDF5에서 추출한 deterministic CSV view는 디버깅/검토용 보조 artifact로 허용하지만, 공식 solver output이나 reference artifact로 취급하지 않는다.
### ADR-006: 해석 알고리즘과 수치 backend는 Strategy와 Adapter 경계 뒤에 둔다
**결정**: `Analysis`, `LinearSolver`, `TimeIntegrator`, `ConvergenceCriteria`는 Strategy로 구성하고, MKL, TBB, HDF5 API는 adapter 계층 뒤에 둔다. `Vector`는 contiguous `double`, `Matrix`는 row-major contiguous `double`을 소유하고 dense 연산은 MKL CBLAS를 사용한다. `SparseMatrix`는 이들과 상속 관계가 없는 0-based CSR 전용 타입이며, PARDISO factorization과 substitution은 `LinearSolver` 경계 뒤에서 분리한다.
**이유**: 선형 정적, 비선형 정적, 동적, frequency, heat transfer 해석은 공통 흐름을 공유하지만 알고리즘과 backend가 다르다. 외부 API를 core에 노출하면 테스트 double, backend 교체, dependency review가 어려워진다.
**트레이드오프**: 단일 기능만 구현할 때는 adapter가 다소 장황해 보일 수 있다. Row-major dense storage와 CSR sparse storage를 따로 유지해야 하지만 backend 의존성과 dense/sparse 의미가 core 모델에 섞이지 않는다.
### ADR-007: Analysis base는 최소 실행 계약만 제공한다
**결정**: `Analysis` base는 virtual `Analysis::Run(const AnalysisRequest&)`만 제공하고
linear-static-specific protected hook을 정의하지 않는다. 승인된 선형 정적 순서인
`parse input -> initialize Domain -> build AnalysisModel -> build DOF map/sparse pattern ->
assemble stiffness -> partition constraints -> factorize Kff -> assemble load -> form effective
RHS -> substitute -> reconstruct displacement -> recover results -> write HDF5`는
`LinearStaticAnalysis::Run()`의 private lifecycle로 유지한다. 강성행렬 factorization은
하중벡터 조립보다 먼저 수행하고 factorization과 substitution을 하나의 불투명한 solve
호출로 합치지 않는다.
**이유**: 현재 여덟 단계는 linear static equation, state와 failure taxonomy에 특화되어
있다. 최소 base contract는 이 순서의 검증 가능성을 보존하면서 승인되지 않은 dynamic,
eigenvalue 또는 nonlinear procedure에 같은 protected hook과 사용하지 않는 state를
강제하지 않는다. Factorization과 substitution 분리는 동일 강성행렬에 여러 RHS를 적용할
수 있고 각 실패 단계를 구조화된 diagnostic으로 분류하게 한다.
**트레이드오프**: Procedure 사이의 lifecycle code는 base Template Method로 자동 재사용되지
않는다. 두 번째 procedure가 승인되면 실제로 같은 단계만 focused collaborator로 추출하되,
linear-static hook 사이에 조건문으로 새 physics를 삽입하지 않는다.
### ADR-008: Sparse assembly는 deterministic COO-to-CSR 경로로 시작한다
**결정**: 초기 assembly는 element-local contribution을 COO triplet으로 수집한 뒤 CSR로 finalize한다. MKL PARDISO backend는 CSR input contract를 받는다.
**이유**: CSR은 MKL PARDISO와 잘 맞고, COO-to-CSR 경로는 구현과 테스트가 명확하다. deterministic reduction은 reference comparison의 재현성을 지킨다.
**트레이드오프**: 대규모 모델에서는 메모리와 변환 비용이 생길 수 있다. 성능 문제가 실제로 확인되면 typed batch assembly 또는 kernel 분리를 추가한다.
### ADR-009: TBB 병렬화는 element-local computation부터 적용한다
**결정**: 첫 oneTBB 적용 지점은 element-local matrix/residual 계산이다. 전역 sparse write는 thread-local buffer 또는 deterministic reduction으로 제한한다.
**이유**: element-local 계산은 독립성이 높고 병렬화 효과가 명확하다. 전역 sparse matrix에 직접 병렬 write하면 재현성, race, ordering 문제가 생긴다.
**트레이드오프**: 초기 병렬화 범위가 제한된다. MKL 내부 thread와 TBB task arena의 oversubscription 정책을 별도로 문서화해야 한다.
### ADR-010: Abaqus reference artifact는 사람이 생성하거나 명시 승인된 절차로만 갱신한다
**상태**: Artifact read-only 및 실행 제한은 유지하며 metadata/provenance/naming 계약은 ADR-019로 대체됨.
**결정**: Agent는 Abaqus, Nastran 또는 reference solver를 직접 실행하지 않는다. reference artifact 생성, 수정, 복원은 명시 승인된 phase에서만 수행한다. 모든 bundle의 provenance, generator/version, units, coordinate system, step/frame identity, schema, tolerance와 limitations는 승인된 기능별 Reference Model Contract에 기록한다. `metadata.json`은 선택 reference artifact이며, 부재만으로 bundle을 불완전하다고 판정하지 않는다. 파일이 존재하면 read-only 보조 자료로 inventory하고 계약 및 실제 artifact와 일치하는지 확인하며, 충돌은 숨기지 않고 upstream 계약 문제로 보고한다. 승인된 `cantilever-beam-b33` legacy baseline의 space-containing filename과 `README.md` N/A 예외는 유지한다.
**이유**: reference 결과는 solver correctness의 기준이다. 생성 절차가 불명확하면 구현 결함과 reference artifact 오류를 구분할 수 없다.
**트레이드오프**: Reference Model Contract가 필수 provenance의 단일 source of truth가 되어 별도 JSON 파일 없이도 bundle을 사용할 수 있다. 선택 `metadata.json`이 계약과 중복될 수 있으므로 존재 시 일관성 검사가 필요하다. Legacy filename과 `README.md` 예외는 일반 artifact 규칙을 복잡하게 하지만 exact path와 source commit을 고정하고 read-only로 취급해 감사 가능성을 유지한다.
### ADR-011: 구형 단일 검증 진입점 계약을 폐기한다
**상태**: ADR-012로 대체됨.
**결정**: 삭제된 legacy validation entry point, legacy Python test discovery, 환경 변수 기반 command override를 Harness의 기본 검증 계약으로 사용하지 않는다.
### ADR-012: Harness는 계획, 실행, Hook 검증의 세 계층으로 운영한다
**결정**: 계획은 `.agents/skills/harness`, Step 실행과 Git 상태 관리는 `scripts/execute.py`, 도구 호출 전 정책과 종료 전 검증은 `.codex/hooks.json`에 연결된 `scripts/hooks/`가 담당한다. C++ production 변경은 관련 테스트 파일이 있어야 하며, 실제 RED 실패와 GREEN 성공은 같은 Step 안에서 확인한다. Stop은 `.harness/config.json` 또는 자동 감지 결과로 전체 MSVC build/test를 검증한다. Harness Python 변경은 `uv run --with pytest python -m pytest -v -rs`로 검증한다.
**이유**: 테스트 파일 존재 검사, TDD 실행 증거, 전체 build/test는 서로 다른 책임이다. 이를 분리하면 Hook이 보장하는 범위를 과장하지 않으면서 Step 종료 시 green 상태를 강제할 수 있다.
**트레이드오프**: PreToolUse만으로 구현 전 RED 실행을 증명할 수 없으므로 Implementation report에 RED/GREEN 명령과 결과를 기록해야 한다. C/C++가 없는 저장소는 Stop이 통과하므로 Harness Python 검증은 별도 acceptance command로 유지한다.
### ADR-013: V0 선형 정적 해석은 단일 step B33 Euler beam으로 제한한다
**결정**: 첫 end-to-end 제품 기능은 입력 파일당 하나의 `*STEP, *STATIC`을 해석하는 2절점 3D Euler–Bernoulli beam이다. Abaqus `TYPE=B33`만 이 요소로 매핑하고 B31은 `unsupported-element-formulation`으로 거부한다. `*PART/*ASSEMBLY/*INSTANCE`는 여러 identity instance와 stable source identity를 지원하지만 instance transform, nested assembly, 다중 step은 지원하지 않는다. Output-request keyword는 승인 allowlist에서 warning 후 no-op 처리하고 FESA 기본 HDF5 결과는 항상 생성한다.
**이유**: B31은 transverse shear deformation을 포함하므로 Euler–Bernoulli 정식화와 의미가 다르다. 단일 step과 identity instance로 범위를 제한하면 parser wrapper, source identity, assembly, 해법 및 결과 복구를 end-to-end로 검증하면서 의미를 왜곡하지 않는다.
**트레이드오프**: 기존 Abaqus 모델 중 B31, instance transform, 다중 step 또는 `*DLOAD`를 사용하는 입력은 거부된다. 이후 기능은 별도 요구조건과 formulation/reference gate를 거쳐 추가한다.
### ADR-014: B33 cantilever baseline은 component-scale 혼합 tolerance로 비교한다
**상태**: Artifact inventory와 component mapping의 역사적 결정은 유지하며 tolerance와
node-station projection 결정은 ADR-022로 대체됨.
**결정**: `reference/cantilever beam/`의 B33 input, displacement CSV, reaction CSV, elemental-force CSV를 V0 reference baseline으로 사용한다. Displacement와 reaction은 node identity로, section resultant는 CSV node station과 정규화된 FESA element endpoint로 비교한다. 같은 model, step/frame, quantity, component에 대해 `reference_scale = max(abs(reference rows))`를 계산하고 모든 row에 `absolute_floor + 1e-6 * reference_scale`을 적용한다. SI displacement/rotation absolute floor는 `1e-9`, force/moment floor는 `1e-3`이다. Beam stress는 출력하되 Abaqus stress reference comparison은 N/A다.
**이유**: 자유단 moment처럼 이론적으로 0인 값에는 행별 상대오차가 정의되지 않으며 Abaqus 결과에 작은 수치 잔차가 남을 수 있다. Component scale을 사용하면 전체 물리량 크기에 비해 작은 잔차를 허용하면서 각 row를 결정적으로 판정할 수 있다.
**트레이드오프**: 큰 component scale은 zero row의 허용폭을 넓힌다. 이를 완화하기 위해 quantity와 component를 섞지 않고 Abaqus 값만 scale에 사용하며, 모든 row의 absolute/normalized error와 worst row를 보고하고 누락·추가·nonfinite row를 tolerance 전에 실패시킨다.
### ADR-015: 외부 CMake target을 FESA 경계로 정규화하고 Windows runtime closure를 명시한다
**결정**: MKL, TBB, HDF5 CONFIG package가 제공하는 target은 dependency module에서
`Fesa::MKL`, `Fesa::TBB`, `Fesa::HDF5`로 정규화한다. Product target은 이 경계만
`PRIVATE` link하고 public header에 vendor/Win32 type을 노출하지 않는다. Approved Windows
환경에서는 packaged shared HDF5 C target을 우선하며, CLI와 test executable 옆에 TBB,
MKL, OpenMP, Intel math runtime, HDF5를 포함한 실제 runtime DLL closure를 POST_BUILD로
stage한다.
**이유**: Package version이나 shared/static variant에 따라 imported target 이름과 숨은
runtime dependency가 달라질 수 있다. Configure와 link 성공만 확인하면 GoogleTest
discovery 또는 배포된 CLI가 `0xc0000135`로 실패할 수 있다. FESA-owned target과 명시적
runtime closure는 module code와 실행 환경을 package 세부사항에서 분리한다.
**트레이드오프**: Windows staging CMake가 길어지고 새 dynamic dependency마다 runtime
audit가 필요하다. 대신 개인 설치 경로를 source에 하드코딩하거나 developer `PATH`에
의존하지 않고 build tree executable을 재현 가능하게 실행할 수 있다.
### ADR-016: 결정론과 failure atomicity를 correctness contract로 취급한다
**결정**: Parallel element 계산은 index별 독립 buffer만 쓰고, COO tuple ordering과
floating-point sum은 join 이후 고정된 serial 순서로 수행한다. Result recovery, solver
output, HDF5 writer는 candidate를 완성·검증한 뒤 caller-owned state 또는 final file에
commit한다. HDF5는 same-directory temporary file을 checked close/reopen한 후에만 atomic
finalization한다.
**이유**: Reference comparison과 물리 검토는 row identity와 작은 수치 차이에 민감하다.
Thread scheduling 또는 중간 실패가 sparse bytes, result order, 이전 output을 바꾸면 같은
입력에 대한 evidence를 신뢰할 수 없다.
**트레이드오프**: Serial reduction과 candidate copy가 throughput과 memory를 더 사용할 수
있다. 성능 최적화는 동일한 ordering, failure preservation, reference 결과를 증명할 때만
대체할 수 있으며, nondeterministic global sparse write는 허용하지 않는다.
### ADR-017: Essential constraint는 stable elimination으로 적용하고 reaction은 full residual로 정의한다
**결정**: V0는 DofManager의 stable free/constrained order로 full stiffness를
`Kff/Kfc/Kcf/Kcc`로 분할하고 `Kff * df = Ff - Kfc * dc`를 푼 뒤 full displacement를
복구한다. 모든 DOF가 constrained인 모델의 `0 x 0 Kff`는 유효한 trivial factorization과
empty substitution이다. Recovery의 full residual `r = K*d - F`를 reaction vector로
보존하며 constrained entry는 physical reaction, free entry는 equilibrium evidence다.
**이유**: Equation numbering과 prescribed displacement를 한 owner가 관리하면 nonzero
constraint, no/all/mixed constraint가 같은 수식과 stable order를 사용한다. Full residual은
element end action을 별도로 합산하는 경로보다 조립·하중·해법 전체의 equilibrium을 직접
검증한다.
**트레이드오프**: Full K와 네 partition을 유지하는 메모리 비용이 있고 reaction vector의
free entry가 정확한 0이라고 가정할 수 없다. V0에는 penalty, MPC, Lagrange multiplier를
혼합하지 않으며, 추가 constraint policy는 별도 formulation과 equation/output 계약을
요구한다.
### ADR-018: Kernel 존재와 제품 노출을 분리하고 계층형 검증을 요구한다
**결정**: Local element/load/recovery kernel이 존재해도 syntax, semantic Domain mapping,
analysis orchestration, mandatory HDF5와 diagnostic 계약이 연결되지 않으면 CLI 지원으로
간주하지 않는다. 검증은 unit, integration, reference comparison, physics sanity를 서로
대체할 수 없는 계층으로 유지한다. Reference가 가능하지 않은 quantity는 명시적 N/A와
analytical/schema/physics 대체 evidence를 요구한다.
**이유**: Unit test는 수식과 validation을, integration test는 lifetime과 호출 순서를,
reference comparison은 외부 solver와의 수치 일치를, physics sanity는 공통-mode 오류와
model adequacy를 검출한다. 한 계층의 성공만으로 parser exposure 또는 물리 correctness를
추론하면 지원 범위와 검증 강도가 과장된다.
**트레이드오프**: 작은 기능도 여러 계약과 evidence를 함께 준비해야 하므로 개발 속도가
느려진다. 대신 `*DLOAD`처럼 kernel은 있지만 입력에 노출되지 않은 기능, stress처럼
mandatory output이지만 Abaqus reference가 N/A인 기능을 정확하게 표현할 수 있다.
### ADR-019: Abaqus는 입력 형식과 외부 수치 reference이며 FESA 내부 동작 계약이 아니다
**결정**: FESA는 Abaqus와 독립적인 솔버다. 기능별 승인 `.inp` subset을 입력으로
사용하고, 기능이 blocking으로 선언한 FESA HDF5 quantity만 기존 Abaqus CSV와 승인
tolerance로 비교한다. Abaqus 요소 정식화, 적분, stabilization, 내부 상태와 결과 생성
절차를 재현하거나 동등하게 구현하지 않는다. Exact numerical equality는 허용되지만
내부 동작 동등성의 evidence가 아니다.
Reference case readiness에는 선언된 `.inp`, 실제 비교에 필요한 CSV, deterministic
source-ID/component matching과 tolerance만 필요하다. 기존 path와 filename을 그대로
사용하며 canonical naming, legacy-alias 승인, bundle `README.md`, `metadata.json`, Abaqus
version/provenance, 중복 units/coordinates/model/step/frame/material/section 정보와 CSV schema
version은 요구하지 않는다. Reference artifact는 계속 read-only이며 누락, 추가, 중복,
nonfinite required row는 tolerance 전에 실패한다.
**이유**: Reference comparison의 목적은 FESA의 독립 정식화가 승인된 observable quantity를
충분히 가깝게 계산하는지 판정하는 것이다. 수치 비교에 사용되지 않는 artifact
거버넌스가 formulation review나 implementation planning을 차단하면 제품 검증보다 문서
형식 준수가 우선된다. 같은 정보는 `.inp`, CSV header와 feature contract에서 직접 얻을
수 있다.
**트레이드오프**: Reference 생성 환경을 사후에 완전히 재구성하는 감사 기능은 줄어든다.
대신 비교 대상과 source-row/component mapping, tolerance, artifact immutability는 유지해
false match와 결과 보정을 방지한다. 더 강한 provenance가 필요한 기능은 해당 요구조건이
명시적으로 추가할 수 있으나 프로젝트 기본 gate로 자동 승격하지 않는다.
### ADR-020: MITC4 displacement reference는 고정 절대오차로 판정한다
**상태**: S4 artifact 선택과 U blocking/UR warning-only 분류는 유지하며 고정 절대오차
결정은 ADR-022로 대체됨.
**결정**: Full-integration FESA-MITC4의 sole S4 reference comparison은 matched global
`U1/U2/U3` row에 고정 절대오차 `1.0e-5`를 적용해 pass/fail을 판정한다.
`UR1/UR2/UR3`도 고정 절대오차 `1.0e-5`로 비교하지만 초과는 deterministic warning만
생성한다. Reference scale은 보고용 통계로 남을 수 있으나 MITC4 row tolerance 또는
normalized error의 분모를 결정하지 않는다. ADR-014의 B33 component-scale 혼합
tolerance는 변경하지 않는다.
**이유**: Abaqus S4는 FESA-MITC4와 동일한 요소 정식화가 아니므로 B33에서 승인한 매우
엄격한 component-scale tolerance를 그대로 재사용하는 것은 독립 솔버의 observable
displacement 검증 목적에 맞지 않는다. 고정 절대오차는 현재 사용자 단위계에서 승인된
차이를 명시적으로 제한하면서 zero clamp나 row omission 없이 모든 displacement row를
동일하게 판정한다.
**트레이드오프**: Model scale이 크게 달라지면 고정 절대오차의 상대적 엄격도가 달라질 수
있다. 따라서 이 값은 현재 승인된 MITC4 S4 case의 기능 완료 기준이며 개발 완료 후
별도 reference-verification evidence와 함께 재점검한다.
### ADR-021: Semantic definition과 runtime solver contract를 분리한다
**결정**: Domain-owned semantic definition과 analysis-time numerical object를 다음
dependency 방향으로 분리한다.
```text
Domain owns ElementDefinition / ElementProperty / Material / StepDefinition
AnalysisModel is a non-owning stable-index view into Domain
ElementFactory creates runtime Element candidates from compatible definitions
DofManager -> ElementDofLayout
SparseAssembler -> ElementStiffnessContribution
ResultRecovery -> ElementResultBundle
LoadAssembler -> ordered LoadContribution
EssentialConstraintPolicy -> ConstraintDefinition
Analysis <- LinearStaticAnalysis
```
`Domain`의 polymorphic semantic collection은 `std::unique_ptr` 단독 ownership과 stable
vector position을 사용한다. `ElementDefinition`은 source identity, connectivity와
property/material identity를 제공하고 runtime `Element`는 DOF layout, stiffness와 result
recovery를 제공한다. `ElementFactory`가 definition/property/material compatibility를
중앙에서 검사하며 unknown 또는 incompatible 조합은 fail-closed diagnostic으로 거부한다.
Consumer는 B33/MITC4 concrete type branch를 분산시키지 않고 runtime contract를 사용한다.
Linear-static candidate가 runtime `Element`를 `std::unique_ptr`로 소유하고 consumer는 그
수명에 한정된 non-owning view만 사용한다.
`Material` base에는 identity, source location과 lifetime 이외의 future capability를
추가하지 않는다. 현재 isotropic linear elasticity가 실제로 요구하는 data는 concrete
material에 둔다. Density, anisotropy, plastic state, temperature와 rate dependency는
optional field 또는 no-op virtual method로 미리 할당하지 않는다. `ElementProperty`도
현재 beam/shell 의미를 각 concrete type에 둔다.
`Load`는 ordered `LoadContribution`을 생성하고 global full-DOF accumulation은
`LoadAssembler`가 단독 소유한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고
`EssentialConstraintPolicy`가 prescribed-displacement elimination과 reconstruction을
소유한다. Distributed/body load와 MPC/penalty/Lagrange-multiplier enforcement는 이번
결정으로 구현된 기능이 아니다.
Abaqus Domain mapper, result recovery와 HDF5 writer는 기존 public facade를 유지하면서
각각 topology/material-property/step-final-assembly, equilibrium/beam/shell/atomic-state,
RAII/model-result-dataset/self-check/atomic-finalization 책임으로 private implementation을
나눈다.
**이유**: Semantic identity와 runtime kernel을 같은 concrete record에 두면 DofManager,
SparseAssembler, ResultRecovery, parser와 output이 B33/MITC4 storage를 함께 알아야 한다.
Definition/factory/runtime contract와 contribution/policy 경계를 분리하면 stable source
identity와 deterministic reduction owner를 유지하면서 실제 두 element 구현을 공통
consumer로 연결할 수 있다. Focused facade 분할은 외부 계약을 바꾸지 않고 큰 translation
unit의 서로 다른 failure-atomicity 책임을 검토 가능하게 한다.
**트레이드오프**: Base object, factory와 contribution record가 늘고 checked compatibility에
한 단계의 indirection이 생긴다. 대신 `std::shared_ptr`, speculative `Clone()`, global
registry와 future-only material/analysis capability는 도입하지 않는다. B33/MITC4의 승인된
formulation, 연산·reduction 순서, sign, units, coordinates와 result identity가 이
리팩터링보다 우선하며 HDF5 schema, reference artifact와 ADR-014/ADR-020 tolerance는
변경하지 않는다. MITC3, solid, dynamic과 plastic behavior는 별도 feature gate 전까지
구현된 것으로 간주하지 않는다.
### ADR-022: 외부 reference comparison은 공통 family-scale 정책을 사용한다
운영 상수, 검증 순서, report schema와 변경 관리는 `docs/TOLERANCE.md`를 따른다.
**결정**: B33, MITC4와 이후 기능의 외부 reference comparison은 동일한 무차원 수치
정책을 사용한다. 같은 model/case, step/frame, logical quantity, unit dimension, coordinate
system과 blocking behavior의 component family에 대해 reference-only scale
`S=max(abs(reference))`를 계산한다. `abs(reference)<=0.01*S`인 행은
`abs(fesa-reference)<=0.01*S`, 나머지 행은 `abs(fesa-reference)/abs(reference)<=0.05`를
만족해야 한다. 모든 행과 함께 family scale-relative RMS `RMS(error)/S<=0.01`도
통과해야 한다. 독립 absolute-error gate는 두지 않으며 `S=0`이면 모든 FESA 값도 exact
zero일 때만 통과한다.
B33 family는 translation, rotation, reaction force, reaction moment, section force와
section moment로 구분한다. 2026-08-18에 다시 생성된 elemental-force CSV의
`Element Label`과 `Node Label`을 사용해 `(instance, element, endpoint node, component)`를
HDF5 endpoint에 직접 대응하고 node-station collapse나 평균을 사용하지 않는다. MITC4는
translation `U1/U2/U3` family를 blocking으로, rotation `UR1/UR2/UR3` family를
warning-only로 유지한다.
**이유**: Feature별 absolute floor와 fixed absolute tolerance는 모델 단위와 크기에 따라
서로 다른 엄격도를 만들었다. 개별 component scale은 물리적으로 zero-like인 MITC4
`U1/U2` residue를 자체 scale로 만들어 잘못 실패시킨다. 동일 차원의 family scale,
near-zero 대체 분기와 relative RMS를 결합하면 zero row의 불안정한 raw relative error를
피하면서 모든 행과 전체 오차 수준을 함께 검사할 수 있다. B33의 element-endpoint identity는
reference와 HDF5가 제공하는 실제 source identity를 보존한다.
**트레이드오프**: Family 최대값이 작은 component의 허용폭을 결정하므로 행별 relative
gate와 family RMS gate를 모두 유지해야 한다. Reference family 전체가 zero이면 별도
절대 scale이 없으므로 exact-zero만 허용하는 엄격한 fail-closed 정책이 된다. 기존 B33과
MITC4 verification report 및 comparator schema는 새 정책에 맞춰 다시 생성해야 하지만
reference artifact, HDF5 schema, element formulation과 blocking/warning 분류는 변경하지
않는다.
### ADR-023: Nonlinear Static은 prepared dispatch와 accepted-frame evidence로 분리한다
**결정**: CLI는 하나의 `.inp` operand만 받고 input lexical sibling
`<stem>_results.h5`와 `<stem>_log.txt`를 유도한다. `--output`은 지원하지 않는다.
`PrepareAnalysisInput()`이 syntax/semantic map을 한 번만 수행하고, prepared Domain의
procedure identity가 linear static 또는 separate nonlinear full-Newton procedure를 선택한다.
Nonlinear procedure는 trial/committed state, unsymmetric tangent solver와 iteration log를
독립적으로 소유하며 log close 뒤에만 schema-v1 HDF5 writer가 accepted frames를 atomic publish한다.
schema-v1 `/global/equilibrium`의 six values는 global origin `[0,0,0]`에서 current `X+u`
force arm과 spatial physical nodal moments를 쓴 applied-plus-constrained-reaction balance
error다. Accepted free generalized residual과 constrained-reaction resultant는 distinct
projections이며 result dataset을 서로 대체하지 않는다. Nonlinear reference portfolio는 fine
primary `shellNL-meshfine`, coarse companion `shellNL`, linear control `shell`을 분리한다.
External U is blocking, UR is warning-only, local RF/RM is review-only, and RM3/stress is excluded;
the factor-one internal global force/moment balance and accepted free residual remain blocking.
**이유**: Input parse, linear lifecycle, nonlinear trial state와 writer finalization을 한
procedure에 섞으면 output lifetime과 failure atomicity를 검증할 수 없다. Applied-plus-reaction
balance, constrained reaction과 free residual을 구분하면 nonzero prescribed translation/rotation
case에서도 force arm, mask와 rotation-coordinate conversion의 의미가 보존된다.
**트레이드오프**: Nonlinear path는 linear procedure보다 state/backend/writer 수가 늘고 fine
reference run 시간이 길다. 대신 HDF5 authoritative output, immutable CSV artifact와 external
solver internal-algorithm non-equivalence 원칙을 유지하며 local support-force distribution을
blocking tolerance로 위장하지 않는다.
@@ -0,0 +1,506 @@
# 아키텍처
## 목표
FESA의 아키텍처 목표는 Abaqus `.inp` subset을 내부 semantic model로 변환하고, 유한요소 equation system을 구성해 구조해석 결과를 HDF5로 저장하며, reference comparison과 physics sanity가 가능한 C++17/MSVC 솔버 구조를 제공하는 것이다.
FESA의 element formulation과 numerical path는 Abaqus와 독립적이다. Abaqus `.inp`는
승인된 입력 형식이고 Abaqus CSV는 기능별 blocking quantity의 외부 수치 reference다.
Abaqus 내부 적분, stabilization, state 또는 recovery 동작은 FESA architecture contract가
아니다.
핵심 품질 속성:
- FEM formulation traceability
- explicit I/O contracts
- sparse linear algebra backend isolation
- deterministic verification
- incremental feature addition
- Harness 기반 TDD
현재 승인된 V0 end-to-end 기능은 `linear-static-3d-euler-beam`이다. 상세 계약의
source of truth는
`docs/superpowers/specs/2026-08-08-linear-static-3d-euler-beam-design.md`이며, 이 문서는
그 계약을 전체 solver architecture의 모듈과 데이터 흐름에 배치한다. 아래에 나타난
비선형, 동적, thermal 및 다른 element 계층은 장기 확장 경계이며 V0 지원 범위가 아니다.
## 현재 구현된 디렉토리 구조
```text
include/fesa/ # backend-neutral public C++ API
src/
fesa/
analysis/ # Analysis lifecycle, V0 LinearStaticAnalysis
app/ # CLI application and main
assembly/ # deterministic stiffness/load assembly, ParallelFor adapter
constraints/ # essential-constraint elimination and reconstruction
core/ # source identity, status, diagnostics
elements/ # current B33/MITC4 kernels and recovery
fem/ # DOF/equation numbering and sparse pattern
io/
abaqus/ # .inp syntax reader and semantic Domain mapper
hdf5/ # private HDF5 writer and atomic finalization
math/ # owning Vector, row-major Matrix, 0-based CSR SparseMatrix
model/ # concrete V0 semantic records and immutable Domain
results/ # recovery records, full residual, ResultsWriter boundary
solvers/
linear/ # LinearSolver interface and MKL PARDISO adapter
tests/
unit/ # local contracts and failure paths
integration/ # analysis orchestration and CLI contracts
reference/ # HDF5-to-Abaqus projection and comparison
reference/
<case-dir>/ # declared read-only Abaqus input/required CSV pair
.agents/
skills/ # Harness and review skills
.codex/
hooks.json # PreToolUse/Stop hook registration
agents/ # FESA workflow custom agents
skills/ # FESA solver workflow skills
docs/ # Product, architecture, ADR, workflow artifacts
scripts/
execute.py # Phase step executor
hooks/ # PreToolUse/Stop hook implementations
msvc_harness/ # MSVC project discovery and validation adapters
phases/ # Optional generated phase plans
```
`materials/`, `properties/`, `loads/`와 checked `ElementFactory`는 승인된 C++ modular
refactoring의 target boundary이며 후속 implementation Step에서 추가한다. 이
documentation-only Step 시점에는 현재 구현 디렉토리로 표시하지 않는다. Density,
plasticity, anisotropy, nonlinear/dynamic analysis, MPC/penalty, history output과 production
validation module은 계속 장기 확장 경계이며 별도 승인 기능이 필요하다.
## Harness Execution Layer
Harness는 solver core와 분리된 세 계층의 개발 운영 인프라다.
- 계획 계층: `.agents/skills/harness`가 사용자 승인 전 Step 초안을 만들고, 승인 후 `phases/` 파일을 생성한다.
- 실행 계층: `scripts/execute.py`가 `feat-<phase-name>` 브랜치에서 Step마다 독립 Codex 세션을 실행하고 상태와 커밋을 관리한다.
- 검증 계층: `.codex/hooks.json`이 `scripts/hooks/pre_tool_use.py`와 `scripts/hooks/stop_validation.py`를 연결한다. Stop 검증은 `scripts/msvc_harness/`를 통해 MSVC build와 test를 실행한다.
Runner는 `git add -A`를 사용하므로 clean worktree 또는 별도 Git worktree가 실행 전제다. 전체 동작 계약은 `docs/HARNESS_WORKFLOW.md`, 설치와 `.harness/config.json` 설정은 `docs/HARNESS.md`를 source of truth로 삼는다.
## CMake target과 dependency graph
Root CMake project는 C++17, extension off, CMake 3.25 이상을 요구하고
`cmake/FesaDependencies.cmake`, `src/fesa`, `tests`를 차례로 구성한다.
```text
MKL CONFIG package ─> Fesa::MKL ─┐
TBB CONFIG package ─> Fesa::TBB ─┼─> fesa_solver (STATIC) ─> fesa_cli
HDF5 CONFIG package ─> Fesa::HDF5 ─┘ │
├─> fesa_unit_tests
approved local GoogleTest source ─> GTest targets ├─> fesa_integration_tests
└─> fesa_reference_tests
```
- `FESA_GTEST_SOURCE_DIR`는 네트워크 fetch 대신 승인된 local GoogleTest source checkout을 가리키는 필수 cache path다.
- MKL, TBB, HDF5는 CONFIG package로 탐지한다. Package search가 설치를 찾지 못하면 `MKL_DIR`, `TBB_DIR`, `HDF5_DIR`를 configure 때 지정한다.
- Package별 imported target 이름은 `Fesa::MKL`, `Fesa::TBB`, `Fesa::HDF5`로 정규화한다. Product module은 vendor target 이름을 직접 선택하지 않는다.
- HDF5 package가 shared와 static C target을 모두 제공하면 approved Windows environment에서는 shared target을 우선한다. Static archive의 숨은 compiler-runtime 요구가 link interface 밖으로 새는 것을 피하기 위한 결정이다.
- `fesa_solver`는 외부 dependency를 `PRIVATE`으로 link하고 `/W4 /WX`를 사용한다. 따라서 public header는 MKL/TBB/HDF5/Win32 type을 포함하지 않아야 한다.
- Test executable은 unit, integration, reference 경계를 분리하며 `fesa_tests` target은 세 executable을 build하는 aggregate target이다. Reference target에만 source/build root compile definition을 제공한다.
### Windows runtime closure
Configure 성공은 executable이 GoogleTest discovery 또는 CLI 실행 시 필요한 DLL을 찾는다는
뜻이 아니다. `fesa_cli`와 세 test executable의 POST_BUILD 단계는 TBB, MKL thread/core/default
dispatch, OpenMP, `libmmd.dll`, HDF5를 포함한 imported-target runtime DLL을 executable 옆에
복사한다. 새 dynamic backend를 도입할 때는 link 성공뿐 아니라 clean environment에서의
post-build discovery/실행까지 runtime closure로 다뤄야 한다. 개인 설치 absolute path를
CMake source에 기록하지 말고 config package와 imported target metadata를 확장한다.
## 모듈 경계
- `core`는 외부 라이브러리에 의존하지 않는다.
- `io/abaqus`는 syntax와 semantic mapping만 담당하고 해석 알고리즘을 알지 않는다.
- `model`은 Abaqus keyword 문자열이 아니라 solver semantic model을 가지며 `Domain`과
non-owning `AnalysisModel`의 수명 경계를 소유한다.
- `materials`와 `properties`는 Domain이 소유하는 semantic identity와 현재 승인된
isotropic elasticity 및 beam/shell property data만 제공한다.
- `elements`는 Domain-owned `ElementDefinition`, runtime numerical `Element`, checked
`ElementFactory`와 element-local stiffness/recovery contract를 제공한다.
- `fem`의 `DofManager`는 DOF, equation ordering, scatter와 sparse pattern을 소유한다.
- `assembly`는 runtime element contribution과 ordered load contribution을 stable full-DOF
space에 조립한다. Contribution producer는 global storage를 직접 갱신하지 않는다.
- `loads`는 semantic target과 magnitude를 소유하고 ordered `LoadContribution`을 생성한다.
- `constraints`는 `ConstraintDefinition` 생성과 V0 essential BC elimination 및 full/reduced
vector 변환을 분리한다. MPC와 penalty는 현재 범위가 아니다.
- `solvers`는 `LinearSolver` 뒤에 MKL PARDISO 세부 구현을 감춘다. TBB는 `assembly/ParallelFor`, HDF5는 `results/ResultsWriter` 경계 뒤에 각각 격리된다.
- `analysis`는 step/history data를 받아 procedure를 실행하고 solver backend와 result writer를 조율한다.
- `results`는 full residual과 B33/MITC4 rows를 복구하고 backend-neutral writer contract를
제공한다. HDF5 schema 구현은 `io/hdf5`가 담당한다.
- test helper는 production parser/solver 내부 상태를 우회하지 않는다.
## 승인된 리팩터링 dependency와 ownership
다음 graph는 C++ object-oriented modular refactoring의 구현 방향을 고정한다. `owns`는
단독 수명 소유권을, 나머지 화살표는 왼쪽 consumer가 오른쪽 contract를 사용한다는
뜻이다. 이 graph는 기존 B33/MITC4 물리 기능을 늘리지 않는다.
```text
Domain owns ElementDefinition / ElementProperty / Material / StepDefinition
AnalysisModel is a non-owning stable-index view into Domain
ElementFactory creates runtime Element candidates from compatible definitions
DofManager -> ElementDofLayout
SparseAssembler -> ElementStiffnessContribution
ResultRecovery -> ElementResultBundle
LoadAssembler -> ordered LoadContribution
EssentialConstraintPolicy -> ConstraintDefinition
Analysis <- LinearStaticAnalysis
```
승인된 B33/MITC4 formulation, operation/reduction order, sign, units, coordinates와 row
identity는 이 ownership 리팩터링보다 우선한다. HDF5 schema, reference artifact와
ADR-014/ADR-020 tolerance도 변경하지 않는다.
`Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과 `StepDefinition` base
object를 `std::unique_ptr`로 단독 소유하고 const access를 제공한다. Collection position은
기존 stable `EntityIndex` 의미를 유지한다. `AnalysisModel`과 solver consumer는 ownership을
가져오지 않고 Domain 수명 안에서 stable index 또는 const reference만 사용한다.
`std::shared_ptr`, speculative `Clone()`과 global registry는 이 계약에 포함되지 않는다.
`ElementDefinition`은 source identity, source element type, connectivity와
property/material identity를 보존하는 semantic object다. Runtime `Element`는 active
`ElementDofLayout`, `ElementStiffnessContribution`과 `ElementResultBundle`을 제공하는
numerical kernel이다. `ElementFactory`만 compatible definition/property/material 조합을
검사해 runtime candidate를 만들며 unknown 또는 incompatible 조합을 기존
`Status`/`Result<T>` diagnostic으로 fail-closed 처리한다. `DofManager`,
`SparseAssembler`와 `ResultRecovery`는 B33/MITC4 concrete storage가 아니라 위 runtime
contract를 소비한다. Linear-static candidate는 runtime `Element`를
`std::vector<std::unique_ptr<Element>>`로 소유하고, consumer에는 그 owner 수명 안에서만
유효한 non-owning `ElementView`를 제공한다.
`Material` base는 identity, source location과 수명 의미만 공유한다. 현재 concrete
isotropic linear elasticity에 필요한 capability만 사용하며 density, anisotropy, plastic
state, temperature 또는 rate dependency를 optional field나 no-op method로 미리 추가하지
않는다. `ElementProperty`도 beam/shell이 실제 사용하는 data만 각 concrete type에 둔다.
`Load`는 semantic target과 magnitude를 소유하고 source order가 보존된
`LoadContribution`을 생성한다. Global vector의 deterministic accumulation은
`LoadAssembler`만 수행한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고
`EssentialConstraintPolicy`가 prescribed displacement의 stable elimination과
reconstruction을 수행한다. Future distributed/body load와 MPC enforcement는 구현된
기능이 아니며 별도 승인 계약 없이 이 경계에 branch나 optional state를 추가하지 않는다.
책임이 큰 facade는 외부 계약을 유지한 채 private implementation만 다음 owner로 나눈다.
- Abaqus Domain mapping: topology, material/property, step/load/boundary mapping과 final
Domain assembly
- Result recovery: global equilibrium, beam recovery, shell recovery와 atomic state commit
- HDF5 writing: RAII/primitives, model datasets, result datasets, self-check와 atomic
finalization
이 분할은 parser diagnostic, `ResultsWriter` boundary, HDF5 schema 또는 final-file
atomicity를 변경하지 않는다.
## V0 입력 경계
V0 parser는 keyword와 parameter를 case-insensitive하게 해석하되 source label의 원문을
보존한다. 지원하는 model/procedure 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`
Part 내부 label은 `SourceEntityId { instance_name, source_label }`로 보존하고 Domain은
별도 stable internal index를 부여한다. 같은 part의 여러 identity instance는 허용하지만
translation/rotation data와 nested assembly는 구조화된 unsupported diagnostic으로
거부한다. 입력 파일당 하나의 static step만 허용하고 두 번째 step은 오류다.
`*PREPRINT`, `*RESTART`, `*TRANSVERSE SHEAR STIFFNESS`, `*OUTPUT, FIELD`,
`*OUTPUT, HISTORY`, `*NODE OUTPUT`, `*ELEMENT OUTPUT`, `*CONTACT OUTPUT` 및 그에 속한
미지원 output variable data는 warning 후 no-op 처리한다. 이 allowlist 밖의 미지원
model-affecting keyword는 오류다. FESA output은 Abaqus output request에 좌우되지 않는다.
## V0 beam과 section 계약
`EulerBeam3D`는 2절점과 절점당 `[UX, UY, UZ, URX, URY, URZ]` 6 DOF를 사용하며 축,
두 방향 Euler–Bernoulli 굽힘과 Saint-Venant 비틀림을 제공한다. Beam tangent를 local
`x`, Abaqus first section axis `n1`을 local `y`, `t x n1`을 local `z`로 둔다.
`*BEAM GENERAL SECTION`의 `A, I11, I12, I22, J`는 `Iy=I11`, `Iz=I22`로 매핑하고
V0는 `I12=0`만 허용한다. `E`, `G`, `A`, `Iy`, `Iz`, `J`는 양수여야 하며 zero-length
element와 tangent에 평행한 guide vector를 scale-aware tolerance로 거부한다.
요소 API는 stiffness, transformation, load와 recovery 책임을 분리한다.
```cpp
Matrix localStiffness() const;
Matrix globalStiffness() const;
Vector localEquivalentLoad(const ConstantLocalLineLoad& load) const;
BeamRecovery recover(const Vector& globalElementDisplacement) const;
```
`localEquivalentLoad`는 formulation의 constant local line-load kernel을 unit test하기
위한 계약이다. V0 parser는 `*DLOAD`나 distributed-load Domain object를 생성하지 않으므로
CLI pipeline에서는 이 kernel을 호출하지 않는다. Stiffness와 recovery는 formulation의
2점 Gauss rule과 부호 규약을 따른다.
## 핵심 객체 모델
```text
Domain
├── owns nodes, sets and source identity
├── owns unique_ptr<ElementDefinition / ElementProperty / Material>
├── owns StepDefinition with Load / BoundaryCondition definitions
└── owns source path/identity and mapping warnings
AnalysisModel
├── non-owning stable-index view into Domain
├── stable active element/BC/load definition indices
└── reachable material/property indices
ElementFactory
└── creates checked runtime Element candidates
Element
├── exposes ElementDofLayout
├── produces ElementStiffnessContribution
└── recovers ElementResultBundle
DofManager
├── owns node x [UX,UY,UZ,URX,URY,URZ] full-DOF numbering
├── owns stable free/constrained order and prescribed values
├── owns element scatter maps
└── owns full-space CSR structural pattern
AnalysisState
├── displacement U
├── external force Fext
├── internal force Fint
├── residual R and full-index reaction
├── StepFrameIdentity
└── endpoint, Gauss and S11 recovery rows
Analysis
└── LinearStaticAnalysis
Vector
Matrix
SparseMatrix
```
위 abstract boundary는 현재 B33/MITC4, isotropic linear elasticity, beam/shell property,
concentrated nodal load, prescribed displacement와 linear static procedure를 연결하는 데
필요한 최소 계약이다. MITC3, solid, dynamic, frequency, heat-transfer와 plastic behavior는
구현된 기능이 아니며 승인된 사용 사례 전에 future-only method나 state를 base에 추가하지
않는다.
## 상태 관리
- `Domain`은 입력 파일에서 만들어진 전체 모델 정의를 `std::unique_ptr`로 단독 소유한다.
파싱 이후에는 가능한 한 불변으로 취급하고 stable collection index를 바꾸지 않는다.
- `LinearStaticAnalysis`가 `Domain`을 소유하고, 그 뒤에 `AnalysisModel`, `DofManager`, `AnalysisState`, stiffness/RHS를 순서대로 만든다. 재사용 시에는 역순으로 해제하여 이전 Domain을 가리키는 view를 남기지 않는다.
- `AnalysisModel`은 현재 step에서 활성화되는 해석 객체들의 실행 view이다. `Domain`을 복사하지 않으므로 Domain이 반드시 더 오래 살아야 한다.
- `DofManager`는 자유도와 방정식 번호를 전담한다. `Node` 또는 `Element` 내부에 equation id를 분산 저장하지 않는다.
- `AnalysisState`는 V0 frame에 필요한 다섯 full-DOF vector와 recovery rows만 소유한다. Velocity, acceleration, temperature, iteration history, nonlinear element state는 해당 procedure가 승인될 때 별도 계약으로 추가한다.
- Result recovery는 모든 candidate vector/row를 검증한 뒤 state에 반영한다. 실패한 recovery가 앞선 유효 state를 부분적으로 덮어쓰지 않아야 한다.
## 데이터 흐름
```text
Abaqus input file
-> syntax parse and semantic mapping
-> immutable Domain 생성
-> 단일 step AnalysisModel view 생성
-> ElementFactory가 compatible definition에서 runtime Element candidate 생성
-> DofManager가 ElementDofLayout으로 DOF/scatter map/sparse pattern 생성
-> ElementStiffnessContribution의 deterministic COO-to-CSR 조립
-> ConstraintDefinition의 stable essential-constraint partition 생성
-> LinearSolver::factorize(Kff)
-> ordered LoadContribution의 full nodal load vector 조립
-> effective RHS = Ff - Kfc * dc
-> LinearSolver::solve(rhs, df) substitution
-> full displacement 복구
-> full residual/reaction = K*d - F 및 ElementResultBundle 복구
-> ResultsWriter로 derived `<stem>_results.h5` atomic finalization
```
### 승인된 Nonlinear Static 경로
`PrepareAnalysisInput()`은 input syntax와 semantic Domain을 정확히 한 번 만든다.
`ExecutePreparedAnalysis()`는 sole static step의 procedure identity로 linear static 또는
nonlinear static executor를 선택하며 두 procedure의 mutable state를 공유하지 않는다.
Nonlinear executor는 committed/trial `NonlinearAnalysisState`, full unsymmetric CSR tangent
solver와 closed-before-finalization Newton iteration log를 소유한다. Completion 뒤
`FinalizePreparedAnalysisResult()`가 selected backend-neutral writer로 only accepted frames를
atomic finalization한다.
Nonlinear schema v1의 factor-one `/global/equilibrium`은 raw full-residual sum이 아니라
global origin `[0,0,0]`에서 current `X+u` force arm과 independently spatialized applied and
masked constrained-reaction moments를 합한 applied-plus-reaction balance error다. Accepted
free residual은 generalized residual의 free mask projection이고 constrained-reaction resultant는
별도 review summary다. 어느 quantity도 다른 quantity의 substitute가 아니다.
강성행렬 factorization은 하중벡터 조립보다 먼저 수행한다. 반력은 element end action의
별도 합이 아니라 조립된 전체 residual에서 구한다. Constrained component는 physical
reaction이고 free component는 equilibrium residual evidence로 full-index vector에 남긴다.
## 해석 실행 흐름
`Analysis` base는 procedure-specific protected hook을 정의하지 않고 최소 실행 계약인
`Analysis::Run(const AnalysisRequest&)`만 제공한다. 다음 여덟 단계의 순서와 fail-fast
경계는 `LinearStaticAnalysis::Run()`의 private lifecycle이며 다른 procedure에 강제되지
않는다.
| 순서 | Private stage | 주요 작업과 생성되는 소유 객체 | 순서/실패 불변식 |
| --- | --- | --- | --- |
| 1 | `Initialize(request)` | `.inp` syntax read, semantic map, owned immutable `Domain`, sorted warnings | 이전 run의 dependent object를 역순으로 제거하고 parse/map 실패를 input category로 반환한다. |
| 2 | `BuildAnalysisModel()` | non-owning `AnalysisModel` view | Domain을 복사하지 않으며 Domain lifetime 안에서만 사용한다. |
| 3 | `BuildDofMapAndSparsePattern()` | `DofManager`, zero-initialized `AnalysisState` | Stable full/free/constrained numbering과 structural pattern을 한 소유자에게 둔다. |
| 4 | `AssembleAndPartitionStiffness()` | full CSR K와 `Kff/Kfc/Kcf/Kcc` | Element-local buffer를 deterministic하게 reduce하고 structural zero와 stable order를 보존한다. |
| 5 | `Factorize()` | retained `Kff` factorization | 모든 load assembly보다 먼저 호출한다. Valid fully constrained model의 `0 x 0 Kff`는 trivial success다. |
| 6 | `AssembleLoadsAndEffectiveRhs()` | full F와 `Ff-Kfc*dc` | Semantic load source order와 finite sum을 보존하며 solver를 호출하지 않는다. |
| 7 | `SubstituteAndReconstruct()` | free solution과 full displacement | Factorization을 재수행하지 않고 substitution한 뒤 prescribed value를 stable order로 복구한다. |
| 8 | `RecoverAndWriteResults()` | full residual/reaction, B33/MITC4 rows, final HDF5 | Recovery candidate를 원자적으로 commit하고 writer 성공 뒤에만 최종 output을 교체한다. |
비선형 정적 및 동적 해석은 V0 범위가 아니며 별도 ADR과 formulation을 승인한 뒤 이
lifecycle과 state/equation 계약을 별도 procedure에 정의한다. LinearStaticAnalysis의
private stage 사이에 조용히 반복·증분·시간 적분 동작을 삽입하지 않는다.
## 설계 패턴
- Strategy/Adapter Pattern: `Analysis::Run(const AnalysisRequest&)`, `LinearSolver`,
`ParallelFor`, `ResultsWriter`가 현재 승인된 public 실행/backend 경계다. Vendor API는
concrete adapter implementation 안에만 둔다.
- Procedure-owned lifecycle: `Analysis`는 protected Template Method hook을 공유하지 않고
`LinearStaticAnalysis`가 승인된 여덟 단계 lifecycle을 private하게 소유한다.
- Syntax/Semantic separation: `AbaqusInputReader`는 syntax record를 만들고 `AbaqusDomainMapper`가 승인된 keyword 의미를 concrete Domain record로 변환한다.
- Runtime Polymorphism: backend와 승인된 analysis/element/material/property/load/boundary
경계에만 사용한다. Factory compatibility는 중앙에서 fail-closed로 검사하며 global
registry 또는 future-only capability를 추가하지 않는다.
- RAII: MKL handle, HDF5 file/dataset, temporary solver workspace의 수명과 오류 처리를 wrapper에 묶는다.
## Sparse Matrix Policy
- Assembly는 element마다 index-addressed contribution buffer를 만들고, join 뒤 COO tuple을 stable order로 정렬해 한 thread에서 순서대로 합산한 후 CSR로 finalize한다.
- `SparseMatrix`는 0-based CSR 데이터를 소유하는 별도 타입이며 dense `Matrix`를
상속하지 않는다. MKL PARDISO backend는 adapter 경계에서 필요한 descriptor와 indexing을
변환한다.
- CSR row offset, sorted-unique column, dimensions, finite values를 construction boundary에서 검증하며 structural zero를 삭제하지 않는다.
- Parallel worker는 global sparse matrix나 shared reduction accumulator를 직접 갱신하지 않는다. Worker별 failure slot과 contribution만 쓰고, deterministic reduction은 join 뒤에 수행한다.
- Matrix symmetry와 factorization/substitution failure는 solver adapter가 구조화된 solver diagnostic으로 번역한다. 승인되지 않은 regularization이나 fallback으로 singularity를 숨기지 않는다.
## Dense Math Policy
- `Vector`는 contiguous `double` 데이터와 크기를 소유하고 copy, dot, Euclidean norm,
scale, axpy를 MKL CBLAS adapter로 수행한다.
- `Matrix`는 row-major contiguous `double` 데이터와 dimensions를 소유하고
matrix-vector 및 matrix-matrix 연산에 `CBLAS_ROW_MAJOR`를 사용한다.
- 두 타입은 copy/move semantics와 bounds-checked access를 제공한다.
- MKL header와 MKL-specific type은 adapter implementation 밖으로 노출하지 않는다.
## Parallel Policy
- `ParallelFor`는 `[0,count)` index-addressed 독립 작업만 노출하며 `SerialParallelFor`와 `TbbParallelFor`가 같은 observable contract를 가진다.
- 첫 oneTBB 적용 지점은 element-local stiffness 계산이다. 각 callback은 자기 index의 output slot만 쓴다.
- 전역 sparse write와 부동소수 reduction은 parallel callback 밖의 deterministic 단계로 제한한다.
- MKL 내부 thread와 TBB element loop가 oversubscription을 만들지 않도록 thread count와 task arena 정책을 명시한다.
## HDF5 Result 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
```
Schema requirements:
- schema version, units, coordinate system, solver version, source input identity를 metadata에 기록한다.
- field output과 history output을 구분한다.
- reference comparison을 위한 row identity는 node id, element id, integration point id, step/frame id를 포함한다.
- FESA solver는 input lexical sibling `<stem>_results.h5`를 authoritative output으로 쓰며,
같은 directory의 `<stem>_log.txt`는 procedure log다.
- Abaqus reference results는 기능 문서가 선언한 기존 CSV 파일이다. Directory/file
naming, README, metadata 또는 provenance는 architecture readiness 조건이 아니다.
- Verification은 기능이 요구하는 source identity와 component를 결정적으로 대응시키고
승인 tolerance를 적용한다. Missing/extra/duplicate/nonfinite required row는 숫자 비교
전에 실패한다. 단일 step/final-frame 기능은 별도 CSV step/frame 열을 요구하지 않는다.
- FESA HDF5에서 추출한 deterministic CSV view는 optional debugging/review artifact이며 공식 solver output 또는 reference artifact가 아니다.
- Writer는 final과 같은 directory의 임시 HDF5에 전체 schema를 쓴 뒤 flush, checked close,
read-only reopen/self-check를 수행한다. Existing final은 `ReplaceFileW`, 새 final은
`MoveFileExW(..., MOVEFILE_WRITE_THROUGH)`로 완료하며 실패 시 temporary artifact를
정리하고 불완전한 파일을 정상 `<stem>_results.h5`로 노출하지 않는다.
## V0 결과 복구와 reference normalization
- Nodal displacement와 reaction은 global `[UX, UY, UZ, URX, URY, URZ]` 순서다.
- Equilibrium end action은 local `[FX,FY,FZ,MX,MY,MZ]`, endpoint section resultant는
`[N,T,My,Mz]`, generalized strain/resultant는 두 Gauss point에 기록한다.
- General beam section stress는 section point의 axial `S11`만 복구한다. Section point가
없으면 centroid `(0,0)`을 `source=fesa-default`로 기록한다.
- 승인된 `reference/cantilever beam/cantilever beam elemental forces.csv`는 각 B33
element의 두 endpoint에 `Element Label`, `Node Label`과 `SF1/SM1/SM2/SM3`을 제공한다.
`(instance, element label, endpoint node label, component)` identity로 HDF5
`[element,endpoint,N/T/My/Mz]`에 직접 대응하고 `SF1 -> N`, `SM1 -> My`, `SM2 -> Mz`,
`SM3 -> T`로 비교한다. External reference comparison은 node-station collapse나 평균을
사용하지 않는다.
- Reference tolerance는 같은 model/case, step/frame, logical quantity, unit dimension,
coordinate system과 blocking behavior의 component family에서 Abaqus-only scale
`S=max(abs(reference))`를 구한다. `abs(reference)<=0.01*S`인 행은 absolute error
`<=0.01*S`, 그 외 행은 relative error `<=0.05`로 판정하며 family scale-relative RMS
`RMS(error)/S<=0.01`도 통과해야 한다. 독립 absolute-error gate는 사용하지 않고
zero-scale family는 FESA도 exact zero일 때만 통과한다. 전체 판정 과정과 report/change
management contract는 `docs/TOLERANCE.md`를 따른다.
- Beam stress는 HDF5 schema와 unit/analytical test로 검증하지만 Abaqus reference
comparison은 N/A다.
## CLI와 diagnostics
```powershell
fesa.exe <model.inp>
```
CLI는 input과 같은 lexical sibling directory에 `<stem>_results.h5`와
`<stem>_log.txt`를 유도하고 `--output`을 거부한다. Exit code는
`0=success`, `2=usage`, `3=input syntax/semantic mapping`, `4=model validation`,
`5=factorization/substitution`, `6=HDF5 output`으로 고정한다. Diagnostic은 `severity`,
`code`, `file`, `line`, `keyword`, `entity_identity`, `message`를 가지며 stderr에
deterministic한 순서로 출력한다.
## 기능 확장 플레이북
다음 표는 코드 위치만이 아니라 함께 바뀌어야 하는 계약 경계를 나타낸다. 한 열만
구현하고 다른 열을 생략하면 internal utility 또는 실험 kernel일 수는 있어도 제품 기능은
아니다.
| 기능 유형 | 시작 전에 고정할 것 | 주요 구현 경계 | 함께 검증할 것 | 피해야 할 shortcut |
| --- | --- | --- | --- | --- |
| 새 element/material | DOF, interpolation, constitutive law, integration, local axes/sign, feature-approved validity boundary | Domain record와 mapper, element kernel, DofManager scatter/pattern, SparseAssembler, ResultRecovery | feature-required invariants/tests and blocking reference quantities | 서로 다른 물리를 같다고 주장, source ID와 internal index 혼용, 검증 전 범용 hierarchy 추가 |
| 새 load/constraint | Abaqus target grammar, application order, units, follower 여부, prescribed-value 의미 | Syntax/mapper, Domain target, full-space LoadAssembler 또는 constraint partition, diagnostics | set/direct target ambiguity, multi-instance identity, nonfinite sum, `Ff-Kfc*dc`, reaction | Element load kernel 존재를 parser 지원으로 간주, penalty를 elimination에 몰래 혼합 |
| 새 analysis procedure | governing equation, state variables, increment/time lifecycle, tangent/residual, convergence와 output frame | 별도 Analysis implementation, procedure-specific state/equation owner, solver interface extension | orchestration order, failure atomicity, restart/frame identity, numerical benchmark | V0 hook 사이에 조건문으로 반복/시간 적분 삽입, 사용하지 않는 future state 선할당 |
| 새 numerical backend | matrix/index contract, lifecycle, reusable state, failure taxonomy, thread/runtime policy | 기존 `LinearSolver` 또는 `ParallelFor` interface의 concrete adapter, CMake normalized target | empty/dimension/extreme-scale input, repeated call, failed-output preservation, clean runtime discovery | Vendor type을 public header에 노출, silent fallback/regularization, absolute install path 고정 |
| 새 output/reference quantity | 물리 정의, location, sign, units, coordinates, stable row identity, mandatory 여부, tolerance | Result record/recovery, AnalysisState, ResultsWriter/HDF5 schema, comparator projection | schema dtype/shape, ordering, nonfinite rejection, identity inventory, reference N/A 대체 evidence | 서로 다른 result identity 혼합, station mismatch 평균, output request로 mandatory result 제거 |
모든 확장은 PRD의 제품 완료 정의와 요구조건→정식화→I/O→구현→reference→physics gate를
따른다. 기존 feature contract에 없는 범위를 편의상 “Abaqus compatible”이라고 넓히지 않는다.
## MITC4 확장 경계
MITC4가 구현될 때 Abaqus `S4`와 `S4R` source type은 같은 FESA formulation을 선택한다.
Source type은 metadata/diagnostic identity로 보존하지만 FESA integration 또는 hourglass
경로를 선택하지 않는다. 6-DOF embedding의 비물리 drilling coordinate에는 physical
rotational stiffness block의 positive minimum diagonal에 `1e-3`을 곱한 고정 numerical
stabilization만 둔다. Drilling calibration, artificial-energy policy와 별도 drilling result
dataset은 이 기능 범위가 아니다.
Full-integration FESA-MITC4의 reference comparison은 `reference/shell/` S4의 기존 input 및
displacement CSV만 사용한다. Global `U1/U2/U3` translation family만 blocking이고
`UR1/UR2/UR3` rotation family는 warning-only evidence다. 두 family 모두 ADR-022의 공통
family-scale row/RMS 정책을 사용한다. S4R은
같은 kernel을 선택하는 source mapping과 metadata를 unit/integration tests로 검증하며
`reference/shellR/` artifact는 acceptance comparison에 포함하지 않는다.
Approved nonlinear MITC4 verification은 `reference/shellNL-meshfine/` fine primary,
`reference/shellNL/` coarse companion과 `reference/shell/` linear control을 각각 독립
copied-input directory에서 실행한다. Factor-one global force/moment balance와 accepted free
residual은 blocking internal evidence다. External `U1/U2/U3`는 blocking, `UR1/UR2/UR3`는
warning-only이며 local nodal `RF1/RF2/RF3/RM1/RM2`는 deterministic review-only evidence다;
`RM3`와 stress는 nonlinear numerical comparison에서 제외한다.
+179
View File
@@ -0,0 +1,179 @@
# PRD: FESA 구조해석 솔버
## 목표
FESA는 Abaqus `.inp` keyword subset을 입력으로 받아 자체 유한요소 정식화로 구조해석을
수행하고, step/frame 단위 결과를 input lexical sibling `<stem>_results.h5` HDF5로 저장하며, 기능이 지정한 Abaqus
reference CSV 수치와 비교 가능한 C++17/MSVC 솔버를 제공한다. Abaqus의 요소 알고리즘,
적분법, stabilization 또는 내부 결과 생성 절차를 재현하는 것은 목표가 아니다.
이 프로젝트의 성공 기준은 단순 실행 성공이 아니다. 기능 구현은 요구조건, 정식화,
I/O 계약, C++ build/test와 기능별 blocking reference comparison을 통과해야 완료된다.
Physics sanity와 release readiness는 구현 완료 뒤 별도 배포 판단을 제공하며 Abaqus 내부
동작 동등성을 요구하지 않는다.
## 사용자
- Solver developer: C++17/MSVC/CMake/CTest 환경에서 요소, 재료, 해석 절차, solver backend를 구현한다.
- Verification reviewer: reference artifact, tolerance, physics sanity, release readiness를 검토한다.
- Analyst preparing Abaqus-compatible input subsets: FESA가 지원하는 제한된 `.inp` subset에 맞춰 입력 모델을 준비한다.
- Codex agent workflow operator: project-local agent와 skill을 사용해 요구조건부터 release까지의 gate를 운영한다.
## 핵심 기능
1. Abaqus `.inp` keyword subset parser와 내부 `Domain` semantic model 생성
2. `AnalysisModel`, `DofManager`, `AnalysisState` 기반의 step별 equation system 구성
3. 선형 정적 해석을 시작점으로 하는 `Analysis` procedure 계층
4. Stable source identity를 보존하는 concrete V0 node, B33 element, material, section, boundary, load record
5. sparse matrix pattern 생성, 전역 행렬/벡터 조립, 제약조건 적용
6. `LinearSolver`, `ParallelFor`, `ResultsWriter` interface를 통한 MKL PARDISO, oneTBB, HDF5 backend 격리
7. HDF5 기반 versioned step/frame field-result 저장과 향후 history-output 확장 경계
8. FESA HDF5 rows와 `reference/<model-id>/` 아래 Abaqus reference CSV rows의 직접 비교
9. CMake/MSVC/x64/Debug, CTest 기반 개발 검증
Element/material 계층의 일반적인 runtime polymorphism, iterative solver, history output은 장기 확장 방향이다. 현재 제품 계약으로 간주하지 않으며, 실제 사용 사례와 성능·수명 요구가 승인되기 전에 추상 base class를 미리 추가하지 않는다.
## 사용자 관점 제품 흐름
1. 사용자는 승인된 Abaqus `.inp` subset으로 모델과 단일 analysis step을 기술한다.
2. FESA는 syntax를 읽은 뒤 semantic mapping과 model validation을 수행한다. 지원하지 않는 모델 의미는 구조화된 diagnostic과 안정된 exit code로 거부한다.
3. 해석 procedure는 active model view, DOF/equation map과 sparse system을 만들고, essential constraint elimination을 적용해 선형계를 factorize하고 substitution한다.
4. FESA는 full displacement를 복구하고 equilibrium residual/reaction과 element 결과를 계산한다.
5. 성공 시 output request와 무관한 mandatory 결과, metadata와 diagnostic을 versioned lexical sibling `<stem>_results.h5`에 기록한다. 실패 시 불완전한 최종 결과 파일을 정상 결과처럼 남기지 않는다.
6. 검증 workflow는 기능이 지정한 HDF5 quantity를 기존 Abaqus CSV의 source identity와
component에 대응시켜 tolerance를 판정하고, 별도로 equilibrium과 물리적 타당성을
검토한다. Reference bundle naming이나 provenance는 수치 비교 gate가 아니다.
Parser keyword, element kernel, solver backend 또는 output dataset 중 하나만 추가된 상태는 end-to-end 제품 기능이 아니다. 같은 기능의 입력 의미부터 외부 결과와 검증까지 연결되어야 한다.
## V0 범위
- 선형 정적 해석 파이프라인 구현
- 승인된 첫 end-to-end 기능: 2절점 3D Euler–Bernoulli beam, Abaqus `TYPE=B33`
- 입력 파일당 하나의 `*STEP, *STATIC`
- 절점당 자유도 `[UX, UY, UZ, URX, URY, URZ]`
- 축, 두 방향 굽힘, Saint-Venant 비틀림 및 선형 등방 탄성
- 최소 Abaqus keyword subset:
- `*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`
- `*PREPRINT`, `*RESTART`, `*TRANSVERSE SHEAR STIFFNESS`, `*OUTPUT, FIELD`,
`*OUTPUT, HISTORY`, `*NODE OUTPUT`, `*ELEMENT OUTPUT`, `*CONTACT OUTPUT`과 그에 속한
미지원 variable data는 warning 후 no-op 처리
- 같은 part의 여러 identity instance와 stable source label mapping
- nonzero prescribed displacement를 포함한 free/constrained partition
- formulation의 constant local line-load equivalent nodal vector kernel. V0 parser와 CLI는
`*DLOAD`를 지원하거나 이 kernel을 호출하지 않음
- deterministic COO-to-CSR stiffness assembly
- MKL PARDISO 기반 sparse direct solver
- stiffness factorization과 load-vector substitution 분리
- displacements, reactions, equilibrium end actions, section resultants, generalized results,
axial `S11` output
- HDF5 result schema v0
- `fesa.exe <model.inp>` CLI with lexical sibling result/log names
- 승인된 `reference/cantilever beam/` B33 결과와 displacement, reaction, section resultant
comparison; beam stress reference comparison은 N/A
## 승인된 Nonlinear Static 확장
- `*STATIC, NLGEOM=YES` 단일 step은 parse/map을 정확히 한 번 수행한 뒤 linear static과
분리된 full-Newton procedure로 dispatch한다. Nonlinear path는 별도 mutable state,
unsymmetric tangent solver, iteration log writer와 schema-v1 HDF5 writer를 사용한다.
- CLI는 정확히 하나의 `<model.inp>`만 받고 `<stem>_results.h5`와 `<stem>_log.txt`를 같은
lexical sibling directory에 유도한다. `--output`은 지원하지 않는다.
- Nonlinear HDF5 schema v1은 committed accepted frame만 기록한다. factor-zero는 metadata
baseline이며 accepted frame이 아니고, successful factor-one row는 unique
`load_factor=1.0` accepted frame이다.
- Factor-one `/global/equilibrium`은 global origin에서 current `X+u` arm과 spatial physical
moment를 사용한 applied-plus-constrained-reaction balance error다. Accepted free residual과
constrained-reaction resultant는 그 dataset의 대체 quantity가 아니다.
- `shellNL-meshfine`는 primary nonlinear case, `shellNL`은 companion, `shell`은 linear
regression control이다. `U1/U2/U3`는 blocking, `UR1/UR2/UR3`는 warning-only이며 local
`RF/RM`은 review-only (`RM3` 및 stress 제외)로 비교한다.
## 신규 기능의 제품 완료 정의
새로운 element, load, constraint, material, analysis procedure 또는 output quantity는 다음 조건을 모두 만족할 때 FESA 제품 기능으로 취급한다.
1. 지원 범위와 제외 범위, 실패 category, solver output의 units/coordinates/identity,
blocking reference quantity와 tolerance가 요구조건과 I/O 계약에 명시되어 있다.
2. 필요한 FEM 정식화와 recovery/sign convention이 검토되었고, 수치 위험과 검증 문제를 numerical review가 다룬다.
3. Syntax와 semantic mapping이 내부 모델에 안정된 source identity로 연결되며 잘못된 입력을 fail-closed로 거부한다. Kernel만 제공하는 기능은 parser/CLI 지원 여부를 별도로 표시한다.
4. DOF, sparse pattern, assembly, constraint, solver lifecycle과 mutable state ownership이 기존 아키텍처에 연결되거나 승인된 새 procedure 경계를 가진다.
5. Mandatory HDF5 schema와 diagnostic, CLI 실패 의미가 정의되고 failure path가 기존 state 또는 최종 output을 오염시키지 않는다.
6. Unit test가 local 수식과 validation을, integration test가 orchestration과 외부 계약을,
required reference comparison이 기능별 blocking quantity의 외부 수치 acceptance를
각각 증명한다. Reference가 N/A이면 그 이유와 대체 evidence를 명시한다.
## 기능 요구조건
| ID | 요구조건 | Acceptance Criteria | Verification Method |
| --- | --- | --- | --- |
| FESA-PRD-001 | FESA는 Abaqus `.inp` full compatibility가 아니라 승인된 keyword subset만 지원해야 한다. | 지원/미지원 keyword가 문서화되고, 미지원 keyword는 구조화된 diagnostic을 남긴다. | I/O contract review, parser unit test |
| FESA-PRD-002 | FESA는 입력 모델을 `Domain`으로 변환해야 한다. | nodes, elements, materials, properties, sets, loads, boundary conditions, step definitions가 semantic model에 보존된다. | parser integration test |
| FESA-PRD-003 | FESA는 현재 step의 실행 view를 `AnalysisModel`로 구성해야 한다. | active elements, loads, boundary conditions, properties/materials가 Domain 복사 없이 참조 또는 id view로 연결된다. | analysis model unit test |
| FESA-PRD-004 | FESA는 equation numbering과 constraint/free mapping을 `DofManager`에 집중해야 한다. | Node/Element 내부에 equation id를 분산 저장하지 않는다. | code review, DofManager unit test |
| FESA-PRD-005 | FESA는 해석 중 변하는 물리량을 `AnalysisState`에 저장해야 한다. | V0 displacement, external/internal force, residual, constrained reaction, step/frame identity와 element recovery rows가 출력에 연결되고 velocity, acceleration, temperature, iteration history는 할당하지 않는다. | state unit test, integration test |
| FESA-PRD-006 | FESA는 solver 결과를 derived HDF5 authoritative output `<stem>_results.h5`로 저장해야 한다. | V0 step/frame field results, metadata, diagnostics가 schema version과 함께 저장된다. | HDF5 schema test |
| FESA-PRD-007 | FESA는 기능이 지정한 Abaqus reference CSV quantity와 비교 가능한 deterministic source-row/component mapping을 제공해야 한다. | Required source IDs/components는 일대일 대응되고 missing/extra/duplicate/nonfinite row는 tolerance 전에 실패한다. Canonical naming, README, metadata, provenance 또는 CSV schema version은 요구하지 않는다. | reference comparison report |
| FESA-PRD-008 | FESA의 production C++ 변경은 테스트를 먼저 작성하고 실패를 확인한 뒤 구현해야 한다. | 관련 C++ test file, RED 실패와 후속 GREEN 성공 증거가 있고 Stop의 전체 MSVC build/test가 통과한다. | implementation report, Hook guardrail, CTest |
| FESA-PRD-009 | FESA는 외부 라이브러리 API를 solver core에 직접 노출하지 않아야 한다. | MKL, TBB, HDF5 의존은 adapter module에 제한된다. | architecture review, dependency review |
| FESA-PRD-010 | FESA 기능 구현 완료는 build/test와 기능별 blocking reference comparison 통과를 요구해야 한다. | Required CTest가 통과하고 선언된 blocking quantity가 승인 tolerance 안에 있다. Physics sanity와 release readiness는 별도 후속 gate다. | build/test report, reference verification report |
| FESA-PRD-011 | V0는 입력 파일당 하나의 linear static step과 Abaqus B33 3D Euler beam만 해석해야 한다. | 단일 B33 model은 해석되고, B31과 두 번째 step은 구조화된 unsupported diagnostic으로 거부된다. | parser/semantic unit test, CLI integration test |
| FESA-PRD-012 | V0는 Part/Assembly/Instance wrapper와 source identity를 보존해야 한다. | 여러 identity instance의 node/element/set label이 stable internal ID로 deterministic하게 매핑되고 transform 또는 nested assembly는 거부된다. | semantic mapping unit test |
| FESA-PRD-013 | Output-request allowlist는 해석 의미를 변경하지 않아야 한다. | 승인 keyword와 variable data는 warning 후 no-op이고, allowlist 밖 model-affecting keyword는 오류이며 기본 결과는 output request와 무관하게 생성된다. | parser diagnostic test, HDF5 integration test |
| FESA-PRD-014 | 선형 정적 pipeline은 stiffness factorization과 load substitution을 분리해야 한다. | `Kff` factorization이 load vector assembly보다 먼저 수행되고, `rhs=Ff-Kfc*dc` substitution으로 full displacement를 복구한다. | orchestration test, solver-adapter test |
| FESA-PRD-015 | FESA는 V0 결과와 diagnostic을 안정된 외부 계약으로 출력해야 한다. | CLI가 `0=success`, `2=usage`, `3=input`, `4=model`, `5=solver`, `6=HDF5` exit code를 사용하고 diagnostic field가 계약과 일치하며 HDF5가 displacement, reaction, end force, section resultant, generalized strain/resultant, axial `S11`을 포함하고 실패 시 불완전한 최종 파일을 남기지 않는다. | CLI integration test, HDF5 schema/atomicity test |
| FESA-PRD-016 | Dense와 sparse math storage 및 backend 경계를 분리해야 한다. | `Vector`는 contiguous, `Matrix`는 row-major contiguous storage와 MKL CBLAS를 사용하고 `SparseMatrix`는 별도 0-based CSR 타입이며 MKL 타입이 public core API에 노출되지 않는다. | math unit test, dependency review |
| FESA-PRD-017 | 모든 외부 reference comparison은 승인된 공통 family-scale tolerance를 사용해야 한다. | 각 matched row가 near-zero 대체 조건 또는 상대오차 `0.05`를 통과하고 각 family의 scale-relative RMS가 `0.01` 이하이며 missing/extra/duplicate/nonfinite row는 comparison 전에 실패한다. | reference comparison unit/integration test, verification report |
| FESA-PRD-018 | 승인된 B33 reference artifact는 현재 경로의 read-only baseline으로 유지해야 한다. | `reference/cantilever beam/` 파일을 rename, rewrite 또는 보정하지 않고 기능이 선언한 exact path에서 읽는다. | artifact inventory, Git diff review |
| FESA-PRD-019 | B33 beam section과 local axis를 Abaqus 의미에 맞게 매핑해야 한다. | `n1 -> local y`, `t x n1 -> local z`, `Iy=I11`, `Iz=I22`, `I12=0`을 적용하고 nonpositive property, zero-length element, tangent-parallel guide vector를 구조화된 model diagnostic으로 거부한다. | section-mapping unit test, element geometry test |
## 비기능 요구조건
- MSVC x64 Debug 환경에서 configure, build, CTest를 검증한다.
- reference test 결과는 deterministic해야 한다.
- HDF5 schema는 versioned contract로 관리한다.
- 모든 외부 reference comparison은 동일 logical quantity와 unit dimension의 component
family별 Abaqus-only maximum scale을 사용한다. Near-zero ratio는 `0.01`, 일반 행
상대오차는 `0.05`, family scale-relative RMS는 `0.01`이며 독립 absolute-error gate는
사용하지 않는다.
- B33 section resultant는 source element label과 endpoint node label로 직접 대응한다.
MITC4 `U1/U2/U3`만 blocking이고 `UR1/UR2/UR3` 초과는 warning-only다.
- parser, solver, HDF5 writer는 실패 원인을 구조화된 diagnostic으로 보고한다.
- oneMKL, oneTBB, HDF5는 CMake에서 명시 탐지하고 실패 원인을 분류한다.
- 대규모 모델 성능 최적화보다 V0의 명확성, 테스트 가능성, 검증 traceability를 우선한다.
## Acceptance Gates
1. Requirements approved: 기능 범위, 제외 범위, 입력, 출력, tolerance, 검증 물리량이 정의되어 있다.
2. Research evidence complete: 정식화와 benchmark 근거가 신뢰도와 한계와 함께 정리되어 있다.
3. Formulation reviewed: 약형, shape function, B matrix, constitutive contract, 수치적분, output recovery가 검토되어 있다.
4. I/O contract approved: Abaqus keyword subset, internal model mapping, HDF5 result contract,
required reference quantity의 최소 source-ID/component matching이 승인되어 있다.
5. Tests fail before implementation: C++/integration/reference test를 제품 코드보다 먼저 작성하고 같은 Step 안에서 RED 실패와 후속 GREEN 성공을 확인한다.
6. CMake/CTest pass: MSVC/x64/Debug 기준 configure, build, test가 통과한다.
7. Reference comparison pass: 기능이 blocking으로 선언한 FESA `<stem>_results.h5` quantity가
선언된 Abaqus CSV와 source identity/component별로 대응되고 승인된 tolerance 안에 있다.
8. Physics sanity pass: equilibrium, reaction consistency, displacement direction, symmetry, section-force consistency와 normalized residual이 검토되어 있다.
9. Release readiness pass: acceptance traceability, known limitations, release notes draft가 준비되어 있다.
## 제외 사항
- Abaqus full parser 호환
- Abaqus B31/Timoshenko beam
- 다중 analysis step과 step 간 load/BC propagation
- instance translation/rotation, nested assembly 및 dependent/independent mesh semantics
- `I12 != 0`, taper, offset, release, curved beam, warping
- Abaqus `*DLOAD` 입력과 Domain distributed-load object
- 승인된 fixed-load-factor nonlinear-static 범위를 벗어난 기하·재료비선형, dynamics,
contact, thermal effects
- transverse shear stress와 torsional shear stress recovery
- beam stress에 대한 Abaqus reference comparison
- Abaqus, Nastran 또는 reference solver 직접 실행 자동화
- Agent가 Abaqus reference CSV 파일을 임의 생성 또는 수정하는 작업
- GUI 또는 postprocessor
- Visual Studio `.sln`/`.vcxproj` 전용 MSBuild workflow
- plasticity와 shell end-to-end 구현