Source code for monee.network.res

import monee.express as mx
import monee.model as mm


def _line(net, from_id, to_id, length_m, kv_class="120"):
    """Add a PowerLine with parameters appropriate for the voltage class."""
    if kv_class == "20":
        r, x, max_i_ka = 3e-4, 3e-4, 0.30  # 20 kV cable   → ~10 MVA/line
    elif kv_class == "110":
        r, x, max_i_ka = 7e-5, 7e-5, 0.40  # 110 kV OHL    → ~76 MVA/line
    else:  # 120 kV
        r, x, max_i_ka = 3e-4, 3e-4, 0.30  # 120 kV cable  → ~62 MVA/line
    net.branch(
        mm.PowerLine(
            length_m=length_m,
            r_ohm_per_m=r,
            x_ohm_per_m=x,
            max_i_ka=max_i_ka,
            parallel=1,
        ),
        from_node_id=from_id,
        to_node_id=to_id,
    )


[docs] def create_urban_district_net() -> mm.Network: """ Urban residential district: 20 kV power + medium-pressure gas + district heat. 5 buses · 5 gas junctions · 4 heat junctions (3 supply + 1 return) · 3 CPs. Highest CP-to-node ratio of the three grids. Suitable for: testing CHP-centred resilience. The heat grid uses a supply-return two-pipe structure: the CHP injects heat on the return→supply side (r1→s1, ~176 kW) and a single ``HeatExchangerLoad`` consumer extracts on the supply→return side (s3→r1). """ net = mx.create_multi_energy_network() b0 = mx.create_bus(net, base_kv=20, name="B0_gen") b1 = mx.create_bus(net, base_kv=20, name="B1_slack") b2 = mx.create_bus(net, base_kv=20, name="B2_load") b3 = mx.create_bus(net, base_kv=20, name="B3_load") b4 = mx.create_bus(net, base_kv=20, name="B4_load") mx.create_ext_power_grid(net, b1, p_mw=0, q_mvar=0, vm_pu=1.0) mx.create_power_generator(net, b0, p_mw=8, q_mvar=0) mx.create_power_load(net, b2, p_mw=3, q_mvar=0.5) mx.create_power_load(net, b3, p_mw=5, q_mvar=0.5) mx.create_power_load(net, b4, p_mw=4, q_mvar=0.5) _line(net, b0, b1, length_m=500, kv_class="20") _line(net, b1, b2, length_m=400, kv_class="20") _line(net, b2, b3, length_m=300, kv_class="20") _line(net, b2, b4, length_m=350, kv_class="20") g0 = mx.create_gas_junction(net, name="G0_ext") g1 = mx.create_gas_junction(net, name="G1") g2 = mx.create_gas_junction(net, name="G2") g3 = mx.create_gas_junction(net, name="G3_sink") g4 = mx.create_gas_junction(net, name="G4_sink") mx.create_ext_hydr_grid(net, g0) mx.create_sink(net, g3, mass_flow_kgs=0.04) # direct gas consumer mx.create_sink(net, g4, mass_flow_kgs=0.02) # P2G injection node + consumer mx.create_gas_pipe(net, g0, g1, diameter_m=0.15, length_m=400) mx.create_gas_pipe(net, g1, g2, diameter_m=0.12, length_m=300) mx.create_gas_pipe(net, g2, g3, diameter_m=0.10, length_m=250) mx.create_gas_pipe(net, g1, g4, diameter_m=0.10, length_m=200) # Supply side (hot, ~356 K): CP hot outlets + distribution + HE consumers. # CHP and P2H bridge return→supply, just as HEs bridge supply→return. s1 = mx.create_water_junction(net, name="s1") s2 = mx.create_water_junction(net, name="s2") s3 = mx.create_water_junction(net, name="s3") mx.create_water_pipe(net, s1, s2, diameter_m=0.10, length_m=100) mx.create_water_pipe(net, s2, s3, diameter_m=0.10, length_m=100) mx.create_ext_hydr_grid(net, s1) r1 = mx.create_water_junction(net, name="r1") mx.create_consume_hydr_grid(net, r1) mx.create_heat_exchanger(net, s3, r1, 0.2) # CHP: gas at G2 → power at B3, heat from r1→s1. # heat_w = 0.40 × 0.008 kg/s × 3.6 × 11.79011 kWh/kg × 1e6 ≈ 135 822 W # (default gas is now lgas, HHV 11.79011 kWh/kg; was 15.3 for methane) mx.create_chp( net, power_node_id=b3, heat_node_id=r1, heat_return_node_id=s1, gas_node_id=g2, diameter_m=0.10, efficiency_power=0.40, efficiency_heat=0.40, mass_flow_setpoint_kgs=0.006, regulation=1, ) # P2G: surplus power at B0 → hydrogen injection at G4 mx.create_p2g( net, from_node_id=b0, to_node_id=g4, efficiency=0.70, mass_flow_setpoint_kgs=0.010, regulation=1, ) # G2P: gas peaker at G3 → power backup at B2 mx.create_g2p( net, from_node_id=g3, to_node_id=b2, efficiency=0.85, p_mw_setpoint=1.5, regulation=1, ) return net
def _add_urban_district(net, idx: int, slack_bus, ext_gas_junction): """Add a single urban-district sub-grid attached to shared external feeders. Returns ``(district_slack_bus, district_gas_head)`` so the caller can wire inter-district trunks. """ suffix = f"_d{idx}" b0 = mx.create_bus(net, base_kv=20, name=f"B0_gen{suffix}") b1 = mx.create_bus(net, base_kv=20, name=f"B1_local{suffix}") b2 = mx.create_bus(net, base_kv=20, name=f"B2_load{suffix}") b3 = mx.create_bus(net, base_kv=20, name=f"B3_load{suffix}") b4 = mx.create_bus(net, base_kv=20, name=f"B4_load{suffix}") mx.create_power_generator(net, b0, p_mw=4, q_mvar=0) mx.create_power_load(net, b2, p_mw=2, q_mvar=0.3) mx.create_power_load(net, b3, p_mw=3, q_mvar=0.3) mx.create_power_load(net, b4, p_mw=2, q_mvar=0.3) _line(net, slack_bus, b1, length_m=600, kv_class="20") _line(net, b0, b1, length_m=400, kv_class="20") _line(net, b1, b2, length_m=300, kv_class="20") _line(net, b2, b3, length_m=250, kv_class="20") _line(net, b2, b4, length_m=300, kv_class="20") mx.create_line( net, b3, b4, length_m=350, r_ohm_per_m=3e-4, x_ohm_per_m=3e-4, parallel=1, on_off=0, name=f"tie_b3_b4{suffix}", ) g1 = mx.create_gas_junction(net, name=f"G1{suffix}") g2 = mx.create_gas_junction(net, name=f"G2{suffix}") g3 = mx.create_gas_junction(net, name=f"G3_sink{suffix}") g4 = mx.create_gas_junction(net, name=f"G4_sink{suffix}") mx.create_sink(net, g3, mass_flow_kgs=0.03) mx.create_sink(net, g4, mass_flow_kgs=0.015) mx.create_gas_pipe(net, ext_gas_junction, g1, diameter_m=0.15, length_m=400) mx.create_gas_pipe(net, g1, g2, diameter_m=0.12, length_m=250) mx.create_gas_pipe(net, g2, g3, diameter_m=0.10, length_m=200) mx.create_gas_pipe(net, g1, g4, diameter_m=0.10, length_m=180) mx.create_gas_pipe( net, ext_gas_junction, g2, diameter_m=0.12, length_m=550, on_off=0, name=f"tie_g0_g2{suffix}", ) s1 = mx.create_water_junction(net, name=f"s1{suffix}") s2 = mx.create_water_junction(net, name=f"s2{suffix}") s3 = mx.create_water_junction(net, name=f"s3{suffix}") mx.create_water_pipe(net, s1, s2, diameter_m=0.10, length_m=100) mx.create_water_pipe(net, s2, s3, diameter_m=0.10, length_m=100) mx.create_water_pipe( net, s1, s3, diameter_m=0.10, length_m=200, on_off=0, name=f"tie_s1_s3{suffix}", ) mx.create_ext_hydr_grid(net, s1) r1 = mx.create_water_junction(net, name=f"r1{suffix}") mx.create_consume_hydr_grid(net, r1) mx.create_heat_exchanger(net, s3, r1, 0.15) r2 = mx.create_water_junction(net, name=f"r2{suffix}") mx.create_consume_hydr_grid(net, r2) mx.create_heat_exchanger(net, s2, r2, 0.08) mx.create_chp( net, power_node_id=b3, heat_node_id=r1, heat_return_node_id=s1, gas_node_id=g2, diameter_m=0.10, efficiency_power=0.40, efficiency_heat=0.40, mass_flow_setpoint_kgs=0.005, regulation=1, ) mx.create_p2g( net, from_node_id=b0, to_node_id=g4, efficiency=0.70, mass_flow_setpoint_kgs=0.008, regulation=1, ) mx.create_g2p( net, from_node_id=g3, to_node_id=b2, efficiency=0.85, p_mw_setpoint=1.0, regulation=1, ) return b1, g1
[docs] def create_large_urban_mes_net(n_districts: int = 6) -> mm.Network: """ Scaled multi-district urban MES for large-grid restoration evaluation. Replicates the urban-district pattern ``n_districts`` times under a shared HV slack and a shared external gas feeder, linking adjacent districts with normally-open MV power ties and live gas trunks. Heat is intentionally local-only (one return-side consumer pair per district), so the heat sector decomposes into one connected component per district while electricity and gas remain single-component. Sizing (per district): 5 power buses, 4 gas junctions, 4 water junctions, 2 heat consumers, 3 CPs (CHP/P2G/G2P), 4 internal ties. Defaults (``n_districts=6``) yield ~96 nodes / ~30 children. Set ``n_districts=20`` for a ~320-node / ~100-child stress test that actually exercises gossip scaling and meaningful holon formation in the heat sector (one group per district). Args: n_districts: Number of urban districts to replicate. Must be ≥1. """ if n_districts < 1: raise ValueError("n_districts must be >= 1") net = mx.create_multi_energy_network() slack = mx.create_bus(net, base_kv=20, name="HV_slack") mx.create_ext_power_grid(net, slack, p_mw=0, q_mvar=0, vm_pu=1.0) ext_gas = mx.create_gas_junction(net, name="G_ext") mx.create_ext_hydr_grid(net, ext_gas) district_heads_power: list = [] district_heads_gas: list = [] for i in range(n_districts): bp, gh = _add_urban_district(net, i, slack, ext_gas) district_heads_power.append(bp) district_heads_gas.append(gh) for i in range(n_districts - 1): a, b = district_heads_power[i], district_heads_power[i + 1] mx.create_line( net, a, b, length_m=2000, r_ohm_per_m=3e-4, x_ohm_per_m=3e-4, parallel=1, on_off=0, name=f"inter_district_power_{i}", ) ga, gb = district_heads_gas[i], district_heads_gas[i + 1] mx.create_gas_pipe( net, ga, gb, diameter_m=0.20, length_m=1500, name=f"inter_district_gas_{i}", ) return net
if __name__ == "__main__": import monee net = create_urban_district_net() net.apply_formulation(monee.EL_MISOCP_FORMULATION) print(monee.run_energy_flow(net, solver="gurobi"))