NREL-reV 0.13.1__tar.gz → 0.14.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {nrel_rev-0.13.1 → nrel_rev-0.14.1/NREL_reV.egg-info}/PKG-INFO +2 -5
  2. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/NREL_reV.egg-info/SOURCES.txt +1 -0
  3. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/NREL_reV.egg-info/requires.txt +1 -1
  4. {nrel_rev-0.13.1/NREL_reV.egg-info → nrel_rev-0.14.1}/PKG-INFO +2 -5
  5. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/README.rst +0 -3
  6. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/pyproject.toml +2 -2
  7. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/version_checker.py +3 -2
  8. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/bespoke.py +22 -15
  9. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/cli.py +4 -2
  10. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/project_points.py +8 -5
  11. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/econ/economies_of_scale.py +160 -61
  12. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/cli_gen.py +4 -2
  13. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/losses/scheduled.py +18 -31
  14. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/aggregation.py +15 -6
  15. nrel_rev-0.14.1/reV/supply_curve/cli_tech_mapping.py +66 -0
  16. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/points.py +118 -28
  17. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/sc_aggregation.py +93 -23
  18. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/tech_mapping.py +190 -245
  19. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/__init__.py +9 -4
  20. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/version.py +1 -1
  21. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/LICENSE +0 -0
  22. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/MANIFEST.in +0 -0
  23. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/NREL_reV.egg-info/dependency_links.txt +0 -0
  24. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/NREL_reV.egg-info/entry_points.txt +0 -0
  25. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/NREL_reV.egg-info/top_level.txt +0 -0
  26. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/SAM.py +0 -0
  27. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/__init__.py +0 -0
  28. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/USA AZ Phoenix Sky Harbor Intl Ap (TMY3).csv +0 -0
  29. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/USA CA Daggett (TMY2).csv +0 -0
  30. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/US_Wave.csv +0 -0
  31. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/WY Southern-Flat Lands.srw +0 -0
  32. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/geothermal.json +0 -0
  33. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults/i_pvwattsv5.json +0 -0
  34. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/defaults.py +0 -0
  35. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/econ.py +0 -0
  36. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/generation.py +0 -0
  37. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/SAM/windbos.py +0 -0
  38. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/__init__.py +0 -0
  39. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/__init__.py +0 -0
  40. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/cli_bespoke.py +0 -0
  41. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/gradient_free.py +0 -0
  42. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/pack_turbs.py +0 -0
  43. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/bespoke/place_turbines.py +0 -0
  44. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/__init__.py +0 -0
  45. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/base_analysis_config.py +0 -0
  46. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/base_config.py +0 -0
  47. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/cli_project_points.py +0 -0
  48. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/curtailment.py +0 -0
  49. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/execution.py +0 -0
  50. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/output_request.py +0 -0
  51. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/config/sam_config.py +0 -0
  52. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/econ/__init__.py +0 -0
  53. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/econ/cli_econ.py +0 -0
  54. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/econ/econ.py +0 -0
  55. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/econ/utilities.py +0 -0
  56. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/__init__.py +0 -0
  57. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/base.py +0 -0
  58. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/generation.py +0 -0
  59. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/generation.json +0 -0
  60. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/lcoe_fcr.json +0 -0
  61. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/lcoe_fcr_inputs.json +0 -0
  62. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/linear_fresnel.json +0 -0
  63. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/other.json +0 -0
  64. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/single_owner.json +0 -0
  65. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/solar_water_heat.json +0 -0
  66. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/trough_heat.json +0 -0
  67. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/generation/output_attributes/windbos.json +0 -0
  68. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/__init__.py +0 -0
  69. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/cli_collect.py +0 -0
  70. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/cli_multi_year.py +0 -0
  71. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/exclusions.py +0 -0
  72. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/multi_year.py +0 -0
  73. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/outputs.py +0 -0
  74. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/handlers/transmission.py +0 -0
  75. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/hybrids/__init__.py +0 -0
  76. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/hybrids/cli_hybrids.py +0 -0
  77. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/hybrids/hybrid_methods.py +0 -0
  78. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/hybrids/hybrids.py +0 -0
  79. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/losses/__init__.py +0 -0
  80. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/losses/power_curve.py +0 -0
  81. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/losses/utils.py +0 -0
  82. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/nrwal/__init__.py +0 -0
  83. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/nrwal/cli_nrwal.py +0 -0
  84. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/nrwal/nrwal.py +0 -0
  85. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/qa_qc/__init__.py +0 -0
  86. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/qa_qc/cli_qa_qc.py +0 -0
  87. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/qa_qc/qa_qc.py +0 -0
  88. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/qa_qc/summary.py +0 -0
  89. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/rep_profiles/__init__.py +0 -0
  90. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/rep_profiles/cli_rep_profiles.py +0 -0
  91. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/rep_profiles/rep_profiles.py +0 -0
  92. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/__init__.py +0 -0
  93. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/cli_sc_aggregation.py +0 -0
  94. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/cli_supply_curve.py +0 -0
  95. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/competitive_wind_farms.py +0 -0
  96. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/exclusions.py +0 -0
  97. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/extent.py +0 -0
  98. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/supply_curve/supply_curve.py +0 -0
  99. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/_clean_readme.py +0 -0
  100. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/cli_functions.py +0 -0
  101. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/curtailment.py +0 -0
  102. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/exceptions.py +0 -0
  103. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/pytest_utils.py +0 -0
  104. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/reV/utilities/slots.py +0 -0
  105. {nrel_rev-0.13.1 → nrel_rev-0.14.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: NREL-reV
3
- Version: 0.13.1
3
+ Version: 0.14.1
4
4
  Summary: National Renewable Energy Laboratory's (NREL's) Renewable Energy Potential(V) Model: reV
5
5
  Author-email: Galen Maclaurin <galen.maclaurin@nrel.gov>
6
6
  Maintainer-email: Grant Buster <gbuster@nrel.gov>, Paul Pinchuk <ppinchuk@nrel.gov>
@@ -22,7 +22,7 @@ Description-Content-Type: text/x-rst
22
22
  License-File: LICENSE
23
23
  Requires-Dist: NREL-gaps<0.9,>=0.8.0
24
24
  Requires-Dist: NREL-NRWAL<0.1,>=0.0.11
25
- Requires-Dist: NREL-PySAM~=6.0.1
25
+ Requires-Dist: NREL-PySAM~=7.0.0
26
26
  Requires-Dist: NREL-rex<0.4,>=0.3.2
27
27
  Requires-Dist: numpy<3,>=2.0.2
28
28
  Requires-Dist: packaging<25,>=24.2
@@ -156,9 +156,6 @@ Option 1: Install from PIP (recommended for analysts):
156
156
  3. Install reV:
157
157
  1) ``pip install NREL-reV`` or
158
158
 
159
- - NOTE: If you install using conda and want to run from files directly on S3 like in the `running reV locally example <https://nrel.github.io/reV/misc/examples.running_locally.html>`_
160
- you will also need to install S3 filesystem dependencies: ``pip install NREL-reV[s3]``
161
-
162
159
  - NOTE: If you install using conda and want to use `HSDS <https://github.com/NREL/hsds-examples>`_
163
160
  you will also need to install HSDS dependencies: ``pip install NREL-reV[hsds]``
164
161
 
@@ -86,6 +86,7 @@ reV/supply_curve/__init__.py
86
86
  reV/supply_curve/aggregation.py
87
87
  reV/supply_curve/cli_sc_aggregation.py
88
88
  reV/supply_curve/cli_supply_curve.py
89
+ reV/supply_curve/cli_tech_mapping.py
89
90
  reV/supply_curve/competitive_wind_farms.py
90
91
  reV/supply_curve/exclusions.py
91
92
  reV/supply_curve/extent.py
@@ -1,6 +1,6 @@
1
1
  NREL-gaps<0.9,>=0.8.0
2
2
  NREL-NRWAL<0.1,>=0.0.11
3
- NREL-PySAM~=6.0.1
3
+ NREL-PySAM~=7.0.0
4
4
  NREL-rex<0.4,>=0.3.2
5
5
  numpy<3,>=2.0.2
6
6
  packaging<25,>=24.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: NREL-reV
3
- Version: 0.13.1
3
+ Version: 0.14.1
4
4
  Summary: National Renewable Energy Laboratory's (NREL's) Renewable Energy Potential(V) Model: reV
5
5
  Author-email: Galen Maclaurin <galen.maclaurin@nrel.gov>
6
6
  Maintainer-email: Grant Buster <gbuster@nrel.gov>, Paul Pinchuk <ppinchuk@nrel.gov>
@@ -22,7 +22,7 @@ Description-Content-Type: text/x-rst
22
22
  License-File: LICENSE
23
23
  Requires-Dist: NREL-gaps<0.9,>=0.8.0
24
24
  Requires-Dist: NREL-NRWAL<0.1,>=0.0.11
25
- Requires-Dist: NREL-PySAM~=6.0.1
25
+ Requires-Dist: NREL-PySAM~=7.0.0
26
26
  Requires-Dist: NREL-rex<0.4,>=0.3.2
27
27
  Requires-Dist: numpy<3,>=2.0.2
28
28
  Requires-Dist: packaging<25,>=24.2
@@ -156,9 +156,6 @@ Option 1: Install from PIP (recommended for analysts):
156
156
  3. Install reV:
157
157
  1) ``pip install NREL-reV`` or
158
158
 
159
- - NOTE: If you install using conda and want to run from files directly on S3 like in the `running reV locally example <https://nrel.github.io/reV/misc/examples.running_locally.html>`_
160
- you will also need to install S3 filesystem dependencies: ``pip install NREL-reV[s3]``
161
-
162
159
  - NOTE: If you install using conda and want to use `HSDS <https://github.com/NREL/hsds-examples>`_
163
160
  you will also need to install HSDS dependencies: ``pip install NREL-reV[hsds]``
164
161
 
@@ -111,9 +111,6 @@ Option 1: Install from PIP (recommended for analysts):
111
111
  3. Install reV:
112
112
  1) ``pip install NREL-reV`` or
113
113
 
114
- - NOTE: If you install using conda and want to run from files directly on S3 like in the `running reV locally example <https://nrel.github.io/reV/misc/examples.running_locally.html>`_
115
- you will also need to install S3 filesystem dependencies: ``pip install NREL-reV[s3]``
116
-
117
114
  - NOTE: If you install using conda and want to use `HSDS <https://github.com/NREL/hsds-examples>`_
118
115
  you will also need to install HSDS dependencies: ``pip install NREL-reV[hsds]``
119
116
 
@@ -1,6 +1,6 @@
1
1
  [build-system]
2
2
  requires = [
3
- "setuptools >= 61",
3
+ "setuptools >= 80",
4
4
  "setuptools_scm[toml] >= 8",
5
5
  ]
6
6
  build-backend = 'setuptools.build_meta'
@@ -33,7 +33,7 @@ classifiers=[
33
33
  dependencies = [
34
34
  "NREL-gaps>=0.8.0,<0.9",
35
35
  "NREL-NRWAL>=0.0.11,<0.1",
36
- "NREL-PySAM~=6.0.1",
36
+ "NREL-PySAM~=7.0.0",
37
37
  "NREL-rex>=0.3.2,<0.4",
38
38
  "numpy>=2.0.2,<3",
39
39
  "packaging>=24.2,<25",
@@ -6,8 +6,9 @@ Created on Mon Feb 3 14:40:42 2020
6
6
  @author: gbuster
7
7
  """
8
8
  import logging
9
+ import importlib
9
10
  from warnings import warn
10
- from pkg_resources import get_distribution
11
+
11
12
  from packaging import version
12
13
  from reV.utilities.exceptions import PySAMVersionError, PySAMVersionWarning
13
14
 
@@ -105,7 +106,7 @@ class PySamVersionChecker:
105
106
  @property
106
107
  def pysam_version(self):
107
108
  """Get the PySAM distribution version"""
108
- return str(get_distribution('nrel-pysam')).split(' ')[1]
109
+ return importlib.metadata.version("nrel-pysam")
109
110
 
110
111
  @classmethod
111
112
  def run(cls, tech, parameters):
@@ -23,7 +23,7 @@ from rex.multi_year_resource import MultiYearWindResource
23
23
  from rex.utilities.bc_parse_table import parse_bc_table
24
24
  from rex.utilities.execution import SpawnProcessPool
25
25
  from rex.utilities.loggers import create_dirs, log_mem
26
- from rex.utilities.utilities import parse_year
26
+ from rex.utilities.utilities import parse_year, check_res_file
27
27
 
28
28
  from reV.config.output_request import SAMOutputRequest
29
29
  from reV.econ.utilities import lcoe_fcr
@@ -80,7 +80,8 @@ class BespokeMultiPlantData:
80
80
  Option to pre-load relative humidity data (useful for icing
81
81
  runs). If ``False``, relative humidities are not loaded.
82
82
  """
83
- self.res_fpath = res_fpath
83
+ self.res_fpath = ([res_fpath]
84
+ if isinstance(res_fpath, str) else res_fpath)
84
85
  self.sc_gid_to_hh = sc_gid_to_hh
85
86
  self.sc_gid_to_res_gid = sc_gid_to_res_gid
86
87
  self.hh_to_res_gids = {}
@@ -104,8 +105,9 @@ class BespokeMultiPlantData:
104
105
  hh: sorted(gids) for hh, gids in self.hh_to_res_gids.items()
105
106
  }
106
107
 
108
+ hsds = all(check_res_file(fp)[1] for fp in self.res_fpath)
107
109
  start_time = time.time()
108
- with MultiYearWindResource(self.res_fpath) as res:
110
+ with MultiYearWindResource(self.res_fpath, hsds=hsds) as res:
109
111
  self._wind_dirs = {
110
112
  hh: res[f"winddirection_{hh}m", :, gids]
111
113
  for hh, gids in self.hh_to_res_gids.items()
@@ -488,7 +490,9 @@ class BespokeSinglePlant:
488
490
  self._pre_loaded_data = pre_loaded_data
489
491
  self._outputs = {}
490
492
 
491
- res = res if not isinstance(res, str) else MultiYearWindResource(res)
493
+ if isinstance(res, str):
494
+ __, hsds = check_res_file(res)
495
+ res = MultiYearWindResource(res, hsds=hsds)
492
496
 
493
497
  self._sc_point = AggSCPoint(
494
498
  gid,
@@ -1087,8 +1091,8 @@ class BespokeSinglePlant:
1087
1091
  fcr = lcoe_kwargs['fixed_charge_rate']
1088
1092
  cc = lcoe_kwargs['capital_cost']
1089
1093
  foc = lcoe_kwargs['fixed_operating_cost']
1090
- voc = lcoe_kwargs['variable_operating_cost']
1091
- aep = self.outputs['annual_energy-means']
1094
+ voc = lcoe_kwargs['variable_operating_cost'] # $/kWh
1095
+ aep = self.outputs['annual_energy-means'] # kWh
1092
1096
 
1093
1097
  my_mean_lcoe = lcoe_fcr(fcr, cc, foc, aep, voc)
1094
1098
 
@@ -1184,6 +1188,7 @@ class BespokeSinglePlant:
1184
1188
  'wind_resource_data',
1185
1189
  'wind_turbine_powercurve_powerout',
1186
1190
  'adjust_hourly',
1191
+ 'adjust_timeindex',
1187
1192
  'capital_cost',
1188
1193
  'fixed_operating_cost',
1189
1194
  'variable_operating_cost',
@@ -1387,12 +1392,12 @@ class BespokeSinglePlant:
1387
1392
  self._meta[SupplyCurveField.EOS_MULT] = eos_mult
1388
1393
  self._meta[SupplyCurveField.REG_MULT] = reg_mult_cc
1389
1394
 
1390
- self._meta[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW] = (
1395
+ self._meta[SupplyCurveField.COST_SITE_CC_USD_PER_AC_MW] = (
1391
1396
  (self.plant_optimizer.capital_cost
1392
1397
  + self.plant_optimizer.balance_of_system_cost)
1393
1398
  / capacity_ac_mw
1394
1399
  )
1395
- self._meta[SupplyCurveField.COST_BASE_OCC_USD_PER_AC_MW] = (
1400
+ self._meta[SupplyCurveField.COST_BASE_CC_USD_PER_AC_MW] = (
1396
1401
  (self.plant_optimizer.capital_cost / eos_mult / reg_mult_cc
1397
1402
  + self.plant_optimizer.balance_of_system_cost / reg_mult_bos)
1398
1403
  / capacity_ac_mw
@@ -1406,14 +1411,13 @@ class BespokeSinglePlant:
1406
1411
  / reg_mult_foc
1407
1412
  / capacity_ac_mw
1408
1413
  )
1409
- self._meta[SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW] = (
1410
- self.plant_optimizer.variable_operating_cost
1411
- / capacity_ac_mw
1414
+ self._meta[SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MWH] = (
1415
+ self.plant_optimizer.variable_operating_cost * 1000 # to $/MWh
1412
1416
  )
1413
- self._meta[SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MW] = (
1417
+ self._meta[SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MWH] = (
1414
1418
  self.plant_optimizer.variable_operating_cost
1415
1419
  / reg_mult_voc
1416
- / capacity_ac_mw
1420
+ * 1000 # to $/MWh
1417
1421
  )
1418
1422
  self._meta[SupplyCurveField.FIXED_CHARGE_RATE] = (
1419
1423
  self.plant_optimizer.fixed_charge_rate
@@ -1972,7 +1976,8 @@ class BespokeWindPlants(BaseAggregation):
1972
1976
  pre_extract_inclusions=pre_extract_inclusions,
1973
1977
  )
1974
1978
 
1975
- self._res_fpath = res_fpath
1979
+ self._res_fpath = ([res_fpath]
1980
+ if isinstance(res_fpath, str) else res_fpath)
1976
1981
  self._obj_fun = objective_function
1977
1982
  self._cap_cost_fun = capital_cost_function
1978
1983
  self._foc_fun = fixed_operating_cost_function
@@ -2123,8 +2128,9 @@ class BespokeWindPlants(BaseAggregation):
2123
2128
  )
2124
2129
  )
2125
2130
 
2131
+ hsds = all(check_res_file(fp)[1] for fp in self._res_fpath)
2126
2132
  # just check that this file exists, cannot check res_fpath if *glob
2127
- with MultiYearWindResource(self._res_fpath) as f:
2133
+ with MultiYearWindResource(self._res_fpath, hsds=hsds) as f:
2128
2134
  assert any(f.dsets)
2129
2135
 
2130
2136
  def _pre_load_data(self, pre_load_data):
@@ -2494,6 +2500,7 @@ class BespokeWindPlants(BaseAggregation):
2494
2500
  "area_filter_kernel": area_filter_kernel,
2495
2501
  "min_area": min_area,
2496
2502
  "h5_handler": MultiYearWindResource,
2503
+ "hsds": all(check_res_file(fp)[1] for fp in res_fpath),
2497
2504
  }
2498
2505
 
2499
2506
  with AggFileHandler(excl_fpath, res_fpath, **file_kwargs) as fh:
@@ -12,6 +12,7 @@ from reV.handlers.cli_collect import collect_command
12
12
  from reV.handlers.cli_multi_year import my_command
13
13
  from reV.supply_curve.cli_sc_aggregation import sc_agg_command
14
14
  from reV.supply_curve.cli_supply_curve import sc_command
15
+ from reV.supply_curve.cli_tech_mapping import tm_command
15
16
  from reV.rep_profiles.cli_rep_profiles import rep_profiles_command
16
17
  from reV.hybrids.cli_hybrids import hybrids_command
17
18
  from reV.nrwal.cli_nrwal import nrwal_command
@@ -24,8 +25,9 @@ logger = logging.getLogger(__name__)
24
25
 
25
26
 
26
27
  commands = [bespoke_command, gen_command, econ_command, collect_command,
27
- my_command, sc_agg_command, sc_command, rep_profiles_command,
28
- hybrids_command, nrwal_command, qa_qc_command]
28
+ my_command, tm_command, sc_agg_command, sc_command,
29
+ rep_profiles_command, hybrids_command, nrwal_command,
30
+ qa_qc_command]
29
31
  main = make_cli(commands, info={"name": "reV", "version": __version__})
30
32
  main.add_command(qa_qc_extra)
31
33
  main.add_command(project_points)
@@ -464,8 +464,10 @@ class ProjectPoints:
464
464
  h_var = "wind_turbine_hub_ht"
465
465
  if self._h is None:
466
466
  if "wind" in self.tech:
467
- # wind technology, get a list of h values
468
- self._h = [self[site][1][h_var] for site in self.sites]
467
+ if h_var in self.df.columns:
468
+ self._h = self.df[h_var].values.tolist()
469
+ else:
470
+ self._h = [self[site][1][h_var] for site in self.sites]
469
471
 
470
472
  return self._h
471
473
 
@@ -837,7 +839,6 @@ class ProjectPoints:
837
839
  logger.error(msg)
838
840
  raise ConfigError(msg)
839
841
 
840
-
841
842
  unused_configs = set(curtail_configs) - set(df_configs)
842
843
  if unused_configs:
843
844
  msg = ("One or more curtailment configurations not found in "
@@ -1164,12 +1165,14 @@ class ProjectPoints:
1164
1165
  multi_h5_res, hsds = check_res_file(res_file)
1165
1166
  if multi_h5_res:
1166
1167
  res_cls = MultiFileResourceX
1168
+ res_kwargs = {}
1167
1169
  else:
1168
1170
  res_cls = ResourceX
1171
+ res_kwargs = {"hsds": hsds}
1169
1172
 
1170
1173
  logger.info("Extracting ProjectPoints for desired regions")
1171
1174
  points = []
1172
- with res_cls(res_file, hsds=hsds) as f:
1175
+ with res_cls(res_file, **res_kwargs) as f:
1173
1176
  meta = f.meta
1174
1177
  for region, region_col in regions.items():
1175
1178
  logger.debug("- {}: {}".format(region_col, region))
@@ -1181,7 +1184,7 @@ class ProjectPoints:
1181
1184
  if duplicates:
1182
1185
  msg = (
1183
1186
  "reV Cannot currently handle duplicate "
1184
- "Resource gids! The given regions containg the "
1187
+ "Resource gids! The given regions containing the "
1185
1188
  "same gids:\n{}".format(duplicates)
1186
1189
  )
1187
1190
  logger.error(msg)
@@ -34,31 +34,54 @@ class EconomiesOfScale:
34
34
  lcoe : $/MWh
35
35
  """
36
36
 
37
- def __init__(self, eqn, data):
37
+ def __init__(self, data, cap_eqn=None, fixed_eqn=None, var_eqn=None):
38
38
  """
39
+
39
40
  Parameters
40
41
  ----------
41
- eqn : str
42
- LCOE scaling equation to implement "economies of scale".
43
- Equation must be in python string format and return a scalar
44
- value to multiply the capital cost by. Independent variables in
45
- the equation should match the keys in the data input arg. This
46
- equation may use numpy functions with the package prefix "np".
47
42
  data : dict | pd.DataFrame
48
43
  Namespace of econ data to use to calculate economies of scale. Keys
49
44
  in dict or column labels in dataframe should match the Independent
50
45
  variables in the eqn input. Should also include variables required
51
46
  to calculate LCOE.
47
+ cap_eqn : str, optional
48
+ LCOE scaling equation to implement "economies of scale".
49
+ Equation must be in python string format and return a scalar
50
+ value to multiply the capital cost by. Independent variables in
51
+ the equation should match the keys in the data input arg. This
52
+ equation may use numpy functions with the package prefix "np". If
53
+ ``None``, no economies of scale are applied to the capital cost.
54
+ By default, ``None``.
55
+ fixed_eqn : str, optional
56
+ LCOE scaling equation to implement "economies of scale".
57
+ Equation must be in python string format and return a scalar
58
+ value to multiply the fixed operating cost by. Independent
59
+ variables in the equation should match the keys in the data input
60
+ arg. This equation may use numpy functions with the package prefix
61
+ "np". If ``None``, no economies of scale are applied to the
62
+ fixed operating cost. By default, ``None``.
63
+ var_eqn : str, optional
64
+ LCOE scaling equation to implement "economies of scale".
65
+ Equation must be in python string format and return a scalar
66
+ value to multiply the variable operating cost by. Independent
67
+ variables in the equation should match the keys in the data input
68
+ arg. This equation may use numpy functions with the package prefix
69
+ "np". If ``None``, no economies of scale are applied to the
70
+ variable operating cost. By default, ``None``.
52
71
  """
53
- self._eqn = eqn
54
72
  self._data = data
73
+ self._cap_eqn = cap_eqn
74
+ self._fixed_eqn = fixed_eqn
75
+ self._var_eqn = var_eqn
76
+ self._vars = None
55
77
  self._preflight()
56
78
 
57
79
  def _preflight(self):
58
80
  """Run checks to validate EconomiesOfScale equation and input data."""
59
81
 
60
- if self._eqn is not None:
61
- check_eval_str(str(self._eqn))
82
+ for eq in self._all_equations:
83
+ if eq is not None:
84
+ check_eval_str(str(eq))
62
85
 
63
86
  if isinstance(self._data, pd.DataFrame):
64
87
  self._data = {
@@ -79,11 +102,16 @@ class EconomiesOfScale:
79
102
  if any(missing):
80
103
  e = (
81
104
  "Cannot evaluate EconomiesOfScale, missing data for variables"
82
- ": {} for equation: {}".format(missing, self._eqn)
105
+ ": {} for equation: {}".format(missing, self._cap_eqn)
83
106
  )
84
107
  logger.error(e)
85
108
  raise KeyError(e)
86
109
 
110
+ @property
111
+ def _all_equations(self):
112
+ """gen: All EOS equations"""
113
+ yield from (self._cap_eqn, self._fixed_eqn, self._var_eqn)
114
+
87
115
  @staticmethod
88
116
  def is_num(s):
89
117
  """Check if a string is a number"""
@@ -111,36 +139,51 @@ class EconomiesOfScale:
111
139
  the equation string. This will return an empty list if the equation
112
140
  has no variables.
113
141
  """
114
- var_names = []
115
- if self._eqn is not None:
116
- delimiters = (">", "<", ">=", "<=", "==", ",", "*", "/", "+", "-",
117
- " ", "(", ")", "[", "]")
142
+ if self._vars is not None:
143
+ return self._vars
144
+
145
+ self._vars = []
146
+ for eq in self._all_equations:
147
+ if eq is None:
148
+ continue
149
+
150
+ delimiters = (">", "<", ">=", "<=", "==", ",", "*", "/", "+",
151
+ "-", " ", "(", ")", "[", "]")
118
152
  regex_pattern = "|".join(map(re.escape, delimiters))
119
- var_names = []
120
- for sub in re.split(regex_pattern, str(self._eqn)):
121
- if sub and not self.is_num(sub) and not self.is_method(sub):
122
- var_names.append(sub)
123
- var_names = sorted(set(var_names))
153
+ for sub_str in re.split(regex_pattern, str(eq)):
154
+ is_valid_var_name = (sub_str and not self.is_num(sub_str)
155
+ and not self.is_method(sub_str))
156
+ if is_valid_var_name:
157
+ self._vars.append(sub_str)
124
158
 
125
- return var_names
159
+ self._vars = sorted(set(self._vars))
160
+ return self._vars
126
161
 
127
- def _evaluate(self):
162
+ def _evaluate(self, eqn):
128
163
  """Evaluate the EconomiesOfScale equation with Independent variables
129
164
  parsed into a kwargs dictionary input.
130
165
 
166
+ Parameters
167
+ ----------
168
+ eqn : str
169
+ LCOE scaling equation to implement "economies of scale".
170
+ Equation must be in python string format and return a scalar
171
+ multiplier. Independent variables in the equation should match the
172
+ keys in the data input arg. This equation may use numpy functions
173
+ with the package prefix "np". If ``None``, this function returns
174
+ ``1``.
175
+
131
176
  Returns
132
177
  -------
133
178
  out : float | np.ndarray
134
- Evaluated output of the EconomiesOfScale equation. Should be
135
- numeric scalars to apply directly to the capital cost.
179
+ Evaluated output of the EconomiesOfScale equation.
136
180
  """
137
- out = 1
138
- if self._eqn is not None:
139
- kwargs = {k: self._data[k] for k in self.vars}
140
- # pylint: disable=eval-used
141
- out = eval(str(self._eqn), globals(), kwargs)
181
+ if eqn is None:
182
+ return 1
142
183
 
143
- return out
184
+ kwargs = {k: self._data[k] for k in self.vars}
185
+ # pylint: disable=eval-used
186
+ return eval(str(eqn), globals(), kwargs)
144
187
 
145
188
  @staticmethod
146
189
  def _get_prioritized_keys(input_dict, key_list):
@@ -180,8 +223,8 @@ class EconomiesOfScale:
180
223
 
181
224
  @property
182
225
  def capital_cost_scalar(self):
183
- """Evaluated output of the EconomiesOfScale equation. Should be
184
- numeric scalars to apply directly to the capital cost.
226
+ """Evaluated output of the EconomiesOfScale capital cost equation.
227
+ Should be numeric scalars to apply directly to the capital cost.
185
228
 
186
229
  Returns
187
230
  -------
@@ -189,7 +232,35 @@ class EconomiesOfScale:
189
232
  Evaluated output of the EconomiesOfScale equation. Should be
190
233
  numeric scalars to apply directly to the capital cost.
191
234
  """
192
- return self._evaluate()
235
+ return self._evaluate(self._cap_eqn)
236
+
237
+ @property
238
+ def fixed_operating_cost_scalar(self):
239
+ """Evaluated output of the EconomiesOfScale fixed operating cost
240
+ equation. Should be numeric scalars to apply directly to the fixed
241
+ operating cost.
242
+
243
+ Returns
244
+ -------
245
+ out : float | np.ndarray
246
+ Evaluated output of the EconomiesOfScale equation. Should be
247
+ numeric scalars to apply directly to the fixed operating cost.
248
+ """
249
+ return self._evaluate(self._fixed_eqn)
250
+
251
+ @property
252
+ def variable_operating_cost_scalar(self):
253
+ """Evaluated output of the EconomiesOfScale equation variable
254
+ operating cost. Should be numeric scalars to apply directly to the
255
+ variable operating cost.
256
+
257
+ Returns
258
+ -------
259
+ out : float | np.ndarray
260
+ Evaluated output of the EconomiesOfScale equation. Should be
261
+ numeric scalars to apply directly to the variable operating cost.
262
+ """
263
+ return self._evaluate(self._var_eqn)
193
264
 
194
265
  def _cost_from_cap(self, col_name):
195
266
  """Get full cost value from cost per mw in data.
@@ -221,10 +292,10 @@ class EconomiesOfScale:
221
292
  Returns
222
293
  -------
223
294
  out : float | np.ndarray
224
- Unscaled (raw) capital_cost found in the data input arg.
295
+ Unscaled (raw) capital_cost ($) found in the data input arg.
225
296
  """
226
297
  raw_capital_cost_from_cap = self._cost_from_cap(
227
- SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW
298
+ SupplyCurveField.COST_SITE_CC_USD_PER_AC_MW
228
299
  )
229
300
  if raw_capital_cost_from_cap is not None:
230
301
  return raw_capital_cost_from_cap
@@ -240,8 +311,8 @@ class EconomiesOfScale:
240
311
  Returns
241
312
  -------
242
313
  out : float | np.ndarray
243
- Capital cost found in the data input arg scaled by the evaluated
244
- EconomiesOfScale equation.
314
+ Capital cost ($) found in the data input arg scaled by the
315
+ evaluated EconomiesOfScale equation.
245
316
  """
246
317
  cc = copy.deepcopy(self.raw_capital_cost)
247
318
  cc *= self.capital_cost_scalar
@@ -265,13 +336,13 @@ class EconomiesOfScale:
265
336
  return self._get_prioritized_keys(self._data, key_list)
266
337
 
267
338
  @property
268
- def foc(self):
269
- """Fixed operating cost from input data arg
339
+ def raw_fixed_operating_cost(self):
340
+ """Unscaled (raw) fixed operating cost from input data arg
270
341
 
271
342
  Returns
272
343
  -------
273
344
  out : float | np.ndarray
274
- Fixed operating cost from input data arg
345
+ Unscaled (raw) fixed operating cost ($/year) from input data arg
275
346
  """
276
347
  foc_from_cap = self._cost_from_cap(
277
348
  SupplyCurveField.COST_SITE_FOC_USD_PER_AC_MW
@@ -284,42 +355,70 @@ class EconomiesOfScale:
284
355
  return self._get_prioritized_keys(self._data, key_list)
285
356
 
286
357
  @property
287
- def voc(self):
288
- """Variable operating cost from input data arg
358
+ def scaled_fixed_operating_cost(self):
359
+ """Fixed operating cost found in the data input arg scaled by the
360
+ evaluated EconomiesOfScale input equation.
289
361
 
290
362
  Returns
291
363
  -------
292
364
  out : float | np.ndarray
293
- Variable operating cost from input data arg
365
+ Fixed operating cost ($/year) found in the data input arg scaled
366
+ by the evaluated EconomiesOfScale equation.
294
367
  """
295
- voc_from_cap = self._cost_from_cap(
296
- SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW
297
- )
298
- if voc_from_cap is not None:
299
- return voc_from_cap
368
+ foc = copy.deepcopy(self.raw_fixed_operating_cost)
369
+ foc *= self.fixed_operating_cost_scalar
370
+ return foc
371
+
372
+ @property
373
+ def raw_variable_operating_cost(self):
374
+ """Unscaled (raw) variable operating cost from input data arg
375
+
376
+ Returns
377
+ -------
378
+ out : float | np.ndarray
379
+ Unscaled (raw) variable operating cost ($/kWh) from input
380
+ data arg
381
+ """
382
+ voc_mwh = self._data.get(SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MWH)
383
+ if voc_mwh is not None:
384
+ return voc_mwh / 1000 # convert to $/kWh
300
385
 
301
386
  key_list = ["variable_operating_cost", "mean_variable_operating_cost",
302
387
  "voc", "mean_voc"]
303
388
  return self._get_prioritized_keys(self._data, key_list)
304
389
 
390
+ @property
391
+ def scaled_variable_operating_cost(self):
392
+ """Variable operating cost found in the data input arg scaled by the
393
+ evaluated EconomiesOfScale input equation.
394
+
395
+ Returns
396
+ -------
397
+ out : float | np.ndarray
398
+ Variable operating cost ($/kWh) found in the data input arg
399
+ scaled by the evaluated EconomiesOfScale equation.
400
+ """
401
+ voc = copy.deepcopy(self.raw_variable_operating_cost)
402
+ voc *= self.variable_operating_cost_scalar
403
+ return voc
404
+
305
405
  @property
306
406
  def aep(self):
307
- """Annual energy production back-calculated from the raw LCOE:
407
+ """Annual energy production (kWh) back-calculated from the raw LCOE:
308
408
 
309
- AEP = (fcr * raw_cap_cost + foc) / raw_lcoe
409
+ AEP = (fcr * raw_cap_cost + raw_foc) / (raw_lcoe - raw_voc)
310
410
 
311
411
  Returns
312
412
  -------
313
413
  out : float | np.ndarray
314
414
  """
315
-
316
- aep = (self.fcr * self.raw_capital_cost + self.foc) / self.raw_lcoe
317
- aep *= 1000 # convert MWh to KWh
318
- return aep
415
+ num = self.fcr * self.raw_capital_cost + self.raw_fixed_operating_cost
416
+ denom = self.raw_lcoe - (self.raw_variable_operating_cost * 1000)
417
+ return num / denom * 1000 # convert MWh to KWh
319
418
 
320
419
  @property
321
420
  def raw_lcoe(self):
322
- """Raw LCOE taken from the input data
421
+ """Raw LCOE ($/MWh) taken from the input data
323
422
 
324
423
  Returns
325
424
  -------
@@ -330,17 +429,17 @@ class EconomiesOfScale:
330
429
 
331
430
  @property
332
431
  def scaled_lcoe(self):
333
- """LCOE calculated with the scaled capital cost based on the
432
+ """LCOE ($/MWh) calculated with the scaled costs based on the
334
433
  EconomiesOfScale input equation.
335
434
 
336
- LCOE = (FCR * scaled_capital_cost + FOC) / AEP + VOC
435
+ LCOE = (FCR * scaled_capital_cost + scaled_FOC) / AEP + scaled_VOC
337
436
 
338
437
  Returns
339
438
  -------
340
439
  lcoe : float | np.ndarray
341
- LCOE calculated with the scaled capital cost based on the
440
+ LCOE calculated with the scaled costs based on the
342
441
  EconomiesOfScale input equation.
343
442
  """
344
- return lcoe_fcr(
345
- self.fcr, self.scaled_capital_cost, self.foc, self.aep, self.voc
346
- )
443
+ return lcoe_fcr(self.fcr, self.scaled_capital_cost,
444
+ self.scaled_fixed_operating_cost, self.aep,
445
+ self.scaled_variable_operating_cost)