# Linear Static 3D Euler Beam I/O Definition ## Metadata - feature_id: `linear-static-3d-euler-beam` - source_requirement: `docs/requirements/linear-static-3d-euler-beam.md` - source_formulation: `docs/formulations/3d-isoparametric-euler-beam-formulation.md` - source_numerical_review: `docs/numerical-reviews/linear-static-3d-euler-beam-review.md` - source_research: `docs/research/linear-static-3d-euler-beam-research.md` - approved_design: `docs/superpowers/specs/2026-08-08-linear-static-3d-euler-beam-design.md` - status: `ready-for-implementation-planning` - owner_agent: `io-definition-agent` - date: `2026-08-09` - authoritative_output: `results.h5` - reference_baseline: `reference/cantilever beam/` at source commit `2b34d0b` 이 문서는 승인된 V0의 semantic I/O contract만 정의한다. Parser, HDF5 writer, comparison tooling의 C++ API나 구현 구조는 정의하지 않으며 Abaqus full compatibility를 주장하지 않는다. ## Abaqus Input Scope - input_format: Abaqus input file (`.inp`) - supported_analysis: 입력 파일당 하나의 linear-static step과 `TYPE=B33` 2절점 3D Euler–Bernoulli beam - ordinary_unit_system: user-consistent; `.inp`만 보고 SI를 추론하지 않음 - compatibility_disclaimer: 아래 표의 위치, parameter, data grammar만 지원함 `supported`는 해당 행의 정확한 subset만 의미한다. `warning no-op`은 syntax를 소비하고 구조화된 warning을 기록하지만 Domain, AnalysisModel 또는 mandatory HDF5 output을 변경하지 않는다는 뜻이다. | keyword | status and allowed location | required parameters and data grammar | purpose and semantic mapping | unsupported behavior | | --- | --- | --- | --- | --- | | `*HEADING` | supported; optional top-level first keyword | parameters 없음; 다음 keyword 전까지 0개 이상의 text data line | 원문 heading을 source metadata로 보존 | 중첩 위치 또는 parameter는 input error | | `*PART` / `*END PART` | supported; top-level model block | `NAME=` 필수; `*END PART` data 없음 | part-local node, element, set, section 정의 범위 | 닫히지 않음, 중첩 part, duplicate part name은 error | | `*NODE` | supported; part 내부 | parameter 없음; 각 row `node_label, x, y, z` | positive integer source label과 finite global Cartesian 좌표 | 다른 arity, duplicate label, nonfinite 좌표는 error | | `*ELEMENT` | supported; part 내부 | `TYPE=B33` 필수; 각 row `element_label, node_1, node_2` | 2절점 straight Euler beam definition | `TYPE=B31`은 `unsupported-element-formulation`; 다른 type/arity와 dangling connectivity는 error | | `*NSET` | supported; part 또는 assembly 내부 | `NSET=` 필수; optional `GENERATE`; assembly에서는 `INSTANCE=` 필수; explicit row는 하나 이상의 node label, generate row는 `first,last,increment` | part-local 또는 single-instance assembly node set | mixed-instance set, zero/negative increment, duplicate name, dangling member는 error | | `*ELSET` | supported; part 또는 assembly 내부 | `ELSET=` 필수; optional `GENERATE`; assembly에서는 `INSTANCE=` 필수; explicit/generate grammar는 `*NSET`과 동일 | part-local 또는 single-instance assembly element set | mixed-instance set, invalid range, duplicate name, dangling member는 error | | `*MATERIAL` | supported; top-level model data | `NAME=` 필수; data 없음 | 뒤따르는 단일 isotropic `*ELASTIC`을 소유 | duplicate name, missing/duplicate elasticity, 다른 material model은 error | | `*ELASTIC` | supported; 현재 material 내부 | parameter 없음; 정확히 한 row `E, nu` | homogeneous isotropic elasticity; `G=E/(2(1+nu))` | extra field/row, nonfinite value 또는 `E<=0`/`G<=0`은 model error | | `*BEAM GENERAL SECTION` | supported; part 내부 | `ELSET=`, `MATERIAL=`, `SECTION=GENERAL` 필수; 첫 row `A,I11,I12,I22,J`, 둘째 row `n1x,n1y,n1z` | section assignment, properties와 first section axis | 다른 `SECTION`, missing/dangling reference, `I12!=0`, invalid property/guide vector는 error | | `*SECTION POINTS` | supported; 바로 앞 general beam section에 종속 | parameter 없음; 하나 이상의 row `x1,x2` | 입력 순서의 stress recovery point; `x1=y`, `x2=z` | 선행 section 없음, 다른 arity, nonfinite 또는 duplicate point는 error | | `*ASSEMBLY` / `*END ASSEMBLY` | supported; 정확히 하나의 top-level assembly block | `NAME=` 필수; `*END ASSEMBLY` data 없음 | identity instance와 assembly set 범위 | nested/duplicate assembly는 `unsupported-nested-assembly` | | `*INSTANCE` / `*END INSTANCE` | supported; assembly 내부 | `NAME=`, `PART=` 필수; 두 keyword 사이 data 없음 | named identity copy; 같은 part의 여러 identity instance 허용 | translation/rotation data는 `unsupported-instance-transform`; duplicate/dangling instance는 error | | `*BOUNDARY` | supported; top-level model data 또는 sole step 내부 | parameter 없음; 각 row `target, first_dof, last_dof[, value]`; omitted value는 `0` | sole step의 prescribed displacement | invalid arity/range, unresolved target, conflicting expanded node/DOF value는 error | | `*CLOAD` | supported; sole step 내부 | parameter 없음; 각 row `target, dof, magnitude` | sole step의 global nodal concentrated load | invalid arity/DOF, nonfinite magnitude 또는 unresolved target은 error | | `*STEP` / `*END STEP` | supported; exactly one top-level history block | optional `NAME`; optional `NLGEOM=NO`; `*END STEP` data 없음 | canonical result identity `(Step-1, frame 0)` | second step은 `unsupported-multiple-step`; `NLGEOM=YES`는 `unsupported-nonlinear-geometry` | | `*STATIC` | supported; sole step 내부, exactly once | parameter 없음; exactly one row `initial_increment, time_period, minimum_increment, maximum_increment` | 승인 legacy row를 읽되 V0는 하나의 linear solve와 frame 0만 생성 | missing/extra/nonfinite/nonpositive field 또는 다른 procedure는 error | | `*PREPRINT` | warning no-op; top-level | 모든 parameter를 보존 후 무시; data 없음 | legacy generator control 수용 | semantic object를 만들지 않음 | | `*RESTART` | warning no-op; sole step | 모든 parameter를 보존 후 무시; data 없음 | legacy restart request 수용 | restart state를 만들지 않음 | | `*TRANSVERSE SHEAR STIFFNESS` | warning no-op; beam section context | keyword와 소속 data line을 보존 후 무시 | B33 legacy deck 수용 | Euler formulation/property를 변경하지 않음 | | `*OUTPUT, FIELD` | warning no-op; sole step | output parameter와 subordinate data를 보존 후 무시 | legacy field request root 수용 | mandatory FESA output을 선택·억제하지 않음 | | `*OUTPUT, HISTORY` | warning no-op; sole step | output parameter와 subordinate data를 보존 후 무시 | legacy history request root 수용 | history result를 생성하지 않음 | | `*NODE OUTPUT` | warning no-op; active output request 내부 | 모든 parameter와 다음 keyword 전 variable data를 무시 | legacy nodal variable request 수용 | requested variables로 HDF5 schema를 변경하지 않음 | | `*ELEMENT OUTPUT` | warning no-op; active output request 내부 | 모든 parameter와 다음 keyword 전 variable data를 무시 | legacy element variable request 수용 | requested variables로 HDF5 schema를 변경하지 않음 | | `*CONTACT OUTPUT` | warning no-op; active output request 내부 | 모든 parameter와 다음 keyword 전 variable data를 무시 | legacy contact variable request 수용 | contact model/result를 만들지 않음 | `*DLOAD`, `*INCLUDE` 및 표에 없는 model-affecting keyword는 no-op 대상이 아니며 `unsupported-keyword` input error다. 특히 formulation-only constant local line-load kernel은 parser나 Domain의 distributed-load 지원을 뜻하지 않는다. ### Nesting grammar ```text input-file := heading? part+ assembly material+ model-boundary* step EOF part := *PART node-block+ element-block+ (nset | elset)* general-section+ section-points* *END PART assembly := *ASSEMBLY instance+ assembly-set* *END ASSEMBLY instance := *INSTANCE *END INSTANCE step := *STEP *STATIC step-boundary* cload* allowed-no-op* *END STEP ``` Top-level material과 model boundary는 step 전에만 나타난다. Part는 assembly 전에 모두 닫혀야 하고 assembly 안에는 instance와 assembly-level set만 허용한다. Instance 안의 node/element 재정의, nested assembly, dependent/independent mesh option은 지원하지 않는다. Sole step의 source `NAME` spelling은 metadata에 보존하지만 V0 HDF5와 comparison의 canonical identity는 항상 `Step-1`, `frame 0`이다. ## Syntax Policy - keyword line은 첫 non-whitespace character가 `*`이고 `**`가 아니어야 한다. - comment line은 `**`로 시작하며 의미 모델에서는 제외하되 file과 1-based line 위치를 유지한다. - keyword, parameter name, enumerated parameter value와 named-reference lookup은 ASCII case-insensitive다. Part, instance, material, set의 원래 spelling과 numeric label lexeme는 외부 identity를 위해 그대로 보존한다. - keyword line은 comma-separated `KEY[=VALUE]` fields다. Data line도 comma-separated이며 field 양끝 whitespace를 제거한다. Required empty field, trailing empty optional value, 잘못된 numeric token은 input error다. - Keyword/data continuation, quoted/multiline name, include file 및 line continuation은 V0에서 지원하지 않는다. 한 logical keyword/data row는 한 physical line에 완결되어야 한다. - Node/element labels와 explicit set members는 positive base-10 integer다. Internal index로 바꾸어도 raw source label text를 잃지 않는다. - 모든 numeric value는 finite `double`이어야 한다. `NaN`, positive/negative infinity는 syntax/semantic validation에서 거부한다. - 각 parsed keyword, parameter, data row와 semantic entity는 `file`, 1-based `line`, raw `keyword`, raw source label을 추적할 수 있어야 한다. - Output-request subordinate variable data는 직전의 allowlisted output keyword부터 다음 keyword까지에만 warning no-op이다. 그 밖의 예상되지 않은 data line은 input error다. ### Duplicate and dangling-reference policy - Part, assembly, instance, material, set 이름은 각 semantic scope의 case-insensitive key로 unique해야 한다. Node/element numeric source label은 part scope에서 unique해야 한다. - 같은 part의 여러 identity instance는 duplicate가 아니다. 각 copy는 instance name으로 구분되는 별도 source identity를 가진다. - Element connectivity, set membership, instance `PART`, section `ELSET`/`MATERIAL`, assembly set `INSTANCE`, boundary/load target은 Domain finalization 전에 모두 resolve되어야 한다. - Duplicate definition은 `duplicate-entity`; unresolved reference는 `unresolved-reference`로 진단하고 partial Domain을 해석에 넘기지 않는다. ## Model Data Mapping ### Stable source identity and instances Part-local node, element, set은 instance expansion 뒤 다음 identity를 갖는다. ```text SourceEntityId { instance_name, source_label } ``` `instance_name`과 `source_label`은 원래 spelling을 보존한다. Case-insensitive lookup key와 표시용 raw text는 별개다. Stable Domain internal index는 input declaration order, instance declaration order, part-local entity declaration order의 결정적 순서로 부여하며 thread count나 hash iteration order에 의존하지 않는다. 같은 part의 두 identity instance는 source label이 같아도 instance name이 다르므로 서로 merge하지 않는다. Assembly-level `*NSET`/`*ELSET`의 `INSTANCE`는 정확히 하나의 identity instance를 지정하고 data의 label을 그 instance가 참조하는 part-local source label로 resolve한다. 따라서 assembly set member도 `(instance_name, source_label)`로 결정된다. V0는 한 set에 여러 instance의 member를 섞는 grammar를 제공하지 않는다. ### Nodes, elements, sets, material, and section - Node는 global Cartesian coordinate `[X,Y,Z]`, stable internal node ID와 source identity를 가진다. - B33 element는 ordered connectivity `[node_1,node_2]`, stable internal element ID, source identity, general-section assignment를 가진다. Connectivity order가 local tangent `t=(X2-X1)/L`의 방향을 정한다. - Explicit set은 data order, generated set은 inclusive `first,last,increment` expansion order를 보존한다. Membership은 internal ID에 연결되지만 source identity로 round-trip 가능해야 한다. - Material은 정확한 입력 `E,nu`를 보존하고 `G=E/(2(1+nu))`를 유도한다. - General section 첫 row는 정확히 `[A,I11,I12,I22,J]`다. V0는 `I12`의 exact numeric zero만 허용하고 `Iy=I11`, `Iz=I22`로 매핑한다. - Guide vector `a=n1`을 tangent에 직교 투영·정규화하여 local `y`로, `t x n1`을 local `z`로 둔다. `(x,y,z)`는 right-handed다. ### Model validation 모든 값은 finite여야 하고 다음 조건을 element calculation 전에 검사한다. ```text E > 0 G = E / (2 * (1 + nu)) > 0 A > 0, Iy > 0, Iz > 0, J > 0 L > 1e-12 * max(1, norm(X1), norm(X2)) norm(a_perp) > 1e-12 * max(1, norm(a)) ``` `a_perp = a - dot(a,t)*t`다. 길이 조건 실패는 `invalid-beam-length`, zero guide vector나 projection 조건 실패는 `invalid-beam-guide-vector`, nonpositive property는 `invalid-beam-property`, `I12!=0`은 `unsupported-coupled-section` model diagnostic이다. Fallback axis, absolute-value 보정 또는 B31 재해석은 허용하지 않는다. ## History Data Mapping V0는 하나의 history object, canonical `Step-1`만 만든다. `*STATIC`의 네 legacy field는 각각 `initial_increment`, `time_period`, `minimum_increment`, `maximum_increment`로 보존한다. 모두 finite positive여야 하고 `minimum_increment <= maximum_increment`여야 한다. 이 값들은 입력 호환성과 provenance를 위한 값이며 V0가 increment loop나 여러 frame을 생성하게 하지 않는다. 결과는 항상 `(Step-1, frame 0)`이다. `*BOUNDARY`의 target은 node source label 또는 node set이다. Assembly set은 그 `INSTANCE`를 포함해 source node identity로 확장한다. `first_dof <= last_dof`이고 두 값은 1..6이어야 한다. 생략된 value는 exact zero다. Model-level boundary와 step-level boundary는 sole step에 활성화되며 같은 expanded node/DOF에 서로 다른 value가 생기면 input error다. `*CLOAD` target resolution은 boundary와 같고 각 row는 해당 target의 모든 node에 global component load를 적용한다. 같은 node/DOF로 resolve되는 여러 load row는 input order로 결정적으로 합산한다. | DOF | nodal kinematic component | boundary unit dimension | CLOAD component | load unit dimension | | ---: | --- | --- | --- | --- | | 1 | `UX` | length | `FX` | force | | 2 | `UY` | length | `FY` | force | | 3 | `UZ` | length | `FZ` | force | | 4 | `URX` | radian | `MX` | force x length | | 5 | `URY` | radian | `MY` | force x length | | 6 | `URZ` | radian | `MZ` | force x length | Abaqus output request는 history activation이나 output selection으로 매핑하지 않는다. Allowlisted request의 존재 여부와 무관하게 mandatory HDF5 dataset은 모두 생성된다. ## Internal Model Contract - Domain은 nodes, B33 elements, sets, material, section, boundary, load와 sole static step의 완전한 semantic definition을 소유하고 mapping 이후 effectively immutable하다. - AnalysisModel은 sole step에 활성인 Domain IDs/references만 제공하며 Domain object를 복사하지 않는다. - Node/element는 equation ID를 소유하지 않는다. DOF numbering과 constrained/free mapping은 이 I/O 계약 밖의 DofManager 책임이다. - Boundary와 load는 expansion 전 target identity와 expansion 후 stable node identity를 모두 추적할 수 있어야 한다. - Result identity는 source identity와 stable internal identity를 모두 보유해야 하며 parser의 raw keyword string을 solver physics object로 사용하지 않는다. - Endpoint equilibrium action, endpoint section resultant, Gauss generalized result, assembled residual reaction은 서로 다른 quantity/location identity다. ## Output HDF5 Schema Authoritative output은 하나의 HDF5 file `results.h5`, schema version `0`이다. 아래의 ``은 V0에서 literal `Step-1`이다. 모든 string은 UTF-8, 모든 물리 실수는 IEEE-754 float64, stable internal ID는 uint64다. ### Metadata and model identity `/metadata`는 group이며 다음 scalar attributes를 반드시 가진다. | attribute | required value or meaning | | --- | --- | | `schema_version` | `0` | | `feature_id` | `linear-static-3d-euler-beam` | | `solver_version` | 실행 solver version string | | `source_input_identity` | normalized input path와 content identity를 추적 가능한 string | | `unit_system_label` | ordinary run은 `user-consistent-unspecified` | | `coordinate_convention` | `global-cartesian; beam-local=(t,n1,t-cross-n1)` | | `element_formulation` | `B33-3D-Euler-Bernoulli` | | `step_name` | `Step-1` | | `frame_index` | integer `0` | 승인 legacy comparison은 `.inp`에서 SI를 추론하지 않는다. Reference Model Contract와 verification report가 model `cantilever-beam-b33`에 외부 `SI` provenance를 적용한다. | dataset path | shape and dtype | row identity / fields | required attributes and ordering | | --- | --- | --- | --- | | `/model/nodes` | `[node_count]` compound | `internal_node_id:uint64`, `instance_name:utf8`, `source_label:utf8`, `coordinates:float64[3]` | internal node ID ascending; `coordinate_system=global-cartesian`, `units_label=length` | | `/model/elements` | `[element_count]` compound | `internal_element_id:uint64`, `instance_name:utf8`, `source_label:utf8`, `node_internal_ids:uint64[2]`, `local_axes:float64[3,3]` | internal element ID ascending; axes row order `[x,y,z]`, `formulation=B33-3D-Euler-Bernoulli` | ### Step/frame result datasets | quantity | exact dataset path | shape | row identity and component order | units/coordinates/location | | --- | --- | --- | --- | --- | | displacement | `/steps//frames/0/nodal/displacement` | `[node_count,6]` float64 | `/model/nodes` row; `[UX,UY,UZ,URX,URY,URZ]` | `[length,length,length,radian,radian,radian]`; global; nodal | | reaction | `/steps//frames/0/nodal/reaction` | `[node_count,6]` float64 | `/model/nodes` row; `[RF1,RF2,RF3,RM1,RM2,RM3]` | `[force,force,force,force*length,force*length,force*length]`; global; nodal | | equilibrium end action | `/steps//frames/0/element/end_force_local` | `[element_count,2,6]` float64 | element row, endpoint `[-1,+1]`; `[FX,FY,FZ,MX,MY,MZ]` | `[force x3, force*length x3]`; beam local; endpoint outward action | | endpoint section resultant | `/steps//frames/0/element/section_resultant` | `[element_count,2,4]` float64 | element row, endpoint `[-1,+1]`; `[N,T,My,Mz]` | `[force,force*length,force*length,force*length]`; beam local; positive-local-x section cut | | generalized strain | `/steps//frames/0/element/generalized_strain` | `[element_count,2,4]` float64 | element row, Gauss point `[-1/sqrt(3),+1/sqrt(3)]`; `[epsilon0,kappa_x,kappa_y,kappa_z]` | `[1,1/length,1/length,1/length]`; beam local; integration point | | generalized resultant | `/steps//frames/0/element/generalized_resultant` | `[element_count,2,4]` float64 | element row, same Gauss points; `[N,T,My,Mz]` | `[force,force*length,force*length,force*length]`; beam local; integration point | | axial stress | `/steps//frames/0/element/stress_s11` | `[stress_row_count]` compound | `internal_element_id`, `gauss_point_index`, `section_point_index`, `x1`, `x2`, `source`, `S11` | element/Gauss/section order; `units_label=force/length^2`, beam local section point | | diagnostics | `/diagnostics` | `[diagnostic_count]` compound | `severity`, `code`, `file`, `line`, `keyword`, `entity_identity`, `message` | deterministic diagnostic order; empty dataset is required when count is zero | 각 numeric result dataset은 `component_names`, `component_unit_dimensions`, `coordinate_system`, `location`, `step_name=Step-1`, `frame_index=0` attributes를 가진다. Endpoint axis order는 `xi=-1` then `xi=+1`, Gauss axis order는 negative then positive다. Stress row는 internal element ID, Gauss index 1..2, input section-point index 순으로 정렬한다. 입력 section point가 없으면 `(x1,x2)=(0,0)`, index `0`, `source=fesa-default`인 centroid row 하나를 각 Gauss point에 쓴다. 입력 point는 index 1부터 원래 data order를 따른다. Reaction은 모든 node와 여섯 component에 존재하며 free DOF의 residual도 포함한다. Transverse/torsional shear stress dataset이나 averaged nodal stress는 만들지 않는다. `S11`은 mandatory HDF5 output이지만 Abaqus reference comparison은 명시적 N/A다. ### Atomic finalization Writer는 requested final path와 같은 directory에 temporary HDF5를 만들고 모든 mandatory group/dataset/attribute 작성, flush, close, schema self-check가 성공한 뒤에만 final path를 원자적으로 교체한다. 실패하면 temporary artifact는 비권위적이며 기존 final file이 있다면 그대로 보존한다. 실패한 새 run은 불완전한 `results.h5`를 남기지 않고 exit code `6`과 HDF5 diagnostic을 반환한다. ## FESA HDF5 to Reference CSV Comparison Schema Authoritative 비교는 위 HDF5 rows와 read-only Abaqus CSV rows 사이에서만 수행한다. HDF5에서 추출한 deterministic CSV view는 debugging/review 보조물이며 solver output이나 reference artifact가 아니다. ### Approved legacy artifact precheck Comparison 전에 다음 exact files가 존재하고 변경되지 않았음을 확인한다. - `reference/cantilever beam/cantilever beam.inp` - `reference/cantilever beam/cantilever beam displacements.csv` - `reference/cantilever beam/cantilever beam reactions.csv` - `reference/cantilever beam/cantilever beam elemental forces.csv` Input은 `TYPE=B33`이어야 하고 trim한 CSV header는 아래 mapping 표와 정확히 일치해야 한다. 각 projected row key는 unique하고 모든 numeric value는 finite여야 한다. 파일 missing/type mismatch는 `needs-reference-artifacts`, header/value/identity mismatch는 `schema-mismatch`이며 comparison은 시작하지 않는다. `metadata.json` 부재는 프로젝트 전역 정책에 따라 허용되고, `README.md`는 이 legacy bundle에서 N/A다. 파일을 rename, rewrite, zero-clamp 또는 보정하지 않는다. ### Header and component normalization | legacy file/header | canonical quantity/component | FESA HDF5 source | | --- | --- | --- | | `U-U1`, `U-U2`, `U-U3` | displacement `UX`, `UY`, `UZ` | `nodal/displacement` columns 0..2 | | `UR-UR1`, `UR-UR2`, `UR-UR3` | displacement `URX`, `URY`, `URZ` | `nodal/displacement` columns 3..5 | | `RF-RF1`, `RF-RF2`, `RF-RF3` | reaction `RF1`, `RF2`, `RF3` | `nodal/reaction` columns 0..2 | | `RM-RM1`, `RM-RM2`, `RM-RM3` | reaction `RM1`, `RM2`, `RM3` | `nodal/reaction` columns 3..5 | | `SF-SF1` | section resultant `N` | `element/section_resultant` component `N` | | `SM-SM1` | section resultant `My` | `element/section_resultant` component `My` | | `SM-SM2` | section resultant `Mz` | `element/section_resultant` component `Mz` | | `SM-SM3` | section resultant `T` | `element/section_resultant` component `T` | General Abaqus beam component meaning and FESA local mapping은 다음과 같다. | Abaqus component | equilibrium end-action component | section-resultant component | | --- | --- | --- | | `SF1` | `FX` | `N` | | `SF3` | `FY` | N/A in `[N,T,My,Mz]` | | `SF2` | `FZ` | N/A in `[N,T,My,Mz]` | | `SM3` | `MX` | `T` | | `SM1` | `MY` | `My` | | `SM2` | `MZ` | `Mz` | 이 general mapping은 component axis의 의미다. Outward equilibrium end action과 positive-local-x-face section resultant의 sign identity를 합치지 않는다. 승인 legacy CSV는 `SF1/SM1/SM2/SM3`만 제공하고 section-cut result와 비교하므로 `SF2`/`SF3` row를 0으로 만들거나 reference row로 합성하지 않는다. HDF5의 transverse end action은 unit/analytical test와 physics sanity 대상이다. ### Frame, instance, and node-station normalization - Legacy `Frame` value `Increment 1: Step Time = 1.000`은 canonical `(Step-1, frame 0)`으로 변환한다. 승인 bundle의 다른 increment/time string은 `schema-mismatch`다. - `Part Instance Name`은 HDF5 `/model/nodes` 또는 `/model/elements`의 exact preserved `instance_name`과 case-insensitive lookup 후 raw identity 일치 여부를 확인한다. - `Node Label`은 instance 안의 preserved source node label로 resolve한다. Displacement와 reaction key는 `(model_id,Step-1,0,instance_name,source_node_label,quantity,component)`다. - Elemental-force CSV는 element label이 없으므로 HDF5 endpoint section resultants를 source node station으로 project한다. Boundary station은 유일한 incident endpoint를 쓴다. - Interior station collapse는 정확히 두 incident B33 endpoints, 동일 section/local-axis orientation, 일관된 chain connectivity, 해당 node의 concentrated force/moment가 없는 경우에만 허용한다. 두 positive-face section-cut 값이 아래 승인 component tolerance 안에서 먼저 일치해야 한다. - Interior 값이 일치하면 stable internal element ID가 작은 endpoint를 deterministic representative로 선택한다. 두 값을 평균하지 않는다. 불일치는 `tolerance-failure`다. - Reversed connectivity, local-axis discontinuity, section jump, branch 또는 loaded interior station은 element label 없는 legacy schema로 collapse할 수 없다. 이 approved bundle 밖에서는 element-aware reference row가 필요하며 legacy projection은 `schema-mismatch`로 중단한다. Projected canonical comparison row는 다음 fields를 가진다. ```text model_id, step_name, frame_index, instance_name, source_node_label, quantity, component, value, unit_dimension, coordinate_system, hdf5_dataset_path ``` Stable ordering은 quantity inventory order, instance declaration order, stable source node order, component order다. Approved model ID는 `cantilever-beam-b33`; nodal quantities는 global Cartesian, section resultants는 beam local이다. ### Row-set precheck and tolerance 먼저 양쪽을 legacy contract가 실제 제공하는 quantity/component projection으로 제한한다. 그 projection 안에서는 missing, extra, duplicate, nonfinite, schema-mismatched 또는 identity-mismatched row가 하나라도 있으면 tolerance 계산 전에 실패한다. HDF5에만 mandatory인 `SF2/SF3` 대응 end action, generalized results와 `S11`은 계약상 비교 대상이 아니므로 extra reference row가 아니다. Matched rows는 같은 `model_id`, step/frame, quantity, component로 group한다. ```text reference_scale = max(abs(reference_value_i)) row_tolerance = absolute_floor + 1e-6 * reference_scale row_pass = abs(fesa_value_i - reference_value_i) <= row_tolerance ``` 즉 exact policy는 `absolute_floor + 1e-6 * reference_scale`이다. `reference_scale`은 read-only Abaqus values만 사용하고 FESA 값으로 조정하지 않는다. Scale이 zero면 relative term은 zero다. Reference value나 작은 residue를 zero-clamp하지 않고 모든 row를 판정한다. | approved SI component class | absolute floor | | --- | ---: | | displacement and rotation | `1e-9` | | force and moment | `1e-3` | Interior endpoint consistency도 해당 CSV quantity/component의 same Abaqus-only scale과 floor를 사용한다. Verification report는 모든 row pass/fail과 quantity별 max absolute error, component-scale normalized error, RMS error, norm error, worst row/component를 기록한다. 이 reference tolerance는 analytical/formulation tolerance를 대체하지 않는다. ## CLI and Diagnostics Contract ```powershell fesa.exe --output ``` `--output`을 생략하면 현재 작업 directory의 `results.h5`가 final path다. Input path는 정확히 하나이며 unknown option, missing argument, repeated `--output`은 usage error다. | exit code | meaning | | ---: | --- | | `0` | success; authoritative HDF5 finalization complete | | `2` | CLI usage error | | `3` | input syntax or semantic mapping error, including unsupported keyword/formulation/wrapper | | `4` | model validation error, including geometry, section or property invalidity | | `5` | factorization or substitution error | | `6` | HDF5 write, validation or atomic finalization error | 각 stderr diagnostic record는 exact field order `severity`, `code`, `file`, `line`, `keyword`, `entity_identity`, `message`를 사용한다. Source-backed diagnostics는 normalized file path와 1-based line을 가지며, source가 없는 solver/output error는 빈 source field를 명시한다. 출력 순서는 source file declaration order, line, entity stable internal ID, diagnostic code의 tuple로 결정하고 같은 tuple에서는 discovery order를 보존한다. Warning은 성공 run에서도 `/diagnostics`에 기록되며 error가 있으면 해당 exit class를 반환한다. ## Validation Rules | validation area | required pass condition | failure class | | --- | --- | --- | | keyword inventory | supported 또는 exact warning no-op allowlist에 속함 | input, exit 3 | | nesting/cardinality | closed part/assembly/instance/step; one assembly and one static step | input, exit 3 | | source identity | duplicate 없음; all references resolve; multi-instance identity unique | input, exit 3 | | B33 semantics | only `TYPE=B33`; two distinct connected nodes | input/model, exit 3 or 4 | | section/material | exact data arity/mapping, `I12=0`, all required positive properties | model, exit 4 | | geometry/local axes | approved length/projection thresholds and right-handed axes | model, exit 4 | | history | DOF 1..6, resolved targets, finite values, sole canonical frame | input, exit 3 | | HDF5 | all exact paths, shapes, attributes, identities and finite result values | output, exit 6 | | legacy artifacts | exact four files, B33, exact headers, unique finite rows | reference precheck | | comparison | exact projected row-set, endpoint eligibility/consistency, approved tolerance | reference verification | No parser/HDF5 implementation, reference artifact mutation, Abaqus execution, physics pass 또는 release approval을 이 status가 의미하지 않는다. ## Open Issues and Downstream Handoff ### Resolved numerical-review handoff `NR-O03-STATION-NORMALIZATION`은 approved legacy bundle에 대해 unloaded, consistently oriented two-endpoint interior station만 collapse하고, tolerance check 후 smaller stable element ID를 선택하는 규칙으로 구체화했다. Reversed/branched/loaded/jumped station은 element-aware reference가 없는 한 비교하지 않는다. ### Reference Model Agent - Exact legacy inventory, generator `Abaqus/CAE Learning Edition 2024`, source commit `2b34d0b`, external SI provenance와 stress comparison N/A를 계약에 고정한다. - 추가 reference model은 canonical filenames와 metadata를 사용하며 이 legacy file을 변경하지 않는다. ### Implementation Planning Agent - Keyword별 positive/negative grammar, source location, duplicates/dangling references, B31/transform/nested/multiple-step/NLGEOM diagnostics를 TDD cases로 만든다. - Exact HDF5 path/shape/component/identity, mandatory-output independence와 atomic failure를 검증한다. - C++ API는 이 semantic contract에서 파생하되 여기에 소급해 API 설계를 추가하지 않는다. ### Reference Verification Agent - Artifact precheck 뒤 HDF5-to-legacy projection, node-station eligibility, row-set equality, component-scale comparison 순서를 유지한다. - Missing/extra/nonfinite row를 무시하거나 `SF2/SF3`/stress reference row를 합성하지 않는다.