osiris-utils 1.1.10a0__py3-none-any.whl → 1.2.1__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 (54) hide show
  1. benchmarks/benchmark_hdf5_io.py +46 -0
  2. benchmarks/benchmark_load_all.py +54 -0
  3. docs/source/_static/Imagem1.png +0 -0
  4. docs/source/_static/custom.css +24 -8
  5. docs/source/api/decks.rst +48 -0
  6. docs/source/api/postprocess.rst +72 -8
  7. docs/source/api/sim_diag.rst +9 -7
  8. docs/source/api/utilities.rst +6 -6
  9. docs/source/conf.py +28 -8
  10. docs/source/examples/example_Derivatives.md +78 -0
  11. docs/source/examples/example_FFT.md +152 -0
  12. docs/source/examples/example_InputDeck.md +149 -0
  13. docs/source/examples/example_Simulation_Diagnostic.md +213 -0
  14. docs/source/examples/quick_start.md +51 -0
  15. docs/source/examples.rst +14 -0
  16. docs/source/index.rst +8 -0
  17. examples/edited-deck.1d +1 -1
  18. examples/example_Derivatives.ipynb +24 -36
  19. examples/example_FFT.ipynb +44 -23
  20. examples/example_InputDeck.ipynb +24 -277
  21. examples/example_Simulation_Diagnostic.ipynb +27 -17
  22. examples/quick_start.ipynb +17 -1
  23. osiris_utils/__init__.py +10 -6
  24. osiris_utils/cli/__init__.py +6 -0
  25. osiris_utils/cli/__main__.py +85 -0
  26. osiris_utils/cli/export.py +199 -0
  27. osiris_utils/cli/info.py +156 -0
  28. osiris_utils/cli/plot.py +189 -0
  29. osiris_utils/cli/validate.py +247 -0
  30. osiris_utils/data/__init__.py +15 -0
  31. osiris_utils/data/data.py +41 -171
  32. osiris_utils/data/diagnostic.py +285 -274
  33. osiris_utils/data/simulation.py +20 -13
  34. osiris_utils/decks/__init__.py +4 -0
  35. osiris_utils/decks/decks.py +83 -8
  36. osiris_utils/decks/species.py +12 -9
  37. osiris_utils/postprocessing/__init__.py +28 -0
  38. osiris_utils/postprocessing/derivative.py +317 -106
  39. osiris_utils/postprocessing/fft.py +135 -24
  40. osiris_utils/postprocessing/field_centering.py +28 -14
  41. osiris_utils/postprocessing/heatflux_correction.py +39 -18
  42. osiris_utils/postprocessing/mft.py +10 -2
  43. osiris_utils/postprocessing/postprocess.py +8 -5
  44. osiris_utils/postprocessing/pressure_correction.py +29 -17
  45. osiris_utils/utils.py +26 -17
  46. osiris_utils/vis/__init__.py +3 -0
  47. osiris_utils/vis/plot3d.py +148 -0
  48. {osiris_utils-1.1.10a0.dist-info → osiris_utils-1.2.1.dist-info}/METADATA +61 -7
  49. {osiris_utils-1.1.10a0.dist-info → osiris_utils-1.2.1.dist-info}/RECORD +53 -35
  50. {osiris_utils-1.1.10a0.dist-info → osiris_utils-1.2.1.dist-info}/WHEEL +1 -1
  51. osiris_utils-1.2.1.dist-info/entry_points.txt +2 -0
  52. {osiris_utils-1.1.10a0.dist-info → osiris_utils-1.2.1.dist-info}/top_level.txt +1 -0
  53. osiris_utils/postprocessing/mft_for_gridfile.py +0 -55
  54. {osiris_utils-1.1.10a0.dist-info → osiris_utils-1.2.1.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,8 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
4
+ from typing import Any
2
5
 
3
6
  from ..data.diagnostic import Diagnostic
4
7
  from ..decks.decks import InputDeckIO
5
8
 
9
+ __all__ = ["Simulation", "Species_Handler"]
10
+
6
11
 
7
12
  class Simulation:
8
13
  """
@@ -17,7 +22,7 @@ class Simulation:
17
22
  ----------
18
23
  simulation_folder : str
19
24
  The simulation folder.
20
- species : Specie object
25
+ species : Species object
21
26
  The species to analyze.
22
27
  diagnostics : dict
23
28
  Dictionary to store diagnostics for each quantity when `load_all` method is used.
@@ -34,7 +39,7 @@ class Simulation:
34
39
 
35
40
  """
36
41
 
37
- def __init__(self, input_deck_path):
42
+ def __init__(self, input_deck_path: str) -> None:
38
43
  folder_path = os.path.dirname(input_deck_path)
39
44
  self._input_deck_path = input_deck_path
40
45
  self._input_deck = InputDeckIO(self._input_deck_path, verbose=False)
@@ -60,7 +65,7 @@ class Simulation:
60
65
  else:
61
66
  print(f"Diagnostic {key} not found in simulation")
62
67
 
63
- def __getitem__(self, key):
68
+ def __getitem__(self, key: str) -> Diagnostic | Species_Handler:
64
69
  # check if key is a species
65
70
  if key in self._species:
66
71
  # check if species handler already exists
@@ -94,7 +99,7 @@ class Simulation:
94
99
 
95
100
  return diag
96
101
 
97
- def add_diagnostic(self, diagnostic, name=None):
102
+ def add_diagnostic(self, diagnostic: Diagnostic, name: str | None = None) -> str:
98
103
  """
99
104
  Add a custom diagnostic to the simulation.
100
105
 
@@ -130,27 +135,28 @@ class Simulation:
130
135
  # If already a Diagnostic, store directly
131
136
  if isinstance(diagnostic, Diagnostic):
132
137
  self._diagnostics[name] = diagnostic
138
+ return name
133
139
  else:
134
140
  raise ValueError("Only Diagnostic objects are supported for now")
135
141
 
136
142
  @property
137
- def species(self):
143
+ def species(self) -> list[str]:
138
144
  return self._species
139
145
 
140
146
  @property
141
- def loaded_diagnostics(self):
147
+ def loaded_diagnostics(self) -> dict[str, Diagnostic]:
142
148
  return self._diagnostics
143
149
 
144
150
 
145
151
  # This is to handle species related diagnostics
146
152
  class Species_Handler:
147
- def __init__(self, simulation_folder, species_name, input_deck):
153
+ def __init__(self, simulation_folder: str, species_name: Any, input_deck: Any) -> None:
148
154
  self._simulation_folder = simulation_folder
149
155
  self._species_name = species_name
150
156
  self._input_deck = input_deck
151
157
  self._diagnostics = {}
152
158
 
153
- def __getitem__(self, key):
159
+ def __getitem__(self, key: str) -> Diagnostic:
154
160
  if key in self._diagnostics:
155
161
  return self._diagnostics[key]
156
162
 
@@ -173,7 +179,7 @@ class Species_Handler:
173
179
 
174
180
  return diag
175
181
 
176
- def add_diagnostic(self, diagnostic, name=None):
182
+ def add_diagnostic(self, diagnostic: Diagnostic, name: str | None = None) -> str:
177
183
  """
178
184
  Add a custom diagnostic to the simulation.
179
185
 
@@ -203,10 +209,11 @@ class Species_Handler:
203
209
  # If already a Diagnostic, store directly
204
210
  if isinstance(diagnostic, Diagnostic):
205
211
  self._diagnostics[name] = diagnostic
212
+ return name
206
213
  else:
207
214
  raise ValueError("Only Diagnostic objects are supported for now")
208
215
 
209
- def delete_diagnostic(self, key):
216
+ def delete_diagnostic(self, key: str) -> None:
210
217
  """
211
218
  Delete a diagnostic.
212
219
  """
@@ -216,16 +223,16 @@ class Species_Handler:
216
223
  print(f"Diagnostic {key} not found in species {self._species_name}")
217
224
  return None
218
225
 
219
- def delete_all_diagnostics(self):
226
+ def delete_all_diagnostics(self) -> None:
220
227
  """
221
228
  Delete all diagnostics.
222
229
  """
223
230
  self._diagnostics = {}
224
231
 
225
232
  @property
226
- def species(self):
233
+ def species(self) -> Any:
227
234
  return self._species_name
228
235
 
229
236
  @property
230
- def loaded_diagnostics(self):
237
+ def loaded_diagnostics(self) -> dict[str, Diagnostic]:
231
238
  return self._diagnostics
@@ -0,0 +1,4 @@
1
+ from .decks import InputDeckIO, deval
2
+ from .species import Species
3
+
4
+ __all__ = ["InputDeckIO", "deval", "Species"]
@@ -4,7 +4,9 @@ import re
4
4
 
5
5
  import numpy as np
6
6
 
7
- from .species import Specie
7
+ from .species import Species
8
+
9
+ __all__ = ["InputDeckIO", "deval"]
8
10
 
9
11
 
10
12
  def deval(x):
@@ -42,7 +44,7 @@ class InputDeckIO:
42
44
  Number of dimensions in the simulation (1, 2, or 3).
43
45
  """
44
46
 
45
- def __init__(self, filename: str, verbose: bool = True):
47
+ def __init__(self, filename: str, verbose: bool = False):
46
48
  self._filename = str(filename)
47
49
  self._sections = self._parse_input_deck(verbose)
48
50
  self._dim = self._get_dim()
@@ -54,7 +56,7 @@ class InputDeckIO:
54
56
  if verbose:
55
57
  print(f"\nParsing input deck : {self._filename}")
56
58
 
57
- with open(self._filename, "r", encoding="utf-8") as f:
59
+ with open(self._filename, encoding="utf-8") as f:
58
60
  lines = f.readlines()
59
61
 
60
62
  # remove comments
@@ -162,14 +164,14 @@ class InputDeckIO:
162
164
  s_qreal = np.ones(len(s_names))
163
165
  # check if we have information for all species
164
166
  if len(s_names) != self.n_species:
165
- raise RuntimeError("Number of specie names does not match number of species: " f"{len(s_names)} != {len(self.n_species)}.")
167
+ raise RuntimeError(f"Number of specie names does not match number of species: {len(s_names)} != {len(self.n_species)}.")
166
168
  if len(s_rqm) != self.n_species:
167
- raise RuntimeError("Number of specie rqm does not match number of species: " f"{len(s_rqm)} != {len(self.n_species)}.")
169
+ raise RuntimeError(f"Number of specie rqm does not match number of species: {len(s_rqm)} != {len(self.n_species)}.")
168
170
  if len(s_qreal) != self.n_species:
169
- raise RuntimeError("Number of specie rqm does not match number of species: " f"{len(s_qreal)} != {len(self.n_species)}.")
171
+ raise RuntimeError(f"Number of specie rqm does not match number of species: {len(s_qreal)} != {len(self.n_species)}.")
170
172
 
171
173
  return {
172
- ast.literal_eval(s_names[i]): Specie(
174
+ ast.literal_eval(s_names[i]): Species(
173
175
  name=ast.literal_eval(s_names[i]),
174
176
  rqm=float(s_rqm[i]),
175
177
  q=int(s_qreal[0]) * np.sign(float(s_rqm[i])),
@@ -178,6 +180,29 @@ class InputDeckIO:
178
180
  }
179
181
 
180
182
  def set_param(self, section, param, value, i_use=None, unexistent_ok=False):
183
+ """
184
+ Set a parameter value in the input deck.
185
+
186
+ Parameters
187
+ ----------
188
+ section : str
189
+ The name of the section where the parameter is located.
190
+ param : str
191
+ The name of the parameter to set.
192
+ value : str or list or int or float
193
+ The value to set. If a list, it is converted to a comma-separated string.
194
+ i_use : int or list of int, optional
195
+ The index(es) of the section(s) to modify if multiple sections with the same name exist.
196
+ If None, all sections with the matching name are modified.
197
+ unexistent_ok : bool, optional
198
+ If True, allows setting a parameter that does not currently exist in the section.
199
+ Default is False.
200
+
201
+ Raises
202
+ ------
203
+ KeyError
204
+ If the section is not found, or if the parameter is not found (and unexistent_ok is False).
205
+ """
181
206
  # get all sections with the same name
182
207
  # (e.g. there might be multiple 'species')
183
208
  i_sections = [i for i, m in enumerate(self._sections) if m[0] == section]
@@ -193,7 +218,7 @@ class InputDeckIO:
193
218
 
194
219
  for i in i_sections:
195
220
  if not unexistent_ok and param not in self._sections[i][1]:
196
- raise KeyError(f'"{param}" not yet inside section "{section}" ' "(set unexistent_ok=True to ignore).")
221
+ raise KeyError(f'"{param}" not yet inside section "{section}" (set unexistent_ok=True to ignore).')
197
222
  if isinstance(value, str):
198
223
  self._sections[i][1][param] = str(f'"{value}"')
199
224
  elif isinstance(value, list):
@@ -202,11 +227,43 @@ class InputDeckIO:
202
227
  self._sections[i][1][param] = str(value)
203
228
 
204
229
  def set_tag(self, tag, value):
230
+ """
231
+ Replace a tag in all parameters within the input deck.
232
+ This is useful for template replacement.
233
+
234
+ Parameters
235
+ ----------
236
+ tag : str
237
+ The tag substring to search for (e.g., "<TAG>").
238
+ value : str or int or float
239
+ The value to replace the tag with.
240
+ """
205
241
  for im, (_, params) in enumerate(self._sections):
206
242
  for p, v in params.items():
207
243
  self._sections[im][1][p] = v.replace(tag, str(value))
208
244
 
209
245
  def get_param(self, section, param):
246
+ """
247
+ Get the value(s) of a parameter from a specific section.
248
+
249
+ Parameters
250
+ ----------
251
+ section : str
252
+ The name of the section.
253
+ param : str
254
+ The name of the parameter.
255
+
256
+ Returns
257
+ -------
258
+ values : list
259
+ A list of values for the parameter. Returns a list because there can be multiple
260
+ sections with the same name.
261
+
262
+ Raises
263
+ ------
264
+ KeyError
265
+ If the parameter is not found in one of the sections.
266
+ """
210
267
  i_sections = [i for i, m in enumerate(self._sections) if m[0] == section]
211
268
 
212
269
  if len(i_sections) == 0:
@@ -222,6 +279,16 @@ class InputDeckIO:
222
279
  return values
223
280
 
224
281
  def delete_param(self, section, param):
282
+ """
283
+ Delete a parameter from a specific section.
284
+
285
+ Parameters
286
+ ----------
287
+ section : str
288
+ The name of the section.
289
+ param : str
290
+ The name of the parameter to delete.
291
+ """
225
292
  sections_new = []
226
293
  for m_name, m_dict in self._sections:
227
294
  if m_name == section and param in m_dict:
@@ -230,6 +297,14 @@ class InputDeckIO:
230
297
  self._sections = sections_new
231
298
 
232
299
  def print_to_file(self, filename):
300
+ """
301
+ Write the current state of the input deck to a file.
302
+
303
+ Parameters
304
+ ----------
305
+ filename : str
306
+ The path to the output file.
307
+ """
233
308
  with open(filename, "w", encoding="utf-8") as f:
234
309
  for section, section_dict in self._sections:
235
310
  f.write(f"{section}\n{{\n")
@@ -1,32 +1,35 @@
1
- class Specie:
1
+ __all__ = ["Species"]
2
+
3
+
4
+ class Species:
2
5
  """
3
6
  Class to store OSIRIS species object.
4
7
 
5
8
  Parameters
6
9
  ----------
7
10
  name : str
8
- Specie name.
11
+ Species name.
9
12
 
10
13
  rqm : float
11
- Specie charge to mass ratio.
14
+ Species charge to mass ratio.
12
15
 
13
16
  q : int
14
- Specie charge in units of the electron charge.
17
+ Species charge in units of the electron charge.
15
18
  Electrons would be represented by q=-1 and protons q=1.
16
19
 
17
20
  Attributes
18
21
  ----------
19
22
  name : str
20
- Specie name.
23
+ Species name.
21
24
 
22
25
  rqm : float
23
- Specie charge to mass ratio.
26
+ Species charge to mass ratio.
24
27
 
25
28
  q : int
26
- Specie charge in units of the electron charge.
29
+ Species charge in units of the electron charge.
27
30
 
28
31
  m : float
29
- Specie mass in units of the electron mass.
32
+ Species mass in units of the electron mass.
30
33
  """
31
34
 
32
35
  def __init__(self, name, rqm, q: int = 1):
@@ -36,7 +39,7 @@ class Specie:
36
39
  self._m = rqm * q
37
40
 
38
41
  def __repr__(self) -> str:
39
- return f"Specie(name={self._name}, rqm={self._rqm}, q={self._q}, m={self._m})"
42
+ return f"Species(name={self._name}, rqm={self._rqm}, q={self._q}, m={self._m})"
40
43
 
41
44
  @property
42
45
  def name(self):
@@ -0,0 +1,28 @@
1
+ from .derivative import Derivative_Diagnostic, Derivative_Simulation, Derivative_Species_Handler
2
+ from .fft import FFT_Diagnostic, FFT_Simulation, FFT_Species_Handler
3
+ from .field_centering import FieldCentering_Diagnostic, FieldCentering_Simulation
4
+ from .heatflux_correction import HeatfluxCorrection_Diagnostic, HeatfluxCorrection_Simulation, HeatfluxCorrection_Species_Handler
5
+ from .mft import MFT_Diagnostic, MFT_Simulation, MFT_Species_Handler
6
+ from .postprocess import PostProcess
7
+ from .pressure_correction import PressureCorrection_Diagnostic, PressureCorrection_Simulation, PressureCorrection_Species_Handler
8
+
9
+ __all__ = [
10
+ "Derivative_Simulation",
11
+ "Derivative_Diagnostic",
12
+ "Derivative_Species_Handler",
13
+ "FFT_Simulation",
14
+ "FFT_Diagnostic",
15
+ "FFT_Species_Handler",
16
+ "FieldCentering_Simulation",
17
+ "FieldCentering_Diagnostic",
18
+ "HeatfluxCorrection_Simulation",
19
+ "HeatfluxCorrection_Diagnostic",
20
+ "HeatfluxCorrection_Species_Handler",
21
+ "MFT_Simulation",
22
+ "MFT_Diagnostic",
23
+ "MFT_Species_Handler",
24
+ "PostProcess",
25
+ "PressureCorrection_Simulation",
26
+ "PressureCorrection_Diagnostic",
27
+ "PressureCorrection_Species_Handler",
28
+ ]