# FESA Architecture ## 1. 목표 FESA의 아키텍처 목표는 Abaqus `.inp` 부분집합을 내부 semantic model로 변환하고, 유한요소 equation system을 구성해 구조해석 결과를 HDF5로 저장하며, reference comparison과 physics sanity가 가능한 C++20/MSVC 솔버 구조를 제공하는 것이다. 핵심 품질 속성: - FEM formulation traceability - explicit I/O contracts - sparse linear algebra backend isolation - deterministic verification - incremental feature addition - Harness 기반 TDD와 workspace validation ## 2. 디렉터리 구조 public header와 implementation은 같은 모듈 구조를 사용한다. ```text include/ fesa/ core/ io/ abaqus/ hdf5/ model/ fem/ elements/ materials/ assembly/ constraints/ solvers/ linear/ nonlinear/ analysis/ results/ validation/ src/ fesa/ core/ io/ abaqus/ hdf5/ model/ fem/ elements/ materials/ assembly/ constraints/ solvers/ linear/ nonlinear/ analysis/ results/ validation/ tests/ unit/ integration/ reference/ reference/ / model.inp _displacements.csv _reactions.csv _internalforces.csv _stresses.csv .agents/ skills/ harness/ review/ .codex/ hooks.json .harness/ config.example.json config.json docs/ scripts/ execute.py hooks/ msvc_harness/ phases/ ``` 목표 구조는 장기적인 namespace와 책임 분류다. 실제 소스 디렉터리와 클래스는 해당 기능을 구현하는 phase에서만 만든다. Phase 1에서 실체화하는 범위: - `elements/beam`: 2절점 3D Timoshenko Beam - `materials/elastic`: 등방성 선형 탄성 - `constraints`: essential BC elimination - `solvers/linear`: MKL PARDISO - `analysis`: `LinearStaticAnalysis` - `results`: 단일 step/frame의 field와 diagnostic output Truss, plane, solid, shell, plasticity, MPC, nonlinear, dynamic, frequency 및 heat transfer는 목표 taxonomy로만 유지하고 빈 구현을 미리 만들지 않는다. ## 3. 모듈 경계 ### `core` ID, status, diagnostic, source location 및 작은 값 타입을 제공한다. 외부 라이브러리에 의존하지 않는다. 단위 변환 엔진은 두지 않고 일관 단위계 규약만 표현한다. ### `io/abaqus` `.inp` lexer/parser, flat 또는 Part/Assembly/Instance scope record 및 syntax-to-semantic mapping을 담당한다. 해석 알고리즘과 equation numbering을 알지 않는다. parser의 임시 syntax 객체는 `model`에 노출하지 않는다. `*HEADING`, `*PREPRINT`, `*RESTART`, `*OUTPUT`은 명시적인 no-op record로 처리하고 일반적인 unknown-keyword ignore 경로를 만들지 않는다. ### `io/hdf5` HDF5 결과 writer/reader, schema versioning 및 HDF5 resource 수명을 담당한다. HDF5 handle은 RAII wrapper 밖으로 노출하지 않는다. ### `model` 활성 Instance에서 정규화된 절점, 요소, 집합, 재료, 단면, step, 하중 및 경계조건의 solver semantic model을 소유한다. Part/Assembly keyword record나 MKL 자료구조를 저장하지 않는다. ### `fem` DOF 정의, equation numbering 계약, quadrature, shape function, Jacobian 및 local/global mapping을 제공한다. 특정 analysis procedure에 종속되지 않는다. ### `elements`와 `materials` 요소의 local contribution과 결과 회복 계약을 제공한다. Phase 1 요소는 선형 문제에 필요한 local stiffness, equivalent load 및 section response만 계산한다. ### `assembly` local-to-global mapping, sparse pattern 생성, contribution 정렬·병합 및 COO/CSR 변환을 담당한다. 요소 formulation이나 PARDISO handle을 소유하지 않는다. ### `constraints` essential BC와 full/reduced vector 변환 정책을 담당한다. Phase 1에는 elimination만 구현하고 MPC, penalty 및 Lagrange multiplier는 추가하지 않는다. ### `solvers` 희소 선형계 backend 경계를 제공한다. Phase 1의 `solvers/linear`는 MKL PARDISO를 adapter로 감싸며 symbolic analysis, factorization, solve 및 release 수명을 관리한다. ### `analysis` step data를 실행 가능한 `AnalysisModel`로 변환하고 DOF, assembly, constraint, solver 및 result writer를 조율한다. 구체 수치 kernel이나 외부 API를 직접 구현하지 않는다. ### `results` nodal, element, integration-point, field, history 및 diagnostic output의 semantic 표현을 담당한다. Phase 1에는 nodal/element field와 diagnostic만 실체화한다. ### `validation` reference mapping, 비교 metric, tolerance와 physics sanity helper를 제공한다. production parser와 solver 내부 상태를 우회하는 별도 해석 경로를 만들지 않는다. ## 4. 핵심 객체 모델 ```text ParsedDeck (io/abaqus 전용) ├── PartDefinition[] ├── AssemblyDefinition │ └── InstanceDefinition[1] ├── MaterialDefinition[] └── StepDefinition Domain ├── Node ├── Element ├── Material ├── Property ├── NodeSet ├── ElementSet ├── BoundaryCondition ├── Load └── StepDefinition AnalysisModel ├── active elements ├── active loads ├── active boundary conditions ├── active properties/materials └── equation system view AnalysisState ├── displacement U ├── external force Fext ├── internal force Fint ├── residual R ├── reaction └── element/integration-point response DofManager ├── node dof definitions ├── constrained/free dof mapping ├── equation numbering ├── element equation adjacency view └── full/reduced vector reconstruction Results └── ResultStep └── ResultFrame ├── FieldOutput ├── HistoryOutput └── DiagnosticOutput ``` 장기 목표인 `AnalysisState`의 velocity, acceleration, temperature, increment, iteration 및 material state는 해당 해석 기능을 구현할 때 추가한다. Phase 1 객체에 사용되지 않는 상태를 미리 할당하지 않는다. ## 5. 상태 관리 - `Domain`은 입력에서 만들어진 전체 모델 정의를 소유한다. - syntax-to-semantic mapping과 validation이 끝난 `Domain`은 가능한 한 불변으로 취급한다. - 계층형 입력의 외부 ID는 `(instance name, part-local label)`로 표현하고 내부 dense index와 구분한다. flat 입력은 예약된 global scope를 사용한다. - 여러 Part를 파싱할 수 있지만 단일 Assembly의 단일 무변환 Instance가 참조하는 Part만 `Domain`에 포함한다. - `AnalysisModel`은 현재 step에서 활성화되는 객체의 ID/참조 기반 view다. `Domain`을 복제하지 않는다. - `DofManager`는 DOF와 equation numbering을 전담한다. `Node`와 `Element`에 equation ID를 저장하지 않는다. - `AnalysisState`는 해석 중 변하는 물리량만 소유한다. - 결과는 `ResultStep -> ResultFrame -> FieldOutput/HistoryOutput` 구조로 관리한다. ## 6. 데이터 흐름 ```text Abaqus input file -> lexer/parser -> scoped syntax records -> complete-deck reference resolution -> flat scope 또는 단일 active Part/Instance 선택 -> set/material/section/load/BC 정규화와 validation -> immutable Domain -> StepDefinition -> AnalysisModel -> DofManager -> sparse pattern -> element contributions -> deterministic Assembler -> essential BC elimination -> MKL PARDISO -> full state/reaction reconstruction -> element result recovery -> Results -> HDF5 writer ``` 파싱, semantic validation, equation construction, solve 및 output 단계는 서로 다른 diagnostic context를 유지한다. ## 7. 해석 실행 흐름 `Analysis::run()`은 다음 생명주기를 고정한다. ```text initialize buildAnalysisModel buildDofMap buildSparsePattern executeProcedure finalizeResults ``` Phase 1의 `LinearStaticAnalysis::executeProcedure()`는 다음을 수행한다. ```text assemble applyBoundaryConditions solve reconstructFullState recoverReactions recoverElementResults writeResults ``` 미래의 비선형·동적 해석은 `executeProcedure` 내부에 각각 Newton 또는 time-step loop를 소유한다. base class가 모든 해석 종류의 반복 변수를 미리 소유하지 않는다. ## 8. Timoshenko Beam kernel Phase 1 kernel은 다음 입력만 받는다. - 두 절점 좌표 - 12개 local/global DOF mapping - \(E,\nu\) - \(A,I_y,I_z,J,A_{sy},A_{sz}\) - 국부 단면축 기준 방향 - 필요한 평가 위치와 회복점 kernel 책임: - 강건한 국부 직교 기저 생성 - 자연좌표 shape function과 Jacobian 평가 - 축·굽힘·비틀림 2점 Gauss 적분 - 전단 1점 Gauss 적분 - local stiffness와 global transformation - section strain/resultant와 \(\sigma_{xx}\) 회복 kernel은 Abaqus의 slenderness compensation을 구현하지 않는다. 명시적 전단강성이 없으면 semantic mapper가 \(A_{sy}=A_{sz}=5A/6\)과 `SCF=0`을 적용한다. 명시적 전단강성은 이 기본값을 덮어쓰며 nonzero `SCF`는 거부한다. ## 9. 희소 조립과 병렬성 1. `assembly`의 sparse pattern builder가 요소 connectivity와 `DofManager`의 equation mapping으로 sparsity pattern을 생성한다. 2. oneTBB가 요소별 local contribution을 독립적으로 계산한다. 3. worker는 공유 CSR 값 배열에 무질서하게 누적하지 않고 thread-local contribution을 생성한다. 4. contribution을 전역 row, column 및 안정된 tie-break key로 정렬한다. 5. 고정된 순서로 합산해 대칭 CSR을 생성한다. 6. essential BC를 소거해 reduced symmetric system을 만든다. 7. TBB 작업이 끝난 뒤 MKL PARDISO를 호출한다. 성능보다 같은 입력·설정에서의 수치 재현성을 우선한다. 병렬·직렬 결과 비교와 thread count 변화 테스트를 reference suite에 포함한다. ## 10. 선형해법 backend `LinearSolver` 경계는 matrix structure, numeric values, RHS를 입력받고 solution과 진단을 반환한다. Phase 1의 유일한 구현은 `PardisoLinearSolver`다. PARDISO adapter 책임: - 0-based 대칭 CSR 계약 검증 - analysis, factorization, solve 및 release phase 관리 - MKL error code를 FESA diagnostic으로 변환 - matrix checker와 residual diagnostic 제공 - handle과 workspace의 RAII 수명 관리 반력은 reduced solve 결과를 full vector로 복원한 뒤 원래 시스템의 \(r=Ku-f\)에서 계산한다. ## 11. HDF5 schema 최상위 구조: ```text / ├── metadata ├── model │ ├── nodes │ ├── elements │ ├── sets │ ├── materials │ ├── properties │ └── id_maps ├── analysis │ ├── steps │ ├── boundary_conditions │ ├── loads │ └── solver_settings ├── results │ └── steps//frames/ │ ├── nodal │ ├── element │ └── history └── diagnostics ``` 작은 schema 정보와 설명은 attribute로, 수치 배열과 가변 크기 데이터는 dataset으로 저장한다. root metadata에는 schema version, FESA version, 입력 fingerprint, 좌표계 및 단위 정책을 기록한다. 계층형 입력은 Part/Instance 이름, part-local ID와 전단강성 값의 입력/기본값 출처를 함께 저장한다. ## 12. 오류 처리 진단은 최소한 다음 분류를 가진다. - I/O 및 encoding 오류 - lexical/syntax 오류 - 미지원 keyword/option - semantic reference 오류 - model validity 오류 - equation system 오류 - numerical solver 오류 - result recovery 또는 HDF5 오류 각 진단은 가능한 경우 source file, line, keyword, entity ID, analysis stage 및 원인을 포함한다. 다음 조건은 묵시적으로 보정하지 않고 실패시킨다. - 길이가 0인 요소 - 요소축과 평행하거나 길이가 0인 단면 방향 벡터 - 존재하지 않는 절점·집합·재료·단면 참조 - 중첩 집합 순환 - 여러 Assembly/Instance 또는 Instance 평행이동·회전 - Instance가 참조하지 않는 Part entity를 Assembly 집합이 참조하는 경우 - 재료나 단면이 없거나 중복 할당된 요소 - 상충하는 경계조건 - 강체모드가 남은 singular equation system - NaN 또는 무한대 입력·결과 ## 13. 설계 패턴 - Adapter: Abaqus, MKL, TBB 및 HDF5 경계 - RAII: PARDISO handle, HDF5 object와 temporary workspace - Strategy: 실제 교체 가능성이 있는 solver와 writer 경계 - Template Method: `Analysis::run()`의 공통 생명주기 - Factory: Phase 1에는 B31을 생성하는 명시적 factory - Registry: 두 번째 실제 요소나 material type이 추가되는 phase에서만 도입 - Runtime polymorphism: assembly가 구체 요소 내부 상태를 알지 않게 하는 최소 계약 대규모 모델에서 virtual dispatch가 병목이라는 측정 결과가 있을 때만 타입별 batch kernel을 추가한다. ## 14. 검증 구조 - `tests/unit`: 값 타입, parser 단위, shape function, quadrature, transformation, element matrix - `tests/integration`: `.inp`에서 HDF5까지 전체 경로 - `tests/reference`: CSV 골든 결과와 FESA HDF5 결과 비교 - `reference/`: Abaqus 입력과 현재 사용할 수 있는 결과 CSV reference comparison request가 비교할 물리량과 CSV 경로 및 물리량별 절대 scale을 명시한다. 요청한 CSV가 없으면 실패하며 요청하지 않은 결과를 통과로 표시하지 않는다. 현재 캔틸레버는 변위, 반력 및 요소 단면력을 요청하고, 단면 도심 응력 adapter는 synthetic CSV로 검증한다. 요소 내력 CSV의 `(Instance, Element Label, Node Label)` 위치에서 `SF1,SF3,SF2,SM3,SM1,SM2`를 \(N,V_y,V_z,T,M_y,M_z\)로 매핑한다. 응력 CSV의 같은 위치에 있는 `Sxx`는 단면 도심값 \(N/A\)와 비교한다. 단일 Instance에서는 Instance 열 생략을 허용하되 comparison request가 제공한 Instance 이름으로 보완한다. Abaqus와 FESA의 정식화가 다른 상관성 비교는 component별 RMSE와 Relative L2를 보고하며 관측값으로 만든 pass/fail tolerance를 적용하지 않는다. reference helper는 반드시 public parser와 analysis 경로로 FESA 결과를 생성한다. 테스트 전용 경로로 Domain이나 matrix를 직접 주입해 전체 파이프라인 결함을 숨기지 않는다. ## 15. Harness 실행 계층 현재 저장소의 `scripts/execute.py`, `docs/HARNESS.md` 및 `.agents/skills/harness/SKILL.md`를 실행 계약으로 사용한다. Executor 동작: - `feat-{phase-name}` 브랜치 생성 또는 checkout - `AGENTS.md`와 `docs/*.md` guardrail 주입 - 완료된 step의 `summary`를 다음 prompt에 전달 - 실패 시 이전 오류를 포함해 최대 3회 재시도 - 코드 변경과 phase metadata를 분리해 commit - step/phase timestamp 기록 - `--push` 사용 시에만 원격 push Codex hook 동작: - PreToolUse hook은 위험한 명령 패턴을 검사한다. - Stop hook은 감지된 C/C++ 프로젝트를 MSVC로 빌드하고 테스트한다. - `.harness/config.json`이 있으면 해당 설정과 preset을 우선한다. 현재 executor에 없는 `allowed_paths`, `validate_workspace.py`, `codex/` 브랜치 및 명시적 clean-worktree 정책은 FESA 아키텍처의 요구사항으로 간주하지 않는다.