diff --git a/hourlize/reeds_to_rev.py b/hourlize/reeds_to_rev.py index 455d5a306..c879c1286 100644 --- a/hourlize/reeds_to_rev.py +++ b/hourlize/reeds_to_rev.py @@ -279,7 +279,7 @@ def get_preexisting_capacity(df_sc_in, tech, first_model_year=2009): # Find existing capacity by bin with raw supply curve. # Consider existing capacity as investment in 2009 to use the # same logic as inv_rsc when assigning to gid. - exist_columns = ["tech", "region", "year", "bin", "MW"] + exist_columns = ["tech", "class", "region", "year", "bin", "MW"] if "existing_capacity" in df_sc_in: if "online_year" not in df_sc_in: raise KeyError( @@ -333,11 +333,9 @@ class that can be used to check capacity values at the end of disaggregation. # Get check for capacity cap_chk = os.path.join(run_folder, "outputs", "cap.csv") df_cap_chk = pd.read_csv( - cap_chk, low_memory=False, names=["tech", "region", "year", "MW"], header=0 - ) - df_cap_chk[["tech_cat", "class"]] = df_cap_chk["tech"].str.rsplit( - "_", n=1, expand=True + cap_chk, low_memory=False, names=["tech", "class", "region", "year", "MW"], header=0 ) + df_cap_chk["tech_cat"] = df_cap_chk["tech"].str.rsplit("_", n=1).str[0] df_cap_chk = df_cap_chk[df_cap_chk["tech_cat"] == tech].copy() df_cap_chk = df_cap_chk[["year", "region", "class", "MW"]].dropna(subset=["class"]) df_cap_chk["class"] = df_cap_chk["class"].astype("int") @@ -370,8 +368,8 @@ def get_new_investments(run_folder, tech): df_inv_rsc = pd.read_csv( inv_rsc, low_memory=False, - names=["tech", "vintage", "region", "year", "bin", "MW"], - usecols=["tech", "region", "year", "bin", "MW"], + names=["tech", "class", "vintage", "region", "year", "bin", "MW"], + usecols=["tech", "class", "region", "year", "bin", "MW"], header=0, ) df_inv_rsc = df_inv_rsc[df_inv_rsc["tech"].str.startswith(tech)].copy() @@ -401,8 +399,6 @@ def combine_preexisting_and_new_investments(df_bin_exist, df_inv_rsc): """ # Concatenate existing and inv_rsc df_inv = pd.concat([df_bin_exist, df_inv_rsc], sort=False, ignore_index=True) - # Split tech from class - df_inv[["tech_cat", "class"]] = df_inv["tech"].str.rsplit("_", n=1, expand=True) df_inv = df_inv[["year", "region", "class", "bin", "MW"]] df_inv["class"] = df_inv["class"].astype("int") df_inv["bin"] = df_inv["bin"].str.replace("bin", "", regex=False).astype("int") @@ -435,9 +431,9 @@ def get_input_refurbishments(run_folder, tech): df_inv_refurb_in = pd.read_csv( inv_refurb, low_memory=False, - names=["tech", "vintage", "region", "year", "MW"], + names=["tech", "class", "vintage", "region", "year", "MW"], header=0, - usecols=["tech", "region", "year", "MW"], + usecols=["tech", "class", "region", "year", "MW"], ) df_inv_refurb_in = df_inv_refurb_in[ df_inv_refurb_in["tech"].str.startswith(tech) @@ -462,14 +458,7 @@ def amend_refurbishments(df_inv_refurb_in): Returns refurbishments for the given technology, by year, region, and class. Output columns include: ["year", "region", "class", "MW"] """ - # Split tech from class df_inv_refurb = df_inv_refurb_in.copy() - if df_inv_refurb.empty: - df_inv_refurb[["tech_cat", "class"]] = "" - else: - df_inv_refurb[["tech_cat", "class"]] = df_inv_refurb["tech"].str.split( - "_", n=1, expand=True - ) df_inv_refurb = df_inv_refurb[["year", "region", "class", "MW"]] df_inv_refurb["class"] = df_inv_refurb["class"].astype("int") df_inv_refurb = df_inv_refurb.sort_values(by=["year", "region", "class"]) @@ -593,9 +582,9 @@ def get_exogenous_capacity(run_folder, tech): df_cap_exog = pd.read_csv( cap_exog, low_memory=False, - names=["tech", "vintage", "region", "year", "MW"], + names=["tech", "class", "vintage", "region", "year", "MW"], header=0, - usecols=["tech", "region", "year", "MW"], + usecols=["tech", "class", "region", "year", "MW"], ) df_cap_exog = df_cap_exog[df_cap_exog["tech"].str.startswith(tech)].copy() @@ -1540,7 +1529,7 @@ def simultaneous_fill( break # check to make sure inv_left isn't negative if ret_left < 0: - print(f"ERROR at rcby={rcby}: ret_left is negative: {ret_left}") + print(f"ERROR at rcy={rcy}: ret_left is negative: {ret_left}") if np.floor(ret_left * 100) / 100 != 0: print( @@ -1607,7 +1596,7 @@ def simultaneous_fill( # check to make sure inv_left isn't negative if refurb_left < 0: print( - f"ERROR at rcby={rcby}: refurb_left is negative: {refurb_left}" + f"ERROR at rcy={rcy}: refurb_left is negative: {refurb_left}" ) if round(refurb_left, 2) != 0: @@ -2016,7 +2005,7 @@ def check_tech(run_folder, tech): """ cap_chk = os.path.join(run_folder, "outputs", "cap.csv") df_cap = pd.read_csv( - cap_chk, low_memory=False, names=["tech", "region", "year", "MW"], header=0 + cap_chk, low_memory=False, names=["tech", "class", "region", "year", "MW"], header=0 ) tech_included = df_cap["tech"].str.startswith(tech).any() diff --git a/postprocessing/bokehpivot/reeds2.py b/postprocessing/bokehpivot/reeds2.py index ee1413e50..81cd092fd 100644 --- a/postprocessing/bokehpivot/reeds2.py +++ b/postprocessing/bokehpivot/reeds2.py @@ -476,9 +476,10 @@ def pre_abatement_cost(dfs, **kw): return df def add_class(df, **kw): - cond = df['tech'].str.contains('_', regex=False) - #Assume class is at the end, after the final underscore: - df.loc[cond, 'class']='class_' + df.loc[cond, 'tech'].str.split('_').str[-1] + #Class is read from the class column; '0' marks techs with no resource class + cond = df['class'].astype(str) != '0' + df.loc[cond, 'class'] = 'class_' + df.loc[cond, 'class'].astype(str) + df.loc[~cond, 'class'] = None return df def sort_timeslices(df, **kw): @@ -817,12 +818,12 @@ def pre_lcoe(dfs, **kw): #Apply inflation dfs['lcoe']['$/MWh'] = inflate_series(dfs['lcoe']['$/MWh']) #Merge with available capacity - df = pd.merge(left=dfs['lcoe'], right=dfs['avail'], how='left', on=['tech', 'rb', 'year', 'bin'], sort=False) + df = pd.merge(left=dfs['lcoe'], right=dfs['avail'], how='left', on=['tech', 'class', 'rb', 'year', 'bin'], sort=False) df['available MW'] = df['available MW'].fillna(0) df['available'] = 'no' df.loc[df['available MW'] > 0.001, 'available'] = 'yes' #Merge with chosen capacity - df = pd.merge(left=df, right=dfs['inv'], how='left', on=['tech', 'vintage', 'rb', 'year', 'bin'], sort=False) + df = pd.merge(left=df, right=dfs['inv'], how='left', on=['tech', 'class', 'vintage', 'rb', 'year', 'bin'], sort=False) df['chosen MW'] = df['chosen MW'].fillna(0) df['chosen'] = 'no' df.loc[df['chosen MW'] != 0, 'chosen'] = 'yes' @@ -1375,7 +1376,7 @@ def pre_spur(dfs, **kw): ('Capacity BA (GW)', {'file':'cap', - 'columns': ['tech', 'rb', 'year', 'Capacity (GW)'], + 'columns': ['tech', 'class', 'rb', 'year', 'Capacity (GW)'], 'preprocess': [ {'func': scale_column, 'args': {'scale_factor': .001, 'column':'Capacity (GW)'}}, ], @@ -1395,7 +1396,7 @@ def pre_spur(dfs, **kw): ('Capacity BA by class (GW)', {'file':'cap', - 'columns': ['tech', 'rb', 'year', 'Capacity (GW)'], + 'columns': ['tech', 'class', 'rb', 'year', 'Capacity (GW)'], 'preprocess': [ {'func': add_class, 'args': {}}, {'func': scale_column, 'args': {'scale_factor': .001, 'column':'Capacity (GW)'}}, @@ -1407,7 +1408,7 @@ def pre_spur(dfs, **kw): ('Capacity ivrt (GW)', {'file':'cap_ivrt', - 'columns': ['tech', 'vintage', 'rb', 'year','Capacity (GW)'], + 'columns': ['tech', 'class', 'vintage', 'rb', 'year','Capacity (GW)'], 'preprocess': [ {'func': scale_column, 'args': {'scale_factor': .001, 'column':'Capacity (GW)'}}, ], @@ -1456,7 +1457,7 @@ def pre_spur(dfs, **kw): ('Storage Capacity (GW or GWh)', {'sources': [ - {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'rb', 'year', 'Capacity (GW)']}, + {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'class', 'rb', 'year', 'Capacity (GW)']}, {'name': 'energy', 'file': 'stor_energy_cap', 'columns': ['tech', 'vintage', 'rb', 'year', 'Energy (GWh)']}, {'name': 'bcr', 'file': '../inputs_case/bcr.csv', 'columns': ['tech', 'bcr']}, ], @@ -1540,7 +1541,7 @@ def pre_spur(dfs, **kw): ('Exogenous capacity (GW)', {'file':'cap_exog', - 'columns': ['tech', 'vintage', 'region', 'year', 'Capacity (GW)'], + 'columns': ['tech', 'class', 'vintage', 'region', 'year', 'Capacity (GW)'], 'preprocess': [ {'func': scale_column, 'args': {'scale_factor': .001, 'column':'Capacity (GW)'}}, ], @@ -1893,7 +1894,7 @@ def pre_spur(dfs, **kw): ('Capacity Factor ivrt', {'sources': [ {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year','MWh']}, - {'name': 'cap', 'file': 'cap_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year','MW']}, + {'name': 'cap', 'file': 'cap_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year','MW']}, ], 'preprocess': [ {'func': pre_cf, 'args': {}}, @@ -1979,7 +1980,7 @@ def pre_spur(dfs, **kw): ('Firm Capacity National (GW)', {'sources': [ {'name': 'firmcap', 'file': 'cap_firm', 'columns': ['tech', 'rb', 'season', 'year', 'Firm Capacity (GW)']}, - {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'rb', 'year', 'Capacity (GW)']}, + {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'class', 'rb', 'year', 'Capacity (GW)']}, ], 'index': ['tech', 'season', 'year'], 'preprocess': [ @@ -1997,7 +1998,7 @@ def pre_spur(dfs, **kw): ('Firm Capacity BA (GW)', {'sources': [ {'name': 'firmcap', 'file': 'cap_firm', 'columns': ['tech', 'rb', 'season', 'year', 'Firm Capacity (GW)']}, - {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'rb', 'year', 'Capacity (GW)']}, + {'name': 'cap', 'file': 'cap', 'columns': ['tech', 'class', 'rb', 'year', 'Capacity (GW)']}, ], 'index': ['tech', 'rb', 'season', 'year'], 'preprocess': [ @@ -2464,7 +2465,7 @@ def pre_spur(dfs, **kw): ('Value Streams Sequential New Techs', {'sources': [ {'name': 'vs', 'file': 'valuestreams_chosen.csv', 'columns': ['tech', 'vintage', 'rb', 'year', 'var_name', 'con_name', '$']}, - {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MW']}, + {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'MW']}, {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'pvf_cap', 'file': 'pvf_capital', 'columns': ['year', 'pvfcap']}, {'name': 'pvf_onm', 'file': 'pvf_onm', 'columns': ['year', 'pvfonm']}, @@ -2494,7 +2495,7 @@ def pre_spur(dfs, **kw): ('Competitiveness Sequential New Techs', {'sources': [ {'name': 'vs', 'file': 'valuestreams_chosen.csv', 'columns': ['tech', 'vintage', 'rb', 'year', 'var_name', 'con_name', '$']}, - {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MW']}, + {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'MW']}, {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'pvf_cap', 'file': 'pvf_capital', 'columns': ['year', 'pvfcap']}, {'name': 'pvf_onm', 'file': 'pvf_onm', 'columns': ['year', 'pvfonm']}, @@ -2530,7 +2531,7 @@ def pre_spur(dfs, **kw): ('LCOE ($/MWh) Sequential New Techs (uncurt MWh)', {'sources': [ {'name': 'vs', 'file': 'valuestreams_chosen.csv', 'columns': ['tech', 'vintage', 'rb', 'year', 'var_name', 'con_name', '$']}, - {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MW']}, + {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'MW']}, {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'gen_uncurt', 'file': 'gen_ivrt_uncurt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'pvf_cap', 'file': 'pvf_capital', 'columns': ['year', 'pvfcap']}, @@ -2550,7 +2551,7 @@ def pre_spur(dfs, **kw): ('Value Streams Sequential Existing Techs', {'sources': [ {'name': 'vs', 'file': 'valuestreams_chosen.csv', 'columns': ['tech', 'vintage', 'rb', 'year', 'var_name', 'con_name', '$']}, - {'name': 'cap', 'file': 'cap_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MW']}, + {'name': 'cap', 'file': 'cap_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'MW']}, {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'pvf_cap', 'file': 'pvf_capital', 'columns': ['year', 'pvfcap']}, {'name': 'pvf_onm', 'file': 'pvf_onm', 'columns': ['year', 'pvfonm']}, @@ -2573,7 +2574,7 @@ def pre_spur(dfs, **kw): ('Value Streams Intertemporal', {'sources': [ {'name': 'vs', 'file': 'valuestreams_chosen.csv', 'columns': ['tech', 'vintage', 'rb', 'year', 'var_name', 'con_name', '$']}, - {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MW']}, + {'name': 'cap', 'file': 'cap_new_ivrt', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'MW']}, {'name': 'gen', 'file': 'gen_ivrt', 'columns': ['tech', 'vintage', 'rb', 'year', 'MWh']}, {'name': 'pvf_cap', 'file': 'pvf_capital', 'columns': ['year', 'pvfcap']}, {'name': 'pvf_onm', 'file': 'pvf_onm', 'columns': ['year', 'pvfonm']}, @@ -2679,9 +2680,9 @@ def pre_spur(dfs, **kw): ('LCOE ($/MWh)', {'sources': [ - {'name': 'lcoe', 'file': 'lcoe', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','$/MWh']}, - {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','chosen MW']}, - {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'rb', 'year', 'bin','available MW']}, + {'name': 'lcoe', 'file': 'lcoe', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','$/MWh']}, + {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','chosen MW']}, + {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'class', 'rb', 'year', 'bin','available MW']}, ], 'preprocess': [ {'func': pre_lcoe, 'args': {}}, @@ -2697,9 +2698,9 @@ def pre_spur(dfs, **kw): ('LCOE cf_act ($/MWh)', {'sources': [ - {'name': 'lcoe', 'file': 'lcoe_cf_act', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','$/MWh']}, - {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','chosen MW']}, - {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'rb', 'year', 'bin','available MW']}, + {'name': 'lcoe', 'file': 'lcoe_cf_act', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','$/MWh']}, + {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','chosen MW']}, + {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'class', 'rb', 'year', 'bin','available MW']}, ], 'preprocess': [ {'func': pre_lcoe, 'args': {}}, @@ -2715,9 +2716,9 @@ def pre_spur(dfs, **kw): ('LCOE nopol ($/MWh)', {'sources': [ - {'name': 'lcoe', 'file': 'lcoe_nopol', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','$/MWh']}, - {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','chosen MW']}, - {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'rb', 'year', 'bin','available MW']}, + {'name': 'lcoe', 'file': 'lcoe_nopol', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','$/MWh']}, + {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','chosen MW']}, + {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'class', 'rb', 'year', 'bin','available MW']}, ], 'preprocess': [ {'func': pre_lcoe, 'args': {}}, @@ -2733,9 +2734,9 @@ def pre_spur(dfs, **kw): ('LCOE fullpol ($/MWh)', {'sources': [ - {'name': 'lcoe', 'file': 'lcoe_fullpol', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','$/MWh']}, - {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'vintage', 'rb', 'year', 'bin','chosen MW']}, - {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'rb', 'year', 'bin','available MW']}, + {'name': 'lcoe', 'file': 'lcoe_fullpol', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','$/MWh']}, + {'name': 'inv', 'file': 'cap_new_bin_out', 'columns': ['tech', 'class', 'vintage', 'rb', 'year', 'bin','chosen MW']}, + {'name': 'avail', 'file': 'cap_avail', 'columns': ['tech', 'class', 'rb', 'year', 'bin','available MW']}, ], 'preprocess': [ {'func': pre_lcoe, 'args': {}}, @@ -2837,7 +2838,7 @@ def pre_spur(dfs, **kw): {'name':'tran_mi_out', 'file':'tran_mi_out', 'columns':['trtype', 'year', 'Amount (GW-mi)']}, {'name':'tran_prm_mi_out', 'file':'tran_prm_mi_out', 'columns':['trtype', 'year', 'Trans cap, PRM (GW-mi)']}, {'name':'spur_parameters', 'file':'../inputs_case/spur_parameters.csv'}, - {'name':'cap_new_bin_out', 'file':'cap_new_bin_out', 'columns':['i','v','r','year','rscbin','MW']}, + {'name':'cap_new_bin_out', 'file':'cap_new_bin_out', 'columns':['i','c','v','r','year','rscbin','MW']}, {'name': 'scalars', 'file': '../inputs_case/scalars.csv', 'header':None, 'columns': ['scalar', 'value', 'comment']}, ], 'preprocess': [ diff --git a/postprocessing/compare_cases.py b/postprocessing/compare_cases.py index c03d8f868..4391a3d05 100644 --- a/postprocessing/compare_cases.py +++ b/postprocessing/compare_cases.py @@ -661,7 +661,9 @@ def plot_bars_abs_stacked( 'RPS': {'title': 'Non-RecMap\nRECS\n[GWh]', 'scale':1e-3}, 'OpRes': {'title': 'Non-valgen\nopres\n[MWh]', 'scale':1}, 'm_rsc_dat': {'title': 'Supply curve\ntweaks [GW]', 'scale':1e-3}, + 'cspns': {'title': 'Unassigned\ncsp-ns [MW]', 'scale':1}, 'dropped': {'title': 'Dropped load\n[GWh]', 'scale':1e-3}, + 'excess': {'title': 'Excess load\n[GWh]', 'scale':1e-3}, } data = {k:v for k,v in data.items() if k in dfplot.index} diff --git a/postprocessing/uncertainty_plots.py b/postprocessing/uncertainty_plots.py index 8e8f9f4a9..3f61a7dde 100644 --- a/postprocessing/uncertainty_plots.py +++ b/postprocessing/uncertainty_plots.py @@ -588,6 +588,10 @@ def _fetch_cap_out(self, case: str) -> pd.DataFrame: columns={'Value': 'Capacity (GW)', 't': 'year', 'i': 'tech'}, inplace=True, ) + + # Sum over resource class + df = df.groupby(['tech', 'r', 'year'], as_index=False)['Capacity (GW)'].sum() + return df @@ -973,7 +977,8 @@ def apply_transformations( items_map = Conventions.items_color_map[items_map_name][0] if items_column == 'tech': df['tech'] = df['tech'].str.lower().map(lambda x: items_map.get(x, x)) - df = df.groupby(['tech', 'r', 'year']).sum().reset_index() + valcols = df.select_dtypes('number').columns.difference(['year']) + df = df.groupby(['tech', 'r', 'year'])[valcols].sum().reset_index() # Fill missing techs with 0 idx = pd.MultiIndex.from_product( diff --git a/reeds/core/setup/b_inputs.gms b/reeds/core/setup/b_inputs.gms index e809c33c4..d1ba57cf6 100644 --- a/reeds/core/setup/b_inputs.gms +++ b/reeds/core/setup/b_inputs.gms @@ -1641,10 +1641,11 @@ m_capacity_exog(i,v,r,t)$capacity_exog(i,v,r,t) = capacity_exog(i,v,r,t) ; m_capacity_exog_energy(i,v,r,t)$capacity_exog_energy(i,v,r,t) = capacity_exog_energy(i,v,r,t) ; m_capacity_exog(i,"init-1",r,t)$geo(i) = geo_cap_exog(i,r) ; -* We assign the ~1.3 GW of exising csp-ns to upv throughout the model, but then -* convert 1.3 GW of upv back to csp-ns in the output processing. +* We assign the ~1.3 GW of existing csp-ns to upv throughout the model, both in the +* exogenous and the prescribed capacity, and convert it back to csp-ns when reporting. +* Written by writecapdat.py $onempty -parameter cap_cspns(r,allt) "--MW-- csp-ns capacity" +parameter cap_cspns(c,r,allt) "--MW-- csp-ns capacity modeled as upv, by resource class" / $offlisting $ondelim diff --git a/reeds/core/setup/c_model.gms b/reeds/core/setup/c_model.gms index dab5b9aef..66ca00f8a 100644 --- a/reeds/core/setup/c_model.gms +++ b/reeds/core/setup/c_model.gms @@ -37,7 +37,7 @@ positive variables EXTRA_PRESCRIP_ENERGY(i,v,r,t) "--MWh-- builds beyond those prescribed battery energy capacity once allowed in firstyear(i)" INV_CAP_UP(i,v,r,rscbin,t) "--MW-- upsized generation capacity addition in year t" INV_ENER_UP(i,v,r,rscbin,t) "--MW-- upsized energy addition in year t using capacity factor to convert to capacity units" - INV_REFURB(i,v,r,t) "--MW-- investment in refurbishments of technologies that use a resource supply curve" + INV_REFURB(i,c,v,r,t) "--MW-- investment in refurbishments of technologies that use a resource supply curve" INV_RSC(i,c,v,r,rscbin,t) "--MW-- investment in technologies that use a resource supply curve" UPGRADES(i,v,r,t) "--MW-- investments in upgraded capacity from ii to i" UPGRADES_RETIRE(i,v,r,t) "--MW-- upgrades that have been retired - used as a free slack variable in eq_cap_upgrade" @@ -694,7 +694,7 @@ eq_cap_new_noret(i,v,r,t)$[valcap(i,v,r,t)$tmodel(t)$newv(v)$(not upgrade(i)) $(not retiretech(i,v,r,t))$(not Sw_PCM)].. sum{tt$[inv_cond(i,v,r,t,tt)$(tmodel(tt) or tfix(tt))$valcap(i,v,r,tt)], - degrade(i,tt,t) * (INV(i,v,r,tt) + INV_REFURB(i,v,r,tt)$[refurbtech(i)$Sw_Refurb]) + degrade(i,tt,t) * (INV(i,v,r,tt) + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,tt) }$[refurbtech(i)$Sw_Refurb]) } - sum{(tt,ttt)$[inv_cond(i,v,r,tt,ttt)$(tmodel(tt) or tfix(tt))$valcap(i,v,r,ttt)$(tt.val>=ttt.val)$(t.val>=tt.val)], @@ -751,7 +751,7 @@ eq_cap_new_retub(i,v,r,t)$[valcap(i,v,r,t)$tmodel(t)$newv(v)$(not upgrade(i)) $retiretech(i,v,r,t)$(not Sw_PCM)].. sum{tt$[inv_cond(i,v,r,t,tt)$(tmodel(tt) or tfix(tt))$valcap(i,v,r,tt)], - degrade(i,tt,t) * (INV(i,v,r,tt) + INV_REFURB(i,v,r,tt)$[refurbtech(i)$Sw_Refurb]) + degrade(i,tt,t) * (INV(i,v,r,tt) + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,tt) }$[refurbtech(i)$Sw_Refurb]) } - sum{(tt,ttt)$[inv_cond(i,v,r,tt,ttt)$(tmodel(tt) or tfix(tt))$valcap(i,v,r,ttt)$(tt.val>=ttt.val)$(t.val>=tt.val)], @@ -802,7 +802,7 @@ eq_cap_new_retmo(i,v,r,t)$[valcap(i,v,r,t)$tmodel(t)$newv(v)$(not upgrade(i)) + INV(i,v,r,t)$valinv(i,v,r,t) - + INV_REFURB(i,v,r,t)$[valinv(i,v,r,t)$refurbtech(i)$Sw_Refurb] + + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,t) }$[valinv(i,v,r,t)$refurbtech(i)$Sw_Refurb] * Account for capacity upsizing within new vintages + sum{rscbin$allow_cap_up(i,v,r,rscbin,t), INV_CAP_UP(i,v,r,rscbin,t) } @@ -948,7 +948,7 @@ eq_forceprescription_power(i,newv,r,t) *capacity built in the current period or prior - INV(i,newv,r,t) + INV_REFURB(i,newv,r,t)$[refurbtech(i)$Sw_Refurb] + INV(i,newv,r,t) + sum{c$i_c(i,c), INV_REFURB(i,c,newv,r,t) }$[refurbtech(i)$Sw_Refurb] =e= @@ -1012,8 +1012,8 @@ eq_refurblim(i,r,t)$[tmodel(t)$refurbtech(i)$Sw_Refurb$(not Sw_PCM)].. *must exceed the total sum of investments in refurbishments *that have yet to expire - implying an investment can be refurbished more than once *if the first refurbishment has exceed its age limit - sum{(vv,tt)$[inv_cond(i,vv,r,t,tt)$(tmodel(tt) or tfix(tt))$valinv(i,vv,r,tt)], - INV_REFURB(i,vv,r,tt) + sum{(c,vv,tt)$[i_c(i,c)$inv_cond(i,vv,r,t,tt)$(tmodel(tt) or tfix(tt))$valinv(i,vv,r,tt)], + INV_REFURB(i,c,vv,r,tt) } ; @@ -1400,7 +1400,7 @@ eq_interconnection_queues(tg,r,t) sum{(i,newv,tt)$[valinv(i,newv,r,tt)$tg_i(tg,i) $(yeart(tt)>=interconnection_start) $(tmodel(tt) or tfix(tt))], - INV(i,newv,r,tt) + INV_REFURB(i,newv,r,tt)$[refurbtech(i)$Sw_Refurb] } + INV(i,newv,r,tt) + sum{c$i_c(i,c), INV_REFURB(i,c,newv,r,tt) }$[refurbtech(i)$Sw_Refurb] } ; *=============================== @@ -1732,7 +1732,7 @@ eq_reserve_margin(r,ccseason,t) *only used in sequential solve case (otherwise m_cc_mar = 0) *Note: new distpv is included with cc_old + sum{(i,v)$[(vre(i) or csp(i) or pvb(i))$valinv(i,v,r,t)$(not forced_retire(i,r,t))], - m_cc_mar(i,r,ccseason,t) * (INV(i,v,r,t) + INV_REFURB(i,v,r,t)$[refurbtech(i)$Sw_Refurb]) + m_cc_mar(i,r,ccseason,t) * (INV(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,t) }$[refurbtech(i)$Sw_Refurb]) } *[plus] firm capacity contribution from all binned storage capacity @@ -2818,7 +2818,7 @@ eq_RPS_OFSWind(st,t)$[tmodel(t)$stfeas(st)$offshore_cap_req(st,t)$Sw_StateRPS * investments over time + sum{(i,v,r,tt)$[r_st(r,st)$ofswind(i)$inv_cond(i,v,r,t,tt)$(tmodel(tt) or tfix(tt))], - INV(i,v,r,tt) + INV_REFURB(i,v,r,tt)$[refurbtech(i)$Sw_Refurb] } + INV(i,v,r,tt) + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,tt) }$[refurbtech(i)$Sw_Refurb] } =g= diff --git a/reeds/core/setup/d_objective.gms b/reeds/core/setup/d_objective.gms index 1298021be..51cb27c6d 100644 --- a/reeds/core/setup/d_objective.gms +++ b/reeds/core/setup/d_objective.gms @@ -77,7 +77,7 @@ eq_ObjFn_inv(t)$tmodel(t).. * --- cost of water access--- + [ (8760/1E6) * sum{ (i,v,w,r)$[i_w(i,w)$valinv(i,v,r,t)], sum{wst$i_wst(i,wst), m_watsc_dat(wst,"cost",r,t) } * water_rate(i,w) * - ( INV(i,v,r,t) + INV_REFURB(i,v,r,t)$[refurbtech(i)$Sw_Refurb] ) } + ( INV(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB(i,c,v,r,t) }$[refurbtech(i)$Sw_Refurb] ) } + sum{(rscbin,i,c,v,r)$[i_c(i,c)$m_rscfeas(r,i,c,rscbin)$psh(i)], sum{wst$i_wst(i,wst), m_watsc_dat(wst,"cost",r,t) } * INV_RSC(i,c,v,r,rscbin,t) * water_req_psh(r,rscbin) }$Sw_PSHwatercon @@ -88,8 +88,8 @@ eq_ObjFn_inv(t)$tmodel(t).. + sum{(wst,r), 1E6 * WATER_CAPACITY_LIMIT_SLACK(wst,r,t) }$[Sw_WaterMain$Sw_WaterCapacity] * --- cost of refurbishments of RSC tech--- - + sum{(i,v,r)$[Sw_Refurb$valinv(i,v,r,t)$refurbtech(i)], - cost_cap_fin_mult(i,r,t) * cost_cap(i,t) * INV_REFURB(i,v,r,t) + + sum{(i,c,v,r)$[i_c(i,c)$Sw_Refurb$valinv(i,v,r,t)$refurbtech(i)], + cost_cap_fin_mult(i,r,t) * cost_cap(i,t) * INV_REFURB(i,c,v,r,t) } * --- cost of interzonal AC transmission--- @@ -213,7 +213,7 @@ eq_Objfn_op(t)$tmodel(t).. cost_fom(i,v,r,t) * retire_penalty(t) * (CAP(i,v,r,t) - INV(i,v,r,t)$valinv(i,v,r,t) - - INV_REFURB(i,v,r,t)$[valinv(i,v,r,t)$refurbtech(i)$Sw_Refurb] + - sum{c$i_c(i,c), INV_REFURB(i,c,v,r,t) }$[valinv(i,v,r,t)$refurbtech(i)$Sw_Refurb] - UPGRADES(i,v,r,t)$[upgrade(i)$Sw_Upgrades] ) } diff --git a/reeds/core/solve/5_varfix.gms b/reeds/core/solve/5_varfix.gms index 63da328cc..29998ad9a 100644 --- a/reeds/core/solve/5_varfix.gms +++ b/reeds/core/solve/5_varfix.gms @@ -8,6 +8,7 @@ if(Sw_RemoveSmallNumbers = 1, CAP_ABOVE_LIM.l(tg,r,tfix)$[abs(CAP_ABOVE_LIM.l(tg,r,tfix)) < rhs_tolerance] = 0 ; INV.l(i,v,r,tfix)$[abs(INV.l(i,v,r,tfix)) < rhs_tolerance] = 0 ; INV_ENERGY.l(i,v,r,tfix)$[abs(INV_ENERGY.l(i,v,r,tfix)) < rhs_tolerance] = 0 ; + INV_REFURB.l(i,c,v,r,tfix)$[abs(INV_REFURB.l(i,c,v,r,tfix)) < rhs_tolerance] = 0 ; INV_RSC.l(i,c,v,r,rscbin,tfix)$[abs(INV_RSC.l(i,c,v,r,rscbin,tfix)) < rhs_tolerance] = 0 ; INV_POI.l(r,tfix)$[abs(INV_POI.l(r,tfix)) < rhs_tolerance] = 0 ; H2_STOR_INV.l(h2_stor,r,tfix)$[abs(H2_STOR_INV.l(h2_stor,r,tfix)) < rhs_tolerance] = 0 ; @@ -36,7 +37,7 @@ CAP_SDBIN_ENERGY.fx(i,v,r,ccseason,sdbin,tfix)$[valcap(i,v,r,tfix)$battery(i)$Sw GROWTH_BIN.fx(gbin,i,st,tfix)$[sum{r$[r_st(r,st)], valinv_irt(i,r,tfix) }$stfeas(st)$Sw_GrowthPenalties$(yeart(tfix)<=Sw_GrowthPenLastYear)] = GROWTH_BIN.l(gbin,i,st,tfix) ; INV.fx(i,v,r,tfix)$[valinv(i,v,r,tfix)] = INV.l(i,v,r,tfix) ; INV_ENERGY.fx(i,v,r,tfix)$[valinv(i,v,r,tfix)$battery(i)] = INV_ENERGY.l(i,v,r,tfix) ; -INV_REFURB.fx(i,v,r,tfix)$[valinv(i,v,r,tfix)$refurbtech(i)] = INV_REFURB.l(i,v,r,tfix) ; +INV_REFURB.fx(i,c,v,r,tfix)$[i_c(i,c)$valinv(i,v,r,tfix)$refurbtech(i)] = INV_REFURB.l(i,c,v,r,tfix) ; INV_RSC.fx(i,c,v,r,rscbin,tfix)$[i_c(i,c)$valinv(i,v,r,tfix)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)] = INV_RSC.l(i,c,v,r,rscbin,tfix) ; CAP_RSC.fx(i,c,v,r,rscbin,tfix)$[i_c(i,c)$valcap(i,v,r,tfix)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)] = CAP_RSC.l(i,c,v,r,rscbin,tfix) ; INV_CAP_UP.fx(i,v,r,rscbin,tfix)$[allow_cap_up(i,v,r,rscbin,tfix)] = INV_CAP_UP.l(i,v,r,rscbin,tfix) ; diff --git a/reeds/core/solve/6_data_dump.gms b/reeds/core/solve/6_data_dump.gms index 3dfb9f515..732a4d7e2 100644 --- a/reeds/core/solve/6_data_dump.gms +++ b/reeds/core/solve/6_data_dump.gms @@ -39,12 +39,12 @@ cap_exist(i,v,r) "--MW-- capacity that exists in the current s cap_exog_filt(i,v,r) "--MW-- exogenous capacity" cap_hyd_szn_adj_filt(i,allszn,r) "--fraction-- seasonal hydro capacity adjustment filtered for the previous solve year" cap_init(i,v,r) "--MW-- initial capacity" -cap_ivrt(i,v,r,t) "--MW-- generation power capacity" +cap_ivrt(i,c,v,r,t) "--MW-- generation power capacity" cap_energy_ivrt(i,v,r,t) "--MWh-- generation energy capacity" cap_pvb(i,v,r) "--MW-- Hybrid PV+battery capacity (PV)" cap_trans_energy(r,rr,trtype) "--MW-- transmission capacity for energy trading" cap_trans_prm(r,rr,trtype) "--MW-- transmission capacity for PRM trading" -cf_adj_t_filt(i,v,t) "--fraction-- capacity factor adjustment for wind" +cf_adj_t_filt(i,c,v,t) "--fraction-- capacity factor adjustment for wind" cost_cap_filt(i,t) "--2004$/MW-- technology capital costs" cost_cap_fin_mult_filt(i,r,t) "--unitless-- capital cost financial multipliers" cost_vom_filt(i,v,r) "--$/MWh-- VO&M costs filtered for the previous solve year and existing capacity" @@ -60,16 +60,16 @@ gen_h_stress_filt(i,r,allh,t) "--MW-- generation by stress timeslice with c heat_rate_filt(i,v,r) "--MMBtu/MWh-- heat rate" h2_usage_regional(r,allh,t) "--metric tons-- H2 usage by region" inv_cond_filt(i,v,t) "--set-- vintage-year mapping for investments by technology" -inv_ivrt(i,v,r,t) "--MW-- investments in power generation capacity" +inv_ivrt(i,c,v,r,t) "--MW-- investments in power generation capacity" inv_energy_ivrt(i,v,r,t) "--MWh-- investments in energy generation capacity" -m_cf_filt(i,v,r,allh) "--fraction-- capacity factor used in the model" +m_cf_filt(i,c,v,r,allh) "--fraction-- capacity factor used in the model" m_cf_szn_filt(i,v,r,allszn) "--fraction-- modelled capacity factors filtered for hydro resources to set seasonal energy constraints" minloadfrac_filt(r,i,allszn) "--fraction-- modelled mingen fraction filtered for hydro resources to set mingen constraints" prod_filt(i,v,r,allh) "--MW-- power consumed for PRODUCE.l" ra_cap_loadsite(r,t) "--MW-- capacity of flexibly sited load" repbioprice_filt(r) "--2004$/MWh-- marginal price for biofuel in region where biofuel was used" repgasquant(cendiv,t) "--mmBTU-- NG fuel usage in ReEDS - used to determine NG price" -ret_ivrt(i,v,r,t) "--MW-- retirements of generation capacity" +ret_ivrt(i,c,v,r,t) "--MW-- retirements of generation capacity" ret(i,v,r) "--MW-- retirements of generation capacity" rsc_dat_filt(i,r,sc_cat,rscbin) "--$/MW-- capital costs filtered for pumped-hydro so arbitrage value doesn't exceed capital costs" storage_eff_filt(i) "--fraction-- storage efficiency filtered for the next solve year" @@ -118,23 +118,29 @@ cap_exist_ir(i,r)$valcap_ir_filt(i,r) = sum{v, cap_exist(i,v,r) } ; cap_exist_iv(i,v)$valcap_iv_filt(i,v) = sum{r, cap_exist(i,v,r) } ; cap_exist_i(i)$valcap_i_filt(i) = sum{(r,v), cap_exist(i,v,r) } ; -cap_ivrt(i,v,r,t)$([not (upv(i) or wind(i))]$valcap(i,v,r,t)$trange(t)) = CAP.l(i,v,r,t) ; +cap_ivrt(i,c,v,r,t)$[i_c(i,c)$(not (upv(i) or wind(i)))$valcap(i,v,r,t)$trange(t)] = CAP.l(i,v,r,t) ; +cap_ivrt(i,c,v,r,t)$[valcap_class(i,c,v,r,t)$(not (upv(i) or wind(i)))$trange(t)] = CAP_CLASS.l(i,c,v,r,t) ; cap_energy_ivrt(i,v,r,t)$[valcap(i,v,r,t)$trange(t)$battery(i)] = CAP_ENERGY.l(i,v,r,t) ; -cap_ivrt(i,v,r,t)$([upv(i) or wind(i)]$valcap(i,v,r,t)) = - m_capacity_exog(i,v,r,t)$trange(t) +cap_ivrt(i,c,v,r,t)$[i_c(i,c)$(upv(i) or wind(i))$valcap(i,v,r,t)] = + sum{rscbin, capacity_exog_rsc(i,c,v,r,rscbin,t) }$trange(t) + sum{tt$[inv_cond(i,v,r,t,tt)$trange(tt)], - INV.l(i,v,r,tt) + INV_REFURB.l(i,v,r,tt)$[refurbtech(i)$Sw_Refurb]} ; -cap_init(i,v,r)$([not distpv(i)]$valcap_ivr(i,v,r)) = sum{t$tcur(t), cap_ivrt(i,v,r,t)$initv(v) } ; -cap_init(i,v,r)$(distpv(i)$valcap_ivr(i,v,r)) = sum{t$tfirst(t), cap_ivrt(i,v,r,t) } ; -inv_ivrt(i,v,r,t)$[valcap(i,v,r,t)$trange(t)] = [INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)]$valinv(i,v,r,t) + UPGRADES.l(i,v,r,t)$[upgrade(i)$valcap(i,v,r,t)$Sw_Upgrades] ; + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,tt) } + + INV_REFURB.l(i,c,v,r,tt)$[refurbtech(i)$Sw_Refurb]} ; +cap_init(i,v,r)$([not distpv(i)]$valcap_ivr(i,v,r)) = sum{(c,t)$[i_c(i,c)$tcur(t)], cap_ivrt(i,c,v,r,t)$initv(v) } ; +cap_init(i,v,r)$(distpv(i)$valcap_ivr(i,v,r)) = sum{(c,t)$[i_c(i,c)$tfirst(t)], cap_ivrt(i,c,v,r,t) } ; +inv_ivrt(i,c,v,r,t)$[i_c(i,c)$valcap(i,v,r,t)$trange(t)] = + [INV.l(i,v,r,t)$(not rsc_i(i)) + + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,t) }$rsc_i(i) + + INV_REFURB.l(i,c,v,r,t)]$valinv(i,v,r,t) + + UPGRADES.l(i,v,r,t)$[upgrade(i)$valcap(i,v,r,t)$Sw_Upgrades] ; inv_energy_ivrt(i,v,r,t)$[valcap(i,v,r,t)$trange(t)$battery(i)] = INV_ENERGY.l(i,v,r,t); -inv_ivrt("distpv",v,r,t)$([trange(t)$(not tfirst(t))]$valcap("distpv",v,r,t)) = cap_ivrt("distpv",v,r,t) - sum{tt$tprev(t,tt), cap_ivrt("distpv",v,r,tt) } ; -inv_ivrt("distpv","init-1",r,"%next_year%") = inv_distpv(r,"%next_year%") ; +inv_ivrt("distpv",c,v,r,t)$[i_c("distpv",c)$trange(t)$(not tfirst(t))$valcap("distpv",v,r,t)] = cap_ivrt("distpv",c,v,r,t) - sum{tt$tprev(t,tt), cap_ivrt("distpv",c,v,r,tt) } ; +inv_ivrt("distpv",c,"init-1",r,"%next_year%")$i_c("distpv",c) = inv_distpv(r,"%next_year%") ; -ret_ivrt(i,v,r,t)$([trange(t)$(not tfirst(t))$newv(v)]$valcap(i,v,r,t)) = sum{tt$tprev(t,tt), cap_ivrt(i,v,r,tt)} - cap_ivrt(i,v,r,t) + inv_ivrt(i,v,r,t) ; -ret_ivrt(i,v,r,t)$([abs(ret_ivrt(i,v,r,t) < 1e-6)]$valcap(i,v,r,t)) = 0 ; +ret_ivrt(i,c,v,r,t)$[i_c(i,c)$trange(t)$(not tfirst(t))$newv(v)$valcap(i,v,r,t)] = sum{tt$tprev(t,tt), cap_ivrt(i,c,v,r,tt)} - cap_ivrt(i,c,v,r,t) + inv_ivrt(i,c,v,r,t) ; +ret_ivrt(i,c,v,r,t)$([abs(ret_ivrt(i,c,v,r,t) < 1e-6)]$valcap(i,v,r,t)) = 0 ; -ret(i,v,r)$valcap_ivr(i,v,r) = sum{t, ret_ivrt(i,v,r,t) } ; +ret(i,v,r)$valcap_ivr(i,v,r) = sum{(c,t)$i_c(i,c), ret_ivrt(i,c,v,r,t) } ; cap_exog_filt(i,v,r)$([not canada(i)]$valcap_ivr(i,v,r)) = sum{t$tnext(t), m_capacity_exog(i,v,r,t) } ; @@ -215,8 +221,8 @@ cost_cap_fin_mult_filt(i,r,t)$([storage_standalone(i)]) = cost_cap_fin_mult(i,r, cost_vom_filt(i,v,r)$cap_exist(i,v,r) = sum{t$tcur(t), cost_vom(i,v,r,t) } ; -cf_adj_t_filt(i,v,t)$[cap_exist_iv(i,v)$trange(t)] = sum{c$i_c(i,c), cf_adj_t(i,c,v,t) } ; -cf_adj_t_filt(i,v,"%next_year%") = sum{c$i_c(i,c), cf_adj_t(i,c,v,"%next_year%") }$(vre(i) or pvb(i)) ; +cf_adj_t_filt(i,c,v,t)$[i_c(i,c)$cap_exist_iv(i,v)$trange(t)] = cf_adj_t(i,c,v,t) ; +cf_adj_t_filt(i,c,v,"%next_year%")$i_c(i,c) = cf_adj_t(i,c,v,"%next_year%")$(vre(i) or pvb(i)) ; ctt_i_ii_filt(i,ii) = ctt_i_ii(i,ii)$cap_exist_i(i) ; @@ -228,7 +234,7 @@ heat_rate_filt(i,v,r)$cap_exist(i,v,r) = sum{t$tcur(t), heat_rate(i,v,r,t) } ; inv_cond_filt(i,v,t)$[(vre(i) or pvb(i))$tnext(t)] = sum{(tt,r), inv_cond(i,v,r,tt,t) } ; -m_cf_filt(i,v,r,h)$[(vre(i) or pvb(i))$cap_exist(i,v,r)] = sum{(t,c)$[tnext(t)$i_c(i,c)], m_cf(i,c,v,r,h,t) } ; +m_cf_filt(i,c,v,r,h)$[i_c(i,c)$(vre(i) or pvb(i))$cap_exist(i,v,r)] = sum{t$tnext(t), m_cf(i,c,v,r,h,t) } ; m_cf_szn_filt(i,v,r,szn)$[hydro(i)$cap_exist(i,v,r)] = sum{t$tcur(t), m_cf_szn(i,v,r,szn,t) } ; diff --git a/reeds/core/terminus/report.gms b/reeds/core/terminus/report.gms index a11b561bd..c661e5f60 100644 --- a/reeds/core/terminus/report.gms +++ b/reeds/core/terminus/report.gms @@ -189,7 +189,7 @@ avg_cf(i,v,r,t)$[CAP.l(i,v,r,t)$(not rsc_i(i))] = *LCOE calculation is appropriate for sequential solve mode only where annual energy production is the same in every year. *In inter-temporal modes this isn't the case and energy production should be discounted appropriately. -lcoe(i,v,r,t,"bin1")$[(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_avail(i,v,r)] = +lcoe(i,c,v,r,t,"bin1")$[i_c(i,c)$(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_avail(i,v,r)] = * cost of capacity divided by generation ((crf(t) * cost_cap_fin_mult(i,r,t) * cost_cap(i,t)$newv(v) + cost_fom(i,v,r,t) @@ -200,26 +200,26 @@ lcoe(i,v,r,t,"bin1")$[(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_avail(i + heat_rate(i,v,r,t) * fuel_price(i,r,t) ; -gen_rsc(i,v,r,t)$[valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)] = - sum{(h,c)$i_c(i,c), m_cf(i,c,v,r,h,t) * hours(h) } ; +gen_rsc(i,c,v,r,t)$[i_c(i,c)$valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)] = + sum{h, m_cf(i,c,v,r,h,t) * hours(h) } ; -lcoe(i,v,r,t,rscbin)$[valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$sum{c, m_rscfeas(r,i,c,rscbin) }$gen_rsc(i,v,r,t)] = +lcoe(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)$gen_rsc(i,c,v,r,t)] = * cost of capacity divided by generation (crf(t) * (cost_cap_fin_mult(i,r,t) * cost_cap(i,t) * Spur-line costs embedded in supply curve for techs without explicitly-modeled spurlines - + sum{c, m_rsc_dat(r,i,c,rscbin,"cost") }$[newv(v)$(not spur_techs(i))] + + m_rsc_dat(r,i,c,rscbin,"cost")$[newv(v)$(not spur_techs(i))] * Spur-line costs assuming 1:1 ratio between gen cap and spur cap (i.e. no overbuilding) + sum{x$[xfeas(x)$x_r(x,r)$spur_techs(i)], spurline_cost(x) * Sw_SpurCostMult} ) + cost_fom(i,v,r,t) - ) / gen_rsc(i,v,r,t) + ) / gen_rsc(i,c,v,r,t) *plus VOM costs + cost_vom(i,v,r,t) ; -lcoe_cf_act(i,v,r,t,rscbin)$[valcap_init(i,v,r,t)$rsc_i(i)] = lcoe(i,v,r,t,rscbin) ; -lcoe_cf_act(i,v,r,t,"bin1")$[(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_cf(i,v,r,t)] = +lcoe_cf_act(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)$rsc_i(i)] = lcoe(i,c,v,r,t,rscbin) ; +lcoe_cf_act(i,c,v,r,t,"bin1")$[i_c(i,c)$(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_cf(i,v,r,t)] = * cost of capacity divided by generation ((crf(t) * cost_cap_fin_mult(i,r,t) * cost_cap(i,t)$newv(v) + cost_fom(i,v,r,t) @@ -231,32 +231,32 @@ lcoe_cf_act(i,v,r,t,"bin1")$[(not rsc_i(i))$valcap_init(i,v,r,t)$ivt(i,v,t)$avg_ + heat_rate(i,v,r,t) * fuel_price(i,r,t) ; -lcoe_nopol(i,v,r,t,rscbin)$valcap_init(i,v,r,t) = lcoe(i,v,r,t,rscbin) ; -lcoe_nopol(i,v,r,t,rscbin)$[valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$sum{c, m_rscfeas(r,i,c,rscbin) }$gen_rsc(i,v,r,t)] = +lcoe_nopol(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)] = lcoe(i,c,v,r,t,rscbin) ; +lcoe_nopol(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)$gen_rsc(i,c,v,r,t)] = * cost of capacity divided by generation (crf(t) * (cost_cap_fin_mult_noITC(i,r,t) * cost_cap(i,t) * Spur-line costs embedded in supply curve for techs without explicitly-modeled spurlines - + sum{c, m_rsc_dat(r,i,c,rscbin,"cost") }$newv(v)$(not spur_techs(i))) + + m_rsc_dat(r,i,c,rscbin,"cost")$newv(v)$(not spur_techs(i))) * Spur-line costs assuming 1:1 ratio between gen cap and spur cap (i.e. no overbuilding) + sum{x$[xfeas(x)$x_r(x,r)$spur_techs(i)], spurline_cost(x) * Sw_SpurCostMult} + cost_fom(i,v,r,t) - ) / gen_rsc(i,v,r,t) + ) / gen_rsc(i,c,v,r,t) *plus VOM costs + cost_vom(i,v,r,t) ; -lcoe_fullpol(i,v,r,t,rscbin)$valcap_init(i,v,r,t) = lcoe(i,v,r,t,rscbin) ; -lcoe_fullpol(i,v,r,t,rscbin)$[valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$sum{c, m_rscfeas(r,i,c,rscbin) }$gen_rsc(i,v,r,t)] = +lcoe_fullpol(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)] = lcoe(i,c,v,r,t,rscbin) ; +lcoe_fullpol(i,c,v,r,t,rscbin)$[i_c(i,c)$valcap_init(i,v,r,t)$ivt(i,v,t)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)$gen_rsc(i,c,v,r,t)] = * cost of capacity divided by generation (crf(t) * (cost_cap_fin_mult(i,r,t) * cost_cap(i,t) * Spur-line costs embedded in supply curve for techs without explicitly-modeled spurlines - + sum{c, m_rsc_dat(r,i,c,rscbin,"cost") }$newv(v)$(not spur_techs(i))) + + m_rsc_dat(r,i,c,rscbin,"cost")$newv(v)$(not spur_techs(i))) * Spur-line costs assuming 1:1 ratio between gen cap and spur cap (i.e. no overbuilding) + sum{x$[xfeas(x)$x_r(x,r)$spur_techs(i)], spurline_cost(x) * Sw_SpurCostMult} + cost_fom(i,v,r,t)) - / gen_rsc(i,v,r,t) + / gen_rsc(i,c,v,r,t) *plus VOM costs + cost_vom(i,v,r,t) ; @@ -650,17 +650,41 @@ gen_h(i,r,h,t)$[tmodel_new(t)$valgen_irt(i,r,t)] = * less load from hydrogen production - sum{(v,p)$[consume(i)$valcap(i,v,r,t)$i_p(i,p)], PRODUCE.l(p,i,v,r,h,t) / prod_conversion_rate(i,v,r,t)}$Sw_Prod ; +* Capacity is needed here to reassign csp-ns, so calculate it before generation. +cap_deg_ivrt(i,c,v,r,t)$[i_c(i,c)$valcap(i,v,r,t)] = CAP.l(i,v,r,t) / ilr(i) ; +cap_deg_ivrt(i,c,v,r,t)$valcap_class(i,c,v,r,t) = CAP_CLASS.l(i,c,v,r,t) / ilr(i) ; + +cap_ivrt(i,c,v,r,t)$[i_c(i,c)$(not (upv(i) or wind(i)))$valcap(i,v,r,t)] = cap_deg_ivrt(i,c,v,r,t) ; +*upv, and wind have degradation, so use INV rather than CAP to get the reported capacity +cap_ivrt(i,c,v,r,t)$[i_c(i,c)$(upv(i) or wind(i))$valcap(i,v,r,t)] = ( + sum{rscbin, capacity_exog_rsc(i,c,v,r,rscbin,t) }$tmodel_new(t) + + sum{tt$[inv_cond(i,v,r,t,tt)$[tmodel(tt) or tfix(tt)]], + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,tt) } + + INV_REFURB.l(i,c,v,r,tt)$[refurbtech(i)$Sw_Refurb]}) / ilr(i) ; + * A small amount of upv capacity is actually csp-ns, so convert it back now. -* UPV capacity is already in MWac at this point (matching csp-ns), -* so don't need to account for ILR. -gen_h("csp-ns",r,h,t)$[cap_cspns(r,t)$tmodel_new(t)] - = cap_cspns(r,t) * sum{c$i_c("upv_5",c), m_cf("upv_5",c,"new1",r,h,t) } ; -* We have to take csp-ns generation from somewhere, so take it from upv_5 (which all the -* csp-ns-containing regions have) -gen_h("upv_5",r,h,t)$[cap_cspns(r,t)$tmodel_new(t)] - = gen_h("upv_5",r,h,t) - gen_h("csp-ns",r,h,t) ; -* Make sure it doesn't go negative, just in case -gen_h("upv_5",r,h,t)$[cap_cspns(r,t)$tmodel_new(t)$(gen_h("upv_5",r,h,t) < 0)] = 0 ; +* writecapdat.py bins csp-ns into the upv resource classes it is modeled as, so take it +* back out of those same classes. cap_cspns_short catches any csp-ns left with no upv to +* come out of, which means the capacity written by writecapdat.py and the capacity carried +* by the model have diverged. +* cap_upv_class uses the same undegraded basis as cap_ivrt so that the capacity moved out +* of upv and the generation that goes with it are taken from the same denominator. +cap_upv_class(c,r,t)$tmodel_new(t) = + sum{(i,v)$[upv(i)$i_c(i,c)$valcap(i,v,r,t)], cap_ivrt(i,c,v,r,t) } ; + +cap_cspns_short(c,r,t)$[cap_cspns(c,r,t)$tmodel_new(t)] = + max(0, cap_cspns(c,r,t) - cap_upv_class(c,r,t)) ; + +* Move the generation that goes with the reassigned capacity, class by class +gen_h("csp-ns",r,h,t)$[sum{c, cap_cspns(c,r,t) }$tmodel_new(t)] = + sum{(i,c)$[upv(i)$i_c(i,c)$cap_upv_class(c,r,t)], + gen_h(i,r,h,t) * min(cap_cspns(c,r,t), cap_upv_class(c,r,t)) / cap_upv_class(c,r,t) } ; + +gen_h(i,r,h,t)$[upv(i)$tmodel_new(t)$sum{c$i_c(i,c), cap_cspns(c,r,t) } + $sum{c$i_c(i,c), cap_upv_class(c,r,t) }] = + gen_h(i,r,h,t) + * (1 - sum{c$i_c(i,c), + min(cap_cspns(c,r,t), cap_upv_class(c,r,t)) / cap_upv_class(c,r,t) }) ; gen_h_nat(i,h,t)$tmodel_new(t) = sum{r, gen_h(i,r,h,t) } ; * Do it again for stress periods @@ -680,7 +704,7 @@ gen_ann_nat(i,t)$tmodel_new(t) = sum{r, gen_ann(i,r,t) } ; * Report generation without the charging and production included as above gen_ivrt(i,v,r,t)$valgen(i,v,r,t) = sum{h, GEN.l(i,v,r,h,t) * hours(h) } ; gen_ivrt_uncurt(i,v,r,t)$[(vre(i) or storage_hybrid(i)$(not csp(i)))$valgen(i,v,r,t)] = - sum{(h,c)$i_c(i,c), m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) * hours(h) } ; + sum{(h,c)$valcap_class(i,c,v,r,t), m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) * hours(h) } ; * Report generation that will be used as a denominator in outputs, where VRE uses uncurtailed gen and storage uses GEN gen_uncurtailed(i,r,t)$[valgen_irt(i,r,t)$(not vre(i))] = sum{v, gen_ivrt(i,v,r,t) } ; @@ -709,7 +733,7 @@ watcap_new_out(i,r,t)$[valcap_irt(i,r,t)$i_water_cooling(i)] = hours(h) * sum{w$[i_w(i,w)], water_rate(i,w) } - * ( sum{v$valinv(i,v,r,t), INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)} + * ( sum{v$valinv(i,v,r,t), INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }} + sum{v$valcap(i,v,r,t), (1-upgrade_derate(i,v,r,t)) * (UPGRADES.l(i,v,r,t) - UPGRADES_RETIRE.l(i,v,r,t))}$[upgrade(i)$Sw_Upgrades] ) * (1 + sum{(v,szn), h_szn(h,szn) * seas_cap_frac_delta(i,v,r,szn,t)}) @@ -721,7 +745,7 @@ watcap_new_ivrt(i,v,r,t)$[valcap(i,v,r,t)$i_water_cooling(i)] = hours(h) * sum{w$[i_w(i,w)], water_rate(i,w) } - * ( [INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)]$valinv(i,v,r,t) + * ( [INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }]$valinv(i,v,r,t) + [(1-upgrade_derate(i,v,r,t)) * (UPGRADES.l(i,v,r,t) - UPGRADES_RETIRE.l(i,v,r,t))]$[upgrade(i)$valcap(i,v,r,t)$Sw_Upgrades] ) * (1 + sum{szn, h_szn(h,szn) * seas_cap_frac_delta(i,v,r,szn,t)}) } / 1E6 @@ -758,13 +782,13 @@ opres_trade(ortype,r,rr,t)$[opres_routes(r,rr,t)$tmodel_new(t)] = *========================= gen_new_uncurt(i,r,h,t)$[(vre(i) or storage_hybrid(i)$(not csp(i)))$valcap_irt(i,r,t)] = - sum{(v,c)$[valinv(i,v,r,t)$i_c(i,c)], (INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)) * m_cf(i,c,v,r,h,t) * hours(h) } + sum{(v,c)$[i_c(i,c)$valinv(i,v,r,t)], (INV.l(i,v,r,t) + INV_REFURB.l(i,c,v,r,t)) * m_cf(i,c,v,r,h,t) * hours(h) } ; * curtailment = (availability - generation - operating reserves) curt_h(r,h,t)$tmodel_new(t) = - sum{(i,v,c)$[valcap(i,v,r,t)$(vre(i) or storage_hybrid(i)$(not csp(i)))$i_c(i,c)], - m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) } + sum{(i,v,c)$[valcap_class(i,c,v,r,t)$(vre(i) or storage_hybrid(i)$(not csp(i)))], + m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) } - sum{(i,v)$[valgen(i,v,r,t)$vre(i)], GEN.l(i,v,r,h,t) } - sum{(i,v)$[valgen(i,v,r,t)$storage_hybrid(i)$(not csp(i))], GEN_PLANT.l(i,v,r,h,t) }$Sw_HybridPlant - sum{(ortype,i,v)$[Sw_OpRes$opres_h(h)$reserve_frac(i,ortype)$valgen(i,v,r,t)$vre(i)], @@ -774,8 +798,8 @@ curt_h(r,h,t)$tmodel_new(t) = curt_ann(r,t)$tmodel_new(t) = sum{h, curt_h(r,h,t) * hours(h) } ; curt_tech(i,r,t)$[tmodel_new(t)$vre(i)] = - sum{(v,h,c)$[valcap(i,v,r,t)$i_c(i,c)], - m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) * hours(h) } + sum{(v,h,c)$[valcap_class(i,c,v,r,t)], + m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) * hours(h) } - sum{(v,h)$valgen(i,v,r,t), GEN.l(i,v,r,h,t) * hours(h) } - sum{(ortype,v,h)$[Sw_OpRes$opres_h(h)$reserve_frac(i,ortype)$valgen(i,v,r,t)], @@ -813,29 +837,20 @@ losses_tran_h(rr,r,h,trtype,t)$[routes(r,rr,trtype,t)$tmodel_new(t)] * CAPACITY *========================= -cap_deg_ivrt(i,v,r,t)$valcap(i,v,r,t) = CAP.l(i,v,r,t) / ilr(i) ; - -cap_ivrt(i,v,r,t)$[(not (upv(i) or wind(i)))$valcap(i,v,r,t)] = cap_deg_ivrt(i,v,r,t) ; -*upv, and wind have degradation, so use INV rather than CAP to get the reported capacity -cap_ivrt(i,v,r,t)$[(upv(i) or wind(i))$valcap(i,v,r,t)] = ( - m_capacity_exog(i,v,r,t)$tmodel_new(t) - + sum{tt$[inv_cond(i,v,r,t,tt)$[tmodel(tt) or tfix(tt)]], - INV.l(i,v,r,tt) + INV_REFURB.l(i,v,r,tt)$[refurbtech(i)$Sw_Refurb]}) / ilr(i) ; - -cap_out(i,r,t)$[valcap_irt(i,r,t)$tmodel_new(t)] = sum{v$valcap(i,v,r,t), cap_ivrt(i,v,r,t) } ; +cap_out(i,c,r,t)$[i_c(i,c)$valcap_irt(i,r,t)$tmodel_new(t)] = sum{v$valcap(i,v,r,t), cap_ivrt(i,c,v,r,t) } ; * A small amount of upv capacity is actually csp-ns, so convert it back now. * UPV capacity is already in MWac at this point (matching csp-ns), * so don't need to account for ILR -cap_out("csp-ns",r,t)$[cap_cspns(r,t)$tmodel_new(t)] = cap_cspns(r,t) ; -* We have to take csp-ns capacity from somewhere, so take it from upv_6 (which all the -* csp-ns-containing regions have) -cap_out("upv_5",r,t)$[cap_cspns(r,t)$tmodel_new(t)] = cap_out("upv_5",r,t) - cap_cspns(r,t) ; -* Make sure it doesn't go negative, just in case -cap_out("upv_5",r,t)$[cap_cspns(r,t)$tmodel_new(t)$(cap_out("upv_5",r,t) < 0)] = 0 ; -cap_nat(i,t)$tmodel_new(t) = sum{r, cap_out(i,r,t) } ; +cap_out("csp-ns",c,r,t)$[i_c("csp-ns",c)$tmodel_new(t)] = sum{cc, cap_cspns(cc,r,t) } ; +* Take it back out of the same upv classes it was binned into +cap_out(i,c,r,t)$[upv(i)$i_c(i,c)$cap_cspns(c,r,t)$tmodel_new(t)] = + max(0, cap_out(i,c,r,t) - cap_cspns(c,r,t)) ; +cap_nat(i,t)$tmodel_new(t) = sum{(c,r)$i_c(i,c), cap_out(i,c,r,t) } ; * Exogenous capacity (used by reeds_to_rev) -cap_exog(i,v,r,t)$tmodel_new(t) = m_capacity_exog(i,v,r,t) ; +cap_exog(i,c,v,r,t)$[i_c(i,c)$tmodel_new(t)] = m_capacity_exog(i,v,r,t) ; +cap_exog(i,c,v,r,t)$[i_c(i,c)$tmodel_new(t)$exog_rsc(i)] = + sum{rscbin, capacity_exog_rsc(i,c,v,r,rscbin,t) } ; *========================= * NEW CAPACITY @@ -843,26 +858,28 @@ cap_exog(i,v,r,t)$tmodel_new(t) = m_capacity_exog(i,v,r,t) ; cap_new_out(i,r,t)$[valcap_irt(i,r,t)] = [ sum{v$valinv(i,v,r,t), - INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t) } + INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) } } + sum{v$valcap(i,v,r,t), (1 - upgrade_derate(i,v,r,t)) * (UPGRADES.l(i,v,r,t) - UPGRADES_RETIRE.l(i,v,r,t))}$[upgrade(i)$Sw_Upgrades] ] / ilr(i) ; * Capacity of distpv is not tracked in INV because it is an exogenous input, so use the change in cap_out to calculate new capacity * (except for the first year, in which all distpv capacity is counted as new) -cap_new_out("distpv",r,t)$[tfirst(t)$valcap_irt("distpv",r,t)] = cap_out("distpv",r,t) ; -cap_new_out("distpv",r,t)$[(not tfirst(t))$valcap_irt("distpv",r,t)] = cap_out("distpv",r,t) - sum{tt$tprev(t,tt), cap_out("distpv",r,tt) } ; +cap_new_out("distpv",r,t)$[tfirst(t)$valcap_irt("distpv",r,t)] = sum{c$i_c("distpv",c), cap_out("distpv",c,r,t) } ; +cap_new_out("distpv",r,t)$[(not tfirst(t))$valcap_irt("distpv",r,t)] = sum{c$i_c("distpv",c), cap_out("distpv",c,r,t) - sum{tt$tprev(t,tt), cap_out("distpv",c,r,tt) } } ; cap_new_ann(i,r,t)$cap_new_out(i,r,t) = cap_new_out(i,r,t) / (yeart(t) - sum{tt$tprev(t,tt), yeart(tt) }) ; cap_new_ann_nat(i,t)$tmodel_new(t) = sum{r, cap_new_ann(i,r,t) } ; -cap_new_bin_out(i,v,r,t,rscbin)$[rsc_i(i)$valinv(i,v,r,t)] = - sum{c$i_c(i,c), INV_RSC.l(i,c,v,r,rscbin,t) } / ilr(i) ; -cap_new_bin_out(i,v,r,t,"bin1")$[(not rsc_i(i))$valinv(i,v,r,t)] = INV.l(i,v,r,t) / ilr(i) ; -cap_new_ivrt(i,v,r,t)$[valcap(i,v,r,t)] = [ - [INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)]$valinv(i,v,r,t) - + [(1-upgrade_derate(i,v,r,t)) * (UPGRADES.l(i,v,r,t) - UPGRADES_RETIRE.l(i,v,r,t))]$[upgrade(i)$valcap(i,v,r,t)$Sw_Upgrades] +cap_new_bin_out(i,c,v,r,t,rscbin)$[i_c(i,c)$rsc_i(i)$valinv(i,v,r,t)] = + INV_RSC.l(i,c,v,r,rscbin,t) / ilr(i) ; +cap_new_bin_out(i,c,v,r,t,"bin1")$[i_c(i,c)$(not rsc_i(i))$valinv(i,v,r,t)] = INV.l(i,v,r,t) / ilr(i) ; +cap_new_ivrt(i,c,v,r,t)$[i_c(i,c)$valcap(i,v,r,t)] = [ + [INV.l(i,v,r,t)$(not rsc_i(i)) + + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,t) }$rsc_i(i) + + INV_REFURB.l(i,c,v,r,t)]$valinv(i,v,r,t) + + [(1-upgrade_derate(i,v,r,t)) * (UPGRADES.l(i,v,r,t) - UPGRADES_RETIRE.l(i,v,r,t))]$[upgrade(i)$valcap(i,v,r,t)$Sw_Upgrades] ] / ilr(i) ; -cap_new_ivrt("distpv",v,r,t)$[tfirst(t)$valcap("distpv",v,r,t)] = cap_ivrt("distpv",v,r,t) ; -cap_new_ivrt("distpv",v,r,t)$[(not tfirst(t))$valcap("distpv",v,r,t)] = cap_ivrt("distpv",v,r,t) - sum{tt$tprev(t,tt), cap_ivrt("distpv",v,r,tt) } ; -cap_new_ivrt_refurb(i,v,r,t)$valinv(i,v,r,t) = INV_REFURB.l(i,v,r,t) / ilr(i) ; +cap_new_ivrt("distpv",c,v,r,t)$[i_c("distpv",c)$tfirst(t)$valcap("distpv",v,r,t)] = cap_ivrt("distpv",c,v,r,t) ; +cap_new_ivrt("distpv",c,v,r,t)$[i_c("distpv",c)$(not tfirst(t))$valcap("distpv",v,r,t)] = cap_ivrt("distpv",c,v,r,t) - sum{tt$tprev(t,tt), cap_ivrt("distpv",c,v,r,tt) } ; +cap_new_ivrt_refurb(i,c,v,r,t)$[i_c(i,c)$valinv(i,v,r,t)] = INV_REFURB.l(i,c,v,r,t) / ilr(i) ; * Capacity by reV site site_spurinv(x,t)$[tmodel_new(t)$xfeas(x)] = INV_SPUR.l(x,t) ; @@ -871,10 +888,10 @@ site_spurcap(x,t)$[tmodel_new(t)$xfeas(x)] = CAP_SPUR.l(x,t) ; site_cap(i,x,t)$[tmodel_new(t)$sum{(c,r,rscbin), spurline_sitemap(i,c,r,rscbin,x)}] = sum{(c,v,r,rscbin,tt) $[spurline_sitemap(i,c,r,rscbin,x) - $cap_new_bin_out(i,v,r,tt,rscbin) + $cap_new_bin_out(i,c,v,r,tt,rscbin) $(yeart(tt) <= yeart(t))], * Multiply by ILR to get DC capacity for PV - cap_new_bin_out(i,v,r,tt,rscbin) * ilr(i) + cap_new_bin_out(i,c,v,r,tt,rscbin) * ilr(i) } ; site_gir(i,x,t)$[site_cap(i,x,t)$site_spurcap(x,t)] = site_cap(i,x,t) / site_spurcap(x,t) ; @@ -887,21 +904,21 @@ site_hybridization(x,t)$site_pv_fraction(x,t) = abs(1 - 2 * abs(site_pv_fraction *========================= * AVAILABLE CAPACITY *========================= -cap_avail(i,r,t,rscbin)$[tmodel_new(t)$rsc_i(i)$sum{c, m_rscfeas(r,i,c,rscbin) }$sum{c, m_rsc_con(r,i,c) }] = - sum{c, m_rsc_dat(r,i,c,rscbin,"cap") } +cap_avail(i,c,r,t,rscbin)$[i_c(i,c)$tmodel_new(t)$rsc_i(i)$m_rscfeas(r,i,c,rscbin)$m_rsc_con(r,i,c)] = + m_rsc_dat(r,i,c,rscbin,"cap") + hyd_add_upg_cap(r,i,rscbin,t)$(Sw_HydroCapEnerUpgradeType=1) - ( - sum{(ii,c,v,tt)$[rsc_agg(i,ii)$i_c(ii,c)$valinv(ii,v,r,tt)$(yeart(tt) < yeart(t))], + sum{(ii,v,tt)$[rsc_agg(i,ii)$i_c(ii,c)$valinv(ii,v,r,tt)$(yeart(tt) < yeart(t))], INV_RSC.l(ii,c,v,r,rscbin,tt) * resourcescaler(ii) } - + sum{(ii,c,v,tt)$[rsc_agg(i,ii)$i_c(ii,c)$tfirst(tt)$exog_rsc(i)], + + sum{(ii,v,tt)$[rsc_agg(i,ii)$i_c(ii,c)$tfirst(tt)$exog_rsc(i)], capacity_exog_rsc(ii,c,v,r,rscbin,tt) } ); capacity_offline(i,r,allh,t) $[valcap_irt(i,r,t)$tmodel_new(t)$(h_stress_t(allh,t) or h_rep(allh))] = - cap_out(i,r,t) * (1 - avail(i,r,allh)) ; + sum{c$i_c(i,c), cap_out(i,c,r,t) } * (1 - avail(i,r,allh)) ; forced_outage(i) = sum{(r,h), outage_forced_h(i,r,h) * hours(h) } / sum{(r,h), hours(h) } ; planned_outage(i) = sum{h, outage_scheduled_h(i,h) * hours(h) } / sum{h, hours(h) } ; @@ -917,12 +934,12 @@ cap_upgrade_ivrt(i,v,r,t)$[valcap(i,v,r,t)$upgrade(i)$Sw_Upgrades] = (1-upgrade_ * RETIRED CAPACITY *========================= -ret_ivrt(i,v,r,t)$[(not tfirst(t))] = - sum{tt$tprev(t,tt), cap_ivrt(i,v,r,tt) } - cap_ivrt(i,v,r,t) + cap_new_ivrt(i,v,r,t) +ret_ivrt(i,c,v,r,t)$[i_c(i,c)$(not tfirst(t))] = + sum{tt$tprev(t,tt), cap_ivrt(i,c,v,r,tt) } - cap_ivrt(i,c,v,r,t) + cap_new_ivrt(i,c,v,r,t) - sum{ii$upgrade_from(ii,i), UPGRADES.l(ii,v,r,t) } ; -ret_ivrt(i,v,r,t)$[abs(ret_ivrt(i,v,r,t)) < 1e-6] = 0 ; +ret_ivrt(i,c,v,r,t)$[abs(ret_ivrt(i,c,v,r,t)) < 1e-6] = 0 ; -ret_out(i,r,t)$[(not tfirst(t))] = sum{v, ret_ivrt(i,v,r,t) } ; +ret_out(i,r,t)$[(not tfirst(t))] = sum{(c,v)$i_c(i,c), ret_ivrt(i,c,v,r,t) } ; ret_out(i,r,t)$[abs(ret_out(i,r,t)) < 1e-6] = 0 ; ret_ann(i,r,t)$ret_out(i,r,t) = ret_out(i,r,t) / (yeart(t) - sum{tt$tprev(t,tt), yeart(tt) }) ; ret_ann_nat(i,t)$tmodel_new(t) = sum{r, ret_ann(i,r,t) } ; @@ -953,7 +970,7 @@ cc_all_out(i,v,r,ccseason,t)$tmodel_new(t) = m_cc_mar(i,r,ccseason,t)$[(vre(i) or csp(i) or storage(i) or storage_hybrid(i)$(not csp(i)))$valinv_init(i,v,r,t)] ; -cap_new_cc(i,r,ccseason,t)$[(vre(i) or storage(i) or storage_hybrid(i)$(not csp(i)))$valcap_irt(i,r,t)] = sum{v$ivt(i,v,t),cap_new_ivrt(i,v,r,t) } ; +cap_new_cc(i,r,ccseason,t)$[(vre(i) or storage(i) or storage_hybrid(i)$(not csp(i)))$valcap_irt(i,r,t)] = sum{(c,v)$[i_c(i,c)$ivt(i,v,t)], cap_new_ivrt(i,c,v,r,t) } ; cc_new(i,r,ccseason,t)$[valcap_irt(i,r,t)$cap_new_cc(i,r,ccseason,t)] = sum{v$ivt(i,v,t), cc_all_out(i,v,r,ccseason,t) } ; @@ -965,7 +982,7 @@ cap_firm(i,r,ccseason,t)$[valcap_irt(i,r,t)$[not consume(i)]$tmodel_new(t)$Sw_PR } + cc_old(i,r,ccseason,t) + sum{v$[(vre(i) or csp(i) or storage_hybrid(i)$(not csp(i)))$valinv(i,v,r,t)], - m_cc_mar(i,r,ccseason,t) * (INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)$[refurbtech(i)$Sw_Refurb]) } + m_cc_mar(i,r,ccseason,t) * (INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }$[refurbtech(i)$Sw_Refurb]) } + sum{v$[(vre(i) or csp(i) or storage_hybrid(i)$(not csp(i)))$valcap(i,v,r,t)], cc_int(i,v,r,ccseason,t) * CAP.l(i,v,r,t) } + cc_excess(i,r,ccseason,t)$[(vre(i) or csp(i) or storage_hybrid(i)$(not csp(i)))] @@ -1013,10 +1030,10 @@ revenue_en(rev_cat,i,r,t) revenue_en(rev_cat,i,r,t) $[tmodel_new(t) - $sum{(v,h,c)$[valcap(i,v,r,t)$i_c(i,c)], m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) } + $sum{(v,h,c)$valcap_class(i,c,v,r,t), m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) } $vre(i)] = - revenue(rev_cat,i,r,t) / sum{(v,h,c)$[valcap(i,v,r,t)$i_c(i,c)], - m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) * hours(h) } ; + revenue(rev_cat,i,r,t) / sum{(v,h,c)$valcap_class(i,c,v,r,t), + m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) * hours(h) } ; revenue_en_nat(rev_cat,i,t) $[tmodel_new(t) @@ -1026,15 +1043,15 @@ revenue_en_nat(rev_cat,i,t) revenue_en_nat(rev_cat,i,t) $[tmodel_new(t) - $sum{(v,r,h,c)$[valcap(i,v,r,t)$i_c(i,c)], m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) } + $sum{(v,r,h,c)$valcap_class(i,c,v,r,t), m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) } $vre(i)] = - revenue_nat(rev_cat,i,t) / sum{(v,r,h,c)$[valcap(i,v,r,t)$i_c(i,c)], - m_cf(i,c,v,r,h,t) * CAP.l(i,v,r,t) * hours(h) } ; + revenue_nat(rev_cat,i,t) / sum{(v,r,h,c)$valcap_class(i,c,v,r,t), + m_cf(i,c,v,r,h,t) * CAP_CLASS.l(i,c,v,r,t) * hours(h) } ; -revenue_cap(rev_cat,i,r,t)$[tmodel_new(t)$cap_out(i,r,t)] = - revenue(rev_cat,i,r,t) / cap_out(i,r,t) ; +revenue_cap(rev_cat,i,r,t)$[tmodel_new(t)$sum{c$i_c(i,c), cap_out(i,c,r,t) }] = + revenue(rev_cat,i,r,t) / sum{c$i_c(i,c), cap_out(i,c,r,t) } ; -revenue_cap_nat(rev_cat,i,t)$[tmodel_new(t)$sum{r$valcap_irt(i,r,t), cap_out(i,r,t) }] = +revenue_cap_nat(rev_cat,i,t)$[tmodel_new(t)$sum{(c,r)$[i_c(i,c)$valcap_irt(i,r,t)], cap_out(i,c,r,t) }] = revenue_nat(rev_cat,i,t) / cap_nat(i,t) ; *======================================== @@ -1042,9 +1059,9 @@ revenue_cap_nat(rev_cat,i,t)$[tmodel_new(t)$sum{r$valcap_irt(i,r,t), cap_out(i,r *======================================== valnew('MW',i,r,t)$[(not tfirst(t))$valcap_irt(i,r,t)] = - sum{v$valinv(i,v,r,t), INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t) } / ilr(i) ; + sum{v$valinv(i,v,r,t), INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) } } / ilr(i) ; valnew('inv_cap_ratio',i,r,t)$[valnew('MW',i,r,t)] = - sum{v$[valinv(i,v,r,t)$CAP.l(i,v,r,t)], (INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)) + sum{v$[valinv(i,v,r,t)$CAP.l(i,v,r,t)], (INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }) / CAP.l(i,v,r,t) } ; valnew('MWh',i,r,t)$[valnew('MW',i,r,t)] = sum{v$valinv(i,v,r,t), gen_ivrt(i,v,r,t)} * valnew('inv_cap_ratio',i,r,t) ; @@ -1219,11 +1236,13 @@ RE_gen_price_nat(t)$tmodel_new(t) = (1/cost_scale) * crf(t) * eq_national_gen.m( * [i,v,r,t]-level capital expenditures (for retail rate calculations) *========================= -capex_ivrt(i,v,r,t)$valcap(i,v,r,t) = - INV.l(i,v,r,t) * (cost_cap_fin_mult_no_credits(i,r,t) * cost_cap(i,t) ) +capex_ivrt(i,c,v,r,t)$[i_c(i,c)$valcap(i,v,r,t)] = + [INV.l(i,v,r,t)$(not rsc_i(i)) + + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,t) }$rsc_i(i)] + * (cost_cap_fin_mult_no_credits(i,r,t) * cost_cap(i,t) ) + INV_ENERGY.l(i,v,r,t) * (cost_cap_fin_mult_no_credits(i,r,t) * cost_cap_energy(i,t) ) - + sum{(c,rscbin)$[i_c(i,c)$m_rscfeas(r,i,c,rscbin)],INV_RSC.l(i,c,v,r,rscbin,t) * m_rsc_dat(r,i,c,rscbin,"cost") * cost_cap_fin_mult_no_credits(i,r,t) } - + (INV_REFURB.l(i,v,r,t) * (cost_cap_fin_mult_no_credits(i,r,t) * cost_cap(i,t)))$[refurbtech(i)$Sw_Refurb] + + sum{rscbin$m_rscfeas(r,i,c,rscbin), INV_RSC.l(i,c,v,r,rscbin,t) * m_rsc_dat(r,i,c,rscbin,"cost") * cost_cap_fin_mult_no_credits(i,r,t) } + + (INV_REFURB.l(i,c,v,r,t) * (cost_cap_fin_mult_no_credits(i,r,t) * cost_cap(i,t)))$[refurbtech(i)$Sw_Refurb] + UPGRADES.l(i,v,r,t) * (cost_upgrade(i,v,r,t) * cost_cap_fin_mult_no_credits(i,r,t))$[upgrade(i)$Sw_Upgrades] ; *========================= @@ -1315,13 +1334,13 @@ systemcost_techba("inv_investment_capacity_costs",i,r,t)$[tmodel_new(t)$consume( systemcost_techba("inv_investment_refurbishment_capacity",i,r,t)$tmodel_new(t) = *costs of refurbishments of RSC tech (without the subtraction of any ITC/PTC value) + sum{v$[Sw_Refurb$valinv(i,v,r,t)$refurbtech(i)], - (cost_cap_fin_mult_noITC(i,r,t) * cost_cap(i,t)) * INV_REFURB.l(i,v,r,t) } + (cost_cap_fin_mult_noITC(i,r,t) * cost_cap(i,t)) * sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) } } ; systemcost_techba("inv_itc_payments_negative_refurbishments",i,r,t)$tmodel_new(t) = *costs of refurbishments of RSC tech (including reduction from ITC) + sum{v$[Sw_Refurb$valinv(i,v,r,t)$refurbtech(i)], - (cost_cap_fin_mult_out(i,r,t) * cost_cap(i,t)) * INV_REFURB.l(i,v,r,t) } + (cost_cap_fin_mult_out(i,r,t) * cost_cap(i,t)) * sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) } } *minus capacity costs without ITC - systemcost_techba("inv_investment_refurbishment_capacity",i,r,t) ; @@ -1329,7 +1348,7 @@ systemcost_techba("inv_itc_payments_negative_refurbishments",i,r,t)$tmodel_new(t systemcost_techba("inv_investment_water_access",i,r,t)$tmodel_new(t) = *cost of water access + (8760/1E6) * sum{ (v,w)$[i_w(i,w)$valinv(i,v,r,t)], sum{wst$i_wst(i,wst), m_watsc_dat(wst,"cost",r,t)} * water_rate(i,w) * - ( INV.l(i,v,r,t) + INV_REFURB.l(i,v,r,t)$[refurbtech(i)$Sw_Refurb] ) } + ( INV.l(i,v,r,t) + sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }$[refurbtech(i)$Sw_Refurb] ) } + sum{(rscbin,c,v)$[i_c(i,c)$m_rscfeas(r,i,c,rscbin)$psh(i)], sum{wst$i_wst(i,wst), m_watsc_dat(wst,"cost",r,t) } * ( INV_RSC.l(i,c,v,r,rscbin,t) * water_req_psh(r,rscbin) ) } ; @@ -1356,7 +1375,7 @@ systemcost_techba("op_vom_costs",i,r,t)$[tmodel_new(t)$consume(i)] = 0 ; systemcost_techba("op_fom_costs",i,r,t)$tmodel_new(t) = *fixed O&M costs for generation capacity + sum{v$[valcap(i,v,r,t)$((not one_newv(i)) or retiretech(i,v,r,t))], - cost_fom(i,v,r,t) * cap_ivrt(i,v,r,t) * ilr(i) } + cost_fom(i,v,r,t) * sum{c$i_c(i,c), cap_ivrt(i,c,v,r,t) } * ilr(i) } *for technologies with only one newv that are not allowed to retire, *use the investments rather than the capacity to calculate FOM costs + sum{(v,tt)$[inv_cond(i,v,r,t,tt)$one_newv(i)$(not retiretech(i,v,r,tt))], @@ -1708,7 +1727,7 @@ error_check('z') = ( * Retirement penalty - pvf_onm(t) * sum{(i,v,r)$[valcap(i,v,r,t)$retiretech(i,v,r,t)$Sw_RetirePenalty], cost_fom(i,v,r,t) * retire_penalty(t) - * (CAP.l(i,v,r,t) - INV.l(i,v,r,t) - INV_REFURB.l(i,v,r,t)$[refurbtech(i)$Sw_Refurb] - UPGRADES.l(i,v,r,t)$[upgrade(i)$Sw_Upgrades]) } + * (CAP.l(i,v,r,t) - INV.l(i,v,r,t) - sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) }$[refurbtech(i)$Sw_Refurb] - UPGRADES.l(i,v,r,t)$[upgrade(i)$Sw_Upgrades]) } * Hurdle costs + pvf_onm(t) * sum{(r,rr,trtype)$cost_hurdle(r,rr,t), tran_hurdle_cost_ann(r,rr,trtype,t) } * Penalty cost for dropped/excess load before Sw_StartMarkets @@ -1717,9 +1736,9 @@ error_check('z') = ( + pvf_onm(t) * sum{(p,i,v,r,h)$[valcap(i,v,r,t)$i_p(i,p)$h_rep(h)$Sw_RetailAdder$Sw_Prod], hours(h) * Sw_RetailAdder * PRODUCE.l(p,i,v,r,h,t) / prod_conversion_rate(i,v,r,t) } * Account for difference in fixed O&M between model (CAP.l(i,v,r,t)) -* and outputs (cap_ivrt(i,v,r,t) * ilr(i)) for techs with more than one newv +* and outputs (cap_ivrt summed over class * ilr(i)) for techs with more than one newv + pvf_onm(t) * sum{(i,v,r)$[valcap(i,v,r,t)$((not one_newv(i)) or retiretech(i,v,r,t))], - cost_fom(i,v,r,t) * (CAP.l(i,v,r,t) - cap_ivrt(i,v,r,t) * ilr(i)) } + cost_fom(i,v,r,t) * (CAP.l(i,v,r,t) - sum{c$i_c(i,c), cap_ivrt(i,c,v,r,t) } * ilr(i)) } * Account for difference in fixed O&M between model (CAP.l(i,v,r,t)) * and outputs (based on INV.l) for techs with more only one newv that cannot retire + pvf_onm(t) * sum{(i,v,r)$[valcap(i,v,r,t)$(one_newv(i))$(not retiretech(i,v,r,t))], @@ -1762,7 +1781,7 @@ error_check('z') = ( * (cost_cap_fin_mult(i,r,t) - cost_cap_fin_mult_out(i,r,t)) } + sum{(i,v,r)$[Sw_Refurb$valinv(i,v,r,t)$refurbtech(i)], - cost_cap(i,t) * INV_REFURB.l(i,v,r,t) + cost_cap(i,t) * sum{c$i_c(i,c), INV_REFURB.l(i,c,v,r,t) } * (cost_cap_fin_mult(i,r,t) - cost_cap_fin_mult_out(i,r,t)) } ) * account for penalty paid to deploy capacity beyond interconnection queue limits @@ -1780,6 +1799,8 @@ error_check("cap") = sum{(i,v,r,t)$[not valcap(i,v,r,t)], CAP.l(i,v,r,t) } ; error_check("RPS") = sum{(RPSCat,i,st,ast,t)$[(not RecMap(i,RPSCat,st,ast,t))$[(not stfeas(ast)) or not sameas(ast,"voluntary")]], RECS.l(RPSCat,i,st,ast,t) } ; error_check("OpRes") = sum{(ortype,i,v,r,h,t)$[not valgen(i,v,r,t)], OPRES.l(ortype,i,v,r,h,t) } ; error_check("m_rsc_dat") = sum{(r,i,c,rscbin)$m_rsc_dat(r,i,c,rscbin,"cap"), m_rsc_dat_init(r,i,c,rscbin) - m_rsc_dat(r,i,c,rscbin,"cap") } ; +* csp-ns capacity is reported by moving it out of upv; flag any that had no upv to come out of +error_check("cspns") = sum{(c,r,t), cap_cspns_short(c,r,t) } ; * Check to make sure there's no dropped/excess load in or after Sw_StartMarkets error_check("dropped") = sum{(r,h,t)$[yeart(t)>=Sw_StartMarkets], DROPPED.l(r,h,t) } ; diff --git a/reeds/core/terminus/report_params.csv b/reeds/core/terminus/report_params.csv index e30647243..361e5a0e7 100644 --- a/reeds/core/terminus/report_params.csv +++ b/reeds/core/terminus/report_params.csv @@ -2,35 +2,37 @@ # This parameter list is in alphabetical order - please add new entries that way,,,,, param,units,comment,reeds2x,output_rename,input "acp_purchases_out(rpscat,st,t)",MWh,Annual alternative compliance credits from the variable ACP_PURCHASES,,, -"avg_cf(i,v,r,t)",frac,Annual average capacity factor for rsc technologies,,, +"avg_cf(i,v,r,t)",frac,Annual average capacity factor for non-rsc technologies from realized generation,,, "avg_avail(i,v,r)",frac,Annual average avail factor,,, "bioused_out(bioclass,r,t)",dry tons (imperial),biomass used by class in each model region (-> bioused.csv),,, "bioused_usda(bioclass,usda_region,t)",dry tons (imperial),biomass used by class in each USDA region,,, "state_cap_and_trade_price(st,t)",$/metric ton,marginal from state annual CO2 cap constraints,,, "state_cap_and_trade_quant(st,t)",metric tons,state annual CO2 cap constraints,,, "cap_above_limit(tg,r,t)",MW,Near-term capacity deployed above interconnection queue limit,,, -"cap_avail(i,r,t,rscbin)",MW,Available capacity at beginning of model year for rsc techs,,, -"cap_exog(i,v,r,t)",MW,Exogenous capacity from m_capacity_exog; used by reeds_to_rev,,, +"cap_avail(i,c,r,t,rscbin)",MW,Available capacity at beginning of model year for rsc techs,,, +"cap_cspns_short(c,r,t)",MWac,csp-ns capacity that could not be reassigned out of upv,,, +"cap_exog(i,c,v,r,t)",MW,Exogenous capacity from m_capacity_exog; used by reeds_to_rev,,, "cap_firm(i,r,ccseason,t)",MW,firm capacity that counts toward the reserve margin constraint by BA and season,,, "cap_nat(i,t)",MW,national capacity,,, "cap_new_cc(i,r,ccseason,t)",MW,"new capacity that is VRE, for new capacity credit calculation",,, "cc_new(i,r,ccseason,t)",frac,capacity credit for new VRE techs,,, "cap_converter_out(r,t)",MW,AC/DC converter capacity,1,, -"cap_ivrt(i,v,r,t)",MW,"undegraded power capacity by tech, year, region, and class",1,, +"cap_ivrt(i,c,v,r,t)",MW,"undegraded power capacity by tech, year, region, and class",1,, "cap_energy_ivrt(i,v,r,t)",MWh,"undegraded energy capacity by tech, year, region, and class",1,, "cap_sdbin_out(i,r,ccseason,sdbin,t)",MW,binned storage capacity by year,,, -"cap_deg_ivrt(i,v,r,t)",MW,"Degraded capacity, equal to CAP.l",,, +"cap_deg_ivrt(i,c,v,r,t)",MW,"Degraded capacity, equal to CAP.l",,, +"cap_upv_class(c,r,t)",MWac,upv capacity by resource class,,, "cap_new_ann(i,r,t)",MW/yr,new annual capacity by region,,, "cap_new_ann_nat(i,t)",MW/yr,new annual capacity national,,, -"cap_new_bin_out(i,v,r,t,rscbin)",MW,capacity of built techs,,, -"cap_new_ivrt(i,v,r,t)",MW,new capacity,1,, -"cap_new_ivrt_refurb(i,v,r,t)",MW,new refurbished capacity,,, +"cap_new_bin_out(i,c,v,r,t,rscbin)",MW,capacity of built techs,,, +"cap_new_ivrt(i,c,v,r,t)",MW,new capacity,1,, +"cap_new_ivrt_refurb(i,c,v,r,t)",MW,new refurbished capacity,,, "cap_new_out(i,r,t)",MW,"new capacity by region, which are investments and upgrades from one solve year to the next",,, "cap_energy_new_out(i,v,r,t)",MWh,"new energy capacity by region, which are investments from one solve year to the next",,, -"cap_out(i,r,t)",MW,capacity by region,1,cap, +"cap_out(i,c,r,t)",MW,capacity by region,1,cap, "cap_out_ivrt(i,v,r,t)",MW,capacity by region and vintage,,, "capacity_offline(i,r,allh,t)",MW,capacity offline due to forced or scheduled outages,,, -"capex_ivrt(i,v,r,t)",$,"capital expenditure for new capacity, no ITC/depreciation/PTC reductions",,, +"capex_ivrt(i,c,v,r,t)",$,"capital expenditure for new capacity, no ITC/depreciation/PTC reductions",,, "cap_upgrade(i,r,t)",MW,upgraded capacity by region,,, "cap_upgrade_ivrt(i,v,r,t)",MW,upgraded capacity by region and vintage,,, "CO2_CAPTURED_out(r,allh,t)",metric tons/hour,amount of CO2 captured_out from DAC and CCS technologies,,, @@ -90,7 +92,7 @@ planned_outage(i),fraction,average scheduled outage rate (h-weighted) by technol "gen_ann_nat(i,t)",MWh,"annual generation with charge and production load as negative generation, nationwide",,, "gen_uncurtailed(i,r,t)",MWh,annual generation where VRE uses uncurtailed gen and storage uses GEN,,, "gen_uncurtailed_nat(i,t)",MWh,national annual generation where VRE uses uncurtailed gen and storage uses GEN,,, -"gen_rsc(i,v,r,t)",MWh/MW,Annual generation per MW from rsc techs,,, +"gen_rsc(i,c,v,r,t)",MWh/MW,Annual generation per MW from rsc techs,,, "h2_demand_by_sector(h2_demand_type,t)",metric tons,national H2 demand by use,,, "h2_inout(h2_stor,r,allh,t,*)",metric tons/hour,H2 moving in/out of storage,,, "h2_price_h(r,allh,t)",$2004/kg,Marginal cost of H2 by region and timeslice,,, @@ -112,12 +114,12 @@ planned_outage(i),fraction,average scheduled outage rate (h-weighted) by technol "loadsite_cap(r,t)",MW,Capacity of flexibly sited load,,, "loadsite_op(r,allh,t)",MW,Operations of flexibly sited load,,, "invtran_out(r,rr,trtype,t)",MW,new transmission capacity,1,, -"lcoe(i,v,r,t,rscbin)",$/MWh,levelized cost of electricity for all tech options,,, +"lcoe(i,c,v,r,t,rscbin)",$/MWh,levelized cost of electricity for all tech options,,, "lcoe_built(i,r,t)",$/MWh,levelized cost of electricity for technologies that were built,,, "lcoe_built_nat(i,t)",$/MWh,national average levelized cost of electricity for technologies that were built,,, -"lcoe_cf_act(i,v,r,t,rscbin)",$/MWh,LCOE using actual (instead of max) capacity factors,,, -"lcoe_fullpol(i,v,r,t,rscbin)",$/MWh,"LCOE considering full ITC and PTC value, whereas the LCOE parameter considers the annualized objective function",,, -"lcoe_nopol(i,v,r,t,rscbin)",$/MWh,LCOE without considering ITC and PTC adjustments,,, +"lcoe_cf_act(i,c,v,r,t,rscbin)",$/MWh,LCOE using actual (instead of max) capacity factors,,, +"lcoe_fullpol(i,c,v,r,t,rscbin)",$/MWh,"LCOE considering full ITC and PTC value, whereas the LCOE parameter considers the annualized objective function",,, +"lcoe_nopol(i,c,v,r,t,rscbin)",$/MWh,LCOE without considering ITC and PTC adjustments,,, "lcoe_pieces(lcoe_cat,i,r,t)",varies,levelized cost of electricity elements for technologies that were built,,, "lcoe_pieces_nat(lcoe_cat,i,t)",varies,national average levelized cost of electricity elements for technologies that were built,,, "losses_ann(*,t)",MWh,annual losses by category,1,, @@ -157,7 +159,7 @@ repgasquant_nat(t),Quads,national consumption of natural gas,,, "reqt_quant_sys(*,*,*,t)",varies,System-wide requirement quantity,,, "ret_ann(i,r,t)",MW/yr,annual retired capacity by region,,, "ret_ann_nat(i,t)",MW/yr,annual retired capacity national,,, -"ret_ivrt(i,v,r,t)",MW,retired capacity by region and vintage,1,, +"ret_ivrt(i,c,v,r,t)",MW,retired capacity by region and vintage,1,, "ret_out(i,r,t)",MW,retired capacity by region,,, "revenue(rev_cat,i,r,t)",2004$,sum of revenues,,, "revenue_nat(rev_cat,i,t)",2004$,sum of revenues,,, diff --git a/reeds/input_processing/recf.py b/reeds/input_processing/recf.py index 0d0fdbdaa..c556a5075 100644 --- a/reeds/input_processing/recf.py +++ b/reeds/input_processing/recf.py @@ -454,7 +454,9 @@ def main(reeds_path, inputs_case): # Set the column names for resources to match ReEDS resources['ccreg'] = resources.area.map(r2ccreg) resources.rename(columns={'area':'r','tech':'i'}, inplace=True) - resources = resources[['r','i','ccreg','resource']] + i2c = reeds.techs.get_class_map(inputs_case) + resources['c'] = resources['i'].map(i2c) + resources = resources[['r','i','c','ccreg','resource']] #%%### Concentrated solar thermal power (CSP) @@ -475,8 +477,9 @@ def main(reeds_path, inputs_case): .assign(i=csp_resources['tech'] + '_' + csp_resources['class'].astype(str)) .assign(resource=csp_resources['tech'] + '_' + csp_resources['resource']) .assign(ccreg=csp_resources.r.map(r2ccreg)) - [['i','r','resource','ccreg']] - ) + ) + csp_resources['c'] = csp_resources['i'].map(i2c) + csp_resources = csp_resources[['i','r','c','resource','ccreg']] ###### Simulate CSP dispatch for each design ### Get solar multiples sms = {tech: scalars[f'csp_sm_{tech.strip("csp")}'] for tech in csptechs} diff --git a/reeds/input_processing/writecapdat.py b/reeds/input_processing/writecapdat.py index 1b53264dd..522c5bd91 100644 --- a/reeds/input_processing/writecapdat.py +++ b/reeds/input_processing/writecapdat.py @@ -437,28 +437,33 @@ def main(reeds_path, inputs_case): # We model csp-ns (CSP No Storage) as upv throughout ReEDS, but switch it back for reporting. # So save the csp-ns capacity separately, then rename it. - csp_units = ( - gdb_use.loc[(gdb_use['tech']=='csp-ns') & (gdb_use['RetireYear'] > startyear)] - .groupby(['r','StartYear','RetireYear']).summer_power_capacity_MW.sum() - .reset_index() - ) + csp_units = gdb_use.loc[ + (gdb_use['tech']=='csp-ns') & (gdb_use['RetireYear'] > startyear) + ].copy() if len(csp_units): - cap_cspns = ( - pd.concat( - {i: pd.Series( - [row.summer_power_capacity_MW]*(row.RetireYear - row.StartYear + 2), - index=range(row.StartYear, row.RetireYear + 2) - ) for (i,row) in csp_units.iterrows()}, - axis=1) - .rename(columns=csp_units['r']).fillna(0) - .T.groupby(level=0).sum().T - .stack().replace(0,np.nan).dropna() - .rename_axis(['t','r']).reorder_levels(['r','t']).rename('MWac') - ) + # csp-ns is modeled as upv, so bin it into the same resource classes that the + # upv capacity it becomes will be binned into. Reporting takes it back out of + # those classes. + upv_class = get_class_cf_bounds( + reeds_path, tech='upv', access_case=sw.GSw_SitingUPV, subtech='') + csp_units['c'] = csp_units['reV_capacity_factor_ac'].apply( + lambda x: assign_class(x, 'upv', upv_class)) + cap_cspns = pd.concat( + [ + pd.DataFrame({ + 'c': row.c, + 'r': row.r, + 't': list(range(row.StartYear, row.RetireYear + 2)), + 'MWac': row.summer_power_capacity_MW, + }) + for (_, row) in csp_units.iterrows() + ], + ignore_index=True, + ).groupby(['c','r','t']).MWac.sum() cap_cspns = ( cap_cspns.loc[cap_cspns.index.get_level_values('t') >= startyear].copy()) else: - cap_cspns = pd.DataFrame(columns=['r','t','MWac']).set_index(['r','t']) + cap_cspns = pd.DataFrame(columns=['c','r','t','MWac']).set_index(['c','r','t']) # Rename csp-ns to upv gdb_use.loc[gdb_use['tech']=='csp-ns','coolingwatertech'] = ( gdb_use.loc[gdb_use['tech']=='csp-ns','coolingwatertech'] @@ -642,6 +647,11 @@ def main(reeds_path, inputs_case): (cap_exog, rsc_class) = create_exog_rsc(reeds_path, inputs_case, gdb_use_cap_exog, TECH, COLNAMES, sw, startyear) + # csp-ns is modeled as upv, so its pre-startyear capacity belongs with the exogenous + # upv capacity. + exog_cap_upv = pd.concat( + [cap_exog['upv'], cap_exog['csp-ns']], ignore_index=True) + #%%#################################### # -- RSC Prescribed Capacity -- # @@ -1034,7 +1044,7 @@ def main(reeds_path, inputs_case): 'can_imports_capacity' : can_imports_capacity.reset_index(), 'geoexist' : geoexist, 'h2_ba_share': h2_ba_share_out, - 'exog_cap_upv':cap_exog['upv'], + 'exog_cap_upv':exog_cap_upv, 'exog_cap_wind-ons':cap_exog['wind-ons'], 'exog_cap_wind-ofs':cap_exog['wind-ofs'], 'exog_cap_geohydro':cap_exog['geohydro_allkm'] diff --git a/reeds/reedsplots.py b/reeds/reedsplots.py index c1771be29..5b367b561 100644 --- a/reeds/reedsplots.py +++ b/reeds/reedsplots.py @@ -972,8 +972,8 @@ def plot_diff_maps( dfbase.i = simplify_techs(dfbase.i) dfcomp.i = simplify_techs(dfcomp.i) - dfbase = dfbase.groupby(['i','r','t']).sum().reset_index().copy() - dfcomp = dfcomp.groupby(['i','r','t']).sum().reset_index().copy() + dfbase = dfbase.groupby(['i','r','t'])[valcol].sum().reset_index().copy() + dfcomp = dfcomp.groupby(['i','r','t'])[valcol].sum().reset_index().copy() # print(dfbase.i.unique()) # print(dfcomp.i.unique()) diff --git a/reeds/resource_adequacy/prep_data.py b/reeds/resource_adequacy/prep_data.py index fd63e86f1..74161428e 100644 --- a/reeds/resource_adequacy/prep_data.py +++ b/reeds/resource_adequacy/prep_data.py @@ -196,14 +196,14 @@ def main(t, casedir, iteration=0): #%%### Nameplate capacity cap_ivr_realvint = ( gdxreeds['cap_ivrt'].loc[gdxreeds['cap_ivrt'].t==t].drop('t', axis=1) - .groupby(['i','v','r'], as_index=False).Value.sum() + .groupby(['i','c','v','r'], as_index=False).Value.sum() ) ### Reset the vintages of all storage units to 'new1' to reduce model size cap_storage_devint = cap_ivr_realvint.loc[ cap_ivr_realvint.i.isin(gdxreeds['storage_standalone'].i)].copy() cap_storage_devint['v'] = 'new1' cap_storage_devint = ( - cap_storage_devint.groupby(['i','v','r'], as_index=False).Value.sum()) + cap_storage_devint.groupby(['i','c','v','r'], as_index=False).Value.sum()) def _devint_storage(dfin): dfout = pd.concat([ @@ -237,7 +237,7 @@ def _devint_storage(dfin): vretechs_i = resources.i.str.lower().unique() cap_vre = ( cap_ivr.loc[cap_ivr.i.str.lower().isin(vretechs_i)] - .set_index(['i','v','r']).Value.copy() + .set_index(['i','c','v','r']).Value.copy() ) #%%### VRE generation, accounting for generation @@ -247,7 +247,7 @@ def _devint_storage(dfin): ### so fill missing values with 1, then drop rows with missing region (indicating no capacity) cf_adj_iv = ( gdxreeds['cf_adj_t_filt'].loc[gdxreeds['cf_adj_t_filt'].t==t].drop('t', axis=1) - .set_index(['i','v']).Value + .set_index(['i','c','v']).Value ) cap_vre_derated = cap_vre.multiply(cf_adj_iv, fill_value=1).reset_index().dropna() if len(cap_vre) != len(cap_vre_derated): @@ -440,7 +440,8 @@ def intify(v): ]) ### Nameplate capacity - max_cap = cap_nonloadtechs.set_index(['i','v','r']).Value.rename('MW') + max_cap = ( + cap_nonloadtechs.groupby(['i','v','r']).Value.sum().rename('MW')) ## Drop VRE since it is handled through pras_vre_gen max_cap = max_cap.loc[ ~max_cap.index.get_level_values('i').str.startswith( diff --git a/reeds/results.py b/reeds/results.py index 22743d651..741142da0 100644 --- a/reeds/results.py +++ b/reeds/results.py @@ -48,7 +48,7 @@ def calc_cap(case): Value (float): Capacity (GW) """ # Get data - df = reeds.io.read_output(case, 'cap') + df = reeds.io.read_output(case, 'cap').drop(columns='c', errors='ignore') # simplify technology names based on bokehpivot mapping df['i'] = reeds.reedsplots.simplify_techs(df['i'])