diff --git a/docs/ADR.md b/docs/ADR.md index 778d4c8..d07b85c 100644 --- a/docs/ADR.md +++ b/docs/ADR.md @@ -35,7 +35,12 @@ solution과 test command를 명시한 직접 MSBuild 프로젝트도 검증할 **트레이드오프**: 사용자는 기존 Abaqus input file을 그대로 사용할 수 없을 수 있다. 대신 지원 범위와 실패 원인이 명확해진다. ### ADR-004: Domain, AnalysisModel, DofManager, AnalysisState를 분리한다 -**결정**: `Domain`은 입력 모델 정의를 소유하고, `AnalysisModel`은 현재 step의 실행 view를 제공하며, `DofManager`는 equation numbering과 constrained/free mapping을 전담하고, `AnalysisState`는 해석 중 변하는 물리량을 소유한다. +**결정**: `Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과 +`StepDefinition` 입력 모델 정의를 `std::unique_ptr`로 단독 소유하고 const access와 +stable collection index를 제공한다. `AnalysisModel`은 Domain 수명 안에서 stable index와 +const reference만 사용하는 non-owning current-step view다. `DofManager`는 equation +numbering과 constrained/free mapping을 전담하고, `AnalysisState`는 해석 중 변하는 +물리량을 소유한다. **이유**: 모델 정의, step activation, equation system, transient/nonlinear state가 섞이면 parser, assembler, solver, result writer가 강하게 결합된다. 분리된 상태 모델은 선형 정적 해석에서 시작해 비선형, 동적, thermal coupling으로 확장하기 쉽다. @@ -57,12 +62,25 @@ solution과 test command를 명시한 직접 MSBuild 프로젝트도 검증할 **트레이드오프**: 단일 기능만 구현할 때는 adapter가 다소 장황해 보일 수 있다. Row-major dense storage와 CSR sparse storage를 따로 유지해야 하지만 backend 의존성과 dense/sparse 의미가 core 모델에 섞이지 않는다. -### ADR-007: Analysis 실행 흐름은 Template Method로 고정한다 -**결정**: `Analysis::run()`은 공통 lifecycle을 고정한다. 선형 정적 V0의 순서는 `parse input -> initialize Domain -> build AnalysisModel -> build DOF map/sparse pattern -> assemble stiffness -> partition constraints -> factorize Kff -> assemble load -> form effective RHS -> substitute -> reconstruct displacement -> recover results -> write HDF5`다. 강성행렬 factorization은 하중벡터 조립보다 먼저 수행하고, factorization과 substitution을 하나의 불투명한 solve 호출로 합치지 않는다. +### ADR-007: Analysis base는 최소 실행 계약만 제공한다 +**결정**: `Analysis` base는 virtual `Analysis::Run(const AnalysisRequest&)`만 제공하고 +linear-static-specific protected hook을 정의하지 않는다. 승인된 선형 정적 순서인 +`parse input -> initialize Domain -> build AnalysisModel -> build DOF map/sparse pattern -> +assemble stiffness -> partition constraints -> factorize Kff -> assemble load -> form effective +RHS -> substitute -> reconstruct displacement -> recover results -> write HDF5`는 +`LinearStaticAnalysis::Run()`의 private lifecycle로 유지한다. 강성행렬 factorization은 +하중벡터 조립보다 먼저 수행하고 factorization과 substitution을 하나의 불투명한 solve +호출로 합치지 않는다. -**이유**: 해석 procedure가 늘어나도 공통 실행 순서가 유지되어야 검증, logging, result writing, failure classification이 일관된다. Factorization과 substitution을 분리하면 동일 강성행렬에 여러 RHS를 적용할 수 있고 각 실패 단계를 구조화된 diagnostic으로 분류할 수 있다. +**이유**: 현재 여덟 단계는 linear static equation, state와 failure taxonomy에 특화되어 +있다. 최소 base contract는 이 순서의 검증 가능성을 보존하면서 승인되지 않은 dynamic, +eigenvalue 또는 nonlinear procedure에 같은 protected hook과 사용하지 않는 state를 +강제하지 않는다. Factorization과 substitution 분리는 동일 강성행렬에 여러 RHS를 적용할 +수 있고 각 실패 단계를 구조화된 diagnostic으로 분류하게 한다. -**트레이드오프**: 특수 해석 절차가 공통 흐름에 맞지 않는 경우 hook point가 필요하다. 초기에는 선형 정적 해석을 기준으로 최소 hook만 둔다. +**트레이드오프**: Procedure 사이의 lifecycle code는 base Template Method로 자동 재사용되지 +않는다. 두 번째 procedure가 승인되면 실제로 같은 단계만 focused collaborator로 추출하되, +linear-static hook 사이에 조건문으로 새 physics를 삽입하지 않는다. ### ADR-008: Sparse assembly는 deterministic COO-to-CSR 경로로 시작한다 **결정**: 초기 assembly는 element-local contribution을 COO triplet으로 수집한 뒤 CSR로 finalize한다. MKL PARDISO backend는 CSR input contract를 받는다. @@ -230,3 +248,61 @@ displacement 검증 목적에 맞지 않는다. 고정 절대오차는 현재 **트레이드오프**: Model scale이 크게 달라지면 고정 절대오차의 상대적 엄격도가 달라질 수 있다. 따라서 이 값은 현재 승인된 MITC4 S4 case의 기능 완료 기준이며 개발 완료 후 별도 reference-verification evidence와 함께 재점검한다. + +### ADR-021: Semantic definition과 runtime solver contract를 분리한다 + +**결정**: Domain-owned semantic definition과 analysis-time numerical object를 다음 +dependency 방향으로 분리한다. + +```text +Domain owns ElementDefinition / ElementProperty / Material / StepDefinition +AnalysisModel is a non-owning stable-index view into Domain +ElementFactory creates runtime Element candidates from compatible definitions +DofManager -> ElementDofLayout +SparseAssembler -> ElementStiffnessContribution +ResultRecovery -> ElementResultBundle +LoadAssembler -> ordered LoadContribution +EssentialConstraintPolicy -> ConstraintDefinition +Analysis <- LinearStaticAnalysis +``` + +`Domain`의 polymorphic semantic collection은 `std::unique_ptr` 단독 ownership과 stable +vector position을 사용한다. `ElementDefinition`은 source identity, connectivity와 +property/material identity를 제공하고 runtime `Element`는 DOF layout, stiffness와 result +recovery를 제공한다. `ElementFactory`가 definition/property/material compatibility를 +중앙에서 검사하며 unknown 또는 incompatible 조합은 fail-closed diagnostic으로 거부한다. +Consumer는 B33/MITC4 concrete type branch를 분산시키지 않고 runtime contract를 사용한다. +Linear-static candidate가 runtime `Element`를 `std::unique_ptr`로 소유하고 consumer는 그 +수명에 한정된 non-owning view만 사용한다. + +`Material` base에는 identity, source location과 lifetime 이외의 future capability를 +추가하지 않는다. 현재 isotropic linear elasticity가 실제로 요구하는 data는 concrete +material에 둔다. Density, anisotropy, plastic state, temperature와 rate dependency는 +optional field 또는 no-op virtual method로 미리 할당하지 않는다. `ElementProperty`도 +현재 beam/shell 의미를 각 concrete type에 둔다. + +`Load`는 ordered `LoadContribution`을 생성하고 global full-DOF accumulation은 +`LoadAssembler`가 단독 소유한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고 +`EssentialConstraintPolicy`가 prescribed-displacement elimination과 reconstruction을 +소유한다. Distributed/body load와 MPC/penalty/Lagrange-multiplier enforcement는 이번 +결정으로 구현된 기능이 아니다. + +Abaqus Domain mapper, result recovery와 HDF5 writer는 기존 public facade를 유지하면서 +각각 topology/material-property/step-final-assembly, equilibrium/beam/shell/atomic-state, +RAII/model-result-dataset/self-check/atomic-finalization 책임으로 private implementation을 +나눈다. + +**이유**: Semantic identity와 runtime kernel을 같은 concrete record에 두면 DofManager, +SparseAssembler, ResultRecovery, parser와 output이 B33/MITC4 storage를 함께 알아야 한다. +Definition/factory/runtime contract와 contribution/policy 경계를 분리하면 stable source +identity와 deterministic reduction owner를 유지하면서 실제 두 element 구현을 공통 +consumer로 연결할 수 있다. Focused facade 분할은 외부 계약을 바꾸지 않고 큰 translation +unit의 서로 다른 failure-atomicity 책임을 검토 가능하게 한다. + +**트레이드오프**: Base object, factory와 contribution record가 늘고 checked compatibility에 +한 단계의 indirection이 생긴다. 대신 `std::shared_ptr`, speculative `Clone()`, global +registry와 future-only material/analysis capability는 도입하지 않는다. B33/MITC4의 승인된 +formulation, 연산·reduction 순서, sign, units, coordinates와 result identity가 이 +리팩터링보다 우선하며 HDF5 schema, reference artifact와 ADR-014/ADR-020 tolerance는 +변경하지 않는다. MITC3, solid, dynamic과 plastic behavior는 별도 feature gate 전까지 +구현된 것으로 간주하지 않는다. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index ab11b20..8cae88a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -32,7 +32,7 @@ src/ assembly/ # deterministic stiffness/load assembly, ParallelFor adapter constraints/ # essential-constraint elimination and reconstruction core/ # source identity, status, diagnostics - elements/ # V0 EulerBeam3D kernel and recovery + elements/ # current B33/MITC4 kernels and recovery fem/ # DOF/equation numbering and sparse pattern io/ abaqus/ # .inp syntax reader and semantic Domain mapper @@ -62,9 +62,11 @@ scripts/ phases/ # Optional generated phase plans ``` -`materials/`, nonlinear/dynamic analysis, MPC/penalty policies, general element factories, -history output과 production validation module은 장기 확장 경계이지 현재 구현된 module이 -아니다. 새 디렉토리와 추상 계층은 승인된 기능이 실제로 필요로 할 때 추가한다. +`materials/`, `properties/`, `loads/`와 checked `ElementFactory`는 승인된 C++ modular +refactoring의 target boundary이며 후속 implementation Step에서 추가한다. 이 +documentation-only Step 시점에는 현재 구현 디렉토리로 표시하지 않는다. Density, +plasticity, anisotropy, nonlinear/dynamic analysis, MPC/penalty, history output과 production +validation module은 계속 장기 확장 경계이며 별도 승인 기능이 필요하다. ## Harness Execution Layer @@ -109,16 +111,86 @@ CMake source에 기록하지 말고 config package와 imported target metadata ## 모듈 경계 - `core`는 외부 라이브러리에 의존하지 않는다. - `io/abaqus`는 syntax와 semantic mapping만 담당하고 해석 알고리즘을 알지 않는다. -- `model`은 Abaqus keyword 문자열이 아니라 solver semantic model을 가진다. +- `model`은 Abaqus keyword 문자열이 아니라 solver semantic model을 가지며 `Domain`과 + non-owning `AnalysisModel`의 수명 경계를 소유한다. +- `materials`와 `properties`는 Domain이 소유하는 semantic identity와 현재 승인된 + isotropic elasticity 및 beam/shell property data만 제공한다. +- `elements`는 Domain-owned `ElementDefinition`, runtime numerical `Element`, checked + `ElementFactory`와 element-local stiffness/recovery contract를 제공한다. - `fem`의 `DofManager`는 DOF, equation ordering, scatter와 sparse pattern을 소유한다. -- `elements`는 local/global stiffness, transformation, optional load kernel과 recovery를 제공한다. V0 material/section은 concrete Domain record다. -- `assembly`는 element-local contribution과 full nodal load를 stable full-DOF space에 조립한다. -- `constraints`는 V0 essential BC elimination과 full/reduced vector 변환을 담당한다. MPC와 penalty는 현재 범위가 아니다. +- `assembly`는 runtime element contribution과 ordered load contribution을 stable full-DOF + space에 조립한다. Contribution producer는 global storage를 직접 갱신하지 않는다. +- `loads`는 semantic target과 magnitude를 소유하고 ordered `LoadContribution`을 생성한다. +- `constraints`는 `ConstraintDefinition` 생성과 V0 essential BC elimination 및 full/reduced + vector 변환을 분리한다. MPC와 penalty는 현재 범위가 아니다. - `solvers`는 `LinearSolver` 뒤에 MKL PARDISO 세부 구현을 감춘다. TBB는 `assembly/ParallelFor`, HDF5는 `results/ResultsWriter` 경계 뒤에 각각 격리된다. - `analysis`는 step/history data를 받아 procedure를 실행하고 solver backend와 result writer를 조율한다. -- `results`는 full residual과 beam rows를 복구하고 backend-neutral writer contract를 제공한다. HDF5 schema 구현은 `io/hdf5`가 담당한다. +- `results`는 full residual과 B33/MITC4 rows를 복구하고 backend-neutral writer contract를 + 제공한다. HDF5 schema 구현은 `io/hdf5`가 담당한다. - test helper는 production parser/solver 내부 상태를 우회하지 않는다. +## 승인된 리팩터링 dependency와 ownership + +다음 graph는 C++ object-oriented modular refactoring의 구현 방향을 고정한다. `owns`는 +단독 수명 소유권을, 나머지 화살표는 왼쪽 consumer가 오른쪽 contract를 사용한다는 +뜻이다. 이 graph는 기존 B33/MITC4 물리 기능을 늘리지 않는다. + +```text +Domain owns ElementDefinition / ElementProperty / Material / StepDefinition +AnalysisModel is a non-owning stable-index view into Domain +ElementFactory creates runtime Element candidates from compatible definitions +DofManager -> ElementDofLayout +SparseAssembler -> ElementStiffnessContribution +ResultRecovery -> ElementResultBundle +LoadAssembler -> ordered LoadContribution +EssentialConstraintPolicy -> ConstraintDefinition +Analysis <- LinearStaticAnalysis +``` + +승인된 B33/MITC4 formulation, operation/reduction order, sign, units, coordinates와 row +identity는 이 ownership 리팩터링보다 우선한다. HDF5 schema, reference artifact와 +ADR-014/ADR-020 tolerance도 변경하지 않는다. + +`Domain`은 `ElementDefinition`, `ElementProperty`, `Material`과 `StepDefinition` base +object를 `std::unique_ptr`로 단독 소유하고 const access를 제공한다. Collection position은 +기존 stable `EntityIndex` 의미를 유지한다. `AnalysisModel`과 solver consumer는 ownership을 +가져오지 않고 Domain 수명 안에서 stable index 또는 const reference만 사용한다. +`std::shared_ptr`, speculative `Clone()`과 global registry는 이 계약에 포함되지 않는다. + +`ElementDefinition`은 source identity, source element type, connectivity와 +property/material identity를 보존하는 semantic object다. Runtime `Element`는 active +`ElementDofLayout`, `ElementStiffnessContribution`과 `ElementResultBundle`을 제공하는 +numerical kernel이다. `ElementFactory`만 compatible definition/property/material 조합을 +검사해 runtime candidate를 만들며 unknown 또는 incompatible 조합을 기존 +`Status`/`Result` diagnostic으로 fail-closed 처리한다. `DofManager`, +`SparseAssembler`와 `ResultRecovery`는 B33/MITC4 concrete storage가 아니라 위 runtime +contract를 소비한다. Linear-static candidate는 runtime `Element`를 +`std::vector>`로 소유하고, consumer에는 그 owner 수명 안에서만 +유효한 non-owning `ElementView`를 제공한다. + +`Material` base는 identity, source location과 수명 의미만 공유한다. 현재 concrete +isotropic linear elasticity에 필요한 capability만 사용하며 density, anisotropy, plastic +state, temperature 또는 rate dependency를 optional field나 no-op method로 미리 추가하지 +않는다. `ElementProperty`도 beam/shell이 실제 사용하는 data만 각 concrete type에 둔다. + +`Load`는 semantic target과 magnitude를 소유하고 source order가 보존된 +`LoadContribution`을 생성한다. Global vector의 deterministic accumulation은 +`LoadAssembler`만 수행한다. `BoundaryCondition`은 `ConstraintDefinition`을 생성하고 +`EssentialConstraintPolicy`가 prescribed displacement의 stable elimination과 +reconstruction을 수행한다. Future distributed/body load와 MPC enforcement는 구현된 +기능이 아니며 별도 승인 계약 없이 이 경계에 branch나 optional state를 추가하지 않는다. + +책임이 큰 facade는 외부 계약을 유지한 채 private implementation만 다음 owner로 나눈다. + +- Abaqus Domain mapping: topology, material/property, step/load/boundary mapping과 final + Domain assembly +- Result recovery: global equilibrium, beam recovery, shell recovery와 atomic state commit +- HDF5 writing: RAII/primitives, model datasets, result datasets, self-check와 atomic + finalization + +이 분할은 parser diagnostic, `ResultsWriter` boundary, HDF5 schema 또는 final-file +atomicity를 변경하지 않는다. + ## V0 입력 경계 V0 parser는 keyword와 parameter를 case-insensitive하게 해석하되 source label의 원문을 @@ -174,14 +246,23 @@ CLI pipeline에서는 이 kernel을 호출하지 않는다. Stiffness와 recover ```text Domain -├── owns nodes, B33 elements, materials, beam sections, sets -├── owns boundary conditions, nodal loads, one static step +├── owns nodes, sets and source identity +├── owns unique_ptr +├── owns StepDefinition with Load / BoundaryCondition definitions └── owns source path/identity and mapping warnings AnalysisModel -├── non-owning view into Domain -├── stable active element/BC/load indices -└── reachable material/section indices +├── non-owning stable-index view into Domain +├── stable active element/BC/load definition indices +└── reachable material/property indices + +ElementFactory +└── creates checked runtime Element candidates + +Element +├── exposes ElementDofLayout +├── produces ElementStiffnessContribution +└── recovers ElementResultBundle DofManager ├── owns node x [UX,UY,UZ,URX,URY,URZ] full-DOF numbering @@ -205,12 +286,15 @@ Matrix SparseMatrix ``` -Nonlinear/static, dynamic, frequency, heat-transfer procedure와 general element/material/load -base hierarchy는 이 구조 위의 가능한 확장 방향일 뿐 현재 public API가 아니다. 사용 사례가 -승인되기 전에 V0 concrete record를 speculative hierarchy로 감싸지 않는다. +위 abstract boundary는 현재 B33/MITC4, isotropic linear elasticity, beam/shell property, +concentrated nodal load, prescribed displacement와 linear static procedure를 연결하는 데 +필요한 최소 계약이다. MITC3, solid, dynamic, frequency, heat-transfer와 plastic behavior는 +구현된 기능이 아니며 승인된 사용 사례 전에 future-only method나 state를 base에 추가하지 +않는다. ## 상태 관리 -- `Domain`은 입력 파일에서 만들어진 전체 모델 정의를 소유한다. 파싱 이후에는 가능한 한 불변으로 취급한다. +- `Domain`은 입력 파일에서 만들어진 전체 모델 정의를 `std::unique_ptr`로 단독 소유한다. + 파싱 이후에는 가능한 한 불변으로 취급하고 stable collection index를 바꾸지 않는다. - `LinearStaticAnalysis`가 `Domain`을 소유하고, 그 뒤에 `AnalysisModel`, `DofManager`, `AnalysisState`, stiffness/RHS를 순서대로 만든다. 재사용 시에는 역순으로 해제하여 이전 Domain을 가리키는 view를 남기지 않는다. - `AnalysisModel`은 현재 step에서 활성화되는 해석 객체들의 실행 view이다. `Domain`을 복사하지 않으므로 Domain이 반드시 더 오래 살아야 한다. - `DofManager`는 자유도와 방정식 번호를 전담한다. `Node` 또는 `Element` 내부에 equation id를 분산 저장하지 않는다. @@ -223,15 +307,16 @@ 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 생성 +-> ElementFactory가 compatible definition에서 runtime Element candidate 생성 +-> DofManager가 ElementDofLayout으로 DOF/scatter map/sparse pattern 생성 +-> ElementStiffnessContribution의 deterministic COO-to-CSR 조립 +-> ConstraintDefinition의 stable essential-constraint partition 생성 -> LinearSolver::factorize(Kff) --> full nodal load vector 조립 +-> ordered LoadContribution의 full nodal load vector 조립 -> effective RHS = Ff - Kfc * dc -> LinearSolver::solve(rhs, df) substitution -> full displacement 복구 --> full residual/reaction = K*d - F 및 element result 복구 +-> full residual/reaction = K*d - F 및 ElementResultBundle 복구 -> ResultsWriter로 results.h5 atomic finalization ``` @@ -240,28 +325,37 @@ Abaqus input file reaction이고 free component는 equilibrium residual evidence로 full-index vector에 남긴다. ## 해석 실행 흐름 -`Analysis::run()`은 Template Method로 다음 여덟 hook의 순서와 fail-fast 경계를 고정한다. -| 순서 | Hook | 주요 작업과 생성되는 소유 객체 | 순서/실패 불변식 | +`Analysis` base는 procedure-specific protected hook을 정의하지 않고 최소 실행 계약인 +`Analysis::Run(const AnalysisRequest&)`만 제공한다. 다음 여덟 단계의 순서와 fail-fast +경계는 `LinearStaticAnalysis::Run()`의 private lifecycle이며 다른 procedure에 강제되지 +않는다. + +| 순서 | Private stage | 주요 작업과 생성되는 소유 객체 | 순서/실패 불변식 | | --- | --- | --- | --- | -| 1 | `initialize(request)` | `.inp` syntax read, semantic map, owned immutable `Domain`, sorted warnings | 이전 run의 dependent object를 역순으로 제거하고 parse/map 실패를 input category로 반환한다. | -| 2 | `buildAnalysisModel()` | non-owning `AnalysisModel` view | Domain을 복사하지 않으며 Domain lifetime 안에서만 사용한다. | -| 3 | `buildDofMapAndSparsePattern()` | `DofManager`, zero-initialized `AnalysisState` | Stable full/free/constrained numbering과 structural pattern을 한 소유자에게 둔다. | -| 4 | `assembleAndPartitionStiffness()` | full CSR K와 `Kff/Kfc/Kcf/Kcc` | Element-local buffer를 deterministic하게 reduce하고 structural zero와 stable order를 보존한다. | -| 5 | `factorize()` | retained `Kff` factorization | 모든 load assembly보다 먼저 호출한다. Valid fully constrained model의 `0 x 0 Kff`는 trivial success다. | -| 6 | `assembleLoadsAndEffectiveRhs()` | full F와 `Ff-Kfc*dc` | Semantic load source order와 finite sum을 보존하며 solver를 호출하지 않는다. | -| 7 | `substituteAndReconstruct()` | free solution과 full displacement | Factorization을 재수행하지 않고 substitution한 뒤 prescribed value를 stable order로 복구한다. | -| 8 | `recoverAndWriteResults()` | full residual/reaction, beam rows, final HDF5 | Recovery candidate를 원자적으로 commit하고 writer 성공 뒤에만 최종 output을 교체한다. | +| 1 | `Initialize(request)` | `.inp` syntax read, semantic map, owned immutable `Domain`, sorted warnings | 이전 run의 dependent object를 역순으로 제거하고 parse/map 실패를 input category로 반환한다. | +| 2 | `BuildAnalysisModel()` | non-owning `AnalysisModel` view | Domain을 복사하지 않으며 Domain lifetime 안에서만 사용한다. | +| 3 | `BuildDofMapAndSparsePattern()` | `DofManager`, zero-initialized `AnalysisState` | Stable full/free/constrained numbering과 structural pattern을 한 소유자에게 둔다. | +| 4 | `AssembleAndPartitionStiffness()` | full CSR K와 `Kff/Kfc/Kcf/Kcc` | Element-local buffer를 deterministic하게 reduce하고 structural zero와 stable order를 보존한다. | +| 5 | `Factorize()` | retained `Kff` factorization | 모든 load assembly보다 먼저 호출한다. Valid fully constrained model의 `0 x 0 Kff`는 trivial success다. | +| 6 | `AssembleLoadsAndEffectiveRhs()` | full F와 `Ff-Kfc*dc` | Semantic load source order와 finite sum을 보존하며 solver를 호출하지 않는다. | +| 7 | `SubstituteAndReconstruct()` | free solution과 full displacement | Factorization을 재수행하지 않고 substitution한 뒤 prescribed value를 stable order로 복구한다. | +| 8 | `RecoverAndWriteResults()` | full residual/reaction, B33/MITC4 rows, final HDF5 | Recovery candidate를 원자적으로 commit하고 writer 성공 뒤에만 최종 output을 교체한다. | 비선형 정적 및 동적 해석은 V0 범위가 아니며 별도 ADR과 formulation을 승인한 뒤 이 -lifecycle과 state/equation 계약을 확장한다. 기존 hook 사이에 조용히 반복·증분·시간 적분 -동작을 삽입하지 않는다. +lifecycle과 state/equation 계약을 별도 procedure에 정의한다. LinearStaticAnalysis의 +private stage 사이에 조용히 반복·증분·시간 적분 동작을 삽입하지 않는다. ## 설계 패턴 -- Strategy/Adapter Pattern: 현재 교체 가능한 public 경계는 `LinearSolver`, `ParallelFor`, `ResultsWriter`다. Vendor API는 concrete adapter implementation 안에만 둔다. -- Template Method Pattern: `Analysis::run()`은 공통 실행 흐름을 고정하고 세부 단계는 procedure별로 재정의한다. +- Strategy/Adapter Pattern: `Analysis::Run(const AnalysisRequest&)`, `LinearSolver`, + `ParallelFor`, `ResultsWriter`가 현재 승인된 public 실행/backend 경계다. Vendor API는 + concrete adapter implementation 안에만 둔다. +- Procedure-owned lifecycle: `Analysis`는 protected Template Method hook을 공유하지 않고 + `LinearStaticAnalysis`가 승인된 여덟 단계 lifecycle을 private하게 소유한다. - Syntax/Semantic separation: `AbaqusInputReader`는 syntax record를 만들고 `AbaqusDomainMapper`가 승인된 keyword 의미를 concrete Domain record로 변환한다. -- Runtime Polymorphism: V0에서는 backend 경계에만 사용한다. 요소/재료/하중 base hierarchy와 factory/registry는 두 번째 실제 구현이 필요해질 때 trade-off를 다시 결정한다. +- Runtime Polymorphism: backend와 승인된 analysis/element/material/property/load/boundary + 경계에만 사용한다. Factory compatibility는 중앙에서 fail-closed로 검사하며 global + registry 또는 future-only capability를 추가하지 않는다. - RAII: MKL handle, HDF5 file/dataset, temporary solver workspace의 수명과 오류 처리를 wrapper에 묶는다. ## Sparse Matrix Policy