Files
FESADev/docs/mitc4-shell-feast-eigen2/io.md
T
2026-10-04 03:32:59 +09:00

586 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MITC4 eigen 입력·결과·mapping 계약
Density/Frequency 입력, authoritative additive HDF5 schema와 identity·실패 lifecycle의 현재 계약이다.
<a id="io"></a>
<a id="io--mitc4-eigen-io-계약"></a>
## MITC4 eigen I/O 계약
- Feature ID: `mitc4-shell-feast-eigen2`; Owner: `io-definition-agent`; Contract revision: `r2` (외부 Value acceptance만 변경).
- 입력 baseline: [requirements r1](requirements.md#requirements), [formulation r1](formulation.md).
- 기준: [프로젝트 지침](../../AGENTS.md), [PRD](../PRD.md), [ADR-028](../ADR.md#adr-028),
[ARCHITECTURE](../ARCHITECTURE.md), [Feature ADR](ADR.md).
- 상태: formulation r1과 독립 NR의 `pass-for-io-definition` 및 최종 controls/reference-model을 반영한 I/O 계약 작성 완료. 구현·실행 검증 기록이 아니다.
<a id="io--결정"></a>
### 결정
원본 frequency input의 N과 source step을 보존하며 consistent에서 유도한 lumped mass와
실제 MKL FEAST의 N개 고유쌍을 공식 HDF5로 식별한다. 기존 static schema0/1과 CLI/output
lifecycle는 유지한다. Eigen discriminator·density·modal datasets는 additive다.
N개의 global mass-normalized vectors는 내부 검증을 위해 필수이며 외부 shape gate는 없다.
전체 c개의 내부 validation evidence는 공개 mode N개와 분리한다.
2026-09-10 사용자 명시 5% 승인에 따라 첫 구현 외부 Value 비교에는
`mitc4-eigen-first-implementation` 정책을 적용한다. 같은 identity의 mode별 singleton에서
상대오차와 relative RMS를 모두 5% 이하(inclusive)로 판정한다. 근거는
[공통 TOLERANCE](../TOLERANCE.md)와 [MFE2-ADR-012](ADR.md)이며 I/O가 새 기준을 선택한 것이 아니다.
다른 공통 comparison family의 RMS 1%, 전체 c개 내부 독립 검증 `1e-10`, HDF5 schema는 유지한다.
정확도 개선과 이미 분리한 S3는 후속 과제이며 이 acceptance 변경으로 해결을 주장하지 않는다.
| 상세 문서 | 권위와 내용 |
| --- | --- |
| [io-input](io.md#io-input) | Supported syntax/defaults, source scope, rho/BC mapping, no-op allowlist, fail-closed diagnostics |
| [io-schema](io.md#io-schema) | Authoritative HDF5 types/shapes/units, source step·mode identity, all-c evidence, self-check |
| [io-mapping](io.md#io-mapping) | Domain/AnalysisModel/DOF/state ownership, candidate/failure lifecycle, TXT grammar·prechecks·Value projection |
| [NR controls](numerical-review-controls.md), [reference-model](reference-model.md) | 내부 수치 controls와 외부 modal-frame family; I/O가 tolerance를 선택하지 않음 |
공개 Abaqus convention은 [입력 문서의 공식 출처](io.md#io-input--step와-frequency)를 직접 대조했다.
Lanczos/SIM은 source compatibility 정보이며 실제 algorithm 동등성을 주장하지 않는다.
ACOUSTIC COUPLING=ON은 acoustic-free 모델에서만 적용 대상 없음으로 처리한다.
물리량은 사용자 일관 units이며 SI로 추론하지 않는다. Meaningful unsupported input은 실패한다.
<a id="io--현재-source와의-차이"></a>
### 설계 당시 source와의 차이
2026-09-08 설계 당시 지정 source를 읽기 전용으로 확인한 기록이다. 아래 표는 당시의
미구현 연결을 설명하며 현재 구현 상태를 뜻하지 않는다. 연결 후 실행 결과와 남은 한계는
[구현 검증](implementation-verification.md)을 따른다. 기존 Feature의 pass를 승계하지 않았다.
| 실제 확인 파일 | 확인 결과와 필요한 연결 |
| --- | --- |
| [input_reader](../../src/fesa/io/abaqus/input_reader.cpp) | ASCII/256-byte/continuation/raw fields와 FNV byte identity 재사용; 새 lexical framework 불필요 |
| [domain_mapping_context](../../src/fesa/io/abaqus/domain_mapping_context.cpp) | RawMaterial에 density 없음, RawStep은 static 전용, DENSITY/FREQUENCY 없음. PERTURBATION/ENERGY OUTPUT도 새 eigen subset 필요. FinalizeStep의 hardcoded Step-1 외에 raw source name·N을 보존해야 함 |
| [material mapper](../../src/fesa/io/abaqus/material_property_mapper.cpp), [step mapper](../../src/fesa/io/abaqus/step_definition_mapper.cpp) | Context 위임 경계다. Density/property와 Frequency semantic 확정은 같은 candidate 흐름에 연결 |
| [model writer](../../src/fesa/io/hdf5/hdf5_model_writer.cpp), [primitives](../../src/fesa/io/hdf5/hdf5_primitives.cpp) | 기존 compounds, UTF-8/fixed-width, user-consistent-unspecified, path+content identity 재사용; material compound 수정 대신 별도 densities |
| [linear writer](../../src/fesa/io/hdf5/hdf5_results_writer.cpp), [nonlinear writer](../../src/fesa/io/hdf5/nonlinear_hdf5_results_writer.cpp), [self_check](../../src/fesa/io/hdf5/hdf5_self_check.cpp) | Static0/1 전용 경로를 eigen에 재사용해 modal 값을 static frame0으로 내면 오류. Dedicated eigen serialization/self-check dispatch 필요 |
<a id="io--후속-검증-의무"></a>
### 후속 검증 의무
Requirement prefix는 `FEM-REQ-MITC4-EIGEN2-`다. 아래 검증을 문서 작업 중 실행한 것으로
집계하지 않는다. 수치 기준·oracle는 [NR](numerical-review.md#numerical-review)와 연결된 상세가 권위다.
| ID | 필수 관찰 | Requirement suffix |
| --- | --- | --- |
| IO-T01 | 원본 변경 없이 Step-2/N10/rho2700/t0.5, keyword defaults/no-op warnings·실제 FEAST; S4R source-only 변형 같은 physical path | 001–004,015–016 |
| IO-T02 | 다중 material/section 연결; missing/duplicate/unresolved/0/negative/nonfinite/dependent rho, extra row/field, 잘못된 geometry/section 거부 | 003–004,016 |
| IO-T03 | N blank/0/fraction/overflow, nonblank frequency slots2~7(0 포함), eighth empty slot, duplicate/unknown option, multiple/preload/acoustic/load/nonzero BC 거부 | 001,009,015–016 |
| IO-T04 | Source label/instance/set renumbering·모호함, partial BC·fully constrained·drill-only, 실제 free injection/global 복구; rank cutoff로 tiny positive mass 삭제 금지 | 006–008,014,018 |
| IO-T05 | Additive schema round-trip·source step·units·N/c·mass/backend identity; normalized final phi로 original residual/Gram/energy 재검증; raw negative/zero/positive와 frequency subset | 010–013,017–018 |
| IO-T06 | 실제 FEAST known zero/repeated/cluster/n1/N=n·full capacity, optional abandoned count와 safe fallback, count/reset/budget/index/allocation/Gram/residual 실패; 최종 N과 c 구별 | 008–013,019 |
| IO-T07 | 기존 accepted state/final 준비 후 solve/validation/log/lock/write/flush/close/reopen/self-check/replace failure injection; 기존 final 보존과 최초 실패 final 미생성 | 012,019 |
| IO-T08 | TXT reorder·같은 Value의 다른 mode 허용; missing/extra/duplicate/nonfinite/malformed/step/quantity/unit/mass/backend/schema 오류를 tolerance 전에 거부; Freq 변화는 Value 판정 불변 | 020–021 |
| IO-T09 | Named first-implementation 정책의 singleton row/RMS 5% inclusive 경계·양옆, near-zero와 exact zero-scale; report policy_id/relative_rms_tolerance와 다른 공통 family RMS1% 유지 확인 | 022 |
| IO-T10 | Density 없는 static 입력과 schema0/1 유지, retained shell/shellNL/linear-limit source identity·U/UR/reaction 분류와 fresh 회귀, 제외 예제0건 | 023–025,027 |
| IO-T11 | Consistent→lumped 원본 연결과 같은 mass의 실제 FEAST/검증; mass oracle·inertia/null·coordinate/NR-MFE-001 및 deterministic assembly/row/diagnostic | 005–008,011,013–014,023,026–027 |
<a id="io--최종-대조와-미실행"></a>
### 최종 대조와 미실행
최종 NR의 B=0 enclosure, 초기 count 최대3회·전체 count512/solve3, fixed a0와
optional upper search 종료·certified fallback, normalized final phi metrics를 대조했다.
별도 per-call control 변경 없이 base_fpm 한 개와 count index49 override로 현재 controls를 표현한다.
입력 계약과 additive schema 선택은 이번 요청 안의 정의 작업이다. 기존 static public 호환성
변경은 없다. 새 mode shape 외부 acceptance, CSV mandate, reference 보조 metadata, full matrix
mandatory dump, lower/empty-prefix 검색 schema를 추가하지 않았다.
이 I/O 정의를 작성할 당시 density/Frequency/state/writer 연결은 미구현이었다. Research G01/G02의 installed
FEAST 동작·workspace와 실제 peak memory, retained regression/새 eigen reference 및 physics
검증은 당시 후속 실행 의무였다. 현재 실행·미실행 범위는 [구현 검증](implementation-verification.md)에
기록했다. Safe enclosure fallback이 runtime 확인을 대신하지 않는다.
문서만 수정하므로 build/test/Harness/FEAST/외부 solver를 실행하지 않았다. Source/test/reference와
제외 네 예제의 원본·복사·cache는 수정·검증에 사용하지 않았다.
정적 검사: owned 문서 4개의 UTF-8·Markdown fence·trailing whitespace·상대 파일 링크
41개와 원본 TXT full grammar/finite Value/unique Mode1..10을 Python read-only 검사로 확인했다.
경로 한정 `git diff --check`도 exit0이었다. Untracked 문서는 별도 내용 검사로 확인했으며
diff 검사만으로 검증했다고 하지 않는다. Build/test와 수치 comparison은 미실행이다.
<a id="io-input"></a>
<a id="io-input--mitc4-eigen-입력진단-계약"></a>
## MITC4 eigen 입력·진단 계약
- Feature ID: `mitc4-shell-feast-eigen2`
- Contract revision: `r1`
- 기본 보고서: [io.md](io.md#io)
<a id="io-input--문법과-기존-지원-범위"></a>
### 문법과 기존 지원 범위
기존 [shell 입력](../linear-static-mitc4-shell/io.md#1-abaqus-input-scope)과
[후속 lexical 계약](../shell-surface-pressure-load/io.md)을 유지한다. 현재
[input_reader.cpp](../../src/fesa/io/abaqus/input_reader.cpp)와
[domain_mapping_context.cpp](../../src/fesa/io/abaqus/domain_mapping_context.cpp)를 대조했다.
LF/CRLF, 종결자 제외 physical line 256 ASCII bytes, printable ASCII/tab, blank와 `**`
comment, keyword parameter continuation은 기존 규칙을 따른다. Inline comment, data
continuation, include/substitution/quoted name을 추가하지 않는다. Keyword·parameter·enum·
name lookup은 ASCII case-insensitive이며 raw spelling/physical source line은 보존한다.
Duplicate parameter는 같은 값이어도 실패한다. Comma split은 빈 field를 보존한다.
Eigen model의 순서는 `HEADING? PREPRINT? PART+ ASSEMBLY MATERIAL+ BOUNDARY* STEP EOF`다.
Part 내부 NODE→ELEMENT→sets→SHELL SECTION, assembly의 identity INSTANCE와 explicit-instance
sets, forward section→material lookup은 기존 shell 범위다. `S4`와 `S4R`는 source type만
구별하고 같은 FESA MITC4 kernel에 대응한다. Node/element positive int64 source label,
instance/name scope, element 네 distinct nodes, section 유일 할당, geometry-derived director,
centered finite thickness>0, homogeneous isotropic `E>0,-1<nu<0.5` 검증은 기존 계약 그대로다.
`*SHELL SECTION`의 optional positive integration-point integer는 기존 명시 예외로
warning 없이 읽고 물리 integration을 바꾸지 않는다. 새 mass integration은 formulation 권위다.
Model/history의 허용 keyword는 기존 topology/material의 `HEADING,PART,END PART,NODE,
ELEMENT,NSET,ELSET,SHELL SECTION,ASSEMBLY,END ASSEMBLY,INSTANCE,END INSTANCE,MATERIAL,
ELASTIC,BOUNDARY`와 아래 DENSITY/STEP/FREQUENCY/no-op 목록뿐이다. Assembly ELSET의 기존
`INTERNAL` flag도 보존한다. 기존 static의 load·output 범위를 이 eigen allowlist로 축소하지 않는다.
<a id="io-input--density"></a>
### Density
`*DENSITY`는 current MATERIAL 안에서 parameter 없이 최대 한 번, 정확히 한 data row를
갖는다. `rho` 또는 `rho,`만 허용한다. 뒤의 빈 temperature slot은 constant 값이며 원본
`2700.,`를 그대로 수용한다. Nonempty temperature, 추가 field/comma/row, `DEPENDENCIES=0`을
포함한 모든 parameter와 distribution은 거부한다. ELASTIC과 DENSITY의 상대 순서는 자유다.
새 rho의 C-locale token은 아래 full-match이고 binary64 full conversion을 요구한다.
```text
number := [+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[Ee][+-]?[0-9]+)?
```
Hex/D exponent/locale comma/잘못된 token은 input 오류다. NaN/Inf spelling은 아래 model
nonfinite 진단으로 분류하며 허용 token이 아니다. Overflow/underflow conversion error,
nonfinite, `rho<=0`는 invalid material이다. 모든 활성 `element→section→material→rho`가
정확히 하나로 결정되어야 한다. 누락값·다른 material·global 평균으로 대체하지 않는다.
사용하지 않은 material에 선언된 density도 문법·양성 검증한다. 필수 존재 조건은 활성 material에
적용한다. 단위는 `mass/length^3`, 사용자 일관 단위계이며 자동 SI 추론·변환은 없다.
Density 허용은 새 eigen procedure에 한정한다. 기존 static 입력 지원을 확장하거나 density를
필수화하지 않는다. Procedure 확인 전 raw material을 보존한 뒤 해당 procedure로 검증한다.
<a id="io-input--step와-frequency"></a>
### Step와 Frequency
`*STEP`은 정확히 하나이며 optional `NAME`, `NLGEOM=NO`, value 없는 `PERTURBATION`만
허용한다. Data는 없다. 생략 NLGEOM은 NO, 생략 NAME은 source `Step-1`이다. FREQUENCY가
원형상 무응력 linear perturbation procedure를 결정하므로 PERTURBATION 생략도 같은 의미다.
Raw/canonical name과 flag presence를 보존한다. Storage `Step-1`과 source `Step-2`는 별개다.
`NLGEOM=YES`, INC, 선행/다중 step, 다른 procedure와 step description은 거부한다.
| FREQUENCY parameter | 허용/생략 default | FESA 의미 |
| --- | --- | --- |
| `EIGENSOLVER` | `LANCZOS` / LANCZOS | 실제 MKL FEAST 사용; 항상 `source-eigensolver-mapped-to-feast` warning |
| `SIM` | flag 또는 `YES` / YES | Source option만 보존; 명시되면 `source-sim-option-not-applied` warning |
| `ACOUSTIC COUPLING` | `ON` / ON | Structural-only 모델에서 적용 대상 없음; 명시되면 `acoustic-option-inapplicable-structural-only` warning |
| `NORMALIZATION` | `MASS` / MASS | 실제 derived lumped mass로 normalization |
SIM=NO, DISPLACEMENT normalization, AMS/SUBSPACE/FEAST enum, coupling OFF/PROJECTION,
RESIDUAL MODES, DAMPING PROJECTION, PROPERTY EVALUATION, NSET와 모든 미열거 parameter는
실패한다. Acoustic 요소/ASI/TIE/coupling 정의가 존재하면 ON no-op을 적용하지 않고 실패한다.
FREQUENCY data는 한 physical row, 1~7 comma fields다. 첫 field N은 `[0-9]+`, checked
positive int64이며 나머지 존재하는 fields는 전부 empty여야 한다. Fields 2~7은 source의
minimum/maximum frequency, shift, block size, Lanczos step count, acoustic range factor 자리다.
빈칸은 unspecified이며 숫자0이 아니다. Nonempty0도 실패하고 eighth empty field도 실패한다.
원본 `10, , , , ,`는 6 fields, N=10이다. Bounds/shift/FEAST controls는 사용자 입력 기능으로
추가하지 않는다. `N>finite_dimension`과 빈 finite system은 equation 구성 뒤 model 실패다.
공개 Abaqus convention의 근거는 [FREQUENCY](https://docs.software.vt.edu/abaqusv2025/English/SIMACAEKEYRefMap/simakey-r-frequency.htm),
[DENSITY](https://docs.software.vt.edu/abaqusv2025/English/SIMACAEKEYRefMap/simakey-r-density.htm),
[STEP](https://docs.software.vt.edu/abaqusv2025/English/SIMACAEKEYRefMap/simakey-r-step.htm)이다.
2026-09-08 직접 확인했다. 위 allowlist와 warning은 FESA의 지원 차이이며 Abaqus algorithm·
SIM·parser 내부 구현의 동등성을 주장하지 않는다.
<a id="io-input--homogeneous-bc와-result-neutral-allowlist"></a>
### Homogeneous BC와 result-neutral allowlist
BOUNDARY는 model 또는 FREQUENCY 뒤/output 앞에 parameter 없이
`target,first,last[,value]`로 둔다. `1<=first<=last<=6`; value 생략은 exact0, 명시 value는
finite exact0만 허용한다. 빈 fourth field는 생략으로 보지 않는다. 기존 bare source label 또는
unambiguous node-set resolver와 assembly INSTANCE binding을 사용한다. 새로운 dotted target,
local/tangent BC, MPC를 추가하지 않는다. Model BC→step BC 순서의 zero constraint union이며
같은 zero 재선언은 같은 constraint다. Nonzero를 상쇄·override해서 통과시키지 않는다.
Global DOF는 `UX,UY,UZ,URX,URY,URZ`; partial rotation BC를 그대로 유지한다.
| Keyword | 정확한 조합·위치; 모두 data 없음 |
| --- | --- |
| PREPRINT | Optional top-level, ECHO=NO,MODEL=NO,HISTORY=NO,CONTACT=NO 네 개 |
| RESTART | FREQUENCY/BC 뒤, WRITE flag와 FREQUENCY=0 |
| OUTPUT | FREQUENCY/BC 뒤, FIELD 또는 HISTORY flag 하나, optional VARIABLE=PRESELECT |
| NODE OUTPUT | 활성 OUTPUT FIELD 아래, VARIABLE=PRESELECT |
| ENERGY OUTPUT | 활성 OUTPUT HISTORY 아래, VARIABLE=ALL |
Parameter 순서는 자유이며 duplicate/extra parameter는 실패한다. OUTPUT root/RESTART/END STEP은
이전 output scope를 닫는다. 모든 허용 no-op keyword마다 `ignored-input-keyword` warning과
`mandatory-eigen-output-unchanged` 이유를 기록한다. 선택·억제·restart state를 생성하지 않는다.
Unknown output variable row/child, restart READ/nonzero frequency는 실패한다.
어떤 위치의 CLOAD/DLOAD/DSLOAD(값0 포함), initial state/stress/temperature, damping,
amplitude, acoustic/beam/solid/mixed model, concentrated/nonstructural mass, composite/offset/
variable thickness, contact/MPC/TIE, transform/orientation/explicit director, surface 등 의미 있는
미지원 입력은 fail-closed다. 이름 `shellNL` 또는 `Step-2`에서 preload를 추정하지 않는다.
<a id="io-input--진단"></a>
### 진단
기존 record `severity,code,file,line,keyword,entity_identity,message`와 CLI category를 유지한다.
File은 absolute lexical normalized path, line은 1-based; entity에 source instance/material/
element/node/step와 DOF 또는 field ordinal을 연결한다. Backend 오류도 Frequency 위치를 붙인다.
Warnings는 기존 SortDiagnostics와 same-key discovery order다. Fatal은 첫 원인을 유지하고
후속 solve/commit을 중단한다. 수치값은 round-trip decimal로 보고하며 임의 tolerance를 붙이지 않는다.
| 실패 | Code | Exit |
| --- | --- | --- |
| Lexical/arity/duplicate parameter/unresolved | 해당 기존 code: invalid-input-character, input-line-too-long, invalid-data-arity, duplicate-entity, unresolved-reference 등 | 3 |
| Density scope/malformed data/options/duplicate | invalid-density-data / unsupported-density-option / duplicate-density | 3 |
| Active rho missing / nonfinite·nonpositive·conversion range | missing-material-density / invalid-material-density | 4 |
| Frequency options/count/data | unsupported-frequency-option / invalid-frequency-data | 3 |
| Multiple/preload/other procedure | unsupported-analysis-procedure | 3 |
| Nonzero prescribed BC | unsupported-eigen-boundary | 3 |
| Other unsupported model semantics | unsupported-keyword / unsupported-element-formulation / unsupported-mixed-element-model | 3 |
| Existing geometry/material/section invalid | 기존 model code; 새 mass point 오류 invalid-shell-mass-geometry | 4 |
| Empty finite system / N>n | empty-eigenproblem / insufficient-finite-modes | 4 |
| Mass-space/conditioning/backend/numerical failure | [mapping의 solver diagnostics](io.md#io-mapping--실패와-공개-lifecycle) | 5 |
| Log/candidate/self-check/finalization | 기존 output category | 6 |
Usage2/success0와 stderr escaping은 기존 공통 CLI 계약이다. 지원되는 입력의 conditioning
실패를 input subset 축소나 인공 mass/zero clamp로 우회하지 않는다.
<a id="io-schema"></a>
<a id="io-schema--mitc4-eigen-authoritative-hdf5-schema"></a>
## MITC4 eigen authoritative HDF5 schema
- Feature ID: `mitc4-shell-feast-eigen2`; Owner: `io-definition-agent`; Contract revision: `r1`.
- 기본 보고서: [io.md](io.md#io). 수치 원본: [formulation-eigen](formulation-eigen.md),
[NR controls](numerical-review-controls.md).
<a id="io-schema--container와-compatibility"></a>
### Container와 compatibility
공식 결과는 input lexical sibling `<stem>_results.h5`다. Linear schema0와 nonlinear schema1의
기존 dataset/type/필수성/reader 의미를 바꾸지 않는다. 새 eigen discriminator는
`(schema_version=0,feature_id=mitc4-shell-feast-eigen2,analysis_procedure=linear-frequency,
eigen_schema_version=1)`이다. 이는 공통 shell model container에 대한 additive procedure다.
Reader는 schema_version만 보고 static으로 해석하지 않는다. Unknown procedure/version 또는
eigen 필수 field 누락은 명시적 unsupported/invalid schema다. Static 파일에 새 eigen fields를
요구하거나 migration하지 않는다. Unknown optional additive fields만 무시할 수 있다.
File scalar는 f64=`H5T_IEEE_F64LE`, u64/u8/i64는 해당 fixed-width little-endian integer,
string은 variable-length UTF-8다. Compound byte padding/offset은 private이며 field name/type/
array extent가 계약이다. 차원 product는 allocation 전에 checked integer다. 아래 nn/ne/nmat는
model node/element/material 수, N은 input 요청, n은 finite dimension, c는 최종 전체 검증 수다.
<a id="io-schema--metadata와-model"></a>
### Metadata와 model
`/metadata` 필수 attributes:
| 이름 | Type / 값 |
| --- | --- |
| schema_version, eigen_schema_version | u64 0,1 |
| feature_id, analysis_procedure | utf8 mitc4-shell-feast-eigen2, linear-frequency |
| solver_version | utf8 실제 binary version |
| source_input_identity | utf8 기존 `path=<absolute lexical generic path>;content_identity=fnv1a64:<16 lower hex>`; 실제 읽은 원본 bytes |
| unit_system_label | utf8 user-consistent-unspecified |
| coordinate_convention | utf8 global-cartesian; shell-local=initial-reference; positive-thickness=+zeta |
| internal_formulation | utf8 FESA-MITC4 |
| integration_rule, mass_integration_rule | utf8 2x2x2-gauss; mitc4-edge-midpoint-shear / 3x3x3-gauss |
| stabilization_rule | utf8 initial-physical-rotary-trace-mean |
| mass_variant, mass_origin, normalization | utf8 derived-lumped, consistent-moment-row-sum, mass |
| eigensolver_backend, eigensolver_routine | utf8 MKL FEAST, dfeast_scsrgv |
| backend_problem | utf8 scaled-whitened-lumped-with-identity-mass |
| numerical_contract | utf8 mitc4-shell-feast-eigen2:r1 |
Model compounds의 기존 physical field는 수정하지 않고 아래처럼 재사용한다.
| Dataset | Shape / fields | 의미 |
| --- | --- | --- |
| /model/nodes | [nn] internal_node_id:u64,instance_name:utf8,source_label:utf8,coordinates:f64[3] | ID 0..nn-1, 기존 expansion/declaration order, global length |
| /model/elements | [ne] internal_element_id:u64,instance_name:utf8,source_label:utf8,source_element_type:utf8,internal_formulation:utf8,node_internal_ids:u64[4],shell_section_internal_id:u64,material_internal_id:u64 | ID order; S4/S4R 원형 유지; 모두 FESA-MITC4 |
| /model/shell/materials | [nmat] internal_material_id:u64,name:utf8,E:f64,nu:f64 | 기존 declaration order; E force/length^2, nu1; rho를 compound에 삽입하지 않음 |
| /model/shell/sections | [section_count] internal_section_id:u64,source_file:utf8,source_line:u64,source_elset:utf8,material_internal_id:u64,thickness:f64 | 기존 centered-single-layer와 thickness length |
| /model/shell/nodal_director | [nn,3] f64 | 기존 global unit director D1,D2,D3 |
| /model/shell/nodal_frame | [nn,3,3] f64 | 기존 A,B,D axes×global X,Y,Z, dimension1 |
| /model/nodal_constraint_mask | [nn,6] u8 | UX,UY,UZ,URX,URY,URZ; free0/constrained1 |
| /model/prescribed_displacement | [nn,6] f64 | 같은 component order; 전부 exact0, 기존 length/radian dimensions |
| /model/shell/densities | [density_count] 새 compound material_internal_id:u64,rho:f64,source_file:utf8,source_line:u64 | Material ID ascending, 선언 density마다 한 row; 활성 material 전부 존재, rho>0 mass/length^3 |
| /diagnostics | [diagnostic_count] 기존 severity:utf8,code:utf8,file:utf8,line:u64,keyword:utf8,entity_identity:utf8,message:utf8 | 기존 deterministic order, 성공 파일은 warning만 |
기존 model dataset attrs는 [현재 model writer](../../src/fesa/io/hdf5/hdf5_model_writer.cpp)의
동일 field 의미를 따른다. `/model/shell/densities` attrs는 component_names=rho,
component_unit_dimensions=mass/length^3,coordinate_system=scalar,location=model-material다.
공유 writer의 midsurface_locations/section_positions 추가 저장은 허용하지만 eigen 필수량이 아니다.
`/steps/Step-1`은 storage group이며 아래 attributes가 source/procedure authority다.
Raw name을 HDF5 path에 넣거나 Step-1에서 source name을 역추정하지 않는다.
| Attribute | Type / 의미 |
| --- | --- |
| source_step_name, source_step_name_canonical | utf8 원문/ASCII uppercase; 지정 입력 Step-2/STEP-2 |
| step_source_line, frequency_source_line, frequency_data_line | u64 source 1-based 위치 |
| source_nlgeom, source_perturbation_present | u8 effective0 / flag presence0 또는1 |
| source_eigensolver, source_sim, source_acoustic_coupling, source_normalization | utf8 effective LANCZOS,YES,ON,MASS |
| source_option_presence | u8[4] 위 네 option의 explicit presence 순서 |
| requested_mode_count, returned_mode_count | u64 N,N |
| full_dof_count, free_dof_count, mass_null_dimension, finite_dimension | u64 6nn,nf,nz,n; nf=n+nz |
| validated_eigenpair_count | u64 c; N<=c<=n |
| frame_indexing | utf8 mode-rank-one-based |
별도 raw source-record table이나 duplicate reference provenance 파일은 필수로 만들지 않는다.
Raw keyword/data/blank fields는 Domain의 ParsedInput provenance와 source byte identity로 추적한다.
<a id="io-schema--공개-modal-결과"></a>
### 공개 modal 결과
Prefix `/steps/Step-1/eigen`. 새 result dataset의 공통 attrs는
`eigen_schema_version:u64=1,source_step_name:utf8=<raw>,domain:utf8=mode`와 아래 quantity/
component/dimension/coordinate/location이다. Numeric/physical values는 전부 finite다.
| Dataset | Shape/type | Quantity·identity |
| --- | --- | --- |
| modes | [N] compound mode_id:u64,eigenvalue:f64,classification:u8,cluster_id:u64 | 유일 Value authority; mode_id1..N 순서, quantity=eigenvalue, component_names=Value, component_unit_dimensions=time^-2, coordinate_system=scalar, location=modal-frame |
| frequencies | [Nv] compound mode_id:u64,frequency:f64 | modes 중 raw lambda>=0의 정확한 ID subset, mode order; quantity=cycle-frequency, component_names=Freq, component_unit_dimensions=time^-1, coordinate_system=scalar, location=modal-frame |
| vectors | [N,nn,6] f64 | Modes와 같은 mode axis, model/nodes와 같은 node axis; component_names=UX,UY,UZ,URX,URY,URZ, global-cartesian, nodal-modal-vector |
Vectors는 **mandatory 내부 검증 projection**이다. 병진 dimension `mass^-1/2` 세 개와
회전 `mass^-1/2*length^-1` 세 개를 component_unit_dimensions에 기록한다.
`normalization=mass,mass_variant=derived-lumped,interpretation=normalized-mode-not-response-displacement`
attrs를 둔다. 회전은 initial global infinitesimal rotation이다. Constrained component는 exact0.
Static displacement/reaction/stress/accepted_frames를 modal 결과로 생성하지 않는다.
[NR raw 분류](numerical-review-controls.md)대로 mu=lambda/s의 절댓값<=1e-9는
classification0=near-zero, 나머지 허용 양수는1=positive다. mu<-1e-9는 성공 파일을 만들 수 없다.
Raw lambda는 작은 음수도 보존하며 절댓값/zero clamp하지 않는다. Frequency는 raw lambda>0이면
sqrt(lambda)/(2pi), exact0이면0, 음수에는 row가 없다. Mandatory frequencies dataset은 Nv=0도
허용하며 unavailable_rule=negative-raw-eigenvalue를 기록한다. Finite/range 검사는 NR 기준이며
양수의 frequency underflow-to-zero도 invalid-eigenvalue-result다.
Sort는 paired raw lambda ascending, exact tie는 원 FEAST column order다. Sign은 최대 절댓값
scaled global component(translation/ell,rotation)를 양수로, tie는 model row×DOF 순서다.
Cluster는 전체 c sorted pairs의 NR connected rule로 1부터 부여한 후 N개에 투영한다.
Cluster label은 진단 identity이며 mode average/deduplicate/외부 shape 비교를 유발하지 않는다.
<a id="io-schema--전체-c-검증과-실제-backend-evidence"></a>
### 전체 c 검증과 실제 backend evidence
Prefix `/steps/Step-1/eigen/verification`. Attributes `characteristic_length:f64=ell [length]`,
`operator_scale:f64=s [time^-2]`는 positive finite다. `validation_scope=all-computed-c-columns`,
`eta_gram:f64,max_eta_orth:f64`는 dimension1, c=1이면 latter0이다. Null 검사는
`null_checks_applicable:u8`와 `eta_mz,eta_kz,eta_pz:f64`로 저장한다. nz=0이면 flag0/storage0이며
N/A이지 검증 통과 metric0이 아니다. 모든 metric 식과 limit는 NR controls와 채택 V식이다. 정규화 후 최종 phi에서
modal_mass와 yf를 다시 계산하고 모든 저장 residual/Gram/Rayleigh/energy에 이 값을 사용한다.
| Dataset | Shape / fields |
| --- | --- |
| nodal_reduction | [nn] compound free_count:u8,null_count:u8,positive_count:u8,rcond_available:u8,rcond_inf:f64 |
| eigenpair_checks | [c] compound sorted_rank:u64,solver_column:u64,eigenvalue:f64,modal_mass:f64,rayleigh_quotient:f64,eta_r:f64,eta_w:f64,rho_b:f64,eta_norm:f64,eta_energy:f64,backend_res_available:u8,backend_res:f64 |
두 검증 dataset attrs는 coordinate_system=scalar이며 location은 각각 nodal-mass-reduction,
eigenpair-verification이다. component_names는 표의 f64 fields 순서, component_unit_dimensions는
아래 해당 field 차원 순서다. Nodal counts는 nn source row에 대응하고 합이 nf/nz/n과 일치한다. Positive block 없는 node는
rcond_available0/storage0이다. Sorted_rank1..c, solver_column0-based unique, modes의 첫 N scalar와
exact pairing한다. Eigenvalue/Rayleigh는 time^-2, 나머지는 dimension1이다. Backend relative res가
zero-mode에서 정의되지 않는 경우에만 unavailable0/storage0으로 두고 의미를 명시한다.
Nonzero mode의 nonfinite res 및 모든 mandatory independent metric nonfinite는 실패다.
C개 vectors는 solve/validation 동안 유지한다. Accepted state/HDF5에는 N vectors와 전체 c의
metrics를 남긴다. N vectors로 같은 input의 K/ML를 재조립해 N개의 original-free residual/
normalization을 재현할 수 있다. 전체 c Gram의 실제 검증 evidence는 runtime/test 결과로 남기며
N vectors만으로 c Gram를 재계산했다고 주장하지 않는다. Full matrices의 영속 dump는 요구하지 않는다.
Prefix `/steps/Step-1/eigen/backend` attributes:
`runtime_version:utf8,integer_abi:utf8=LP64|ILP64,thread_count:u64=1,seed:u64`,
`enclosure_lower:f64,enclosure_upper:f64,solve_lower:f64,solve_upper:f64`,
`count_calls:u64,solve_calls:u64,final_solve_ordinal:u64,final_count:u64=c`,
`upper_search_termination:utf8`를 둔다. 마지막 값은 count-target/width-limit/no-midpoint/
optimization-budget/collision-exhausted/optional-status 중 실제 종료 이유다.
Bounds는 dimensionless B-space이며 사용자 frequency interval이 아니다. Seed는 NR 값이다.
| Dataset | Shape / fields | 의미 |
| --- | --- | --- |
| base_fpm | [128] i64 | feastinit 뒤 NR override한 실제 solve control snapshot; defaults 포함. Count는 동일 snapshot에서 C-index49만1, 매 call 재초기화 |
| calls | [Lcalls] compound ordinal:u64,kind:utf8,purpose:utf8,lower:f64,upper:f64,allocated_m0:u64,info:i64,count_available:u8,count:u64,loop_available:u8,loop:u64,epsout_available:u8,epsout:f64,outcome:utf8,decision_reason:utf8 | 실제 chronological 호출, ordinal0-based; kind=count/solve, purpose=total-enclosure/upper-guard/final-count/solve |
Count의 overwritten m0 또는 solve의 returned m을 count에 담고 allocated_m0와 구분한다.
Outcome은 accepted/optional-abandoned/retry이며 NR의 실제 결정에 대응한다. Decision_reason은
accepted 또는 status/count-mismatch/endpoint-separation 등의 결정 원인과 필요한 관측값을
round-trip decimal로 남긴다. 호출 없이 budget/width로 종료한 이유는 upper_search_termination에 둔다.
초기 enclosing 재시도에서만 a0가 확정 전 변경될 수 있고, 성공한 total enclosure 이후 하한은 고정이다. Guard 세 구간은
각각 call row다. 실패·fallback을 삭제하지 않는다. Undefined vendor output은 flag0/storage0으로
두고 읽지 않는다. 성공 count는 count_available1; 성공 solve는 loop/epsout available1이고 finite다.
Calls와 final interval/rank/c를 통해 fixed a0, certified upper/full enclosure fallback, budget,
capacity, returned count의 경로를 재구성할 수 있어야 한다. CLI live log로 이 trace를 옮기지 않는다.
Calls의 f64 component_names는 lower,upper,epsout이고 component_unit_dimensions=1,1,1,
coordinate_system=scalar,location=backend-call이다. Base_fpm은 component_names=fpm,
component_unit_dimensions=1,coordinate_system=none,location=backend-parameter다.
128개 per-call dump 대신 공통 snapshot 한 개와 kind로 실제 controls를 재현한다. 향후 call별
control 차이를 추가하려면 이 표현과 NR 계약을 함께 재검토해야 한다.
<a id="io-schema--closed-candidate-self-check"></a>
### Closed candidate self-check
현재 [self_check](../../src/fesa/io/hdf5/hdf5_self_check.cpp)는 static schema0/1 전용이므로
별도 eigen dispatch/check가 필요하다. Candidate를 닫고 read-only reopen하여 다음을 검증한다.
- Discriminator/metadata/source input bytes·step·요청수, known type/rank/shape/dimension attrs와
model source identity uniqueness/각 reference ID range, density coverage/positivity를 candidate와 대조한다.
- Model mask는0/1, prescribed values exact0, modes inventory 정확히1..N, 오름차순·cluster/classification,
frequencies 정확한 subset, vectors paired axis/finite/constraint zero와 validated candidate 값을 대조한다.
- nf=n+nz 및 nodal count 합, N<=c<=n, c rank/solver-column uniqueness, first-N scalar pairing,
independent metrics finite/NR limits, applicable/available flags를 검사한다. N/A를 pass로 계산하지 않는다.
- Backend routine/ABI/runtime/base controls, actual call ordering/count/bounds/capacity/status/budget와 final
certified interval·c 및 successful all-c validation 연결을 확인한다. Static result paths가 없어야 한다.
- Mandatory row 누락/추가/중복/nonfinite/잘못된 quantity·units·mass는 실패한다. Writer가 sorting,
averaging, 값 수정으로 candidate mismatch를 수리하지 않는다. 모든 handle close 후에만 replace한다.
Self-check는 serialization과 검증된 state의 동일성을 확인한다. 독립 physics/NR 테스트를 대신하거나
저장 metric만으로 실행되지 않은 residual/Gram 계산을 통과로 인정하지 않는다.
<a id="io-mapping"></a>
<a id="io-mapping--mitc4-eigen-내부-mappingreference-projection"></a>
## MITC4 eigen 내부 mapping·reference projection
- Feature ID: `mitc4-shell-feast-eigen2`; Owner: `io-definition-agent`; Contract revision: `r2` (외부 Value acceptance만 변경).
- 기본 보고서: [io.md](io.md#io). 수학 원본: [formulation-eigen](formulation-eigen.md).
<a id="io-mapping--내부-소유권과-identity"></a>
### 내부 소유권과 identity
| Owner | 필수 의미와 mapping |
| --- | --- |
| ParsedInput | 실제 input bytes의 기존 content identity, lexical path, keyword/parameter presence·raw 값·빈 data slot·source line |
| Domain | 전체 geometry/source topology, section→material→constant rho, 원형상 director, homogeneous BC, sole Frequency definition; 파싱 후 가능한 불변 |
| Frequency definition | source step raw/canonical name, step/Frequency/data 위치, requested N, 각 option의 explicit presence/effective value, no-op warning inventory; storage Step-1과 구별 |
| AnalysisModel | Domain보다 짧은 수명의 활성 shell/material/section/BC/procedure const non-owning view |
| DofManager | Source node×고정 6 DOF, full/free/constrained injection, stable equation IDs/scatter/sparse pattern; Node/Element에 equation ID를 저장하지 않음 |
| Assembly/procedure | 실제 consistent moment→derived lumped→개선 K, 같은 source scatter/reduction; E1~E7의 constraint-first split·whitening·FEAST·복구·all-c validation |
| Private backend | Vendor CSR/index/workspace/FEAST control·runtime·call evidence; MKL type/header를 public core에 노출하지 않음 |
| Eigen state | Candidate/accepted 분리, N개의 paired raw scalar/global vectors, source mapping, c개 validation evidence; static/Newton state를 mode count로 재사용하지 않음 |
| ResultsWriter | Validated state serialization→closed candidate self-check→final replacement; 물리값·identity 재계산/보정으로 실패를 숨기지 않음 |
Source `(instance_name,numeric source label)`과 raw spelling, internal model row, free equation
index, FEAST column, sorted rank, public mode ID는 별개다. Instance expansion/declaration의 기존
model 순서와 DOF `UX,UY,UZ,URX,URY,URZ` 순서를 유지한다. Source renumbering 비교는
geometry/connectivity/BC 대응을 함께 사용하며 숫자가 우연히 같은 internal ID를 source key로
대체하지 않는다. Repeated eigenvalues는 별개 rank이며 특정 vector 방향의 유일성을 요구하지 않는다.
Raw consistent 계산을 lumped로 덮어쓰지 않는다. Global dense mass dump는 필수 결과가 아니다.
실제 constrained free space에서만 analytic null을 제거하며 tiny positive mass를 rank cutoff로
삭제하지 않는다. `requested N`, finite dimension n, count의 overwritten m0, allocated m0,
solve returned m, validated c, public N을 각기 보존한다. 모든 c를 검증한 뒤 첫 N을 공개한다.
<a id="io-mapping--실패와-공개-lifecycle"></a>
### 실패와 공개 lifecycle
Public CLI·path·lock·log는 [현재 공통 계약 §7.1](../nonlinear-static-newton-raphson/io.md#71-public-output-names-log-and-lifecycle)을
유지한다. `fesa.exe <model.inp>`이며 output override를 추가하지 않는다. Input lexical sibling은
`<stem>_results.h5`와 `<stem>_log.txt`다. 마지막 `.inp` extension만 제거하고 basename case·
앞선 dot은 보존한다. Symlink/junction을 resolve해 결과 위치를 바꾸지 않는다.
1. Usage 검증→derived pair의 exclusive nonblocking ownership→live log open/truncate.
2. Parse/model/solve/all-c validation을 candidate에서 수행한다. 기존 accepted state/final은 유지한다.
3. Candidate state를 완성하고 log close 성공을 확인한다. 같은 directory의 exclusive-create private
HDF5 candidate를 write/flush/close/reopen/self-check하고 모든 handle을 닫는다.
4. Final replace가 성공한 뒤 준비된 state를 no-fail swap한다. 이후 allocation/validation/callback
failure를 남기지 않는다. 실패 candidate는 authoritative 결과가 아니다.
제어된 solve/validation/write/flush/close/reopen/self-check/replace 실패에서 이전 valid final과
state를 보존한다. 이전 final이 없으면 만들지 않는다. Log는 별도 live lifecycle이며 rollback하지
않는다. Eigen log에는 Newton iteration/FEAST trace를 새로 쓰지 않고 정상 log는 zero-byte다.
Backend evidence는 아래 result/Status에 둔다. Lock 실패는 기존 log/final도 건드리지 않는다.
Candidate 정리는 best effort이며 다른 run 파일을 삭제하지 않는다. Crash/power-loss 전체 원자성은
약속하지 않는다. Reference `.inp`/TXT/CSV는 read-only이며 output으로 덮어쓰지 않는다.
| Solver 실패 / exit5 | Stable code·필수 context |
| --- | --- |
| Analytic mass space·null identity 오류 | invalid-eigen-mass-space: node/DOF/n/nz·실패 identity |
| Positive block conditioning 실패 | eigen-mass-conditioning: node·metric·관측값·NR limit |
| Checked index/capacity 또는 CSR | eigen-index-overflow / invalid-eigen-csr: n,nnz,N,m0와 실패 bound |
| Workspace allocation | eigen-allocation-failed: 역할·checked byte request; N 축소 없음 |
| Fatal FEAST status | eigen-feast-failed: raw info, call kind/ordinal, interval, allocated m0 |
| Count/solve 수·monotonicity 불일치 | eigen-count-inconsistent: 실제 count history·certified interval |
| Endpoint separation | eigen-endpoint-separation: raw endpoints·nearest returned value·NR limit |
| Mandatory search budget 소진 | eigen-search-budget-exhausted: attempts·마지막 safe bracket·fallback 가능 여부 |
| Significant negative spectrum | negative-eigenvalue-spectrum: raw lambda/mu/s·rank·NR limit |
| Nonfinite/invalid conversion/frequency | invalid-eigenvalue-result: raw quantity·stage·source step |
| Pair/Gram/original-free residual/energy 실패 | eigenpair-validation-failed: metric·value·limit·solver column/rank |
선택적 upper-prefix 최적화에서 인증되지 않은 empty/count status는 count0으로 바꾸지 않는다.
Formulation E4와 NR가 허용한 safe bracket fallback은 실패를 은폐한 성공 count가 아니며
actual attempted call·종료 이유를 evidence에 남긴다. Mandatory final count/solve/validation 실패는
부분 결과로 성공하지 않는다. Count workspace의 작은/null scratch를 문헌 보장으로 가정하지 않는다.
Failure Status는 Frequency 위치와 지금까지의 chronological call context를 포함한다.
Undefined vendor outputs는 읽지 않고 unavailable로 표시한다. Allocation 실패의 부속 message
생성은 기존 best-effort diagnostic 한계를 따른다.
<a id="io-mapping--원본-txt-grammar와-prechecks"></a>
### 원본 TXT grammar와 prechecks
Input은 `reference/shellNL-eigen-meshfine/shellNL-eigen-meshfine.inp`, reference는 같은 폴더의
`shellNL-eigen-meshfine eigenvalues.txt`다. 이름 변경, TXT rewrite, CSV 변환, companion
README/metadata/version/provenance 추가를 요구하지 않는다. TXT에 step이 없으므로 지정 input의
**유일한 frequency source step Step-2**에 대응한다. 이름에서 ODB frame index를 추정하지 않는다.
LF/CRLF logical line에서 space/tab-only 행은 건너뛴다. 나머지는 아래 case-sensitive full-match다.
`ws=[ \t]*`, `ws1=[ \t]+`; id는 checked positive int64 decimal이다.
```text
number := [+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[Ee][+-]?[0-9]+)?
id := [0-9]+
row := ws 'Frame:' ws1 'Mode' ws1 id ':' ws1 'Value' ws '=' ws number
ws1 'Freq' ws '=' ws number ws1 '(cycles/time)' ws
```
Header/footer/comment/BOM/extra token/malformed row는 schema 실패다. Value는 finite binary64
full conversion이며 range error를 거부한다. Freq는 숫자 token 구조만 검사하며 수치 변환·
물리 일치·오차 판정에 사용하지 않는다. Freq에서 Value를 재구성하지 않는다. 같은 numeric mode
ID의 재등장은 duplicate이며 같은 Value의 다른 mode는 정상이다.
Tolerance 전에 다음을 순서대로 완료한다.
1. 지정 input/TXT와 HDF5 존재, eigen discriminator, source_input_identity를 현재 입력의
lexical path와 기존 byte-content identity에 대조한다. Static output·unknown eigen schema를 거부한다.
2. Input sole source step/N을 직접 읽어 HDF5 source step·requested/public count와 대응한다.
N을 TXT row 수나 검증 c에서 추론하지 않는다. 현재 양쪽 required mode inventory는 1..10이다.
3. TXT 모든 nonblank row를 parse하고 duplicate/missing/extra/nonfinite를 거부한다. Malformed-row
skip/dictionary overwrite/값 sorting으로 source mode identity를 바꾸지 않는다.
4. HDF5 mandatory dataset/type/shape, units·quantity·실제 backend·mass variant·normalization,
source/model identities, modes ID 1..N, paired vector shape, raw eigenvalue finite를 검사한다.
HDF5 순서 오류는 reader 재정렬로 숨기지 않는다. 값이 같아도 ID가 다르면 multiplicity다.
5. `(case,source_step_name,mode_id,component=Value)`로 one-to-one join하고 mode ID 순서로 출력한다.
TXT row reorder는 허용한다. `modes.eigenvalue`만 FESA scalar authority다. c개 검증 table,
frequencies, vectors 또는 static fields에서 fallback하지 않는다.
<a id="io-mapping--family와-보고"></a>
### Family와 보고
[NR reference-model](reference-model.md)이 정의하는 family는 `(case,source step,modal-frame=mode_id,quantity=eigenvalue,
dimension=time^-2,coordinates=scalar,impact=blocking)`다. Mode별 frame은 10개 singleton
family이며 하나의 storage table이라고 서로 합치지 않는다. 2026-09-10 사용자 명시 5% 승인과
[MFE2-ADR-012](ADR.md)에 따라 [공통 TOLERANCE](../TOLERANCE.md)의 승인된 한정 정책
`mitc4-eigen-first-implementation`을 이 Feature의 외부 Value 비교에 적용한다.
Reference-only S와 near-zero 분류·row branch는 유지하고 상대오차와 relative RMS의 한계를
각각 `0.05`로 적용한다. 같은 identity의 양수 singleton에서는 두 metric이 모두
`abs(FESA - reference) / abs(reference)`이므로 mode별 5% 이하(inclusive)가 통과 조건이다.
Mode 사이 평균·collapse·재정렬로 실패를 숨기지 않는다. S=0은 exact-zero FESA만 성공하며,
missing/extra/duplicate/nonfinite/schema/identity 오류는 위 prechecks에서 먼저 거부한다.
다른 공통 family의 RMS `0.01`과 전체 c개 내부 독립 검증 `1e-10`은 유지한다.
이는 승인된 첫 구현 acceptance이며 후속 정확도 개선이나 S3 해결의 evidence가 아니다.
Report는 input/reference/result identity, freshness evidence, 전체 prechecks, source key/
component/family/count/S, raw reference/FESA/error·branch·row verdict, RMS·family verdict,
blocking failure와 overall verdict를 mode 순서로 남긴다. Comparator report는
`policy_id=mitc4-eigen-first-implementation`과 `relative_rms_tolerance=0.05`를 명시해
공통 RMS 1% 정책과 구별한다. 임의 tolerance를 지정하는 generic policy argument는 노출하지 않는다.
이 report 계약 변경은 HDF5 field·shape·단위·schema version을 변경하지 않는다.
Zero-scale 미정 metric은 named state로
표시하고 NaN/Inf/floor를 넣지 않는다. 필요 시 HDF5 projection CSV는 보조 debug view일 뿐이다.
외부 eigen gate는 Value뿐이다. N개의 global vectors는 내부 constraint/residual/normalization
재검증용이며 외부 shape reference는 요구하지 않는다. 기존 static 회귀는 [requirements](requirements.md#requirements)의
retained shell/shellNL/linear-limit portfolio와 기존 source step/frame·U blocking·UR warning-only,
nonlinear reaction review-only 의미를 유지한다. 제외 네 예제는 원본·복사·cache로도 사용하지 않는다.