NREL-reV 0.9.2__py3-none-any.whl → 0.9.5__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.
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/METADATA +14 -14
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/RECORD +15 -15
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/WHEEL +1 -1
- reV/SAM/SAM.py +15 -0
- reV/SAM/generation.py +4 -63
- reV/bespoke/bespoke.py +122 -78
- reV/generation/generation.py +12 -6
- reV/handlers/multi_year.py +6 -9
- reV/supply_curve/cli_sc_aggregation.py +19 -6
- reV/supply_curve/sc_aggregation.py +1 -2
- reV/supply_curve/tech_mapping.py +1 -1
- reV/version.py +1 -1
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/LICENSE +0 -0
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/entry_points.txt +0 -0
- {NREL_reV-0.9.2.dist-info → NREL_reV-0.9.5.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: NREL-reV
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.5
|
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
|
21
|
-
Requires-Dist: NREL-NRWAL
|
22
|
-
Requires-Dist: NREL-PySAM
|
23
|
-
Requires-Dist: NREL-rex
|
24
|
-
Requires-Dist: numpy
|
25
|
-
Requires-Dist: packaging
|
26
|
-
Requires-Dist: plotly
|
27
|
-
Requires-Dist: plotting
|
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
|
31
|
-
Requires-Dist: flake8
|
32
|
-
Requires-Dist: pre-commit
|
33
|
-
Requires-Dist: pylint
|
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
|
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
|
4
|
-
reV/SAM/SAM.py,sha256=
|
3
|
+
reV/version.py,sha256=-d0FHT8TbXm_fBuvfSz3da_dWANi_ww6eK4n0DOIYU0,50
|
4
|
+
reV/SAM/SAM.py,sha256=1xuxs2gb1wsgbBkhj3mdQVDuSWbp5T5Bh7kLRl69pkg,32258
|
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=
|
8
|
+
reV/SAM/generation.py,sha256=vUM2DUHCsKh_FBzuUKtFsq_oUXxm47c-oP33KvfA7Ow,86524
|
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=
|
17
|
+
reV/bespoke/bespoke.py,sha256=nWmryaLRFkOwkYLkKUQHgjXqc5YcFGODK4k6VEX0bRU,113473
|
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=
|
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=
|
54
|
+
reV/handlers/multi_year.py,sha256=nLskop2crDnRfd0DwnFw6SZZBqgiJbf9BABtr7u4j7w,30789
|
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=
|
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=
|
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=
|
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.
|
93
|
-
NREL_reV-0.9.
|
94
|
-
NREL_reV-0.9.
|
95
|
-
NREL_reV-0.9.
|
96
|
-
NREL_reV-0.9.
|
97
|
-
NREL_reV-0.9.
|
92
|
+
NREL_reV-0.9.5.dist-info/LICENSE,sha256=hDwoTANtan2ZpufBlXm5C3W_PJ-mCqItvlcobgjxL7k,1526
|
93
|
+
NREL_reV-0.9.5.dist-info/METADATA,sha256=hx7F_iukuZl9zoHjAmjElOamOiFwUJPjVa0r2WpFiUY,10279
|
94
|
+
NREL_reV-0.9.5.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
95
|
+
NREL_reV-0.9.5.dist-info/entry_points.txt,sha256=KGtPEOQRZMSqKXjjv5jt_T4e4HQN0fHiaGdAWwTtuW4,617
|
96
|
+
NREL_reV-0.9.5.dist-info/top_level.txt,sha256=S6YF2ZYgXUB6n28SY0K2H8YB9tMJdXQ9CyQbo6VC89M,4
|
97
|
+
NREL_reV-0.9.5.dist-info/RECORD,,
|
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
|
|
@@ -922,6 +927,9 @@ class RevPySam(Sam):
|
|
922
927
|
|
923
928
|
def _add_cost_defaults(sam_inputs):
|
924
929
|
"""Add default values for required cost outputs if they are missing. """
|
930
|
+
if sam_inputs.get("__already_added_cost_defaults"):
|
931
|
+
return
|
932
|
+
|
925
933
|
sam_inputs.setdefault("fixed_charge_rate", None)
|
926
934
|
|
927
935
|
reg_mult = sam_inputs.setdefault("capital_cost_multiplier", 1)
|
@@ -938,6 +946,8 @@ def _add_cost_defaults(sam_inputs):
|
|
938
946
|
else:
|
939
947
|
sam_inputs["capital_cost"] = None
|
940
948
|
|
949
|
+
sam_inputs["__already_added_cost_defaults"] = True
|
950
|
+
|
941
951
|
|
942
952
|
def _add_sys_capacity(sam_inputs):
|
943
953
|
"""Add system capacity SAM input if it is missing. """
|
@@ -954,3 +964,8 @@ def _add_sys_capacity(sam_inputs):
|
|
954
964
|
cap = sam_inputs.get("nameplate")
|
955
965
|
|
956
966
|
sam_inputs["system_capacity"] = cap
|
967
|
+
|
968
|
+
|
969
|
+
def _sam_config_contains_turbine_layout(sam_config):
|
970
|
+
"""Detect wether SAM config contains multiple turbines in layout. """
|
971
|
+
return len(sam_config.get("wind_farm_xCoordinates", ())) > 1
|
reV/SAM/generation.py
CHANGED
@@ -1546,23 +1546,6 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1546
1546
|
- ``conversion_type`` : Integer flag representing the conversion
|
1547
1547
|
plant type. Either Binary (0) or Flash (1). Only values of 0
|
1548
1548
|
or 1 allowed.
|
1549
|
-
- ``design_temp`` : EGS plant design temperature (in C). Only
|
1550
|
-
affects EGS runs. This value may be adjusted internally by
|
1551
|
-
``reV under the following conditions:
|
1552
|
-
|
1553
|
-
- The design temperature is larger than the resource
|
1554
|
-
temperature
|
1555
|
-
- The design temperature is lower than the resource
|
1556
|
-
temperature by a factor of ``MAX_RT_TO_EGS_RATIO``
|
1557
|
-
|
1558
|
-
If either of these conditions are true, the ``design_temp`` is
|
1559
|
-
adjusted to match the resource temperature input in order to
|
1560
|
-
avoid SAM errors.
|
1561
|
-
- ``set_EGS_PDT_to_RT`` : Boolean flag to set EGS design
|
1562
|
-
temperature to match the resource temperature input. If this
|
1563
|
-
is ``True``, the ``design_temp`` input is ignored. This helps
|
1564
|
-
avoid SAM/GETEM errors when the plant design temperature is
|
1565
|
-
too high/low compared to the resource temperature.
|
1566
1549
|
- ``geotherm.cost.inj_prod_well_ratio`` : Fraction representing
|
1567
1550
|
the injection to production well ratio (0-1). SAM GUI defaults
|
1568
1551
|
to 0.5 for this value, but it is recommended to set this to
|
@@ -1632,10 +1615,6 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1632
1615
|
|
1633
1616
|
"""
|
1634
1617
|
|
1635
|
-
# Per Matt Prilliman on 2/22/24, it's unclear where this ratio originates,
|
1636
|
-
# but SAM errors out if it's exceeded.
|
1637
|
-
MAX_RT_TO_EGS_RATIO = 1.134324
|
1638
|
-
"""Max value of ``resource_temperature``/``EGS_plan_design_temperature``"""
|
1639
1618
|
MODULE = "geothermal"
|
1640
1619
|
PYSAM = PySamGeothermal
|
1641
1620
|
PYSAM_WEATHER_TAG = "file_name"
|
@@ -1738,52 +1717,14 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1738
1717
|
self.sam_sys_inputs["resource_temp"] = val
|
1739
1718
|
|
1740
1719
|
def _set_egs_plant_design_temperature(self):
|
1741
|
-
"""Set the EGS plant temp to match resource
|
1720
|
+
"""Set the EGS plant temp to match resource (avoids cf > 1)"""
|
1742
1721
|
if self.sam_sys_inputs.get("resource_type") != 1:
|
1743
1722
|
return # Not EGS run
|
1744
1723
|
|
1745
|
-
set_egs_pdt_to_rt = self.sam_sys_inputs.get("set_EGS_PDT_to_RT", False)
|
1746
|
-
egs_plant_design_temp = self.sam_sys_inputs.get("design_temp", 0)
|
1747
1724
|
resource_temp = self.sam_sys_inputs["resource_temp"]
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
"Setting EGS plant design temperature ({}C) to match "
|
1752
|
-
"resource temperature ({}C)".format(
|
1753
|
-
egs_plant_design_temp, resource_temp
|
1754
|
-
)
|
1755
|
-
)
|
1756
|
-
logger.info(msg)
|
1757
|
-
self.sam_sys_inputs["design_temp"] = resource_temp
|
1758
|
-
return
|
1759
|
-
|
1760
|
-
if egs_plant_design_temp > resource_temp:
|
1761
|
-
msg = (
|
1762
|
-
"EGS plant design temperature ({}C) exceeds resource "
|
1763
|
-
"temperature ({}C). Lowering EGS plant design temperature "
|
1764
|
-
"to match resource temperature".format(
|
1765
|
-
egs_plant_design_temp, resource_temp
|
1766
|
-
)
|
1767
|
-
)
|
1768
|
-
logger.warning(msg)
|
1769
|
-
warn(msg)
|
1770
|
-
self.sam_sys_inputs["design_temp"] = resource_temp
|
1771
|
-
return
|
1772
|
-
|
1773
|
-
if resource_temp / egs_plant_design_temp > self.MAX_RT_TO_EGS_RATIO:
|
1774
|
-
msg = (
|
1775
|
-
"EGS plant design temperature ({}C) is lower than resource "
|
1776
|
-
"temperature ({}C) by more than a factor of {}. Increasing "
|
1777
|
-
"EGS plant design temperature to match resource "
|
1778
|
-
"temperature".format(
|
1779
|
-
egs_plant_design_temp,
|
1780
|
-
resource_temp,
|
1781
|
-
self.MAX_RT_TO_EGS_RATIO,
|
1782
|
-
)
|
1783
|
-
)
|
1784
|
-
logger.warning(msg)
|
1785
|
-
warn(msg)
|
1786
|
-
self.sam_sys_inputs["design_temp"] = resource_temp
|
1725
|
+
logger.debug("Setting EGS plant design temperature to match "
|
1726
|
+
"resource temperature ({}C)".format(resource_temp))
|
1727
|
+
self.sam_sys_inputs["design_temp"] = resource_temp
|
1787
1728
|
|
1788
1729
|
def _set_nameplate_to_match_resource_potential(self, resource):
|
1789
1730
|
"""Set the nameplate capacity to match the resource potential."""
|
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
|
@@ -55,13 +54,19 @@ class BespokeMultiPlantData:
|
|
55
54
|
reads to a single HDF5 file.
|
56
55
|
"""
|
57
56
|
|
58
|
-
def __init__(self, res_fpath, sc_gid_to_hh, sc_gid_to_res_gid
|
57
|
+
def __init__(self, res_fpath, sc_gid_to_hh, sc_gid_to_res_gid,
|
58
|
+
pre_load_humidity=False):
|
59
59
|
"""Initialize BespokeMultiPlantData
|
60
60
|
|
61
61
|
Parameters
|
62
62
|
----------
|
63
|
-
res_fpath : str
|
64
|
-
|
63
|
+
res_fpath : str | list
|
64
|
+
Unix shell style path (potentially containing wildcard (*)
|
65
|
+
patterns) to a single or multi-file resource file set(s).
|
66
|
+
Can also be an explicit list of resource file paths, which
|
67
|
+
themselves can contain wildcards. This input must be
|
68
|
+
readable by
|
69
|
+
:py:class:`rex.multi_year_resource.MultiYearWindResource`.
|
65
70
|
sc_gid_to_hh : dict
|
66
71
|
Dictionary mapping SC GID values to hub-heights. Data for
|
67
72
|
each SC GID will be pulled for the corresponding hub-height
|
@@ -69,8 +74,11 @@ class BespokeMultiPlantData:
|
|
69
74
|
sc_gid_to_res_gid : dict
|
70
75
|
Dictionary mapping SC GID values to an iterable oif resource
|
71
76
|
GID values. Resource GID values should correspond to GID
|
72
|
-
values in
|
77
|
+
values in the HDF5 file, so any GID map must be applied
|
73
78
|
before initializing :class`BespokeMultiPlantData`.
|
79
|
+
pre_load_humidity : optional, default=False
|
80
|
+
Option to pre-load relative humidity data (useful for icing
|
81
|
+
runs). If ``False``, relative humidities are not loaded.
|
74
82
|
"""
|
75
83
|
self.res_fpath = res_fpath
|
76
84
|
self.sc_gid_to_hh = sc_gid_to_hh
|
@@ -80,6 +88,8 @@ class BespokeMultiPlantData:
|
|
80
88
|
self._wind_speeds = None
|
81
89
|
self._temps = None
|
82
90
|
self._pressures = None
|
91
|
+
self._relative_humidities = None
|
92
|
+
self._pre_load_humidity = pre_load_humidity
|
83
93
|
self._time_index = None
|
84
94
|
self._pre_load_data()
|
85
95
|
|
@@ -95,12 +105,7 @@ class BespokeMultiPlantData:
|
|
95
105
|
}
|
96
106
|
|
97
107
|
start_time = time.time()
|
98
|
-
|
99
|
-
handler = MultiYearWindResource
|
100
|
-
else:
|
101
|
-
handler = WindResource
|
102
|
-
|
103
|
-
with handler(self.res_fpath) as res:
|
108
|
+
with MultiYearWindResource(self.res_fpath) as res:
|
104
109
|
self._wind_dirs = {
|
105
110
|
hh: res[f"winddirection_{hh}m", :, gids]
|
106
111
|
for hh, gids in self.hh_to_res_gids.items()
|
@@ -118,6 +123,11 @@ class BespokeMultiPlantData:
|
|
118
123
|
for hh, gids in self.hh_to_res_gids.items()
|
119
124
|
}
|
120
125
|
self._time_index = res.time_index
|
126
|
+
if self._pre_load_humidity:
|
127
|
+
self._relative_humidities = {
|
128
|
+
hh: res["relativehumidity_2m", :, gids]
|
129
|
+
for hh, gids in self.hh_to_res_gids.items()
|
130
|
+
}
|
121
131
|
|
122
132
|
logger.debug(
|
123
133
|
f"Data took {(time.time() - start_time) / 60:.2f} " f"min to load"
|
@@ -140,6 +150,9 @@ class BespokeMultiPlantData:
|
|
140
150
|
hh = self.sc_gid_to_hh[sc_gid]
|
141
151
|
sc_point_res_gids = sorted(self.sc_gid_to_res_gid[sc_gid])
|
142
152
|
data_inds = np.searchsorted(self.hh_to_res_gids[hh], sc_point_res_gids)
|
153
|
+
|
154
|
+
rh = (None if not self._pre_load_humidity
|
155
|
+
else self._relative_humidities[hh][:, data_inds])
|
143
156
|
return BespokeSinglePlantData(
|
144
157
|
sc_point_res_gids,
|
145
158
|
self._wind_dirs[hh][:, data_inds],
|
@@ -147,6 +160,7 @@ class BespokeMultiPlantData:
|
|
147
160
|
self._temps[hh][:, data_inds],
|
148
161
|
self._pressures[hh][:, data_inds],
|
149
162
|
self._time_index,
|
163
|
+
rh,
|
150
164
|
)
|
151
165
|
|
152
166
|
|
@@ -159,7 +173,8 @@ class BespokeSinglePlantData:
|
|
159
173
|
"""
|
160
174
|
|
161
175
|
def __init__(
|
162
|
-
self, data_inds, wind_dirs, wind_speeds, temps, pressures, time_index
|
176
|
+
self, data_inds, wind_dirs, wind_speeds, temps, pressures, time_index,
|
177
|
+
relative_humidities=None,
|
163
178
|
):
|
164
179
|
"""Initialize BespokeSinglePlantData
|
165
180
|
|
@@ -170,22 +185,41 @@ class BespokeSinglePlantData:
|
|
170
185
|
the second dimension of `wind_dirs`, `wind_speeds`, `temps`,
|
171
186
|
and `pressures`. The GID value of data_inds[0] should
|
172
187
|
correspond to the `wind_dirs[:, 0]` data, etc.
|
173
|
-
wind_dirs
|
174
|
-
Array of wind directions
|
188
|
+
wind_dirs : 2D np.array
|
189
|
+
Array of wind directions. Dimensions should be correspond to
|
190
|
+
[time, location]. See documentation for `data_inds` for
|
191
|
+
required spatial mapping of GID values.
|
192
|
+
wind_speeds : 2D np.array
|
193
|
+
Array of wind speeds. Dimensions should be correspond to
|
194
|
+
[time, location]. See documentation for `data_inds` for
|
195
|
+
required spatial mapping of GID values.
|
196
|
+
temps : 2D np.array
|
197
|
+
Array oftemperatures. Dimensions should be correspond to
|
198
|
+
[time, location]. See documentation for `data_inds` for
|
199
|
+
required spatial mapping of GID values.
|
200
|
+
pressures : 2D np.array
|
201
|
+
Array of pressures. Dimensions should be correspond to
|
175
202
|
pressures, respectively. Dimensions should be correspond to
|
176
203
|
[time, location]. See documentation for `data_inds` for
|
177
204
|
required spatial mapping of GID values.
|
178
205
|
time_index : 1D np.array
|
179
206
|
Time index array corresponding to the temporal dimension of
|
180
207
|
the 2D data. Will be exposed directly to user.
|
181
|
-
|
208
|
+
relative_humidities : 2D np.array, optional
|
209
|
+
Array of relative humidities. Dimensions should be
|
210
|
+
correspond to [time, location]. See documentation for
|
211
|
+
`data_inds` for required spatial mapping of GID values.
|
212
|
+
If ``None``, relative_humidities cannot be queried.
|
182
213
|
"""
|
214
|
+
|
183
215
|
self.data_inds = data_inds
|
184
216
|
self.wind_dirs = wind_dirs
|
185
217
|
self.wind_speeds = wind_speeds
|
186
218
|
self.temps = temps
|
187
219
|
self.pressures = pressures
|
188
220
|
self.time_index = time_index
|
221
|
+
self.relative_humidities = relative_humidities
|
222
|
+
self._humidities_exist = relative_humidities is not None
|
189
223
|
|
190
224
|
def __getitem__(self, key):
|
191
225
|
dset_name, t_idx, gids = key
|
@@ -198,6 +232,8 @@ class BespokeSinglePlantData:
|
|
198
232
|
return self.temps[t_idx, data_inds]
|
199
233
|
if "pressure" in dset_name:
|
200
234
|
return self.pressures[t_idx, data_inds]
|
235
|
+
if self._humidities_exist and "relativehumidity" in dset_name:
|
236
|
+
return self.relative_humidities[t_idx, data_inds]
|
201
237
|
msg = f"Unknown dataset name: {dset_name!r}"
|
202
238
|
logger.error(msg)
|
203
239
|
raise ValueError(msg)
|
@@ -481,8 +517,7 @@ class BespokeSinglePlant:
|
|
481
517
|
self._pre_loaded_data = pre_loaded_data
|
482
518
|
self._outputs = {}
|
483
519
|
|
484
|
-
|
485
|
-
res = res if not isinstance(res, str) else Handler(res)
|
520
|
+
res = res if not isinstance(res, str) else MultiYearWindResource(res)
|
486
521
|
|
487
522
|
self._sc_point = AggSCPoint(
|
488
523
|
gid,
|
@@ -713,6 +748,7 @@ class BespokeSinglePlant:
|
|
713
748
|
weights[i] = self.sc_point.include_mask_flat[mask].sum()
|
714
749
|
|
715
750
|
weights /= weights.sum()
|
751
|
+
data = data.astype(np.float32)
|
716
752
|
data *= weights
|
717
753
|
data = np.sum(data, axis=1)
|
718
754
|
|
@@ -898,15 +934,18 @@ class BespokeSinglePlant:
|
|
898
934
|
if np.nanmax(pres) > 1000:
|
899
935
|
pres *= 9.86923e-6
|
900
936
|
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
937
|
+
data = {
|
938
|
+
"temperature": temp,
|
939
|
+
"pressure": pres,
|
940
|
+
"windspeed": ws,
|
941
|
+
"winddirection": wd,
|
942
|
+
}
|
943
|
+
|
944
|
+
if self.sam_sys_inputs.get("en_icing_cutoff"):
|
945
|
+
rh = self.get_weighted_res_ts("relativehumidity_2m")
|
946
|
+
data["relativehumidity"] = rh
|
947
|
+
|
948
|
+
self._res_df = pd.DataFrame(data, index=ti)
|
910
949
|
|
911
950
|
if "time_index_step" in self.original_sam_sys_inputs:
|
912
951
|
ti_step = self.original_sam_sys_inputs["time_index_step"]
|
@@ -1142,29 +1181,6 @@ class BespokeSinglePlant:
|
|
1142
1181
|
lcoe_kwargs["capital_cost"] = lcoe_kwargs["capital_cost"] + bos
|
1143
1182
|
return lcoe_kwargs
|
1144
1183
|
|
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
1184
|
@classmethod
|
1169
1185
|
def check_dependencies(cls):
|
1170
1186
|
"""Check special dependencies for bespoke"""
|
@@ -1382,32 +1398,45 @@ class BespokeSinglePlant:
|
|
1382
1398
|
eos_mult = (self.plant_optimizer.capital_cost
|
1383
1399
|
/ self.plant_optimizer.capacity
|
1384
1400
|
/ baseline_cost)
|
1385
|
-
|
1401
|
+
reg_mult_cc = self.sam_sys_inputs.get(
|
1402
|
+
"capital_cost_multiplier", 1)
|
1403
|
+
reg_mult_foc = self.sam_sys_inputs.get(
|
1404
|
+
"fixed_operating_cost_multiplier", 1)
|
1405
|
+
reg_mult_voc = self.sam_sys_inputs.get(
|
1406
|
+
"variable_operating_cost_multiplier", 1)
|
1407
|
+
reg_mult_bos = self.sam_sys_inputs.get(
|
1408
|
+
"balance_of_system_cost_multiplier", 1)
|
1386
1409
|
|
1387
1410
|
self._meta[SupplyCurveField.EOS_MULT] = eos_mult
|
1388
|
-
self._meta[SupplyCurveField.REG_MULT] =
|
1411
|
+
self._meta[SupplyCurveField.REG_MULT] = reg_mult_cc
|
1389
1412
|
|
1390
|
-
cap_cost = (
|
1391
|
-
self.plant_optimizer.capital_cost
|
1392
|
-
+ self.plant_optimizer.balance_of_system_cost
|
1393
|
-
)
|
1394
1413
|
self._meta[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW] = (
|
1395
|
-
|
1414
|
+
(self.plant_optimizer.capital_cost
|
1415
|
+
+ self.plant_optimizer.balance_of_system_cost)
|
1416
|
+
/ capacity_ac_mw
|
1396
1417
|
)
|
1397
1418
|
self._meta[SupplyCurveField.COST_BASE_OCC_USD_PER_AC_MW] = (
|
1398
|
-
|
1419
|
+
(self.plant_optimizer.capital_cost / eos_mult / reg_mult_cc
|
1420
|
+
+ self.plant_optimizer.balance_of_system_cost / reg_mult_bos)
|
1421
|
+
/ capacity_ac_mw
|
1399
1422
|
)
|
1400
1423
|
self._meta[SupplyCurveField.COST_SITE_FOC_USD_PER_AC_MW] = (
|
1401
|
-
self.plant_optimizer.fixed_operating_cost
|
1424
|
+
self.plant_optimizer.fixed_operating_cost
|
1425
|
+
/ capacity_ac_mw
|
1402
1426
|
)
|
1403
1427
|
self._meta[SupplyCurveField.COST_BASE_FOC_USD_PER_AC_MW] = (
|
1404
|
-
self.plant_optimizer.fixed_operating_cost
|
1428
|
+
self.plant_optimizer.fixed_operating_cost
|
1429
|
+
/ reg_mult_foc
|
1430
|
+
/ capacity_ac_mw
|
1405
1431
|
)
|
1406
1432
|
self._meta[SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW] = (
|
1407
|
-
self.plant_optimizer.variable_operating_cost
|
1433
|
+
self.plant_optimizer.variable_operating_cost
|
1434
|
+
/ capacity_ac_mw
|
1408
1435
|
)
|
1409
1436
|
self._meta[SupplyCurveField.COST_BASE_VOC_USD_PER_AC_MW] = (
|
1410
|
-
self.plant_optimizer.variable_operating_cost
|
1437
|
+
self.plant_optimizer.variable_operating_cost
|
1438
|
+
/ reg_mult_voc
|
1439
|
+
/ capacity_ac_mw
|
1411
1440
|
)
|
1412
1441
|
self._meta[SupplyCurveField.FIXED_CHARGE_RATE] = (
|
1413
1442
|
self.plant_optimizer.fixed_charge_rate
|
@@ -1489,8 +1518,9 @@ class BespokeWindPlants(BaseAggregation):
|
|
1489
1518
|
ws_bins=(0.0, 20.0, 5.0), wd_bins=(0.0, 360.0, 45.0),
|
1490
1519
|
excl_dict=None, area_filter_kernel='queen', min_area=None,
|
1491
1520
|
resolution=64, excl_area=None, data_layers=None,
|
1492
|
-
pre_extract_inclusions=False,
|
1493
|
-
|
1521
|
+
pre_extract_inclusions=False, eos_mult_baseline_cap_mw=200,
|
1522
|
+
prior_run=None, gid_map=None, bias_correct=None,
|
1523
|
+
pre_load_data=False):
|
1494
1524
|
"""reV bespoke analysis class.
|
1495
1525
|
|
1496
1526
|
Much like generation, ``reV`` bespoke analysis runs SAM
|
@@ -1521,14 +1551,15 @@ class BespokeWindPlants(BaseAggregation):
|
|
1521
1551
|
uniquely defined (i.e.only appear once and in a single
|
1522
1552
|
input file).
|
1523
1553
|
res_fpath : str
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1554
|
+
Unix shell style path to wind resource HDF5 file in NREL WTK
|
1555
|
+
format. Can also be a path including a wildcard input like
|
1556
|
+
``/h5_dir/prefix*suffix`` to run bespoke on multiple years
|
1557
|
+
of resource data. Can also be an explicit list of resource
|
1558
|
+
HDF5 file paths, which themselves can contain wildcards. If
|
1559
|
+
multiple files are specified in this way, they must have the
|
1560
|
+
same coordinates but can have different time indices (i.e.
|
1561
|
+
different years). This input must be readable by
|
1562
|
+
:py:class:`rex.multi_year_resource.MultiYearWindResource`
|
1532
1563
|
(i.e. the resource data conform to the
|
1533
1564
|
`rex data format <https://tinyurl.com/3fy7v5kx>`_). This
|
1534
1565
|
means the data file(s) must contain a 1D ``time_index``
|
@@ -1855,6 +1886,13 @@ class BespokeWindPlants(BaseAggregation):
|
|
1855
1886
|
the `excl_dict` input. It is typically faster to compute
|
1856
1887
|
the inclusion mask on the fly with parallel workers.
|
1857
1888
|
By default, ``False``.
|
1889
|
+
eos_mult_baseline_cap_mw : int | float, optional
|
1890
|
+
Baseline plant capacity (MW) used to calculate economies of
|
1891
|
+
scale (EOS) multiplier from the `capital_cost_function`. EOS
|
1892
|
+
multiplier is calculated as the $-per-kW of the wind plant
|
1893
|
+
divided by the $-per-kW of a plant with this baseline
|
1894
|
+
capacity. By default, `200` (MW), which aligns the baseline
|
1895
|
+
with ATB assumptions. See here: https://tinyurl.com/y85hnu6h.
|
1858
1896
|
prior_run : str, optional
|
1859
1897
|
Optional filepath to a bespoke output HDF5 file belonging to
|
1860
1898
|
a prior run. If specified, this module will only run the
|
@@ -1980,6 +2018,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
1980
2018
|
self._ws_bins = ws_bins
|
1981
2019
|
self._wd_bins = wd_bins
|
1982
2020
|
self._data_layers = data_layers
|
2021
|
+
self._eos_mult_baseline_cap_mw = eos_mult_baseline_cap_mw
|
1983
2022
|
self._prior_meta = self._parse_prior_run(prior_run)
|
1984
2023
|
self._gid_map = BespokeSinglePlant._parse_gid_map(gid_map)
|
1985
2024
|
self._bias_correct = Gen._parse_bc(bias_correct)
|
@@ -2119,8 +2158,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
2119
2158
|
)
|
2120
2159
|
|
2121
2160
|
# just check that this file exists, cannot check res_fpath if *glob
|
2122
|
-
|
2123
|
-
with Handler(self._res_fpath) as f:
|
2161
|
+
with MultiYearWindResource(self._res_fpath) as f:
|
2124
2162
|
assert any(f.dsets)
|
2125
2163
|
|
2126
2164
|
def _pre_load_data(self, pre_load_data):
|
@@ -2159,7 +2197,10 @@ class BespokeWindPlants(BaseAggregation):
|
|
2159
2197
|
|
2160
2198
|
logger.info("Pre-loading resource data for Bespoke run... ")
|
2161
2199
|
self._pre_loaded_data = BespokeMultiPlantData(
|
2162
|
-
self._res_fpath,
|
2200
|
+
self._res_fpath,
|
2201
|
+
sc_gid_to_hh,
|
2202
|
+
sc_gid_to_res_gid,
|
2203
|
+
pre_load_humidity=self._project_points.sam_config_obj.icing,
|
2163
2204
|
)
|
2164
2205
|
|
2165
2206
|
def _hh_for_sc_gid(self, sc_gid):
|
@@ -2453,8 +2494,8 @@ class BespokeWindPlants(BaseAggregation):
|
|
2453
2494
|
area_filter_kernel='queen', min_area=None,
|
2454
2495
|
resolution=64, excl_area=0.0081, data_layers=None,
|
2455
2496
|
gids=None, exclusion_shape=None, slice_lookup=None,
|
2456
|
-
|
2457
|
-
pre_loaded_data=None):
|
2497
|
+
eos_mult_baseline_cap_mw=200, prior_meta=None,
|
2498
|
+
gid_map=None, bias_correct=None, pre_loaded_data=None):
|
2458
2499
|
"""
|
2459
2500
|
Standalone serial method to run bespoke optimization.
|
2460
2501
|
See BespokeWindPlants docstring for parameter description.
|
@@ -2480,14 +2521,13 @@ class BespokeWindPlants(BaseAggregation):
|
|
2480
2521
|
exclusion_shape = sc.exclusions.shape
|
2481
2522
|
|
2482
2523
|
cls._check_inclusion_mask(inclusion_mask, gids, exclusion_shape)
|
2483
|
-
Handler = BespokeSinglePlant.get_wind_handler(res_fpath)
|
2484
2524
|
|
2485
2525
|
# pre-extract handlers so they are not repeatedly initialized
|
2486
2526
|
file_kwargs = {
|
2487
2527
|
"excl_dict": excl_dict,
|
2488
2528
|
"area_filter_kernel": area_filter_kernel,
|
2489
2529
|
"min_area": min_area,
|
2490
|
-
"h5_handler":
|
2530
|
+
"h5_handler": MultiYearWindResource,
|
2491
2531
|
}
|
2492
2532
|
|
2493
2533
|
with AggFileHandler(excl_fpath, res_fpath, **file_kwargs) as fh:
|
@@ -2520,6 +2560,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
2520
2560
|
excl_area=excl_area,
|
2521
2561
|
data_layers=data_layers,
|
2522
2562
|
exclusion_shape=exclusion_shape,
|
2563
|
+
eos_mult_baseline_cap_mw=eos_mult_baseline_cap_mw,
|
2523
2564
|
prior_meta=prior_meta,
|
2524
2565
|
gid_map=gid_map,
|
2525
2566
|
bias_correct=bias_correct,
|
@@ -2612,6 +2653,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
2612
2653
|
gids=gid,
|
2613
2654
|
exclusion_shape=self.shape,
|
2614
2655
|
slice_lookup=copy.deepcopy(self.slice_lookup),
|
2656
|
+
eos_mult_baseline_cap_mw=self._eos_mult_baseline_cap_mw,
|
2615
2657
|
prior_meta=self._get_prior_meta(gid),
|
2616
2658
|
gid_map=self._gid_map,
|
2617
2659
|
bias_correct=self._get_bc_for_gid(gid),
|
@@ -2676,6 +2718,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
2676
2718
|
afk = self._area_filter_kernel
|
2677
2719
|
wlm = self._wake_loss_multiplier
|
2678
2720
|
i_bc = self._get_bc_for_gid(gid)
|
2721
|
+
ebc = self._eos_mult_baseline_cap_mw
|
2679
2722
|
|
2680
2723
|
si = self.run_serial(self._excl_fpath,
|
2681
2724
|
self._res_fpath,
|
@@ -2700,6 +2743,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
2700
2743
|
excl_area=self._excl_area,
|
2701
2744
|
data_layers=self._data_layers,
|
2702
2745
|
slice_lookup=slice_lookup,
|
2746
|
+
eos_mult_baseline_cap_mw=ebc,
|
2703
2747
|
prior_meta=prior_meta,
|
2704
2748
|
gid_map=self._gid_map,
|
2705
2749
|
bias_correct=i_bc,
|
reV/generation/generation.py
CHANGED
@@ -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
|
240
|
-
|
241
|
-
a
|
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
|
-
|
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:
|
reV/handlers/multi_year.py
CHANGED
@@ -96,15 +96,17 @@ class MultiYearGroup:
|
|
96
96
|
pass_through_dsets : list
|
97
97
|
List of pass through datasets.
|
98
98
|
"""
|
99
|
+
with Resource(self.source_files[0]) as res:
|
100
|
+
all_dsets = res.datasets
|
101
|
+
|
99
102
|
if isinstance(dsets, str) and dsets == 'PIPELINE':
|
100
|
-
|
101
|
-
with Resource(files[0]) as res:
|
102
|
-
dsets = res.datasets
|
103
|
+
dsets = all_dsets
|
103
104
|
|
104
105
|
if "lcoe_fcr" in dsets:
|
105
106
|
for dset in LCOE_REQUIRED_OUTPUTS:
|
106
|
-
if dset not in pass_through_dsets:
|
107
|
+
if dset not in pass_through_dsets and dset in all_dsets:
|
107
108
|
pass_through_dsets.append(dset)
|
109
|
+
|
108
110
|
if "dc_ac_ratio" in dsets:
|
109
111
|
if "dc_ac_ratio" not in pass_through_dsets:
|
110
112
|
pass_through_dsets.append("dc_ac_ratio")
|
@@ -839,11 +841,6 @@ def my_collect_groups(out_fpath, groups, clobber=True):
|
|
839
841
|
dset, group=group['group'])
|
840
842
|
|
841
843
|
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
844
|
for dset in pass_through_dsets:
|
848
845
|
MultiYear.pass_through(out_fpath, group['source_files'],
|
849
846
|
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)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
`
|
1412
|
+
`gen_fpath` input will have to be specified manually.
|
1414
1413
|
|
1415
1414
|
By default, ``None``.
|
1416
1415
|
args : tuple | list, optional
|
reV/supply_curve/tech_mapping.py
CHANGED
@@ -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
|
188
|
+
Extract the exclusion coordinates for the desired gids for TechMapping.
|
189
189
|
|
190
190
|
Parameters
|
191
191
|
----------
|
reV/version.py
CHANGED
File without changes
|
File without changes
|
File without changes
|