Feature identifiers

Feature identifiers are a concise, unambiguous way to point to any feature in PLAID. They replace legacy name-only APIs (now deprecated) and make it possible to uniquely address features across time steps, bases, zones and locations.

  • A feature is one of: scalar, field, nodes.

  • A FeatureIdentifier is a small dictionary that encodes the feature type and, when relevant, its context (e.g., base, zone, location, time).

Why this matters:

  • Names alone can be ambiguous (e.g., a field called “pressure” may exist at several locations, times, or zones). Identifiers remove ambiguity and make operations deterministic and hashable.

  • Identifiers are stable keys, so they can be used in sets, dicts, and sorting. See the underlying implementation in FeatureIdentifier.

  • Discussion and design notes are available in the project discussion: Feature identifier concept.

Structure

FeatureIdentifier is a dict[str, str | float] with a mandatory type key. Depending on the feature type, other keys are required or optional:

  • scalar: {"type": "scalar", "name": <str>}

  • field: {"type": "field", "name": <str>, "base_name": <str>, "zone_name": <str>, "location": <str>, "time": <float>}

    • location must be one of: Vertex, EdgeCenter, FaceCenter, CellCenter.

    • base_name, zone_name, location, time are optional if default value mechanics apply (see Default values mechanics).

  • nodes: {"type": "nodes", "base_name": <str>, "zone_name": <str>, "time": <float>}

Notes:

  • Time must be a float when present.

  • FeatureIdentifier is hashable and orderable (internally sorted), enabling deduplication and stable sorting.

Examples

Minimal identifiers:

from plaid.types import FeatureIdentifier

fid_scalar = FeatureIdentifier({"type": "scalar", "name": "Re"})

fid_field = FeatureIdentifier({
    "type": "field",
    "name": "pressure",
    "base_name": "Base",
    "zone_name": "Zone",
    "location": "Vertex",
    "time": 0.0,
})

fid_nodes = FeatureIdentifier({
    "type": "nodes",
    "base_name": "Base",
    "zone_name": "Zone",
    "time": 0.0,
})

Using identifiers with Sample

The Sample container exposes helpers to retrieve, update, extract and merge features via identifiers.

from plaid.containers.sample import Sample

sample = Sample(path)

# 1) Retrieve one feature
u = sample.get_feature_from_identifier(fid_field)

# 2) Retrieve several features
features = sample.get_features_from_identifiers([fid_scalar, fid_field])

# 3) Update one or several features
updated = sample.update_features_from_identifier(fid_scalar, 0.5)            # scalar
updated = sample.update_features_from_identifier([fid_field], [u_new])       # field

# 4) Extract a sub-sample containing only selected features
sub = sample.extract_sample_from_identifier([fid_field, fid_nodes])

# 5) Merge all features from another sample
merged = sample.merge_features(sub)

Sample also offers string identifiers for convenience:

u = sample.get_feature_from_string_identifier(
    "field::pressure/Base/Zone/Vertex/0.0"
)

Re = sample.get_feature_from_string_identifier("scalar::Re")

String format is: <type>::<detail1>/<detail2>/.... The order is fixed per type. If time is provided, it is parsed as float.

Using identifiers with ProblemDefinition

ProblemDefinition stores learning inputs/outputs as lists of FeatureIdentifiers and offers utilities to add and filter them.

from plaid.problem_definition import ProblemDefinition

problem = ProblemDefinition()

problem.add_in_feature_identifier(fid_scalar)
problem.add_in_features_identifiers([fid_field])

problem.add_out_feature_identifier(fid_nodes)

ins  = problem.get_in_features_identifiers()
outs = problem.get_out_features_identifiers()

# Filtering among registered identifiers
subset_in  = problem.filter_in_features_identifiers([fid_scalar, fid_nodes])
subset_out = problem.filter_out_features_identifiers([fid_nodes])

Legacy name-based methods (e.g., add_input_scalars_names) are deprecated; prefer the identifier-based ones.

Best practices

  • Always include enough context to disambiguate a feature. For fields/nodes on multiple bases/zones/times, set all relevant keys.

  • Use get_all_features_identifiers() to introspect what identifiers exist in a sample.

  • Use sets to deduplicate identifiers safely: set(list_of_identifiers).

  • When authoring problem definitions on disk, _save_to_dir_() persists identifiers under problem_definition/problem_infos.yaml (keys input_features and output_features).

See also