NREL-reV 0.9.2__py3-none-any.whl → 0.9.4__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: NREL-reV
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: National Renewable Energy Laboratory's (NREL's) Renewable Energy Potential(V) Model: reV
5
5
  Home-page: https://nrel.github.io/reV/
6
6
  Author: Galen Maclaurin
@@ -17,22 +17,22 @@ Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Requires-Python: >=3.8
20
- Requires-Dist: NREL-gaps >=0.6.11
21
- Requires-Dist: NREL-NRWAL >=0.0.7
22
- Requires-Dist: NREL-PySAM ~=4.1.0
23
- Requires-Dist: NREL-rex >=0.2.85
24
- Requires-Dist: numpy ~=1.24.4
25
- Requires-Dist: packaging >=20.3
26
- Requires-Dist: plotly >=4.7.1
27
- Requires-Dist: plotting >=0.0.6
20
+ Requires-Dist: NREL-gaps>=0.6.11
21
+ Requires-Dist: NREL-NRWAL>=0.0.7
22
+ Requires-Dist: NREL-PySAM~=4.1.0
23
+ Requires-Dist: NREL-rex>=0.2.89
24
+ Requires-Dist: numpy~=1.24.4
25
+ Requires-Dist: packaging>=20.3
26
+ Requires-Dist: plotly>=4.7.1
27
+ Requires-Dist: plotting>=0.0.6
28
28
  Requires-Dist: shapely
29
29
  Provides-Extra: dev
30
- Requires-Dist: pytest >=5.2 ; extra == 'dev'
31
- Requires-Dist: flake8 ; extra == 'dev'
32
- Requires-Dist: pre-commit ; extra == 'dev'
33
- Requires-Dist: pylint ; extra == 'dev'
30
+ Requires-Dist: pytest>=5.2; extra == "dev"
31
+ Requires-Dist: flake8; extra == "dev"
32
+ Requires-Dist: pre-commit; extra == "dev"
33
+ Requires-Dist: pylint; extra == "dev"
34
34
  Provides-Extra: test
35
- Requires-Dist: pytest >=5.2 ; extra == 'test'
35
+ Requires-Dist: pytest>=5.2; extra == "test"
36
36
 
37
37
 
38
38
                 
@@ -1,11 +1,11 @@
1
1
  reV/__init__.py,sha256=tXTpWu_qVo3uotfSw_TJ-gNbidGaIPPfUTwBlpCMJ-g,856
2
2
  reV/cli.py,sha256=jfGGOr6QlLz8ghA7vBgx5-VgNsy4bBQo5DdHk42-q9A,1601
3
- reV/version.py,sha256=ZggWF5z5HY0xtKYNitKGKEQSDJ5G21AZQKZMzs5u-wo,50
4
- reV/SAM/SAM.py,sha256=SUyaWK3InUh90iQqbka-g_X36EfGuwslEfKEPCIpMrw,31691
3
+ reV/version.py,sha256=yGiTX3S7R3_KR7tg1ywY2A7vCKmVDUNzRXtyt803-Ds,50
4
+ reV/SAM/SAM.py,sha256=wdrL7EAbn6246_3NP6EIksLM2yIg4IKK4taaTA7oj5o,32130
5
5
  reV/SAM/__init__.py,sha256=LJqoncyKDY5ZP5WA4kboh561bce11F9Ge645Izah0EY,240
6
6
  reV/SAM/defaults.py,sha256=2zqT_mfrVtbvU7Pe6H4anNtiVkIyQbuJcGIOARzEsbM,7193
7
7
  reV/SAM/econ.py,sha256=dFhtUXp5eozSsPyk0XXji0HGexKJnxoct8cwE1ApHVg,20704
8
- reV/SAM/generation.py,sha256=D4vkir6uU9QgY_9AMQOXA-4blGcQoxRH0O6PEfgqWok,89142
8
+ reV/SAM/generation.py,sha256=WYFXb39v7gJp1xxyLtsMLrP8Ze9dB15cxqxRoeNdZyk,89144
9
9
  reV/SAM/version_checker.py,sha256=q-eXsmSB08A5hSelNH7uAe_bqPpqjsxaiS3OBjXBs-0,3997
10
10
  reV/SAM/windbos.py,sha256=fnq1uxtSl-vtJth0gTlHkCSsmvDbRROCo9RGdqA7hK4,7504
11
11
  reV/SAM/defaults/USA AZ Phoenix Sky Harbor Intl Ap (TMY3).csv,sha256=8QorTX0ACjgPgNV7kLSpTHOqfY4E17gkkpKB-qseiFk,406896
@@ -14,7 +14,7 @@ reV/SAM/defaults/US_Wave.csv,sha256=wvn9vGl9ZGKVHbCyq4muhMI6x1-nAaQfDS3hC4ftwBA,
14
14
  reV/SAM/defaults/geothermal.json,sha256=ivxnpxkfBrEl1MwLKXClLJfTfvF5UrbN87wpC_BFLck,2598
15
15
  reV/SAM/defaults/i_pvwattsv5.json,sha256=pZpNlK5MiowZmNwY7i9XRWp9G8pPLirwdBWCMVJVuKE,312
16
16
  reV/bespoke/__init__.py,sha256=vpXbyBUrUsTgK8UP_LafMjLiDg2CRG9WZLHPsOJoxek,109
17
- reV/bespoke/bespoke.py,sha256=DgNPIeCmeqpOSaMbaqmJKQGatoLd8MOPTTQpZBlvzJI,110353
17
+ reV/bespoke/bespoke.py,sha256=vvCyCaJc333yifTqQvGb-nV7OPen3fhpUE6vecelU78,111283
18
18
  reV/bespoke/cli_bespoke.py,sha256=nZc6rJlfxH2IXUz9bym4EO-C1k6VvulgweWoRrMg_cE,3028
19
19
  reV/bespoke/gradient_free.py,sha256=URWV1yiO2jyWk3_GOpfpLV_wlgJhXXGmTUwCB3WTV0Y,12015
20
20
  reV/bespoke/pack_turbs.py,sha256=l4btC2dPZkLvDgAAGVhAYgAZDbvwimGYRdrQDq0xT68,3740
@@ -37,7 +37,7 @@ reV/econ/utilities.py,sha256=ZOA49S1jfsvdenvlL7m-BAJIrAvpAHSix5-wrSW0uLc,1232
37
37
  reV/generation/__init__.py,sha256=LBecrbpL69tROol_OwVHTKBrTqgSSxJW59fs0k3o0jQ,75
38
38
  reV/generation/base.py,sha256=p6g8Bj8T98OfKu44LTocGtEozstbUvti6wSi3oroS5U,48758
39
39
  reV/generation/cli_gen.py,sha256=5RSlr8yO9zlB-1FzFZGClqsxqsrbr9rcS_8PlOjVx2s,4435
40
- reV/generation/generation.py,sha256=jtlUcfmQKDcXarRwj-iJBS_60TG-w2TKoowfU_1tBQg,46981
40
+ reV/generation/generation.py,sha256=o6nJlEcgs-QQ_fdqva-7jOhWl1wj-J7CIrRR5qNJyEQ,47434
41
41
  reV/generation/output_attributes/generation.json,sha256=cy8efVCJgNSYCsR3x3_VpMCtynYS3oaQG4M2MwcdzFY,4954
42
42
  reV/generation/output_attributes/lcoe_fcr.json,sha256=d_TGMkZsmsfDXQiWfhYjFkmwqi-wKF8JdHmiMCj2h38,136
43
43
  reV/generation/output_attributes/lcoe_fcr_inputs.json,sha256=Yb-WTXt9YD4wE4Uu315W2uLFH6g3fT40YY83mxS-aWE,1289
@@ -51,7 +51,7 @@ reV/handlers/__init__.py,sha256=N7KfWbXfHLizMpoUw6yo0egbyq3jb9QL4YouBLUf4mI,130
51
51
  reV/handlers/cli_collect.py,sha256=QRjhuJ1lV4BwGoguu0m4etrNRPMXGIZlijNyYsb7_5U,799
52
52
  reV/handlers/cli_multi_year.py,sha256=xMAQ70lVUMAPM10EkZwc_FreQLjnzQ9VmKl48MS1SO0,660
53
53
  reV/handlers/exclusions.py,sha256=_s-LHbjHAAHSIM6tFXCoJlLKcv0FBxbm6JAmuE_X_-I,12266
54
- reV/handlers/multi_year.py,sha256=3s4sYWBl9-1rxeTBTMkl5lDeFqCioi4uuxcZlbWmIbE,30998
54
+ reV/handlers/multi_year.py,sha256=4U-9nMVeKs03jIKdyeLq5FM9uQqAuYcgheAyMyWa5tg,30825
55
55
  reV/handlers/outputs.py,sha256=VbSPFwA0ZH-oWUCCtef7zGyPbWXKY07ilPzpZIOMmuc,6034
56
56
  reV/handlers/transmission.py,sha256=JzpmiweCez7vzGSutO21XIbG9czY_H6ysg_R7z290w0,25610
57
57
  reV/hybrids/__init__.py,sha256=oBrJSt9WeBlER7GVd-NEJgVqFlasl0WuyHJRMgLgpAY,133
@@ -74,24 +74,24 @@ reV/rep_profiles/cli_rep_profiles.py,sha256=i3fRolT7HTzTQePXpNLDyxwgpRa7FEfHO1mO
74
74
  reV/rep_profiles/rep_profiles.py,sha256=oqmtU9FbUlKurkglmZLyDBNH8VRKv8fgdSuvtYWLm04,48271
75
75
  reV/supply_curve/__init__.py,sha256=dbf0cO0qmt1VhV8dnDddztrcpnwua9T2HBhM6tLKaP8,274
76
76
  reV/supply_curve/aggregation.py,sha256=fv4FTdRUQWZ_1Ds84ubgJdrf5lR1xb3luhAnibe3Y3Q,38752
77
- reV/supply_curve/cli_sc_aggregation.py,sha256=drzYGFEHC3Ww1GBnk_iClFoQuXjT3nUEpv8I4Fgx8W4,2867
77
+ reV/supply_curve/cli_sc_aggregation.py,sha256=qGfJyZjg4tFARG2dl-wAlHv9KjEp2u4wg1Boxz18Gf0,3347
78
78
  reV/supply_curve/cli_supply_curve.py,sha256=e-XrHQIe4OqWTL6u-TUAyHrw7Alk7vkXQ2HoLbE3zTM,2163
79
79
  reV/supply_curve/competitive_wind_farms.py,sha256=eOjM72-4oWtsqxB7Wh2gnB2zVAt4LY3iPE_DqWdXbQ4,15795
80
80
  reV/supply_curve/exclusions.py,sha256=4-ZxTO5Vlu03vie0V_74uvdajQfCuC8FE96Pg8I4U_c,42950
81
81
  reV/supply_curve/extent.py,sha256=a31po753hXSxQ8lfcCvpE8hoKc4bY7MmYq0NO0jtdqA,17414
82
82
  reV/supply_curve/points.py,sha256=YEYHpn3KlBbGqpxywrfbrUrlhL3BndgX7cVQerdB6zg,86107
83
- reV/supply_curve/sc_aggregation.py,sha256=6kJg4CaLlFAC196azbfzA-T_wXkXSwNDQKOW-k2lqcE,61645
83
+ reV/supply_curve/sc_aggregation.py,sha256=R_h3xXKum4JTYMuq2us0rWhW0t2wm-G9Wj2on1d8FeY,61604
84
84
  reV/supply_curve/supply_curve.py,sha256=igbloCkvYQwaH4zjbrYO17J7TtCTX5dKkk-TnlGJJeY,69931
85
- reV/supply_curve/tech_mapping.py,sha256=7him2R-8kpigI47ATSN4ncnvzuF_AzeXyrtz_jmzLug,18573
85
+ reV/supply_curve/tech_mapping.py,sha256=nfqPIj9o1pllX3aRC1Hi2KGXYJOYy68Vbvr_1asNmFk,18573
86
86
  reV/utilities/__init__.py,sha256=iOvOuqcXv_WaSP627z2i2wF5820DbUSGRa7lSj23diQ,10534
87
87
  reV/utilities/cli_functions.py,sha256=1_T_sXz0Ct8lW-vOk3mMRcpD6NYsc9cGI7dEujIi9z4,3864
88
88
  reV/utilities/curtailment.py,sha256=fu48Lje-iyd2Awfe-6jFebvgcKSeJ3daNNTqjFI2GvM,4963
89
89
  reV/utilities/exceptions.py,sha256=f7sRGsbFLpmL6Caq_H1cD4GfVhnLMyvYUsLPA1UVDDE,3974
90
90
  reV/utilities/pytest_utils.py,sha256=T22NFEGxPOc9wRwgy0Pt2cHvw3Vam9cKwUj4AkzI7bU,3244
91
91
  reV/utilities/slots.py,sha256=xsw-JuUVZ0YeoCNuwP_HxGNxFMA4xRs1tuImXHIJqaU,2618
92
- NREL_reV-0.9.2.dist-info/LICENSE,sha256=hDwoTANtan2ZpufBlXm5C3W_PJ-mCqItvlcobgjxL7k,1526
93
- NREL_reV-0.9.2.dist-info/METADATA,sha256=eIecsAhbE1ayna5v0f8gIhfDFYeHN_Mgyjdo_uLEATY,10294
94
- NREL_reV-0.9.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
95
- NREL_reV-0.9.2.dist-info/entry_points.txt,sha256=KGtPEOQRZMSqKXjjv5jt_T4e4HQN0fHiaGdAWwTtuW4,617
96
- NREL_reV-0.9.2.dist-info/top_level.txt,sha256=S6YF2ZYgXUB6n28SY0K2H8YB9tMJdXQ9CyQbo6VC89M,4
97
- NREL_reV-0.9.2.dist-info/RECORD,,
92
+ NREL_reV-0.9.4.dist-info/LICENSE,sha256=hDwoTANtan2ZpufBlXm5C3W_PJ-mCqItvlcobgjxL7k,1526
93
+ NREL_reV-0.9.4.dist-info/METADATA,sha256=IN6FHUL4PezUaGzk6bmUM-0fF1Ux2HGNQoXumrFo4Lg,10279
94
+ NREL_reV-0.9.4.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
95
+ NREL_reV-0.9.4.dist-info/entry_points.txt,sha256=KGtPEOQRZMSqKXjjv5jt_T4e4HQN0fHiaGdAWwTtuW4,617
96
+ NREL_reV-0.9.4.dist-info/top_level.txt,sha256=S6YF2ZYgXUB6n28SY0K2H8YB9tMJdXQ9CyQbo6VC89M,4
97
+ NREL_reV-0.9.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: bdist_wheel (0.44.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
reV/SAM/SAM.py CHANGED
@@ -195,6 +195,11 @@ class SamResourceRetriever:
195
195
  # make precip rate available for curtailment analysis
196
196
  kwargs["precip_rate"] = True
197
197
 
198
+ sam_configs = project_points.sam_inputs.values()
199
+ needs_wd = any(_sam_config_contains_turbine_layout(sam_config)
200
+ for sam_config in sam_configs)
201
+ kwargs["require_wind_dir"] = needs_wd
202
+
198
203
  elif res_handler == GeothermalResource:
199
204
  args += (project_points.d,)
200
205
 
@@ -954,3 +959,8 @@ def _add_sys_capacity(sam_inputs):
954
959
  cap = sam_inputs.get("nameplate")
955
960
 
956
961
  sam_inputs["system_capacity"] = cap
962
+
963
+
964
+ def _sam_config_contains_turbine_layout(sam_config):
965
+ """Detect wether SAM config contains multiple turbines in layout. """
966
+ return len(sam_config.get("wind_farm_xCoordinates", ())) > 1
reV/SAM/generation.py CHANGED
@@ -1548,7 +1548,7 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
1548
1548
  or 1 allowed.
1549
1549
  - ``design_temp`` : EGS plant design temperature (in C). Only
1550
1550
  affects EGS runs. This value may be adjusted internally by
1551
- ``reV under the following conditions:
1551
+ ``reV`` under the following conditions:
1552
1552
 
1553
1553
  - The design temperature is larger than the resource
1554
1554
  temperature
reV/bespoke/bespoke.py CHANGED
@@ -20,7 +20,6 @@ import pandas as pd
20
20
  import psutil
21
21
  from rex.joint_pd.joint_pd import JointPD
22
22
  from rex.multi_year_resource import MultiYearWindResource
23
- from rex.renewable_resource import WindResource
24
23
  from rex.utilities.bc_parse_table import parse_bc_table
25
24
  from rex.utilities.execution import SpawnProcessPool
26
25
  from rex.utilities.loggers import create_dirs, log_mem
@@ -60,8 +59,13 @@ class BespokeMultiPlantData:
60
59
 
61
60
  Parameters
62
61
  ----------
63
- res_fpath : str
64
- Path to resource h5 file.
62
+ res_fpath : str | list
63
+ Unix shell style path (potentially containing wildcard (*)
64
+ patterns) to a single or multi-file resource file set(s).
65
+ Can also be an explicit list of resource file paths, which
66
+ themselves can contain wildcards. This input must be
67
+ readable by
68
+ :py:class:`rex.multi_year_resource.MultiYearWindResource`.
65
69
  sc_gid_to_hh : dict
66
70
  Dictionary mapping SC GID values to hub-heights. Data for
67
71
  each SC GID will be pulled for the corresponding hub-height
@@ -69,7 +73,7 @@ class BespokeMultiPlantData:
69
73
  sc_gid_to_res_gid : dict
70
74
  Dictionary mapping SC GID values to an iterable oif resource
71
75
  GID values. Resource GID values should correspond to GID
72
- values in teh HDF5 file, so any GID map must be applied
76
+ values in the HDF5 file, so any GID map must be applied
73
77
  before initializing :class`BespokeMultiPlantData`.
74
78
  """
75
79
  self.res_fpath = res_fpath
@@ -95,12 +99,7 @@ class BespokeMultiPlantData:
95
99
  }
96
100
 
97
101
  start_time = time.time()
98
- if "*" in self.res_fpath:
99
- handler = MultiYearWindResource
100
- else:
101
- handler = WindResource
102
-
103
- with handler(self.res_fpath) as res:
102
+ with MultiYearWindResource(self.res_fpath) as res:
104
103
  self._wind_dirs = {
105
104
  hh: res[f"winddirection_{hh}m", :, gids]
106
105
  for hh, gids in self.hh_to_res_gids.items()
@@ -481,8 +480,7 @@ class BespokeSinglePlant:
481
480
  self._pre_loaded_data = pre_loaded_data
482
481
  self._outputs = {}
483
482
 
484
- Handler = self.get_wind_handler(res)
485
- res = res if not isinstance(res, str) else Handler(res)
483
+ res = res if not isinstance(res, str) else MultiYearWindResource(res)
486
484
 
487
485
  self._sc_point = AggSCPoint(
488
486
  gid,
@@ -1142,29 +1140,6 @@ class BespokeSinglePlant:
1142
1140
  lcoe_kwargs["capital_cost"] = lcoe_kwargs["capital_cost"] + bos
1143
1141
  return lcoe_kwargs
1144
1142
 
1145
- @staticmethod
1146
- def get_wind_handler(res):
1147
- """Get a wind resource handler for a resource filepath.
1148
-
1149
- Parameters
1150
- ----------
1151
- res : str
1152
- Resource filepath to wtk .h5 file. Can include * wildcards
1153
- for multi year resource.
1154
-
1155
- Returns
1156
- -------
1157
- handler : WindResource | MultiYearWindResource
1158
- Wind resource handler or multi year handler
1159
- """
1160
- handler = res
1161
- if isinstance(res, str):
1162
- if "*" in res:
1163
- handler = MultiYearWindResource
1164
- else:
1165
- handler = WindResource
1166
- return handler
1167
-
1168
1143
  @classmethod
1169
1144
  def check_dependencies(cls):
1170
1145
  """Check special dependencies for bespoke"""
@@ -1382,32 +1357,45 @@ class BespokeSinglePlant:
1382
1357
  eos_mult = (self.plant_optimizer.capital_cost
1383
1358
  / self.plant_optimizer.capacity
1384
1359
  / baseline_cost)
1385
- reg_mult = self.sam_sys_inputs.get("capital_cost_multiplier", 1)
1360
+ reg_mult_cc = self.sam_sys_inputs.get(
1361
+ "capital_cost_multiplier", 1)
1362
+ reg_mult_foc = self.sam_sys_inputs.get(
1363
+ "fixed_operating_cost_multiplier", 1)
1364
+ reg_mult_voc = self.sam_sys_inputs.get(
1365
+ "variable_operating_cost_multiplier", 1)
1366
+ reg_mult_bos = self.sam_sys_inputs.get(
1367
+ "balance_of_system_cost_multiplier", 1)
1386
1368
 
1387
1369
  self._meta[SupplyCurveField.EOS_MULT] = eos_mult
1388
- self._meta[SupplyCurveField.REG_MULT] = reg_mult
1370
+ self._meta[SupplyCurveField.REG_MULT] = reg_mult_cc
1389
1371
 
1390
- cap_cost = (
1391
- self.plant_optimizer.capital_cost
1392
- + self.plant_optimizer.balance_of_system_cost
1393
- )
1394
1372
  self._meta[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW] = (
1395
- cap_cost / capacity_ac_mw
1373
+ (self.plant_optimizer.capital_cost
1374
+ + self.plant_optimizer.balance_of_system_cost)
1375
+ / capacity_ac_mw
1396
1376
  )
1397
1377
  self._meta[SupplyCurveField.COST_BASE_OCC_USD_PER_AC_MW] = (
1398
- cap_cost / eos_mult / reg_mult / capacity_ac_mw
1378
+ (self.plant_optimizer.capital_cost / eos_mult / reg_mult_cc
1379
+ + self.plant_optimizer.balance_of_system_cost / reg_mult_bos)
1380
+ / capacity_ac_mw
1399
1381
  )
1400
1382
  self._meta[SupplyCurveField.COST_SITE_FOC_USD_PER_AC_MW] = (
1401
- self.plant_optimizer.fixed_operating_cost / capacity_ac_mw
1383
+ self.plant_optimizer.fixed_operating_cost
1384
+ / capacity_ac_mw
1402
1385
  )
1403
1386
  self._meta[SupplyCurveField.COST_BASE_FOC_USD_PER_AC_MW] = (
1404
- self.plant_optimizer.fixed_operating_cost / capacity_ac_mw
1387
+ self.plant_optimizer.fixed_operating_cost
1388
+ / reg_mult_foc
1389
+ / capacity_ac_mw
1405
1390
  )
1406
1391
  self._meta[SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW] = (
1407
- self.plant_optimizer.variable_operating_cost / capacity_ac_mw
1392
+ self.plant_optimizer.variable_operating_cost
1393
+ / capacity_ac_mw
1408
1394
  )
1409
1395
  self._meta[SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MW] = (
1410
- self.plant_optimizer.variable_operating_cost / capacity_ac_mw
1396
+ self.plant_optimizer.variable_operating_cost
1397
+ / reg_mult_voc
1398
+ / capacity_ac_mw
1411
1399
  )
1412
1400
  self._meta[SupplyCurveField.FIXED_CHARGE_RATE] = (
1413
1401
  self.plant_optimizer.fixed_charge_rate
@@ -1489,8 +1477,9 @@ class BespokeWindPlants(BaseAggregation):
1489
1477
  ws_bins=(0.0, 20.0, 5.0), wd_bins=(0.0, 360.0, 45.0),
1490
1478
  excl_dict=None, area_filter_kernel='queen', min_area=None,
1491
1479
  resolution=64, excl_area=None, data_layers=None,
1492
- pre_extract_inclusions=False, prior_run=None, gid_map=None,
1493
- bias_correct=None, pre_load_data=False):
1480
+ pre_extract_inclusions=False, eos_mult_baseline_cap_mw=200,
1481
+ prior_run=None, gid_map=None, bias_correct=None,
1482
+ pre_load_data=False):
1494
1483
  """reV bespoke analysis class.
1495
1484
 
1496
1485
  Much like generation, ``reV`` bespoke analysis runs SAM
@@ -1521,14 +1510,15 @@ class BespokeWindPlants(BaseAggregation):
1521
1510
  uniquely defined (i.e.only appear once and in a single
1522
1511
  input file).
1523
1512
  res_fpath : str
1524
- Filepath to wind resource data in NREL WTK format. This
1525
- input can be path to a single resource HDF5 file or a path
1526
- including a wildcard input like ``/h5_dir/prefix*suffix`` to
1527
- run bespoke on multiple years of resource data. The former
1528
- must be readable by
1529
- :py:class:`rex.renewable_resource.WindResource` while the
1530
- latter must be readable by
1531
- or :py:class:`rex.multi_year_resource.MultiYearWindResource`
1513
+ Unix shell style path to wind resource HDF5 file in NREL WTK
1514
+ format. Can also be a path including a wildcard input like
1515
+ ``/h5_dir/prefix*suffix`` to run bespoke on multiple years
1516
+ of resource data. Can also be an explicit list of resource
1517
+ HDF5 file paths, which themselves can contain wildcards. If
1518
+ multiple files are specified in this way, they must have the
1519
+ same coordinates but can have different time indices (i.e.
1520
+ different years). This input must be readable by
1521
+ :py:class:`rex.multi_year_resource.MultiYearWindResource`
1532
1522
  (i.e. the resource data conform to the
1533
1523
  `rex data format <https://tinyurl.com/3fy7v5kx>`_). This
1534
1524
  means the data file(s) must contain a 1D ``time_index``
@@ -1855,6 +1845,13 @@ class BespokeWindPlants(BaseAggregation):
1855
1845
  the `excl_dict` input. It is typically faster to compute
1856
1846
  the inclusion mask on the fly with parallel workers.
1857
1847
  By default, ``False``.
1848
+ eos_mult_baseline_cap_mw : int | float, optional
1849
+ Baseline plant capacity (MW) used to calculate economies of
1850
+ scale (EOS) multiplier from the `capital_cost_function`. EOS
1851
+ multiplier is calculated as the $-per-kW of the wind plant
1852
+ divided by the $-per-kW of a plant with this baseline
1853
+ capacity. By default, `200` (MW), which aligns the baseline
1854
+ with ATB assumptions. See here: https://tinyurl.com/y85hnu6h.
1858
1855
  prior_run : str, optional
1859
1856
  Optional filepath to a bespoke output HDF5 file belonging to
1860
1857
  a prior run. If specified, this module will only run the
@@ -1980,6 +1977,7 @@ class BespokeWindPlants(BaseAggregation):
1980
1977
  self._ws_bins = ws_bins
1981
1978
  self._wd_bins = wd_bins
1982
1979
  self._data_layers = data_layers
1980
+ self._eos_mult_baseline_cap_mw = eos_mult_baseline_cap_mw
1983
1981
  self._prior_meta = self._parse_prior_run(prior_run)
1984
1982
  self._gid_map = BespokeSinglePlant._parse_gid_map(gid_map)
1985
1983
  self._bias_correct = Gen._parse_bc(bias_correct)
@@ -2119,8 +2117,7 @@ class BespokeWindPlants(BaseAggregation):
2119
2117
  )
2120
2118
 
2121
2119
  # just check that this file exists, cannot check res_fpath if *glob
2122
- Handler = BespokeSinglePlant.get_wind_handler(self._res_fpath)
2123
- with Handler(self._res_fpath) as f:
2120
+ with MultiYearWindResource(self._res_fpath) as f:
2124
2121
  assert any(f.dsets)
2125
2122
 
2126
2123
  def _pre_load_data(self, pre_load_data):
@@ -2453,8 +2450,8 @@ class BespokeWindPlants(BaseAggregation):
2453
2450
  area_filter_kernel='queen', min_area=None,
2454
2451
  resolution=64, excl_area=0.0081, data_layers=None,
2455
2452
  gids=None, exclusion_shape=None, slice_lookup=None,
2456
- prior_meta=None, gid_map=None, bias_correct=None,
2457
- pre_loaded_data=None):
2453
+ eos_mult_baseline_cap_mw=200, prior_meta=None,
2454
+ gid_map=None, bias_correct=None, pre_loaded_data=None):
2458
2455
  """
2459
2456
  Standalone serial method to run bespoke optimization.
2460
2457
  See BespokeWindPlants docstring for parameter description.
@@ -2480,14 +2477,13 @@ class BespokeWindPlants(BaseAggregation):
2480
2477
  exclusion_shape = sc.exclusions.shape
2481
2478
 
2482
2479
  cls._check_inclusion_mask(inclusion_mask, gids, exclusion_shape)
2483
- Handler = BespokeSinglePlant.get_wind_handler(res_fpath)
2484
2480
 
2485
2481
  # pre-extract handlers so they are not repeatedly initialized
2486
2482
  file_kwargs = {
2487
2483
  "excl_dict": excl_dict,
2488
2484
  "area_filter_kernel": area_filter_kernel,
2489
2485
  "min_area": min_area,
2490
- "h5_handler": Handler,
2486
+ "h5_handler": MultiYearWindResource,
2491
2487
  }
2492
2488
 
2493
2489
  with AggFileHandler(excl_fpath, res_fpath, **file_kwargs) as fh:
@@ -2520,6 +2516,7 @@ class BespokeWindPlants(BaseAggregation):
2520
2516
  excl_area=excl_area,
2521
2517
  data_layers=data_layers,
2522
2518
  exclusion_shape=exclusion_shape,
2519
+ eos_mult_baseline_cap_mw=eos_mult_baseline_cap_mw,
2523
2520
  prior_meta=prior_meta,
2524
2521
  gid_map=gid_map,
2525
2522
  bias_correct=bias_correct,
@@ -2612,6 +2609,7 @@ class BespokeWindPlants(BaseAggregation):
2612
2609
  gids=gid,
2613
2610
  exclusion_shape=self.shape,
2614
2611
  slice_lookup=copy.deepcopy(self.slice_lookup),
2612
+ eos_mult_baseline_cap_mw=self._eos_mult_baseline_cap_mw,
2615
2613
  prior_meta=self._get_prior_meta(gid),
2616
2614
  gid_map=self._gid_map,
2617
2615
  bias_correct=self._get_bc_for_gid(gid),
@@ -2676,6 +2674,7 @@ class BespokeWindPlants(BaseAggregation):
2676
2674
  afk = self._area_filter_kernel
2677
2675
  wlm = self._wake_loss_multiplier
2678
2676
  i_bc = self._get_bc_for_gid(gid)
2677
+ ebc = self._eos_mult_baseline_cap_mw
2679
2678
 
2680
2679
  si = self.run_serial(self._excl_fpath,
2681
2680
  self._res_fpath,
@@ -2700,6 +2699,7 @@ class BespokeWindPlants(BaseAggregation):
2700
2699
  excl_area=self._excl_area,
2701
2700
  data_layers=self._data_layers,
2702
2701
  slice_lookup=slice_lookup,
2702
+ eos_mult_baseline_cap_mw=ebc,
2703
2703
  prior_meta=prior_meta,
2704
2704
  gid_map=self._gid_map,
2705
2705
  bias_correct=i_bc,
@@ -236,10 +236,10 @@ class Gen(BaseGen):
236
236
  info on the allowed and/or required SAM config file inputs.
237
237
  resource_file : str
238
238
  Filepath to resource data. This input can be path to a
239
- single resource HDF5 file, a path to a directory containing
240
- data spread across multiple HDF5 files, or a path including
241
- a wildcard input like ``/h5_dir/prefix*suffix``. In all
242
- cases, the resource data must be readable by
239
+ single resource HDF5 file or a path including a wildcard
240
+ input like ``/h5_dir/prefix*suffix`` (i.e. if your datasets
241
+ for a single year are spread out over multiple files). In
242
+ all cases, the resource data must be readable by
243
243
  :py:class:`rex.resource.Resource`
244
244
  or :py:class:`rex.multi_file_resource.MultiFileResource`.
245
245
  (i.e. the resource data conform to the
@@ -253,8 +253,14 @@ class Gen(BaseGen):
253
253
  consideration, and its shape must be a multiple of 8760.
254
254
 
255
255
  .. Note:: If executing ``reV`` from the command line, this
256
- path can contain brackets ``{}`` that will be filled in by
257
- the `analysis_years` input.
256
+ input string can contain brackets ``{}`` that will be
257
+ filled in by the `analysis_years` input. Alternatively,
258
+ this input can be a list of explicit files to process. In
259
+ this case, the length of the list must match the length of
260
+ the `analysis_years` input exactly, and the path are
261
+ assumed to align with the `analysis_years` (i.e. the first
262
+ path corresponds to the first analysis year, the second
263
+ path corresponds to the second analysis year, and so on).
258
264
 
259
265
  .. Important:: If you are using custom resource data (i.e.
260
266
  not NSRDB/WTK/Sup3rCC, etc.), ensure the following:
@@ -103,8 +103,9 @@ class MultiYearGroup:
103
103
 
104
104
  if "lcoe_fcr" in dsets:
105
105
  for dset in LCOE_REQUIRED_OUTPUTS:
106
- if dset not in pass_through_dsets:
106
+ if dset not in pass_through_dsets and dset in dsets:
107
107
  pass_through_dsets.append(dset)
108
+
108
109
  if "dc_ac_ratio" in dsets:
109
110
  if "dc_ac_ratio" not in pass_through_dsets:
110
111
  pass_through_dsets.append("dc_ac_ratio")
@@ -839,11 +840,6 @@ def my_collect_groups(out_fpath, groups, clobber=True):
839
840
  dset, group=group['group'])
840
841
 
841
842
  pass_through_dsets = group.get('pass_through_dsets') or []
842
- if "lcoe_fcr" in group['dsets']:
843
- for dset in LCOE_REQUIRED_OUTPUTS:
844
- if dset not in pass_through_dsets:
845
- pass_through_dsets.append(dset)
846
-
847
843
  for dset in pass_through_dsets:
848
844
  MultiYear.pass_through(out_fpath, group['source_files'],
849
845
  dset, group=group['group'])
@@ -50,12 +50,25 @@ def _preprocessor(config, out_dir):
50
50
  def _format_res_fpath(config):
51
51
  """Format res_fpath with year, if need be. """
52
52
  res_fpath = config.setdefault("res_fpath", None)
53
- if isinstance(res_fpath, str) and '{}' in res_fpath:
54
- for year in range(1998, 2018):
55
- if os.path.exists(res_fpath.format(year)):
56
- break
57
-
58
- config["res_fpath"] = res_fpath.format(year)
53
+ if isinstance(res_fpath, str):
54
+ if '{}' in res_fpath:
55
+ for year in range(1950, 2100):
56
+ if os.path.exists(res_fpath.format(year)):
57
+ break
58
+ else:
59
+ msg = ("Could not find any files that match the pattern"
60
+ "{!r}".format(res_fpath.format("<year>")))
61
+ logger.error(msg)
62
+ raise FileNotFoundError(msg)
63
+
64
+ res_fpath = res_fpath.format(year)
65
+
66
+ elif not os.path.exists(res_fpath):
67
+ msg = "Could not find resource file: {!r}".format(res_fpath)
68
+ logger.error(msg)
69
+ raise FileNotFoundError(msg)
70
+
71
+ config["res_fpath"] = res_fpath
59
72
 
60
73
  return config
61
74
 
@@ -18,7 +18,6 @@ from rex.multi_file_resource import MultiFileResource
18
18
  from rex.resource import Resource
19
19
  from rex.utilities.execution import SpawnProcessPool
20
20
 
21
- from reV.generation.base import BaseGen
22
21
  from reV.handlers.exclusions import ExclusionLayers
23
22
  from reV.supply_curve.aggregation import (
24
23
  AbstractAggFileHandler,
@@ -1410,7 +1409,7 @@ class SupplyCurveAggregation(BaseAggregation):
1410
1409
  ``multi-year``, ``collect``, or ``econ``. However, note
1411
1410
  that duplicate executions of any of these commands within
1412
1411
  the pipeline may invalidate this parsing, meaning the
1413
- `econ_fpath` input will have to be specified manually.
1412
+ `gen_fpath` input will have to be specified manually.
1414
1413
 
1415
1414
  By default, ``None``.
1416
1415
  args : tuple | list, optional
@@ -185,7 +185,7 @@ class TechMapping:
185
185
  excl_row_slices, excl_col_slices,
186
186
  coord_labels=(LATITUDE, LONGITUDE)):
187
187
  """
188
- Extract the exclusion coordinates for teh desired gids for TechMapping.
188
+ Extract the exclusion coordinates for the desired gids for TechMapping.
189
189
 
190
190
  Parameters
191
191
  ----------
reV/version.py CHANGED
@@ -2,4 +2,4 @@
2
2
  reV Version number
3
3
  """
4
4
 
5
- __version__ = "0.9.2"
5
+ __version__ = "0.9.4"