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>}locationmust be one of:Vertex,EdgeCenter,FaceCenter,CellCenter.base_name,zone_name,location,timeare 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 underproblem_definition/problem_infos.yaml(keysinput_featuresandoutput_features).