NREL-reV 0.8.9__py3-none-any.whl → 0.9.0__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.8.9.dist-info → NREL_reV-0.9.0.dist-info}/METADATA +2 -1
- {NREL_reV-0.8.9.dist-info → NREL_reV-0.9.0.dist-info}/RECORD +34 -34
- reV/SAM/SAM.py +35 -0
- reV/SAM/generation.py +3 -3
- reV/bespoke/bespoke.py +302 -243
- reV/bespoke/cli_bespoke.py +2 -0
- reV/bespoke/place_turbines.py +181 -37
- reV/config/output_request.py +2 -1
- reV/config/project_points.py +1 -3
- reV/econ/econ.py +2 -2
- reV/econ/economies_of_scale.py +58 -35
- reV/generation/base.py +22 -2
- reV/generation/generation.py +31 -13
- reV/generation/output_attributes/lcoe_fcr_inputs.json +38 -3
- reV/handlers/__init__.py +0 -1
- reV/handlers/multi_year.py +45 -17
- reV/handlers/transmission.py +44 -27
- reV/hybrids/hybrid_methods.py +16 -14
- reV/hybrids/hybrids.py +10 -10
- reV/nrwal/nrwal.py +1 -1
- reV/qa_qc/qa_qc.py +1 -1
- reV/qa_qc/summary.py +4 -4
- reV/rep_profiles/rep_profiles.py +1 -1
- reV/supply_curve/exclusions.py +1 -1
- reV/supply_curve/extent.py +1 -1
- reV/supply_curve/points.py +250 -132
- reV/supply_curve/sc_aggregation.py +13 -45
- reV/supply_curve/supply_curve.py +200 -140
- reV/utilities/__init__.py +114 -39
- reV/version.py +1 -1
- {NREL_reV-0.8.9.dist-info → NREL_reV-0.9.0.dist-info}/LICENSE +0 -0
- {NREL_reV-0.8.9.dist-info → NREL_reV-0.9.0.dist-info}/WHEEL +0 -0
- {NREL_reV-0.8.9.dist-info → NREL_reV-0.9.0.dist-info}/entry_points.txt +0 -0
- {NREL_reV-0.8.9.dist-info → NREL_reV-0.9.0.dist-info}/top_level.txt +0 -0
reV/generation/generation.py
CHANGED
@@ -113,7 +113,7 @@ class Gen(BaseGen):
|
|
113
113
|
allowed and/or required SAM config file inputs. If economic
|
114
114
|
parameters are supplied in the SAM config, then you can bundle a
|
115
115
|
"follow-on" econ calculation by just adding the desired econ
|
116
|
-
output keys to the `output_request`. You can request ``reV`` to
|
116
|
+
output keys to the `output_request`. You can request ``reV`` to
|
117
117
|
run the analysis for one or more "sites", which correspond to
|
118
118
|
the meta indices in the resource data (also commonly called the
|
119
119
|
``gid's``).
|
@@ -128,7 +128,7 @@ class Gen(BaseGen):
|
|
128
128
|
>>> import os
|
129
129
|
>>> from reV import Gen, TESTDATADIR
|
130
130
|
>>>
|
131
|
-
>>> sam_tech = '
|
131
|
+
>>> sam_tech = 'pvwattsv8'
|
132
132
|
>>> sites = 0
|
133
133
|
>>> fp_sam = os.path.join(TESTDATADIR, 'SAM/naris_pv_1axis_inv13.json')
|
134
134
|
>>> fp_res = os.path.join(TESTDATADIR, 'nsrdb/ri_100_nsrdb_2013.h5')
|
@@ -145,15 +145,16 @@ class Gen(BaseGen):
|
|
145
145
|
>>> gen.run()
|
146
146
|
>>>
|
147
147
|
>>> gen.out
|
148
|
-
{'
|
149
|
-
'
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
148
|
+
{'fixed_charge_rate': array([0.096, 0.096, 0.096, 0.096],
|
149
|
+
'base_capital_cost': array([39767200, 39767200, 39767200, 39767200],
|
150
|
+
'base_variable_operating_cost': array([0, 0, 0, 0],
|
151
|
+
'base_fixed_operating_cost': array([260000, 260000, 260000, 260000],
|
152
|
+
'capital_cost': array([39767200, 39767200, 39767200, 39767200],
|
153
|
+
'fixed_operating_cost': array([260000, 260000, 260000, 260000],
|
154
|
+
'variable_operating_cost': array([0, 0, 0, 0],
|
155
|
+
'capital_cost_multiplier': array([1, 1, 1, 1],
|
156
|
+
'cf_mean': array([0.17859147, 0.17869979, 0.1834818 , 0.18646291],
|
157
|
+
'lcoe_fcr': array([130.32126, 130.24226, 126.84782, 124.81981]}
|
157
158
|
|
158
159
|
Parameters
|
159
160
|
----------
|
@@ -454,7 +455,7 @@ class Gen(BaseGen):
|
|
454
455
|
Meta data df for sites in project points. Column names are meta
|
455
456
|
data variables, rows are different sites. The row index
|
456
457
|
does not indicate the site number if the project points are
|
457
|
-
non-sequential or do not start from 0, so a `
|
458
|
+
non-sequential or do not start from 0, so a `SiteDataField.GID`
|
458
459
|
column is added.
|
459
460
|
"""
|
460
461
|
if self._meta is None:
|
@@ -712,6 +713,8 @@ class Gen(BaseGen):
|
|
712
713
|
for k in site_output.keys():
|
713
714
|
# iterate through variable names in each site's output dict
|
714
715
|
if k in cls.OUT_ATTRS:
|
716
|
+
if out[site][k] is None:
|
717
|
+
continue
|
715
718
|
# get dtype and scale for output variable name
|
716
719
|
dtype = cls.OUT_ATTRS[k].get("dtype", "float32")
|
717
720
|
scale_factor = cls.OUT_ATTRS[k].get("scale_factor", 1)
|
@@ -947,12 +950,20 @@ class Gen(BaseGen):
|
|
947
950
|
Output variables requested from SAM.
|
948
951
|
"""
|
949
952
|
|
950
|
-
output_request =
|
953
|
+
output_request = super()._parse_output_request(req)
|
951
954
|
|
952
955
|
# ensure that cf_mean is requested from output
|
953
956
|
if "cf_mean" not in output_request:
|
954
957
|
output_request.append("cf_mean")
|
955
958
|
|
959
|
+
if _is_solar_run_with_ac_outputs(self.tech):
|
960
|
+
if "dc_ac_ratio" not in output_request:
|
961
|
+
output_request.append("dc_ac_ratio")
|
962
|
+
for dset in ["cf_mean", "cf_profile"]:
|
963
|
+
ac_dset = f"{dset}_ac"
|
964
|
+
if dset in output_request and ac_dset not in output_request:
|
965
|
+
output_request.append(ac_dset)
|
966
|
+
|
956
967
|
for request in output_request:
|
957
968
|
if request not in self.OUT_ATTRS:
|
958
969
|
msg = (
|
@@ -1097,3 +1108,10 @@ class Gen(BaseGen):
|
|
1097
1108
|
raise e
|
1098
1109
|
|
1099
1110
|
return self._out_fpath
|
1111
|
+
|
1112
|
+
|
1113
|
+
def _is_solar_run_with_ac_outputs(tech):
|
1114
|
+
"""True if tech is pvwattsv8+"""
|
1115
|
+
if "pvwatts" not in tech.casefold():
|
1116
|
+
return False
|
1117
|
+
return tech.casefold() not in {f"pvwattsv{i}" for i in range(8)}
|
@@ -4,7 +4,7 @@
|
|
4
4
|
"dtype": "float32",
|
5
5
|
"scale_factor": 1,
|
6
6
|
"type": "scalar",
|
7
|
-
"units": "
|
7
|
+
"units": "usd"
|
8
8
|
},
|
9
9
|
"fixed_charge_rate": {
|
10
10
|
"chunks": null,
|
@@ -18,13 +18,48 @@
|
|
18
18
|
"dtype": "float32",
|
19
19
|
"scale_factor": 1,
|
20
20
|
"type": "scalar",
|
21
|
-
"units": "
|
21
|
+
"units": "usd"
|
22
22
|
},
|
23
23
|
"variable_operating_cost": {
|
24
24
|
"chunks": null,
|
25
25
|
"dtype": "float32",
|
26
26
|
"scale_factor": 1,
|
27
27
|
"type": "scalar",
|
28
|
-
"units": "
|
28
|
+
"units": "usd/kWh"
|
29
|
+
},
|
30
|
+
"base_capital_cost": {
|
31
|
+
"chunks": null,
|
32
|
+
"dtype": "float32",
|
33
|
+
"scale_factor": 1,
|
34
|
+
"type": "scalar",
|
35
|
+
"units": "usd"
|
36
|
+
},
|
37
|
+
"base_fixed_operating_cost": {
|
38
|
+
"chunks": null,
|
39
|
+
"dtype": "float32",
|
40
|
+
"scale_factor": 1,
|
41
|
+
"type": "scalar",
|
42
|
+
"units": "usd"
|
43
|
+
},
|
44
|
+
"base_variable_operating_cost": {
|
45
|
+
"chunks": null,
|
46
|
+
"dtype": "float32",
|
47
|
+
"scale_factor": 1,
|
48
|
+
"type": "scalar",
|
49
|
+
"units": "usd/kWh"
|
50
|
+
},
|
51
|
+
"capital_cost_multiplier": {
|
52
|
+
"chunks": null,
|
53
|
+
"dtype": "float32",
|
54
|
+
"scale_factor": 1,
|
55
|
+
"type": "scalar",
|
56
|
+
"units": "unitless"
|
57
|
+
},
|
58
|
+
"system_capacity": {
|
59
|
+
"chunks": null,
|
60
|
+
"dtype": "float32",
|
61
|
+
"scale_factor": 1,
|
62
|
+
"type": "scalar",
|
63
|
+
"units": "kW"
|
29
64
|
}
|
30
65
|
}
|
reV/handlers/__init__.py
CHANGED
reV/handlers/multi_year.py
CHANGED
@@ -18,6 +18,7 @@ from rex.utilities.utilities import (
|
|
18
18
|
parse_year,
|
19
19
|
)
|
20
20
|
|
21
|
+
from reV.generation.base import LCOE_REQUIRED_OUTPUTS
|
21
22
|
from reV.config.output_request import SAMOutputRequest
|
22
23
|
from reV.handlers.outputs import Outputs
|
23
24
|
from reV.utilities import ModuleName, log_versions
|
@@ -60,8 +61,12 @@ class MultiYearGroup:
|
|
60
61
|
source files. This takes priority over `source_dir` and
|
61
62
|
`source_prefix` but is not used if `source_files` are
|
62
63
|
specified explicitly. By default, ``None``.
|
63
|
-
dsets : list | tuple, optional
|
64
|
-
List of datasets to collect.
|
64
|
+
dsets : str | list | tuple, optional
|
65
|
+
List of datasets to collect. This can be set to
|
66
|
+
``"PIPELINE"`` if running from the command line as part of a
|
67
|
+
reV pipeline. In this case, all the datasets from the
|
68
|
+
previous pipeline step will be collected.
|
69
|
+
By default, ``('cf_mean',)``.
|
65
70
|
pass_through_dsets : list | tuple, optional
|
66
71
|
Optional list of datasets that are identical in the
|
67
72
|
multi-year files (e.g. input datasets that don't vary from
|
@@ -76,10 +81,35 @@ class MultiYearGroup:
|
|
76
81
|
self._source_prefix = source_prefix
|
77
82
|
self._source_pattern = source_pattern
|
78
83
|
self._pass_through_dsets = None
|
79
|
-
|
80
|
-
self._pass_through_dsets = SAMOutputRequest(pass_through_dsets)
|
84
|
+
self._dsets = None
|
81
85
|
|
82
|
-
self.
|
86
|
+
self._parse_pass_through_dsets(dsets, pass_through_dsets or [])
|
87
|
+
self._parse_dsets(dsets)
|
88
|
+
|
89
|
+
def _parse_pass_through_dsets(self, dsets, pass_through_dsets):
|
90
|
+
"""Parse a multi-year pass-through dataset collection request.
|
91
|
+
|
92
|
+
Parameters
|
93
|
+
----------
|
94
|
+
dsets : str | list
|
95
|
+
One or more datasets to collect, or "PIPELINE"
|
96
|
+
pass_through_dsets : list
|
97
|
+
List of pass through datasets.
|
98
|
+
"""
|
99
|
+
if isinstance(dsets, str) and dsets == 'PIPELINE':
|
100
|
+
files = parse_previous_status(self._dirout, ModuleName.MULTI_YEAR)
|
101
|
+
with Resource(files[0]) as res:
|
102
|
+
dsets = res.datasets
|
103
|
+
|
104
|
+
if "lcoe_fcr" in dsets:
|
105
|
+
for dset in LCOE_REQUIRED_OUTPUTS:
|
106
|
+
if dset not in pass_through_dsets:
|
107
|
+
pass_through_dsets.append(dset)
|
108
|
+
if "dc_ac_ratio" in dsets:
|
109
|
+
if "dc_ac_ratio" not in pass_through_dsets:
|
110
|
+
pass_through_dsets.append("dc_ac_ratio")
|
111
|
+
|
112
|
+
self._pass_through_dsets = SAMOutputRequest(pass_through_dsets)
|
83
113
|
|
84
114
|
def _parse_dsets(self, dsets):
|
85
115
|
"""Parse a multi-year dataset collection request. Can handle PIPELINE
|
@@ -90,11 +120,6 @@ class MultiYearGroup:
|
|
90
120
|
----------
|
91
121
|
dsets : str | list
|
92
122
|
One or more datasets to collect, or "PIPELINE"
|
93
|
-
|
94
|
-
Returns
|
95
|
-
-------
|
96
|
-
dsets : SAMOutputRequest
|
97
|
-
Dataset list object.
|
98
123
|
"""
|
99
124
|
if isinstance(dsets, str) and dsets == 'PIPELINE':
|
100
125
|
files = parse_previous_status(self._dirout, ModuleName.MULTI_YEAR)
|
@@ -104,9 +129,7 @@ class MultiYearGroup:
|
|
104
129
|
and d != 'meta'
|
105
130
|
and d not in self.pass_through_dsets]
|
106
131
|
|
107
|
-
|
108
|
-
|
109
|
-
return dsets
|
132
|
+
self._dsets = SAMOutputRequest(dsets)
|
110
133
|
|
111
134
|
@property
|
112
135
|
def name(self):
|
@@ -815,10 +838,15 @@ def my_collect_groups(out_fpath, groups, clobber=True):
|
|
815
838
|
MultiYear.collect_means(out_fpath, group['source_files'],
|
816
839
|
dset, group=group['group'])
|
817
840
|
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
841
|
+
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
|
+
for dset in pass_through_dsets:
|
848
|
+
MultiYear.pass_through(out_fpath, group['source_files'],
|
849
|
+
dset, group=group['group'])
|
822
850
|
|
823
851
|
runtime = (time.time() - t0) / 60
|
824
852
|
logger.info('- {} collection completed in: {:.2f} min.'
|
reV/handlers/transmission.py
CHANGED
@@ -9,6 +9,7 @@ import os
|
|
9
9
|
import pandas as pd
|
10
10
|
from warnings import warn
|
11
11
|
|
12
|
+
from reV.utilities import SupplyCurveField
|
12
13
|
from reV.utilities.exceptions import (HandlerWarning, HandlerKeyError,
|
13
14
|
HandlerRuntimeError)
|
14
15
|
|
@@ -153,12 +154,17 @@ class TransmissionFeatures:
|
|
153
154
|
raise
|
154
155
|
|
155
156
|
trans_table = \
|
156
|
-
trans_table.rename(
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
157
|
+
trans_table.rename(
|
158
|
+
columns={'trans_line_gid': SupplyCurveField.TRANS_GID,
|
159
|
+
'trans_gids': 'trans_line_gids'})
|
160
|
+
|
161
|
+
contains_dist_in_miles = "dist_mi" in trans_table
|
162
|
+
missing_km_dist = SupplyCurveField.DIST_SPUR_KM not in trans_table
|
163
|
+
if contains_dist_in_miles and missing_km_dist:
|
164
|
+
trans_table = trans_table.rename(
|
165
|
+
columns={"dist_mi": SupplyCurveField.DIST_SPUR_KM}
|
166
|
+
)
|
167
|
+
trans_table[SupplyCurveField.DIST_SPUR_KM] *= 1.60934
|
162
168
|
|
163
169
|
return trans_table
|
164
170
|
|
@@ -184,23 +190,28 @@ class TransmissionFeatures:
|
|
184
190
|
features = {}
|
185
191
|
|
186
192
|
cap_frac = self._avail_cap_frac
|
187
|
-
trans_features = trans_table.groupby(
|
193
|
+
trans_features = trans_table.groupby(SupplyCurveField.TRANS_GID)
|
194
|
+
trans_features = trans_features.first()
|
188
195
|
|
189
196
|
for gid, feature in trans_features.iterrows():
|
190
|
-
name = feature[
|
197
|
+
name = feature[SupplyCurveField.TRANS_TYPE].lower()
|
191
198
|
feature_dict = {'type': name}
|
192
199
|
|
193
200
|
if name == 'transline':
|
194
|
-
feature_dict[
|
201
|
+
feature_dict[SupplyCurveField.TRANS_CAPACITY] = (
|
202
|
+
feature['ac_cap'] * cap_frac
|
203
|
+
)
|
195
204
|
|
196
205
|
elif name == 'substation':
|
197
206
|
feature_dict['lines'] = json.loads(feature['trans_line_gids'])
|
198
207
|
|
199
208
|
elif name == 'loadcen':
|
200
|
-
feature_dict[
|
209
|
+
feature_dict[SupplyCurveField.TRANS_CAPACITY] = (
|
210
|
+
feature['ac_cap'] * cap_frac
|
211
|
+
)
|
201
212
|
|
202
213
|
elif name == 'pcaloadcen':
|
203
|
-
feature_dict[
|
214
|
+
feature_dict[SupplyCurveField.TRANS_CAPACITY] = None
|
204
215
|
|
205
216
|
else:
|
206
217
|
msg = ('Cannot not recognize feature type "{}" '
|
@@ -297,7 +308,8 @@ class TransmissionFeatures:
|
|
297
308
|
Substation available capacity
|
298
309
|
"""
|
299
310
|
try:
|
300
|
-
line_caps = [self[l_gid][
|
311
|
+
line_caps = [self[l_gid][SupplyCurveField.TRANS_CAPACITY]
|
312
|
+
for l_gid in line_gids]
|
301
313
|
except HandlerKeyError as e:
|
302
314
|
msg = ('Could not find capacities for substation gid {} and '
|
303
315
|
'connected lines: {}'.format(gid, line_gids))
|
@@ -331,8 +343,8 @@ class TransmissionFeatures:
|
|
331
343
|
|
332
344
|
feature = self[gid]
|
333
345
|
|
334
|
-
if
|
335
|
-
avail_cap = feature[
|
346
|
+
if SupplyCurveField.TRANS_CAPACITY in feature:
|
347
|
+
avail_cap = feature[SupplyCurveField.TRANS_CAPACITY]
|
336
348
|
|
337
349
|
elif 'lines' in feature:
|
338
350
|
avail_cap = self._substation_capacity(gid, feature['lines'])
|
@@ -387,7 +399,7 @@ class TransmissionFeatures:
|
|
387
399
|
capacity : float
|
388
400
|
Capacity needed in MW
|
389
401
|
"""
|
390
|
-
avail_cap = self[gid][
|
402
|
+
avail_cap = self[gid][SupplyCurveField.TRANS_CAPACITY]
|
391
403
|
|
392
404
|
if avail_cap < capacity:
|
393
405
|
msg = ("Cannot connect to {}: "
|
@@ -397,7 +409,7 @@ class TransmissionFeatures:
|
|
397
409
|
logger.error(msg)
|
398
410
|
raise RuntimeError(msg)
|
399
411
|
|
400
|
-
self[gid][
|
412
|
+
self[gid][SupplyCurveField.TRANS_CAPACITY] -= capacity
|
401
413
|
|
402
414
|
def _fill_lines(self, line_gids, line_caps, capacity):
|
403
415
|
"""
|
@@ -471,7 +483,7 @@ class TransmissionFeatures:
|
|
471
483
|
Substation connection is limited by maximum capacity of the
|
472
484
|
attached lines
|
473
485
|
"""
|
474
|
-
line_caps = np.array([self[gid][
|
486
|
+
line_caps = np.array([self[gid][SupplyCurveField.TRANS_CAPACITY]
|
475
487
|
for gid in line_gids])
|
476
488
|
if self._line_limited:
|
477
489
|
gid = line_gids[np.argmax(line_caps)]
|
@@ -603,8 +615,8 @@ class TransmissionFeatures:
|
|
603
615
|
raise
|
604
616
|
|
605
617
|
feature_cap = pd.Series(feature_cap)
|
606
|
-
feature_cap.name =
|
607
|
-
feature_cap.index.name =
|
618
|
+
feature_cap.name = SupplyCurveField.TRANS_CAPACITY
|
619
|
+
feature_cap.index.name = SupplyCurveField.TRANS_GID
|
608
620
|
feature_cap = feature_cap.to_frame().reset_index()
|
609
621
|
|
610
622
|
return feature_cap
|
@@ -635,16 +647,20 @@ class TransmissionCosts(TransmissionFeatures):
|
|
635
647
|
|
636
648
|
features = {}
|
637
649
|
|
638
|
-
if
|
650
|
+
if SupplyCurveField.TRANS_CAPACITY not in trans_table:
|
639
651
|
kwargs = {'avail_cap_frac': self._avail_cap_frac}
|
640
652
|
fc = TransmissionFeatures.feature_capacity(trans_table,
|
641
653
|
**kwargs)
|
642
|
-
trans_table = trans_table.merge(fc, on=
|
654
|
+
trans_table = trans_table.merge(fc, on=SupplyCurveField.TRANS_GID)
|
643
655
|
|
644
|
-
trans_features = trans_table.groupby(
|
656
|
+
trans_features = trans_table.groupby(SupplyCurveField.TRANS_GID)
|
657
|
+
trans_features = trans_features.first()
|
645
658
|
for gid, feature in trans_features.iterrows():
|
646
|
-
name = feature[
|
647
|
-
feature_dict = {'type': name,
|
659
|
+
name = feature[SupplyCurveField.TRANS_TYPE].lower()
|
660
|
+
feature_dict = {'type': name,
|
661
|
+
SupplyCurveField.TRANS_CAPACITY: (
|
662
|
+
feature[SupplyCurveField.TRANS_CAPACITY]
|
663
|
+
)}
|
648
664
|
features[gid] = feature_dict
|
649
665
|
|
650
666
|
return features
|
@@ -665,7 +681,7 @@ class TransmissionCosts(TransmissionFeatures):
|
|
665
681
|
default = 100%
|
666
682
|
"""
|
667
683
|
|
668
|
-
return self[gid][
|
684
|
+
return self[gid][SupplyCurveField.TRANS_CAPACITY]
|
669
685
|
|
670
686
|
@classmethod
|
671
687
|
def feature_costs(cls, trans_table, capacity=None, line_tie_in_cost=14000,
|
@@ -722,8 +738,9 @@ class TransmissionCosts(TransmissionFeatures):
|
|
722
738
|
costs = []
|
723
739
|
for _, row in trans_table.iterrows():
|
724
740
|
tm = row.get('transmission_multiplier', 1)
|
725
|
-
costs.append(feature.cost(row[
|
726
|
-
row[
|
741
|
+
costs.append(feature.cost(row[SupplyCurveField.TRANS_GID],
|
742
|
+
row[SupplyCurveField.DIST_SPUR_KM],
|
743
|
+
capacity=capacity,
|
727
744
|
transmission_multiplier=tm))
|
728
745
|
except Exception:
|
729
746
|
logger.exception("Error computing costs for all connections in {}"
|
reV/hybrids/hybrid_methods.py
CHANGED
@@ -31,9 +31,9 @@ def aggregate_solar_capacity(h):
|
|
31
31
|
capacity ratio and the solar capacity is copied into this new
|
32
32
|
column.
|
33
33
|
"""
|
34
|
-
if f'hybrid_solar_{SupplyCurveField.
|
34
|
+
if f'hybrid_solar_{SupplyCurveField.CAPACITY_AC_MW}' in h.hybrid_meta:
|
35
35
|
return None
|
36
|
-
return h.hybrid_meta[f'solar_{SupplyCurveField.
|
36
|
+
return h.hybrid_meta[f'solar_{SupplyCurveField.CAPACITY_AC_MW}']
|
37
37
|
|
38
38
|
|
39
39
|
def aggregate_wind_capacity(h):
|
@@ -60,9 +60,9 @@ def aggregate_wind_capacity(h):
|
|
60
60
|
exist, it is assumed that there is no limit on the solar to wind
|
61
61
|
capacity ratio and the wind capacity is copied into this new column.
|
62
62
|
"""
|
63
|
-
if f'hybrid_wind_{SupplyCurveField.
|
63
|
+
if f'hybrid_wind_{SupplyCurveField.CAPACITY_AC_MW}' in h.hybrid_meta:
|
64
64
|
return None
|
65
|
-
return h.hybrid_meta[f'wind_{SupplyCurveField.
|
65
|
+
return h.hybrid_meta[f'wind_{SupplyCurveField.CAPACITY_AC_MW}']
|
66
66
|
|
67
67
|
|
68
68
|
def aggregate_capacity(h):
|
@@ -81,8 +81,8 @@ def aggregate_capacity(h):
|
|
81
81
|
A series of data containing the aggregated capacity, or `None`
|
82
82
|
if the capacity columns are missing.
|
83
83
|
"""
|
84
|
-
sc = f'hybrid_solar_{SupplyCurveField.
|
85
|
-
wc = f'hybrid_wind_{SupplyCurveField.
|
84
|
+
sc = f'hybrid_solar_{SupplyCurveField.CAPACITY_AC_MW}'
|
85
|
+
wc = f'hybrid_wind_{SupplyCurveField.CAPACITY_AC_MW}'
|
86
86
|
missing_solar_cap = sc not in h.hybrid_meta.columns
|
87
87
|
missing_wind_cap = wc not in h.hybrid_meta.columns
|
88
88
|
if missing_solar_cap or missing_wind_cap:
|
@@ -109,10 +109,10 @@ def aggregate_capacity_factor(h):
|
|
109
109
|
if the capacity and/or mean_cf columns are missing.
|
110
110
|
"""
|
111
111
|
|
112
|
-
sc = f'hybrid_solar_{SupplyCurveField.
|
113
|
-
wc = f'hybrid_wind_{SupplyCurveField.
|
114
|
-
scf = f'solar_{SupplyCurveField.
|
115
|
-
wcf = f'wind_{SupplyCurveField.
|
112
|
+
sc = f'hybrid_solar_{SupplyCurveField.CAPACITY_AC_MW}'
|
113
|
+
wc = f'hybrid_wind_{SupplyCurveField.CAPACITY_AC_MW}'
|
114
|
+
scf = f'solar_{SupplyCurveField.MEAN_CF_AC}'
|
115
|
+
wcf = f'wind_{SupplyCurveField.MEAN_CF_AC}'
|
116
116
|
missing_solar_cap = sc not in h.hybrid_meta.columns
|
117
117
|
missing_wind_cap = wc not in h.hybrid_meta.columns
|
118
118
|
missing_solar_mean_cf = scf not in h.hybrid_meta.columns
|
@@ -130,8 +130,10 @@ def aggregate_capacity_factor(h):
|
|
130
130
|
|
131
131
|
|
132
132
|
HYBRID_METHODS = {
|
133
|
-
f'hybrid_solar_{SupplyCurveField.
|
134
|
-
|
135
|
-
|
136
|
-
f'
|
133
|
+
f'hybrid_solar_{SupplyCurveField.CAPACITY_AC_MW}': (
|
134
|
+
aggregate_solar_capacity
|
135
|
+
),
|
136
|
+
f'hybrid_wind_{SupplyCurveField.CAPACITY_AC_MW}': aggregate_wind_capacity,
|
137
|
+
f'hybrid_{SupplyCurveField.CAPACITY_AC_MW}': aggregate_capacity,
|
138
|
+
f'hybrid_{SupplyCurveField.MEAN_CF_AC}': aggregate_capacity_factor
|
137
139
|
}
|
reV/hybrids/hybrids.py
CHANGED
@@ -38,11 +38,11 @@ NON_DUPLICATE_COLS = {
|
|
38
38
|
SupplyCurveField.SC_POINT_GID, SupplyCurveField.SC_ROW_IND,
|
39
39
|
SupplyCurveField.SC_COL_IND
|
40
40
|
}
|
41
|
-
|
42
|
-
DEFAULT_FILL_VALUES = {f'solar_{SupplyCurveField.
|
43
|
-
f'wind_{SupplyCurveField.
|
44
|
-
f'solar_{SupplyCurveField.
|
45
|
-
f'wind_{SupplyCurveField.
|
41
|
+
HYBRIDS_GID_COL = "gid"
|
42
|
+
DEFAULT_FILL_VALUES = {f'solar_{SupplyCurveField.CAPACITY_AC_MW}': 0,
|
43
|
+
f'wind_{SupplyCurveField.CAPACITY_AC_MW}': 0,
|
44
|
+
f'solar_{SupplyCurveField.MEAN_CF_AC}': 0,
|
45
|
+
f'wind_{SupplyCurveField.MEAN_CF_AC}': 0}
|
46
46
|
OUTPUT_PROFILE_NAMES = ['hybrid_profile',
|
47
47
|
'hybrid_solar_profile',
|
48
48
|
'hybrid_wind_profile']
|
@@ -702,7 +702,7 @@ class MetaHybridizer:
|
|
702
702
|
self._propagate_duplicate_cols(duplicate_cols)
|
703
703
|
self._drop_cols(duplicate_cols)
|
704
704
|
self._hybrid_meta.rename(self.__col_name_map, inplace=True, axis=1)
|
705
|
-
self._hybrid_meta.index.name =
|
705
|
+
self._hybrid_meta.index.name = HYBRIDS_GID_COL
|
706
706
|
|
707
707
|
def _propagate_duplicate_cols(self, duplicate_cols):
|
708
708
|
"""Fill missing column values from outer merge."""
|
@@ -713,9 +713,9 @@ class MetaHybridizer:
|
|
713
713
|
self._hybrid_meta.loc[null_idx, no_suffix] = non_null_vals
|
714
714
|
|
715
715
|
def _drop_cols(self, duplicate_cols):
|
716
|
-
"""Drop any
|
716
|
+
"""Drop any remaining duplicate and 'HYBRIDS_GID_COL' columns."""
|
717
717
|
self._hybrid_meta.drop(
|
718
|
-
duplicate_cols +
|
718
|
+
duplicate_cols + [HYBRIDS_GID_COL],
|
719
719
|
axis=1,
|
720
720
|
inplace=True,
|
721
721
|
errors="ignore",
|
@@ -1196,8 +1196,8 @@ class Hybridization:
|
|
1196
1196
|
def __rep_profile_hybridization_params(self):
|
1197
1197
|
"""Zip the rep profile hybridization parameters."""
|
1198
1198
|
|
1199
|
-
cap_col_names = [f"hybrid_solar_{SupplyCurveField.
|
1200
|
-
f"hybrid_wind_{SupplyCurveField.
|
1199
|
+
cap_col_names = [f"hybrid_solar_{SupplyCurveField.CAPACITY_AC_MW}",
|
1200
|
+
f"hybrid_wind_{SupplyCurveField.CAPACITY_AC_MW}"]
|
1201
1201
|
idx_maps = [
|
1202
1202
|
self.meta_hybridizer.solar_profile_indices_map,
|
1203
1203
|
self.meta_hybridizer.wind_profile_indices_map,
|
reV/nrwal/nrwal.py
CHANGED
@@ -37,7 +37,7 @@ class RevNrwal:
|
|
37
37
|
|
38
38
|
def __init__(self, gen_fpath, site_data, sam_files, nrwal_configs,
|
39
39
|
output_request, save_raw=True,
|
40
|
-
meta_gid_col=ResourceMetaField.GID,
|
40
|
+
meta_gid_col=str(ResourceMetaField.GID), # str() to fix docs
|
41
41
|
site_meta_cols=None):
|
42
42
|
"""Framework to handle reV-NRWAL analysis.
|
43
43
|
|
reV/qa_qc/qa_qc.py
CHANGED
@@ -105,7 +105,7 @@ class QaQc:
|
|
105
105
|
if file.endswith(".csv"):
|
106
106
|
summary_csv = os.path.join(self.out_dir, file)
|
107
107
|
summary = pd.read_csv(summary_csv)
|
108
|
-
has_right_cols = (
|
108
|
+
has_right_cols = ("gid" in summary
|
109
109
|
and SupplyCurveField.LATITUDE in summary
|
110
110
|
and SupplyCurveField.LONGITUDE in summary)
|
111
111
|
if has_right_cols:
|
reV/qa_qc/summary.py
CHANGED
@@ -597,11 +597,11 @@ class SummaryPlots(PlotBase):
|
|
597
597
|
sc_df : pandas.DataFrame
|
598
598
|
Supply curve data
|
599
599
|
"""
|
600
|
-
values = [SupplyCurveField.
|
600
|
+
values = [SupplyCurveField.CAPACITY_AC_MW, lcoe]
|
601
601
|
self._check_value(self.summary, values, scatter=False)
|
602
602
|
sc_df = self.summary[values].sort_values(lcoe)
|
603
603
|
sc_df['cumulative_capacity'] = (
|
604
|
-
sc_df[SupplyCurveField.
|
604
|
+
sc_df[SupplyCurveField.CAPACITY_AC_MW].cumsum()
|
605
605
|
)
|
606
606
|
|
607
607
|
return sc_df
|
@@ -800,11 +800,11 @@ class SupplyCurvePlot(PlotBase):
|
|
800
800
|
sc_df : pandas.DataFrame
|
801
801
|
Supply curve data
|
802
802
|
"""
|
803
|
-
values = [SupplyCurveField.
|
803
|
+
values = [SupplyCurveField.CAPACITY_AC_MW, lcoe]
|
804
804
|
self._check_value(self.sc_table, values, scatter=False)
|
805
805
|
sc_df = self.sc_table[values].sort_values(lcoe)
|
806
806
|
sc_df['cumulative_capacity'] = (
|
807
|
-
sc_df[SupplyCurveField.
|
807
|
+
sc_df[SupplyCurveField.CAPACITY_AC_MW].cumsum()
|
808
808
|
)
|
809
809
|
|
810
810
|
return sc_df
|
reV/rep_profiles/rep_profiles.py
CHANGED
@@ -953,7 +953,7 @@ class RepProfiles(RepProfilesBase):
|
|
953
953
|
def __init__(self, gen_fpath, rev_summary, reg_cols,
|
954
954
|
cf_dset='cf_profile',
|
955
955
|
rep_method='meanoid', err_method='rmse',
|
956
|
-
weight=SupplyCurveField.GID_COUNTS,
|
956
|
+
weight=str(SupplyCurveField.GID_COUNTS), # str() to fix docs
|
957
957
|
n_profiles=1, aggregate_profiles=False):
|
958
958
|
"""ReV rep profiles class.
|
959
959
|
|
reV/supply_curve/exclusions.py
CHANGED
@@ -111,7 +111,7 @@ class LayerMask:
|
|
111
111
|
specifications to create a boolean mask that defines the
|
112
112
|
extent to which the original mask should be applied.
|
113
113
|
For example, suppose you specify the input the following
|
114
|
-
way
|
114
|
+
way::
|
115
115
|
|
116
116
|
input_dict = {
|
117
117
|
"viewsheds": {
|