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

23 KiB
Raw Blame History

Step 11: equilibrium-projection-and-reference-gate

과거 개발 계획이다. 아래 작업·상태·예시는 현재 실행 지시가 아니다. 현재 구현과 검증 한계는 기능 요약을 따른다.

목적

USER-DECISION-004 option 1과 AUDIT-001을 구현·검증한다. 같은 accepted factor-one state에서 accepted free residual, constrained reaction resultant, global applied-plus-reaction balance error를 서로 다른 quantity로 재구성하고, 기존 schema-v1 /global/equilibrium에는 balance error만 저장한다. Fine nonlinear case는 primary, coarse nonlinear case는 companion으로 검증한다. Local nodal RF1/RF2/RF3와 physical spatial RM1/RM2는 deterministic review-only evidence이고 blocking verdict를 바꾸지 않는다. Global force와 moment balance는 각각 fixed normalized <=1e-8 comparator gate를 사용하며 runtime configuration 또는 product solver acceptance로 노출하지 않는다.

읽어야 할 파일

  • AGENTS.md
  • ../../docs/solver-core/README.md
  • ../../docs/solver-core/README.md
  • ../../docs/solver-core/README.md
  • ../../docs/solver-core/README.md
  • ../../docs/solver-core/README.md
  • ../../docs/nonlinear-static-newton-raphson/README.md
  • ../../docs/nonlinear-static-newton-raphson/README.md
  • ../../docs/nonlinear-static-newton-raphson/formulation.md §§11.4, 13.1, 13.4, 14.1
  • ../../docs/nonlinear-static-newton-raphson/README.md §§3.2, 6.2, 6.3
  • ../../docs/nonlinear-static-newton-raphson/README.md §§3–6
  • ../../docs/nonlinear-static-newton-raphson/README.md §§7.3–7.5.1, 8.1–8.7
  • ../../docs/nonlinear-static-newton-raphson/README.md
  • ../../docs/nonlinear-static-newton-raphson/README.md §13
  • phases/nonlinear-static-newton-raphson/index.json
  • include/fesa/analysis/nonlinear_analysis_state.h
  • include/fesa/analysis/nonlinear_static_procedure.h
  • include/fesa/analysis/nonlinear_static_control.h
  • src/fesa/analysis/nonlinear_static_procedure.cpp
  • src/fesa/analysis/nonlinear_static_control.cpp
  • include/fesa/results/nonlinear_results_writer.h
  • include/fesa/io/hdf5/nonlinear_hdf5_results_writer.h
  • src/fesa/io/hdf5/nonlinear_hdf5_results_writer.cpp
  • tests/integration/analysis/nonlinear_static_procedure_test.cpp
  • tests/unit/io/hdf5/nonlinear_hdf5_results_writer_test.cpp
  • tests/unit/analysis/nonlinear_static_control_test.cpp
  • tests/unit/analysis/newton_iteration_log_test.cpp
  • tests/reference/reference_tolerance_policy.h
  • tests/reference/reference_tolerance_policy.cpp
  • tests/reference/nonlinear_static_reference_comparison.h
  • tests/reference/nonlinear_static_reference_comparison.cpp
  • tests/reference/nonlinear_static_reference_cases_test.cpp
  • tests/CMakeLists.txt
  • 과거 검증 자료(정리됨)
  • CMakePresets.json

이전 Step과 보존 전제

  • Steps 0–10은 completed다. 그 status, summary, timestamp, commit 또는 구현을 replay, amend, reset하거나 다시 작성하지 않는다.
  • 현재 worktree의 NSNR-CTRL-018..021, NSNR-LOG-012, NSNR-PROC-019, NSNR-HDF5-014, residual-selector GREEN과 NSNR-REF-001..023 comparator/CMake 작업은 이전 blocked Step 11에서 생성된 보존 대상이다. 삭제·재생성·reset하지 말고 현재 내용에서 계속한다.
  • 현재 comparator의 shared <=1e-10 global force/moment gate는 이전 blocker를 재현하는 보존된 implementation state다. 새 RED가 approved between-threshold metric을 거부하는 것을 증명한 뒤 comparator 내부 gate만 <=1e-8로 변경한다.
  • Selector RED는 이미 과거 실행 evidence에 속한다. 이 재실행에서 selector RED를 fabricate하거나 다시 실패시키지 않는다. 기존 테스트가 계속 green인지 focused VERIFY에서 확인한다.
  • Step 12는 pending이며 이 Step에서 시작하지 않는다.

소유 파일

RED test를 먼저 추가한 뒤 필요한 production file만 최소 수정한다.

  • Modify test first: tests/integration/analysis/nonlinear_static_procedure_test.cpp
  • Modify test first: tests/unit/io/hdf5/nonlinear_hdf5_results_writer_test.cpp
  • Preserve and extend test-private comparator: tests/reference/nonlinear_static_reference_comparison.h
  • Preserve and extend test-private comparator: tests/reference/nonlinear_static_reference_comparison.cpp
  • Preserve and extend tests: tests/reference/nonlinear_static_reference_cases_test.cpp
  • Preserve existing registration; edit only if the current sources are not registered: tests/CMakeLists.txt
  • Minimal GREEN: src/fesa/analysis/nonlinear_static_procedure.cpp
  • Minimal GREEN: src/fesa/io/hdf5/nonlinear_hdf5_results_writer.cpp
  • Preserve existing partial GREEN/tests without redesign: src/fesa/analysis/nonlinear_static_control.cpp, tests/unit/analysis/nonlinear_static_control_test.cpp, tests/unit/analysis/newton_iteration_log_test.cpp

No public header, new CMake target, new HDF5 dataset, schema-version change or reference artifact is owned by this Step.

Authoritative HDF5 입력과 test-private report 경계

Comparator는 아래 existing schema-v1 paths만 읽는다.

/model/nodes                                           [node_count]
/model/nodal_constraint_mask                           [node_count,6]
/steps/Step-1/accepted_frames                          unique factor-one row
/steps/Step-1/frames/<frame>/nodal/displacement        [node_count,6]
/steps/Step-1/frames/<frame>/nodal/generalized_internal_force [node_count,6]
/steps/Step-1/frames/<frame>/nodal/generalized_external_force [node_count,6]
/steps/Step-1/frames/<frame>/nodal/generalized_residual [node_count,6]
/steps/Step-1/frames/<frame>/nodal/reaction            [node_count,6]
/steps/Step-1/frames/<frame>/global/equilibrium        [6]

/global/equilibrium component order is FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3 and its required location is global-balance-error.

Preserve the current test-private types and make only the extensions needed by the approved dispositions and distinct internal evidence. Add the required standard <array> and <optional> includes to the test-private header. Candidate signature-level shape:

namespace fesa::test {

enum class NonlinearReferenceDisposition {
  kBlocking,
  kWarningOnly,
  kReviewOnly,
  kExcluded,
};

struct NonlinearReferencePrecheckFinding {
  std::string family_identity;
  NonlinearReferenceDisposition disposition;
  std::string diagnostic_code;
  std::vector<NonlinearReferenceRowKey> affected_keys;
};

struct NonlinearInternalEquilibriumReport {
  std::string family_identity;
  std::size_t row_count;
  double numerator;
  double scale;
  std::optional<double> normalized_metric;
  bool passed;
  std::string diagnostic_code;
};

struct ConstrainedReactionResultantReport {
  std::array<double, 3> force;
  std::array<double, 3> moment;
};

struct NonlinearReferenceComparisonReport {
  std::string case_id;
  std::filesystem::path original_input_path;
  std::filesystem::path copied_input_path;
  std::filesystem::path generated_results_hdf5;
  std::filesystem::path generated_log_path;
  std::vector<ArtifactSnapshot> pre_run_artifacts;
  std::vector<ArtifactSnapshot> post_run_artifacts;
  std::vector<NonlinearReferenceFamilyReport> families;
  std::vector<NonlinearReferencePrecheckFinding> precheck_findings;
  std::vector<NonlinearInternalEquilibriumReport> internal_equilibrium;
  ConstrainedReactionResultantReport constrained_reaction_resultant;
  bool external_blocking_passed;
  bool internal_blocking_passed;
  bool blocking_passed;
};

}  // namespace fesa::test

These are test-support interfaces only. Match the existing aggregate/data style and avoid a public solver API. For an exact-zero internal scale, leave normalized_metric empty and use diagnostic_code plus the exact-zero numerator/pass rule instead of writing NaN or Inf.

Required physical algorithm

For each node in stable Domain order at the accepted state:

  1. Read X from Domain/model identity and u, phi from the accepted state. Set x=X+u.
  2. Read generalized applied force/covector from generalized_external_force.
  3. Build constrained generalized reaction by applying the exact component mask to generalized_residual before any rotational conversion.
  4. Convert applied and constrained-reaction rotational covectors independently with InverseTransposeLeftJacobianSO3(phi). Do not convert their sum as a shortcut and do not mix free generalized residual into reaction.
  5. Accumulate, about global origin [0,0,0]:
F_applied             += applied spatial force
M_applied             += x cross F_applied_node + applied spatial physical moment
F_reaction            += constrained reaction spatial force
M_reaction            += x cross F_reaction_node + reaction spatial physical moment
global balance error   = [F_applied + F_reaction,
                          M_applied + M_reaction]

Store only the six-component balance error in the existing accepted-frame global_equilibrium and existing /global/equilibrium dataset. Reconstruct the constrained reaction resultant and accepted free residual separately in the comparator; do not add summary datasets or a public header.

For internal blocking gates:

  • Force scale is max(sum(||F_applied_node||2), sum(||F_reaction_node||2)).
  • Moment scale is max(sum(||x cross F_applied_node + M_applied_node||2), sum(||x cross F_reaction_node + M_reaction_node||2)).
  • Force and moment use separate ||balance_error||2/scale <= 1e-8 gates. If scale is exact zero, only exact-zero balance passes. No floor, max(1,scale) or clamp is allowed.
  • Accepted free translation-force and rotation-moment rows use the exact free mask and reproduce NSNR-069: nonzero matching external scale uses ||residual||inf/max(||internal||inf,||external||inf) <= 1e-2; exact-zero external scale uses typed absolute <=1e-3. Finite checks occur first.
  • ../../docs/solver-core/README.md is not used for these internal gates.

RED

기존 dirty NSNR-PROC-019, NSNR-HDF5-014, NSNR-REF-020..023은 재작성하지 않는다. 먼저 existing NSNR-REF-022를 실행해 old shared gate failure를 다시 관찰·기록한 뒤, NSNR-REF-024..025를 comparator threshold 변경 전에 test-first로 추가한다. Procedure/HDF5 behavior는 threshold rework를 위해 추가 변경하지 않는다.

  • Approved draft label NSNR-PROC-011 collides with completed Step 10's historical NSNR-PROC-011 increment-loop identity. Preserve that history and use collision-resolved test ID NSNR-PROC-019 with exact GTest symbol NonlinearStaticProcedure.NonzeroPrescribedMotionWritesCurrentArmSpatialAppliedPlusReactionBalance. Use a supported nonlinear shell input with nonzero prescribed translation and rotation plus a resolved fixed-global load. Independently reconstruct the six balance components from accepted X,u,phi, external force and masked residual. Expected RED: the current helper uses initial coordinates, raw full-residual summation and raw rotational residual, so the current-arm/spatial expected vector or distinct constrained/free projection assertion fails.
  • NSNR-HDF5-014 NonlinearHdf5ResultsWriter.WritesSchemaV1GlobalBalanceErrorLocation checks existing path/shape, exact component names, schema version 1 and location=global-balance-error. Expected RED: current writer emits location=global-origin.
  • NSNR-REF-020 NonlinearStaticReference.AuditsFinePrimaryAndCoarseCompanionArtifacts checks all exact fine, coarse and linear input/CSV hashes, fine/coarse independent execution directories and case roles. Expected RED: current case inventory supports only coarse nonlinear and linear cases.
  • NSNR-REF-021 NonlinearStaticReference.ReviewOnlyLocalReactionsCannotChangeBlockingVerdict injects or observes failing local RF/RM row/RMS decisions while U and internal blocking families pass. It requires deterministic local error/precheck reporting and an unchanged blocking pass. Expected RED: current local RF/RM dispositions are kBlocking.
  • NSNR-REF-022 NonlinearStaticReference.BlocksOnGlobalBalanceAndAcceptedFreeResidual fails each coarse/fine global-force, global-moment, free-force-residual and free-moment-residual family one at a time, then passes all. It also asserts the constrained reaction resultant is a distinct review summary. Expected RED for this re-execution: the preserved comparator applies the old shared <=1e-10 gate, so the approved coarse metric 1.413750912531167e-10 and fine metric 2.7454660159924086e-10 are rejected even though both are below 1e-8.
  • NSNR-REF-023 NonlinearStaticReference.RejectsMissingExtraDuplicateAndNonfiniteRowsBeforeToleranceAndRecordsReviewOnlyFindings covers blocking, warning-only and review-only families. Blocking precheck failure changes the blocking verdict; warning/review failures remain ordered findings. Expected RED: the current comparator cannot retain review-only precheck findings independently of the blocking verdict.
  • NSNR-REF-024 NonlinearStaticReference.GlobalForceAndMomentBalanceUseApprovedInclusiveOneEighthGate uses a test-private balance evaluator for distinct force and moment family identities. It requires an approved between-threshold metric such as 5e-9 and exact 1e-8 to pass, and nextafter(1e-8,+infinity) to fail for both identities. Expected decisive RED: the preserved shared <=1e-10 comparison rejects 5e-9 and 1e-8.
  • NSNR-REF-025 NonlinearStaticReference.GlobalForceAndMomentExactZeroScaleRequiresExactZeroBalance exercises force and moment identities independently and requires exact-zero scale plus exact-zero numerator to pass while any nonzero numerator fails without NaN/Inf or a fabricated normalized metric. This is an unchanged-contract regression and may already pass in the RED batch; it must be present before GREEN.

Run and record the observed failures:

cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "^(NonlinearStaticProcedure|NonlinearHdf5ResultsWriter|NonlinearStaticReference)\." --output-on-failure

The new tests must fail for the stated reasons. A compile failure caused only by the test-first enum/report extension is valid RED when the diagnostic identifies the missing planned production/ test-support behavior. An unexpected pass or unrelated failure stops the Step for classification.

Minimal GREEN

  1. Replace the private raw-residual/initial-coordinate global helper in src/fesa/analysis/nonlinear_static_procedure.cpp with the Required physical algorithm above. Keep stable node order, mask-before-conversion, independent applied/reaction conversion and finite failure behavior. Do not change the public procedure header or accepted-state layout.
  2. In src/fesa/io/hdf5/nonlinear_hdf5_results_writer.cpp, preserve the path, shape, component names and schema version; change the exact /global/equilibrium location attribute to global-balance-error and keep writer validation finite/fail-closed.
  3. Extend the existing comparator without deleting its partial work:
    • add fine primary inventory and keep coarse companion/linear control independent;
    • add kReviewOnly and keep local RF/RM key/schema/inventory/finite/row/RMS evidence;
    • reconstruct the constrained reaction resultant and accepted free residual from the exact HDF5 paths/mask; never use /nodal/reaction or /global/equilibrium as a substitute for all three;
    • apply internal gates exactly as specified above, using one test-private/internal shared 1.0e-8 constant for both distinct force and moment families;
    • keep U blocking, UR warning-only, local RF/RM review-only, RM3/stress excluded;
    • reject blocking missing/extra/duplicate/nonfinite rows before tolerance and retain ordered nonblocking findings;
    • set overall blocking verdict from blocking external U families AND all internal global/free families only.
  4. Preserve existing NSNR-CTRL-018..021, NSNR-LOG-012, Full Newton, fixed factors, iteration limit, 39-field log schema and the already corrected residual selector unchanged.
  5. Do not change production solver/configuration behavior for the balance threshold. No fesa.env, environment variable, CLI option, public API or HDF5 schema change is part of this GREEN.

Exact read-only artifact inventory

case exact path rows SHA-256
fine primary reference/shellNL-meshfine/shellNL-meshfine.inp input 40DF1CE77311C8D799564A21A60F3BDEBB8148D52CAE22B7292FDFAD32018220
fine primary reference/shellNL-meshfine/shellNL-meshfine displacements.csv 729 740819FF8AED0E279961581F7CDBFA12784CFBA3A488C35A652E80103F64433F
fine primary reference/shellNL-meshfine/shellNL-meshfine reactions.csv 729 AEB01C98C596792B0E5F2B86A81945CAB0BEB0C6969CFC6738C6F81DF1F94363
fine optional reference/shellNL-meshfine/shellNL-meshfine stresses.csv 5,408 6D6213AB5DB9D6B1F5FBD641367D08BACC805967B6C5A95BCE0E1A5395377782
coarse companion reference/shellNL/shellNL.inp input 4BF3ECB0F7F1E8462C573E993DBC97AC5D920C91CF6F23AD4C6891D77FFBADA2
coarse companion reference/shellNL/shellNL displacements.csv 49 4E0F99CA9372B1ADF7FAF102F43BC0B887DC743FDEDA378E4342D2CF8E0C0786
coarse companion reference/shellNL/shellNL reactions.csv 49 001CB1541A9E94424E5E650509D46BC8724970DF4DE47184D9DB09C7938AB069
coarse optional reference/shellNL/shellNL stresses.csv 288 5500E5114B1C44887528E30CEC054A1EB0F68BE3F4B8CE81FA59FC74A881483F
linear control reference/shell/shell.inp input 4005851E1AB22FD3A16AC17A8D5DA3E051233F69F37419079F3553AD134ECFCF
linear control reference/shell/shell displacements.csv 49 C81D94E0B4A849F87AA0F79C83A79B94D5661AC79E44ED826919AB432C87746B
linear optional reference/shell/shell reactions.csv 49 0E34EEC27E700C3C0C744C1DAFD8A3B95EFEF34B8616FE96665876586FE82D41
linear optional reference/shell/shell stresses.csv 288 2B75A5B0DEB045A283C9BB7E9B1153B79F7537FF487214BF4A23316B59B660A7

For every case, snapshot original inventory, bytes, SHA-256, size and timestamp; copy only the .inp bytes to a unique build-local directory; run only the copy; consume copied-sibling _results.h5 and _log.txt; compare against original read-only CSVs; then prove the original inventory is unchanged.

External comparison and classification

  • Fine and coarse U1/U2/U3 are separate blocking families.
  • Linear U1/U2/U3 is a blocking regression family.
  • All UR1/UR2/UR3 families are warning-only.
  • Fine/coarse local RF1/RF2, RF3, spatial RM1/RM2 are separate review-only families with exact mask-derived keys and complete common-policy error reports.
  • RM3 and all stress values have no numerical family. Stress files remain hash-audited optional inventory; the known fine malformed optional stress key is not repaired.
  • External families use exactly ../../docs/solver-core/README.md: reference-only S=max(abs(reference)), B=0.01*S, near-zero row abs(error)<=B, other-row relative <=0.05, family RMS(error)/S<=0.01, exact-zero family exact-zero FESA only. No absolute floor, averaging, collapse, row-order identity, clamp or tolerance relaxation.

The final gate order is literally:

ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT

Focused and full VERIFY

After minimal GREEN, run in this order and retain command, exit code, duration and output tail for Step 12:

cmake --preset windows-msvc-ninja-debug
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "^(NonlinearConvergence|NewtonIterationLog)\." --output-on-failure
ctest --preset windows-msvc-ninja-debug -R "^(NonlinearStaticProcedure|NonlinearHdf5ResultsWriter)\." --output-on-failure
ctest --preset windows-msvc-ninja-debug -R "^NonlinearStaticReference\." --output-on-failure
ctest --preset windows-msvc-ninja-debug -R "^(NonlinearStaticReference|ReferenceTolerance|Mitc4Reference)\." --output-on-failure
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
ctest --preset windows-msvc-ninja-debug --output-on-failure

The Harness launch environment must be VsDevCmd x64 and inherit FESA_GTEST_SOURCE_DIR, MKL_DIR, TBB_DIR, and HDF5_DIR. Do not substitute the solution-only MSBuild path.

Acceptance Criteria

  • New RED tests fail first for their declared current behavior, then pass after minimal GREEN.
  • /global/equilibrium remains schema v1 [6] with the same component names and stores only the current-arm/spatial-moment applied-plus-reaction balance error with location=global-balance-error.
  • Fine/coarse global force and moment normalized metrics are each <=1e-8; exact-zero scale follows the exact-zero rule.
  • Fine/coarse accepted free force and moment residual gates pass NSNR-069 independently.
  • Fine/coarse U blocking and linear U regression pass ../../docs/solver-core/README.md.
  • UR differences remain warning-only. Local RF/RM findings remain review-only and cannot fail the blocking verdict. RM3/stress remain excluded.
  • Missing/extra/duplicate/nonfinite blocking rows fail before tolerance; warning/review findings are deterministic and nonblocking.
  • Original reference artifact content, inventory, size, timestamp and hash are unchanged.
  • Focused tests, test discovery and full CTest pass without new compiler warnings.

상태 기록

On success, update only Step 11 to completed and add one concise summary. On an implementation, build, test or reference-comparison failure, classify it and update only the Executor-selected Step's allowed payload. Executor owns retry, timestamps, commits, advancement and top-level status. Do not start Step 12.

금지사항

  • Do not edit any reference artifact. 이유: exact stored files are immutable external evidence.
  • Do not run FESA on an original reference .inp. 이유: derived sibling outputs would mutate the reference directory.
  • Do not add HDF5 datasets, change schema version/path/shape/components or add public headers. 이유: Stage 5 requires reconstruction from existing schema-v1 datasets.
  • Do not use initial coordinates or raw rotational covectors for global physical moment. 이유: AUDIT-001 requires accepted current arms and spatial moment conversion.
  • Do not apply the constraint mask after spatial conversion. 이유: partial rotational constraints would mix free residual into reaction.
  • Do not use /global/equilibrium, local /nodal/reaction or a raw full-residual sum as a substitute for all three equilibrium quantities. 이유: their physical identities differ.
  • Do not make local reaction rows blocking or omit their review evidence. 이유: USER-DECISION-004 fixes review-only with deterministic findings.
  • Do not compare RM3 or stress values, average/collapse rows, match by row order, clamp zero values, add max(1,S), relax tolerance or repair CSVs. 이유: approved identity/tolerance contracts forbid it.
  • Do not add fesa.env, runtime configuration, product solver acceptance, CLI or public API behavior for the 1e-8 gate. 이유: this fixed threshold belongs only to comparator-owned internal verification.
  • Do not replay or fabricate selector RED, delete partial Step 11 work, reset history, commit, push, run a reference solver, start Step 12, or claim Physics/Release readiness.
  • Stop and return a classified blocker if the required behavior needs an upstream contract, public API, HDF5 schema, tolerance or reference-artifact change.