diff --git a/config.yml b/config.yml index 606b016..03b8315 100644 --- a/config.yml +++ b/config.yml @@ -1,6 +1,6 @@ state_abbr: 'IL' -version: "5.0" -scenario: "export_and_growth_0pct" +version: "10.0" +scenario: "test_single_year" solver: 'cplex' # 'cplex','highs','gurobi' geo_res: 'rto' # accepts: 'rto' or 'county' @@ -11,8 +11,8 @@ total_demand: 185e6 # Annual MWh in the first year load_growth: 0.00 # % annual growth random_seed: 1234 -model_years: [2025, 2030, 2035, 2040, 2045] -# model_years: [2025] +# model_years: [2025, 2030, 2035, 2040, 2045] +model_years: [2025] plot_year: 2025 co2_limits: @@ -37,11 +37,21 @@ retirements: # need to have every modeled year, at least 2040: 2045: - -solar_years: [2016,2017,2018,2019,2020] # NSRDB only accepts years 1998-2020 -wind_years: [2009,2010,2011,2012,2013] # WTK only goes from 2009-2013 -# solar_years: [2016] # NSRDB only accepts years 1998-2020 -# wind_years: [2009] # WTK only goes from 2009-2013 +capacity_max: + Solar: + # 2025: 1693 + 2025: 461 + Wind: + # 2025: 8700 + 2025: 798 + Batteries: + # 2025: 114 + 2025: 18 + +# solar_years: [2016,2017,2018,2019,2020] # NSRDB only accepts years 1998-2020 +# wind_years: [2009,2010,2011,2012,2013] # WTK only goes from 2009-2013 +solar_years: [2017] # NSRDB only accepts years 1998-2020 +wind_years: [2009] # WTK only goes from 2009-2013 load_year: 2019 fuel_cost_year: 2023 @@ -60,16 +70,6 @@ growth_rates: # MW/year Solar: 2.5e3 Wind: 2.5e3 -# lifetime: -# Nuclear: 80 -# Biomass: 40 -# Natural Gas: 40 -# Coal: 50 -# Solar: 20 -# Wind: 20 -# Batteries: 15 -# Petroleum: 40 - lifetime: Nuclear: 80 Biomass: 60 diff --git a/dag.png b/dag.png index d8d88e0..1defe72 100644 Binary files a/dag.png and b/dag.png differ diff --git a/scripts/add_electricity.py b/scripts/add_electricity.py index e968ccf..4a0a97e 100644 --- a/scripts/add_electricity.py +++ b/scripts/add_electricity.py @@ -16,6 +16,7 @@ pudl_year = int(snakemake.config['fuel_cost_year']) wind_cf = float(snakemake.config['turbine_params']['capacity_factor']) retirements_df = pd.DataFrame(snakemake.config['retirements']).fillna(0) +capacity_limits_df = pd.DataFrame(snakemake.config['capacity_max']).fillna(0) BUILD_YEAR = 2025 # a universal build year place holder @@ -299,7 +300,7 @@ def attach_generators( # minimum/maximum power output if tech == 'LWR': - p_min_pu = 0 + p_min_pu = 0.0 p_max_pu = 1.0 else: p_max_pu = 1 @@ -392,7 +393,6 @@ def add_retirements(n): carriers = retirements_df.columns df = retirements_df.loc[model_years, :].cumsum() - # breakpoint() c_by_carrier = n.generators.groupby('carrier').sum().loc[carriers, 'p_nom'] for carrier in carriers: @@ -405,7 +405,7 @@ def add_retirements(n): limit = remaining * (8760/resolution) n.add(class_name="GlobalConstraint", - name=f'{carrier} limit {year}', + name=f'{carrier} Energy Limit {year}', sense='<=', carrier_attribute=carrier, constant=limit, @@ -416,6 +416,31 @@ def add_retirements(n): pass return + + +def add_capacity_max(n): + + carriers = capacity_limits_df.columns + + df = capacity_limits_df.copy() + n_buses = n.buses.shape[0] + + for carrier in carriers: + for year in df.index: + try: + limit = df.loc[year, carrier] / n_buses + n.add(class_name="GlobalConstraint", + name=f'{carrier} Capacity Limit {year}', + sense='<=', + carrier_attribute=carrier, + constant=limit, + type='tech_capacity_expansion_limit', + investment_period=year, + ) + except (AttributeError, KeyError, TypeError): + pass + + return if __name__ == "__main__": @@ -477,7 +502,10 @@ def add_retirements(n): # add energy constraints - add_retirements(n) + # add_retirements(n) + + # add capacity constraints + add_capacity_max(n) # add co2 constraint emissions_dict = snakemake.config['co2_limits'] diff --git a/scripts/plot_results.py b/scripts/plot_results.py index 86f1a17..c187195 100644 --- a/scripts/plot_results.py +++ b/scripts/plot_results.py @@ -14,7 +14,7 @@ def power_by_carrier(n): p_by_carrier = n.generators_t.p.T.groupby( - n.generators.carrier).sum().T + n.generators.carrier).sum().T return p_by_carrier @@ -164,7 +164,7 @@ def plot_active_units(n): return fig, ax -def plot_monthly_generation(n, time_res): +def plot_monthly_generation(n, time_res, model_years): p_by_carrier = power_by_carrier(n) * time_res p_by_carrier = p_by_carrier.resample('ME', level='timestep').sum() @@ -173,13 +173,22 @@ def plot_monthly_generation(n, time_res): color = p_by_carrier.columns.map(n.carriers.color) - fig, ax = plt.subplots(figsize=(12, 8)) - p_by_carrier.plot.area(ax=ax, - color=color, - fontsize=16) - - ax.set_xlabel('') - ax.set_ylabel('Generation [MWh]', fontsize=18) + if len(model_years) > 1: + fig, ax = plt.subplots(1,len(model_years), figsize=(16, 8), sharey=True) + for i, year in enumerate(model_years): + p_by_carrier.loc[str(year)].plot.area(ax=ax[i], + color=color, + fontsize=16, ) + + ax[i].set_xlabel('') + + plt.tight_layout() + plt.subplots_adjust(wspace=0, hspace=0) + else: + fig, ax = plt.subplots(figsize=(12,8)) + p_by_carrier.plot.area(ax=ax, + color=color, + fontsize=16, ) return fig, ax @@ -201,5 +210,7 @@ def plot_monthly_generation(n, time_res): fig, ax = plot_active_units(n) plt.savefig(snakemake.output.active_units_figure) - fig, ax = plot_monthly_generation(n, time_res) + + model_years = snakemake.config['model_years'] + fig, ax = plot_monthly_generation(n, time_res, model_years) plt.savefig(snakemake.output.monthly_generation_figure)