Feeder ID Guide
Feeder IDs connect each substation to the branches and nodes it serves. The Grid.set_feeder_ids() call populates the feeder_branch_id and feeder_node_id columns on every branch array plus grid.node, so it is the starting point for structure-aware processing that relies on the active graph.
What Feeder IDs Mean
feeder_branch_idreferences the branch that leaves a substation (a node withnode_type==NodeType.SUBSTATION_NODE) and feeds the component; every downstream branch that remains connected inherits the same feeder branch ID.feeder_node_idis the substation node ID that ultimately supplies the component. Nodes and branches without a feeding substation (including the substations themselves) receive an empty id-2147483648.
Grid.set_feeder_ids() resets any previous feeder columns, tags each branch touching a substation with is_feeder, temporarily removes all substations to find active components, and stamps every member of those components with the appropriate feeder IDs.
from power_grid_model_ds import Grid
grid = Grid.from_txt(
"S101 102 201",
"102 103 202",
"S101 104 203",
"104 105 204",
"103 105 205,open",
)
grid.set_feeder_ids()
The created grid has the following structure

print("Nodes")
for node in grid.node:
node_id = node.id
feeder_node = node.feeder_node_id
feeder_branch = node.feeder_branch_id
print(f"node {node_id}: feeder_node_id={feeder_node}, feeder_branch_id={feeder_branch}")
print()
print("Lines")
for line in grid.line:
bid = line.id
is_feeder = line.is_feeder
from_node = line.from_node
to_node = line.to_node
feeder_branch = line.feeder_branch_id
feeder_node = line.feeder_node_id
print(
f"line {bid}: is_feeder={is_feeder}, from_node={from_node}, to_node={to_node}, "
f"feeder_branch_id={feeder_branch}, feeder_node_id={feeder_node}"
)
Nodes
node [101]: feeder_node_id=[-2147483648], feeder_branch_id=[-2147483648]
node [102]: feeder_node_id=[101], feeder_branch_id=[201]
node [103]: feeder_node_id=[101], feeder_branch_id=[201]
node [104]: feeder_node_id=[101], feeder_branch_id=[203]
node [105]: feeder_node_id=[101], feeder_branch_id=[203]
Lines
line [201]: is_feeder=[ True], from_node=[101], to_node=[102], feeder_branch_id=[201], feeder_node_id=[101]
line [202]: is_feeder=[False], from_node=[102], to_node=[103], feeder_branch_id=[201], feeder_node_id=[101]
line [203]: is_feeder=[ True], from_node=[101], to_node=[104], feeder_branch_id=[203], feeder_node_id=[101]
line [204]: is_feeder=[False], from_node=[104], to_node=[105], feeder_branch_id=[203], feeder_node_id=[101]
line [205]: is_feeder=[False], from_node=[103], to_node=[105], feeder_branch_id=[-2147483648], feeder_node_id=[-2147483648]
Inspecting the Results
After the calculation every branch and node that remains connected to substation 101 carries feeder_node_id 101. The branches that directly touch the substation will also set feeder_branch_id equal to their own id, and the downstream branches inherit that value. Branches or nodes that were deactivated or isolated still show and empty value, which makes it easy to filter them out before safety checks or radial-feed reports.
Substation nodes themselves always have empty an feeder_node_id and feeder_branch_id.
Because the feeder IDs are derived from the active graph, you can trust them to reflect any changes made by make_active or make_inactive once you rerun Grid.set_feeder_ids().
We now update the grid structure and recalculate the feeder ids.

print("\nDeactivate branch 203 and activate branch 205, then recompute feeder IDs")
grid.make_inactive(branch=grid.line.get(203))
grid.make_active(branch=grid.line.get(205))
grid.set_feeder_ids()
print("Nodes after recomputation")
for node_id, feeder_node, feeder_branch in zip(grid.node.id, grid.node.feeder_node_id, grid.node.feeder_branch_id):
print(f"node {node_id}: feeder_node_id={feeder_node}, feeder_branch_id={feeder_branch}")
print("\nLines after recomputation")
for line_id, is_feeder, feeder_branch, feeder_node in zip(
grid.line.id, grid.line.is_feeder, grid.line.feeder_branch_id, grid.line.feeder_node_id
):
print(f"line {line_id}: is_feeder={is_feeder}, feeder_branch_id={feeder_branch}, feeder_node_id={feeder_node}")
Deactivate branch 203 and activate branch 205, then recompute feeder IDs
Nodes after recomputation
node 101: feeder_node_id=-2147483648, feeder_branch_id=-2147483648
node 102: feeder_node_id=101, feeder_branch_id=201
node 103: feeder_node_id=101, feeder_branch_id=201
node 104: feeder_node_id=101, feeder_branch_id=201
node 105: feeder_node_id=101, feeder_branch_id=201
Lines after recomputation
line 201: is_feeder=True, feeder_branch_id=201, feeder_node_id=101
line 202: is_feeder=False, feeder_branch_id=201, feeder_node_id=101
line 203: is_feeder=True, feeder_branch_id=-2147483648, feeder_node_id=-2147483648
line 204: is_feeder=False, feeder_branch_id=201, feeder_node_id=101
line 205: is_feeder=False, feeder_branch_id=201, feeder_node_id=101
Best Practices
Run
Grid.set_feeder_ids()whenever you add, remove, or change the activation status of branches or substations so the feeder metadata matches the current topology.Use the
feeder_node_idcolumn to group or color nodes/branches by the feeding substation and to quickly find segments that lost their connection (they remain at-2147483648).Recompute feeder IDs before serializing or exporting a grid so fixtures and downstream tools can rely on the latest feeder tree without needing to rerun the calculation.
Edge case
If a node lies in a connected path between two substation nodes, there is no unique feeder_node_id or feeder_branch_id. In this case one of the possible feeder_node_id/feeder_branch_id is picked and applied for all nodes in the path.
So it is guarenteed that all nodes in the path have the same feeder_node_id/feeder_branch_id, eventhough there is no unique solution.
grid = Grid.from_txt("S1 2 12", "2 3 23", "3 S4 34")
grid.set_feeder_ids()
print("Nodes:\n", grid.node)
print("\nLines:\n", grid.line)
Nodes:
id | u_rated | node_type | feeder_branch_id | feeder_node_id
1 | nan | 1 | -2147483648 | -2147483648
4 | nan | 1 | -2147483648 | -2147483648
2 | nan | 0 | 12 | 1
3 | nan | 0 | 12 | 1
Lines:
id | from_node | to_node | from_status | to_status | feeder_branch_id | feeder_node_id | is_feeder | r1 | x1 | c1 | tan1 | i_n
12 | 1 | 2 | 1 | 1 | 12 | 1 | True | nan | nan | nan | nan | nan
23 | 2 | 3 | 1 | 1 | 12 | 1 | False | nan | nan | nan | nan | nan
34 | 3 | 4 | 1 | 1 | 12 | 1 | True | nan | nan | nan | nan | nan