NREL-reV 0.8.7__py3-none-any.whl → 0.8.9__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.7.dist-info → NREL_reV-0.8.9.dist-info}/METADATA +12 -10
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/RECORD +38 -38
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/WHEEL +1 -1
- reV/SAM/SAM.py +182 -133
- reV/SAM/econ.py +18 -14
- reV/SAM/generation.py +608 -419
- reV/SAM/windbos.py +93 -79
- reV/bespoke/bespoke.py +690 -445
- reV/bespoke/place_turbines.py +6 -6
- reV/config/project_points.py +220 -140
- reV/econ/econ.py +165 -113
- reV/econ/economies_of_scale.py +57 -34
- reV/generation/base.py +310 -183
- reV/generation/generation.py +298 -190
- reV/handlers/exclusions.py +16 -15
- reV/handlers/multi_year.py +12 -9
- reV/handlers/outputs.py +6 -5
- reV/hybrids/hybrid_methods.py +28 -30
- reV/hybrids/hybrids.py +304 -188
- reV/nrwal/nrwal.py +262 -168
- reV/qa_qc/cli_qa_qc.py +14 -10
- reV/qa_qc/qa_qc.py +217 -119
- reV/qa_qc/summary.py +228 -146
- reV/rep_profiles/rep_profiles.py +349 -230
- reV/supply_curve/aggregation.py +349 -188
- reV/supply_curve/competitive_wind_farms.py +90 -48
- reV/supply_curve/exclusions.py +138 -85
- reV/supply_curve/extent.py +75 -50
- reV/supply_curve/points.py +536 -309
- reV/supply_curve/sc_aggregation.py +366 -225
- reV/supply_curve/supply_curve.py +505 -308
- reV/supply_curve/tech_mapping.py +144 -82
- reV/utilities/__init__.py +199 -16
- reV/utilities/pytest_utils.py +8 -4
- reV/version.py +1 -1
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/LICENSE +0 -0
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/entry_points.txt +0 -0
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/top_level.txt +0 -0
reV/supply_curve/tech_mapping.py
CHANGED
@@ -8,21 +8,21 @@ Created on Fri Jun 21 16:05:47 2019
|
|
8
8
|
|
9
9
|
@author: gbuster
|
10
10
|
"""
|
11
|
-
from concurrent.futures import as_completed
|
12
|
-
import h5py
|
13
11
|
import logging
|
14
|
-
from math import ceil
|
15
|
-
import numpy as np
|
16
12
|
import os
|
17
|
-
from
|
13
|
+
from concurrent.futures import as_completed
|
14
|
+
from math import ceil
|
18
15
|
from warnings import warn
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
import h5py
|
18
|
+
import numpy as np
|
23
19
|
from rex.resource import Resource
|
24
20
|
from rex.utilities.execution import SpawnProcessPool
|
25
21
|
from rex.utilities.utilities import res_dist_threshold
|
22
|
+
from scipy.spatial import cKDTree
|
23
|
+
|
24
|
+
from reV.supply_curve.extent import SupplyCurveExtent, LATITUDE, LONGITUDE
|
25
|
+
from reV.utilities.exceptions import FileInputError, FileInputWarning
|
26
26
|
|
27
27
|
logger = logging.getLogger(__name__)
|
28
28
|
|
@@ -30,8 +30,9 @@ logger = logging.getLogger(__name__)
|
|
30
30
|
class TechMapping:
|
31
31
|
"""Framework to create map between tech layer (exclusions), res, and gen"""
|
32
32
|
|
33
|
-
def __init__(
|
34
|
-
|
33
|
+
def __init__(
|
34
|
+
self, excl_fpath, res_fpath, sc_resolution=2560, dist_margin=1.05
|
35
|
+
):
|
35
36
|
"""
|
36
37
|
Parameters
|
37
38
|
----------
|
@@ -51,11 +52,13 @@ class TechMapping:
|
|
51
52
|
self._excl_fpath = excl_fpath
|
52
53
|
self._check_fout()
|
53
54
|
|
54
|
-
self._tree, self._dist_thresh =
|
55
|
-
|
55
|
+
self._tree, self._dist_thresh = self._build_tree(
|
56
|
+
res_fpath, dist_margin=dist_margin
|
57
|
+
)
|
56
58
|
|
57
|
-
with SupplyCurveExtent(
|
58
|
-
|
59
|
+
with SupplyCurveExtent(
|
60
|
+
self._excl_fpath, resolution=sc_resolution
|
61
|
+
) as sc:
|
59
62
|
self._sc_resolution = sc.resolution
|
60
63
|
self._gids = np.array(list(range(len(sc))), dtype=np.uint32)
|
61
64
|
self._excl_shape = sc.exclusions.shape
|
@@ -64,9 +67,12 @@ class TechMapping:
|
|
64
67
|
self._sc_col_indices = sc.col_indices
|
65
68
|
self._excl_row_slices = sc.excl_row_slices
|
66
69
|
self._excl_col_slices = sc.excl_col_slices
|
67
|
-
logger.info(
|
68
|
-
|
69
|
-
|
70
|
+
logger.info(
|
71
|
+
"Initialized TechMapping object with {} calc chunks "
|
72
|
+
"for {} tech exclusion points".format(
|
73
|
+
len(self._gids), self._n_excl
|
74
|
+
)
|
75
|
+
)
|
70
76
|
|
71
77
|
@property
|
72
78
|
def distance_threshold(self):
|
@@ -110,8 +116,9 @@ class TechMapping:
|
|
110
116
|
# pylint: disable=not-callable
|
111
117
|
tree = cKDTree(lat_lons)
|
112
118
|
|
113
|
-
dist_thresh = res_dist_threshold(
|
114
|
-
|
119
|
+
dist_thresh = res_dist_threshold(
|
120
|
+
lat_lons, tree=tree, margin=dist_margin
|
121
|
+
)
|
115
122
|
|
116
123
|
return tree, dist_thresh
|
117
124
|
|
@@ -135,8 +142,9 @@ class TechMapping:
|
|
135
142
|
return iarr.reshape(shape)
|
136
143
|
|
137
144
|
@staticmethod
|
138
|
-
def _get_excl_slices(
|
139
|
-
|
145
|
+
def _get_excl_slices(
|
146
|
+
gid, sc_row_indices, sc_col_indices, excl_row_slices, excl_col_slices
|
147
|
+
):
|
140
148
|
"""
|
141
149
|
Get the row and column slices of the exclusions grid corresponding
|
142
150
|
to the supply curve point gid.
|
@@ -175,7 +183,7 @@ class TechMapping:
|
|
175
183
|
@classmethod
|
176
184
|
def _get_excl_coords(cls, excl_fpath, gids, sc_row_indices, sc_col_indices,
|
177
185
|
excl_row_slices, excl_col_slices,
|
178
|
-
coord_labels=(
|
186
|
+
coord_labels=(LATITUDE, LONGITUDE)):
|
179
187
|
"""
|
180
188
|
Extract the exclusion coordinates for teh desired gids for TechMapping.
|
181
189
|
|
@@ -210,21 +218,25 @@ class TechMapping:
|
|
210
218
|
tech exclusion points. List entries correspond to input gids.
|
211
219
|
"""
|
212
220
|
coords_out = []
|
213
|
-
with h5py.File(excl_fpath,
|
221
|
+
with h5py.File(excl_fpath, "r") as f:
|
214
222
|
for gid in gids:
|
215
|
-
row_slice, col_slice = cls._get_excl_slices(
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
223
|
+
row_slice, col_slice = cls._get_excl_slices(
|
224
|
+
gid,
|
225
|
+
sc_row_indices,
|
226
|
+
sc_col_indices,
|
227
|
+
excl_row_slices,
|
228
|
+
excl_col_slices,
|
229
|
+
)
|
220
230
|
try:
|
221
231
|
lats = f[coord_labels[0]][row_slice, col_slice]
|
222
232
|
lons = f[coord_labels[1]][row_slice, col_slice]
|
223
233
|
emeta = np.vstack((lats.flatten(), lons.flatten())).T
|
224
234
|
except Exception as e:
|
225
|
-
m = (
|
226
|
-
|
227
|
-
|
235
|
+
m = (
|
236
|
+
"Could not unpack coordinates for gid {} with "
|
237
|
+
"row/col slice {}/{}. Received the following "
|
238
|
+
"error:\n{}".format(gid, row_slice, col_slice, e)
|
239
|
+
)
|
228
240
|
logger.error(m)
|
229
241
|
raise e
|
230
242
|
|
@@ -233,9 +245,17 @@ class TechMapping:
|
|
233
245
|
return coords_out
|
234
246
|
|
235
247
|
@classmethod
|
236
|
-
def map_resource_gids(
|
237
|
-
|
238
|
-
|
248
|
+
def map_resource_gids(
|
249
|
+
cls,
|
250
|
+
gids,
|
251
|
+
excl_fpath,
|
252
|
+
sc_row_indices,
|
253
|
+
sc_col_indices,
|
254
|
+
excl_row_slices,
|
255
|
+
excl_col_slices,
|
256
|
+
tree,
|
257
|
+
dist_thresh,
|
258
|
+
):
|
239
259
|
"""Map exclusion gids to the resource meta.
|
240
260
|
|
241
261
|
Parameters
|
@@ -272,15 +292,26 @@ class TechMapping:
|
|
272
292
|
List of arrays of index values from the NN. List entries correspond
|
273
293
|
to input gids.
|
274
294
|
"""
|
275
|
-
logger.debug(
|
276
|
-
|
295
|
+
logger.debug(
|
296
|
+
"Getting tech map coordinates for chunks {} through {}".format(
|
297
|
+
gids[0], gids[-1]
|
298
|
+
)
|
299
|
+
)
|
277
300
|
ind_out = []
|
278
|
-
coords_out = cls._get_excl_coords(
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
301
|
+
coords_out = cls._get_excl_coords(
|
302
|
+
excl_fpath,
|
303
|
+
gids,
|
304
|
+
sc_row_indices,
|
305
|
+
sc_col_indices,
|
306
|
+
excl_row_slices,
|
307
|
+
excl_col_slices,
|
308
|
+
)
|
309
|
+
|
310
|
+
logger.debug(
|
311
|
+
"Running tech mapping for chunks {} through {}".format(
|
312
|
+
gids[0], gids[-1]
|
313
|
+
)
|
314
|
+
)
|
284
315
|
for i, _ in enumerate(gids):
|
285
316
|
dist, ind = tree.query(coords_out[i])
|
286
317
|
ind[(dist >= dist_thresh)] = -1
|
@@ -289,8 +320,14 @@ class TechMapping:
|
|
289
320
|
return ind_out
|
290
321
|
|
291
322
|
@staticmethod
|
292
|
-
def save_tech_map(
|
293
|
-
|
323
|
+
def save_tech_map(
|
324
|
+
excl_fpath,
|
325
|
+
dset,
|
326
|
+
indices,
|
327
|
+
distance_threshold=None,
|
328
|
+
res_fpath=None,
|
329
|
+
chunks=(128, 128),
|
330
|
+
):
|
294
331
|
"""Save tech mapping indices and coordinates to an h5 output file.
|
295
332
|
|
296
333
|
Parameters
|
@@ -315,31 +352,40 @@ class TechMapping:
|
|
315
352
|
shape = indices.shape
|
316
353
|
chunks = (np.min((shape[0], chunks[0])), np.min((shape[1], chunks[1])))
|
317
354
|
|
318
|
-
with h5py.File(excl_fpath,
|
355
|
+
with h5py.File(excl_fpath, "a") as f:
|
319
356
|
if dset in list(f):
|
320
|
-
wmsg = (
|
321
|
-
|
322
|
-
|
357
|
+
wmsg = (
|
358
|
+
'TechMap results dataset "{}" is being replaced '
|
359
|
+
'in pre-existing Exclusions TechMapping file "{}"'.format(
|
360
|
+
dset, excl_fpath
|
361
|
+
)
|
362
|
+
)
|
323
363
|
logger.warning(wmsg)
|
324
364
|
warn(wmsg, FileInputWarning)
|
325
365
|
f[dset][...] = indices
|
326
366
|
else:
|
327
|
-
f.create_dataset(
|
328
|
-
|
367
|
+
f.create_dataset(
|
368
|
+
dset,
|
369
|
+
shape=shape,
|
370
|
+
dtype=indices.dtype,
|
371
|
+
data=indices,
|
372
|
+
chunks=chunks,
|
373
|
+
)
|
329
374
|
|
330
375
|
if distance_threshold:
|
331
|
-
f[dset].attrs[
|
376
|
+
f[dset].attrs["distance_threshold"] = distance_threshold
|
332
377
|
|
333
378
|
if res_fpath:
|
334
|
-
f[dset].attrs[
|
379
|
+
f[dset].attrs["src_res_fpath"] = res_fpath
|
335
380
|
|
336
|
-
logger.info(
|
337
|
-
|
381
|
+
logger.info(
|
382
|
+
'Successfully saved tech map "{}" to {}'.format(dset, excl_fpath)
|
383
|
+
)
|
338
384
|
|
339
385
|
def _check_fout(self):
|
340
386
|
"""Check the TechMapping output file for cached data."""
|
341
387
|
with h5py.File(self._excl_fpath, 'r') as f:
|
342
|
-
if
|
388
|
+
if LATITUDE not in f or LONGITUDE not in f:
|
343
389
|
emsg = ('Datasets "latitude" and/or "longitude" not in '
|
344
390
|
'pre-existing Exclusions TechMapping file "{}". '
|
345
391
|
'Cannot proceed.'
|
@@ -370,33 +416,36 @@ class TechMapping:
|
|
370
416
|
gid_chunks = np.array_split(self._gids, gid_chunks)
|
371
417
|
|
372
418
|
# init full output arrays
|
373
|
-
indices = -1 * np.ones((self._n_excl,
|
419
|
+
indices = -1 * np.ones((self._n_excl,), dtype=np.int32)
|
374
420
|
iarr = self._make_excl_iarr(self._excl_shape)
|
375
421
|
|
376
422
|
futures = {}
|
377
|
-
loggers = [__name__,
|
378
|
-
with SpawnProcessPool(max_workers=max_workers,
|
379
|
-
loggers=loggers) as exe:
|
380
|
-
|
423
|
+
loggers = [__name__, "reV"]
|
424
|
+
with SpawnProcessPool(max_workers=max_workers, loggers=loggers) as exe:
|
381
425
|
# iterate through split executions, submitting each to worker
|
382
426
|
for i, gid_set in enumerate(gid_chunks):
|
383
427
|
# submit executions and append to futures list
|
384
|
-
futures[
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
428
|
+
futures[
|
429
|
+
exe.submit(
|
430
|
+
self.map_resource_gids,
|
431
|
+
gid_set,
|
432
|
+
self._excl_fpath,
|
433
|
+
self._sc_row_indices,
|
434
|
+
self._sc_col_indices,
|
435
|
+
self._excl_row_slices,
|
436
|
+
self._excl_col_slices,
|
437
|
+
self._tree,
|
438
|
+
self.distance_threshold,
|
439
|
+
)
|
440
|
+
] = i
|
393
441
|
|
394
442
|
n_finished = 0
|
395
443
|
for future in as_completed(futures):
|
396
444
|
n_finished += 1
|
397
|
-
logger.info(
|
398
|
-
|
399
|
-
|
445
|
+
logger.info(
|
446
|
+
"Parallel TechMapping futures collected: "
|
447
|
+
"{} out of {}".format(n_finished, len(futures))
|
448
|
+
)
|
400
449
|
|
401
450
|
i = futures[future]
|
402
451
|
result = future.result()
|
@@ -407,7 +456,8 @@ class TechMapping:
|
|
407
456
|
self._sc_row_indices,
|
408
457
|
self._sc_col_indices,
|
409
458
|
self._excl_row_slices,
|
410
|
-
self._excl_col_slices
|
459
|
+
self._excl_col_slices,
|
460
|
+
)
|
411
461
|
ind_slice = iarr[row_slice, col_slice].flatten()
|
412
462
|
indices[ind_slice] = result[j]
|
413
463
|
|
@@ -416,8 +466,16 @@ class TechMapping:
|
|
416
466
|
return indices
|
417
467
|
|
418
468
|
@classmethod
|
419
|
-
def run(
|
420
|
-
|
469
|
+
def run(
|
470
|
+
cls,
|
471
|
+
excl_fpath,
|
472
|
+
res_fpath,
|
473
|
+
dset=None,
|
474
|
+
sc_resolution=2560,
|
475
|
+
dist_margin=1.05,
|
476
|
+
max_workers=None,
|
477
|
+
points_per_worker=10,
|
478
|
+
):
|
421
479
|
"""Run parallel mapping and save to h5 file.
|
422
480
|
|
423
481
|
Parameters
|
@@ -450,15 +508,19 @@ class TechMapping:
|
|
450
508
|
Index values of the NN resource point. -1 if no res point found.
|
451
509
|
2D integer array with shape equal to the exclusions extent shape.
|
452
510
|
"""
|
453
|
-
kwargs = {"dist_margin": dist_margin,
|
454
|
-
"sc_resolution": sc_resolution}
|
511
|
+
kwargs = {"dist_margin": dist_margin, "sc_resolution": sc_resolution}
|
455
512
|
mapper = cls(excl_fpath, res_fpath, **kwargs)
|
456
|
-
indices = mapper.map_resource(
|
457
|
-
|
513
|
+
indices = mapper.map_resource(
|
514
|
+
max_workers=max_workers, points_per_worker=points_per_worker
|
515
|
+
)
|
458
516
|
|
459
517
|
if dset:
|
460
|
-
mapper.save_tech_map(
|
461
|
-
|
462
|
-
|
518
|
+
mapper.save_tech_map(
|
519
|
+
excl_fpath,
|
520
|
+
dset,
|
521
|
+
indices,
|
522
|
+
distance_threshold=mapper.distance_threshold,
|
523
|
+
res_fpath=res_fpath,
|
524
|
+
)
|
463
525
|
|
464
526
|
return indices
|
reV/utilities/__init__.py
CHANGED
@@ -1,13 +1,196 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
"""
|
3
|
-
reV utilities.
|
4
|
-
"""
|
2
|
+
"""reV utilities."""
|
5
3
|
from enum import Enum
|
4
|
+
|
6
5
|
import PySAM
|
7
6
|
from rex.utilities.loggers import log_versions as rex_log_versions
|
7
|
+
|
8
8
|
from reV.version import __version__
|
9
9
|
|
10
10
|
|
11
|
+
class FieldEnum(str, Enum):
|
12
|
+
"""Base Field enum with some mapping methods."""
|
13
|
+
|
14
|
+
@classmethod
|
15
|
+
def map_to(cls, other):
|
16
|
+
"""Return a rename map from this enum to another.
|
17
|
+
|
18
|
+
Mapping is performed on matching enum names. In other words, if
|
19
|
+
both enums have a `ONE` attribute, this will be mapped from one
|
20
|
+
enum to another.
|
21
|
+
|
22
|
+
Parameters
|
23
|
+
----------
|
24
|
+
other : :class:`Enum`
|
25
|
+
``Enum`` subclass with ``__members__`` attribute.
|
26
|
+
|
27
|
+
Returns
|
28
|
+
-------
|
29
|
+
dict
|
30
|
+
Dictionary mapping matching values from one enum to another.
|
31
|
+
|
32
|
+
Examples
|
33
|
+
--------
|
34
|
+
>>> class Test1(FieldEnum):
|
35
|
+
>>> ONE = "one_x"
|
36
|
+
>>> TWO = "two"
|
37
|
+
>>>
|
38
|
+
>>> class Test2(Enum):
|
39
|
+
>>> ONE = "one_y"
|
40
|
+
>>> THREE = "three"
|
41
|
+
>>>
|
42
|
+
>>> Test1.map_to(Test2)
|
43
|
+
{<Test1.ONE: 'one_x'>: <Test2.ONE: 'one_y'>}
|
44
|
+
"""
|
45
|
+
return {
|
46
|
+
cls[mem]: other[mem]
|
47
|
+
for mem in cls.__members__
|
48
|
+
if mem in other.__members__
|
49
|
+
}
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def map_from(cls, other):
|
53
|
+
"""Map from a dictionary of name / member pairs to this enum.
|
54
|
+
|
55
|
+
Parameters
|
56
|
+
----------
|
57
|
+
other : dict
|
58
|
+
Dictionary mapping key values (typically old aliases) to
|
59
|
+
enum values. For example, ``{'sc_gid': 'SC_GID'}`` would
|
60
|
+
return a dictionary that maps ``'sc_gid'`` to the ``SC_GID``
|
61
|
+
member of this enum.
|
62
|
+
|
63
|
+
Returns
|
64
|
+
-------
|
65
|
+
dict
|
66
|
+
Mapping of input dictionary keys to member values of this
|
67
|
+
enum.
|
68
|
+
|
69
|
+
Examples
|
70
|
+
--------
|
71
|
+
>>> class Test(FieldEnum):
|
72
|
+
>>> ONE = "one_x"
|
73
|
+
>>> TWO = "two_y"
|
74
|
+
>>>
|
75
|
+
>>> Test.map_from({1: "ONE", 2: "TWO"})
|
76
|
+
{1: <Test.ONE: 'one_x'>, 2: <Test.TWO: 'two_y'>}
|
77
|
+
"""
|
78
|
+
return {name: cls[mem] for name, mem in other.items()}
|
79
|
+
|
80
|
+
def __str__(self):
|
81
|
+
return self.value
|
82
|
+
|
83
|
+
def __format__(self, format_spec):
|
84
|
+
return str.__format__(self.value, format_spec)
|
85
|
+
|
86
|
+
|
87
|
+
class SiteDataField(FieldEnum):
|
88
|
+
"""An enumerated map to site data column names."""
|
89
|
+
|
90
|
+
GID = "gid"
|
91
|
+
CONFIG = "config"
|
92
|
+
|
93
|
+
|
94
|
+
class ResourceMetaField(FieldEnum):
|
95
|
+
"""An enumerated map to resource meta column names.
|
96
|
+
|
97
|
+
Each output name should match the name of a key the resource file
|
98
|
+
meta table.
|
99
|
+
"""
|
100
|
+
|
101
|
+
GID = "gid"
|
102
|
+
LATITUDE = "latitude"
|
103
|
+
LONGITUDE = "longitude"
|
104
|
+
ELEVATION = "elevation"
|
105
|
+
TIMEZONE = "timezone"
|
106
|
+
COUNTY = "county"
|
107
|
+
STATE = "state"
|
108
|
+
COUNTRY = "country"
|
109
|
+
OFFSHORE = "offshore"
|
110
|
+
|
111
|
+
|
112
|
+
class SupplyCurveField(FieldEnum):
|
113
|
+
"""An enumerated map to supply curve summary/meta keys.
|
114
|
+
|
115
|
+
Each output name should match the name of a key in
|
116
|
+
meth:`AggregationSupplyCurvePoint.summary` or
|
117
|
+
meth:`GenerationSupplyCurvePoint.point_summary` or
|
118
|
+
meth:`BespokeSinglePlant.meta`
|
119
|
+
"""
|
120
|
+
|
121
|
+
SC_POINT_GID = "sc_point_gid"
|
122
|
+
SOURCE_GIDS = "source_gids"
|
123
|
+
SC_GID = "sc_gid"
|
124
|
+
GID_COUNTS = "gid_counts"
|
125
|
+
GID = "gid"
|
126
|
+
N_GIDS = "n_gids"
|
127
|
+
RES_GIDS = "res_gids"
|
128
|
+
GEN_GIDS = "gen_gids"
|
129
|
+
AREA_SQ_KM = "area_sq_km"
|
130
|
+
LATITUDE = "latitude"
|
131
|
+
LONGITUDE = "longitude"
|
132
|
+
ELEVATION = "elevation"
|
133
|
+
TIMEZONE = "timezone"
|
134
|
+
COUNTY = "county"
|
135
|
+
STATE = "state"
|
136
|
+
COUNTRY = "country"
|
137
|
+
MEAN_CF = "mean_cf"
|
138
|
+
MEAN_LCOE = "mean_lcoe"
|
139
|
+
MEAN_RES = "mean_res"
|
140
|
+
CAPACITY = "capacity"
|
141
|
+
OFFSHORE = "offshore"
|
142
|
+
SC_ROW_IND = "sc_row_ind"
|
143
|
+
SC_COL_IND = "sc_col_ind"
|
144
|
+
CAPACITY_AC = "capacity_ac"
|
145
|
+
CAPITAL_COST = "capital_cost"
|
146
|
+
FIXED_OPERATING_COST = "fixed_operating_cost"
|
147
|
+
VARIABLE_OPERATING_COST = "variable_operating_cost"
|
148
|
+
FIXED_CHARGE_RATE = "fixed_charge_rate"
|
149
|
+
SC_POINT_CAPITAL_COST = "sc_point_capital_cost"
|
150
|
+
SC_POINT_FIXED_OPERATING_COST = "sc_point_fixed_operating_cost"
|
151
|
+
SC_POINT_ANNUAL_ENERGY = "sc_point_annual_energy"
|
152
|
+
SC_POINT_ANNUAL_ENERGY_AC = "sc_point_annual_energy_ac"
|
153
|
+
MEAN_FRICTION = "mean_friction"
|
154
|
+
MEAN_LCOE_FRICTION = "mean_lcoe_friction"
|
155
|
+
TOTAL_LCOE_FRICTION = "total_lcoe_friction"
|
156
|
+
RAW_LCOE = "raw_lcoe"
|
157
|
+
CAPITAL_COST_SCALAR = "capital_cost_scalar"
|
158
|
+
SCALED_CAPITAL_COST = "scaled_capital_cost"
|
159
|
+
SCALED_SC_POINT_CAPITAL_COST = "scaled_sc_point_capital_cost"
|
160
|
+
TURBINE_X_COORDS = "turbine_x_coords"
|
161
|
+
TURBINE_Y_COORDS = "turbine_y_coords"
|
162
|
+
EOS_MULT = "eos_mult"
|
163
|
+
REG_MULT = "reg_mult"
|
164
|
+
|
165
|
+
|
166
|
+
@classmethod
|
167
|
+
def map_from_legacy(cls):
|
168
|
+
"""Map of legacy names to current values.
|
169
|
+
|
170
|
+
Returns
|
171
|
+
-------
|
172
|
+
dict
|
173
|
+
Dictionary that maps legacy supply curve column names to
|
174
|
+
members of this enum.
|
175
|
+
"""
|
176
|
+
legacy_map = {}
|
177
|
+
for current_field, old_field in cls.map_to(_LegacySCAliases).items():
|
178
|
+
aliases = old_field.value
|
179
|
+
if isinstance(aliases, str):
|
180
|
+
aliases = [aliases]
|
181
|
+
legacy_map.update({alias: current_field for alias in aliases})
|
182
|
+
|
183
|
+
return legacy_map
|
184
|
+
|
185
|
+
|
186
|
+
class _LegacySCAliases(Enum):
|
187
|
+
"""Legacy supply curve column names.
|
188
|
+
|
189
|
+
Enum values can be either a single string or an iterable of string
|
190
|
+
values where each string value represents a previously known alias.
|
191
|
+
"""
|
192
|
+
|
193
|
+
|
11
194
|
class ModuleName(str, Enum):
|
12
195
|
"""A collection of the module names available in reV.
|
13
196
|
|
@@ -22,17 +205,17 @@ class ModuleName(str, Enum):
|
|
22
205
|
click name conversions: https://tinyurl.com/4rehbsvf
|
23
206
|
"""
|
24
207
|
|
25
|
-
BESPOKE =
|
26
|
-
COLLECT =
|
27
|
-
ECON =
|
28
|
-
GENERATION =
|
29
|
-
HYBRIDS =
|
30
|
-
MULTI_YEAR =
|
31
|
-
NRWAL =
|
32
|
-
QA_QC =
|
33
|
-
REP_PROFILES =
|
34
|
-
SUPPLY_CURVE =
|
35
|
-
SUPPLY_CURVE_AGGREGATION =
|
208
|
+
BESPOKE = "bespoke"
|
209
|
+
COLLECT = "collect"
|
210
|
+
ECON = "econ"
|
211
|
+
GENERATION = "generation"
|
212
|
+
HYBRIDS = "hybrids"
|
213
|
+
MULTI_YEAR = "multi-year"
|
214
|
+
NRWAL = "nrwal"
|
215
|
+
QA_QC = "qa-qc"
|
216
|
+
REP_PROFILES = "rep-profiles"
|
217
|
+
SUPPLY_CURVE = "supply-curve"
|
218
|
+
SUPPLY_CURVE_AGGREGATION = "supply-curve-aggregation"
|
36
219
|
|
37
220
|
def __str__(self):
|
38
221
|
return self.value
|
@@ -63,6 +246,6 @@ def log_versions(logger):
|
|
63
246
|
logger : logging.Logger
|
64
247
|
Logger object to log memory message to.
|
65
248
|
"""
|
66
|
-
logger.info(
|
249
|
+
logger.info("Running with reV version {}".format(__version__))
|
67
250
|
rex_log_versions(logger)
|
68
|
-
logger.debug(
|
251
|
+
logger.debug("- PySAM version {}".format(PySAM.__version__))
|
reV/utilities/pytest_utils.py
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""Functions used for pytests"""
|
3
3
|
|
4
|
-
import numpy as np
|
5
4
|
import os
|
5
|
+
|
6
|
+
import numpy as np
|
6
7
|
import pandas as pd
|
7
8
|
from packaging import version
|
8
9
|
from rex.outputs import Outputs as RexOutputs
|
9
10
|
|
11
|
+
from reV.utilities import ResourceMetaField
|
12
|
+
|
10
13
|
|
11
14
|
def pd_date_range(*args, **kwargs):
|
12
15
|
"""A simple wrapper on the pd.date_range() method that handles the closed
|
@@ -89,9 +92,10 @@ def make_fake_h5_chunks(td, features, shuffle=False):
|
|
89
92
|
for i, s1 in enumerate(s_slices):
|
90
93
|
for j, s2 in enumerate(s_slices):
|
91
94
|
out_file = out_pattern.format(i=i, j=j)
|
92
|
-
meta = pd.DataFrame(
|
93
|
-
|
94
|
-
|
95
|
+
meta = pd.DataFrame(
|
96
|
+
{ResourceMetaField.LATITUDE: lat[s1, s2].flatten(),
|
97
|
+
ResourceMetaField.LONGITUDE: lon[s1, s2].flatten(),
|
98
|
+
ResourceMetaField.GID: gids[s1, s2].flatten()})
|
95
99
|
write_chunk(meta=meta, times=times, data=data[s1, s2],
|
96
100
|
features=features, out_file=out_file)
|
97
101
|
|
reV/version.py
CHANGED
File without changes
|
File without changes
|
File without changes
|