# 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 경로, 상대 tolerance 및
물리량별 절대 scale을 명시한다. 요청한 CSV가 없으면 실패하며 요청하지 않은 결과를
통과로 표시하지 않는다. 현재 캔틸레버는 변위와 반력만 요청하고, 요소 내력과
단면 도심 응력 adapter는 synthetic CSV로 검증한다.

요소 내력 CSV의 `(Instance, Element Label, Node Label)` 위치에서
`SF1,SF2,SF3,SM1,SM2,SM3`을 \(N,V_y,V_z,T,M_y,M_z\)로 매핑한다. 응력 CSV의
같은 위치에 있는 `Sxx`는 단면 도심값 \(N/A\)와 비교한다. 단일 Instance에서는
Instance 열 생략을 허용하되 comparison request가 제공한 Instance 이름으로
보완한다.

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 아키텍처의
요구사항으로 간주하지 않는다.
