F5 File Format Specification

0. Introduction and Scope

This document is Part 2 of the F5 extension specification series. It is a tentative proposal — the constructs described here are theoretically derived from the established F5 model and are internally consistent with the core specification (F5Layout.md) and Part 1 (F5_Extension_1_NamedTypes.md), but none of this has been implemented. It is offered as a worked-out design proposal to guide future implementation, not as a description of existing behaviour.

This document introduces:

This document depends on Part 1 (F5_Extension_1_NamedTypes.md) for: - ChartDomain and chart object structure (Part 1 §3) - Connectivity type member naming conventions: the simplex scheme {ii, ij, jj} (Part 1 §5.4) - The ChartDomain attribute on committed types (Part 1 §6.3)

This extension is strictly additive. No core spec rules are modified.

Conformance levels:

A validator implementing only Layer 0 and Layer 1 MUST correctly ignore the dart attributes and Fields described in Layer 2.


1. Background

1.1 Combinatorial maps

Combinatorial maps (Edmonds 1960, extended by Lienhardt to n-dimensional quasi-manifolds) represent topological structures via a set of darts D and permutation operations (involutions α_i and permutation σ) encoding adjacency between oriented incidence elements. The half-edge (2D) and half-face (3D) data structures are specialisations.

In F5, darts are not modeled as a new Skeleton type — they would be structurally indistinguishable from vertex Skeletons (both are IndexDepth=0), which defeats the identity-based semantics of the core spec. Instead, the entry space of an existing Positions field within a relative Representation serves as the dart enumeration. Each row of the Positions array is one dart. Permutation operations are stored as sibling Fields in the same Representation group.

This design keeps the simple triangle mesh case simple: a user who only needs connectivity uses only the Layer 0 types defined in Part 1, without any dart structure. The dart layer is purely additive.

1.2 Relationship to the simplex naming scheme

Part 1 §5.4 defines the simplex naming scheme: triangle connectivity is stored as struct { int32 ii, ij, jj } under the triangular ChartDomain. This document builds directly on that: the three entries of each triangle row — ii, ij, jj — are the three darts of that triangle. The dart index space has 3 × N_triangles entries. The naming convention of the member names directly maps to the dart structure: ii is the dart at the first barycentric position, ij at the second, jj at the third.


2. The combinatorial ChartDomain

The permutation Fields of a combinatorial map are integer arrays indexing into the dart entry space. They use a dedicated ChartDomain to signal their nature to readers:

/Charts/combinatorial/
    SinglePrecision/
        Point          <- int32 scalar
                         Attribute ChartDomain: "combinatorial"
                         Attribute F5::DartSource: (present; value advisory)
    DoublePrecision/
        Point          <- int64 scalar (for meshes with > 2^31 darts)
    Point              <- soft link -> SinglePrecision/Point

The F5::DartSource attribute on the committed combinatorial/Point type is a presence signal: its existence on the type (not its value) marks any Field using this type as a dart permutation Field. At read time, the source Positions field is identified as the sibling Field in the same Representation group whose committed type carries F5::DartPermutations.

This design avoids storing file-specific paths or object references in a globally shared committed type.


3. Neighborhood Representations (Layer 1)

3.1 Definition and motivation

Neighborhood information — which vertices are adjacent to a given vertex, which cells share a face — is an intrinsic topological property of a Skeleton. It belongs neither in a coordinate Representation (it is not geometry) nor in a relative Representation pointing to a different Skeleton (it is not a cross-topology relation). The correct location is a self-referential Representation: a Representation subgroup of a Skeleton whose name matches the Skeleton’s own name.

Per core spec §6, a subgroup of a Skeleton is a Representation if its name matches either a Chart name (coordinate) or another Skeleton name (relative). The Skeleton’s own name is structurally valid as the target. This requires no new mechanism.

3.2 Structure

Vertices/
  Vertices/            <- self-referential relative Representation
    Positions          <- integer array; each row lists neighbor vertex indices

Vertices/Vertices/Positions expresses: for each vertex, the set of neighboring vertices. The Positions field indexes into the Vertices Skeleton’s own index space.

For fixed-valence neighborhoods (e.g. all vertices have exactly 6 neighbors on a regular grid), Positions uses a named simplex-like type — a struct with a fixed number of integer members. For variable-valence neighborhoods (general unstructured meshes), the field is fragmented (core spec §8.2) with one fragment per vertex, or uses a separated compound with an offset array.

3.3 Applicability to all Skeletons

Self-referential Representations are valid for any Skeleton:

Faces/
  Faces/               <- face-face adjacency (shared edge)
    Positions          <- type: struct { int32 ii, ij, jj }  (3 face neighbors)
                         using the triangular simplex naming from Part 1 §5.4

Cells/
  Cells/               <- cell-cell adjacency
    Positions          <- neighbor cell indices (type depends on cell valence)

3.4 Reader requirement

Readers that encounter a self-referential Representation MUST NOT treat it as an error. It is structurally valid per core spec §6. Readers that do not implement neighborhood queries MAY ignore these Representations.


4. Combinatorial Map Dart Fields (Layer 2 — Tentative Proposal)

4.1 Dart attributes on the connectivity ChartDomain type

Two attributes are placed on the committed Point type of the connectivity ChartDomain (e.g. /Charts/triangular/SinglePrecision/Point) to declare that the entry space of any Positions field using this type constitutes a dart enumeration:

F5::DartPermutations

  • Placement: attribute on the connectivity ChartDomain’s committed type
  • Type: variable-length HDF5 string array
  • Value: ordered list [α₀, α₁, ..., α_{n-1}, σ] giving the names of sibling Fields in the same Representation group that carry each permutation operation, where n = F5::DartDimension
  • Status: absent = no dart semantics; presence activates Layer 2

Example on /Charts/triangular/SinglePrecision/Point:

F5::DartPermutations = ["alpha0", "sigma"]

F5::DartDimension

  • Placement: attribute on the same committed type as F5::DartPermutations
  • Type: int scalar
  • Value: n, the dimension of the combinatorial map (2 for surfaces, 3 for volumes)
  • Constraint: MUST be present if F5::DartPermutations is present; its absence alongside F5::DartPermutations is a fatal validation error

4.2 Permutation Field structure

Each Field listed in F5::DartPermutations:

  • Is a sibling of Positions in the same Representation group
  • Uses a committed type from the combinatorial ChartDomain (§2)
  • Has total length = arity(Positions_type) × N_elements(Positions) — one integer per dart
  • Contains the dart index of the image dart under that permutation
  • SHOULD be precision-matched to the Positions field

The involutions α_i satisfy α_i[α_i[d]] = d for all darts d (self-inverse property). The permutation σ encodes the vertex orbit structure.

4.3 Entry-space indexing — the only genuinely new semantic concept

The core spec defines Fields as indexing into a Skeleton’s index space. Permutation Fields introduce something new: indexing into the entry space of another Field — specifically into the individual integer entries of a Positions array (each row = one dart), not into Skeleton elements.

This is the only semantic extension genuinely beyond the core spec. A Field F indexes into the entry space of Field G when:

  1. F and G are siblings in the same Representation group
  2. F’s committed type carries F5::DartSource (from the combinatorial ChartDomain)
  3. The values in F are non-negative integers less than arity(G) × size(G)

Entry-space indexing MUST NOT be used outside the combinatorial map context without a further extension document.

4.4 Complete structural example: 2-map on a triangle mesh

The dart layer adds two attributes to the triangular/Point type and two sibling Fields to the Representation. Everything else is unchanged from the Layer 0 layout.

/Charts/
    triangular/
        SinglePrecision/
            Point          struct { int32 ii, ij, jj }
                             Attribute ChartDomain:         "triangular"
                             Attribute F5::DartPermutations: ["alpha0", "sigma"]
                             Attribute F5::DartDimension:    2
        DoublePrecision/
            Point          struct { int64 ii, ij, jj }
        Point              soft link -> SinglePrecision/Point
    combinatorial/
        SinglePrecision/
            Point          int32 scalar
                             Attribute ChartDomain: "combinatorial"
                             Attribute F5::DartSource: 1    (presence is the signal)
        DoublePrecision/
            Point          int64 scalar
        Point              soft link -> SinglePrecision/Point

/t=0/MySurface/
    Points/
        StandardCartesianChart3D/
            Positions      type: Cartesian3D/SinglePrecision/Point
                           {float x,y,z} per vertex

    Faces/
        Points/
            Positions      type: triangular/SinglePrecision/Point
                           {int32 ii,ij,jj} per face
                           Dart attributes inherited from committed type
            alpha0         type: combinatorial/SinglePrecision/Point
                           int32 array, length 3 x N_faces
                           alpha0[dart] = index of twin dart (edge involution α₀)
            sigma          type: combinatorial/SinglePrecision/Point
                           int32 array, length 3 x N_faces
                           sigma[dart]  = next dart in vertex orbit (permutation σ)

A Layer-0 reader opens Positions, reads the triangle connectivity, ignores unknown attributes on the committed type. A Layer-2 reader finds F5::DartPermutations on the type, loads alpha0 and sigma, and has a fully functional half-edge structure.

4.5 Half-edge correspondence

For an orientable surface mesh this 2-map is the classical half-edge data structure:

Half-edge concept F5 dart representation
Half-edge / dart Entry i of Positions (one row = one dart)
twin(h) alpha0[i] — the other dart of the same edge
next(h) sigma[i] — next dart in the vertex orbit
prev(h) sigma[sigma[i]] for triangles (derivable)
Vertex of h Positions[i] — the target vertex index
Face of h floor(i / 3) for a triangle mesh

prev is derivable and need not be stored. If stored for performance, it SHOULD be added to F5::DartPermutations after σ.

4.6 3-map for tetrahedral meshes

For a tetrahedral mesh (Lienhardt’s 3-map / half-face structure):

/Charts/tetrahedral/
    SinglePrecision/
        Point          struct { int32 iii, iij, ijj, jjj }
                         Attribute ChartDomain:          "tetrahedral"
                         Attribute F5::DartPermutations: ["alpha0", "alpha1", "sigma"]
                         Attribute F5::DartDimension:    3

4 × N_tetrahedra darts. Each dart is one (tet, vertex-slot) pair. The permutations:

  • alpha0: face involution — the dart on the other side of the same face
  • alpha1: edge involution — the next dart around the same edge
  • sigma: vertex permutation — the next dart in the vertex orbit

4.7 n-map generalisation

For arbitrary dimension n: a Positions field using an (n+1)-simplex type has n+1 members, yielding (n+1) × N_cells darts. F5::DartDimension = n. F5::DartPermutations lists n involutions and one permutation. The F5 hierarchy places no constraint on IndexDepth, so higher-dimensional combinatorial maps are accommodated without extension.

4.8 Mixed-element meshes

For mixed-element meshes (triangles and quads, tetrahedra and hexahedra):

  • The Positions field is fragmented (core spec §8.2), one fragment per element type
  • Each fragment uses its own named type from its respective connectivity ChartDomain
  • F5::DartPermutations is placed on each connectivity ChartDomain type independently
  • The dart index space spans all fragments in offset order (core spec §9)
  • Permutation fields MUST be consistent across fragment boundaries
  • Readers MUST concatenate fragments in offset order before applying permutation operations

5. Validation Rules (Layer 2)

A validator implementing Layer 2 SHOULD check:

Violations of length consistency or involution consistency are fatal errors for the affected Representation.


6. Interaction with Core Spec Features

6.1 Time-dependence

Permutation Fields follow the same time-dependence rules as any other Field (core spec §10). A combinatorial map whose topology is time-independent MUST use symbolic links for permutation fields across timeslices. A CFL-governed AMR structure where the fine mesh topology changes every sub-step would use new dataset objects at each timeslice for the affected permutation fields, while coarser levels remain linked.

6.2 Fragmented permutation fields

Permutation fields MAY be fragmented with the same structure as their Positions field. Fragment offsets are into the dart index space. All fragments of a permutation field MUST be consistent with all fragments of the corresponding Positions field.

6.3 Multi-file merging

When merging Grids across files (core spec §4.3), dart indices in merged permutation fields MUST be updated to reflect the concatenated dart index space of the merged Positions fragments.


7. Open Implementation Questions

The following questions are identified for resolution during implementation:

Validation cost of involution consistency. Checking α_i[α_i[d]] = d for all darts requires a full pass over the permutation array. For very large meshes this may be prohibitive as a default check. Validators MAY implement this as an optional “deep validation” mode rather than a mandatory per-read check.

F5::DartPermutations on DoublePrecision types. The attributes are placed on the SinglePrecision committed type in the examples. Should the identical attributes be placed on all precision variants of a connectivity ChartDomain, or is it sufficient to place them on the default (soft-linked) type? The current proposal leaves this open; an implementation SHOULD place them on all precision variants for consistency.

ChartDomain for combinatorial across files. When merging files (core spec §4.3), the combinatorial ChartDomain MUST be identical across files. A validator SHOULD verify that the F5::DartSource signal is present on all merged type instances.

Dart indices after mesh topology changes. For a time-evolving mesh where the connectivity changes at some timeslice T, the permutation field is a new dataset at T (time-dependent per core spec §10). The dart indices in the new permutation field must be consistent with the new Positions field at the same timeslice, not with the previous one. Writers MUST ensure this consistency; it cannot be automatically enforced.


8. Summary of Proposed New Elements

All elements in this section are tentative proposals. None are implemented.

Element Layer Status
Self-referential Neighborhood Rep (§3) 1 Valid now per core spec
combinatorial ChartDomain (§2) 2 Proposed
F5::DartPermutations attribute (§4.1) 2 Proposed
F5::DartDimension attribute (§4.1) 2 Proposed
F5::DartSource attribute (§2) 2 Proposed
Entry-space indexing concept (§4.3) 2 Proposed — only new semantic

No new hierarchy levels are introduced. No core spec rules are modified. The F5:: attribute prefix is reserved for normative extension attributes (core spec §6, Part 1 §6.3). Application attributes MUST NOT use this prefix.


9. Literature

The fiber-bundle grounding of the F5 model used throughout this document:


End of Part 2 (Tentative Proposal)