# Generated by scripts/export_project_setup.py from _includes\projects\week11_setup.md
# Requires NumPy, SciPy and Matplotlib. No network access is needed.
# Grunndata og hjelpere for prosjektet. Alle tall er oppdiktede og forenklede.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import linprog

# Ett prisområde (del 1-2): kostnad i kr/MWh og kapasitet i MW.
plant_names = ['vind', 'vannkraft', 'import', 'gass']
cost = np.array([0., 10., 40., 70.])
capacity = np.array([30., 50., 30., 40.])

# Tre timer (del 4): forbruk og tilgjengelig vind i hver time (MW),
# og vannmengden som vannkraften kan bruke til sammen (MWh).
demand3 = np.array([60., 95., 120.])
wind3 = np.array([30., 10., 20.])
water = 120.


# Samme funksjon som i del 1b, slik at senere celler virker etter ny innlasting.
def one_zone(D):
    return linprog(cost, A_eq=[np.ones(4)], b_eq=[D],
                   bounds=list(zip(np.zeros(4), capacity)), method="highs")


# Samme funksjon som i del 3b. Variabler: vind N, vannkraft N, import S, gass S, flyt f.
def two_zones(L, wind_north=20.):
    c = np.array([0., 10., 40., 70., 0.])
    A_eq = np.array([[1., 1., 0., 0., -1.],
                     [0., 0., 1., 1., 1.]])
    bounds = [(0, wind_north), (0, 80), (0, 30), (0, 80), (-L, L)]
    return linprog(c, A_eq=A_eq, b_eq=[30., 80.], bounds=bounds, method="highs")


# Ferdig tre-timersmodell (del 4); vannraden skriver du selv i prosjektet.
def _three_hours():
    c3 = np.tile(cost, 3)
    bounds3 = []
    for h in range(3):
        bounds3 += [(0, wind3[h]), (0, 50.), (0, 30.), (0, 40.)]
    A_eq3 = np.zeros((3, 12))
    for h in range(3):
        A_eq3[h, 4*h:4*h + 4] = 1
    return c3, bounds3, A_eq3


c3, bounds3, A_eq3 = _three_hours()
# Tegnehjelpere: de tegner bare tall som allerede er regnet ut.
def show_merit_order(cost, capacity, D, names=plant_names):
    """Tilbudstrappen: hvert kraftverk er en blokk med bredde = kapasitet og
    høyde = kostnad, sortert billigst først. Den røde linjen er forbruket D."""
    fig, ax = plt.subplots(figsize=(7, 3.5), layout="constrained")
    left = 0.
    for i in np.argsort(cost, kind="stable"):
        ax.bar(left, max(cost[i], 1.5), width=capacity[i], align="edge",
               alpha=.6, edgecolor="k")
        ax.text(left + capacity[i]/2, max(cost[i], 1.5) + 2,
                f"{names[i]}\n{cost[i]:g} kr", ha="center", va="bottom", fontsize=8)
        left += capacity[i]
    ax.axvline(D, color="tab:red", lw=2)
    ax.text(D, 92, f" D = {D:g} MW", color="tab:red", va="top")
    ax.set(xlim=(0, left), ylim=(0, 95), ylabel="kostnad (kr/MWh)",
           xlabel="samlet kapasitet, billigste først (MW)")
    plt.show()


def show_steps(x, steps, smooth=None, xlabel="", ylabel="kr/MWh",
               labels=("Pris (dual)", "Gjennomsnittskostnad")):
    """Trappekurve (dualverdier) og eventuelt en glatt kurve i samme figur."""
    fig, ax = plt.subplots(figsize=(7, 4), layout="constrained")
    ax.step(x, steps, where="mid", label=labels[0])
    if smooth is not None:
        ax.plot(x, smooth, label=labels[1])
        ax.legend()
    ax.set(xlabel=xlabel, ylabel=ylabel)
    ax.grid(alpha=.3)
    plt.show()


def show_two_zones(res, L):
    """Nord og sør som to bokser med produksjon og pris, og linjen som en pil."""
    x, (pN, pS), f = res.x, res.eqlin.marginals, res.x[4]
    fig, ax = plt.subplots(figsize=(7, 2.8), layout="constrained")
    boxes = [(0.02, "NORD (forbruk 30 MW)", [("vind", x[0]), ("vannkraft", x[1])], pN),
             (0.62, "SØR (forbruk 80 MW)", [("import", x[2]), ("gass", x[3])], pS)]
    for x0, title, plants, price in boxes:
        ax.add_patch(plt.Rectangle((x0, .08), .36, .84, fill=False, lw=1.5))
        lines = [title] + [f"{n}: {v:g} MW" for n, v in plants] + [f"pris: {price + 0:g} kr/MWh"]
        ax.text(x0 + .18, .5, "\n".join(lines), ha="center", va="center", fontsize=9)
    full = "full" if abs(f) >= L - 1e-9 else "ikke full"
    ax.annotate("", xy=(.61, .5), xytext=(.39, .5),
                arrowprops=dict(arrowstyle="->", lw=2 + 3*(full == "full"),
                                color="tab:red" if full == "full" else "tab:blue"))
    ax.text(.5, .62, f"f = {f + 0:g} MW\nL = {L:g} MW ({full})", ha="center", fontsize=9)
    ax.set(xlim=(0, 1), ylim=(0, 1))
    ax.axis("off")
    plt.show()
