> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.conductorquantum.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.conductorquantum.com/_mcp/server.

## Groups: Organizing Pads for Isolated Testing

Groups let you define logical subsets of your device for independent characterization and control. This is essential for devices with multiple quantum dots, charge sensors, or when you want to test different regions separately.

### Creating Groups

Define groups by specifying which pads belong to each group:

```yaml
name: "Sample Device"

gates:
  # Control region gates (G1-G5)
  G1: {type: BARRIER, control_channel: 3, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G2: {type: PLUNGER, control_channel: 4, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G3: {type: BARRIER, control_channel: 5, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G4: {type: PLUNGER, control_channel: 6, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G5: {type: BARRIER, control_channel: 7, v_lower_bound: -3.0, v_upper_bound: 3.0}

  # Sensor region gates (G6-G8)
  G6: {type: BARRIER, control_channel: 8, v_lower_bound: -1.5, v_upper_bound: 1.5}
  G7: {type: PLUNGER, control_channel: 9, v_lower_bound: -1.5, v_upper_bound: 1.5}
  G8: {type: BARRIER, control_channel: 10, v_lower_bound: -1.0, v_upper_bound: 1.0}

  # Shared reservoir gates
  G9: {type: RESERVOIR, control_channel: 11, v_lower_bound: -3.0, v_upper_bound: 3.0}
  G10: {type: RESERVOIR, control_channel: 12, v_lower_bound: -3.0, v_upper_bound: 3.0}

contacts:
  IN: {type: SOURCE, control_channel: 1, measure_channel: 1, v_lower_bound: -3.0, v_upper_bound: 3.0}
  OUT: {type: DRAIN, control_channel: 2, measure_channel: 2, v_lower_bound: -3.0, v_upper_bound: 3.0}

gpios:
  MUX1: {type: OUTPUT, control_channel: 30, v_lower_bound: 0.0, v_upper_bound: 5.0}
  MUX2: {type: OUTPUT, control_channel: 31, v_lower_bound: 0.0, v_upper_bound: 5.0}
  SENSOR_ENABLE: {type: OUTPUT, control_channel: 32, v_lower_bound: 0.0, v_upper_bound: 5.0}

groups:
  control:
    name: "Control DUT"
    gates: [G1, G2, G3, G4, G5, G9, G10]
    contacts: [IN, OUT]
    gpios: [MUX1]

  sensor:
    name: "Charge Sensor"
    gates: [G6, G7, G8, G9, G10]
    contacts: [IN, OUT]
    gpios: [MUX2, SENSOR_ENABLE]
```

Use groups in Python to create filtered device views:

```python
from stanza.utils import device_from_yaml

device = device_from_yaml("device.yaml")

# Filter to control region
control_device = device.filter_by_group("control")
print(control_device.gates)     # ['G1', 'G2', 'G3', 'G4', 'G5', 'G9', 'G10']
print(control_device.contacts)  # ['IN', 'OUT']
print(control_device.gpios)     # ['MUX1']

# Filter to sensor region
sensor_device = device.filter_by_group("sensor")
print(sensor_device.gates)      # ['G6', 'G7', 'G8', 'G9', 'G10']
print(sensor_device.contacts)   # ['IN', 'OUT']
print(sensor_device.gpios)      # ['MUX2', 'SENSOR_ENABLE']
```

### Gate Sharing Rules

**Critical constraint**: Only RESERVOIR gates can be shared between groups. Other gate types cannot be shared.

In the example above, notice that both the `control` and `sensor` groups include gates G9 and G10:

```yaml
gates:
  G9: {type: RESERVOIR, ...}   # Shared reservoir
  G10: {type: RESERVOIR, ...}  # Shared reservoir

groups:
  control:
    gates: [G1, G2, G3, G4, G5, G9, G10]  # Includes G9, G10

  sensor:
    gates: [G6, G7, G8, G9, G10]          # Also includes G9, G10 - OK!
```

This is valid because G9 and G10 are RESERVOIR gates. If you tried to share a PLUNGER or BARRIER gate:

```yaml
# INVALID - PLUNGER shared between groups
gates:
  G2: {type: PLUNGER, ...}

groups:
  control: {gates: [G2]}
  sensor: {gates: [G2]}  # ERROR: PLUNGER cannot be shared
```

You would get an error: `Gate 'G2' is assigned to multiple groups: control, sensor. Only RESERVOIR gates can be shared between groups.`

**Rationale**: RESERVOIR gates are voltage references designed to be shared. Other gate types (PLUNGER and BARRIER) control individual quantum dots and sharing them can cause interference or device damage.

**Contacts and GPIOs** can be freely shared between groups with no restrictions. In the example, both groups share the IN and OUT contacts.

### What Happens When You Omit Pads

Stanza uses **conditional filtering** to determine which pads are accessible when you filter by group. The behavior depends on whether you omit, explicitly list, or use an empty list:

| Pad Type     | Omitted from Group | Empty List `[]` | Explicit List  |
| ------------ | ------------------ | --------------- | -------------- |
| **Gates**    | Not included       | Not included    | ONLY specified |
| **Contacts** | ALL included       | Not included    | ONLY specified |
| **GPIOs**    | ALL included       | Not included    | ONLY specified |

Let's explore three variations of our Sample Device groups to see how this works.

#### Variation 1: Explicit Lists (Precise Control)

This is what we saw in the Sample Device - each group explicitly specifies its pads:

```yaml
groups:
  control:
    gates: [G1, G2, G3, G4, G5, G9, G10]
    contacts: [IN, OUT]                    # Explicit: only these contacts
    gpios: [MUX1]                          # Explicit: only MUX1

  sensor:
    gates: [G6, G7, G8, G9, G10]
    contacts: [IN, OUT]                    # Explicit: only these contacts
    gpios: [MUX2, SENSOR_ENABLE]           # Explicit: only these GPIOs
```

**Result**: Each group gets exactly what's listed. The control group can access MUX1 but not MUX2 or SENSOR\_ENABLE. The sensor group can access MUX2 and SENSOR\_ENABLE but not MUX1.

#### Variation 2: Omit GPIOs (Share All Infrastructure)

If we want both groups to access all GPIOs, we can omit the `gpios` field:

```yaml
groups:
  control:
    gates: [G1, G2, G3, G4, G5, G9, G10]
    contacts: [IN, OUT]
    # gpios omitted - gets ALL GPIOs: [MUX1, MUX2, SENSOR_ENABLE]

  sensor:
    gates: [G6, G7, G8, G9, G10]
    contacts: [IN, OUT]
    # gpios omitted - gets ALL GPIOs: [MUX1, MUX2, SENSOR_ENABLE]
```

**Result**: Both groups can now access all GPIO pins. This is useful when you want maximum flexibility or have shared infrastructure like power supplies that every group needs.

#### Variation 3: Empty Lists (Restricted Access)

If we want to restrict the sensor group to gate-only testing, we can use empty lists:

```yaml
groups:
  control:
    gates: [G1, G2, G3, G4, G5, G9, G10]
    contacts: [IN, OUT]
    gpios: [MUX1]

  sensor:
    gates: [G6, G7, G8, G9, G10]
    contacts: []  # Explicit empty: NO contacts accessible
    gpios: []     # Explicit empty: NO GPIOs accessible
```

**Result**: The control group works normally, but the sensor group can only control its gates (G6-G8, G9, G10) without any ability to measure current or control GPIO pins. Useful for isolated voltage sweeps without measurement.