# Results Schema ## Purpose This document defines the FESA result data model and the proposed HDF5 layout. The schema must support Phase 1 linear static results while remaining compatible with future nonlinear increments, dynamic frames, thermal fields, and history outputs. ## Source Basis - HDF5 files organize named objects in a rooted graph with groups and datasets: https://docs.hdfgroup.org/documentation/hdf5/latest/_h5_d_m__u_g.html - HDF5 datasets store multidimensional arrays and metadata needed to interpret them: https://docs.hdfgroup.org/documentation/hdf5/latest/_h5_d__u_g.html - HDF5 attributes are small metadata objects attached to groups or datasets: https://portal.hdfgroup.org/documentation/hdf5/latest/_h5_a__u_g.html ## Data Model FESA stores results with this hierarchy: ```text ResultFile └── ResultStep └── ResultFrame ├── FieldOutput └── HistoryOutput ``` Definitions: - `ResultStep`: one analysis step from input. - `ResultFrame`: one output point inside a step. For Phase 1 linear static, use frame `0`. - `FieldOutput`: node, element, integration-point, or section-point field values. - `HistoryOutput`: scalar or vector time/load history values for selected entities or global quantities. ## HDF5 Root Layout Proposed file layout: ```text / metadata/ model/ results/ steps/ Step-1/ frames/ 0/ fieldOutputs/ U/ RF/ S/ E/ SF/ historyOutputs/ referenceComparison/ ``` ## Root Attributes Attach these attributes to `/`: | Attribute | Type | Required | Meaning | |---|---|---|---| | `schema_name` | string | yes | `FESA_RESULTS` | | `schema_version` | int64 | yes | Start at `1` | | `solver_name` | string | yes | `FESA` | | `solver_version` | string | no | Build or release version | | `created_utc` | string | no | ISO 8601 timestamp | | `input_file` | string | no | Original input path | | `input_sha256` | string | no | Input file hash | | `unit_system_note` | string | no | User-provided self-consistent unit note | | `dof_convention` | string | yes | `UX,UY,UZ,RX,RY,RZ` | | `sign_convention` | string | yes | `Abaqus-compatible` | | `precision` | string | yes for Phase 1 in-memory result model | `double` | | `index_type` | string | yes for Phase 1 in-memory result model | `int64` | ## `/metadata` Recommended datasets or attributes: ```text /metadata/sourceFiles /metadata/analysisType /metadata/precision /metadata/indexType /metadata/conventions ``` Rules: - Use attributes for small scalar metadata. - Use datasets for variable-length tables or arrays. - Store `precision = double`. - Store `index_type = int64`. ## `/model` The result file may contain enough model data to interpret outputs: ```text /model/nodes/ids /model/nodes/coordinates /model/elements/ids /model/elements/types /model/elements/connectivity /model/sets/nodeSets/ /model/sets/elementSets/ /model/dofs/components ``` Rules: - Store ids as int64. - Store coordinates as double. - Store connectivity as int64. - Phase 1 element type string should be `MITC4`. - If complete model mirroring is deferred, store at least node ids, element ids, and output entity labels required to interpret results. ## Field Output Layout Each field output group should follow this pattern: ```text /results/steps/Step-1/frames/0/fieldOutputs/U/ values entity_ids component_labels ``` Attributes: | Attribute | Type | Meaning | |---|---|---| | `position` | string | `NODAL`, `ELEMENT`, `INTEGRATION_POINT`, or `SECTION_POINT` | | `entity_type` | string | `node`, `element`, etc. | | `component_count` | int64 | Number of components | | `basis` | string | `GLOBAL`, `LOCAL_SHELL`, or another documented basis | | `description` | string | Human-readable field description | Datasets: - `entity_ids`: shape `[n_entities]`, int64. - `values`: shape `[n_entities, n_components]`, double. - `component_labels`: shape `[n_components]`, string. ## Phase 1 Field Outputs ### `U` Nodal displacement and rotation. ```text position = NODAL entity_type = node basis = GLOBAL component_labels = ["UX", "UY", "UZ", "RX", "RY", "RZ"] ``` ### `RF` Nodal reaction force and moment. ```text position = NODAL entity_type = node basis = GLOBAL component_labels = ["RFX", "RFY", "RFZ", "RMX", "RMY", "RMZ"] ``` `RF` is computed from the full system: ```text RF = K_full * U_full - F_full ``` ### `S` Shell stress output when implemented. ```text position = INTEGRATION_POINT or SECTION_POINT entity_type = element basis = LOCAL_SHELL component_labels = ["S11", "S22", "S33", "S12", "S13", "S23"] ``` ### `E` Shell strain output when implemented. ```text position = INTEGRATION_POINT or SECTION_POINT entity_type = element basis = LOCAL_SHELL component_labels = ["E11", "E22", "E33", "E12", "E13", "E23"] ``` ### `SF` Shell section force and moment resultants when implemented. ```text position = ELEMENT or INTEGRATION_POINT entity_type = element basis = LOCAL_SHELL component_labels = ["SF1", "SF2", "SF12", "SM1", "SM2", "SM12", "SS13", "SS23"] ``` The final component labels should be cross-checked with the accepted Abaqus reference output variables. ## Phase 1 Mandatory Outputs The first complete linear static solver path must write: - root metadata attributes: `schema_name`, `schema_version`, `solver_name`, `dof_convention`, `sign_convention`, `precision`, and `index_type`. - `/model/nodes/ids` - `/model/nodes/coordinates` - `/model/elements/ids` - `/model/elements/types` - `/model/elements/connectivity` - `/results/steps//frames/0/fieldOutputs/U` - `/results/steps//frames/0/fieldOutputs/RF` - frame attributes for `frame_id`, `step_time`, `total_time`, `increment`, `iteration`, and `converged`. Stress, strain, and section force outputs may remain optional until the MITC4 displacement/reaction benchmarks are stable. ## Frame Attributes Attach these attributes to each frame group: | Attribute | Type | Meaning | |---|---|---| | `frame_id` | int64 | Zero-based frame id | | `step_time` | double | Time/load parameter within step | | `total_time` | double | Accumulated analysis time | | `increment` | int64 | Increment number | | `iteration` | int64 | Newton iteration or `0` for linear static | | `converged` | int | `1` true, `0` false | | `description` | string | Optional note | For Phase 1 linear static: - `frame_id = 0` - `step_time = 1.0` - `total_time = 1.0` - `increment = 1` - `iteration = 0` - `converged = 1` ## History Outputs History output layout: ```text /results/steps/Step-1/historyOutputs// x values component_labels ``` Attributes: - `x_label`: usually `step_time`, `total_time`, `load_factor`, or `frame_id`. - `entity_type`: `global`, `node`, `element`, `set`. - `entity_id` or `entity_name`. Phase 1 recommended history outputs: - total external load by component. - total reaction by component. - maximum displacement magnitude. - linear solver status. ## Reference Comparison Group Optional comparison output: ```text /referenceComparison/cases// expected actual abs_error rel_error pass ``` Attributes: - `reference_source` - `reference_solver` - `reference_solver_version` - `comparison_status` - `comparison_timestamp_utc` ## CSV Reference Input Mapping FESA solver outputs remain HDF5-oriented, but early verification may compare HDF5 field outputs against stored Abaqus CSV artifacts under `references/`. Initial accepted displacement reference naming: ```text references/.inp references/_displacements.csv ``` `*_displacements.csv` maps to: ```text /results/steps//frames//fieldOutputs/U ``` Required CSV columns: | CSV Column | HDF5 Field Component | |---|---| | `Node Label` | `entity_ids` | | `U-U1` | `UX` | | `U-U2` | `UY` | | `U-U3` | `UZ` | | `UR-UR1` | `RX` | | `UR-UR2` | `RY` | | `UR-UR3` | `RZ` | Rules: - CSV files are reference inputs for tests, not the primary FESA result storage format. - The comparator must preserve node-label matching and must not rely on row order alone. - The comparator must require FESA `U` component labels `UX`, `UY`, `UZ`, `RX`, `RY`, `RZ` with `position = NODAL`, `entity_type = node`, and `basis = GLOBAL`. - Duplicate FESA output node ids, duplicate CSV node labels, missing FESA nodes, missing CSV columns, and nonnumeric CSV values are comparison failures. - The comparison report may be stored under `/referenceComparison`. Initial accepted reaction reference naming: ```text references/_reactionforces.csv references/_reactions.csv ``` `*_reactionforces.csv` and `*_reactions.csv` map to: ```text /results/steps//frames//fieldOutputs/RF ``` Required CSV columns: | CSV Column | HDF5 Field Component | |---|---| | `Node Label` | `entity_ids` | | `RF-RF1` | `RFX` | | `RF-RF2` | `RFY` | | `RF-RF3` | `RFZ` | | `RM-RM1` | `RMX` | | `RM-RM2` | `RMY` | | `RM-RM3` | `RMZ` | Rules: - The comparator must require FESA `RF` component labels `RFX`, `RFY`, `RFZ`, `RMX`, `RMY`, `RMZ` with `position = NODAL`, `entity_type = node`, and `basis = GLOBAL`. - The FESA `RF` field must be the full-vector reaction field recovered as `K_full * U_full - F_full`. - Duplicate FESA output node ids, duplicate CSV node labels, missing FESA nodes, missing CSV columns, and nonnumeric CSV values are comparison failures. - Stress CSV or section force CSV formats must be documented before automated use. ## Naming Rules - Use stable ASCII group and dataset names. - Use original input labels as attributes when names contain spaces or nonportable characters. - Normalize step names to HDF5-safe names while preserving original names in attributes. - Never depend on HDF5 object iteration order for semantic ordering. Store explicit ids and labels. ## Compression and Chunking Phase 1 may write contiguous datasets for simplicity. For large models: - Use chunked datasets for large field outputs. - Consider compression only when it does not materially slow common read paths. - Keep metadata small enough for attributes. ## Open Decisions - Exact mandatory stress/strain/resultant output variables in Phase 1. - Whether result files always mirror the model or only store output entity ids. - Whether reference comparison results are stored in solver output files or separate reports. - Exact naming and column contracts for stress, strain, and section-force Abaqus CSV reference files.