Skip to content

Commit

Permalink
Merge pull request #84 from IMMM-SFA/dev
Browse files Browse the repository at this point in the history
release version 2.1.0
  • Loading branch information
crvernon authored May 25, 2022
2 parents 77fa03d + dcda144 commit 8ba37dd
Show file tree
Hide file tree
Showing 19 changed files with 833 additions and 323 deletions.
2 changes: 1 addition & 1 deletion cerf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
from .install_supplement import install_package_data


__version__ = "2.0.9"
__version__ = "2.1.0"
59 changes: 45 additions & 14 deletions cerf/compete.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def __init__(self,
technology_order,
expansion_dict,
lmp_dict,
generation_dict,
operating_cost_dict,
nov_dict,
ic_dict,
nlc_mask,
Expand Down Expand Up @@ -83,6 +85,12 @@ def __init__(self,
# locational marginal pricing
self.lmp_flat_dict = lmp_dict

# generation
self.generation_flat_dict = generation_dict

# operating cost
self.operating_cost_flat_dict = operating_cost_dict

# net operational value
self.nov_flat_dict = nov_dict

Expand Down Expand Up @@ -116,6 +124,12 @@ def __init__(self,
self.xcoords = xcoords
self.ycoords = ycoords

# mask any technologies having 0 expected sites in the expansion plan to exclude them from competition
for index, i in enumerate(self.technology_order, 1):
if expansion_dict[i]["n_sites"] == 0:
self.nlc_mask[index, :, :] = np.ma.masked_array(self.nlc_mask[index, :, :],
np.ones_like(self.nlc_mask[index, :, :]))

# show cheapest option, add 1 to the index to represent the technology number
self.cheapest_arr = np.argmin(self.nlc_mask, axis=0)

Expand Down Expand Up @@ -169,7 +183,7 @@ def compete(self):
required_sites = self.expansion_dict[tech_id]['n_sites']

# calculate the year of retirement
retirement_year = self.settings_dict['run_year'] + int(self.technology_dict[tech_id]['lifetime'])
retirement_year = self.settings_dict['run_year'] + int(self.technology_dict[tech_id]['lifetime_yrs'])

# if there are more power plants to site and there are grids available to site them...
if self.avail_grids > 0 and tech.shape[0] > 0 and required_sites > 0:
Expand All @@ -192,29 +206,42 @@ def compete(self):
self.sited_dict['region_name'].append(self.target_region_name)
self.sited_dict['tech_id'].append(tech_id)
self.sited_dict['tech_name'].append(self.technology_dict[tech_id]['tech_name'])
self.sited_dict['unit_size_mw'].append(self.technology_dict[tech_id]['unit_size'])
self.sited_dict['unit_size_mw'].append(self.technology_dict[tech_id]['unit_size_mw'])
self.sited_dict['xcoord'].append(self.xcoords[target_ix])
self.sited_dict['ycoord'].append(self.ycoords[target_ix])
self.sited_dict['index'].append(self.indices_flat[target_ix])
self.sited_dict['buffer_in_km'].append(self.technology_dict[tech_id]['buffer_in_km'])
self.sited_dict['sited_year'].append(self.settings_dict['run_year'])
self.sited_dict['retirement_year'].append(retirement_year)
self.sited_dict['lmp_zone'].append(self.zones_flat_arr[target_ix])
self.sited_dict['locational_marginal_pricing'].append(self.lmp_flat_dict[tech_id][target_ix])
self.sited_dict['net_operational_value'].append(self.nov_flat_dict[tech_id][target_ix])
self.sited_dict['interconnection_cost'].append(self.ic_flat_dict[tech_id][target_ix])
self.sited_dict['net_locational_cost'].append(self.nlc_flat_dict[tech_id][target_ix])
self.sited_dict['locational_marginal_price_usd_per_mwh'].append(self.lmp_flat_dict[tech_id][target_ix])
self.sited_dict['generation_mwh_per_year'].append(self.generation_flat_dict[tech_id][target_ix])
self.sited_dict['operating_cost_usd_per_year'].append(self.operating_cost_flat_dict[tech_id][target_ix])
self.sited_dict['net_operational_value_usd_per_year'].append(self.nov_flat_dict[tech_id][target_ix])
self.sited_dict['interconnection_cost_usd_per_year'].append(self.ic_flat_dict[tech_id][target_ix])
self.sited_dict['net_locational_cost_usd_per_year'].append(self.nlc_flat_dict[tech_id][target_ix])
self.sited_dict['capacity_factor_fraction'].append(self.technology_dict[tech_id]["capacity_factor_fraction"])
self.sited_dict['carbon_capture_rate_fraction'].append(self.technology_dict[tech_id]["carbon_capture_rate_fraction"])
self.sited_dict['fuel_co2_content_tons_per_btu'].append(self.technology_dict[tech_id]["fuel_co2_content_tons_per_btu"])
self.sited_dict['fuel_price_usd_per_mmbtu'].append(self.technology_dict[tech_id]["fuel_price_usd_per_mmbtu"])
self.sited_dict['fuel_price_esc_rate_fraction'].append(self.technology_dict[tech_id]["fuel_price_esc_rate_fraction"])
self.sited_dict['heat_rate_btu_per_kWh'].append(self.technology_dict[tech_id]["heat_rate_btu_per_kWh"])
self.sited_dict['lifetime_yrs'].append(self.technology_dict[tech_id]["lifetime_yrs"])
self.sited_dict['variable_om_usd_per_mwh'].append(self.technology_dict[tech_id]["variable_om_usd_per_mwh"])
self.sited_dict['variable_om_esc_rate_fraction'].append(self.technology_dict[tech_id]["variable_om_esc_rate_fraction"])
self.sited_dict['carbon_tax_usd_per_ton'].append(self.technology_dict[tech_id]["carbon_tax_usd_per_ton"])
self.sited_dict['carbon_tax_esc_rate_fraction'].append(self.technology_dict[tech_id]["carbon_tax_esc_rate_fraction"])

# add selected index to list
sited_list.append(target_ix)

# apply buffer
result = util.buffer_flat_array(target_index=target_ix,
arr=self.cheapest_arr_1d,
nrows=self.cheapest_arr.shape[0],
ncols=self.cheapest_arr.shape[1],
ncells=self.technology_dict[tech_id]['buffer_in_km'],
set_value=0)
arr=self.cheapest_arr_1d,
nrows=self.cheapest_arr.shape[0],
ncols=self.cheapest_arr.shape[1],
ncells=self.technology_dict[tech_id]['buffer_in_km'],
set_value=0)

# unpack values
self.cheapest_arr_1d, buffer_indices_list = result
Expand Down Expand Up @@ -290,7 +317,7 @@ def compete(self):
elif self.avail_grids == 0:
keep_siting = False

# if there are available grids but n
# if there are available grids and a cheapest option available but no more required sites
elif self.avail_grids > 0 and tech.shape[0] > 0 and required_sites == 0:

# if there are no required sites, then mask the rest of the techs suitable area so
Expand All @@ -307,8 +334,12 @@ def compete(self):
# check for any available grids to site in
self.avail_grids = np.where(self.cheapest_arr_1d > 0)[0].shape[0]

# create sited data frame
df = pd.DataFrame(self.sited_dict).astype(util.sited_dtypes())
# if there are suitable cells AND no winners and some or no sites left to site pass until next round
else:
pass

# create sited data frame
df = pd.DataFrame(self.sited_dict).astype(util.sited_dtypes())

# reshape output array to 2D
return self.sited_arr_1d.reshape(self.cheapest_arr.shape), df
3 changes: 2 additions & 1 deletion cerf/install_supplement.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class InstallSupplement:
'2.0.6': 'https://zenodo.org/record/5247690/files/cerf_package_data.zip?download=1',
'2.0.7': 'https://zenodo.org/record/5514010/files/cerf_package_data.zip?download=1',
'2.0.8': 'https://zenodo.org/record/5514010/files/cerf_package_data.zip?download=1',
'2.0.9': 'https://zenodo.org/record/5514010/files/cerf_package_data.zip?download=1'}
'2.0.9': 'https://zenodo.org/record/5514010/files/cerf_package_data.zip?download=1',
'2.1.0': 'https://zenodo.org/record/5514010/files/cerf_package_data.zip?download=1'}


def __init__(self, data_dir=None):
Expand Down
8 changes: 4 additions & 4 deletions cerf/interconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,10 @@ def __init__(self, template_array, technology_dict, technology_order, region_ras
self.pipeline_costs = self.transmission_to_cost_raster(setting='pipelines')

@staticmethod
def calc_annuity_factor(discount_rate, lifetime):
def calc_annuity_factor(discount_rate, lifetime_yrs):
"""Calculate annuity factor."""

fx = pow(1.0 + discount_rate, lifetime)
fx = pow(1.0 + discount_rate, lifetime_yrs)

return discount_rate * fx / (fx - 1.0)

Expand Down Expand Up @@ -365,10 +365,10 @@ def generate_interconnection_costs_array(self):
# get technology specific information
require_pipelines = self.technology_dict[i].get('require_pipelines', False)
discount_rate = self.technology_dict[i].get('discount_rate')
lifetime = self.technology_dict[i].get('lifetime')
lifetime_yrs = self.technology_dict[i].get('lifetime_yrs')

# calculate annuity factor for technology
annuity_factor = self.calc_annuity_factor(discount_rate=discount_rate, lifetime=lifetime)
annuity_factor = self.calc_annuity_factor(discount_rate=discount_rate, lifetime_yrs=lifetime_yrs)

# get transmission cost array and convert from thous$/km to $/km
substation_cost_array = self.substation_costs * annuity_factor * 1000
Expand Down
16 changes: 8 additions & 8 deletions cerf/lmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,24 @@ def __init__(self, lmp_zone_dict, technology_dict, technology_order, zones_arr):
self.zones_arr = zones_arr

@staticmethod
def get_cf_bin(capacity_factor):
def get_cf_bin(capacity_factor_fraction):
"""Get the correct start and through index values to average over for calculating LMP."""

if capacity_factor == 1.0:
if capacity_factor_fraction == 1.0:
start_index = 0
through_index = 8760

elif capacity_factor >= 0.5:
start_index = int(np.ceil(8760 * (1 - capacity_factor)))
elif capacity_factor_fraction >= 0.5:
start_index = int(np.ceil(8760 * (1 - capacity_factor_fraction)))
through_index = 8760

elif capacity_factor == 0.0:
msg = f"The capacity factor provided `{capacity_factor}` is outside the bounds of 0.0 through 1.0"
elif capacity_factor_fraction == 0.0:
msg = f"The capacity factor provided `{capacity_factor_fraction}` is outside the bounds of 0.0 through 1.0"
raise ValueError(msg)

else:
start_index = 0
through_index = int(np.ceil(8760 * capacity_factor))
through_index = int(np.ceil(8760 * capacity_factor_fraction))

return start_index, through_index

Expand Down Expand Up @@ -149,7 +149,7 @@ def get_lmp(self):
for index, i in enumerate(self.technology_order):

# assign the correct LMP based on the capacity factor of the technology
start_index, through_index = self.get_cf_bin(self.technology_dict[i]['capacity_factor'])
start_index, through_index = self.get_cf_bin(self.technology_dict[i]['capacity_factor_fraction'])

# sort by descending lmp for each zone
for j in lmp_df.columns:
Expand Down
2 changes: 2 additions & 0 deletions cerf/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def run_single_region(self, target_region_name, write_output=True):
regions_dict=self.regions_dict,
suitability_arr=data.suitability_arr,
lmp_arr=data.lmp_arr,
generation_arr=data.generation_arr,
operating_cost_arr=data.operating_cost_arr,
nov_arr=data.nov_arr,
ic_arr=data.ic_arr,
nlc_arr=data.nlc_arr,
Expand Down
Loading

0 comments on commit 8ba37dd

Please sign in to comment.