Groups and Plate Selectors
Groups represent flat, ordered sets of container references.
They are used for batch transfer, environment targets, and batch readout. They are foundation syntax for addressing many containers, not a separate workflow family.
Explicit Groups
let g = group([well_a, well_b, well_c]);Groups are one-level structures. Nested groups are not supported.
Plate Selectors
Declare a plate, then select its wells to create an ordered group:
let reaction_plate = plate(label = "ReactionPlate", format = PlateFormat.WELL_96);
let row = reaction_plate[A1:A12];
let block = reaction_plate[A1:D6];
let mix = reaction_plate[A1:A6, C1:C6];The plate identifies one carrier; the selected group identifies its individual wells. Separate declarations remain distinct even if their labels match. Aliases, protocol arguments and returned plate values preserve the carrier's identity. A declaration can omit layout information until a selector needs it; selecting wells requires a valid, fully determined layout.
Selector order is stable. Ranges are row-major, and unions follow region order. For whole-plate tapping, pass the declared plate itself; passing a well group requests independent actions on its members.
Batch Transfer
A scalar source and quantity can broadcast to a group target:
row << [stock:5uL];Ordered mapping uses series(...):
let three_wells = group([well_a, well_b, well_c]);
three_wells << [series(stock, [1uL, 2uL, 3uL])];The number of series values must match the group size.
Batch Environment
with env(thermal = 37C, duration = 10min) {
hold(row);
}Batch Readout
let obs = img(sample = row, quantity = fluorescence);Batch readout returns a data_group_ref aligned with input group order.
Selector Rules
- Duplicate wells are rejected after selector normalization.
- Out-of-range coordinates are rejected.
- A selector belongs to one carrier.
- Plate selectors are a way to construct well groups; they are not a separate runtime object kind.
