NREL-reV 0.9.0__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.
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.dist-info}/METADATA +14 -14
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.dist-info}/RECORD +19 -19
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.dist-info}/WHEEL +1 -1
- reV/SAM/SAM.py +13 -0
- reV/SAM/generation.py +41 -8
- reV/bespoke/bespoke.py +70 -70
- reV/econ/econ.py +22 -11
- reV/econ/economies_of_scale.py +3 -7
- reV/generation/generation.py +31 -16
- reV/handlers/multi_year.py +2 -6
- reV/supply_curve/cli_sc_aggregation.py +19 -6
- reV/supply_curve/points.py +11 -6
- reV/supply_curve/sc_aggregation.py +1 -2
- reV/supply_curve/supply_curve.py +2 -3
- reV/supply_curve/tech_mapping.py +1 -1
- reV/version.py +1 -1
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.dist-info}/LICENSE +0 -0
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.dist-info}/entry_points.txt +0 -0
- {NREL_reV-0.9.0.dist-info → NREL_reV-0.9.4.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.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
|
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=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=
|
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=
|
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
|
@@ -31,13 +31,13 @@ reV/config/project_points.py,sha256=NmIj7hQm4qSMBqgefZDRNot2B8APCDk0ynTwegk-1Go,
|
|
31
31
|
reV/config/sam_config.py,sha256=xvvx2FTuliq0Sk-BjRE3I9zdDmIdwHVBnWtXCcsoc40,7998
|
32
32
|
reV/econ/__init__.py,sha256=UId1LNaAP9lErCEXVce6JZf0qVRUvwNFOPrajdRevGo,130
|
33
33
|
reV/econ/cli_econ.py,sha256=2KNy3JQD0EKjStaoD2r6nv3ELFw88h2E_up-UKj_sfE,4286
|
34
|
-
reV/econ/econ.py,sha256=
|
35
|
-
reV/econ/economies_of_scale.py,sha256=
|
34
|
+
reV/econ/econ.py,sha256=edsNPZg2amhC_GZeotkY2MU3u17NgWeCpS6okZNrwAA,23637
|
35
|
+
reV/econ/economies_of_scale.py,sha256=GfM0vj4LnwsthzhSsUnmLt78PAUHrxZI5ghWaxvoF7A,10568
|
36
36
|
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=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=
|
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
|
-
reV/supply_curve/points.py,sha256=
|
83
|
-
reV/supply_curve/sc_aggregation.py,sha256=
|
84
|
-
reV/supply_curve/supply_curve.py,sha256=
|
85
|
-
reV/supply_curve/tech_mapping.py,sha256=
|
82
|
+
reV/supply_curve/points.py,sha256=YEYHpn3KlBbGqpxywrfbrUrlhL3BndgX7cVQerdB6zg,86107
|
83
|
+
reV/supply_curve/sc_aggregation.py,sha256=R_h3xXKum4JTYMuq2us0rWhW0t2wm-G9Wj2on1d8FeY,61604
|
84
|
+
reV/supply_curve/supply_curve.py,sha256=igbloCkvYQwaH4zjbrYO17J7TtCTX5dKkk-TnlGJJeY,69931
|
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.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,,
|
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
|
|
@@ -950,4 +955,12 @@ def _add_sys_capacity(sam_inputs):
|
|
950
955
|
if cap is not None:
|
951
956
|
cap = max(cap)
|
952
957
|
|
958
|
+
if cap is None:
|
959
|
+
cap = sam_inputs.get("nameplate")
|
960
|
+
|
953
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
@@ -233,6 +233,15 @@ class AbstractSamGeneration(RevPySam, ScheduledLossesMixin, ABC):
|
|
233
233
|
logger.error(msg)
|
234
234
|
raise InputError(msg)
|
235
235
|
|
236
|
+
if len(resource) < 8760:
|
237
|
+
msg = (f"Detected resource time series of length {len(resource)}, "
|
238
|
+
"which is less than 8760. This may yield unexpected "
|
239
|
+
"results or fail altogether. If this is not intentional, "
|
240
|
+
"try setting 'time_index_step: 1' in your SAM config or "
|
241
|
+
"double check the resource input you're using.")
|
242
|
+
logger.warning(msg)
|
243
|
+
warn(msg)
|
244
|
+
|
236
245
|
@abstractmethod
|
237
246
|
def set_resource_data(self, resource, meta):
|
238
247
|
"""Placeholder for resource data setting (nsrdb or wtk)"""
|
@@ -1539,7 +1548,7 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1539
1548
|
or 1 allowed.
|
1540
1549
|
- ``design_temp`` : EGS plant design temperature (in C). Only
|
1541
1550
|
affects EGS runs. This value may be adjusted internally by
|
1542
|
-
``reV under the following conditions:
|
1551
|
+
``reV`` under the following conditions:
|
1543
1552
|
|
1544
1553
|
- The design temperature is larger than the resource
|
1545
1554
|
temperature
|
@@ -1786,6 +1795,10 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1786
1795
|
"{}".format(self.sam_sys_inputs["nameplate"])
|
1787
1796
|
)
|
1788
1797
|
logger.info(msg)
|
1798
|
+
# required for downstream LCOE calcs
|
1799
|
+
self.sam_sys_inputs["system_capacity"] = (
|
1800
|
+
self.sam_sys_inputs["nameplate"]
|
1801
|
+
)
|
1789
1802
|
return
|
1790
1803
|
|
1791
1804
|
val = set(resource["potential_MW"].unique())
|
@@ -1801,6 +1814,8 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1801
1814
|
|
1802
1815
|
logger.debug("Setting the nameplate to {}".format(val))
|
1803
1816
|
self.sam_sys_inputs["nameplate"] = val
|
1817
|
+
# required for downstream LCOE calcs
|
1818
|
+
self.sam_sys_inputs["system_capacity"] = val
|
1804
1819
|
|
1805
1820
|
def _set_resource_potential_to_match_gross_output(self):
|
1806
1821
|
"""Set the resource potential input to match the gross generation.
|
@@ -1861,7 +1876,9 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1861
1876
|
logger.debug(
|
1862
1877
|
"Setting the capital_cost to ${:,.2f}".format(capital_cost)
|
1863
1878
|
)
|
1864
|
-
self.sam_sys_inputs
|
1879
|
+
reg_mult = self.sam_sys_inputs.get("capital_cost_multiplier", 1)
|
1880
|
+
self.sam_sys_inputs["base_capital_cost"] = capital_cost
|
1881
|
+
self.sam_sys_inputs["capital_cost"] = capital_cost * reg_mult
|
1865
1882
|
|
1866
1883
|
dc_per_well = self.sam_sys_inputs.pop("drill_cost_per_well", None)
|
1867
1884
|
num_wells = self.sam_sys_inputs.pop(
|
@@ -1884,19 +1901,35 @@ class Geothermal(AbstractSamGenerationFromWeatherFile):
|
|
1884
1901
|
drill_cost, num_wells, dc_per_well
|
1885
1902
|
)
|
1886
1903
|
)
|
1887
|
-
self.sam_sys_inputs
|
1904
|
+
reg_mult = self.sam_sys_inputs.get(
|
1905
|
+
"capital_cost_multiplier", 1
|
1906
|
+
)
|
1907
|
+
base_cc = capital_cost / reg_mult
|
1908
|
+
new_base_cc = base_cc + drill_cost
|
1909
|
+
self.sam_sys_inputs["base_capital_cost"] = new_base_cc
|
1910
|
+
self.sam_sys_inputs["capital_cost"] = new_base_cc * reg_mult
|
1888
1911
|
|
1889
1912
|
foc_per_kw = self.sam_sys_inputs.pop(
|
1890
1913
|
"fixed_operating_cost_per_kw", None
|
1891
1914
|
)
|
1892
1915
|
if foc_per_kw is not None:
|
1893
|
-
|
1916
|
+
foc = foc_per_kw * plant_size_kw
|
1894
1917
|
logger.debug(
|
1895
|
-
"Setting the fixed_operating_cost to ${:,.2f}".format(
|
1896
|
-
|
1897
|
-
|
1918
|
+
"Setting the fixed_operating_cost to ${:,.2f}".format(foc)
|
1919
|
+
)
|
1920
|
+
self.sam_sys_inputs["base_fixed_operating_cost"] = foc
|
1921
|
+
self.sam_sys_inputs["fixed_operating_cost"] = foc
|
1922
|
+
|
1923
|
+
voc_per_kw = self.sam_sys_inputs.pop(
|
1924
|
+
"variable_operating_cost_per_kw", None
|
1925
|
+
)
|
1926
|
+
if voc_per_kw is not None:
|
1927
|
+
voc = voc_per_kw * plant_size_kw
|
1928
|
+
logger.debug(
|
1929
|
+
"Setting the variable_operating_cost to ${:,.2f}".format(voc)
|
1898
1930
|
)
|
1899
|
-
self.sam_sys_inputs["
|
1931
|
+
self.sam_sys_inputs["base_variable_operating_cost"] = voc
|
1932
|
+
self.sam_sys_inputs["variable_operating_cost"] = voc
|
1900
1933
|
|
1901
1934
|
def _create_pysam_wfile(self, resource, meta):
|
1902
1935
|
"""Create PySAM weather input file.
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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"""
|
@@ -1263,10 +1238,10 @@ class BespokeSinglePlant:
|
|
1263
1238
|
self._outputs.update(means)
|
1264
1239
|
|
1265
1240
|
self._meta[SupplyCurveField.MEAN_RES] = self.res_df["windspeed"].mean()
|
1266
|
-
self._meta[SupplyCurveField.MEAN_CF_DC] =
|
1267
|
-
self._meta[SupplyCurveField.MEAN_CF_AC] =
|
1268
|
-
self._meta[SupplyCurveField.MEAN_LCOE] =
|
1269
|
-
self._meta[SupplyCurveField.SC_POINT_ANNUAL_ENERGY_MW] =
|
1241
|
+
self._meta[SupplyCurveField.MEAN_CF_DC] = np.nan
|
1242
|
+
self._meta[SupplyCurveField.MEAN_CF_AC] = np.nan
|
1243
|
+
self._meta[SupplyCurveField.MEAN_LCOE] = np.nan
|
1244
|
+
self._meta[SupplyCurveField.SC_POINT_ANNUAL_ENERGY_MW] = np.nan
|
1270
1245
|
# copy dataset outputs to meta data for supply curve table summary
|
1271
1246
|
if "cf_mean-means" in self.outputs:
|
1272
1247
|
self._meta.loc[:, SupplyCurveField.MEAN_CF_AC] = self.outputs[
|
@@ -1373,7 +1348,7 @@ class BespokeSinglePlant:
|
|
1373
1348
|
# convert SAM system capacity in kW to reV supply curve cap in MW
|
1374
1349
|
capacity_ac_mw = system_capacity_kw / 1e3
|
1375
1350
|
self._meta[SupplyCurveField.CAPACITY_AC_MW] = capacity_ac_mw
|
1376
|
-
self._meta[SupplyCurveField.CAPACITY_DC_MW] =
|
1351
|
+
self._meta[SupplyCurveField.CAPACITY_DC_MW] = np.nan
|
1377
1352
|
|
1378
1353
|
# add required ReEDS multipliers to meta
|
1379
1354
|
baseline_cost = self.plant_optimizer.capital_cost_per_kw(
|
@@ -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
|
-
|
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] =
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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,
|
1493
|
-
|
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
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
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``
|
@@ -1618,7 +1608,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
1618
1608
|
multiple sites can be specified to evaluate ``reV`` at
|
1619
1609
|
multiple specific locations. A string pointing to a project
|
1620
1610
|
points CSV file may also be specified. Typically, the CSV
|
1621
|
-
contains
|
1611
|
+
contains the following columns:
|
1622
1612
|
|
1623
1613
|
- ``gid``: Integer specifying the supply curve GID of
|
1624
1614
|
each site.
|
@@ -1635,7 +1625,7 @@ class BespokeWindPlants(BaseAggregation):
|
|
1635
1625
|
site-specific capital cost value for each location). Columns
|
1636
1626
|
that do not correspond to a config key may also be included,
|
1637
1627
|
but they will be ignored. The CSV file input can also have
|
1638
|
-
these extra columns:
|
1628
|
+
these extra, optional columns:
|
1639
1629
|
|
1640
1630
|
- ``capital_cost_multiplier``
|
1641
1631
|
- ``fixed_operating_cost_multiplier``
|
@@ -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
|
-
|
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
|
-
|
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":
|
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,
|
reV/econ/econ.py
CHANGED
@@ -76,25 +76,36 @@ class Econ(BaseGen):
|
|
76
76
|
(or slice) representing the GIDs of multiple sites can be
|
77
77
|
specified to evaluate reV at multiple specific locations.
|
78
78
|
A string pointing to a project points CSV file may also be
|
79
|
-
specified. Typically, the CSV contains
|
79
|
+
specified. Typically, the CSV contains the following
|
80
|
+
columns:
|
80
81
|
|
81
|
-
- ``gid``: Integer specifying the GID of each
|
82
|
+
- ``gid``: Integer specifying the generation GID of each
|
83
|
+
site.
|
82
84
|
- ``config``: Key in the `sam_files` input dictionary
|
83
85
|
(see below) corresponding to the SAM configuration to
|
84
86
|
use for each particular site. This value can also be
|
85
87
|
``None`` (or left out completely) if you specify only
|
86
88
|
a single SAM configuration file as the `sam_files`
|
87
89
|
input.
|
88
|
-
|
89
|
-
|
90
|
+
- ``capital_cost_multiplier``: This is an *optional*
|
91
|
+
multiplier input that, if included, will be used to
|
92
|
+
regionally scale the ``capital_cost`` input in the SAM
|
93
|
+
config. If you include this column in your CSV, you
|
94
|
+
*do not* need to specify ``capital_cost``, unless you
|
95
|
+
would like that value to vary regionally and
|
96
|
+
independently of the multiplier (i.e. the multiplier
|
97
|
+
will still be applied on top of the ``capital_cost``
|
98
|
+
input).
|
99
|
+
|
100
|
+
The CSV file may also contain other site-specific inputs by
|
90
101
|
including a column named after a config keyword (e.g. a
|
91
|
-
column called ``
|
92
|
-
site-specific
|
93
|
-
that do not correspond to a config
|
94
|
-
but they will be ignored. A
|
95
|
-
guidelines as the CSV input
|
96
|
-
|
97
|
-
input as well.
|
102
|
+
column called ``wind_turbine_rotor_diameter`` may be
|
103
|
+
included to specify a site-specific turbine diameter for
|
104
|
+
each location). Columns that do not correspond to a config
|
105
|
+
key may also be included, but they will be ignored. A
|
106
|
+
DataFrame following the same guidelines as the CSV input
|
107
|
+
(or a dictionary that can be used to initialize such a
|
108
|
+
DataFrame) may be used for this input as well.
|
98
109
|
sam_files : dict | str
|
99
110
|
A dictionary mapping SAM input configuration ID(s) to SAM
|
100
111
|
configuration(s). Keys are the SAM config ID(s) which
|
reV/econ/economies_of_scale.py
CHANGED
@@ -212,11 +212,7 @@ class EconomiesOfScale:
|
|
212
212
|
if cost_per_mw is None:
|
213
213
|
return None
|
214
214
|
|
215
|
-
|
216
|
-
if cost > 0:
|
217
|
-
return cost
|
218
|
-
|
219
|
-
return None
|
215
|
+
return cap * cost_per_mw
|
220
216
|
|
221
217
|
@property
|
222
218
|
def raw_capital_cost(self):
|
@@ -278,7 +274,7 @@ class EconomiesOfScale:
|
|
278
274
|
Fixed operating cost from input data arg
|
279
275
|
"""
|
280
276
|
foc_from_cap = self._cost_from_cap(
|
281
|
-
SupplyCurveField.
|
277
|
+
SupplyCurveField.COST_SITE_FOC_USD_PER_AC_MW
|
282
278
|
)
|
283
279
|
if foc_from_cap is not None:
|
284
280
|
return foc_from_cap
|
@@ -297,7 +293,7 @@ class EconomiesOfScale:
|
|
297
293
|
Variable operating cost from input data arg
|
298
294
|
"""
|
299
295
|
voc_from_cap = self._cost_from_cap(
|
300
|
-
SupplyCurveField.
|
296
|
+
SupplyCurveField.COST_SITE_VOC_USD_PER_AC_MW
|
301
297
|
)
|
302
298
|
if voc_from_cap is not None:
|
303
299
|
return voc_from_cap
|
reV/generation/generation.py
CHANGED
@@ -171,7 +171,7 @@ class Gen(BaseGen):
|
|
171
171
|
multiple sites can be specified to evaluate reV at multiple
|
172
172
|
specific locations. A string pointing to a project points
|
173
173
|
CSV file may also be specified. Typically, the CSV contains
|
174
|
-
|
174
|
+
the following columns:
|
175
175
|
|
176
176
|
- ``gid``: Integer specifying the generation GID of each
|
177
177
|
site.
|
@@ -181,16 +181,25 @@ class Gen(BaseGen):
|
|
181
181
|
``None`` (or left out completely) if you specify only
|
182
182
|
a single SAM configuration file as the `sam_files`
|
183
183
|
input.
|
184
|
-
|
185
|
-
|
184
|
+
- ``capital_cost_multiplier``: This is an *optional*
|
185
|
+
multiplier input that, if included, will be used to
|
186
|
+
regionally scale the ``capital_cost`` input in the SAM
|
187
|
+
config. If you include this column in your CSV, you
|
188
|
+
*do not* need to specify ``capital_cost``, unless you
|
189
|
+
would like that value to vary regionally and
|
190
|
+
independently of the multiplier (i.e. the multiplier
|
191
|
+
will still be applied on top of the ``capital_cost``
|
192
|
+
input).
|
193
|
+
|
194
|
+
The CSV file may also contain other site-specific inputs by
|
186
195
|
including a column named after a config keyword (e.g. a
|
187
|
-
column called ``
|
188
|
-
site-specific
|
189
|
-
that do not correspond to a config
|
190
|
-
but they will be ignored. A
|
191
|
-
guidelines as the CSV input
|
192
|
-
|
193
|
-
input as well.
|
196
|
+
column called ``wind_turbine_rotor_diameter`` may be
|
197
|
+
included to specify a site-specific turbine diameter for
|
198
|
+
each location). Columns that do not correspond to a config
|
199
|
+
key may also be included, but they will be ignored. A
|
200
|
+
DataFrame following the same guidelines as the CSV input
|
201
|
+
(or a dictionary that can be used to initialize such a
|
202
|
+
DataFrame) may be used for this input as well.
|
194
203
|
|
195
204
|
.. Note:: By default, the generation GID of each site is
|
196
205
|
assumed to match the resource GID to be evaluated for that
|
@@ -227,10 +236,10 @@ class Gen(BaseGen):
|
|
227
236
|
info on the allowed and/or required SAM config file inputs.
|
228
237
|
resource_file : str
|
229
238
|
Filepath to resource data. This input can be path to a
|
230
|
-
single resource HDF5 file
|
231
|
-
|
232
|
-
a
|
233
|
-
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
|
234
243
|
:py:class:`rex.resource.Resource`
|
235
244
|
or :py:class:`rex.multi_file_resource.MultiFileResource`.
|
236
245
|
(i.e. the resource data conform to the
|
@@ -244,8 +253,14 @@ class Gen(BaseGen):
|
|
244
253
|
consideration, and its shape must be a multiple of 8760.
|
245
254
|
|
246
255
|
.. Note:: If executing ``reV`` from the command line, this
|
247
|
-
|
248
|
-
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).
|
249
264
|
|
250
265
|
.. Important:: If you are using custom resource data (i.e.
|
251
266
|
not NSRDB/WTK/Sup3rCC, etc.), ensure the following:
|
reV/handlers/multi_year.py
CHANGED
@@ -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)
|
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
|
|
reV/supply_curve/points.py
CHANGED
@@ -2188,10 +2188,10 @@ class GenerationSupplyCurvePoint(AggregationSupplyCurvePoint):
|
|
2188
2188
|
def _compute_cost_per_ac_mw(self, dset):
|
2189
2189
|
"""Compute a cost per AC MW for a given input. """
|
2190
2190
|
if self._sam_system_capacity <= 0:
|
2191
|
-
return
|
2191
|
+
return None
|
2192
2192
|
|
2193
2193
|
if dset not in self.gen.datasets:
|
2194
|
-
return
|
2194
|
+
return None
|
2195
2195
|
|
2196
2196
|
sam_cost = self.exclusion_weighted_mean(self.gen[dset])
|
2197
2197
|
sam_cost_per_mw = sam_cost / self._sam_system_capacity
|
@@ -2391,10 +2391,11 @@ class GenerationSupplyCurvePoint(AggregationSupplyCurvePoint):
|
|
2391
2391
|
summary[SupplyCurveField.RAW_LCOE] = eos.raw_lcoe
|
2392
2392
|
summary[SupplyCurveField.MEAN_LCOE] = eos.scaled_lcoe
|
2393
2393
|
summary[SupplyCurveField.EOS_MULT] = eos.capital_cost_scalar
|
2394
|
-
summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW]
|
2395
|
-
|
2396
|
-
|
2397
|
-
|
2394
|
+
cost = summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW]
|
2395
|
+
if cost is not None:
|
2396
|
+
summary[SupplyCurveField.COST_SITE_OCC_USD_PER_AC_MW] = (
|
2397
|
+
cost * summary[SupplyCurveField.EOS_MULT]
|
2398
|
+
)
|
2398
2399
|
return summary
|
2399
2400
|
|
2400
2401
|
@classmethod
|
@@ -2537,6 +2538,10 @@ class GenerationSupplyCurvePoint(AggregationSupplyCurvePoint):
|
|
2537
2538
|
if cap_cost_scale is not None:
|
2538
2539
|
summary = point.economies_of_scale(cap_cost_scale, summary)
|
2539
2540
|
|
2541
|
+
for arg, val in summary.items():
|
2542
|
+
if val is None:
|
2543
|
+
summary[arg] = np.nan
|
2544
|
+
|
2540
2545
|
return summary
|
2541
2546
|
|
2542
2547
|
|
@@ -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/supply_curve.py
CHANGED
@@ -1116,8 +1116,7 @@ class SupplyCurve:
|
|
1116
1116
|
|
1117
1117
|
return table
|
1118
1118
|
|
1119
|
-
#
|
1120
|
-
def _full_sort(
|
1119
|
+
def _full_sort( # noqa: C901
|
1121
1120
|
self,
|
1122
1121
|
trans_table,
|
1123
1122
|
trans_costs=None,
|
@@ -1289,7 +1288,7 @@ class SupplyCurve:
|
|
1289
1288
|
|
1290
1289
|
for col in _REQUIRED_OUTPUT_COLS:
|
1291
1290
|
if col not in self._trans_table:
|
1292
|
-
self._trans_table[col] =
|
1291
|
+
self._trans_table[col] = np.nan
|
1293
1292
|
if col not in columns:
|
1294
1293
|
columns.append(col)
|
1295
1294
|
|
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
|