move uc assigment to add_electricity

make code backwards-compatible
This commit is contained in:
Fabian 2023-06-29 14:50:41 +02:00
parent cc6bae282f
commit 519a4f2a2a
6 changed files with 48 additions and 37 deletions

View File

@ -254,6 +254,8 @@ renewable:
clip_min_inflow: 1.0 clip_min_inflow: 1.0
conventional: conventional:
unit_commitment: false
dynamic_fuel_price: false
nuclear: nuclear:
p_max_pu: "data/nuclear_p_max_pu.csv" # float of file name p_max_pu: "data/nuclear_p_max_pu.csv" # float of file name
@ -345,8 +347,6 @@ solar_thermal:
# only relevant for foresight = myopic or perfect # only relevant for foresight = myopic or perfect
existing_capacities: existing_capacities:
unit_commitment: true # if unit commitment (UC) for conventional power plants is used
# UC is only applied to extendable plants if linearized UC is used
grouping_years_power: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020, 2025, 2030] grouping_years_power: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020, 2025, 2030]
grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # these should not extend 2020 grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # these should not extend 2020
threshold_capacity: 10 threshold_capacity: 10

View File

@ -243,6 +243,8 @@ renewable:
clip_min_inflow: 1.0 clip_min_inflow: 1.0
conventional: conventional:
unit_commitment: true
dynamic_fuel_price: true
nuclear: nuclear:
p_max_pu: "data/nuclear_p_max_pu.csv" # float of file name p_max_pu: "data/nuclear_p_max_pu.csv" # float of file name

View File

@ -296,7 +296,7 @@ rule add_electricity:
countries=config["countries"], countries=config["countries"],
renewable=config["renewable"], renewable=config["renewable"],
electricity=config["electricity"], electricity=config["electricity"],
conventional=config.get("conventional", {}), conventional=config["conventional"],
costs=config["costs"], costs=config["costs"],
input: input:
**{ **{
@ -306,6 +306,7 @@ rule add_electricity:
**{ **{
f"conventional_{carrier}_{attr}": fn f"conventional_{carrier}_{attr}": fn
for carrier, d in config.get("conventional", {None: {}}).items() for carrier, d in config.get("conventional", {None: {}}).items()
if carrier in config["electricity"]["conventional_carriers"]
for attr, fn in d.items() for attr, fn in d.items()
if str(fn).startswith("data/") if str(fn).startswith("data/")
}, },
@ -315,6 +316,7 @@ rule add_electricity:
powerplants=RESOURCES + "powerplants.csv", powerplants=RESOURCES + "powerplants.csv",
hydro_capacities=ancient("data/bundle/hydro_capacities.csv"), hydro_capacities=ancient("data/bundle/hydro_capacities.csv"),
geth_hydro_capacities="data/geth2015_hydro_capacities.csv", geth_hydro_capacities="data/geth2015_hydro_capacities.csv",
unit_commitment="data/unit_commitment.csv",
fuel_price="data/validation/monthly_fuel_price.csv", fuel_price="data/validation/monthly_fuel_price.csv",
load=RESOURCES + "load.csv", load=RESOURCES + "load.csv",
nuts3_shapes=RESOURCES + "nuts3_shapes.geojson", nuts3_shapes=RESOURCES + "nuts3_shapes.geojson",

View File

@ -12,7 +12,6 @@ rule solve_network:
"co2_sequestration_potential", 200 "co2_sequestration_potential", 200
), ),
input: input:
unit_commitment_params="data/unit_commitment.csv",
network=RESOURCES + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc", network=RESOURCES + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc",
output: output:
network=RESULTS + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc", network=RESULTS + "networks/elec_s{simpl}_{clusters}_ec_l{ll}_{opts}.nc",

View File

@ -366,12 +366,13 @@ def attach_wind_and_solar(
def attach_conventional_generators( def attach_conventional_generators(
n, n,
costs, costs,
fuel_price,
ppl, ppl,
conventional_carriers, conventional_carriers,
extendable_carriers, extendable_carriers,
conventional_params, conventional_params,
conventional_inputs, conventional_inputs,
unit_commitment=None,
fuel_price=None,
): ):
carriers = set(conventional_carriers) | set(extendable_carriers["Generator"]) carriers = set(conventional_carriers) | set(extendable_carriers["Generator"])
_add_missing_carriers_from_costs(n, costs, carriers) _add_missing_carriers_from_costs(n, costs, carriers)
@ -383,19 +384,30 @@ def attach_conventional_generators(
) )
ppl["efficiency"] = ppl.efficiency.fillna(ppl.efficiency_r) ppl["efficiency"] = ppl.efficiency.fillna(ppl.efficiency_r)
fuel_price = fuel_price.assign(OCGT=fuel_price["gas"], CCGT=fuel_price["gas"]).drop( if unit_commitment is not None:
"gas", axis=1 committable_attrs = ppl.carrier.isin(unit_commitment).to_frame('committable')
) for attr in unit_commitment.index:
fuel_price = fuel_price.reindex(ppl.carrier, axis=1) default = pypsa.components.component_attrs['Generator'].default[attr]
fuel_price.fillna(costs.fuel, inplace=True) committable_attrs[attr] = ppl.carrier.map(unit_commitment.loc[attr]).fillna(default)
fuel_price.columns = ppl.index else:
marginal_cost = (fuel_price.div(ppl.efficiency)).add(ppl.carrier.map(costs.VOM)) committable_attrs = {}
logger.info(
"Adding {} generators with capacities [GW] \n{}".format( if fuel_price is not None:
len(ppl), ppl.groupby("carrier").p_nom.sum().div(1e3).round(2) fuel_price = (fuel_price.assign(OCGT=fuel_price['gas'],
) CCGT=fuel_price['gas'])
) .drop("gas", axis=1))
missing_carriers = list(carriers - set(fuel_price))
fuel_price = fuel_price.assign(**costs.fuel[missing_carriers])
fuel_price = fuel_price.reindex(ppl.carrier, axis=1)
fuel_price.columns = ppl.index
marginal_cost = fuel_price.div(ppl.efficiency).add(ppl.carrier.map(costs.VOM))
else:
marginal_cost = ppl.carrier.map(costs.VOM) + ppl.carrier.map(costs.fuel) / ppl.efficiency
# Define generators using modified ppl DataFrame
caps = ppl.groupby("carrier").p_nom.sum().div(1e3).round(2)
logger.info(f"Adding {len(ppl)} generators with capacities [GW] \n{caps}")
n.madd( n.madd(
"Generator", "Generator",
@ -410,9 +422,10 @@ def attach_conventional_generators(
capital_cost=ppl.capital_cost, capital_cost=ppl.capital_cost,
build_year=ppl.datein.fillna(0).astype(int), build_year=ppl.datein.fillna(0).astype(int),
lifetime=(ppl.dateout - ppl.datein).fillna(np.inf), lifetime=(ppl.dateout - ppl.datein).fillna(np.inf),
**committable_attrs
) )
for carrier in conventional_params: for carrier in set(conventional_params) & carriers:
# Generators with technology affected # Generators with technology affected
idx = n.generators.query("carrier == @carrier").index idx = n.generators.query("carrier == @carrier").index
@ -752,18 +765,28 @@ if __name__ == "__main__":
k: v for k, v in snakemake.input.items() if k.startswith("conventional_") k: v for k, v in snakemake.input.items() if k.startswith("conventional_")
} }
m_fuel_price = pd.read_csv(snakemake.input.fuel_price, index_col=[0], header=[0]) if params.conventional["unit_commitment"]:
m_fuel_price.index = pd.date_range(start="2019-01-01", end="2019-12-01", freq="MS") unit_commitment = pd.read_csv(snakemake.input.unit_commitment, index_col=0)
fuel_price = m_fuel_price.reindex(n.snapshots).fillna(method="ffill") else:
unit_commitment = None
if params.conventional["dynamic_fuel_price"]:
monthly_fuel_price = pd.read_csv(snakemake.input.fuel_price, index_col=0, header=0)
monthly_fuel_price.index = pd.date_range(start=n.snapshots[0], end=n.snapshots[-1], freq='MS')
fuel_price = monthly_fuel_price.reindex(n.snapshots).fillna(method="ffill")
else:
fuel_price = None
attach_conventional_generators( attach_conventional_generators(
n, n,
costs, costs,
fuel_price,
ppl, ppl,
conventional_carriers, conventional_carriers,
extendable_carriers, extendable_carriers,
params.conventional, params.conventional,
conventional_inputs, conventional_inputs,
unit_commitment=unit_commitment,
fuel_price=fuel_price,
) )
attach_wind_and_solar( attach_wind_and_solar(

View File

@ -149,8 +149,6 @@ def prepare_network(
planning_horizons=None, planning_horizons=None,
co2_sequestration_potential=None, co2_sequestration_potential=None,
): ):
if snakemake.config["existing_capacities"]["unit_commitment"]:
add_unit_commitment(n, snakemake.input.unit_commitment_params)
if "clip_p_max_pu" in solve_opts: if "clip_p_max_pu" in solve_opts:
for df in ( for df in (
@ -600,19 +598,6 @@ def extra_functionality(n, snapshots):
add_pipe_retrofit_constraint(n) add_pipe_retrofit_constraint(n)
def add_unit_commitment(n, fn):
"""
Add unit commitment.
"""
c = "Generator"
uc_data = pd.read_csv(fn, index_col=0)
n.df(c).loc[n.df(c).carrier.isin(uc_data.columns), "committable"] = True
for attr in uc_data.index:
n.df(c)[attr].update(n.df(c)["carrier"].map(uc_data.loc[attr]).dropna())
gen_i = n.df(c).query("carrier in @uc_data.columns").index
n.df(c).loc[gen_i, "committable"] = True
def solve_network(n, config, solving, opts="", **kwargs): def solve_network(n, config, solving, opts="", **kwargs):
set_of_options = solving["solver"]["options"] set_of_options = solving["solver"]["options"]
solver_options = solving["solver_options"][set_of_options] if set_of_options else {} solver_options = solving["solver_options"][set_of_options] if set_of_options else {}