Skip to content

Multi-Sheet Nodes

This guide demonstrates how to create networks where nodes appear on multiple sheets. This pattern is common for:

  • Overview diagrams showing the entire network at a glance
  • Detail sheets focusing on specific feeders or areas
  • Voltage level views separating HV, MV, and LV sections

Full Example

View the complete code: 10_multi_sheet_nodes.py

Concept

A single electrical node (one GUID) can have multiple visual representations across different sheets. This allows the same network element to appear in:

  • A high-level overview
  • A detailed feeder diagram
  • Both simultaneously

The electrical model remains unified: changes to the node affect all its presentations.

Example: Feeder Network

Create Sheets for Different Views

python
from pyptp import NetworkMV, configure_logging
from pyptp.elements.color_utils import CL_BLUE, CL_GRAY, CL_GREEN
from pyptp.elements.mv.sheet import SheetMV

configure_logging(level="INFO")

network = NetworkMV()

# Overview sheet shows entire network
overview_sheet = SheetMV(SheetMV.General(name="Overview", color=CL_GRAY))
overview_sheet.register(network)
overview_guid = overview_sheet.general.guid

# Detail sheets for individual feeders
feeder1_sheet = SheetMV(SheetMV.General(name="Feeder 1 Detail", color=CL_BLUE))
feeder1_sheet.register(network)
feeder1_guid = feeder1_sheet.general.guid

feeder2_sheet = SheetMV(SheetMV.General(name="Feeder 2 Detail", color=CL_GREEN))
feeder2_sheet.register(network)
feeder2_guid = feeder2_sheet.general.guid

Create Shared Busbar

The main busbar appears on all three sheets:

python
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.presentations import NodePresentation

busbar = NodeMV(
    NodeMV.General(name="Main_Busbar", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=200, y=200),
        NodePresentation(sheet=feeder1_guid, x=100, y=150),
        NodePresentation(sheet=feeder2_guid, x=100, y=150),
    ],
)
busbar.register(network)

Create Sheet-Specific Elements

Some elements only appear on specific sheets:

python
from pyptp.elements.mv.source import SourceMV
from pyptp.elements.mv.presentations import ElementPresentation

# Source node only on overview
source_node = NodeMV(
    NodeMV.General(name="Source", unom=10.0),
    presentations=[NodePresentation(sheet=overview_guid, x=200, y=100)],
)
source_node.register(network)

source = SourceMV(
    SourceMV.General(node=source_node.general.guid, sk2nom=100.0),
    presentations=[ElementPresentation(sheet=overview_guid, x=200, y=50)],
)
source.register(network)

Create Feeder Load Nodes

Feeder loads appear on both overview and their respective detail sheets:

python
# Feeder 1 load node - on overview and feeder1 detail
feeder1_load_node = NodeMV(
    NodeMV.General(name="F1_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=350, y=200),
        NodePresentation(sheet=feeder1_guid, x=400, y=150),
    ],
)
feeder1_load_node.register(network)

# Feeder 2 load node - on overview and feeder2 detail
feeder2_load_node = NodeMV(
    NodeMV.General(name="F2_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=50, y=200),
        NodePresentation(sheet=feeder2_guid, x=400, y=150),
    ],
)
feeder2_load_node.register(network)

Create Branches with Multiple Presentations

Branches between multi-sheet nodes need presentations on each common sheet:

python
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.presentations import BranchPresentation

# Feeder 1 connection - appears on both overview and feeder1 detail
link_f1 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder1_load_node.general.guid),
    presentations=[
        # Overview presentation
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (275, 200)],
            second_corners=[(350, 200)],
        ),
        # Detail presentation
        BranchPresentation(
            sheet=feeder1_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f1.register(network)

Add Loads with Multiple Presentations

python
from pyptp.elements.mv.load import LoadMV

load1 = LoadMV(
    LoadMV.General(node=feeder1_load_node.general.guid, P=30.0, Q=15.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=350, y=250),
        ElementPresentation(sheet=feeder1_guid, x=400, y=200),
    ],
)
load1.register(network)

Sheet Visibility Matrix

For the example above:

ElementOverviewFeeder 1Feeder 2
Main_Busbar
Source
F1_Load
F2_Load
Link_F1
Link_F2

Best Practices

Consistent Positioning

Keep element positions logical across sheets:

python
# Good: Busbar on left of detail sheets, center of overview
busbar_presentations = [
    NodePresentation(sheet=overview_guid, x=200, y=200),   # Center
    NodePresentation(sheet=detail_guid, x=100, y=150),      # Left
]

Clear Naming Convention

Use sheet names that indicate their purpose:

python
sheets = [
    ("Overview", CL_GRAY),
    ("Substation_A_Detail", CL_BLUE),
    ("Feeder_West_Detail", CL_GREEN),
]

Branch Presentation per Common Sheet

Always provide a branch presentation for each sheet where both endpoints are visible:

python
def create_multi_sheet_branch(node1, node2, corner_generator):
    """Create branch with presentations on all common sheets."""
    common_sheets = find_common_sheets(node1, node2)

    presentations = []
    for sheet_guid in common_sheets:
        pos1 = get_position_on_sheet(node1, sheet_guid)
        pos2 = get_position_on_sheet(node2, sheet_guid)
        first, second = corner_generator(pos1, pos2)
        presentations.append(
            BranchPresentation(sheet=sheet_guid, first_corners=first, second_corners=second)
        )

    return presentations

Complete Example

python
"""Nodes can appear on multiple sheets.

This is useful for creating overview diagrams or splitting large networks
across multiple sheets while maintaining connections.
"""

from pyptp import NetworkMV, configure_logging
from pyptp.elements.color_utils import CL_BLUE, CL_GRAY, CL_GREEN
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.load import LoadMV
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.presentations import BranchPresentation, ElementPresentation, NodePresentation
from pyptp.elements.mv.sheet import SheetMV
from pyptp.elements.mv.source import SourceMV
from pyptp.ptp_log import logger

configure_logging(level="INFO")

network = NetworkMV()

# Create sheets for different network sections
overview_sheet = SheetMV(SheetMV.General(name="Overview", color=CL_GRAY))
overview_sheet.register(network)
overview_guid = overview_sheet.general.guid

feeder1_sheet = SheetMV(SheetMV.General(name="Feeder 1 Detail", color=CL_BLUE))
feeder1_sheet.register(network)
feeder1_guid = feeder1_sheet.general.guid

feeder2_sheet = SheetMV(SheetMV.General(name="Feeder 2 Detail", color=CL_GREEN))
feeder2_sheet.register(network)
feeder2_guid = feeder2_sheet.general.guid

# Main busbar appears on all sheets
busbar = NodeMV(
    NodeMV.General(name="Main_Busbar", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=200, y=200),
        NodePresentation(sheet=feeder1_guid, x=100, y=150),
        NodePresentation(sheet=feeder2_guid, x=100, y=150),
    ],
)
busbar.register(network)

# Source only on overview
source_node = NodeMV(
    NodeMV.General(name="Source", unom=10.0),
    presentations=[NodePresentation(sheet=overview_guid, x=200, y=100)],
)
source_node.register(network)

source = SourceMV(
    SourceMV.General(node=source_node.general.guid, sk2nom=100.0),
    presentations=[ElementPresentation(sheet=overview_guid, x=200, y=50)],
)
source.register(network)

# Feeder nodes on overview and detail sheets
feeder1_load_node = NodeMV(
    NodeMV.General(name="F1_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=350, y=200),
        NodePresentation(sheet=feeder1_guid, x=400, y=150),
    ],
)
feeder1_load_node.register(network)

feeder2_load_node = NodeMV(
    NodeMV.General(name="F2_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=50, y=200),
        NodePresentation(sheet=feeder2_guid, x=400, y=150),
    ],
)
feeder2_load_node.register(network)

# Source connection (overview only)
link_source = LinkMV(
    LinkMV.General(node1=source_node.general.guid, node2=busbar.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 100), (200, 150)],
            second_corners=[(200, 200)],
        )
    ],
)
link_source.register(network)

# Feeder 1 connection (overview + detail)
link_f1 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder1_load_node.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (275, 200)],
            second_corners=[(350, 200)],
        ),
        BranchPresentation(
            sheet=feeder1_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f1.register(network)

# Feeder 2 connection (overview + detail)
link_f2 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder2_load_node.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (125, 200)],
            second_corners=[(50, 200)],
        ),
        BranchPresentation(
            sheet=feeder2_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f2.register(network)

# Loads with multiple presentations
load1 = LoadMV(
    LoadMV.General(node=feeder1_load_node.general.guid, P=30.0, Q=15.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=350, y=250),
        ElementPresentation(sheet=feeder1_guid, x=400, y=200),
    ],
)
load1.register(network)

load2 = LoadMV(
    LoadMV.General(node=feeder2_load_node.general.guid, P=40.0, Q=20.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=50, y=250),
        ElementPresentation(sheet=feeder2_guid, x=400, y=200),
    ],
)
load2.register(network)

network.save("multi_sheet.vnf")
logger.info("Multi-sheet network saved")