Create summary CSV files for all scenario runs including costs, capacities, capacity factors, curtailment, energy balances, prices and other metrics.

calculate_co2_balance(n, label, co2_balance, withdrawal_stores=['CO2 capture'])

calc the co2 balance [DOES NOT INCLUDE EMISSION GENERATING LINKSs] Args: n (pypsa.Network): the network object withdrawal_stores (list, optional): names of stores. Defaults to ["CO2 capture"]. label (str): the label for the column co2_balance (pd.DataFrame): the df to update

Returns:
  • DataFrame

    tuple[float,float,float]: balance,

Source code in workflow/scripts/make_summary.py
def calculate_co2_balance(
    n: pypsa.Network, label: str, co2_balance: pd.DataFrame, withdrawal_stores=["CO2 capture"]
) -> pd.DataFrame:
    """calc the co2 balance [DOES NOT INCLUDE EMISSION GENERATING LINKSs]
    Args:
        n (pypsa.Network): the network object
        withdrawal_stores (list, optional): names of stores. Defaults to ["CO2 capture"].
        label (str): the label for the column
        co2_balance (pd.DataFrame): the df to update

    Returns:
        tuple[float,float,float]: balance,
    """

    # year *(assumes one planning year intended),
    year = int(np.round(n.snapshots.year.values.mean(), 0))

    # emissions from generators (from fneumann course)
    emissions = (
        n.generators_t.p
        / n.generators.efficiency
        * n.generators.carrier.map(n.carriers.co2_emissions)
    )  # t/h
    emissions_carrier = (
        (n.snapshot_weightings.generators @ emissions).groupby(n.generators.carrier).sum()
    )

    # format and drop 0 values
    emissions_carrier = emissions_carrier.where(emissions_carrier > 0).dropna()
    emissions_carrier.rename(year, inplace=True)
    emissions_carrier = emissions_carrier.to_frame()
    # CO2 withdrawal
    stores = n.stores_t.e.T.groupby(n.stores.carrier).sum()
    co2_stores = stores.index.intersection(withdrawal_stores)
    co2_withdrawal = stores.iloc[:, -1].loc[co2_stores] * -1
    co2_withdrawal.rename(year, inplace=True)
    co2_withdrawal = co2_withdrawal.to_frame()
    year_balance = pd.concat([emissions_carrier, co2_withdrawal])

    #  combine with previous
    co2_balance = co2_balance.reindex(year_balance.index.union(co2_balance.index))
    co2_balance.loc[year_balance.index, label] = year_balance[year]

    return co2_balance

calculate_peak_dispatch(n, label, supply)

Calculate the MAX dispatch of each component at the buses aggregated by carrier.

Parameters:
  • n (Network) –

    the network object

  • label (str) –

    the labe representing the pathway

  • supply (DataFrame) –

    supply energy balance (empty df)

Returns:
  • DataFrame

    pd.DataFrame: updated supply DF

Source code in workflow/scripts/make_summary.py
def calculate_peak_dispatch(n: pypsa.Network, label: str, supply: pd.DataFrame) -> pd.DataFrame:
    """Calculate the MAX dispatch of each component at the buses aggregated by
    carrier.

    Args:
        n (pypsa.Network): the network object
        label (str): the labe representing the pathway
        supply (pd.DataFrame): supply energy balance (empty df)

    Returns:
        pd.DataFrame: updated supply DF
    """

    sup_ = n.statistics.supply(
        groupby=pypsa.statistics.get_carrier_and_bus_carrier, aggregate_time="max"
    )
    supply_reordered = sup_.reorder_levels([2, 0, 1])
    supply_reordered.sort_index(inplace=True)
    supply[label] = supply_reordered

    return supply

calculate_supply_energy(n, label, supply_energy)

Calculate the total energy supply/consuption of each component at the buses aggregated by carrier.

Parameters:
  • n (Network) –

    the network object

  • label (str) –

    the labe representing the pathway

  • supply_energy (DataFrame) –

    supply energy balance (empty df)

Returns:
  • DataFrame

    pd.DataFrame: updated supply energy balance

Source code in workflow/scripts/make_summary.py
def calculate_supply_energy(
    n: pypsa.Network, label: str, supply_energy: pd.DataFrame
) -> pd.DataFrame:
    """Calculate the total energy supply/consuption of each component at the buses
    aggregated by carrier.

    Args:
        n (pypsa.Network): the network object
        label (str): the labe representing the pathway
        supply_energy (pd.DataFrame): supply energy balance (empty df)

    Returns:
        pd.DataFrame: updated supply energy balance
    """

    eb = n.statistics.energy_balance(groupby=pypsa.statistics.get_carrier_and_bus_carrier)
    # fragile
    eb_reordered = eb.reorder_levels([2, 0, 1])
    eb_reordered.sort_index(inplace=True)
    eb_reordered.rename(index={"AC": "transmission losses"}, level=2, inplace=True)

    supply_energy[label] = eb_reordered

    return supply_energy

calculate_weighted_prices(n, label, weighted_prices)

Demand-weighed prices for stores and loads. For stores if withdrawal is zero, use supply instead. Args: n (pypsa.Network): the network object label (str): the label representing the pathway (not needed, refactor) weighted_prices (pd.DataFrame): the dataframe to write to (not needed, refactor)

Returns:
  • DataFrame

    pd.DataFrame: updated weighted_prices

Source code in workflow/scripts/make_summary.py
def calculate_weighted_prices(
    n: pypsa.Network, label: str, weighted_prices: pd.DataFrame
) -> pd.DataFrame:
    """Demand-weighed prices for stores and loads.
        For stores if withdrawal is zero, use supply instead.
    Args:
        n (pypsa.Network): the network object
        label (str): the label representing the pathway (not needed, refactor)
        weighted_prices (pd.DataFrame): the dataframe to write to (not needed, refactor)

    Returns:
        pd.DataFrame: updated weighted_prices
    """
    entries = pd.Index(["electricity", "heat", "H2", "CO2 capture", "gas", "biomass"])
    weighted_prices = weighted_prices.reindex(entries)

    # loads
    loads = (
        n.statistics.revenue(comps="Load", groupby=pypsa.statistics.get_bus_carrier)
        / n.statistics.withdrawal(comps="Load", groupby=pypsa.statistics.get_bus_carrier)
        * -1
    )
    loads.rename(index={"AC": "electricity"}, inplace=True)

    # stores
    w = n.statistics.withdrawal(comps="Store")
    # biomass stores have no withdrawal for some reason
    w[w == 0] = n.statistics.supply(comps="Store")[w == 0]
    weighted_prices[label] = pd.concat([loads, n.statistics.revenue(comps="Store") / w])
    return weighted_prices