# -*- coding: utf-8 -*-
"""
Four-bus optimal power flow (OPF) example from pandapower tutorial ``opf_basic.ipynb``.
Upstream reference:
https://github.com/e2nIEE/pandapower/blob/develop/tutorials/opf_basic.ipynb

Electrisim runs this file on import with ``pandapower`` available as ``pp``.
You MUST leave a variable named ``net`` in scope.

This script builds topology and ``poly_cost`` rows only; it does **not** call
``runopp`` so network import stays robust. Run OPF in the app:
Simulate → Optimal Power Flow → Calculate (pandapower ``runopp`` / ``rundcopp``).
"""

net = pp.create_empty_network()

bus1 = pp.create_bus(net, vn_kv=220.0, name="Bus_220_HV")
bus2 = pp.create_bus(net, vn_kv=110.0, name="Bus_110_A")
bus3 = pp.create_bus(net, vn_kv=110.0, name="Bus_110_B")
bus4 = pp.create_bus(net, vn_kv=110.0, name="Bus_110_C")

pp.create_transformer(net, bus1, bus2, std_type="100 MVA 220/110 kV")

pp.create_lines(
    net,
    [bus2, bus3, bus4],
    [bus3, bus4, bus2],
    length_km=[70, 50, 40],
    std_type="149-AL1/24-ST1A 110.0",
)

pp.create_load(net, bus2, p_mw=60, controllable=False)
pp.create_load(net, bus3, p_mw=70, controllable=False)
pp.create_load(net, bus4, p_mw=10, controllable=False)

pp.create_ext_grid(net, bus1, min_p_mw=-1000, max_p_mw=1000)
pp.create_gen(net, bus3, p_mw=80, min_p_mw=0, max_p_mw=80, vm_pu=1.01, controllable=True)
pp.create_gen(net, bus4, p_mw=100, min_p_mw=0, max_p_mw=100, vm_pu=1.01, controllable=True)

# Loss minimization setup: identical linear marginal cost on slack and both gens.
cost_ext = pp.create_poly_cost(net, 0, "ext_grid", cp1_eur_per_mw=10)
cost_g0 = pp.create_poly_cost(net, 0, "gen", cp1_eur_per_mw=10)
cost_g1 = pp.create_poly_cost(net, 1, "gen", cp1_eur_per_mw=10)

# --- Optional: differentiated marginal costs (see notebook "Individual Generator Costs") ---
# net.poly_cost.at[cost_ext, "cp1_eur_per_mw"] = 10
# net.poly_cost.at[cost_g0, "cp1_eur_per_mw"] = 15
# net.poly_cost.at[cost_g1, "cp1_eur_per_mw"] = 12

# --- Optional: OPF transformer loading limit (notebook constrained case) ---
# net.trafo.loc[:, "max_loading_percent"] = 50
