# 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-id>/
    model.inp
    <model-id>_displacements.csv
    <model-id>_reactions.csv
    <model-id>_internalforces.csv
    <model-id>_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/<step-id>/frames/<frame-id>
│       ├── 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/<model-id>`: 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/<phase-name>` 브랜치 및 명시적 clean-worktree 정책은 FESA 아키텍처의
요구사항으로 간주하지 않는다.
