NREL-reV 0.8.7__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.
Files changed (43) hide show
  1. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/METADATA +13 -10
  2. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/RECORD +43 -43
  3. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/WHEEL +1 -1
  4. reV/SAM/SAM.py +217 -133
  5. reV/SAM/econ.py +18 -14
  6. reV/SAM/generation.py +611 -422
  7. reV/SAM/windbos.py +93 -79
  8. reV/bespoke/bespoke.py +681 -377
  9. reV/bespoke/cli_bespoke.py +2 -0
  10. reV/bespoke/place_turbines.py +187 -43
  11. reV/config/output_request.py +2 -1
  12. reV/config/project_points.py +218 -140
  13. reV/econ/econ.py +166 -114
  14. reV/econ/economies_of_scale.py +91 -45
  15. reV/generation/base.py +331 -184
  16. reV/generation/generation.py +326 -200
  17. reV/generation/output_attributes/lcoe_fcr_inputs.json +38 -3
  18. reV/handlers/__init__.py +0 -1
  19. reV/handlers/exclusions.py +16 -15
  20. reV/handlers/multi_year.py +57 -26
  21. reV/handlers/outputs.py +6 -5
  22. reV/handlers/transmission.py +44 -27
  23. reV/hybrids/hybrid_methods.py +30 -30
  24. reV/hybrids/hybrids.py +305 -189
  25. reV/nrwal/nrwal.py +262 -168
  26. reV/qa_qc/cli_qa_qc.py +14 -10
  27. reV/qa_qc/qa_qc.py +217 -119
  28. reV/qa_qc/summary.py +228 -146
  29. reV/rep_profiles/rep_profiles.py +349 -230
  30. reV/supply_curve/aggregation.py +349 -188
  31. reV/supply_curve/competitive_wind_farms.py +90 -48
  32. reV/supply_curve/exclusions.py +138 -85
  33. reV/supply_curve/extent.py +75 -50
  34. reV/supply_curve/points.py +735 -390
  35. reV/supply_curve/sc_aggregation.py +357 -248
  36. reV/supply_curve/supply_curve.py +604 -347
  37. reV/supply_curve/tech_mapping.py +144 -82
  38. reV/utilities/__init__.py +274 -16
  39. reV/utilities/pytest_utils.py +8 -4
  40. reV/version.py +1 -1
  41. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/LICENSE +0 -0
  42. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/entry_points.txt +0 -0
  43. {NREL_reV-0.8.7.dist-info → NREL_reV-0.9.0.dist-info}/top_level.txt +0 -0
@@ -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 scipy.spatial import cKDTree
13
+ from concurrent.futures import as_completed
14
+ from math import ceil
18
15
  from warnings import warn
19
16
 
20
- from reV.supply_curve.extent import SupplyCurveExtent
21
- from reV.utilities.exceptions import FileInputWarning, FileInputError
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__(self, excl_fpath, res_fpath, sc_resolution=2560,
34
- dist_margin=1.05):
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
- self._build_tree(res_fpath, dist_margin=dist_margin)
55
+ self._tree, self._dist_thresh = self._build_tree(
56
+ res_fpath, dist_margin=dist_margin
57
+ )
56
58
 
57
- with SupplyCurveExtent(self._excl_fpath,
58
- resolution=sc_resolution) as sc:
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('Initialized TechMapping object with {} calc chunks '
68
- 'for {} tech exclusion points'
69
- .format(len(self._gids), self._n_excl))
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(lat_lons, tree=tree,
114
- margin=dist_margin)
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(gid, sc_row_indices, sc_col_indices, excl_row_slices,
139
- excl_col_slices):
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=('latitude', 'longitude')):
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, 'r') as f:
221
+ with h5py.File(excl_fpath, "r") as f:
214
222
  for gid in gids:
215
- row_slice, col_slice = cls._get_excl_slices(gid,
216
- sc_row_indices,
217
- sc_col_indices,
218
- excl_row_slices,
219
- excl_col_slices)
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 = ('Could not unpack coordinates for gid {} with '
226
- 'row/col slice {}/{}. Received the following '
227
- 'error:\n{}'.format(gid, row_slice, col_slice, e))
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(cls, gids, excl_fpath, sc_row_indices,
237
- sc_col_indices, excl_row_slices, excl_col_slices,
238
- tree, dist_thresh):
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('Getting tech map coordinates for chunks {} through {}'
276
- .format(gids[0], gids[-1]))
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(excl_fpath, gids, sc_row_indices,
279
- sc_col_indices, excl_row_slices,
280
- excl_col_slices)
281
-
282
- logger.debug('Running tech mapping for chunks {} through {}'
283
- .format(gids[0], gids[-1]))
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(excl_fpath, dset, indices, distance_threshold=None,
293
- res_fpath=None, chunks=(128, 128)):
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, 'a') as f:
355
+ with h5py.File(excl_fpath, "a") as f:
319
356
  if dset in list(f):
320
- wmsg = ('TechMap results dataset "{}" is being replaced '
321
- 'in pre-existing Exclusions TechMapping file "{}"'
322
- .format(dset, excl_fpath))
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(dset, shape=shape, dtype=indices.dtype,
328
- data=indices, chunks=chunks)
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['distance_threshold'] = distance_threshold
376
+ f[dset].attrs["distance_threshold"] = distance_threshold
332
377
 
333
378
  if res_fpath:
334
- f[dset].attrs['src_res_fpath'] = res_fpath
379
+ f[dset].attrs["src_res_fpath"] = res_fpath
335
380
 
336
- logger.info('Successfully saved tech map "{}" to {}'
337
- .format(dset, excl_fpath))
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 'latitude' not in f or 'longitude' not in f:
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, ), dtype=np.int32)
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__, 'reV']
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[exe.submit(self.map_resource_gids,
385
- gid_set,
386
- self._excl_fpath,
387
- self._sc_row_indices,
388
- self._sc_col_indices,
389
- self._excl_row_slices,
390
- self._excl_col_slices,
391
- self._tree,
392
- self.distance_threshold)] = i
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('Parallel TechMapping futures collected: '
398
- '{} out of {}'
399
- .format(n_finished, len(futures)))
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(cls, excl_fpath, res_fpath, dset=None, sc_resolution=2560,
420
- dist_margin=1.05, max_workers=None, points_per_worker=10):
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(max_workers=max_workers,
457
- points_per_worker=points_per_worker)
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(excl_fpath, dset, indices,
461
- distance_threshold=mapper.distance_threshold,
462
- res_fpath=res_fpath)
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,271 @@
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
+ This is a collection of known supply curve fields that reV outputs
116
+ across aggregation, supply curve, and bespoke outputs.
117
+
118
+ Not all of these columns are guaranteed in every supply-curve like
119
+ output (e.g. "convex_hull_area" is a bespoke-only output).
120
+ """
121
+
122
+ SC_GID = "sc_gid"
123
+ LATITUDE = "latitude"
124
+ LONGITUDE = "longitude"
125
+ COUNTRY = "country"
126
+ STATE = "state"
127
+ COUNTY = "county"
128
+ ELEVATION = "elevation_m"
129
+ TIMEZONE = "timezone"
130
+ SC_POINT_GID = "sc_point_gid"
131
+ SC_ROW_IND = "sc_row_ind"
132
+ SC_COL_IND = "sc_col_ind"
133
+ SOURCE_GIDS = "source_gids"
134
+ RES_GIDS = "res_gids"
135
+ GEN_GIDS = "gen_gids"
136
+ GID_COUNTS = "gid_counts"
137
+ N_GIDS = "n_gids"
138
+ MEAN_RES = "resource"
139
+ MEAN_CF_AC = "capacity_factor_ac"
140
+ MEAN_CF_DC = "capacity_factor_dc"
141
+ MEAN_LCOE = "lcoe_site_usd_per_mwh"
142
+ CAPACITY_AC_MW = "capacity_ac_mw"
143
+ CAPACITY_DC_MW = "capacity_dc_mw"
144
+ OFFSHORE = "offshore"
145
+ AREA_SQ_KM = "area_developable_sq_km"
146
+ MEAN_FRICTION = "friction_site"
147
+ MEAN_LCOE_FRICTION = "lcoe_friction_usd_per_mwh"
148
+ RAW_LCOE = "lcoe_raw_usd_per_mwh"
149
+ EOS_MULT = "multiplier_cc_eos"
150
+ REG_MULT = "multiplier_cc_regional"
151
+ SC_POINT_ANNUAL_ENERGY_MW = "annual_energy_site_mwh"
152
+ COST_BASE_OCC_USD_PER_AC_MW = "cost_base_occ_usd_per_ac_mw"
153
+ COST_SITE_OCC_USD_PER_AC_MW = "cost_site_occ_usd_per_ac_mw"
154
+ COST_BASE_FOC_USD_PER_AC_MW = "cost_base_foc_usd_per_ac_mw"
155
+ COST_SITE_FOC_USD_PER_AC_MW = "cost_site_foc_usd_per_ac_mw"
156
+ COST_BASE_VOC_USD_PER_AC_MW = "cost_base_voc_usd_per_ac_mw"
157
+ COST_SITE_VOC_USD_PER_AC_MW = "cost_site_voc_usd_per_ac_mw"
158
+ FIXED_CHARGE_RATE = "fixed_charge_rate"
159
+
160
+ # Bespoke outputs
161
+ POSSIBLE_X_COORDS = "possible_x_coords"
162
+ POSSIBLE_Y_COORDS = "possible_y_coords"
163
+ TURBINE_X_COORDS = "turbine_x_coords"
164
+ TURBINE_Y_COORDS = "turbine_y_coords"
165
+ N_TURBINES = "n_turbines"
166
+ INCLUDED_AREA = "area_included_sq_km"
167
+ INCLUDED_AREA_CAPACITY_DENSITY = (
168
+ "capacity_density_included_area_mw_per_km2"
169
+ )
170
+ CONVEX_HULL_AREA = "area_convex_hull_sq_km"
171
+ CONVEX_HULL_CAPACITY_DENSITY = "capacity_density_convex_hull_mw_per_km2"
172
+ FULL_CELL_CAPACITY_DENSITY = "capacity_density_full_cell_mw_per_km2"
173
+ BESPOKE_AEP = "optimized_plant_aep"
174
+ BESPOKE_OBJECTIVE = "optimized_plant_objective"
175
+ BESPOKE_CAPITAL_COST = "optimized_plant_capital_cost"
176
+ BESPOKE_FIXED_OPERATING_COST = "optimized_plant_fixed_operating_cost"
177
+ BESPOKE_VARIABLE_OPERATING_COST = "optimized_plant_variable_operating_cost"
178
+ BESPOKE_BALANCE_OF_SYSTEM_COST = "optimized_plant_balance_of_system_cost"
179
+
180
+ # Transmission outputs
181
+ TRANS_GID = "trans_gid"
182
+ TRANS_TYPE = "trans_type"
183
+ TOTAL_LCOE_FRICTION = "lcoe_total_friction_usd_per_mwh"
184
+ TRANS_CAPACITY = "trans_capacity"
185
+ DIST_SPUR_KM = "dist_spur_km"
186
+ DIST_EXPORT_KM = "dist_export_km"
187
+ REINFORCEMENT_DIST_KM = "dist_reinforcement_km"
188
+ TIE_LINE_COST_PER_MW = "cost_spur_usd_per_mw"
189
+ CONNECTION_COST_PER_MW = "cost_poi_usd_per_mw"
190
+ EXPORT_COST_PER_MW = "cost_export_usd_per_mw"
191
+ REINFORCEMENT_COST_PER_MW = "cost_reinforcement_usd_per_mw"
192
+ TOTAL_TRANS_CAP_COST_PER_MW = "cost_total_trans_usd_per_mw"
193
+ LCOT = "lcot_usd_per_mwh"
194
+ TOTAL_LCOE = "lcoe_all_in_usd_per_mwh"
195
+ N_PARALLEL_TRANS = "count_num_parallel_trans"
196
+ POI_LAT = "latitude_poi"
197
+ POI_LON = "longitude_poi"
198
+ REINFORCEMENT_POI_LAT = "latitude_reinforcement_poi"
199
+ REINFORCEMENT_POI_LON = "longitude_reinforcement_poi"
200
+
201
+ @classmethod
202
+ def map_from_legacy(cls):
203
+ """Map of legacy names to current values.
204
+
205
+ Returns
206
+ -------
207
+ dict
208
+ Dictionary that maps legacy supply curve column names to
209
+ members of this enum.
210
+ """
211
+ legacy_map = {}
212
+ for current_field, old_field in cls.map_to(_LegacySCAliases).items():
213
+ aliases = old_field.value
214
+ if isinstance(aliases, str):
215
+ aliases = [aliases]
216
+ legacy_map.update({alias: current_field for alias in aliases})
217
+
218
+ return legacy_map
219
+
220
+
221
+ class _LegacySCAliases(Enum):
222
+ """Legacy supply curve column names.
223
+
224
+ Enum values can be either a single string or an iterable of string
225
+ values where each string value represents a previously known alias.
226
+ """
227
+
228
+ ELEVATION = "elevation"
229
+ MEAN_RES = "mean_res"
230
+ MEAN_CF_AC = "mean_cf"
231
+ MEAN_LCOE = "mean_lcoe"
232
+ CAPACITY_AC_MW = "capacity"
233
+ AREA_SQ_KM = "area_sq_km"
234
+ MEAN_FRICTION = "mean_friction"
235
+ MEAN_LCOE_FRICTION = "mean_lcoe_friction"
236
+ RAW_LCOE = "raw_lcoe"
237
+ TRANS_TYPE = "category"
238
+ TRANS_CAPACITY = "avail_cap"
239
+ DIST_SPUR_KM = "dist_km"
240
+ REINFORCEMENT_DIST_KM = "reinforcement_dist_km"
241
+ TIE_LINE_COST_PER_MW = "tie_line_cost_per_mw"
242
+ CONNECTION_COST_PER_MW = "connection_cost_per_mw"
243
+ REINFORCEMENT_COST_PER_MW = "reinforcement_cost_per_mw"
244
+ TOTAL_TRANS_CAP_COST_PER_MW = "trans_cap_cost_per_mw"
245
+ LCOT = "lcot"
246
+ TOTAL_LCOE = "total_lcoe"
247
+ TOTAL_LCOE_FRICTION = "total_lcoe_friction"
248
+ N_PARALLEL_TRANS = "n_parallel_trans"
249
+ EOS_MULT = "eos_mult", "capital_cost_multiplier"
250
+ REG_MULT = "reg_mult"
251
+ SC_POINT_ANNUAL_ENERGY_MW = "sc_point_annual_energy"
252
+ POI_LAT = "poi_lat"
253
+ POI_LON = "poi_lon"
254
+ REINFORCEMENT_POI_LAT = "reinforcement_poi_lat"
255
+ REINFORCEMENT_POI_LON = "reinforcement_poi_lon"
256
+ BESPOKE_AEP = "bespoke_aep"
257
+ BESPOKE_OBJECTIVE = "bespoke_objective"
258
+ BESPOKE_CAPITAL_COST = "bespoke_capital_cost"
259
+ BESPOKE_FIXED_OPERATING_COST = "bespoke_fixed_operating_cost"
260
+ BESPOKE_VARIABLE_OPERATING_COST = "bespoke_variable_operating_cost"
261
+ BESPOKE_BALANCE_OF_SYSTEM_COST = "bespoke_balance_of_system_cost"
262
+ INCLUDED_AREA = "included_area"
263
+ INCLUDED_AREA_CAPACITY_DENSITY = "included_area_capacity_density"
264
+ CONVEX_HULL_AREA = "convex_hull_area"
265
+ CONVEX_HULL_CAPACITY_DENSITY = "convex_hull_capacity_density"
266
+ FULL_CELL_CAPACITY_DENSITY = "full_cell_capacity_density"
267
+
268
+
11
269
  class ModuleName(str, Enum):
12
270
  """A collection of the module names available in reV.
13
271
 
@@ -22,17 +280,17 @@ class ModuleName(str, Enum):
22
280
  click name conversions: https://tinyurl.com/4rehbsvf
23
281
  """
24
282
 
25
- BESPOKE = 'bespoke'
26
- COLLECT = 'collect'
27
- ECON = 'econ'
28
- GENERATION = 'generation'
29
- HYBRIDS = 'hybrids'
30
- MULTI_YEAR = 'multi-year'
31
- NRWAL = 'nrwal'
32
- QA_QC = 'qa-qc'
33
- REP_PROFILES = 'rep-profiles'
34
- SUPPLY_CURVE = 'supply-curve'
35
- SUPPLY_CURVE_AGGREGATION = 'supply-curve-aggregation'
283
+ BESPOKE = "bespoke"
284
+ COLLECT = "collect"
285
+ ECON = "econ"
286
+ GENERATION = "generation"
287
+ HYBRIDS = "hybrids"
288
+ MULTI_YEAR = "multi-year"
289
+ NRWAL = "nrwal"
290
+ QA_QC = "qa-qc"
291
+ REP_PROFILES = "rep-profiles"
292
+ SUPPLY_CURVE = "supply-curve"
293
+ SUPPLY_CURVE_AGGREGATION = "supply-curve-aggregation"
36
294
 
37
295
  def __str__(self):
38
296
  return self.value
@@ -63,6 +321,6 @@ def log_versions(logger):
63
321
  logger : logging.Logger
64
322
  Logger object to log memory message to.
65
323
  """
66
- logger.info('Running with reV version {}'.format(__version__))
324
+ logger.info("Running with reV version {}".format(__version__))
67
325
  rex_log_versions(logger)
68
- logger.debug('- PySAM version {}'.format(PySAM.__version__))
326
+ logger.debug("- PySAM version {}".format(PySAM.__version__))