diff --git a/config.yaml b/config.yaml index 70e48fab..87fadcdf 100644 --- a/config.yaml +++ b/config.yaml @@ -28,6 +28,7 @@ electricity: voltages: [220., 300., 380.] co2limit: 7.75e+7 # 0.05 * 3.1e9*0.5 co2base: 3.1e+9 # 1 * 3.1e9*0.5 + agg_p_nom_limits: data/agg_p_nom_minmax.csv extendable_carriers: Generator: [OCGT] diff --git a/data/agg_p_nom_minmax.csv b/data/agg_p_nom_minmax.csv new file mode 100644 index 00000000..111215bc --- /dev/null +++ b/data/agg_p_nom_minmax.csv @@ -0,0 +1,31 @@ +country,carrier,min,max +DE,onwind,0.1, +DE,offwind-ac,0.1, +DE,offwind-dc,0.1, +DE,solar,0.2, +LU,onwind,, +LU,solar,, +NL,onwind,, +NL,offwind-ac,, +NL,offwind-dc,, +NL,solar,, +GB,onwind,, +GB,offwind-ac,, +GB,offwind-dc,, +GB,solar,, +IE,onwind,, +IE,offwind-ac,, +IE,offwind-dc,, +IE,solar,, +FR,onwind,, +FR,offwind-ac,, +FR,offwind-dc,, +FR,solar,, +DK,onwind,, +DK,offwind-ac,, +DK,offwind-dc,, +DK,solar,, +BE,onwind,, +BE,offwind-ac,, +BE,offwind-dc,, +BE,solar,, diff --git a/scripts/solve_network.py b/scripts/solve_network.py index f9894261..e20a8398 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -77,6 +77,36 @@ def add_opts_constraints(n, opts=None): ext_gens_i = n.generators.index[n.generators.carrier.isin(conv_techs) & n.generators.p_nom_extendable] n.model.safe_peakdemand = pypsa.opt.Constraint(expr=sum(n.model.generator_p_nom[gen] for gen in ext_gens_i) >= peakdemand - exist_conv_caps) + # Add constraints on the per-carrier capacity in each country + if 'CCL' in opts: + agg_p_nom_limits = snakemake.config['electricity'].get('agg_p_nom_limits') + + try: + agg_p_nom_minmax = pd.read_csv(agg_p_nom_limits, index_col=list(range(2))) + except IOError: + logger.exception("Need to specify the path to a .csv file containing aggregate capacity limits per country in config['electricity']['agg_p_nom_limit'].") + + logger.info("Adding per carrier generation capacity constraints for individual countries") + + gen_country = n.generators.bus.map(n.buses.country) + + def agg_p_nom_min_rule(model, country, carrier): + min = agg_p_nom_minmax.at[(country, carrier), 'min'] + return ((sum(model.generator_p_nom[gen] + for gen in n.generators.index[(gen_country == country) & (n.generators.carrier == carrier)]) + >= min) + if np.isfinite(min) else pypsa.opt.Constraint.Skip) + + def agg_p_nom_max_rule(model, country, carrier): + max = agg_p_nom_minmax.at[(country, carrier), 'max'] + return ((sum(model.generator_p_nom[gen] + for gen in n.generators.index[(gen_country == country) & (n.generators.carrier == carrier)]) + <= max) + if np.isfinite(max) else pypsa.opt.Constraint.Skip) + + n.model.agg_p_nom_min = pypsa.opt.Constraint(list(agg_p_nom_minmax.index), rule=agg_p_nom_min_rule) + n.model.agg_p_nom_max = pypsa.opt.Constraint(list(agg_p_nom_minmax.index), rule=agg_p_nom_max_rule) + def add_lv_constraint(n): line_volume = getattr(n, 'line_volume_limit', None) if line_volume is not None and not np.isinf(line_volume): @@ -145,7 +175,9 @@ def solve_network(n, config=None, solver_log=None, opts=None, callback=None): free_output_series_dataframes(n) pypsa.opf.network_lopf_build_model(n, formulation=solve_opts['formulation']) + add_opts_constraints(n, opts) + if not fix_ext_lines: add_lv_constraint(n) add_lc_constraint(n)