diff --git a/scripts/prepare_perfect_foresight.py b/scripts/prepare_perfect_foresight.py index 66af8ed1..d3ec4966 100644 --- a/scripts/prepare_perfect_foresight.py +++ b/scripts/prepare_perfect_foresight.py @@ -185,6 +185,7 @@ def adjust_stores(n): e_initial_store = ["co2 stored"] co2_i = n.stores[n.stores.carrier.isin(e_initial_store)].index n.stores.loc[co2_i, "e_initial_per_period"] = True + return n @@ -240,13 +241,24 @@ def set_carbon_constraints(n, opts): carrier_attribute="co2_emissions", sense="<=", constant=budget, + investment_period=n.investment_periods[-1] + ) + + # drop other CO2 limits + drop_i = n.global_constraints[n.global_constraints.type=="co2_limit"].index + n.mremove("GlobalConstraint", drop_i) + + n.add( + "GlobalConstraint", + "carbon_neutral", + type="co2_limit", + carrier_attribute="co2_emissions", + sense="<=", + constant=0, + investment_period=n.investment_periods[-1] ) - else: - e_initial_store = ["co2 stored"] - co2_i = n.stores[n.stores.carrier.isin(e_initial_store)].index - n.stores.loc[co2_i, "e_initial_per_period"] = True # set minimum CO2 emission constraint to avoid too fast reduction if "co2min" in opts: emissions_1990 = 4.53693 @@ -305,7 +317,7 @@ if __name__ == "__main__": opts="", clusters="37", ll="v1.0", - sector_opts="4380H-T-H-B-I-A-solar+p3-dist1", + sector_opts="2p0-4380H-T-H-B-I-A-solar+p3-dist1", ) update_config_with_sector_opts(snakemake.config, snakemake.wildcards.sector_opts) diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 25472112..6fa1336b 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -205,7 +205,7 @@ def add_co2_sequestration_limit(n, config, limit=200): ) -def add_carbon_neutral_constraint(n, snapshots): +def add_carbon_constraint(n, snapshots): glcs = n.global_constraints.query('type == "co2_limit"') if glcs.empty: return @@ -231,6 +231,32 @@ def add_carbon_neutral_constraint(n, snapshots): n.model.add_constraints(lhs <= rhs, name=f"GlobalConstraint-{name}") +def add_carbon_budget_constraint(n, snapshots): + glcs = n.global_constraints.query('type == "Co2Budget"') + if glcs.empty: + return + for name, glc in glcs.iterrows(): + rhs = glc.constant + carattr = glc.carrier_attribute + emissions = n.carriers.query(f"{carattr} != 0")[carattr] + + if emissions.empty: + continue + + # stores + n.stores["carrier"] = n.stores.bus.map(n.buses.carrier) + stores = n.stores.query("carrier in @emissions.index and not e_cyclic") + time_valid = int(glc.loc["investment_period"]) + if not stores.empty: + last = n.snapshot_weightings.reset_index().groupby("period").last() + last_i = last.set_index([last.index, last.timestep]).index + final_e = n.model["Store-e"].loc[last_i, stores.index] + time_i = pd.IndexSlice[time_valid, :] + lhs = final_e.loc[time_i,:] + + n.model.add_constraints(lhs <= rhs, name=f"GlobalConstraint-{name}") + + def add_max_growth(n, config): """Add maximum growth rates for different carriers """ @@ -711,7 +737,7 @@ def extra_functionality(n, snapshots): add_battery_constraints(n) add_pipe_retrofit_constraint(n) if n._multi_invest: - add_carbon_neutral_constraint(n, snapshots) + add_carbon_constraint(n, snapshots) def solve_network(n, config, solving, opts="", **kwargs): @@ -776,7 +802,7 @@ if __name__ == "__main__": opts="", clusters="37", ll="v1.0", - sector_opts="4380H-T-H-B-I-A-solar+p3-dist1", + sector_opts="2p0-4380H-T-H-B-I-A-solar+p3-dist1", planning_horizons="2030", ) configure_logging(snakemake)