# Project: FESA Structural Solver ## 기술 스택 - C++17 이상 - MSVC on Windows - CMake + CTest - Python 3 Harness scripts - Intel oneAPI MKL, Intel oneAPI TBB - HDF5 result storage - Abaqus `.inp` keyword subset input ## 프로젝트 정체성 - FESA는 유한요소법 기반 구조해석 솔버를 단계적으로 구축하고 검증하는 프로젝트이다. 목표는 Abaqus를 흉내 내는 parser를 만드는 것이 아니라, 승인된 입력 범위에서 물리적으로 설명 가능하고 재현 가능한 해석 결과를 만드는 것이다. - 새 기능은 입력 keyword만 인식하거나 element kernel만 존재한다고 완성된 것이 아니다. Semantic model, equation system, 해법, 결과 복구, HDF5 외부 계약과 독립 검증 evidence가 하나의 추적 가능한 기능을 이뤄야 한다. - 프로젝트의 배경, 목적, 사용자, 범위는 `docs/PRD.md`에서 확인한다. - 전체 아키텍처와 모듈별 책임은 `docs/ARCHITECTURE.md`에서 확인한다. - 주요 아키텍처 결정과 그 이유 및 트레이드오프는 `docs/ADR.md`에서 확인한다. - AI 에이전트는 설계나 구현 결정을 내리기 전에 PRD에서 제품 범위를, ARCHITECTURE에서 소유권과 데이터 흐름을, ADR에서 이미 결정된 트레이드오프를 먼저 확인한다. 기능별 의미는 `docs/requirements/`, `docs/formulations/`, `docs/io-definitions/`, `docs/reference-models/`의 승인 문서를 source of truth로 삼는다. - Harness는 솔버 자체가 아니라 요구조건, TDD, phase 실행, 검증을 통제하는 개발 운영 인프라이다. 전체 실행 흐름은 `docs/HARNESS_WORKFLOW.md`, 설치와 설정은 `docs/HARNESS.md`를 따른다. - 문서와 구현은 full Abaqus compatibility를 주장하지 않는다. 기능별로 승인된 Abaqus keyword subset만 지원한다. - 공식 solver output은 HDF5 `results.h5`이다. - reference 결과는 FESA와 같은 Abaqus `.inp` 모델을 Abaqus로 해석해 생성한 CSV 파일이다. - reference artifact의 정확한 경로와 파일명은 기능별 reference model contract를 따른다. 신규 모델은 `reference//_*.csv` canonical 이름을 사용한다. - `metadata.json`은 선택 reference artifact다. 파일이 없어도 bundle을 불완전하다고 판정하지 않으며, 필수 provenance, units, coordinate system, step/frame, schema, tolerance 정보는 승인된 기능별 reference model contract에 기록한다. 파일이 존재하면 read-only 보조 자료로 inventory하고 계약과 일치하는지 확인한다. - 승인된 B33 baseline은 예외적으로 `reference/cantilever beam/`의 기존 space-containing 파일명을 read-only legacy alias로 사용한다. - CSV는 FESA 공식 output이 아니며, FESA HDF5에서 추출한 deterministic CSV view는 비교 디버깅/검토용 보조 artifact로만 둔다. ## FESA 개발의 핵심 원칙 ### 물리와 수치 계약 - CRITICAL: 구현보다 요구조건, 정식화, 부호, 단위, 좌표계, row identity와 tolerance 계약을 먼저 고정한다. 구현 편의를 위해 승인된 의미를 조용히 바꾸지 않는다. - CRITICAL: 해석 결과가 유한하고 선형계가 풀렸다는 사실만으로 correctness를 주장하지 않는다. Equilibrium, reaction, rigid-body mode, energy, symmetry와 reference identity를 기능에 맞게 검증한다. - Source label/instance identity와 internal index/equation index를 구분한다. Stable source identity는 진단, 결과, reference mapping 전 구간에서 보존한다. - 병렬 실행 여부와 관계없이 같은 입력은 같은 sparse structure, reduction order, result row order와 diagnostic order를 만들어야 한다. - Scale-aware validation은 formulation과 I/O 계약의 기준을 사용한다. 임의의 `max(1, ...)`, zero clamp, 누락 row 무시 또는 불일치 평균으로 오류를 숨기지 않는다. ### 소유권과 의존성 - CRITICAL: C++ 빌드는 CMake/MSVC/x64/Debug 기준으로 검증한다. - CRITICAL: 새 기능 또는 동작 변경은 테스트를 먼저 작성하고 실패를 확인한 뒤 구현한다. - CRITICAL: C++ production file을 바꿀 때는 관련 C++ test file이 있어야 한다. - CRITICAL: Abaqus reference artifact 생성, 수정, 복원은 명시적으로 요청된 phase에서만 수행한다. - CRITICAL: public header와 implementation 의존성 방향을 역전하지 않는다. - CRITICAL: 사람이 계약과 수치식을 대조할 수 있는 단순한 코드를 작성한다. 주석은 코드가 이미 말하는 동작보다 부호, 수명, 순서, backend 제약처럼 비자명한 이유를 설명한다. - Domain은 입력 파일에서 생성된 전체 모델 정의를 소유하고, 파싱 이후 가능한 한 불변으로 취급한다. - AnalysisModel은 현재 step에서 활성화된 elements, loads, boundary conditions, properties/materials의 non-owning view를 제공하며 Domain을 복사하지 않는다. 따라서 Domain은 AnalysisModel보다 오래 살아야 한다. - DofManager는 node별 자유도 정의, constrained/free mapping, equation numbering, sparse pattern ownership을 전담한다. Node 또는 Element 내부에 equation id를 분산 저장하지 않는다. - AnalysisState는 해당 procedure가 실제로 사용하는 mutable solution과 recovery row만 소유한다. V0는 full displacement/external/internal force/residual/reaction과 step/frame 및 beam recovery rows만 보관하며 미래 state를 미리 할당하지 않는다. - MKL, TBB, HDF5, Win32 API와 vendor type은 public solver core에 노출하지 않는다. `LinearSolver`, `ParallelFor`, `ResultsWriter`, `Vector`, `Matrix`, `SparseMatrix` 경계 뒤에 둔다. - 해석 단계는 실패할 수 있는 candidate를 완성하고 검증한 뒤 소유 state/output에 반영한다. 실패 시 기존 state와 기존 최종 HDF5를 가능한 계약 범위에서 보존한다. ### 선형 정적 해석 불변식 - `Analysis::run()`의 실제 단계와 객체별 책임은 `docs/ARCHITECTURE.md`의 해석 실행 흐름을 따른다. - Full stiffness를 stable free/constrained 순서로 `Kff/Kfc/Kcf/Kcc`에 분할하고, `Kff` factorization을 load assembly보다 먼저 수행한다. - Effective RHS는 `Ff - Kfc * dc`이며 substitution 뒤 full displacement를 복구한다. 모든 DOF가 constrained인 유효한 모델의 `0 x 0 Kff`를 singular error로 바꾸지 않는다. - Reaction과 free-equilibrium evidence는 조립된 full residual `K*d - F`에서 구한다. Constrained 성분은 physical reaction이고 free 성분은 residual evidence다. - Sparse assembly는 element-local contribution과 stable COO ordering, 고정된 reduction을 사용한다. 병렬 worker가 global CSR storage를 직접 갱신하지 않는다. - Element end action, positive-local-x section resultant, Gauss generalized result와 section-point stress는 서로 다른 identity와 부호 계약을 가진다. Station mismatch를 평균으로 합치지 않는다. ### 개발 운영 인프라 - Codex custom agent의 `model_reasoning_effort` 기본값은 `extra high`로 둔다. - Harness runner는 `scripts/execute.py`에 둔다. - `scripts/execute.py`는 `feat-` branch prefix를 사용한다. - runner는 `git add -A`로 변경사항을 stage하므로 실행 전 clean worktree 또는 별도 Git worktree를 사용한다. - Hook 연결은 `.codex/hooks.json`, 구현은 `scripts/hooks/`와 `scripts/msvc_harness/`에 둔다. - PreToolUse는 위험 명령과 C++ production file의 대응 테스트 존재 여부를 검사하는 guardrail이며 RED 실행을 증명하지 않는다. - Stop은 `.harness/config.json` 또는 자동 감지 결과에 따라 MSVC build와 test를 모두 검증한다. - Generated phase execution outputs remain ignored under `phases/**/step*-output.json`. ## 현재 승인된 V0 기능 계약 - `linear-static-3d-euler-beam`의 source of truth는 `docs/superpowers/specs/2026-08-08-linear-static-3d-euler-beam-design.md`이다. 관련 문서를 변경하거나 구현할 때 이 계약의 의미를 임의로 넓히지 않는다. - 입력 파일당 하나의 `*STEP, *STATIC`과 `TYPE=B33`만 지원한다. B31을 Euler 요소로 매핑하지 않고 `unsupported-element-formulation`으로 거부한다. - `*PART/*ASSEMBLY/*INSTANCE`는 identity instance와 stable source identity만 지원한다. instance transform과 nested assembly는 거부한다. - 선형 정적 실행 순서는 stiffness assembly와 constrained partition 뒤 `Kff`를 factorize하고, 그 다음 load vector와 effective RHS를 조립해 substitution하는 순서를 유지한다. - FESA는 output request와 무관하게 displacement, reaction, equilibrium end action, section resultant, generalized strain/resultant, axial `S11`을 HDF5에 기록한다. Beam stress의 Abaqus reference comparison은 N/A다. - B33 reference row는 component별 Abaqus scale로 `absolute_floor + 1e-6 * reference_scale`을 적용한다. Reference 값을 zero-clamp하거나 누락 row를 무시하지 않는다. - `reference/cantilever beam/` artifact는 rename, rewrite 또는 보정하지 않는다. ## 기능을 추가할 때의 판단 기준 - 새 element는 요구조건과 formulation을 승인한 뒤 semantic mapping, property/material 연결, DOF/scatter, local kernel, deterministic assembly, recovery, HDF5 row identity, reference/physics evidence를 함께 설계한다. - 새 load 또는 constraint는 parser 인식만 추가하지 않는다. Source target resolution, stable application order, full-space assembly, partition/effective RHS, diagnostic과 결과 의미까지 연결한다. - 새 analysis procedure는 기존 선형 정적 lifecycle에 조건문을 누적하지 않는다. 필요한 state, equation, solver lifecycle과 recovery contract를 별도 요구조건·ADR·formulation으로 정의한다. - 새 backend는 기존 public interface를 유지하고 vendor lifecycle, integer/index conversion, runtime dependency와 failure translation을 adapter 내부에 격리한다. - 새 output quantity는 계산식뿐 아니라 units, coordinate system, source/internal identity, HDF5 schema, mandatory 여부, reference projection과 tolerance를 동시에 정의한다. - Element API에 kernel이 존재하는 것과 Abaqus keyword/CLI에서 그 기능을 노출하는 것은 별도 계약이다. 예를 들어 V0의 line-load kernel은 `*DLOAD` 지원을 뜻하지 않는다. ## 개발 프로세스 - TDD를 기본으로 한다. 구현은 `RED -> GREEN -> VERIFY` 순서를 따른다. - CRITICAL: 빌드 경고를 새로 추가하지 말 것. - 기능 개발은 다음 gate를 순서대로 통과해야 한다. 1. 요구조건 분석 2. 연구자료 조사 3. 유한요소 정식화 4. 수치 검토 5. I/O 계약 정의 6. reference model 계약 준비 7. C++ 구현 8. build/test 검증 9. reference comparison 10. physics sanity 11. release readiness - 커밋 메시지는 conventional commits 형식을 따른다: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`. ## Agent/Skill Workflow AI 에이전트는 유한요소 구조해석 지식이 필요할 때 FEM wiki를 참조하기 위해 `.codex/skills/fem-theory-query` 스킬을 사용할 수 있다. | 개발 과정 | Agent | Skill | 산출물 | | --- | --- | --- | --- | | 요구조건 분석 | `requirement-agent` | `fesa-requirements-baseline` | `docs/requirements/.md` | | 연구자료 조사 | `research-agent` | `fesa-research-evidence`, `fem-theory-query` | `docs/research/-research.md` | | 유한요소 정식화 | `formulation-agent` | `fesa-formulation-spec` | `docs/formulations/-formulation.md` | | 수치 검토 | `numerical-review-agent` | `fesa-numerical-review` | `docs/numerical-reviews/-review.md` | | I/O 정의 | `io-definition-agent` | `fesa-io-contract` | `docs/io-definitions/-io.md` | | reference model | `reference-model-agent` | `fesa-reference-models` | `docs/reference-models/-reference-models.md` | | 구현 계획/구현 | `implementation-planning-agent`, `implementation-agent` | `fesa-cpp-msvc-tdd` | tests, source, implementation report | | build/test | `build-test-executor-agent` | `fesa-cpp-msvc-tdd` | `docs/build-test-reports/.md` | | correction | `correction-agent` | `fesa-cpp-msvc-tdd` | `docs/corrections/.md` | | reference 비교 | `reference-verification-agent` | `fesa-reference-comparison` | `docs/reference-verifications/-reference-verification.md` | | 물리 검토 | `physics-evaluation-agent` | `fesa-physics-sanity` | `docs/physics-evaluations/-physics-evaluation.md` | | 배포 준비 | `release-agent` | `fesa-release-readiness` | `docs/releases/-release.md` | ## 최소 검증 진입점 세부 target graph, dependency normalization과 Windows runtime staging은 `docs/ARCHITECTURE.md`와 실제 CMake 파일을 따른다. `.harness/config.json`이 존재하면 그 설정을 우선한다. ### Harness Python 검증 ```powershell uv run --with pytest python -m pytest -v -rs ``` ### Phase 실행 ```powershell python scripts/execute.py python scripts/execute.py --push ``` ### CMake/CTest 프로젝트 ```powershell $gtestSource = "C:/path/to/googletest" $mklDir = "C:/path/to/oneAPI/mkl/lib/cmake/mkl" $tbbDir = "C:/path/to/oneAPI/tbb/lib/cmake/tbb" $hdf5Dir = "C:/path/to/HDF5/cmake" cmake --fresh -S . -B .harness/build -G "Visual Studio 18 2026" -A x64 ` "-DFESA_GTEST_SOURCE_DIR=$gtestSource" ` "-DMKL_DIR=$mklDir" ` "-DTBB_DIR=$tbbDir" ` "-DHDF5_DIR=$hdf5Dir" cmake --build .harness/build --config Debug ctest --test-dir .harness/build -C Debug --show-only=json-v1 ctest --test-dir .harness/build -C Debug --output-on-failure ``` `FESA_GTEST_SOURCE_DIR`는 approved local GoogleTest source checkout을 반드시 가리켜야 한다. MKL/TBB/HDF5가 기본 package search에서 발견되지 않는 환경에서는 나머지 세 config directory도 명시한다. FESA 제품 검증은 solution-only MSBuild가 아니라 CMake target과 CTest를 기준으로 한다.