Files
FESADev/docs/cpp-object-oriented-modular-refactoring/README.md
T
2026-10-18 14:32:55 +09:00

112 lines
11 KiB
Markdown

# C++ 모듈화와 공개 API 정리
기존 B33/MITC4 솔버의 모델·local 계산·assembly·procedure·backend·I/O 책임을 분리하고 공개 header의 vendor 의존을 격리한 리팩터링이다. 새 물리·입력·해법·결과 schema 또는 tolerance를 도입하는 기능이 아니다. 현재 재사용할 구조·CLI·I/O·수치 비교 계약은 [solver-core](../solver-core/README.md)에 모았다.
## 설계와 실제 데이터 흐름
[Domain](../../include/fesa/model/domain.h)은 의미 모델을 소유하고 [AnalysisModel](../../include/fesa/analysis/analysis_model.h)은 더 짧게 사는 non-owning view다. [DofManager](../../include/fesa/fem/dof_manager.h)는 equation·partition·pattern을 소유한다. [Element](../../include/fesa/elements/element.h)의 typed local contribution은 [SparseAssembler](../../src/fesa/assembly/sparse_assembler.cpp)에서 결정적 순서로 조립된다. [LinearStaticProcedureExecutor](../../include/fesa/analysis/linear_static_procedure.h)는 caller-owned 실행/선형해법 adapter를 참조하고 실행에 필요한 state만 만든다. [ResultRecovery](../../include/fesa/results/result_recovery.h)는 위치·단위·부호를 가진 결과를 복구하고 [HDF5 writer](../../src/fesa/io/hdf5/hdf5_results_writer.cpp)는 직렬화한다.
[FesaApplication](../../src/fesa/app/fesa_application.cpp)이 객체·lexical output path·lease·실행 수명을 조합한다. 공개 API는 `include/fesa/`, 구현은 대응 `src/fesa/`에 두며 vendor handle과 오류 번호는 private 수치/I/O adapter 뒤에 둔다. 공개 API 이름을 예전 `.hpp` 시절 표기로 복원하거나 parser에서 concrete numerical storage를 직접 소유하지 않는다. Polymorphic base의 public virtual destructor, 단독 소유의 unique_ptr·RAII, self-contained include guard와 source identity를 유지한다.
이 경계는 현재 eigen·dynamic·thermal·solid가 확장한 구조의 기반이다. 당시 static 리팩터링 성공을 나중에 추가된 모든 절차의 재검증으로 해석하지 않는다. 특히 trial/commit과 파일 final replacement는 다른 실패 경계다. 내부 accepted frame이 있어도 전체 해석이 실패하면 미완성 정상 final을 공개하지 않는다.
## 보존한 입력·출력과 비교 의미
CLI는 입력 `.inp` 하나, lexical sibling HDF5·log, warning/오류 진단과 exit 의미를 유지했다. B33는 node·element endpoint·section point를, MITC4는 instance/node·element/point identity를 보존한다. 같은 node에 모인 endpoint action을 평균하거나 physical shell strain에 numerical drilling 값을 섞지 않는다. 정적 schema0·canonical frame0의 mandatory dataset·dtype·shape는 리팩터링 편의를 위해 바꾸지 않는다.
현재 수치 비교는 common family의 row5%·RMS1% 및 identity/finite 사전검사를 따른다. 과거 리팩터링 보고서에는 B33 `absolute_floor+1e-6*reference_scale`와 S4 fixed absolute1e-5로 수행한 당시 비교가 있다. B33176/176행, S4294/294행 통과 기록은 그 옛 기준·revision의 evidence이며 현재 common policy로 다시 판정한 결과가 아니다. Beam stress는 당시 Abaqus 외부 비교 N/A였고 analytical/unit·HDF5 schema evidence와 구분한다.
## 교훈과 검증 한계
- Naming·format·header guard·Doxygen와 dependency 경계를 정리해도 displacement만으로 stress/reaction·수명·실패 보존이 증명되지는 않는다. Header 변경은 대응 src consumer까지 함께 확인한다.
- Dense 크기 곱 overflow는 할당 전에 확인한다. Public API의 Status/Result와 backend exception 변환은 원래 실패 의미를 보존해야 한다.
- 상속된 환경 변수가 검사 실패의 원인이었던 사례가 있다. 환경 오류와 solver 결함을 구분한다. Formatter의 변경 유무와 native exit, link 성공과 runtime DLL 준비를 따로 판단한다.
- 과거 실행 절차를 현재 실행 계획으로 복원하지 않는다. CTest와 별도 Python suite의 성공을 합치지 않는다.
이 문서 작업에서는 build/test를 실행하지 않았다. 당시 모듈화와 reference의 bounded 검증은 남기되 최신 전체 회귀·외부 배포 준비 완료를 선언하지 않는다. 현재 물리적 미해결 사항은 각 기능 README가 소유한다.
## Refactor 코드 채택 후 구조
2026-10-18 통합은 FESADev `7438c827` 이력에 Refactor `11f09eeb`의 제품 `.h/.cpp`
274개와 직접 MSVC 빌드를 선별 도입했다. 옛 구현을 섞는 호환 계층이나 새 정식화는 추가하지 않는다.
[파일 manifest](merge-manifest.json)는 원본 Git blob과 working bytes, 보존·도입 방침을 구분하고,
[테스트 이관표](test-migration.tsv)는 양쪽 기존 identity·assertion·oracle와 최종 위치를 연결한다.
Manifest의 초기 inventory와 중간 snapshot은 각 revision의 이력이며 현재 파일 목록이 아니다.
최종 범위는 `t5_static_scope_verification`·`t6_test_cleanup`·`t7_final_handoff`와 아래 반영 결과로
구분한다. 일반 기능 개발에는 두 대형 파일 전체가 아니라 필요한 key와 검사 identity 행만 읽는다.
- [AnalysisProcedure](../../include/fesa/analysis/analysis_procedure.h)와
[factory](../../src/fesa/analysis/prepared_analysis.cpp)는 shell linear/nonlinear static,
eigen, HHT, thermal과 solid static/frequency/HHT를 선택한다. 실행 수명은 호출자 adapter보다 짧다.
[PreparedAnalysisOutcome](../../include/fesa/analysis/prepared_analysis_outcome.h)은 family별
typed completed payload를 유지하고, [결과 dispatch](../../src/fesa/results/prepared_results_writer.cpp)는
검증된 payload를 해당 writer로 보낸다. 기존 schema·atomic finalize 의미는 유지한다.
- [Element capabilities](../../include/fesa/elements/element_capabilities.h)는 ShellTrialElement,
SolidTrialElement, ShellInertiaElement, ThermalElement, ShellReferenceElement를 분리한다.
Adapter는 immutable kernel을 빌리므로 kernel의 수명과 주소가 안정적이어야 한다.
Equation·accepted history는 요소에 두지 않는다. Local layout과 full response를 typed로 보존한다.
- [EquilibriumAlgorithm/EquilibriumStep](../../src/fesa/analysis/equilibrium_algorithm.h)는
iteration 순서와 procedure-local typed pending candidate를 분리한다. Algorithm은 candidate를
소유하거나 type-erase하지 않는다. Static은1, mechanical HHT는0에서 시작하는 inclusive 순서를 유지하고,
procedure의 검증·commit 경계가 accepted state를 바꾼다.
- [ShellHhtIntegrator](../../src/fesa/analysis/hht_reduced_integrator.h)는 predictor·rate 계산·
physical-rate 복원을 분리한다. Chart/root/solver와 callback은 동기 borrowed view이며
rate 출력 buffer는 호출자 소유로 입력·서로와 alias하지 않는다. `RunReducedHhtStep`은
predictor→pending endpoint→commit 순서만 조정하고 accepted history를 소유하지 않는다.
- [PARDISO Session](../../src/fesa/solvers/linear/pardiso_session.h)은 private factor/solve/release
수명을 공통화한다. 기존1×1 TLS 회피의 범위를 vendor 전체 해결로 확대하지 않는다.
[SparsePattern](../../include/fesa/math/sparse_pattern.h)은 CSR 값 구조이며 지속 backend cache가 아니다.
[SpMV](../../src/fesa/math/sparse_matrix.cpp)는 여전히 호출마다 변환 배열·값 복사·handle을 소유한다.
수식·적분·reduction 순서·cache 수명에 영향이 있는 도입 차이는 manifest에 따로 분류했다.
출처 일치·compile·테스트 통과만으로 수치 동등성을 선언하지 않으며 독립 수치 검토와
영향받은 analytical/invariant·물리·reference 검증을 별도로 수행한다.
## 병합 결과와 검증 범위
2026-10-18 `dev`에 merge commit `762bd4b`로 반영했다. 제품 소스·헤더274개는
Refactor `11f09eeb`의 working bytes와 일치하며 직접 MSBuild가 주 개발 빌드다.
기존 FESADev 기능별 문서와 formulation23개를 보존했다. 과거 단계별 계획과 HHT 인계서는
현재 작업 트리에서 제거했으며 병합 직후 commit `762bd4b`의 `phases/`와 `HANDOFF.md`에서
원문을 복원할 수 있다. 현재 계약과 미해결 사항은 기능별 README가 소유한다.
Native와 CMake/Ninja의 MSVC x64 Debug 전체 target build, public header111개의 독립 TU
compile과 runtime DLL7개 대조가 통과했다. 양쪽 실제 discovery는 unit849·integration72·
reference43, 총964개로 일치한다. 사용자 지시로 정적·공통631개(unit555·integration35·
reference41)만 Native/CMake 직접 실행과 CTest에서 검증했고 failure/error/skip0이었다.
Python 합성·정책145개도 통과했다. 비정적333개는 보존했으며 미검증이다.
정식 정적5모델(beam, shell, shellNL, Hex8 linear/nonlinear static)은 fresh Refactor 기준·
통합 Native·통합 CMake 실행물에서 같은 scratch 입력 bytes와 경로로 총15회 실행했다.
등록 비교15개·보고서 검증15개·schema/identity/field parity5개를 포함한50단계가 exit0이었다.
Beam6가족212행, shell2가족294행과 Hex8 정적 U/RF/S는 기존 판정 계약을 따랐다.
ShellNL의 U blocking·UR warning-only, 내부 평형과 accepted free residual은 통과했으나
RF/RM3가족은 false/review-only이며 stress mapping은 미판정이다.
테스트·helper 삭제는0개다. 동등 대체나 폐기 구조 전용임을 입증하지 못한 항목은
[정리 검토](test-cleanup-review.md)에 따라 유지했다. 이관표의 원래2,876행·12열을
보존하고 최종 판단3열만 추가했다. 최종 단계는 문서만 변경했으므로 build/test/solver를
반복하지 않고, 코드·검사·등록·실행물·입력 hash가 같은 정리 전 실제 근거를 재사용했다.
독립 최종 검토는 차단사항0이며 전체 솔버 물리 검증 승인을 뜻하지 않는다.
## 검증 기록과 후속 확인
근거는 저장소 root의 `.build/merge-verification/refactor-integration-final-20261018-01/`에
보존했다. `archive-inventory.json`은 원래 경로와 보관 위치·SHA256·크기를 연결한다.
실행물9개·DLL35개·fresh Refactor source304개와 실패·중단 기록을 포함한1,379개 파일의
복사 hash를 확인했다. `worker-raw/t7-20261018/final-static-state.json`,
`final-review-ko.md`와 `post-merge-check.json`이 최종 검토·반영 결과를 기록한다.
기록이 없는 다른 checkout에서 과거 통과를 현재 실행 결과로 취급하지 않는다.
최초 integration 실행은 긴 TMP의260/261자 lease 경로 때문에 output-busy로 실패했다.
동일 exe/identity에서 긴 TMP exit1→짧은 TMP exit0을 확인하고 양쪽 integration35개
전체를 짧고 고유한 TMP에서 다시 실행해 통과했다. 원실패는 보존했으며 제품·검사·
허용치는 바꾸지 않았다. 후속 실행도 짧고 고유한 TMP/TEMP를 사용한다.
HHT 전체 큐는 사용자 요청 중단으로 보존하며 수치 FAIL/PASS로 세지 않는다.
HHT·solid dynamic·eigen/frequency·transient thermal 수치 실행, 정식 fine/_02/pressure
자료 누락과 `_02` comparator 연결 부재, 열해석 새 reference와 NT11 diagnostic 제한은
미완료다. `reference/temp`는 검증에 사용하지 않는다. 정적 통과를 이 범위의 완료나
테스트 삭제 근거로 확대하지 않는다. 수치 변경의 독립 검토도 rounding graph 변화와
실제 runtime 미검증 영역을 구분하며 과거 Dev와 bit 동일성을 보장하지 않는다.