Files
FESADev/phases/nonlinear-static-newton-raphson/step10.md
T

182 lines
10 KiB
Markdown

# Step 10: prepared-analysis-flow-and-full-procedure
> 과거 개발 계획이다. 아래 작업·상태·예시는 현재 실행 지시가 아니다.
> 현재 구현과 검증 한계는 [기능 요약](../../docs/nonlinear-static-newton-raphson/README.md)을 따른다.
## 읽어야 할 파일
- `AGENTS.md`
- `../../docs/solver-core/README.md`
- `../../docs/solver-core/README.md`
- `../../docs/nonlinear-static-newton-raphson/README.md`
- `../../docs/nonlinear-static-newton-raphson/formulation.md`
- `../../docs/nonlinear-static-newton-raphson/README.md`
- `../../docs/nonlinear-static-newton-raphson/README.md`
- `include/fesa/analysis/analysis.h`
- `include/fesa/analysis/linear_static_analysis.h`
- `src/fesa/analysis/linear_static_analysis.cpp`
- `src/fesa/app/fesa_application.cpp`
- `include/fesa/io/hdf5/hdf5_results_writer.h`
- `include/fesa/results/results_writer.h`
- `include/fesa/results/nonlinear_results_writer.h`
- Step 0 files: `include/fesa/app/output_paths.h`, `src/fesa/app/output_paths.cpp`
- Step 1 files: `include/fesa/model/domain.h`, `src/fesa/io/abaqus/domain_mapping_context.cpp`
- Step 5 files: `include/fesa/analysis/nonlinear_static_control.h`
- Step 6 files: `include/fesa/solvers/linear/tangent_solver.h`
- Step 7 files: `include/fesa/analysis/newton_iteration_log.h`
- Step 8 files: `include/fesa/analysis/nonlinear_analysis_state.h`
- Step 9 files: `include/fesa/results/nonlinear_results_writer.h`, `include/fesa/io/hdf5/nonlinear_hdf5_results_writer.h`
## 이전 Step 전제
Steps 0-9 provide path/lease, Domain procedure identity, nonlinear element/control/solver/log/state, and nonlinear HDF5 writer.
## 소유 파일
- Create: `include/fesa/analysis/prepared_analysis.h`
- Create: `src/fesa/analysis/prepared_analysis.cpp`
- Create: `include/fesa/analysis/linear_static_procedure.h`
- Create: `src/fesa/analysis/linear_static_procedure.cpp`
- Create: `include/fesa/analysis/nonlinear_static_procedure.h`
- Create: `src/fesa/analysis/nonlinear_static_procedure.cpp`
- Modify: `include/fesa/analysis/linear_static_analysis.h`
- Modify: `src/fesa/analysis/linear_static_analysis.cpp`
- Modify: `src/fesa/app/fesa_application.cpp`
- Test: `tests/integration/analysis/linear_static_analysis_test.cpp`
- Create: `tests/integration/analysis/nonlinear_static_procedure_test.cpp`
- Test: `tests/integration/app/fesa_application_test.cpp`
- Modify: `src/fesa/CMakeLists.txt`
- Modify: `tests/CMakeLists.txt`
## 인터페이스
```cpp
namespace fesa {
struct PreparedAnalysisInput {
Domain domain;
std::vector<Diagnostic> diagnostics;
};
Result<PreparedAnalysisInput> PrepareAnalysisInput(
const std::filesystem::path& input_path);
struct LinearStaticExecutionResult {
AnalysisState state;
std::vector<Diagnostic> diagnostics;
};
class LinearStaticProcedureExecutor {
public:
LinearStaticProcedureExecutor(const ParallelFor& parallel_for,
LinearSolver& linear_solver);
Result<LinearStaticExecutionResult> Execute(const Domain& domain) const;
private:
const ParallelFor& parallel_for_;
LinearSolver& linear_solver_;
};
struct NonlinearStaticExecutionResult {
NonlinearAnalysisState state;
std::vector<Diagnostic> diagnostics;
};
class NonlinearStaticProcedureExecutor {
public:
NonlinearStaticProcedureExecutor(const ParallelFor& parallel_for,
TangentSolver& tangent_solver);
Result<NonlinearStaticExecutionResult> Execute(
const Domain& domain, NewtonIterationLogWriter& log) const;
private:
const ParallelFor& parallel_for_;
TangentSolver& tangent_solver_;
};
using PreparedAnalysisOutcome =
std::variant<LinearStaticExecutionResult, NonlinearStaticExecutionResult>;
Result<PreparedAnalysisOutcome> ExecutePreparedAnalysis(
const Domain& domain,
LinearStaticProcedureExecutor& linear_executor,
NonlinearStaticProcedureExecutor& nonlinear_executor,
NewtonIterationLogWriter& log);
Status FinalizePreparedAnalysisResult(
const DerivedOutputPaths& paths,
const Domain& domain,
const PreparedAnalysisOutcome& outcome,
const std::vector<Diagnostic>& diagnostics,
ResultsWriter& linear_writer,
NonlinearResultsWriter& nonlinear_writer);
} // namespace fesa
```
## RED
Add tests first.
- `NSNR-PROC-001`: app validates argv, derives paths, acquires `OutputWriteLease`, opens log, then parses/maps exactly once.
- `NSNR-PROC-002`: parse/map diagnostics are sorted and preserved in prepared input.
- `NSNR-PROC-003`: linear `NLGEOM=NO` run uses `LinearStaticProcedureExecutor` and preserves existing numerical/HDF5 meaning except output names and log lifecycle.
- `NSNR-PROC-004`: nonlinear `NLGEOM=YES` run uses `NonlinearStaticProcedureExecutor`.
- `NSNR-PROC-005`: linear executor receives injected `ParallelFor` and existing `LinearSolver`; nonlinear executor receives injected `ParallelFor` and `TangentSolver`.
- `NSNR-PROC-006`: app constructs and owns concrete `TbbParallelFor`, `MklPardisoSolver`, `MklPardisoTangentSolver`, `Hdf5ResultsWriter`, and `NonlinearHdf5ResultsWriter`.
- `NSNR-PROC-007`: procedure computation/recovery returns a validated outcome without opening HDF5.
- `NSNR-PROC-008`: app closes log successfully before calling injected linear or nonlinear writer.
- `NSNR-PROC-009`: log close failure blocks HDF5 candidate creation.
- `NSNR-PROC-010`: nonlinear executor builds `NonlinearStateBaselineInput` from Domain nodes in stable internal order, preserving each node's `EntityIndex` and full `SourceEntityId`, then constructs state through `NonlinearAnalysisState::Create(domain, dofs, baseline)` before the first increment; the factor-zero baseline is committed state only and is not an accepted frame.
- `NSNR-PROC-011`: nonlinear increment loop uses factors from Step 5 and iterations `1..100`.
- `NSNR-PROC-012`: each entered iteration performs fresh tangent factorization and solves `Kff * delta = -r_f`.
- `NSNR-PROC-013`: global external vector/tangent from Step 5 is assembled once and combined with approved signs `r = f_int - f_ext`, `K_T = K_int - K_ext`; the fixed-moment tangent is subtracted once and is never duplicated per incident element.
- `NSNR-PROC-014`: iteration 100 can accept if gates pass; failure at 100 emits `nonlinear-nonconvergence` with no retry.
- `NSNR-PROC-015`: nonfinite data, factorization failure, solve failure, invalid accepted state, and log failure map to approved diagnostics.
- `NSNR-PROC-016`: constrained correction is zero and reactions/free residuals come from full residual `r = f_int - f_ext`.
- `NSNR-PROC-017`: failed nonlinear run preserves prior final HDF5 according to output lifecycle.
- `NSNR-PROC-018`: deterministic repeat produces same sparse structure, nodal source-identity order, result row order, diagnostics, and log line ordering.
### USER-DECISION-003 option-1 revision addendum
Step 10의 completed status, summary, timestamps와 commits는 보존한다. Existing procedure는 same-trial free residual/internal/external vectors를 force와 moment channel별로 분리하여 `EvaluateNewtonConvergence`에 전달하고 fresh same-iteration correction을 별도로 전달한다. 따라서 option 1의 production correction은 Step 11의 `nonlinear_static_control.cpp`에 한정하며 `nonlinear_static_procedure.cpp`, prepared-analysis API와 log writer production 변경은 예상하지 않는다. Step 11의 shellNL copied-input run과 log assertions이 unloaded rotational external channel의 exact-zero branch, loaded force channel의 retained relative branch, four-channel AND 및 intended factors `0.1..1.0`을 integration 수준에서 검증한다.
Run:
```powershell
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "LinearStaticAnalysis|NonlinearStaticProcedure|FesaApplication" --output-on-failure
```
Expected: new tests fail. Unexpected pass stops.
## GREEN
Refactor current parse/map and linear compute/recovery out of `LinearStaticAnalysis::Run()` into `PrepareAnalysisInput` and `LinearStaticProcedureExecutor`. Keep `LinearStaticAnalysis` as a compatibility wrapper that delegates through the new flow and does not contain nonlinear conditions. Implement `NonlinearStaticProcedureExecutor` in `nonlinear_static_procedure.*` using Steps 2-8, constructing state only through `NonlinearAnalysisState::Create(...)` with one baseline per Domain node in stable internal order, forming `r = f_int - f_ext` and `K_T = K_int - K_ext`, preserving `EntityIndex` plus full `SourceEntityId` into final writer inputs, and delaying all HDF5 work until `FinalizePreparedAnalysisResult`. The app owns concrete adapters and passes them through interfaces.
## VERIFY
```powershell
cmake --preset windows-msvc-ninja-debug
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "LinearStaticAnalysis|NonlinearStaticProcedure|FesaApplication" --output-on-failure
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
ctest --preset windows-msvc-ninja-debug --output-on-failure
```
Use the ignored 과거 검증 자료(정리됨) preset contract. The Harness process must inherit VsDevCmd x64 and `FESA_GTEST_SOURCE_DIR`, `MKL_DIR`, `TBB_DIR`, and `HDF5_DIR` from its parent launch environment.
## 상태 기록
Update only Step 10 status and one-line payload. Executor owns timestamps, commits, retry, and advancement.
## 금지사항
- Do not parse/map twice. 이유: source identity, diagnostics, and Domain lifetime must be deterministic.
- Do not reconstruct nodal identity from source labels alone. 이유: labels can repeat across instances and HDF5/reference matching requires full `SourceEntityId`.
- Do not open HDF5 before log close succeeds. 이유: io.md requires log close success before HDF5 candidate open/write/final replace.
- Do not insert nonlinear branches into `LinearStaticAnalysis` private lifecycle. 이유: new procedure owns its own lifecycle.
- Do not replace final HDF5 on failed analysis, log failure, or HDF5 failure. 이유: asymmetric preservation contract requires prior valid final preservation.
- Do not construct MKL/TBB/HDF5 backends inside procedure executors. 이유: dependencies are injected so tests can observe lifecycle and no backend type crosses analysis/core public boundaries.
- Do not duplicate the option-1 selector in the procedure or log writer. 이유: the existing procedure already transports the three residual vectors separately and convergence ownership remains in `nonlinear_static_control`.