# 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` 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`를 사용한다. - 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에 변경이 없다.