# -*- coding: utf-8 -*-
"""reV utilities."""
from enum import Enum
import PySAM
from rex.utilities.loggers import log_versions as rex_log_versions
from reV.version import __version__
[docs]class FieldEnum(str, Enum):
"""Base Field enum with some mapping methods."""
[docs] @classmethod
def map_to(cls, other):
"""Return a rename map from this enum to another.
Mapping is performed on matching enum names. In other words, if
both enums have a `ONE` attribute, this will be mapped from one
enum to another.
Parameters
----------
other : :class:`Enum`
``Enum`` subclass with ``__members__`` attribute.
Returns
-------
dict
Dictionary mapping matching values from one enum to another.
Examples
--------
>>> class Test1(FieldEnum):
>>> ONE = "one_x"
>>> TWO = "two"
>>>
>>> class Test2(Enum):
>>> ONE = "one_y"
>>> THREE = "three"
>>>
>>> Test1.map_to(Test2)
{<Test1.ONE: 'one_x'>: <Test2.ONE: 'one_y'>}
"""
return {
cls[mem]: other[mem]
for mem in cls.__members__
if mem in other.__members__
}
[docs] @classmethod
def map_from(cls, other):
"""Map from a dictionary of name / member pairs to this enum.
Parameters
----------
other : dict
Dictionary mapping key values (typically old aliases) to
enum values. For example, ``{'sc_gid': 'SC_GID'}`` would
return a dictionary that maps ``'sc_gid'`` to the ``SC_GID``
member of this enum.
Returns
-------
dict
Mapping of input dictionary keys to member values of this
enum.
Examples
--------
>>> class Test(FieldEnum):
>>> ONE = "one_x"
>>> TWO = "two_y"
>>>
>>> Test.map_from({1: "ONE", 2: "TWO"})
{1: <Test.ONE: 'one_x'>, 2: <Test.TWO: 'two_y'>}
"""
return {name: cls[mem] for name, mem in other.items()}
def __str__(self):
return self.value
def __format__(self, format_spec):
return str.__format__(self.value, format_spec)
[docs]class SiteDataField(FieldEnum):
"""An enumerated map to site data column names."""
GID = "gid"
CONFIG = "config"
[docs]class SupplyCurveField(FieldEnum):
"""An enumerated map to supply curve summary/meta keys.
This is a collection of known supply curve fields that reV outputs
across aggregation, supply curve, and bespoke outputs.
Not all of these columns are guaranteed in every supply-curve like
output (e.g. "convex_hull_area" is a bespoke-only output).
"""
SC_GID = "sc_gid"
LATITUDE = "latitude"
LONGITUDE = "longitude"
COUNTRY = "country"
STATE = "state"
COUNTY = "county"
ELEVATION = "elevation_m"
TIMEZONE = "timezone"
SC_POINT_GID = "sc_point_gid"
SC_ROW_IND = "sc_row_ind"
SC_COL_IND = "sc_col_ind"
SOURCE_GIDS = "source_gids"
RES_GIDS = "res_gids"
GEN_GIDS = "gen_gids"
GID_COUNTS = "gid_counts"
N_GIDS = "n_gids"
MEAN_RES = "resource"
MEAN_CF_AC = "capacity_factor_ac"
MEAN_CF_DC = "capacity_factor_dc"
MEAN_LCOE = "lcoe_site_usd_per_mwh"
CAPACITY_AC_MW = "capacity_ac_mw"
CAPACITY_DC_MW = "capacity_dc_mw"
OFFSHORE = "offshore"
AREA_SQ_KM = "area_developable_sq_km"
MEAN_FRICTION = "friction_site"
MEAN_LCOE_FRICTION = "lcoe_friction_usd_per_mwh"
RAW_LCOE = "lcoe_raw_usd_per_mwh"
EOS_MULT = "multiplier_cc_eos"
REG_MULT = "multiplier_cc_regional"
SC_POINT_ANNUAL_ENERGY_MWH = "annual_energy_site_mwh"
COST_BASE_OCC_USD_PER_AC_MW = "cost_base_occ_usd_per_ac_mw"
COST_SITE_OCC_USD_PER_AC_MW = "cost_site_occ_usd_per_ac_mw"
COST_BASE_FOC_USD_PER_AC_MW = "cost_base_foc_usd_per_ac_mw"
COST_SITE_FOC_USD_PER_AC_MW = "cost_site_foc_usd_per_ac_mw"
COST_BASE_VOC_USD_PER_AC_MW = "cost_base_voc_usd_per_ac_mw"
COST_SITE_VOC_USD_PER_AC_MW = "cost_site_voc_usd_per_ac_mw"
FIXED_CHARGE_RATE = "fixed_charge_rate"
# Bespoke outputs
POSSIBLE_X_COORDS = "possible_x_coords"
POSSIBLE_Y_COORDS = "possible_y_coords"
TURBINE_X_COORDS = "turbine_x_coords"
TURBINE_Y_COORDS = "turbine_y_coords"
N_TURBINES = "n_turbines"
INCLUDED_AREA = "area_included_sq_km"
INCLUDED_AREA_CAPACITY_DENSITY = (
"capacity_density_included_area_mw_per_km2"
)
CONVEX_HULL_AREA = "area_convex_hull_sq_km"
CONVEX_HULL_CAPACITY_DENSITY = "capacity_density_convex_hull_mw_per_km2"
FULL_CELL_CAPACITY_DENSITY = "capacity_density_full_cell_mw_per_km2"
BESPOKE_AEP = "optimized_plant_aep"
BESPOKE_OBJECTIVE = "optimized_plant_objective"
BESPOKE_CAPITAL_COST = "optimized_plant_capital_cost"
BESPOKE_FIXED_OPERATING_COST = "optimized_plant_fixed_operating_cost"
BESPOKE_VARIABLE_OPERATING_COST = "optimized_plant_variable_operating_cost"
BESPOKE_BALANCE_OF_SYSTEM_COST = "optimized_plant_balance_of_system_cost"
# Transmission outputs
TRANS_GID = "trans_gid"
TRANS_TYPE = "trans_type"
TOTAL_LCOE_FRICTION = "lcoe_total_friction_usd_per_mwh"
TRANS_CAPACITY = "trans_capacity"
DIST_SPUR_KM = "dist_spur_km"
DIST_EXPORT_KM = "dist_export_km"
REINFORCEMENT_DIST_KM = "dist_reinforcement_km"
TIE_LINE_COST_PER_MW = "cost_spur_usd_per_mw"
CONNECTION_COST_PER_MW = "cost_poi_usd_per_mw"
EXPORT_COST_PER_MW = "cost_export_usd_per_mw"
REINFORCEMENT_COST_PER_MW = "cost_reinforcement_usd_per_mw"
TOTAL_TRANS_CAP_COST_PER_MW = "cost_total_trans_usd_per_mw"
LCOT = "lcot_usd_per_mwh"
TOTAL_LCOE = "lcoe_all_in_usd_per_mwh"
N_PARALLEL_TRANS = "count_num_parallel_trans"
POI_LAT = "latitude_poi"
POI_LON = "longitude_poi"
REINFORCEMENT_POI_LAT = "latitude_reinforcement_poi"
REINFORCEMENT_POI_LON = "longitude_reinforcement_poi"
[docs] @classmethod
def map_from_legacy(cls):
"""Map of legacy names to current values.
Returns
-------
dict
Dictionary that maps legacy supply curve column names to
members of this enum.
"""
legacy_map = {}
for current_field, old_field in cls.map_to(_LegacySCAliases).items():
aliases = old_field.value
if isinstance(aliases, str):
aliases = [aliases]
legacy_map.update({alias: current_field for alias in aliases})
return legacy_map
class _LegacySCAliases(Enum):
"""Legacy supply curve column names.
Enum values can be either a single string or an iterable of string
values where each string value represents a previously known alias.
"""
ELEVATION = "elevation"
MEAN_RES = "mean_res"
MEAN_CF_AC = "mean_cf"
MEAN_LCOE = "mean_lcoe"
CAPACITY_AC_MW = "capacity"
AREA_SQ_KM = "area_sq_km"
MEAN_FRICTION = "mean_friction"
MEAN_LCOE_FRICTION = "mean_lcoe_friction"
RAW_LCOE = "raw_lcoe"
TRANS_TYPE = "category"
TRANS_CAPACITY = "avail_cap"
DIST_SPUR_KM = "dist_km"
REINFORCEMENT_DIST_KM = "reinforcement_dist_km"
TIE_LINE_COST_PER_MW = "tie_line_cost_per_mw"
CONNECTION_COST_PER_MW = "connection_cost_per_mw"
REINFORCEMENT_COST_PER_MW = "reinforcement_cost_per_mw"
TOTAL_TRANS_CAP_COST_PER_MW = "trans_cap_cost_per_mw"
LCOT = "lcot"
TOTAL_LCOE = "total_lcoe"
TOTAL_LCOE_FRICTION = "total_lcoe_friction"
N_PARALLEL_TRANS = "n_parallel_trans"
EOS_MULT = "eos_mult", "capital_cost_multiplier"
REG_MULT = "reg_mult"
SC_POINT_ANNUAL_ENERGY_MWH = "sc_point_annual_energy"
POI_LAT = "poi_lat"
POI_LON = "poi_lon"
REINFORCEMENT_POI_LAT = "reinforcement_poi_lat"
REINFORCEMENT_POI_LON = "reinforcement_poi_lon"
BESPOKE_AEP = "bespoke_aep"
BESPOKE_OBJECTIVE = "bespoke_objective"
BESPOKE_CAPITAL_COST = "bespoke_capital_cost"
BESPOKE_FIXED_OPERATING_COST = "bespoke_fixed_operating_cost"
BESPOKE_VARIABLE_OPERATING_COST = "bespoke_variable_operating_cost"
BESPOKE_BALANCE_OF_SYSTEM_COST = "bespoke_balance_of_system_cost"
INCLUDED_AREA = "included_area"
INCLUDED_AREA_CAPACITY_DENSITY = "included_area_capacity_density"
CONVEX_HULL_AREA = "convex_hull_area"
CONVEX_HULL_CAPACITY_DENSITY = "convex_hull_capacity_density"
FULL_CELL_CAPACITY_DENSITY = "full_cell_capacity_density"
[docs]class ModuleName(str, Enum):
"""A collection of the module names available in reV.
Each module name should match the name of the click command
that will be used to invoke its respective cli. As of 3/1/2022,
this means that all commands are lowercase with underscores
replaced by dashes.
Reference
---------
See this line in the click source code to get the most up-to-date
click name conversions: https://tinyurl.com/4rehbsvf
"""
BESPOKE = "bespoke"
COLLECT = "collect"
ECON = "econ"
GENERATION = "generation"
HYBRIDS = "hybrids"
MULTI_YEAR = "multi-year"
NRWAL = "nrwal"
QA_QC = "qa-qc"
REP_PROFILES = "rep-profiles"
SUPPLY_CURVE = "supply-curve"
SUPPLY_CURVE_AGGREGATION = "supply-curve-aggregation"
def __str__(self):
return self.value
def __format__(self, format_spec):
return str.__format__(self.value, format_spec)
[docs] @classmethod
def all_names(cls):
"""All module names.
Returns
-------
set
The set of all module name strings.
"""
# pylint: disable=no-member
return {v.value for v in cls.__members__.values()}
[docs]def log_versions(logger):
"""Log package versions:
- rex and reV to info
- h5py, numpy, pandas, scipy, and PySAM to debug
Parameters
----------
logger : logging.Logger
Logger object to log memory message to.
"""
logger.info("Running with reV version {}".format(__version__))
rex_log_versions(logger)
logger.debug("- PySAM version {}".format(PySAM.__version__))