356 lines
16 KiB
Markdown
356 lines
16 KiB
Markdown
# FESA C++ Object-Oriented Modular Refactoring Design
|
|
|
|
## 상태
|
|
|
|
- 설계 대화 승인: 2026-08-16
|
|
- 서면 spec 리뷰: 이 문서에 대한 사용자 검토 필요
|
|
- 구현 상태: not-started
|
|
|
|
## 목적
|
|
|
|
현재 B33 Euler beam, MITC4 shell과 linear static solver의 수치 및 외부 동작을
|
|
유지하면서 C++ production code를 객체 책임 중심으로 재구성한다. 이번 리팩터링은
|
|
Google C++ Style Guide 기반의 일관된 코드 스타일, 중복 제거, production Doxygen 문서화,
|
|
명시적인 추상 경계와 응집된 모듈을 제공해야 한다.
|
|
|
|
효율성은 runtime 성능 향상이 아니라 다음 유지보수 특성을 의미한다.
|
|
|
|
- 새 element, element property, material, analysis, load 또는 boundary condition을 추가할
|
|
때 기존 concrete 구현을 수정하는 범위를 줄인다.
|
|
- 하나의 의미를 여러 translation unit에서 다시 구현하지 않는다.
|
|
- parser semantic data, numerical kernel, assembly, recovery와 output 책임을 구분한다.
|
|
- 수치식과 I/O 계약을 사람이 직접 대조할 수 있는 단순한 dependency direction을 유지한다.
|
|
|
|
## 범위
|
|
|
|
### 포함
|
|
|
|
- production 및 test C++ 전체의 Google-style naming과 formatting 전환
|
|
- production header의 `.hpp`에서 `.h`로 전환과 header guard 적용
|
|
- production 함수와 class의 Doxygen 문서화
|
|
- `ElementDefinition`, `Element`, `ElementProperty`, `Material`, `Analysis`, `Load`,
|
|
`BoundaryCondition` 추상 경계
|
|
- B33, MITC4, isotropic linear elasticity, beam/shell property, linear static analysis,
|
|
concentrated nodal load와 prescribed displacement의 concrete 구현 연결
|
|
- `Vector3`, source-target resolution, DOF invariant validation과 dense-BLAS adapter의
|
|
중복 제거
|
|
- `domain_mapper.cpp`, `hdf5_results_writer.cpp`, `result_recovery.cpp`의 책임별 분할
|
|
- style, Doxygen, MSVC/CTest와 reference comparison 검증
|
|
- `docs/CODINGSTYLE.md` 유지관리 문서와 Implementation Agent 필수 참조 연결
|
|
|
|
### 제외
|
|
|
|
- MITC3, solid hexa/tetra 또는 다른 element 구현
|
|
- density, plasticity, anisotropic material 동작 구현
|
|
- dynamic, eigenvalue, response spectrum 또는 random vibration analysis 구현
|
|
- distributed load, body force 또는 MPC 구현
|
|
- 승인된 formulation, sign, units, coordinate, HDF5 schema, reference artifact 또는
|
|
tolerance 변경
|
|
- runtime 성능 최적화 또는 parallel reduction policy 변경
|
|
- general plugin registry, global static registration 또는 shared ownership framework
|
|
|
|
## 근거와 제약
|
|
|
|
현재 production code는 semantic record와 numerical kernel을 이미 구분하지만 Domain은
|
|
element, material, property, load와 boundary를 concrete vector로 각각 소유한다.
|
|
`SparseAssembler`, `DofManager`와 `ResultRecovery`는 B33/MITC4 concrete storage를 직접
|
|
알아야 한다. B33과 MITC4라는 두 실제 element가 있으므로 element abstraction은 현재
|
|
구현으로 검증할 수 있다.
|
|
|
|
반면 아직 구현되지 않은 plastic integration, dynamic state, MPC enforcement의 메서드를
|
|
base class에 미리 추가할 근거는 없다. 추상 class는 현재 concrete 구현이 실제로 공유하는
|
|
계약만 제공하고 future capability는 해당 기능의 requirements/formulation/ADR이 승인될 때
|
|
추가한다.
|
|
|
|
다음 기존 계약은 리팩터링보다 우선한다.
|
|
|
|
- Domain은 semantic definition을 단독 소유하고 parsing 이후 불변으로 취급한다.
|
|
- AnalysisModel은 Domain을 복사하지 않는 non-owning stable-index view다.
|
|
- DofManager는 DOF와 equation numbering 및 sparse pattern을 단독 소유한다.
|
|
- assembly worker는 global CSR storage를 직접 수정하지 않는다.
|
|
- stiffness partition과 factorization은 load assembly보다 먼저 수행한다.
|
|
- reaction과 free-equilibrium evidence는 full residual `K*d-F`에서 구한다.
|
|
- result recovery와 final HDF5는 candidate validation 후 commit한다.
|
|
- B33 및 MITC4 reference identity와 tolerance는 변경하지 않는다.
|
|
|
|
## 추상 계층과 소유권
|
|
|
|
```text
|
|
Domain
|
|
├─ ElementDefinition*
|
|
│ ├─ EulerBeam3DDefinition
|
|
│ └─ Mitc4ShellDefinition
|
|
├─ ElementProperty*
|
|
│ ├─ GeneralBeamSection
|
|
│ └─ ShellSection
|
|
├─ Material*
|
|
│ └─ IsotropicLinearElasticMaterial
|
|
└─ StepDefinition
|
|
├─ Load*
|
|
│ └─ ConcentratedNodalLoad
|
|
└─ BoundaryCondition*
|
|
└─ PrescribedDisplacementBoundaryCondition
|
|
|
|
Analysis
|
|
└─ LinearStaticAnalysis
|
|
|
|
Element
|
|
├─ EulerBeam3D
|
|
└─ Mitc4Shell
|
|
```
|
|
|
|
Domain은 각 base type을 `std::unique_ptr`로 단독 소유한다. Public access는 const이며
|
|
collection의 vector position은 기존 stable `EntityIndex` 의미를 유지한다. AnalysisModel과
|
|
후속 solver object는 raw ownership을 획득하지 않고 Domain 수명 안에서 index 또는 const
|
|
reference만 사용한다. Copy를 지원하기 위한 speculative `Clone()`과 `std::shared_ptr`는
|
|
추가하지 않는다.
|
|
|
|
`ElementDefinition`과 `Element`는 서로 다른 책임이다.
|
|
|
|
- `ElementDefinition`은 source identity, source element type, node connectivity와
|
|
property/material identity를 제공하는 semantic model이다.
|
|
- `Element`는 active DOF layout, stiffness contribution, transformation과 result recovery를
|
|
제공하는 numerical kernel이다.
|
|
- `ElementFactory`는 definition, property와 material compatibility를 검증한 뒤 concrete
|
|
kernel을 만든다.
|
|
- 잘못된 조합은 `dynamic_cast` 실패나 undefined behavior로 넘기지 않고 기존
|
|
`Status`/`Result<T>` diagnostic으로 fail-closed 처리한다.
|
|
|
|
Element result는 모든 element에 의미 없는 field를 추가한 비대한 base record가 아니다.
|
|
공통 step/frame/source identity를 가진 backend-neutral result bundle이 beam 및 shell row를
|
|
각자의 명확한 record로 보관한다. ResultRecovery와 ResultsWriter는 stable row identity를
|
|
보존하며 서로 다른 result location을 평균하거나 합치지 않는다.
|
|
|
|
## Material과 Element Property
|
|
|
|
`Material` base는 identity, source location과 수명 계약만 제공한다. 현재 concrete type은
|
|
물리 의미를 드러내도록 `IsotropicLinearElasticMaterial`로 명명한다. 현재 element factory가
|
|
필요로 하는 isotropic elastic capability만 노출한다.
|
|
|
|
다음 future concern은 이번 interface에 빈 메서드나 optional field로 미리 넣지 않는다.
|
|
|
|
- density와 inertia contribution
|
|
- anisotropic elastic constitutive data
|
|
- plastic history state와 return mapping
|
|
- temperature 또는 rate dependency
|
|
|
|
이 concern은 각 기능이 승인될 때 별도의 capability 또는 구성 객체로 추가한다. 같은
|
|
원칙으로 `ElementProperty`는 identity를 제공하고 `GeneralBeamSection`과 `ShellSection`은
|
|
각자 필요한 기하 property를 소유한다. Solid property를 예상해 비어 있는 thickness/area
|
|
accessor를 base에 추가하지 않는다.
|
|
|
|
## Analysis 계층
|
|
|
|
현재 `Analysis` base의 8개 protected hook은 linear-static lifecycle에 특화되어 있다.
|
|
이를 모든 future procedure에 강제하지 않는다.
|
|
|
|
```cpp
|
|
class Analysis {
|
|
public:
|
|
virtual ~Analysis() = default;
|
|
virtual Status Run(const AnalysisRequest& request) = 0;
|
|
};
|
|
```
|
|
|
|
현재 승인 순서는 `LinearStaticAnalysis::Run()`의 private 단계로 유지한다.
|
|
|
|
```text
|
|
initialize
|
|
-> build analysis model
|
|
-> build DOF map and sparse pattern
|
|
-> assemble and partition stiffness
|
|
-> factorize Kff
|
|
-> assemble loads and effective RHS
|
|
-> substitute and reconstruct
|
|
-> recover and write results
|
|
```
|
|
|
|
Dynamic, eigenvalue와 stochastic procedure는 추가될 때 별도 state, equation, solver와 output
|
|
lifecycle을 정의한다. 기존 linear-static hook 사이에 condition이나 unused future state를
|
|
추가하지 않는다. 이 책임 변경은 구현 전에 ADR-007을 대체하거나 개정하는 ADR로 기록한다.
|
|
|
|
## Load와 Boundary Condition
|
|
|
|
`Load` concrete object는 자신의 semantic target과 magnitude를 소유하고 ordered full-DOF
|
|
contribution을 생성한다. `LoadAssembler`는 active source order로 contribution을 모아 기존
|
|
fixed accumulation order로 global vector에 반영한다. Polymorphic load가 global vector를
|
|
직접 병렬 갱신하지 않는다.
|
|
|
|
현재 concrete load는 `ConcentratedNodalLoad`다. Future distributed load와 body force는
|
|
element-local contribution을 생성할 수 있지만 stable global reduction은 계속 assembler가
|
|
소유한다.
|
|
|
|
`BoundaryCondition`은 enforcement algorithm을 직접 수행하지 않고 constraint definition을
|
|
생성한다. 현재 concrete type은 nonzero 값을 포함하는
|
|
`PrescribedDisplacementBoundaryCondition`이다. `EssentialConstraintPolicy`가 기존 stable
|
|
elimination과 full/reduced reconstruction을 수행한다.
|
|
|
|
Future MPC는 별도 constraint equation과 enforcement policy를 요구한다. Prescribed
|
|
displacement, MPC, penalty와 Lagrange multiplier를 하나의 bool/enum branch가 누적된 class로
|
|
합치지 않는다.
|
|
|
|
## 공통 수학과 중복 제거
|
|
|
|
### Vector3
|
|
|
|
좌표, local axis, shell director와 cross-product는 고정 크기 `Vector3` 값 class를 사용한다.
|
|
동적 크기와 MKL-backed storage를 소유하는 기존 `Vector`와 역할을 섞지 않는다.
|
|
|
|
`Vector3`는 현재 반복되는 다음 연산을 한 번만 정의한다.
|
|
|
|
- component access
|
|
- addition, subtraction과 scalar multiplication
|
|
- `Dot()`
|
|
- `Cross()`
|
|
- `Norm()`
|
|
- `Normalized()`
|
|
- `IsFinite()`
|
|
|
|
Normalization failure policy는 호출 위치에서 기존 scale-aware diagnostic을 유지한다.
|
|
`Vector3`가 임의 tolerance, zero clamp 또는 solver diagnostic을 소유하지 않는다.
|
|
|
|
### 다른 공통 책임
|
|
|
|
- `SourceTargetResolver`: source label, instance와 set target을 stable identity로 해석한다.
|
|
- `DofManager::ValidateInvariants()`: full/free/constrained ordering과 equation mapping을 owner가
|
|
한 번 검증한다.
|
|
- private dense-BLAS adapter: Matrix와 Vector의 MKL integer conversion 및 copy operation을
|
|
공유한다. Vendor type은 public header에 노출하지 않는다.
|
|
- ASCII utility: case-insensitive name comparison과 positive source-label parsing을 공유한다.
|
|
|
|
중복 제거는 같은 의미와 failure policy가 반복될 때만 적용한다. 이름만 비슷하지만 units,
|
|
identity 또는 diagnostic owner가 다른 계산을 하나로 합치지 않는다. State가 없는 helper를
|
|
static-only class로 포장하지 않고 internal namespace/module을 사용한다.
|
|
|
|
## 모듈 구조
|
|
|
|
```text
|
|
include/fesa/
|
|
├─ analysis/
|
|
│ ├─ analysis.h
|
|
│ └─ linear_static_analysis.h
|
|
├─ elements/
|
|
│ ├─ element.h
|
|
│ ├─ element_definition.h
|
|
│ ├─ element_factory.h
|
|
│ ├─ euler_beam_3d.h
|
|
│ └─ mitc4_shell.h
|
|
├─ properties/
|
|
│ ├─ element_property.h
|
|
│ ├─ general_beam_section.h
|
|
│ └─ shell_section.h
|
|
├─ materials/
|
|
│ ├─ material.h
|
|
│ └─ isotropic_linear_elastic_material.h
|
|
├─ loads/
|
|
│ ├─ load.h
|
|
│ └─ concentrated_nodal_load.h
|
|
├─ constraints/
|
|
│ ├─ boundary_condition.h
|
|
│ ├─ prescribed_displacement.h
|
|
│ └─ essential_constraint_policy.h
|
|
├─ math/
|
|
│ ├─ vector.h
|
|
│ ├─ vector3.h
|
|
│ ├─ matrix.h
|
|
│ └─ sparse_matrix.h
|
|
└─ model/
|
|
├─ domain.h
|
|
├─ analysis_model.h
|
|
└─ source_target_resolver.h
|
|
```
|
|
|
|
`model_types.hpp`의 unrelated record는 각 owner module로 이동한다. Top-level orchestration
|
|
file은 다음과 같이 분리한다.
|
|
|
|
- Abaqus mapping: topology, material/property, step/load/BC와 final Domain assembly
|
|
- HDF5 output: RAII/primitives, model dataset, result dataset, self-check와 atomic finalization
|
|
- Result recovery: global equilibrium, beam recovery, shell recovery와 atomic state commit
|
|
|
|
Public header와 implementation dependency direction을 역전하지 않는다. MKL, TBB, HDF5와
|
|
Win32 type은 기존 adapter/private implementation 경계 안에 남는다.
|
|
|
|
## 코드 스타일과 문서화
|
|
|
|
`docs/CODINGSTYLE.md`를 FESA C++ style의 project-local source of truth로 사용한다. Google
|
|
C++ Style Guide가 baseline이고 FESA 계약이 우선한다.
|
|
|
|
주요 결정은 다음과 같다.
|
|
|
|
- C++17/MSVC 호환을 유지한다. Google guide의 현재 C++20 language target은 적용하지 않는다.
|
|
- 함수와 accessor를 포함한 production API는 PascalCase로 전면 전환한다.
|
|
- type은 PascalCase, 변수는 snake_case, constant/enumerator는 `kPascalCase`, class member는
|
|
trailing underscore를 사용한다.
|
|
- Header는 `.h`와 full-path Google header guard를 사용한다.
|
|
- Source는 기존 FESA/CMake 관례인 `.cpp`를 유지하는 project exception으로 둔다.
|
|
- Formatting은 `BasedOnStyle: Google`, 2-space indentation과 80-column limit를 사용한다.
|
|
- Production public/protected declaration에는 Doxygen contract를 기록한다.
|
|
- Production internal function은 definition에 목적과 비자명한 수치/순서 의미를 기록한다.
|
|
- Test code에는 Doxygen coverage를 요구하지 않는다.
|
|
|
|
Repository는 `.clang-format`, selected C++17-compatible `.clang-tidy`, `Doxyfile`과 optional
|
|
CMake docs target을 제공한다. Generated HTML은 source control에 넣지 않는다.
|
|
|
|
Implementation Agent의 profile은 구현 전에 `docs/CODINGSTYLE.md`를 mandatory global input으로
|
|
읽도록 변경한다. Agent workflow contract test는 해당 profile이 문서를 직접 참조하는지
|
|
검증한다.
|
|
|
|
## 오류 처리
|
|
|
|
- 모든 polymorphic base는 public virtual destructor를 갖는다.
|
|
- Factory는 null object를 성공 결과로 반환하지 않는다.
|
|
- Element/property/material incompatibility는 structured model diagnostic으로 거부한다.
|
|
- Public solver 경계는 기존 `Status`/`Result<T>`를 사용한다.
|
|
- Backend exception은 현재 failure category와 atomicity contract를 유지해 번역한다.
|
|
- Unknown future kind를 silent fallback이나 default concrete type으로 바꾸지 않는다.
|
|
- Failed candidate는 Domain, AnalysisState 또는 final HDF5를 부분 변경하지 않는다.
|
|
|
|
## 단계적 마이그레이션
|
|
|
|
1. 기존 unit/integration/reference 및 HDF5 contract baseline을 기록하고 architecture ADR을
|
|
갱신한다.
|
|
2. `.clang-format`, header rename/guard와 PascalCase를 module slice별 mechanical change로
|
|
적용한다.
|
|
3. `Vector3`, ASCII utility, SourceTargetResolver, DOF invariant validation과 private BLAS
|
|
adapter를 도입한다.
|
|
4. Domain semantic hierarchy와 current concrete material/property/load/boundary type을
|
|
연결한다.
|
|
5. Element runtime hierarchy와 factory를 DofManager, SparseAssembler와 ResultRecovery에
|
|
연결한다.
|
|
6. Ordered load contribution과 essential constraint policy를 연결한다.
|
|
7. Minimal Analysis base와 LinearStaticAnalysis-owned lifecycle로 전환한다.
|
|
8. Mapper, HDF5 writer와 recovery를 책임별로 분할하고 Doxygen/style coverage를 완료한다.
|
|
|
|
Mechanical formatting, API rename와 semantic restructuring을 같은 review unit에 섞지 않는다.
|
|
각 slice는 buildable하고 독립 검증 가능해야 한다.
|
|
|
|
## TDD와 검증
|
|
|
|
각 production change는 관련 C++ test와 같은 Step에서 `RED -> GREEN -> VERIFY`를 수행한다.
|
|
|
|
- abstract base와 concrete polymorphic use를 검증하는 compile-time/unit test
|
|
- factory success와 incompatible property/material rejection test
|
|
- base interface를 통한 B33/MITC4 stiffness 및 recovery test
|
|
- stable element, load와 boundary source-order test
|
|
- Domain ownership, AnalysisModel lifetime와 stable identity test
|
|
- Vector3 arithmetic, finite and normalization-boundary test
|
|
- 기존 parser/I/O, HDF5 schema와 atomicity test
|
|
- B33 및 MITC4 integration/reference comparison
|
|
- repeated execution의 sparse structure, result row와 diagnostic order test
|
|
- Doxygen warning, formatting과 selected lint check
|
|
- full MSVC x64 Debug `/W4 /WX` build와 CTest
|
|
|
|
수치 산술 순서를 의도적으로 변경하지 않은 slice는 가능한 한 exact equality를 요구한다.
|
|
Feature-approved reference tolerance는 최종 external comparison에만 그대로 적용한다.
|
|
|
|
## 완료 기준
|
|
|
|
- 승인된 abstraction과 current concrete implementation이 base interface를 통해 연결된다.
|
|
- DofManager, assembler와 recovery에 B33/MITC4 type branch 또는 duplicate geometry helper가
|
|
남지 않는다.
|
|
- Production 및 test C++가 `docs/CODINGSTYLE.md`의 naming/formatting 규칙을 만족한다.
|
|
- Production API와 non-obvious internal function에 요구된 Doxygen가 존재한다.
|
|
- Implementation Agent profile이 `docs/CODINGSTYLE.md`를 mandatory input으로 참조한다.
|
|
- 전체 MSVC x64 Debug build/CTest와 B33/MITC4 reference comparison이 통과한다.
|
|
- HDF5 schema, stable identity, diagnostic, tolerance와 reference artifact에 변경이 없다.
|