Files
FESADev/docs/nonlinear-static-newton-raphson/implementation-plan.md
T
2026-08-28 00:32:30 +09:00

253 lines
20 KiB
Markdown

# Nonlinear Static Newton-Raphson Implementation Plan
> For Harness workers: this plan is an approved Stage 6 planning artifact. It authorizes planning files only. It does not authorize `scripts/execute.py`, C++ implementation, build, CTest, reference solver execution, or evidence-document creation.
**Goal:** `nonlinear-static-newton-raphson` 기능을 C++17/MSVC/CMake/CTest TDD 순서로 구현하고, 승인된 nonlinear MITC4 Newton-Raphson 절차, HDF5 schema v1, log lifecycle, shellNL/shell reference comparison을 검증한다.
**Architecture:** App layer가 argv 검증, lexical output path derivation, move-only `OutputWriteLease`, log open/close와 final HDF5 writer 호출 순서를 소유한다. 입력 parse/map은 정확히 한 번 수행하고, `StepDefinition::ProcedureKind()`로 linear와 nonlinear procedure executor를 분리한다. `LinearStaticAnalysis`의 기존 private lifecycle에는 nonlinear 조건문을 넣지 않고, 기존 linear numerical/HDF5 의미는 repository-wide output name/log lifecycle 변경만 제외하고 보존한다.
**Tech Stack:** C++17, MSVC on Windows, CMake, CTest, GoogleTest, Intel oneAPI MKL/TBB, HDF5, Abaqus `.inp` approved subset, Python 3 Harness scripts.
**Spec:** `docs/nonlinear-static-newton-raphson/{requirements,research,formulation,numerical-review,reference-model,io}.md`
## Metadata
| key | value |
| --- | --- |
| feature_id | `nonlinear-static-newton-raphson` |
| status | `approved-planning-files-materialized` |
| owner_agent | `implementation-planning-agent` |
| date | `2026-08-24` |
| approval | User approved the final 13-Step draft on `2026-08-24`; Coordinator recorded `DECISION-036`. |
| source_requirement | `docs/nonlinear-static-newton-raphson/requirements.md` |
| source_research | `docs/nonlinear-static-newton-raphson/research.md` |
| source_formulation | `docs/nonlinear-static-newton-raphson/formulation.md` |
| source_numerical_review | `docs/nonlinear-static-newton-raphson/numerical-review.md` |
| source_reference_models | `docs/nonlinear-static-newton-raphson/reference-model.md` |
| source_io_definition | `docs/nonlinear-static-newton-raphson/io.md` |
## Approved Upstream Hashes
| document | SHA-256 |
| --- | --- |
| `requirements.md` | `910E351F3F90FFA42F07D15206B55E62C05EAE821E250424430148337506EBF2` |
| `research.md` | `C920A6B02381230D1DB419D73FE767D611B36720D27D6410507BA88C3CA28EEE` |
| `formulation.md` | `DFA629888041D5762FD0DF4271353464A692B325DC0C821A8D8689688C1EAFD0` |
| `numerical-review.md` | `9517E11804C45A6F3822D18821D52EA493AE20353C8FFAD61E960F4315977D01` |
| `reference-model.md` | `52D10B1D0C0500B295C5E48BCB3618B309D9696371B8070D4E3DCEE8D3D74CD3` |
| `io.md` | `DBB959A68F17D67CA2B42569610B9C1B595A8BFB5502BC194B7E62B656031B28` |
## Readiness Check
- Upstream document status: Stage 1 requirements approved, Stage 2 research passed, Stage 3 formulation ready for numerical review and approved downstream, Stage 4 numerical/reference review passed for I/O definition, Stage 5 I/O definition approved.
- Missing decisions: none.
- Missing required comparison files: none for declared blocking/reference families.
- Planning can proceed: yes.
- `.harness/config.json`: absent during planning inspection. Each Step must recheck at execution time and use it first if it appears.
## Global Constraints
- Use `RED -> observed failure -> minimal GREEN -> focused VERIFY -> full CTest` in every implementation Step.
- C++ production edits require related C++ tests in the same Step.
- Do not edit requirements, research, formulation, numerical review, reference-model, I/O, tolerance, or reference artifacts.
- Do not run Abaqus, Nastran, or any reference solver.
- Do not create `implementation-report.md`, `build-test.md`, or `reference-comparison.md` before Step 12 produces actual command evidence.
- Do not run Harness from this planning approval. `scripts/execute.py` requires a separate explicit request.
- Implementation and Harness execution remain unauthorized by this materialized plan until the user separately requests Executor execution.
- Preserve source label/instance identity, deterministic row order, deterministic diagnostics, finite checks, and docs/TOLERANCE.md exactly.
- Preserve `U1/U2/U3` blocking and `UR1/UR2/UR3` warning-only. For shellNL, preserve constrained `RF1/RF2`, `RF3`, physical spatial `RM1/RM2` blocking, and exclude `RM3` plus stress from numeric comparison.
## Repository Seam Map
| area | current seam | implementation direction |
| --- | --- | --- |
| CLI/app | `src/fesa/app/fesa_application.cpp` currently accepts `[--output <results.h5>]` and constructs `LinearStaticAnalysis`. | Add output path derivation and `OutputWriteLease`, reject any argv token containing `--output`, own log/HDF5 lifecycle. |
| Analysis request | `include/fesa/analysis/analysis.h` contains `input_path` and `output_path`. | Add `log_path`; Step 10 introduces prepared analysis flow for single parse/map and delayed HDF5 finalization. |
| Linear lifecycle | `LinearStaticAnalysis::Run()` currently parses/maps and writes HDF5 inside `RecoverAndWrite()`. | Refactor into `PrepareAnalysisInput`, `LinearStaticProcedureExecutor`, and final writer call after log close; keep linear numerical behavior. |
| Domain | `StaticStepDefinition` in `include/fesa/model/model_types.h`; `StepDefinition` in `include/fesa/model/domain.h`. | Store procedure identity, `NLGEOM`, raw four `*STATIC` values and provenance. Do not store derived factor sequence or PRESELECT state. |
| Parser mapping | `src/fesa/io/abaqus/domain_mapping_context.cpp`, `step_definition_mapper.cpp`. | Accept nonlinear static subset, warning no-op PRESELECT, reject unsupported procedure fail-closed. |
| MITC4 | `include/fesa/elements/mitc4_shell.h`, `src/fesa/elements/mitc4_shell.cpp` are linear small-rotation. | Add separate nonlinear MITC4 files with `Create(...)` from four nodes, four initial frames, `ShellSection`, and `LinearElasticMaterial`; element kernels compute internal residual/tangent/recovery only. |
| Loads/control | Current loads are assembled for linear static RHS. | Step 5 owns global-once fixed CLOAD external vector `f_ext` and exact external load tangent `K_ext`, including projected moment `J_l`/map-Hessian terms, with no incident-element multiplication. Step 5 also owns exact convergence constants: relative `1.0e-2`, zero-scale `1.0e-3` with channel-specific units. Step 10 forms `r = f_int - f_ext` and `K_T = K_int - K_ext`. |
| Source identity | `SourceEntityId { instance_name, source_label, source_label_text }` and `EntityIndex` exist in `include/fesa/core/source_identity.h`; nodes are stored in stable Domain order. | Step 8 baseline uses both `EntityIndex` and full `SourceEntityId`, requires one node baseline per Domain node in stable internal order, rejects label-only or mismatched identities, and preserves identity into HDF5/reference mapping. |
| Solver | `MklPardisoSolver` uses SPD `mtype=2` and upper-triangle copy. | Preserve unchanged; add `TangentSolver` and MKL unsymmetric full CSR `mtype=11`. |
| Results writer | `ResultsWriter` is the backend-neutral linear writer; `Hdf5ResultsWriter` writes schema-v0 single-frame linear output. | Add `NonlinearResultsWriter` backend-neutral boundary and `NonlinearHdf5ResultsWriter` schema-v1 implementation with delayed finalization after log close. |
| Tests | `fesa_unit_tests`, `fesa_integration_tests`, `fesa_reference_tests` use executable-wide labels. | Add focused test sources and use `ctest -R` regex; do not globally relabel existing tests as nonlinear. |
## Work Breakdown
| Step | name | dependency | primary responsibility |
| ---: | --- | --- | --- |
| 0 | `cli-output-lease-and-derived-names` | none | CLI output derivation, `--output` substring rejection, RAII output lease, app-owned log/HDF5 lifecycle entry. |
| 1 | `nonlinear-static-domain-contract` | 0 | Domain/parser semantic contract for `NLGEOM=YES`, raw `*STATIC`, PRESELECT warning no-op. |
| 2 | `finite-rotation-state` | 1 | SO(3) finite rotation state, left Jacobian, branch/invariant validation. |
| 3 | `nonlinear-mitc4-kinematics-and-recovery` | 1,2 | TL MITC4 nonlinear kinematics and recovery rows. |
| 4 | `nonlinear-mitc4-residual-and-tangent` | 2,3 | Same-trial internal residual and internal consistent tangent with recovery. |
| 5 | `load-boundary-path-and-convergence-gates` | 1-4 | Fixed factor path, proportional load/BC path, global-once fixed-load `f_ext`/`K_ext` with approved subtraction signs, `rho_M`, typed four-channel convergence with constants owned by evaluator. |
| 6 | `backend-neutral-tangent-solver` | 4 | Separate nonsymmetric tangent solver boundary and MKL adapter. |
| 7 | `newton-iteration-log-writer` | 0,5 | Exact 39-field Newton text log writer. |
| 8 | `nonlinear-state-commit-rollback` | 3-7 | Factor-zero baseline construction with `EntityIndex` plus `SourceEntityId`, trial/committed nonlinear state, accepted frames, rollback/preservation. |
| 9 | `nonlinear-hdf5-schema-v1-writer` | 8 | Nonlinear HDF5 schema v1 writer using `std::vector<Diagnostic>`. |
| 10 | `prepared-analysis-flow-and-full-procedure` | 0-9 | Single parse/map prepared analysis flow, separate linear/nonlinear executors, delayed writer finalization. |
| 11 | `reference-comparison-gate` | 0-10 | shellNL nonlinear and shell linear real-input reference comparison. |
| 12 | `execution-closure-and-evidence-docs` | 0-11 | Fresh MSVC evidence, deterministic repeat/reference audit, actual-output evidence docs. |
## TDD Test Plan
| test id family | RED assertion scope | Step |
| --- | --- | --- |
| `NSNR-CLI-*` | `--output` substring first-token rejection, lexical result/log names, no-output-change proof, lease lifetime. | 0 |
| `NSNR-IO-*` | `NLGEOM=YES`, raw `*STATIC`, `NLGEOM=NO` regression, PRESELECT warning no-op, unsupported procedure diagnostics. | 1 |
| `NSNR-ROT-*` | finite rotation invariants, `J_l`, branch margin, director update. | 2 |
| `NSNR-ELEM-KIN-*` | nonlinear MITC4 creation inputs, TL shell kinematics, fixed-size four-GP recovery rows, degeneracy fail-closed, linear limit. | 3 |
| `NSNR-ELEM-TAN-*` | same-trial internal residual/tangent, directional derivative, objectivity, symmetry only for internal/no-external cases. | 4 |
| `NSNR-CTRL-*` | load factor path, absolute boundary path, global-once fixed loads and load tangent, moment admissibility, typed four convergence gates with `relative`/`zero-scale` branches and non-injectable exact thresholds/units. | 5 |
| `NSNR-SOLVER-*` | nonsymmetric tangent solve, 0x0, nonfinite/failure translation, SPD solver unchanged. | 6 |
| `NSNR-LOG-*` | serializer-owned 39-field UTF-8/LF/TAB Newton log from explicit stage/failure/channel records and fail-closed write/flush/close. | 7 |
| `NSNR-STATE-*` | factor-zero baseline creation with stable node order and full source identity, trial/committed separation, accepted frame order, full schema-v1 state inventory, finite atomic commit, rollback. | 8 |
| `NSNR-HDF5-*` | `NonlinearResultsWriter` boundary, schema v1 metadata/model/frame datasets, factor-zero metadata, atomic finalization. | 9 |
| `NSNR-PROC-*` | full procedure orchestration, single parse/map, log close before HDF5, deterministic repeat. | 10 |
| `NSNR-REF-*` | original artifact snapshot, temp input copy run, HDF5-to-original-CSV identity mapping, tolerance, classification, report data. | 11 |
| `NSNR-EVID-*` | fresh evidence docs and diff/hash/warning audits from actual command outputs. | 12 |
## CMake And CTest Plan
- Add C++ sources to `src/fesa/CMakeLists.txt` under existing `fesa_solver`.
- Add unit tests to `fesa_unit_tests`, integration tests to `fesa_integration_tests`, reference tests to `fesa_reference_tests`.
- Preserve current executable-wide labels. Use focused regex such as `ctest --test-dir .harness/build -C Debug -R "NonlinearStaticReference|ReferenceTolerance|Mitc4Reference" --output-on-failure`.
- If scoped per-test labels are introduced, the Step that introduces the mechanism must test it and avoid changing labels for unrelated discovered tests.
- Configure/build/test commands:
```powershell
cmake --fresh -S . -B .harness/build -G "Visual Studio 18 2026" -A x64 `
"-DFESA_GTEST_SOURCE_DIR=$gtestSource" `
"-DMKL_DIR=$mklDir" `
"-DTBB_DIR=$tbbDir" `
"-DHDF5_DIR=$hdf5Dir"
cmake --build .harness/build --config Debug
ctest --test-dir .harness/build -C Debug --show-only=json-v1
ctest --test-dir .harness/build -C Debug --output-on-failure
```
## Data Flow Contract
1. CLI receives `fesa.exe <model.inp>`.
2. App scans all argv tokens left-to-right. The first token containing case-sensitive substring `--output` fails with one `cli-usage` diagnostic before path resolution, parse/map, analysis, lease, log, or HDF5.
3. App derives `<stem>_results.h5` and `<stem>_log.txt` beside the lexically normalized user-addressed `.inp`.
4. App acquires move-only `OutputWriteLease` and retains it until all log and HDF5 work ends.
5. App opens/truncates the log, then `PrepareAnalysisInput(input_path)` parses/maps once into `Domain`.
6. Procedure executor receives injected `ParallelFor` plus `LinearSolver` or `TangentSolver` and computes a fully validated linear or nonlinear state without opening HDF5. Nonlinear assembly forms `r = f_int - f_ext` and `K_T = K_int - K_ext` from Step 4 internal quantities and Step 5 global-once external quantities. Nonlinear state construction preserves each node's stable `EntityIndex` and full `SourceEntityId`; source label alone is never a row identity.
7. App closes the log successfully before invoking injected `ResultsWriter` or `NonlinearResultsWriter`.
8. HDF5 is the authoritative solver output. CSV views are comparison/debug artifacts only.
## Reference Inventory
| path | role | rows | SHA-256 |
| --- | --- | ---: | --- |
| `reference/shellNL/shellNL.inp` | nonlinear input | input | `4BF3ECB0F7F1E8462C573E993DBC97AC5D920C91CF6F23AD4C6891D77FFBADA2` |
| `reference/shellNL/shellNL displacements.csv` | required displacement CSV | 49 | `4E0F99CA9372B1ADF7FAF102F43BC0B887DC743FDEDA378E4342D2CF8E0C0786` |
| `reference/shellNL/shellNL reactions.csv` | required reaction CSV | 49 | `001CB1541A9E94424E5E650509D46BC8724970DF4DE47184D9DB09C7938AB069` |
| `reference/shellNL/shellNL stresses.csv` | nonblocking inventory artifact | 288 | `5500E5114B1C44887528E30CEC054A1EB0F68BE3F4B8CE81FA59FC74A881483F` |
| `reference/shell/shell.inp` | linear input | input | `4005851E1AB22FD3A16AC17A8D5DA3E051233F69F37419079F3553AD134ECFCF` |
| `reference/shell/shell displacements.csv` | required displacement CSV | 49 | `C81D94E0B4A849F87AA0F79C83A79B94D5661AC79E44ED826919AB432C87746B` |
| `reference/shell/shell reactions.csv` | nonblocking inventory artifact | 49 | `0E34EEC27E700C3C0C744C1DAFD8A3B95EFEF34B8616FE96665876586FE82D41` |
| `reference/shell/shell stresses.csv` | nonblocking inventory artifact | 288 | `2B75A5B0DEB045A283C9BB7E9B1153B79F7537FF487214BF4A23316B59B660A7` |
Blocking and warning families:
| family | components | rows | disposition |
| --- | --- | ---: | --- |
| `linear.translation` | `U1,U2,U3`, nodes `1..49` | 147 | blocking |
| `linear.rotation` | `UR1,UR2,UR3`, nodes `1..49` | 147 | warning-only |
| `nonlinear.translation` | `U1,U2,U3`, nodes `1..49` | 147 | blocking |
| `nonlinear.rotation` | `UR1,UR2,UR3`, nodes `1..49` | 147 | warning-only |
| `nonlinear.reaction_inplane_force` | `RF1,RF2`, constrained nodes | 48 | blocking |
| `nonlinear.reaction_transverse_force` | `RF3`, constrained nodes | 24 | blocking |
| `nonlinear.reaction_physical_moment` | `RM1,RM2`, constrained nodes | 48 | blocking |
Constrained node labels for shellNL reactions: `1,3,4,5,6,7,8,9,14,15,16,17,22,23,24,25,26,27,28,29,30,31,32,33`.
Exact shellNL `Frame`: `Increment 10: Step Time = 1.000`.
Step 11 must not run original reference input paths directly. It snapshots exact original artifact inventory, copies input bytes unchanged into a unique build-local temp case directory, runs `FesaApplication` on the copied `.inp`, consumes copied-sibling `_results.h5` and `_log.txt`, compares generated HDF5 to original read-only CSVs, and then verifies original reference directory inventory, bytes, timestamps, and hashes are unchanged. HDF5 source path identity matches the copied user-addressed input; source content identity matches the approved input hash.
## Acceptance Traceability Matrix
| requirement | Steps | test ids |
| --- | --- | --- |
| `FESA-REQ-NSNR-001` | 1,10 | `NSNR-IO-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-003` | 1,3,4,10 | `NSNR-IO-*`, `NSNR-ELEM-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-041` | 1,3,10 | `NSNR-IO-*`, `NSNR-ELEM-KIN-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-074` | 2,8,10 | `NSNR-ROT-*`, `NSNR-STATE-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-006` | 4,6,10 | `NSNR-ELEM-TAN-*`, `NSNR-SOLVER-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-007` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-069` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-070` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-008` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-014` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-046` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-048` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-018` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-063` | 5,10 | `NSNR-CTRL-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-016` | 1,5 | `NSNR-IO-*`, `NSNR-CTRL-*` |
| `FESA-REQ-NSNR-011` | 8,9,10 | `NSNR-STATE-*`, `NSNR-HDF5-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-019` | 4,8,10 | `NSNR-ELEM-TAN-*`, `NSNR-STATE-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-020` | 1 | `NSNR-IO-*` |
| `FESA-REQ-NSNR-021` | 8,9,10 | `NSNR-STATE-*`, `NSNR-HDF5-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-024` | 7,10 | `NSNR-LOG-*`, `NSNR-PROC-*` |
| `FESA-REQ-NSNR-083` | 0,10,12 | `NSNR-CLI-*`, `NSNR-PROC-*`, `NSNR-EVID-*` |
| `FESA-REQ-NSNR-026` | 8,10,11,12 | `NSNR-STATE-*`, `NSNR-PROC-*`, `NSNR-REF-*`, `NSNR-EVID-*` |
| `FESA-REQ-NSNR-030` | 2,3,4,5,6,7,8,9,10,11 | `NSNR-ROT-*`, `NSNR-ELEM-*`, `NSNR-CTRL-*`, `NSNR-SOLVER-*`, `NSNR-LOG-*`, `NSNR-STATE-*`, `NSNR-HDF5-*`, `NSNR-PROC-*`, `NSNR-REF-*` |
| `FESA-REQ-NSNR-034` | 11 | `NSNR-REF-*` |
## Numerical Review Coverage
| category | Steps |
| --- | --- |
| linear-limit reduction | 3,4,10,11 |
| rotation invariants and branch margin | 2,8,10 |
| tangent directional derivative schedule | 4 |
| no-moment tangent symmetry | 4 |
| finite rigid objectivity | 3,4 |
| patch/sign recovery | 3,4 |
| load/boundary path and `rho_M` | 5,10 |
| Newton factor/iteration lifecycle | 5,7,10 |
| four convergence gates | 5,7,10 |
| commit/rollback/determinism | 8,10,11,12 |
## Validation Commands
Each Step must:
1. Recheck `.harness/config.json`. If present, use the configured Harness build/test commands.
2. If absent, use:
```powershell
cmake --fresh -S . -B .harness/build -G "Visual Studio 18 2026" -A x64 `
"-DFESA_GTEST_SOURCE_DIR=$gtestSource" `
"-DMKL_DIR=$mklDir" `
"-DTBB_DIR=$tbbDir" `
"-DHDF5_DIR=$hdf5Dir"
cmake --build .harness/build --config Debug
ctest --test-dir .harness/build -C Debug --show-only=json-v1
ctest --test-dir .harness/build -C Debug --output-on-failure
```
Focused CTest commands are written explicitly in each `stepN.md`.
Harness Python validation is not in scope unless a Step changes Harness Python behavior, hook behavior, or agent configuration.
## Risks And Downstream Handoff
- Main implementation risk: current `LinearStaticAnalysis` owns parse/map and HDF5 write internally. Step 10 must refactor through prepared analysis flow so log close precedes HDF5 finalization for both linear and nonlinear runs.
- Main numerical risk: nonlinear MITC4 tangent and finite rotation derivatives must pass internal derivative/objectivity tests before reference comparison can be meaningful.
- Main backend risk: nonlinear tangent can be nonsymmetric. Preserve SPD `MklPardisoSolver` unchanged and add separate `TangentSolver`.
- Handoff to Implementation Agent through Coordinator: execute Steps 0..12 in order, one current Step at a time, with RED observed failure evidence before GREEN implementation, then focused/full CTest. Final reference gate is Step 11; evidence-document closure is Step 12.
## Open Issues
None.
## Plan Approval Boundary
The user-approved plan and pending phase files do not authorize Harness execution. `scripts/execute.py nonlinear-static-newton-raphson` requires a separate explicit user request.