foxes 0.5.1__py3-none-any.whl → 0.5.2__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.

Potentially problematic release.


This version of foxes might be problematic. Click here for more details.

Files changed (66) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +41 -46
  3. foxes/algorithms/downwind/models/point_wakes_calc.py +4 -9
  4. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -22
  5. foxes/core/algorithm.py +1 -1
  6. foxes/core/data_calc_model.py +26 -2
  7. foxes/core/partial_wakes_model.py +1 -1
  8. foxes/core/rotor_model.py +36 -2
  9. foxes/core/turbine_model.py +36 -0
  10. foxes/core/turbine_type.py +35 -1
  11. foxes/core/wake_frame.py +39 -3
  12. foxes/core/wake_model.py +36 -0
  13. foxes/models/model_book.py +132 -85
  14. foxes/models/turbine_models/rotor_centre_calc.py +1 -2
  15. foxes/models/turbine_types/CpCt_file.py +13 -3
  16. foxes/models/turbine_types/CpCt_from_two.py +14 -4
  17. foxes/models/vertical_profiles/abl_log_neutral_ws.py +32 -5
  18. foxes/models/vertical_profiles/abl_log_stable_ws.py +32 -4
  19. foxes/models/vertical_profiles/abl_log_unstable_ws.py +32 -4
  20. foxes/models/vertical_profiles/abl_log_ws.py +50 -18
  21. foxes/models/wake_frames/yawed_wakes.py +15 -9
  22. foxes/models/wake_models/induction/__init__.py +1 -1
  23. foxes/models/wake_models/induction/rankine_half_body.py +33 -7
  24. foxes/models/wake_models/ti/crespo_hernandez.py +6 -1
  25. foxes/models/wake_models/ti/iec_ti.py +5 -3
  26. foxes/models/wake_models/wind/__init__.py +2 -2
  27. foxes/models/wake_models/wind/{bastankhah.py → bastankhah14.py} +11 -14
  28. foxes/models/wake_models/wind/{porte_agel.py → bastankhah16.py} +24 -16
  29. foxes/models/wake_models/wind/turbopark.py +11 -22
  30. foxes/models/wake_superpositions/__init__.py +9 -5
  31. foxes/models/wake_superpositions/ti_linear.py +134 -0
  32. foxes/models/wake_superpositions/ti_max.py +134 -0
  33. foxes/models/wake_superpositions/{ti_superp.py → ti_pow.py} +15 -57
  34. foxes/models/wake_superpositions/ti_quadratic.py +134 -0
  35. foxes/models/wake_superpositions/ws_linear.py +170 -0
  36. foxes/models/wake_superpositions/ws_max.py +173 -0
  37. foxes/models/wake_superpositions/ws_pow.py +175 -0
  38. foxes/models/wake_superpositions/{product.py → ws_product.py} +43 -22
  39. foxes/models/wake_superpositions/ws_quadratic.py +170 -0
  40. foxes/output/__init__.py +4 -0
  41. foxes/output/calc_points.py +143 -0
  42. foxes/output/flow_plots_2d/__init__.py +1 -0
  43. foxes/output/flow_plots_2d/common.py +104 -1
  44. foxes/output/flow_plots_2d/flow_plots.py +237 -569
  45. foxes/output/flow_plots_2d/get_fig.py +183 -0
  46. foxes/output/flow_plots_2d/seq_flow_ani_plugin.py +0 -1
  47. foxes/output/grids.py +705 -0
  48. foxes/output/output.py +58 -11
  49. foxes/output/results_writer.py +101 -17
  50. foxes/output/round.py +10 -0
  51. foxes/output/slice_data.py +900 -0
  52. foxes/utils/__init__.py +5 -3
  53. foxes/utils/exec_python.py +56 -0
  54. foxes/utils/geopandas_utils.py +294 -0
  55. foxes/utils/pandas_utils.py +175 -0
  56. foxes/utils/plotly_utils.py +19 -0
  57. foxes/utils/xarray_utils.py +38 -0
  58. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/METADATA +1 -1
  59. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/RECORD +63 -49
  60. foxes/models/wake_superpositions/linear.py +0 -242
  61. foxes/models/wake_superpositions/max.py +0 -258
  62. foxes/models/wake_superpositions/quadratic.py +0 -252
  63. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/LICENSE +0 -0
  64. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/WHEEL +0 -0
  65. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/top_level.txt +0 -0
  66. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/zip-safe +0 -0
foxes/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.1
1
+ 0.5.2
@@ -8,28 +8,28 @@ from . import models as mdls
8
8
 
9
9
  class Downwind(Algorithm):
10
10
  """
11
- The downwind algorithm.
12
-
13
- The turbines are evaluated once, in the order
14
- that is calculated by the provided `TurbineOrder`
15
- object.
16
-
17
- Attributes
18
- ----------
19
- states: foxes.core.States
20
- The ambient states
21
- wake_models: list of foxes.core.WakeModel
22
- The wake models, applied to all turbines
23
- rotor_model: foxes.core.RotorModel
24
- The rotor model, for all turbines
25
- wake_frame: foxes.core.WakeFrame
26
- The wake frame
27
- partial_wakes_model: foxes.core.PartialWakesModel
28
- The partial wakes model
29
- farm_controller: foxes.core.FarmController
30
- The farm controller
31
- n_states: int
32
- The number of states
11
+ The downwind algorithm.
12
+
13
+ The turbines are evaluated once, in the order
14
+ that is calculated by the provided `TurbineOrder`
15
+ object.
16
+
17
+ Attributes
18
+ ----------
19
+ states: foxes.core.States
20
+ The ambient states
21
+ wake_models: list of foxes.core.WakeModel
22
+ The wake models, applied to all turbines
23
+ rotor_model: foxes.core.RotorModel
24
+ The rotor model, for all turbines
25
+ wake_frame: foxes.core.WakeFrame
26
+ The wake frame
27
+ partial_wakes_model: foxes.core.PartialWakesModel
28
+ The partial wakes model
29
+ farm_controller: foxes.core.FarmController
30
+ The farm controller
31
+ n_states: int
32
+ The number of states
33
33
 
34
34
  :group: algorithms.downwind
35
35
 
@@ -307,6 +307,7 @@ class Downwind(Algorithm):
307
307
  finalize=True,
308
308
  ambient=False,
309
309
  chunked_results=False,
310
+ **kwargs,
310
311
  ):
311
312
  """
312
313
  Calculate farm data.
@@ -325,6 +326,8 @@ class Downwind(Algorithm):
325
326
  Flag for ambient instead of waked calculation
326
327
  chunked_results: bool
327
328
  Flag for chunked results
329
+ kwargs: dict, optional
330
+ Additional parameters for run_calculation
328
331
 
329
332
  Returns
330
333
  -------
@@ -358,7 +361,12 @@ class Downwind(Algorithm):
358
361
  self.print(f"\nChunks: {self.chunks}\n")
359
362
 
360
363
  # run main calculation:
361
- farm_results = self._run_farm_calc(mlist, models_data, parameters=calc_pars)
364
+ farm_results = self._run_farm_calc(
365
+ mlist,
366
+ models_data,
367
+ parameters=calc_pars,
368
+ **kwargs,
369
+ )
362
370
  del models_data
363
371
 
364
372
  # finalize models:
@@ -378,8 +386,6 @@ class Downwind(Algorithm):
378
386
 
379
387
  def _collect_point_models(
380
388
  self,
381
- vars=None,
382
- vars_to_amb=None,
383
389
  calc_parameters={},
384
390
  point_models=None,
385
391
  ambient=False,
@@ -420,16 +426,14 @@ class Downwind(Algorithm):
420
426
 
421
427
  # 2) transfer ambient results:
422
428
  mlist.models.append(
423
- self.get_model("SetAmbPointResults")(
424
- point_vars=vars, vars_to_amb=vars_to_amb
425
- )
429
+ self.get_model("SetAmbPointResults")()
426
430
  )
427
431
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
428
432
 
429
433
  # 3) calc wake effects:
430
434
  if not ambient:
431
435
  mlist.models.append(
432
- self.get_model("PointWakesCalculation")(vars, emodels, emodels_cpars)
436
+ self.get_model("PointWakesCalculation")(emodels, emodels_cpars)
433
437
  )
434
438
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
435
439
 
@@ -439,8 +443,6 @@ class Downwind(Algorithm):
439
443
  self,
440
444
  farm_results,
441
445
  points,
442
- vars=None,
443
- vars_to_amb=None,
444
446
  point_models=None,
445
447
  calc_parameters={},
446
448
  persist_mdata=True,
@@ -448,6 +450,7 @@ class Downwind(Algorithm):
448
450
  finalize=True,
449
451
  ambient=False,
450
452
  chunked_results=False,
453
+ **kwargs,
451
454
  ):
452
455
  """
453
456
  Calculate data at a given set of points.
@@ -459,12 +462,6 @@ class Downwind(Algorithm):
459
462
  dimensions (state, turbine)
460
463
  points: numpy.ndarray
461
464
  The points of interest, shape: (n_states, n_points, 3)
462
- vars: list of str, optional
463
- The variables that should be kept in the output,
464
- or `None` for all
465
- vars_to_amb: list of str, optional
466
- Variables for which ambient variables should
467
- be stored. None means all.
468
465
  point_models: str or foxes.core.PointDataModel
469
466
  Additional point models to be executed
470
467
  calc_parameters: dict
@@ -482,6 +479,8 @@ class Downwind(Algorithm):
482
479
  Flag for ambient instead of waked calculation
483
480
  chunked_results: bool
484
481
  Flag for chunked results
482
+ kwargs: dict, optional
483
+ Additional parameters for run_calculation
485
484
 
486
485
  Returns
487
486
  -------
@@ -503,7 +502,7 @@ class Downwind(Algorithm):
503
502
 
504
503
  # collect models and initialize:
505
504
  mlist, calc_pars = self._collect_point_models(
506
- vars, vars_to_amb, calc_parameters, point_models, ambient
505
+ calc_parameters, point_models, ambient
507
506
  )
508
507
 
509
508
  # initialize models:
@@ -537,25 +536,21 @@ class Downwind(Algorithm):
537
536
 
538
537
  # check vars:
539
538
  ovars = mlist.output_point_vars(self)
540
- if vars is None:
541
- vars = ovars
542
- for v in vars:
543
- if v not in ovars:
544
- raise KeyError(f"Variable '{v}' not in output point vars: {ovars}")
545
- self.print(f"\nOutput point variables:", ", ".join(vars))
539
+ self.print(f"\nOutput point variables:", ", ".join(ovars))
546
540
  self.print(f"\nChunks: {self.chunks}\n")
547
541
 
548
542
  # calculate:
549
543
  self.print(
550
- f"Calculating {len(vars)} variables at {points.shape[1]} points in {self.n_states} states"
544
+ f"Calculating {len(ovars)} variables at {points.shape[1]} points in {self.n_states} states"
551
545
  )
552
546
  point_results = mlist.run_calculation(
553
547
  self,
554
548
  models_data,
555
549
  farm_results,
556
550
  point_data,
557
- out_vars=vars,
551
+ out_vars=ovars,
558
552
  parameters=calc_pars,
553
+ **kwargs,
559
554
  )
560
555
 
561
556
  del models_data, farm_results, point_data
@@ -9,7 +9,7 @@ class PointWakesCalculation(PointDataModel):
9
9
 
10
10
  Attributes
11
11
  ----------
12
- point_vars: list of str
12
+ pvars: list of str
13
13
  The variables of interest
14
14
  emodels: foxes.core.PointDataModelList
15
15
  The extra evaluation models
@@ -23,15 +23,13 @@ class PointWakesCalculation(PointDataModel):
23
23
  """
24
24
 
25
25
  def __init__(
26
- self, point_vars=None, emodels=None, emodels_cpars=None, wake_models=None
26
+ self, emodels=None, emodels_cpars=None, wake_models=None
27
27
  ):
28
28
  """
29
29
  Constructor.
30
30
 
31
31
  Parameters
32
32
  ----------
33
- point_vars: list of str, optional
34
- The variables of interest
35
33
  emodels: foxes.core.PointDataModelList, optional
36
34
  The extra evaluation models
37
35
  emodels_cpars: list of dict, optional
@@ -41,7 +39,7 @@ class PointWakesCalculation(PointDataModel):
41
39
 
42
40
  """
43
41
  super().__init__()
44
- self._pvars = point_vars
42
+ self.pvars = None
45
43
  self.emodels = emodels
46
44
  self.emodels_cpars = emodels_cpars
47
45
  self.wake_models = wake_models
@@ -71,9 +69,7 @@ class PointWakesCalculation(PointDataModel):
71
69
 
72
70
  """
73
71
  super().initialize(algo, verbosity)
74
- self.pvars = (
75
- algo.states.output_point_vars(algo) if self._pvars is None else self._pvars
76
- )
72
+ self.pvars = algo.states.output_point_vars(algo)
77
73
 
78
74
  def output_point_vars(self, algo):
79
75
  """
@@ -194,7 +190,6 @@ class PointWakesCalculation(PointDataModel):
194
190
  amb_res = {v: pdata[FV.var2amb[v]] for v in wdeltas if v in FV.var2amb}
195
191
  for w in wmodels:
196
192
  w.finalize_wake_deltas(algo, mdata, fdata, pdata, amb_res, wdeltas)
197
- import numpy as np
198
193
 
199
194
  for v in self.pvars:
200
195
  if v in wdeltas:
@@ -17,21 +17,13 @@ class SetAmbPointResults(PointDataModel):
17
17
 
18
18
  """
19
19
 
20
- def __init__(self, point_vars=None, vars_to_amb=None):
20
+ def __init__(self):
21
21
  """
22
22
  Constructor.
23
-
24
- Parameters
25
- ----------
26
- point_vars: list of str, optional
27
- The point variables to be treated
28
- vars_to_amb: list of str, optional
29
- The variables to be copied to output
30
-
31
23
  """
32
24
  super().__init__()
33
- self._pvars = point_vars
34
- self._vars = vars_to_amb
25
+ self.pvars = None
26
+ self.vars = None
35
27
 
36
28
  def initialize(self, algo, verbosity=0):
37
29
  """
@@ -45,14 +37,8 @@ class SetAmbPointResults(PointDataModel):
45
37
  The verbosity level, 0 = silent
46
38
 
47
39
  """
48
- self.pvars = (
49
- algo.states.output_point_vars(algo) if self._pvars is None else self._pvars
50
- )
51
- self.vars = (
52
- [v for v in self.pvars if v in FV.var2amb]
53
- if self._vars is None
54
- else self._vars
55
- )
40
+ self.pvars = algo.states.output_point_vars(algo)
41
+ self.vars = [v for v in self.pvars if v in FV.var2amb]
56
42
  super().initialize(algo, verbosity)
57
43
 
58
44
  def output_point_vars(self, algo):
@@ -70,9 +56,6 @@ class SetAmbPointResults(PointDataModel):
70
56
  The output variable names
71
57
 
72
58
  """
73
- for v in algo.states.output_point_vars(algo):
74
- if v not in self.vars and v in FV.var2amb:
75
- self.vars.append(v)
76
59
  return [FV.var2amb[v] for v in self.vars]
77
60
 
78
61
  def calculate(self, algo, mdata, fdata, pdata):
foxes/core/algorithm.py CHANGED
@@ -374,7 +374,7 @@ class Algorithm(Model):
374
374
  or points.shape[2] != 3
375
375
  ):
376
376
  raise ValueError(
377
- f"points have wrong dimensions, expecting ({self.n_states}, n_points, 3), got {points.shape}"
377
+ f"points have wrong dimensions, expecting ({self.n_states}, {points.shape[1]}, 3), got {points.shape}"
378
378
  )
379
379
  idata["data_vars"][FC.POINTS] = ((FC.STATE, FC.POINT, FC.XYH), points)
380
380
 
@@ -174,6 +174,8 @@ class DataCalcModel(Model):
174
174
  loop_dims,
175
175
  out_core_vars,
176
176
  initial_results=None,
177
+ sel=None,
178
+ isel=None,
177
179
  **calc_pars,
178
180
  ):
179
181
  """
@@ -196,10 +198,14 @@ class DataCalcModel(Model):
196
198
  out_core_vars: list of str
197
199
  The core dimensions of the output data, use
198
200
  `FC.VARS` for variables dimension (required)
199
- calc_pars: dict, optional
200
- Additional arguments for the `calculate` function
201
201
  initial_results: xarray.Dataset, optional
202
202
  Initial results
203
+ sel: dict, optional
204
+ Selection of loop_dim variable subset values
205
+ isel: dict, optional
206
+ Selection of loop_dim variable subset index values
207
+ calc_pars: dict, optional
208
+ Additional arguments for the `calculate` function
203
209
 
204
210
  Returns
205
211
  -------
@@ -255,6 +261,24 @@ class DataCalcModel(Model):
255
261
  evars.append(c)
256
262
 
257
263
  dvars.append(list(ds.keys()) + list(ds.coords.keys()))
264
+
265
+ # subset selection:
266
+ if sel is not None:
267
+ nldata = []
268
+ for ds in ldata:
269
+ s = {k: v for k, v in sel.items() if k in ds.coords}
270
+ if len(s):
271
+ nldata.append(ds.sel(s))
272
+ ldata = nldata
273
+ del nldata
274
+ if isel is not None:
275
+ nldata = []
276
+ for ds in ldata:
277
+ s = {k: v for k, v in isel.items() if k in ds.coords}
278
+ if len(s):
279
+ nldata.append(ds.isel(s))
280
+ ldata = nldata
281
+ del nldata
258
282
 
259
283
  # setup dask options:
260
284
  dargs = dict(output_sizes={FC.VARS: len(out_vars)})
@@ -1,8 +1,8 @@
1
1
  from abc import abstractmethod
2
2
 
3
- from .model import Model
4
3
  from foxes.utils import all_subclasses
5
4
 
5
+ from .model import Model
6
6
 
7
7
  class PartialWakesModel(Model):
8
8
  """
foxes/core/rotor_model.py CHANGED
@@ -4,9 +4,9 @@ from abc import abstractmethod
4
4
  import foxes.variables as FV
5
5
  import foxes.constants as FC
6
6
  from .farm_data_model import FarmDataModel
7
- from .data import Data
8
- from foxes.utils import wd2uv, uv2wd
7
+ from foxes.utils import wd2uv, uv2wd, all_subclasses
9
8
 
9
+ from .data import Data
10
10
 
11
11
  class RotorModel(FarmDataModel):
12
12
  """
@@ -412,3 +412,37 @@ class RotorModel(FarmDataModel):
412
412
  )
413
413
 
414
414
  return {v: fdata[v] for v in self.output_farm_vars(algo)}
415
+
416
+ @classmethod
417
+ def new(cls, rmodel_type, *args, **kwargs):
418
+ """
419
+ Run-time rotor model factory.
420
+
421
+ Parameters
422
+ ----------
423
+ rmodel_type: str
424
+ The selected derived class name
425
+ args: tuple, optional
426
+ Additional parameters for constructor
427
+ kwargs: dict, optional
428
+ Additional parameters for constructor
429
+
430
+ """
431
+
432
+ if rmodel_type is None:
433
+ return None
434
+
435
+ allc = all_subclasses(cls)
436
+ found = rmodel_type in [scls.__name__ for scls in allc]
437
+
438
+ if found:
439
+ for scls in allc:
440
+ if scls.__name__ == rmodel_type:
441
+ return scls(*args, **kwargs)
442
+
443
+ else:
444
+ estr = "Rotor model type '{}' is not defined, available types are \n {}".format(
445
+ rmodel_type, sorted([i.__name__ for i in allc])
446
+ )
447
+ raise KeyError(estr)
448
+
@@ -1,5 +1,7 @@
1
1
  from abc import abstractmethod
2
2
 
3
+ from foxes.utils import all_subclasses
4
+
3
5
  from .farm_data_model import FarmDataModel
4
6
 
5
7
 
@@ -42,3 +44,37 @@ class TurbineModel(FarmDataModel):
42
44
 
43
45
  """
44
46
  pass
47
+
48
+ @classmethod
49
+ def new(cls, tmodel_type, *args, **kwargs):
50
+ """
51
+ Run-time turbine model factory.
52
+
53
+ Parameters
54
+ ----------
55
+ tmodel_type: str
56
+ The selected derived class name
57
+ args: tuple, optional
58
+ Additional parameters for constructor
59
+ kwargs: dict, optional
60
+ Additional parameters for constructor
61
+
62
+ """
63
+
64
+ if tmodel_type is None:
65
+ return None
66
+
67
+ allc = all_subclasses(cls)
68
+ found = tmodel_type in [scls.__name__ for scls in allc]
69
+
70
+ if found:
71
+ for scls in allc:
72
+ if scls.__name__ == tmodel_type:
73
+ return scls(*args, **kwargs)
74
+
75
+ else:
76
+ estr = "Turbine model type '{}' is not defined, available types are \n {}".format(
77
+ tmodel_type, sorted([i.__name__ for i in allc])
78
+ )
79
+ raise KeyError(estr)
80
+
@@ -1,6 +1,7 @@
1
- from .turbine_model import TurbineModel
2
1
  import foxes.constants as FC
2
+ from foxes.utils import all_subclasses
3
3
 
4
+ from .turbine_model import TurbineModel
4
5
 
5
6
  class TurbineType(TurbineModel):
6
7
  """
@@ -57,3 +58,36 @@ class TurbineType(TurbineModel):
57
58
  raise KeyError(
58
59
  f"Turbine type '{self.name}': Unkown P_unit '{P_unit}', expecting {list(FC.P_UNITS.keys())}"
59
60
  )
61
+
62
+ @classmethod
63
+ def new(cls, ttype_type, *args, **kwargs):
64
+ """
65
+ Run-time turbine type factory.
66
+
67
+ Parameters
68
+ ----------
69
+ ttype_type: str
70
+ The selected derived class name
71
+ args: tuple, optional
72
+ Additional parameters for constructor
73
+ kwargs: dict, optional
74
+ Additional parameters for constructor
75
+
76
+ """
77
+
78
+ if ttype_type is None:
79
+ return None
80
+
81
+ allc = all_subclasses(cls)
82
+ found = ttype_type in [scls.__name__ for scls in allc]
83
+
84
+ if found:
85
+ for scls in allc:
86
+ if scls.__name__ == ttype_type:
87
+ return scls(*args, **kwargs)
88
+
89
+ else:
90
+ estr = "Turbine type class '{}' is not defined, available types are \n {}".format(
91
+ ttype_type, sorted([i.__name__ for i in allc])
92
+ )
93
+ raise KeyError(estr)
foxes/core/wake_frame.py CHANGED
@@ -2,11 +2,13 @@ from abc import abstractmethod
2
2
  import numpy as np
3
3
  from scipy.interpolate import interpn
4
4
 
5
- from .data import Data
6
- from .model import Model
5
+ from foxes.utils import all_subclasses
7
6
  import foxes.constants as FC
8
7
  import foxes.variables as FV
9
8
 
9
+ from .data import Data
10
+ from .model import Model
11
+
10
12
 
11
13
  class WakeFrame(Model):
12
14
  """
@@ -234,7 +236,7 @@ class WakeFrame(Model):
234
236
  # calc wakes:
235
237
  if not ambient:
236
238
  wcalc = algo.get_model("PointWakesCalculation")(
237
- vrs, wake_models=wake_models
239
+ wake_models=wake_models
238
240
  )
239
241
  wcalc.initialize(algo, verbosity=0)
240
242
  wsrc = states_source_turbine if self_wake else None
@@ -263,3 +265,37 @@ class WakeFrame(Model):
263
265
  )
264
266
 
265
267
  return results.reshape(n_states, n_points, n_vars)
268
+
269
+ @classmethod
270
+ def new(cls, wframe_type, *args, **kwargs):
271
+ """
272
+ Run-time wake frame factory.
273
+
274
+ Parameters
275
+ ----------
276
+ wframe_type: str
277
+ The selected derived class name
278
+ args: tuple, optional
279
+ Additional parameters for constructor
280
+ kwargs: dict, optional
281
+ Additional parameters for constructor
282
+
283
+ """
284
+
285
+ if wframe_type is None:
286
+ return None
287
+
288
+ allc = all_subclasses(cls)
289
+ found = wframe_type in [scls.__name__ for scls in allc]
290
+
291
+ if found:
292
+ for scls in allc:
293
+ if scls.__name__ == wframe_type:
294
+ return scls(*args, **kwargs)
295
+
296
+ else:
297
+ estr = "Wake frame type '{}' is not defined, available types are \n {}".format(
298
+ wframe_type, sorted([i.__name__ for i in allc])
299
+ )
300
+ raise KeyError(estr)
301
+
foxes/core/wake_model.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from abc import abstractmethod
2
2
 
3
+ from foxes.utils import all_subclasses
4
+
3
5
  from .model import Model
4
6
 
5
7
 
@@ -115,3 +117,37 @@ class WakeModel(Model):
115
117
 
116
118
  """
117
119
  pass
120
+
121
+ @classmethod
122
+ def new(cls, wmodel_type, *args, **kwargs):
123
+ """
124
+ Run-time wake model factory.
125
+
126
+ Parameters
127
+ ----------
128
+ wmodel_type: str
129
+ The selected derived class name
130
+ args: tuple, optional
131
+ Additional parameters for constructor
132
+ kwargs: dict, optional
133
+ Additional parameters for constructor
134
+
135
+ """
136
+
137
+ if wmodel_type is None:
138
+ return None
139
+
140
+ allc = all_subclasses(cls)
141
+ found = wmodel_type in [scls.__name__ for scls in allc]
142
+
143
+ if found:
144
+ for scls in allc:
145
+ if scls.__name__ == wmodel_type:
146
+ return scls(*args, **kwargs)
147
+
148
+ else:
149
+ estr = "Wake model type '{}' is not defined, available types are \n {}".format(
150
+ wmodel_type, sorted([i.__name__ for i in allc])
151
+ )
152
+ raise KeyError(estr)
153
+