Skip to content

Advanced case grouping

The common path covers most layouts with name=, key=, and shorthand roles ("mesh", required(...), optional(...)). Use this page when you need finer control over case identity, membership, or admission rules.

Import advanced authoring types from miura.nexus.case_grouping.advanced. API reference: Case grouping (advanced).

When this page applies

You need… Parameter / type Why
Case identity with a platform semantic id or unit different from the path key coordinates= + CaseCoordinate, and primary_key= Downstream selection and CAP identity should use a stable semantic id (and optionally units), not only the path placeholder name
Multi-axis identity (e.g. geometry + angle of attack) coordinates= / primary_key= listing each axis One case is uniquely identified by several dimensions together
Membership role name different from the resource name Full MemberRole Resource keys stay file-oriented; role names stay how the case uses the file
A content selector or shareability on a role Full MemberRole (plus selectors such as CsvRowSelector) Shorthand roles only bind name to resource; selectors pick rows or shared members
An admission rule that lists exactly which roles must be present composition= + CompositionRule You decide which roles are mandatory for a valid case when mixing helpers and full roles

If none of these apply, stay on explicit grouping controls / content-linked cases. Path-shaped multi-root layouts with shareability or Folder(...) resources can also use CaseStructure.compose; content selectors and joins stay on CaseGrouping.content_join.

Explicit coordinates and composition

Use case: path key is case_id, but admitted cases should carry a stable semantic id (openfoam_case_id) for later selection.

Parameter Role in this example
name= Spec id for this grouping (versioned label you pass to plan / CaseSet)
resources= Path templates and components that locate member files
coordinates= Declares each identity axis: path component name, semantic id, value kind
primary_key= Which coordinate names form the case key
roles= Full MemberRoles: role name, resource_ref, join axis, cardinality
composition= Which roles must all be present for a case to admit
from miura.nexus.case_grouping import CaseGrouping, MemberRole
from miura.nexus.case_grouping.advanced import CaseCoordinate, CompositionRule
from miura.sdk.resources import ResourceMap
from miura.nexus.collection.structured_schema import Cardinality, File, Number, Ref

case_id = Ref("case_id")
resources = ResourceMap(
    components={"case_id": Number(min_digits=6, max_digits=6)},
    resources={
        "control_dict": File("case_" + case_id + "/system/controlDict"),
        "velocity": File("case_" + case_id + "/0/U"),
        "pressure": File("case_" + case_id + "/0/p"),
    },
)

case_grouping = CaseGrouping.role_based(
    name="openfoam_case_roles_v1",
    resources=resources,
    coordinates=[CaseCoordinate("case_id", "openfoam_case_id", "string")],
    primary_key=["case_id"],
    roles=[
        MemberRole("control_dict", "control_dict", "case_id", Cardinality.exactly(1)),
        MemberRole("velocity", "velocity", "case_id", Cardinality.exactly(1)),
        MemberRole("pressure", "pressure", "case_id", Cardinality.exactly(1)),
    ],
    composition=CompositionRule.require_all(
        ["control_dict", "velocity", "pressure"]
    ),
)

Full MemberRole in a mixed list

Use case: most roles match resource names, but one resource must appear under a different membership role (or carry a selector). You still want a clear rule for which roles make a complete case.

Parameter Role in this example
key= Shared join axis when you are not spelling out coordinates=
roles= Mix of shorthand ("control_dict", one_or_more(...)) and full MemberRole
composition= Lists every role that must be present — including the explicit MemberRole
from miura.nexus.case_grouping import CaseGrouping, MemberRole, one_or_more, optional
from miura.nexus.case_grouping.advanced import CompositionRule
from miura.sdk.resources import ResourceMap
from miura.nexus.collection.structured_schema import Cardinality, File, Number, Ref

case_id = Ref("case_id")
resources = ResourceMap(
    components={"case_id": Number(min_digits=6, max_digits=6)},
    resources={
        "control_dict": File("case_" + case_id + "/system/controlDict"),
        "velocity": File("case_" + case_id + "/0/U"),
        "pressure": File("case_" + case_id + "/0/p"),
        "force_coeffs": File("case_" + case_id + "/forces.csv"),
    },
)

case_grouping = CaseGrouping.role_based(
    name="mixed_roles_v1",
    resources=resources,
    key="case_id",
    roles=[
        "control_dict",
        one_or_more("velocity"),
        optional("pressure"),
        MemberRole(
            name="forces",
            resource_ref="force_coeffs",
            join_on="case_id",
            cardinality=Cardinality.exactly(1),
        ),
    ],
    composition=CompositionRule.require_all(
        ["control_dict", "velocity", "forces"]
    ),
)

Content join with explicit roles

Use case: same CSV join as the content-linked cases path, but case identity or membership needs the same controls as above (semantic coordinates, renamed roles, or a row selector).

Parameter Role in this example
name= Spec id for this content-join grouping
coordinates= Identity axis for the join key (semantic id / kind)
join_key= Column / axis that links members into one case
evidence= How to read the join key from content (here a CSV column)
roles= Full MemberRoles for mesh and parameters
composition= Both roles required for a valid design case
from miura.nexus.case_grouping import CaseGrouping, MemberRole
from miura.nexus.case_grouping.advanced import CaseCoordinate, CompositionRule, CsvRowSelector
from miura.sdk.resources import ResourceMap
from miura.nexus.collection.structured_schema import AnyString, Cardinality, File, Ref

design_id = Ref("design_id")
resources = ResourceMap(
    components={"design_id": AnyString()},
    resources={
        "mesh": File("meshes/" + design_id + ".stl"),
        "parameters": File("tables/design_params.csv"),
    },
)

case_grouping = CaseGrouping.content_join(
    name="design_csv_join_v1",
    resources=resources,
    coordinates=[CaseCoordinate("design_id", "design_id", "string")],
    join_key="design_id",
    evidence=[
        CsvRowSelector(resource_ref="parameters", key_column="design_id"),
    ],
    roles=[
        MemberRole("mesh", "mesh", "design_id", Cardinality.exactly(1)),
        MemberRole("parameters", "parameters", "design_id", Cardinality.exactly(1)),
    ],
    composition=CompositionRule.require_all(["mesh", "parameters"]),
)