16 KiB
아키텍처
목표
FESA의 아키텍처 목표는 Abaqus .inp subset을 내부 semantic model로 변환하고, 유한요소 equation system을 구성해 구조해석 결과를 HDF5로 저장하며, reference comparison과 physics sanity가 가능한 C++17/MSVC 솔버 구조를 제공하는 것이다.
핵심 품질 속성:
- 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 지원 범위가 아니다.
디렉토리 구조
src/
fesa/
core/ # ids, status, diagnostics, units, small value types
io/
abaqus/ # .inp lexer/parser, keyword subset, include policy
hdf5/ # HDF5 result writer/reader, schema versioning
model/ # semantic model: nodes, elements, sets, materials, sections, steps
fem/ # DOF space, equation numbering, quadrature, shape functions
elements/ # truss/bar, beam, plane, solid, shell element routines
materials/ # elastic/plastic material contracts and state variables
assembly/ # local-to-global mapping, sparse pattern, COO/CSR assembly
constraints/ # essential BC, MPC, penalty or elimination policies
solvers/
linear/ # MKL PARDISO backend, iterative backend boundary
nonlinear/ # Newton control, residual/tangent norms, increments
analysis/ # static, modal, dynamic, nonlinear procedure drivers
results/ # recovery, field/history output, diagnostics
validation/ # comparison metrics and tolerance helpers
math/ # owning Vector, row-major Matrix, CSR SparseMatrix adapters
tests/
unit/
integration/
reference/
reference/
<model-id>/
model.inp
metadata.json
<model-id>_displacements.csv
<model-id>_reactions.csv
<model-id>_internalforces.csv
<model-id>_stresses.csv
.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
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로 삼는다.
모듈 경계
core는 외부 라이브러리에 의존하지 않는다.io/abaqus는 syntax와 semantic mapping만 담당하고 해석 알고리즘을 알지 않는다.model은 Abaqus keyword 문자열이 아니라 solver semantic model을 가진다.fem은 DOF, interpolation, quadrature, local/global mapping을 제공하되 특정 analysis procedure에 종속되지 않는다.elements와materials는 local residual/tangent/stress recovery 계약을 제공한다.assembly는 sparse pattern 생성과 local contribution 조립을 담당한다.constraints는 essential BC, MPC, penalty/elimination 정책을 분리한다.solvers는 MKL/TBB 세부 구현을 감추는 backend boundary를 가진다.analysis는 step/history data를 받아 procedure를 실행하고 solver backend와 result writer를 조율한다.results는 HDF5 schema를 통해 nodal, element, integration-point, diagnostic output을 분리한다.- test helper는 production parser/solver 내부 상태를 우회하지 않는다.
V0 입력 경계
V0 parser는 keyword와 parameter를 case-insensitive하게 해석하되 source label의 원문을 보존한다. 지원하는 model/procedure keyword는 다음과 같다.
*HEADING*PART,*END PART*NODE*ELEMENT, TYPE=B33*NSET,*ELSET, includingGENERATE*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 책임을 분리한다.
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과 부호 규약을 따른다.
핵심 객체 모델
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
├── velocity V
├── acceleration A
├── temperature T
├── external force Fext
├── internal force Fint
├── residual R
├── current time / increment / iteration
└── element state / integration point state
DofManager
├── node dof definitions
├── constrained/free dof mapping
├── equation numbering
├── sparse matrix pattern ownership
└── full/reduced vector reconstruction
Analysis
├── LinearStaticAnalysis
├── NonlinearStaticAnalysis
├── DynamicAnalysis
├── FrequencyAnalysis
└── HeatTransferAnalysis
Element
├── Element1D
│ ├── Truss
│ └── Beam
├── Element2D
│ ├── MITC3
│ └── MITC4
└── Element3D
├── Hexahedral
├── Tetrahedral
├── Wedge
└── Pyramid
BoundaryCondition
├── Fix
├── RBE2
└── RBE3
Load
├── NodalLoad
├── PressureLoad
└── BodyForce
Results
├── ResultStep
├── ResultFrame
├── FieldOutput
└── HistoryOutput
Vector
Matrix
SparseMatrix
이 객체 모델 중 V0 Analysis 구현은 LinearStaticAnalysis 하나이며 AnalysisState는
full displacement, external/internal force, residual, constrained reaction, step/frame
identity와 element recovery rows만 할당한다. Velocity, acceleration, temperature,
iteration history와 nonlinear element state는 V0에서 할당하지 않는다.
상태 관리
Domain은 입력 파일에서 만들어진 전체 모델 정의를 소유한다. 파싱 이후에는 가능한 한 불변으로 취급한다.AnalysisModel은 현재 step에서 활성화되는 해석 객체들의 실행 view이다.Domain을 복사하지 않고 참조 또는 id 기반 view로 구성한다.DofManager는 자유도와 방정식 번호를 전담한다.Node또는Element내부에 equation id를 분산 저장하지 않는다.AnalysisState는 해석 중 변하는 물리량과 반복 상태를 소유한다. Phase 1에서는 displacement 중심으로 최소 구현하되, 기하비선형과 thermal-stress coupling을 위해 element/internal state 확장 지점을 유지한다.- 결과는
ResultStep->ResultFrame->FieldOutput/HistoryOutput구조로 관리한다.
데이터 흐름
Abaqus input file
-> syntax parse and semantic mapping
-> immutable Domain 생성
-> 단일 step AnalysisModel view 생성
-> DofManager DOF/scatter map/sparse pattern 생성
-> element stiffness 계산과 deterministic COO-to-CSR 조립
-> free/constrained partition 생성
-> LinearSolver::factorize(Kff)
-> full nodal load vector 조립
-> effective RHS = Ff - Kfc * dc
-> LinearSolver::solve(rhs, df) substitution
-> full displacement 복구
-> reaction = K*d - F 및 element result 복구
-> ResultsWriter로 results.h5 atomic finalization
강성행렬 factorization은 하중벡터 조립보다 먼저 수행한다. 반력은 element end action의 별도 합이 아니라 조립된 전체 residual에서 구한다.
해석 실행 흐름
Analysis::run()은 Template Method로 다음 V0 흐름을 고정한다. 해석 종류별 class는
승인된 procedure contract 안에서 필요한 단계만 재정의한다.
initialize
buildAnalysisModel
buildDofMap
buildSparsePattern
assembleStiffness
partitionConstraints
factorize
assembleLoads
formEffectiveRhs
substitute
reconstructDisplacement
recoverResults
writeResults
비선형 정적 및 동적 해석은 V0 범위가 아니며 별도 ADR과 formulation을 승인한 뒤 이 lifecycle의 확장 지점을 사용한다.
설계 패턴
- Strategy Pattern:
Analysis,LinearSolver,TimeIntegrator,ConvergenceCriteria를 교체 가능한 전략으로 둔다. - Template Method Pattern:
Analysis::run()은 공통 실행 흐름을 고정하고 세부 단계는 procedure별로 재정의한다. - Factory + Registry Pattern: Abaqus keyword와 내부 객체 생성을 분리한다. 예:
*Element, type=S4->MITC4ElementFactory. - Adapter Pattern: MKL, TBB, HDF5 API는 solver core에 직접 노출하지 않는다.
- Runtime Polymorphism: 요소, 재료, 하중, 경계조건은 base interface를 통해 다룬다. 대규모 모델 성능 최적화가 필요하면 assembly 내부에서 타입별 batch 처리 또는 kernel 분리를 추가한다.
- RAII: MKL handle, HDF5 file/dataset, temporary solver workspace의 수명과 오류 처리를 wrapper에 묶는다.
Sparse Matrix Policy
- assembly는 초기에는 COO triplet 수집 후 CSR finalize를 기준으로 한다.
SparseMatrix는 0-based CSR 데이터를 소유하는 별도 타입이며 denseMatrix를 상속하지 않는다. MKL PARDISO backend는 adapter 경계에서 필요한 descriptor와 indexing을 변환한다.- matrix symmetry, definiteness, singularity diagnostic을 구조화된 diagnostic으로 남긴다.
- deterministic assembly를 위해 TBB element loop는 thread-local contribution buffer 또는 two-pass sparse assembly를 사용한다.
Dense Math Policy
Vector는 contiguousdouble데이터와 크기를 소유하고 copy, dot, Euclidean norm, scale, axpy를 MKL CBLAS adapter로 수행한다.Matrix는 row-major contiguousdouble데이터와 dimensions를 소유하고 matrix-vector 및 matrix-matrix 연산에CBLAS_ROW_MAJOR를 사용한다.- 두 타입은 copy/move semantics와 bounds-checked access를 제공한다.
- MKL header와 MKL-specific type은 adapter implementation 밖으로 노출하지 않는다.
Parallel Policy
- 첫 번째 oneTBB 적용 지점은 element-local matrix/residual 계산이다.
- 전역 sparse write는 thread-local buffer 또는 deterministic reduction으로 제한한다.
- MKL 내부 thread와 TBB element loop가 oversubscription을 만들지 않도록 thread count와 task arena 정책을 명시한다.
HDF5 Result Schema
/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는
results.h5를 authoritative output으로 쓴다. - Abaqus reference results는
reference/<model-id>/아래 CSV 파일이다. - Verification은 documented IDs, components, units, coordinate system, step/frame identity, tolerance 기준으로 FESA HDF5 rows와 Abaqus reference CSV rows를 비교한다.
- FESA HDF5에서 추출한 deterministic CSV view는 optional debugging/review artifact이며 공식 solver output 또는 reference artifact가 아니다.
- Writer는 임시 HDF5 파일을 완성한 뒤 최종 경로로 교체하며 실패 시 불완전한
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는 node station 기준SF1/SM1/SM2/SM3을 제공한다. FESA endpoint를 동일한 section-cut 부호로 정규화하고 interior node의 두 endpoint가 tolerance 안에서 일치하는지 먼저 확인한 뒤SF1 -> N,SM1 -> My,SM2 -> Mz,SM3 -> T로 비교한다. - Reference tolerance는 같은 model, step/frame, quantity, component의 Abaqus rows에서
reference_scale = max(abs(reference_value))를 구하고 각 row에absolute_floor + 1e-6 * reference_scale을 적용한다. SI displacement/rotation floor는1e-9, force/moment floor는1e-3이다. - Beam stress는 HDF5 schema와 unit/analytical test로 검증하지만 Abaqus reference comparison은 N/A다.
CLI와 diagnostics
fesa.exe <model.inp> --output <results.h5>
--output을 생략하면 현재 작업 디렉터리의 results.h5를 사용한다. 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한 순서로 출력한다.