# MITC4 eigen authoritative HDF5 schema - Feature ID: `mitc4-shell-feast-eigen` - Owner: `io-definition-agent` - Input contract revision: `r2` - 기본 보고서: [io.md](io.md) - 수학: [E1~E8](formulation-eigen.md), [V1~V6](formulation-verification.md) - Numerical authority: [C1~C6](numerical-review-controls.md) ## O1. Container, version과 공통 규칙 공식 결과는 input lexical sibling `_results.h5`다. 기존 linear schema0와 nonlinear schema1은 각각의 [현행 static 계약](../shell-surface-pressure-load/io.md#71-version-and-filename-decision)을 유지한다. Eigen은 기존 shell model container에 새 procedure를 추가하며 discriminant는 `(schema_version=0, feature_id=mitc4-shell-feast-eigen, analysis_procedure=linear-frequency, eigen_schema_version=1)`이다. `eigen_schema_version`은 새 procedure 전용 revision이다. Static reader가 schema_version만 보고 eigen을 static으로 해석해서는 안 된다. 기존 static 파일에 새 eigen mandatory fields를 요구하거나 재작성/migration하지 않는다. 앞으로 unknown additive optional field는 무시할 수 있지만 known field의 type/의미 변경, unknown procedure 또는 eigen_schema_version은 reader의 명시적 unsupported schema 실패다. Float는 `H5T_IEEE_F64LE`, unsigned/signed integer는 명시된 `H5T_STD_U{8,64}LE`/ `H5T_STD_I64LE`, string은 variable-length UTF-8이다. Compound field의 byte offset/padding은 private이며 field name/type/array extent가 authoritative다. Shape의 `nn,ne,nmat`는 model node/element/material 수, `N`은 입력 요청, `c`는 최종 solve의 전체 검증 column 수, `Lcalls`는 모든 actual FEAST calls 수다. 모든 shape/capacity는 checked integer다. 새 numeric dataset의 required attrs는 `schema_version=0`, `eigen_schema_version=1`, `component_names`, `component_unit_dimensions`, `coordinate_system`, `location`이다. Compound에서 component attrs는 수치 quantity fields만 table의 명시 순서로 나열하고 identity/flag/counter는 schema 정의를 따른다. 새 modal result에는 추가로 `step_name=Step-1`, `source_step_name=`, `domain=mode`를 기록한다. Tokenized dimension은 아래 `mass`, `length`, `time`를 사용하며 SI label을 붙이지 않는다. 모든 mandatory physical/검증 real 값은 finite다. Optional backend diagnostic의 unavailable는 O4의 명시적 validity flag만 사용한다. NaN payload를 공개하지 않는다. ## O2. Metadata, 모델과 source 요청 `/metadata`의 아래 attributes는 mandatory다. | Attribute | Type / 값 | | --- | --- | | `schema_version`, `eigen_schema_version` | uint64 `0`, `1` | | `feature_id`, `analysis_procedure` | UTF-8 `mitc4-shell-feast-eigen`, `linear-frequency` | | `solver_version` | 실제 실행 binary의 기존 version string | | `source_input_identity` | 기존 `path=;content_identity=fnv1a64:<16 lower hex>`; parser가 실제 읽은 원본 bytes 기준 | | `unit_system_label` | `user-consistent-unspecified` | | `coordinate_convention` | `global-cartesian; shell-local=initial-reference; positive-thickness=+zeta` | | `internal_formulation` | `FESA-MITC4` | | `integration_rule`, `mass_integration_rule` | `2x2x2-gauss; mitc4-edge-midpoint-shear`, `3x3x3-gauss` | | `stabilization_rule` | `initial-physical-rotary-trace-mean-r2` | | `step_name`, `source_step_name`, `frame_indexing` | `Step-1`, raw input name(현재 Step-2), `mode-rank-one-based` | | `mass_variant`, `mass_origin`, `normalization` | `derived-lumped`, `consistent-moment-row-sum`, `mass` | | `eigensolver_backend`, `eigensolver_routine` | `MKL FEAST`, `dfeast_scsrgv` | | `backend_problem` | `scaled-whitened-lumped-with-identity-mass` | | `numerical_contract` | `mitc4-shell-feast-eigen:r2` | Source identity는 [현재 writer primitive](../../src/fesa/io/hdf5/hdf5_primitives.cpp)의 byte identity와 동일하다. SHA-256 reference audit와 FNV source identity는 다른 목적이다. Filename만으로 동일 input이라고 간주하지 않는다. Comparator는 실제 지정 input bytes의 content identity와 lexical input path를 metadata에 대조한다. | Dataset | Shape/type와 fields | Identity·단위·ordering | | --- | --- | --- | | `/model/nodes` | `[nn]` 기존 compound: `internal_node_id:u64,instance_name:utf8,source_label:utf8,coordinates:f64[3]` | Internal ID 0..nn-1, 기존 instance expansion/declaration order; coordinates length, global-cartesian | | `/model/elements` | `[ne]` 기존 shell compound: `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` | Internal ID order; source S4/S4R 구별; formulation FESA-MITC4 | | `/model/shell/materials` | `[nmat]` 기존 compound: `internal_material_id:u64,name:utf8,E:f64,nu:f64` | Declaration order; E force/length^2, nu1. 기존 field에 rho를 끼워 넣지 않음 | | `/model/shell/sections` | 기존 compound: `internal_section_id:u64,source_file:utf8,source_line:u64,source_elset:utf8,material_internal_id:u64,thickness:f64` | Declaration order, thickness length, centered-single-layer | | `/model/shell/nodal_director`, `/model/shell/nodal_frame` | `[nn,3]`, `[nn,3,3]` f64 | 기존 source node rows; D components, frame axes A/B/D×global X/Y/Z, dimension1 | | `/model/nodal_constraint_mask` | `[nn,6]` u8 | Existing DOF order UX,UY,UZ,URX,URY,URZ; free0/constrained1 | | `/model/prescribed_displacement` | `[nn,6]` f64 | 같은 DOF order, 모든 값 exact0; units length×3,radian×3 | | `/model/shell/densities` | `[density_count]` 새 compound: `material_internal_id:u64,rho:f64,source_file:utf8,source_line:u64` | Material ID ascending, rho mass/length^3, location model-material; declared density별 한 row, 활성 material 모두 존재 | | `/model/eigen/source_records` | `[record_count]` compound: `ordinal:u64,source_line:u64,keyword:utf8,physical_text:utf8` | 아래 source provenance 대상의 실제 physical line 순서, ordinal0부터 | | `/diagnostics` | `[diagnostic_count]` 기존 compound: `severity:utf8,code:utf8,file:utf8,line:u64,keyword:utf8,entity_identity:utf8,message:utf8` | 기존 SortDiagnostics 순서. 성공 파일에는 warning만 존재 | 공통 model dataset의 기존 attrs는 [linear model schema](../linear-static-mitc4-shell/io.md)와 [현재 writer](../../src/fesa/io/hdf5/hdf5_model_writer.cpp)를 따른다. Eigen-specific attrs는 새 dataset에만 필수이며 기존 static dataset type/attrs를 바꾸지 않는다. 기존 model-only midsurface_locations/section_positions를 공유 writer가 추가 저장해도 허용하나 eigen result/acceptance quantity는 아니며 eigen의 mandatory replay dataset이 아니다. `source_records` 대상은 STEP, FREQUENCY(그 count data 포함), DENSITY(data 포함), I5 no-op keyword와 그 parameter-continuation physical lines다. Comments는 포함하지 않는다. `keyword`는 canonical parent keyword이고 `physical_text`는 CR/LF를 제거한 원문이다. Frequency 선언 유무·blank slot 수·raw values를 여기서 보존한다. 물리 domain의 기준은 validated semantic fields이며 output consumer가 raw text를 다시 실행하지 않는다. `/steps/Step-1` group attrs는 아래와 같다. Canonical group명과 source name을 구분한다. | Attribute | Type / 의미 | | --- | --- | | `source_step_name`, `source_step_name_canonical` | utf8 raw name / ASCII uppercase key | | `step_source_line`, `frequency_source_line`, `frequency_data_line` | u64 실제 source1-based line | | `source_nlgeom`, `source_perturbation_present` | u8 effective NO=0 / explicit flag 유무0 또는1 | | `source_eigensolver`, `source_sim`, `source_acoustic_coupling`, `source_normalization` | utf8 effective `LANCZOS,YES,ON,MASS`; explicit/omitted는 source_records에서 구분 | | `requested_mode_count`, `returned_mode_count` | u64 N,N; table row수로 입력 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; publicly returned mode 수와 구별 | ## O3. 고유치와 modal vectors Path prefix는 `/steps/Step-1/eigen`이다. `modes`만 공개 eigenvalue row authority다. | Relative dataset | Shape/type/fields | 의미·attrs | | --- | --- | --- | | `modes` | `[N]` compound `mode_id:u64,eigenvalue:f64,classification:u8,cluster_id:u64` | Row k는 mode_id=k+1; quantity=eigenvalue, component_names=Value, component_unit_dimensions=time^-2, coordinate_system=scalar, location=modal-frame | | `frequencies` | `[Nv]` compound `mode_id:u64,frequency:f64` | 정확히 lambda>=0인 modes의 ID subset, mode ID ascending. quantity=cycle-frequency, component_names=Freq, dimension=time^-1, scalar/modal-frame; mandatory dataset이며 Nv=0도 유효 | | `vectors` | `[N,nn,6]` f64 | mode axis는 modes와 동일, node axis는 model/nodes, component_names=UX,UY,UZ,URX,URY,URZ; global-cartesian, location=nodal-modal-vector | `vectors.component_unit_dimensions`는 `mass^-1/2` 세 개와 `mass^-1/2*length^-1` 세 개다. 추가 attrs `normalization=mass`, `amplitude_unit_dimension=mass^1/2*length`, `mass_variant=derived-lumped`, `interpretation=normalized-mode-not-response-displacement`를 둔다. 각 node의 세 회전 성분은 initial global infinitesimal rotation coordinates다. Constrained component는 exact0이며 source node label을 internal/equation index로 바꾸지 않는다. 기존 `/nodal/displacement`, reaction, stress, nonlinear accepted_frames를 modal 결과로 생성하지 않는다. Full matrices/consistent matrix/modal stress를 영속 mandatory output으로 추가하지 않는다. Raw lambda의 오름차순 stable paired sort와 exact tie의 original FEAST column 순서를 따른다. Sign은 [C4](numerical-review-controls.md#c4-repeated-subspace와-결정론)대로 largest absolute scaled global component(translation/ell,rotation)의 양수, tie는 source DOF 순서다. 여기서 source DOF 순서는 model/nodes의 stable row order×정해진 component order다. Cluster는 전체 c sorted columns에서 C4의 connected rule로 1부터 매기고 첫 N개에 같은 ID를 투영한다. Cluster ID는 진단용이며 값을 평균하거나 결과 multiplicity를 줄이지 않는다. `operator_scale=s`는 O4에 저장한다. `mu=lambda/s`에서 `mu<-1e-9`는 성공 파일을 만들 수 없는 negative spectrum failure다. `abs(mu)<=1e-9`이면 classification=0(`near-zero`), 그 외는 classification=1(`positive`)이다. Raw lambda와 부호를 그대로 기록하며 ±boundary는 near-zero다. Frequency는 classification이 아닌 raw lambda 부호로 결정한다: lambda>0이면 sqrt(lambda)/(2pi), lambda==0이면 exact0, lambda<0이면 row가 없다. 따라서 small positive near-zero에도 real frequency가 있고 small negative에는 없다. Negative row의 부재 이유는 `frequencies@unavailable_rule=negative-raw-eigenvalue`로 명시한다. Frequency overflow/양수의 underflow-to-zero도 파생 결과 실패로 처리한다. Mandatory lambda 및 mu→lambda conversion은 C3의 finite/underflow 조건을 그대로 따른다. ## O4. Backend와 검증 evidence Prefix `/steps/Step-1/eigen/verification`의 attrs: | Attribute | Type / 의미 | | --- | --- | | `characteristic_length`, `operator_scale` | positive finite f64 ell[length], s[time^-2] | | `eta_gram`, `max_eta_orth` | finite f64, 전체 c의 V3 Gram와 pairwise 최대 metric; c=1이면 max_eta_orth=0 | | `eta_mz`, `eta_kz`, `eta_pz`, `null_checks_applicable` | f64×3 및 u8; nz=0이면 applicable0와 storage값0, N/A이지 수행 통과로 보고하지 않음 | | `validation_scope`, `numerical_contract` | utf8 `all-computed-c-columns`, `mitc4-shell-feast-eigen:r2` | | Dataset | Fields / shape | 의미 | | --- | --- | --- | | `verification/nodal_reduction` | `[nn]` compound `free_count:u8,null_count:u8,positive_count:u8,rcond_available:u8,rcond_inf:f64` | Source node row 대응; E2 analytic counts. Nonempty positive block에 rcond_available1, C2 cutoff 통과; 빈 block은0/0 storage. nf/nz/n과 합 일치 | | `verification/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` | sorted_rank1..c, solver_column은 원 FEAST column0-based unique; 실제 ML의 V3/V4/C3 metrics. 첫 N ranks의 lambda는 modes와 exact equal | Nodal reduction의 quantity component는 `rcond_inf`, dimension1, coordinates=scalar, location=nodal-mass-reduction이다. Eigenpair checks의 component_names는 표의 f64 fields 순서이고 dimensions는 eigenvalue와 rayleigh_quotient만 time^-2, 나머지는1이다. Coordinates=scalar, location=eigenpair-verification이며 mandatory finite 검증량과 optional backend_res의 validity를 구분한다. `eigenpair_checks`는 내부 count/검증 evidence다. c>N 진단행은 추가 공개 modal frame이 아니며 comparator는 여기서 Value를 추출하지 않는다. c개 vector 전부는 검사 동안 유지하고 accepted state에는 공개 N개 vector와 전체 c의 check evidence를 보존한다. 전체 c Gram의 runtime/독립 검증은 C17/18 evidence로 확인하며 N개 persistent vectors만으로 full-c Gram를 재검산했다고 주장하지 않는다. N개 원 residual/normalization은 model 데이터에서 K/ML를 독립 재구성하여 재현할 수 있다. Consistent/lumped 독립 oracle는 NR cases의 내부 테스트다. Backend `res`가 0-eigenvalue의 상대분모 때문에 unavailable인 경우만 backend_res_available0, backend_res storage0을 사용하고 dataset attr `unavailable_reason=zero-eigenvalue-relative-residual`를 둔다. Available 값은 finite이고, nonzero eigenvalue의 nonfinite backend diagnostic은 failure다. Storage0을 residual evidence0으로 해석하지 않는다. mandatory eta_*는 모든 경우 자체 zero branch와 함께 finite다. Prefix `/steps/Step-1/eigen/backend` attrs는 `runtime_version:utf8`(실제 MKL query), `integer_abi:utf8`(`LP64|ILP64` 실제 linked ABI), `thread_count:u64=1`, `seed:u64=0x4D495443344D4645`, `count_calls:u64`, `solve_calls:u64`, `final_count:u64=c`, `final_solve_ordinal:u64`, `selected_ranks:utf8=1..N`, `enclosure_lower:f64`, `enclosure_upper:f64`, `solve_lower:f64`, `solve_upper:f64`다. Bounds는 모두 dimensionless B-space이며 physical frequency bound가 아니다. | Relative dataset | Shape / fields | 의미 | | --- | --- | --- | | `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` | ordinal0-based 실제 call 순서; kind=count/solve, strict bounds, 실제 allocated capacity. Count의 overwritten m0와 solve의 m을 count로 구분 저장 | | `fpm` | `[Lcalls,128]` i64 | 각 call 직전 feastinit 이후의 exact parameter snapshot; vendor type을 public core에 노출하지 않음 | `purpose`는 `total-enclosure`, `upper-prefix`, `lower-prefix`, `endpoint-guard`, `final-prefix`, `final-interval`, `solve` 중 하나이며 실제 C5 단계에 대응한다. Calls의 component_names는 `lower,upper,epsout`, dimensions는 `1,1,1`, coordinates=scalar, location=backend-call이다. Fpm은 component_names=fpm, dimension1, coordinates=none, location=backend-parameter이며 128개 C-index 순서다. Calls의 unavailable output은 flag0+storage0이고 원인을 info로 해석한다. Undefined vendor output을 읽거나 garbage를 저장하지 않는다. `info=0`이면 count_available1; 성공 solve는 loop/epsout도 available1이고 epsout finite. 내부 허용 재시도의 실패 call도 삭제하지 않는다. 최종 성공과 C5 guard/prefix/total count 관계는 chronological calls/bounds로 재구성 가능해야 한다. Allocated_m0와 input N은 독립이다. Effective fpm와 seed/budget은 C5/C6와 일치해야 한다. Count-only res/epsout을 fabricated physical result로 사용하지 않는다. ## O5. Self-check와 compatibility tests Writer는 candidate를 flush/close한 뒤 read-only reopen하여 type/field/shape/required attrs, finite required values, enum/validity domains 및 다음 관계를 확인하고 검사용 handle도 닫는다. 1. Source identity·input semantic snapshot이 writer 입력과 일치한다. Node/element/material IDs, connectivity/section/material/density links가 unique/in-range이고 모든 활성 material rho>0이다. 2. Source step은 한 개이고 canonical Step-1과 raw name의 관계가 유일하다. Input N, requested N, returned N, modes/vector row수가 같다. mode IDs는 정확히1..N이다. 3. Modes가 raw 오름차순이며 classification/cluster는 C3/C4 규칙과 맞는다. Frequencies의 ID set은 lambda>=0 set과 exact equal이며 각 값은 candidate 파생값과 같고 finite다. 4. Vectors는 finite, source constraint component exact0, scalar/vector pair는 candidate와 일치한다. Selected vectors의 ML normalization/원 residual은 serializer 전 C3 gate에서 검증되었고 해당 metrics 및 read-back values를 대조한다. Serializer 자기복사를 독립 physics로 부르지 않는다. 5. `nf=n+nz`, node별 counts 합, N<=c<=n, 전체 c check rows와 solver-column uniqueness, 첫 N lambda exact equality, modal_mass>0, 모든 적용 C2/C3 metric 한계가 맞는다. 6. Calls/fpm row수·ordinals·strict endpoints·finite available diagnostics, fpm controls, counts/budgets(<=512 count, <=3 solve), final solve info0/returned m=c와 selected1..N이 맞는다. 증거 없는 성공 bool 하나로 대체하지 않는다. 7. `/diagnostics`는 기존 compound `severity,code,file,line,keyword,entity_identity,message`를 유지하며 source order warnings를 저장한다. 성공 파일에 fatal error diagnostic은 없다. 이 mandatory inventory는 reader version dispatch, round-trip, 누락/extra mode/duplicate ID, nonfinite/wrong dimension/type/mass/backend/source, close/reopen/self-check failure tests의 기준이다. Optional unknown dataset의 존재를 extra-mode로 오인하지 않는다. Static 파일은 기존 schema inventory로 계속 검증하고, eigen reader는 static 또는 unknown eigen revision을 명시적으로 거부한다.