foxes 0.8.2__py3-none-any.whl → 1.1.0.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 (215) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +190 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +247 -111
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
  28. foxes/algorithms/downwind/models/init_farm_data.py +2 -2
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
  33. foxes/algorithms/iterative/iterative.py +74 -34
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
  35. foxes/algorithms/iterative/models/urelax.py +3 -3
  36. foxes/algorithms/sequential/models/plugin.py +5 -5
  37. foxes/algorithms/sequential/models/seq_state.py +1 -1
  38. foxes/algorithms/sequential/sequential.py +126 -255
  39. foxes/constants.py +22 -7
  40. foxes/core/__init__.py +1 -0
  41. foxes/core/algorithm.py +632 -147
  42. foxes/core/data.py +252 -20
  43. foxes/core/data_calc_model.py +15 -291
  44. foxes/core/engine.py +640 -0
  45. foxes/core/farm_controller.py +38 -10
  46. foxes/core/farm_data_model.py +16 -1
  47. foxes/core/ground_model.py +2 -2
  48. foxes/core/model.py +249 -182
  49. foxes/core/partial_wakes_model.py +1 -1
  50. foxes/core/point_data_model.py +17 -2
  51. foxes/core/rotor_model.py +27 -21
  52. foxes/core/states.py +17 -1
  53. foxes/core/turbine_type.py +28 -0
  54. foxes/core/wake_frame.py +30 -34
  55. foxes/core/wake_model.py +5 -5
  56. foxes/core/wake_superposition.py +1 -1
  57. foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
  58. foxes/engines/__init__.py +17 -0
  59. foxes/engines/dask.py +982 -0
  60. foxes/engines/default.py +75 -0
  61. foxes/engines/futures.py +72 -0
  62. foxes/engines/mpi.py +38 -0
  63. foxes/engines/multiprocess.py +71 -0
  64. foxes/engines/numpy.py +167 -0
  65. foxes/engines/pool.py +249 -0
  66. foxes/engines/ray.py +79 -0
  67. foxes/engines/single.py +141 -0
  68. foxes/input/farm_layout/__init__.py +1 -0
  69. foxes/input/farm_layout/from_csv.py +4 -0
  70. foxes/input/farm_layout/from_json.py +2 -2
  71. foxes/input/farm_layout/grid.py +2 -2
  72. foxes/input/farm_layout/ring.py +65 -0
  73. foxes/input/farm_layout/row.py +2 -2
  74. foxes/input/states/__init__.py +7 -0
  75. foxes/input/states/create/random_abl_states.py +1 -1
  76. foxes/input/states/field_data_nc.py +158 -33
  77. foxes/input/states/multi_height.py +128 -14
  78. foxes/input/states/one_point_flow.py +577 -0
  79. foxes/input/states/scan_ws.py +74 -3
  80. foxes/input/states/single.py +1 -1
  81. foxes/input/states/slice_data_nc.py +681 -0
  82. foxes/input/states/states_table.py +204 -35
  83. foxes/input/windio/__init__.py +2 -2
  84. foxes/input/windio/get_states.py +44 -23
  85. foxes/input/windio/read_attributes.py +48 -17
  86. foxes/input/windio/read_farm.py +116 -102
  87. foxes/input/windio/read_fields.py +16 -6
  88. foxes/input/windio/read_outputs.py +71 -24
  89. foxes/input/windio/runner.py +31 -17
  90. foxes/input/windio/windio.py +41 -23
  91. foxes/models/farm_models/turbine2farm.py +1 -1
  92. foxes/models/ground_models/wake_mirror.py +10 -6
  93. foxes/models/model_book.py +58 -20
  94. foxes/models/partial_wakes/axiwake.py +3 -3
  95. foxes/models/partial_wakes/rotor_points.py +3 -3
  96. foxes/models/partial_wakes/top_hat.py +2 -2
  97. foxes/models/point_models/set_uniform_data.py +1 -1
  98. foxes/models/point_models/tke2ti.py +1 -1
  99. foxes/models/point_models/wake_deltas.py +1 -1
  100. foxes/models/rotor_models/centre.py +4 -0
  101. foxes/models/rotor_models/grid.py +24 -25
  102. foxes/models/rotor_models/levels.py +4 -5
  103. foxes/models/turbine_models/calculator.py +4 -6
  104. foxes/models/turbine_models/kTI_model.py +22 -6
  105. foxes/models/turbine_models/lookup_table.py +30 -4
  106. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  107. foxes/models/turbine_models/set_farm_vars.py +103 -34
  108. foxes/models/turbine_types/PCt_file.py +27 -3
  109. foxes/models/turbine_types/PCt_from_two.py +27 -3
  110. foxes/models/turbine_types/TBL_file.py +80 -0
  111. foxes/models/turbine_types/__init__.py +2 -0
  112. foxes/models/turbine_types/lookup.py +316 -0
  113. foxes/models/turbine_types/null_type.py +51 -1
  114. foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
  115. foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
  116. foxes/models/vertical_profiles/__init__.py +1 -1
  117. foxes/models/vertical_profiles/data_profile.py +1 -1
  118. foxes/models/wake_frames/__init__.py +1 -0
  119. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  120. foxes/models/wake_frames/farm_order.py +25 -5
  121. foxes/models/wake_frames/rotor_wd.py +6 -4
  122. foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
  123. foxes/models/wake_frames/streamlines.py +21 -22
  124. foxes/models/wake_frames/timelines.py +330 -129
  125. foxes/models/wake_frames/yawed_wakes.py +7 -4
  126. foxes/models/wake_models/dist_sliced.py +2 -4
  127. foxes/models/wake_models/induction/rankine_half_body.py +5 -5
  128. foxes/models/wake_models/induction/rathmann.py +78 -24
  129. foxes/models/wake_models/induction/self_similar.py +78 -28
  130. foxes/models/wake_models/induction/vortex_sheet.py +86 -48
  131. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  132. foxes/models/wake_models/ti/iec_ti.py +40 -21
  133. foxes/models/wake_models/top_hat.py +1 -1
  134. foxes/models/wake_models/wind/bastankhah14.py +8 -6
  135. foxes/models/wake_models/wind/bastankhah16.py +17 -16
  136. foxes/models/wake_models/wind/jensen.py +4 -3
  137. foxes/models/wake_models/wind/turbopark.py +16 -13
  138. foxes/models/wake_superpositions/ti_linear.py +1 -1
  139. foxes/models/wake_superpositions/ti_max.py +1 -1
  140. foxes/models/wake_superpositions/ti_pow.py +1 -1
  141. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  142. foxes/models/wake_superpositions/ws_linear.py +8 -7
  143. foxes/models/wake_superpositions/ws_max.py +8 -7
  144. foxes/models/wake_superpositions/ws_pow.py +8 -7
  145. foxes/models/wake_superpositions/ws_product.py +5 -5
  146. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  147. foxes/output/__init__.py +4 -1
  148. foxes/output/farm_layout.py +16 -12
  149. foxes/output/farm_results_eval.py +1 -1
  150. foxes/output/flow_plots_2d/__init__.py +0 -1
  151. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  152. foxes/output/grids.py +92 -22
  153. foxes/output/results_writer.py +2 -2
  154. foxes/output/rose_plot.py +3 -3
  155. foxes/output/seq_plugins/__init__.py +2 -0
  156. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
  157. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  158. foxes/output/slice_data.py +131 -111
  159. foxes/output/state_turbine_map.py +19 -14
  160. foxes/output/state_turbine_table.py +19 -19
  161. foxes/utils/__init__.py +1 -1
  162. foxes/utils/abl/neutral.py +2 -2
  163. foxes/utils/abl/stable.py +2 -2
  164. foxes/utils/abl/unstable.py +2 -2
  165. foxes/utils/data_book.py +1 -1
  166. foxes/utils/dev_utils.py +42 -0
  167. foxes/utils/dict.py +24 -1
  168. foxes/utils/exec_python.py +1 -1
  169. foxes/utils/factory.py +176 -53
  170. foxes/utils/geom2d/circle.py +1 -1
  171. foxes/utils/geom2d/polygon.py +1 -1
  172. foxes/utils/geopandas_utils.py +2 -2
  173. foxes/utils/load.py +2 -2
  174. foxes/utils/pandas_helpers.py +3 -2
  175. foxes/utils/wind_dir.py +0 -2
  176. foxes/utils/xarray_utils.py +24 -14
  177. foxes/variables.py +39 -2
  178. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
  179. foxes-1.1.0.2.dist-info/RECORD +309 -0
  180. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
  181. foxes-1.1.0.2.dist-info/top_level.txt +4 -0
  182. tests/0_consistency/iterative/test_iterative.py +92 -0
  183. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  184. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  185. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  186. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  187. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  188. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  189. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  190. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  191. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  192. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  193. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  194. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  195. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  196. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  197. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  198. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  199. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  200. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  201. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  202. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  203. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  204. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  205. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  206. tests/3_examples/test_examples.py +34 -0
  207. foxes/VERSION +0 -1
  208. foxes/output/flow_plots_2d.py +0 -0
  209. foxes/utils/geopandas_helpers.py +0 -294
  210. foxes/utils/runners/__init__.py +0 -1
  211. foxes/utils/runners/runners.py +0 -280
  212. foxes-0.8.2.dist-info/RECORD +0 -247
  213. foxes-0.8.2.dist-info/top_level.txt +0 -1
  214. foxes-0.8.2.dist-info/zip-safe +0 -1
  215. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
@@ -1,22 +1,24 @@
1
1
  from xarray import Dataset
2
2
 
3
3
  from foxes.utils import write_nc
4
- import foxes.constants as FC
4
+ import foxes.constants as FC
5
5
 
6
6
  from .output import Output
7
7
 
8
+
8
9
  class StateTurbineTable(Output):
9
10
  """
10
11
  Creates tables of state-turbine type data
11
-
12
+
12
13
  Attributes
13
14
  ----------
14
15
  farm_results: xarray.Dataset
15
16
  The farm results
16
-
17
+
17
18
  :group: output
18
-
19
+
19
20
  """
21
+
20
22
  def __init__(self, farm_results):
21
23
  """
22
24
  Constructor.
@@ -28,17 +30,17 @@ class StateTurbineTable(Output):
28
30
 
29
31
  """
30
32
  self.farm_results = farm_results
31
-
33
+
32
34
  def get_dataset(
33
- self,
34
- variables,
35
- name_map={},
36
- to_file=None,
35
+ self,
36
+ variables,
37
+ name_map={},
38
+ to_file=None,
37
39
  **kwargs,
38
- ):
40
+ ):
39
41
  """
40
42
  Creates a dataset object
41
-
43
+
42
44
  Parameters
43
45
  ----------
44
46
  variables: list of str
@@ -49,12 +51,12 @@ class StateTurbineTable(Output):
49
51
  The output file path, if writing is desired
50
52
  kwargs: dict, optional
51
53
  Additional parameters for write_nc
52
-
54
+
53
55
  Returns
54
56
  -------
55
57
  table: xarray.Dataset
56
58
  The state-turbine data table
57
-
59
+
58
60
  """
59
61
  state = name_map.get(FC.STATE, FC.STATE)
60
62
  turbine = name_map.get(FC.TURBINE, FC.TURBINE)
@@ -65,14 +67,12 @@ class StateTurbineTable(Output):
65
67
  turbine: self.farm_results[FC.TURBINE].to_numpy(),
66
68
  },
67
69
  data_vars={
68
- name_map.get(v, v): (
69
- (state, turbine), self.farm_results[v].to_numpy())
70
+ name_map.get(v, v): ((state, turbine), self.farm_results[v].to_numpy())
70
71
  for v in variables
71
- }
72
+ },
72
73
  )
73
-
74
+
74
75
  if to_file is not None:
75
76
  write_nc(ds=ds, fpath=to_file, **kwargs)
76
-
77
+
77
78
  return ds
78
-
foxes/utils/__init__.py CHANGED
@@ -17,8 +17,8 @@ from .regularize import sqrt_reg
17
17
  from .windrose_plot import TabWindroseAxes
18
18
  from .tab_files import read_tab_file
19
19
  from .random_xy import random_xy_square
20
+ from .dev_utils import print_mem
20
21
 
21
22
  from . import two_circles
22
23
  from . import abl
23
- from . import runners
24
24
  from . import geom2d
@@ -39,7 +39,7 @@ def ustar(ws_ref, h_ref, z0, kappa=0.41):
39
39
  z0: float
40
40
  The roughness length
41
41
  kappa: float
42
- The van-Karman constant
42
+ The von Karman constant
43
43
 
44
44
  Returns
45
45
  -------
@@ -66,7 +66,7 @@ def calc_ws(height, z0, ustar, kappa=0.41):
66
66
  ustar: float
67
67
  The friction velocity
68
68
  kappa: float
69
- The van-Karman constant
69
+ The von Karman constant
70
70
 
71
71
  Returns
72
72
  -------
foxes/utils/abl/stable.py CHANGED
@@ -64,7 +64,7 @@ def ustar(ws_ref, h_ref, z0, mol, kappa=0.41):
64
64
  mol: float
65
65
  The Monin-Obukhov height
66
66
  kappa: float
67
- The van-Karman constant
67
+ The von Karman constant
68
68
 
69
69
  Returns
70
70
  -------
@@ -92,7 +92,7 @@ def calc_ws(height, z0, ustar, psi, kappa=0.41):
92
92
  psi: float
93
93
  The Psi function values
94
94
  kappa: float
95
- The van-Karman constant
95
+ The von Karman constant
96
96
 
97
97
  Returns
98
98
  -------
@@ -47,7 +47,7 @@ def ustar(ws_ref, h_ref, z0, mol, kappa=0.41):
47
47
  mol: float
48
48
  The Monin-Obukhov height
49
49
  kappa: float
50
- The van-Karman constant
50
+ The von Karman constant
51
51
 
52
52
  Returns
53
53
  -------
@@ -75,7 +75,7 @@ def calc_ws(height, z0, ustar, psi, kappa=0.41):
75
75
  psi: float
76
76
  The Psi function values
77
77
  kappa: float
78
- The van-Karman constant
78
+ The von Karman constant
79
79
 
80
80
  Returns
81
81
  -------
foxes/utils/data_book.py CHANGED
@@ -89,7 +89,7 @@ class DataBook:
89
89
  context: str
90
90
  The context
91
91
  package: str or package
92
- The package, must contain init.py` file
92
+ The package, must contain init.py file
93
93
  file_mane: str
94
94
  The file name
95
95
 
@@ -0,0 +1,42 @@
1
+ from .load import import_module
2
+
3
+
4
+ def print_mem(obj, min_csize=0, max_csize=None, pre_str="OBJECT SIZE"):
5
+ """
6
+ Prints the memory consumption of a model and its components
7
+
8
+ Parmeters
9
+ ---------
10
+ obj: object
11
+ The object to be analyzed
12
+ min_csize: int
13
+ The minimal size of a component for being shown
14
+ max_csize: int, optional
15
+ The maximal allowed size of a component
16
+ pre_str: str
17
+ String to be printed before
18
+
19
+ :group: utils
20
+
21
+ """
22
+ objsize = import_module("objsize")
23
+ n = obj.name if hasattr(obj, "name") else ""
24
+ print(pre_str, type(obj).__name__, n, objsize.get_deep_size(obj))
25
+ for k in dir(obj):
26
+ o = None
27
+ try:
28
+ if (
29
+ hasattr(obj, k)
30
+ and not callable(getattr(obj, k))
31
+ and (len(k) < 3 or k[:2] != "__")
32
+ ):
33
+ o = getattr(obj, k)
34
+ except ValueError:
35
+ pass
36
+
37
+ if o is not None:
38
+ s = objsize.get_deep_size(getattr(obj, k))
39
+ if s >= min_csize:
40
+ print(" ", k, s)
41
+ if max_csize is not None and s > max_csize:
42
+ raise ValueError(f"Component {k} exceeds maximal size {max_csize}")
foxes/utils/dict.py CHANGED
@@ -28,10 +28,33 @@ class Dict(dict):
28
28
  super().__init__(*args, **kwargs)
29
29
  self.name = name if name is not None else type(self).__name__
30
30
 
31
+ def get_item(self, key, prnt=True):
32
+ """
33
+ Gets an item, prints readable error if not found
34
+
35
+ Parameters
36
+ ----------
37
+ key: immutable object
38
+ The key
39
+ prnt: bool
40
+ Flag for message printing
41
+
42
+ """
43
+ try:
44
+ return self[key]
45
+ except KeyError as e:
46
+ if prnt:
47
+ print(f"\n{self.name}: Cannot find key '{key}'.\n")
48
+ print("Known keys:")
49
+ for k in self.keys():
50
+ print(" ", k)
51
+ print()
52
+ raise e
53
+
31
54
  def __getitem__(self, key):
32
55
  try:
33
56
  return super().__getitem__(key)
34
57
  except KeyError:
35
- k = ", ".join(sorted(list(self.keys())))
58
+ k = ", ".join(sorted([f"{s}" for s in self.keys()]))
36
59
  e = f"{self.name}: Cannot find key '{key}'. Known keys: {k}"
37
60
  raise KeyError(e)
@@ -17,7 +17,7 @@ def exec_python(s, indicator="%", newline=";", globals=globals(), locals={}):
17
17
  s: list, dict or object
18
18
  The source to by analyzed
19
19
  indicator: str
20
- The indicator that trigger python evaluation
20
+ The indicator that triggers python evaluation
21
21
  newline: str
22
22
  The new line indicator
23
23
  globals: dict
foxes/utils/factory.py CHANGED
@@ -1,3 +1,5 @@
1
+ import numpy as np
2
+
1
3
  from .dict import Dict
2
4
  import foxes.variables as FV
3
5
 
@@ -23,6 +25,8 @@ class Factory:
23
25
  hints: dict
24
26
  Hints for print_toc, only for variables for which the
25
27
  options are functions or missing
28
+ example: str
29
+ An example name
26
30
  options: dict
27
31
  For each variable, e.g. A, B or C, the list or dict
28
32
  or function that maps a str to the actual value
@@ -39,6 +43,7 @@ class Factory:
39
43
  kwargs={},
40
44
  var2arg={},
41
45
  hints={},
46
+ example_vars=None,
42
47
  **options,
43
48
  ):
44
49
  """
@@ -60,6 +65,8 @@ class Factory:
60
65
  hints: dict
61
66
  Hints for print_toc, only for variables for which the
62
67
  options are functions or missing
68
+ example_vars: dict, optional
69
+ Variable values for creating an example
63
70
  options: dict
64
71
  For each variable, e.g. A, B or C, the list or dict
65
72
  or function that maps a str to the actual value
@@ -122,6 +129,30 @@ class Factory:
122
129
  f"Factory '{name_template}': Variable '{v}' has option of type '{type(v).__name__}'. Only list, tuple, dict or function are supported"
123
130
  )
124
131
 
132
+ exvars = dict(
133
+ n=5,
134
+ n2=9,
135
+ superposition="linear",
136
+ kTI=0.2,
137
+ kb=0.001,
138
+ step=100,
139
+ dx=100,
140
+ dt="10s",
141
+ )
142
+ if example_vars is not None:
143
+ exvars.update(example_vars)
144
+ try:
145
+ self.example = ""
146
+ for i, v in enumerate(self._vars):
147
+ self.example += f"{self._pre[i]}{exvars[v]}"
148
+ self.example += self._pre[-1]
149
+ if not self.check_match(self.example, error=False):
150
+ raise ValueError(
151
+ f"Example '{self.example}' does not match template '{self.name_template}'"
152
+ )
153
+ except KeyError:
154
+ self.example = None
155
+
125
156
  @property
126
157
  def name_prefix(self):
127
158
  """
@@ -171,56 +202,77 @@ class Factory:
171
202
  s += f"\n {v} from {list(self.options[v])}"
172
203
  else:
173
204
  s += f"\n {v}={self.hints.get(v, '(value)')}"
205
+ if self.example is not None:
206
+ s += f"\nExample: {self.example}"
174
207
  return s
175
208
 
176
- def check_match(self, name):
209
+ def get_examples(self, **var_values):
177
210
  """
178
- Tests if a name matches the template
211
+ Create example names from given values
179
212
 
180
213
  Parameters
181
214
  ----------
182
- name: str
183
- The name to be checked
215
+ var_values: dict
216
+ Variables values. Key: Variable,
217
+ value: list or value
184
218
 
185
219
  Returns
186
220
  -------
187
- success: bool
188
- True if the template is matched
221
+ examples: list of str
222
+ The examples
189
223
 
190
224
  """
191
- data_str = name
192
- for vi in range(len(self.variables)):
193
- p = self._pre[vi]
194
- i = data_str.find(p)
195
- j = i + len(p)
196
- if i < 0 or len(data_str) <= j:
197
- return False
198
- data_str = data_str[j:]
199
-
200
- q = self._pre[vi + 1]
201
- if q != "":
202
- i = data_str.find(q)
203
- j = i + len(q)
204
- if i < 0 or len(data_str) <= j:
205
- return False
225
+
226
+ def gete(i, vals, vars, values, examples):
227
+ if i >= len(vars):
228
+ e = ""
229
+ for i, v in enumerate(self._vars):
230
+ e += f"{self._pre[i]}{vals[v]}"
231
+ e += self._pre[-1]
232
+ self.check_match(e, error=True)
233
+ examples.append(e)
206
234
  else:
207
- data_str = ""
235
+ v = vars[i]
236
+ if v in self._vars:
237
+ vls = np.atleast_1d(values[i])
238
+ for x in vls:
239
+ vals[v] = x
240
+ gete(i + 1, vals, vars, values, examples)
241
+ else:
242
+ gete(i + 1, vals, vars, values, examples)
243
+
244
+ examples = []
245
+ gete(
246
+ 0,
247
+ {},
248
+ list(var_values.keys()),
249
+ list(var_values.values()),
250
+ examples,
251
+ )
208
252
 
209
- return True
253
+ return examples
210
254
 
211
- def construct(self, name):
255
+ def check_match(self, name, error=False, ret_pars=False):
212
256
  """
213
- Create an object of the base class.
257
+ Tests if a name matches the template and constructs
258
+ parameters
214
259
 
215
260
  Parameters
216
261
  ----------
217
262
  name: str
218
- The name, matching the template
263
+ The name to be checked
264
+ error: bool
265
+ Flag for raising a Value error in case of
266
+ mismatch
267
+ ret_pars: bool
268
+ Flag for returning the parameters
219
269
 
220
270
  Returns
221
271
  -------
222
- obj: object
223
- The instance of the base class
272
+ success: bool
273
+ True if the template is matched
274
+ pars: dict, optional
275
+ The constructed parameters
224
276
 
225
277
  """
226
278
  j = 0
@@ -229,9 +281,14 @@ class Factory:
229
281
  if len(p) > 0:
230
282
  i = name[j:].find(p)
231
283
  if i < 0 or (pi == 0 and i > 0):
232
- raise ValueError(
233
- f"Factory '{self.name_template}': Name '{name}' not matching template"
234
- )
284
+ if error:
285
+ raise ValueError(
286
+ f"Factory '{self.name_template}': Name '{name}' not matching template"
287
+ )
288
+ elif ret_pars:
289
+ return False, {}
290
+ else:
291
+ return False
235
292
  w = name[j : j + i]
236
293
  j += i + len(p)
237
294
  else:
@@ -239,21 +296,41 @@ class Factory:
239
296
  if pi > 0:
240
297
  wlist.append(w)
241
298
 
242
- kwargs = {}
243
- for vi, v in enumerate(self.variables):
244
- w = self.var2arg.get(v, v)
245
- data = wlist[vi]
246
- if v in self.options:
247
- o = self.options[v]
248
- if hasattr(o, "__call__"):
249
- kwargs[w] = o(data)
299
+ if ret_pars:
300
+ kwargs = {}
301
+ for vi, v in enumerate(self.variables):
302
+ w = self.var2arg.get(v, v)
303
+ data = wlist[vi]
304
+ if v in self.options:
305
+ o = self.options[v]
306
+ if hasattr(o, "__call__"):
307
+ kwargs[w] = o(data)
308
+ else:
309
+ kwargs[w] = self.options[v][data]
250
310
  else:
251
- kwargs[w] = self.options[v][data]
252
- else:
253
- kwargs[w] = data
311
+ kwargs[w] = data
254
312
 
255
- kwargs.update(self.kwargs)
313
+ kwargs.update(self.kwargs)
314
+ return True, kwargs
256
315
 
316
+ return True
317
+
318
+ def construct(self, name):
319
+ """
320
+ Create an object of the base class.
321
+
322
+ Parameters
323
+ ----------
324
+ name: str
325
+ The name, matching the template
326
+
327
+ Returns
328
+ -------
329
+ obj: object
330
+ The instance of the base class
331
+
332
+ """
333
+ __, kwargs = self.check_match(name, error=True, ret_pars=True)
257
334
  return self.base(*self.args, **kwargs)
258
335
 
259
336
 
@@ -299,14 +376,20 @@ class WakeKFactory:
299
376
  i0 = name_template.find("_[wake_k]")
300
377
  i1 = i0 + len("_[wake_k]")
301
378
  kw = kwargs.pop("kwargs", {})
379
+ v2a = kwargs.pop("var2arg", {})
302
380
 
303
381
  if i0 < 0:
304
382
  raise ValueError(
305
383
  f"String '_[wake_k]' not found in name template '{name_template}'"
306
384
  )
307
385
 
386
+ exvars = dict(k=0.04, ka=0.2, ambka=0.4, kb=0.001)
387
+ if "example_vars" in kwargs:
388
+ exvars.update(kwargs.pop("example_vars"))
389
+
308
390
  # add case ka, kb:
309
- t = name_template[:i0] + "_ka<ka>_kb<kb>"
391
+ t0 = name_template[:i0]
392
+ t = t0 + "_ka<ka>_kb<kb>"
310
393
  if len(name_template) > i1:
311
394
  t += name_template[i1:]
312
395
  h = hints.copy()
@@ -323,17 +406,20 @@ class WakeKFactory:
323
406
  **kwargs,
324
407
  ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
325
408
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
409
+ example_vars=exvars,
326
410
  )
327
411
  )
328
412
 
329
- # add case ambient ka, kb:
330
- t = name_template[:i0] + "_ambka<ka>_kb<kb>"
413
+ # add case ambient ambka, kb:
414
+ t = name_template[:i0] + "_ambka<ambka>_kb<kb>"
331
415
  if len(name_template) > i1:
332
416
  t += name_template[i1:]
333
417
  h = hints.copy()
334
- h["ka"] = "(Value, e.g. 04 for 0.4)"
418
+ h["ambka"] = "(Value, e.g. 04 for 0.4)"
335
419
  h["kb"] = "(Value, e.g. 001 for 0.01)"
336
420
  kw["ti_var"] = FV.AMB_TI
421
+ hv2a = v2a.copy()
422
+ hv2a["ambka"] = "ka"
337
423
  self.factories.append(
338
424
  Factory(
339
425
  base,
@@ -341,9 +427,11 @@ class WakeKFactory:
341
427
  *args,
342
428
  hints=h,
343
429
  kwargs=kw.copy(),
430
+ var2arg=hv2a,
344
431
  **kwargs,
345
- ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
432
+ ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
346
433
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
434
+ example_vars=exvars,
347
435
  )
348
436
  )
349
437
 
@@ -363,16 +451,19 @@ class WakeKFactory:
363
451
  kwargs=kw.copy(),
364
452
  **kwargs,
365
453
  ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
454
+ example_vars=exvars,
366
455
  )
367
456
  )
368
457
 
369
- # add case ka:
370
- t = name_template[:i0] + "_ambka<ka>"
458
+ # add case ambka:
459
+ t = name_template[:i0] + "_ambka<ambka>"
371
460
  if len(name_template) > i1:
372
461
  t += name_template[i1:]
373
462
  h = hints.copy()
374
- h["ka"] = "(Value, e.g. 04 for 0.4)"
463
+ h["ambka"] = "(Value, e.g. 04 for 0.4)"
375
464
  kw["ti_var"] = FV.AMB_TI
465
+ hv2a = v2a.copy()
466
+ hv2a["ambka"] = "ka"
376
467
  self.factories.append(
377
468
  Factory(
378
469
  base,
@@ -380,8 +471,10 @@ class WakeKFactory:
380
471
  *args,
381
472
  hints=h,
382
473
  kwargs=kw.copy(),
474
+ var2arg=hv2a,
383
475
  **kwargs,
384
- ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
476
+ ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
477
+ example_vars=exvars,
385
478
  )
386
479
  )
387
480
 
@@ -401,6 +494,7 @@ class WakeKFactory:
401
494
  kwargs=kw.copy(),
402
495
  **kwargs,
403
496
  k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
497
+ example_vars=exvars,
404
498
  )
405
499
  )
406
500
 
@@ -417,6 +511,7 @@ class WakeKFactory:
417
511
  hints=hints,
418
512
  kwargs=kw.copy(),
419
513
  **kwargs,
514
+ example_vars=exvars,
420
515
  )
421
516
  )
422
517
 
@@ -523,6 +618,35 @@ class FDict(Dict):
523
618
  return True
524
619
  return found
525
620
 
621
+ def get_item(self, key, prnt=True):
622
+ """
623
+ Gets an item, prints readable error if not found
624
+
625
+ Parameters
626
+ ----------
627
+ key: immutable object
628
+ The key
629
+ prnt: bool
630
+ Flag for message printing
631
+
632
+ """
633
+ try:
634
+ return self[key]
635
+ except KeyError as e:
636
+ if prnt:
637
+ print(
638
+ f"\n{self.name}: Cannot find key '{key}', also no factory matches.\n"
639
+ )
640
+ print("Known keys:")
641
+ for k in self.keys():
642
+ print(" ", k)
643
+ if len(self.factories):
644
+ print("\nKnown factories:")
645
+ for f in self.factories:
646
+ print(" ", f.name_template)
647
+ print()
648
+ raise e
649
+
526
650
  def __getitem__(self, key):
527
651
  try:
528
652
  return super().__getitem__(key)
@@ -535,7 +659,6 @@ class FDict(Dict):
535
659
  return obj
536
660
  except ValueError:
537
661
  pass
538
-
539
662
  k = ", ".join(sorted(list(self.keys())))
540
663
  e = f"{self.name}: Cannot find key '{key}', also no factory matches. Known keys: {k}. Known factories: {[f.name_template for f in self.factories]}"
541
664
  raise KeyError(e)
@@ -21,7 +21,7 @@ class Circle(AreaGeometry):
21
21
 
22
22
  def __init__(self, centre, radius):
23
23
  """
24
- Cobnstructor.
24
+ Constructor.
25
25
 
26
26
  Parameters
27
27
  ----------
@@ -74,7 +74,7 @@ class ClosedPolygon(AreaGeometry):
74
74
  points: numpy.ndarray
75
75
  The probe points, shape (n_points, 2)
76
76
  return_nearest: bool
77
- Flag for return of the nearest point on bundary
77
+ Flag for return of the nearest point on boundary
78
78
 
79
79
  Returns
80
80
  -------
@@ -50,7 +50,7 @@ def check_import_utm():
50
50
 
51
51
  def read_shp(fname, **kwargs):
52
52
  """
53
- Read a shape file
53
+ Read a shapefile file
54
54
 
55
55
  Parameters
56
56
  ----------
@@ -74,7 +74,7 @@ def read_shp(fname, **kwargs):
74
74
 
75
75
  def shp2csv(ifile, ofile, in_kwargs={}, out_kwargs={}, verbosity=1):
76
76
  """
77
- Read shape file, write csv file
77
+ Read shapefile file, write csv file
78
78
 
79
79
  Parameters
80
80
  ----------