osiris-utils 1.1.10__py3-none-any.whl → 1.2.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 (52) hide show
  1. benchmarks/benchmark_hdf5_io.py +46 -0
  2. benchmarks/benchmark_load_all.py +54 -0
  3. docs/source/api/decks.rst +48 -0
  4. docs/source/api/postprocess.rst +66 -2
  5. docs/source/api/sim_diag.rst +1 -1
  6. docs/source/api/utilities.rst +1 -1
  7. docs/source/conf.py +2 -1
  8. docs/source/examples/example_Derivatives.md +78 -0
  9. docs/source/examples/example_FFT.md +152 -0
  10. docs/source/examples/example_InputDeck.md +148 -0
  11. docs/source/examples/example_Simulation_Diagnostic.md +213 -0
  12. docs/source/examples/quick_start.md +51 -0
  13. docs/source/examples.rst +14 -0
  14. docs/source/index.rst +8 -0
  15. examples/edited-deck.1d +1 -1
  16. examples/example_Derivatives.ipynb +24 -36
  17. examples/example_FFT.ipynb +44 -23
  18. examples/example_InputDeck.ipynb +24 -277
  19. examples/example_Simulation_Diagnostic.ipynb +27 -17
  20. examples/quick_start.ipynb +17 -1
  21. osiris_utils/__init__.py +10 -6
  22. osiris_utils/cli/__init__.py +6 -0
  23. osiris_utils/cli/__main__.py +85 -0
  24. osiris_utils/cli/export.py +199 -0
  25. osiris_utils/cli/info.py +156 -0
  26. osiris_utils/cli/plot.py +189 -0
  27. osiris_utils/cli/validate.py +247 -0
  28. osiris_utils/data/__init__.py +15 -0
  29. osiris_utils/data/data.py +41 -171
  30. osiris_utils/data/diagnostic.py +285 -274
  31. osiris_utils/data/simulation.py +20 -13
  32. osiris_utils/decks/__init__.py +4 -0
  33. osiris_utils/decks/decks.py +83 -8
  34. osiris_utils/decks/species.py +12 -9
  35. osiris_utils/postprocessing/__init__.py +28 -0
  36. osiris_utils/postprocessing/derivative.py +317 -106
  37. osiris_utils/postprocessing/fft.py +135 -24
  38. osiris_utils/postprocessing/field_centering.py +28 -14
  39. osiris_utils/postprocessing/heatflux_correction.py +39 -18
  40. osiris_utils/postprocessing/mft.py +10 -2
  41. osiris_utils/postprocessing/postprocess.py +8 -5
  42. osiris_utils/postprocessing/pressure_correction.py +29 -17
  43. osiris_utils/utils.py +26 -17
  44. osiris_utils/vis/__init__.py +3 -0
  45. osiris_utils/vis/plot3d.py +148 -0
  46. {osiris_utils-1.1.10.dist-info → osiris_utils-1.2.0.dist-info}/METADATA +55 -7
  47. {osiris_utils-1.1.10.dist-info → osiris_utils-1.2.0.dist-info}/RECORD +51 -34
  48. {osiris_utils-1.1.10.dist-info → osiris_utils-1.2.0.dist-info}/WHEEL +1 -1
  49. osiris_utils-1.2.0.dist-info/entry_points.txt +2 -0
  50. {osiris_utils-1.1.10.dist-info → osiris_utils-1.2.0.dist-info}/top_level.txt +1 -0
  51. osiris_utils/postprocessing/mft_for_gridfile.py +0 -55
  52. {osiris_utils-1.1.10.dist-info → osiris_utils-1.2.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -0,0 +1,213 @@
1
+ ```python
2
+ %load_ext autoreload
3
+ %autoreload 2
4
+ ```
5
+
6
+
7
+ ```python
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+
11
+ import osiris_utils as ou
12
+ ```
13
+
14
+ # Example notebook for the `Simulation` and `Diagnostic` classes
15
+
16
+ ### `Simulation`
17
+ The `Simulation` class takes in:
18
+ - `simulation_folder`: the folder where the input deck is located
19
+ - `species`: the species in case we are interested in diagnostics that are species-specific (such as vfl1, T11, etc.)
20
+
21
+ Acts as a wrapper for the `Diagnostic` class, allowing for an easy access to diagnostics of the simulation using a **dictionary-like** syntax.
22
+
23
+ ### `Diagnostic`
24
+
25
+ The `Diagnostic` class takes in:
26
+ - `simulation_folder`: the folder where the input deck is located
27
+ - `species`: the species in case we are interested in diagnostics that are species-specific (such as vfl1, T11, etc.)
28
+
29
+
30
+ The `Diagnostic` class has the some relevant methods and properties that you should be aware of:
31
+ - `get_quantity`: "loads" the quantity. Accessing the diagnostic through the `Simulations` using the dictionary-like syntax this will be called automatically.
32
+ - once the quantity is loaded, you can access the data at a specific time through indexing (e.g. `diag['vfl1'][0]` for the first time step). This doesn't store the data in memory, only uses a data generator to access the data (lazy loading).
33
+ - `load_all`: loads all the time steps of the quantity, storing it in memory
34
+ - `unload`: unloads the data from memory
35
+ - `time`: the time steps of the quantity at a specific index
36
+ - Has operator overloading for the `+`, `-`, `*`, `/` operators, allowing for easy manipulation of the data, even when it is not loaded in memory and is accessed through indexing.
37
+
38
+
39
+ ```python
40
+ # sim is a Simulation object
41
+ sim = ou.Simulation(input_deck_path="example_data/thermal.1d")
42
+
43
+ print("Simulation:")
44
+ print(sim)
45
+ print(sim.__dict__.keys())
46
+ print(f"\n")
47
+
48
+ # e3 is a Diagnostic object
49
+ e3 = ou.Diagnostic("example_data", "electrons")
50
+ # now we need to load the data
51
+ e3.get_quantity("e3") # it knows the path there since OSIRIS always saves the data in the same way
52
+
53
+ print("Diagnostic: (e3)")
54
+ print(e3)
55
+ print(e3.__dict__.keys())
56
+ ```
57
+
58
+ If the diagnostic that you want to access if related to a species, you need to access it by using the species name as the first key.
59
+
60
+
61
+ ```python
62
+ # An electric field if not relatec to a species, so you can access it by doing:
63
+ sim["e3"]
64
+
65
+ # To access a species-related diagnostic, you can do:
66
+ sim["electrons"]["vfl1"]
67
+
68
+ # To see the available species of a simulation, you can do:
69
+ sim.species
70
+ ```
71
+
72
+ Notice that the `Diagnostic` class does not have `data` as the data is not saved in memory if `load_all` is not called. The data is accessed through the `__getitem__` method using indexing.
73
+
74
+ To get a `Diagnostic` from a `Simulation`, you can access it through the dictionary-like syntax, where the key is the name of the diagnostic (e.g. `sim['vfl1']` is a `Diagnostic` with the `vfl1` quantity).
75
+
76
+
77
+ ```python
78
+ sim["e3"] # This is equivalent to e3
79
+
80
+ print(sim["e3"])
81
+ print(sim["e3"].__dict__.keys())
82
+ ```
83
+
84
+ If we want to access the data of the diagnostic at a specific time, we can use the indexing syntax (e.g. `sim['vfl1'][0]` for the first time step, using a `Simulation`, or `e3[0]`, using the `Diagnostic` directly).
85
+
86
+
87
+ ```python
88
+ print(sim["e3"][100].shape) # nx
89
+ print(e3[100].shape) # nx
90
+
91
+ print("Are they the same?", np.isclose(sim["e3"][100], e3[100]).all())
92
+ ```
93
+
94
+ This is useful when we want to access a specific iteration of the diagnostic, without loading all the data in memory.
95
+
96
+ For a quick plot, we can even use the other attributes of the `Diagnostic` class, such as `time`, `x` for the axis, of `axis` for info about the axis.
97
+
98
+
99
+ ```python
100
+ plt.figure(figsize=(12, 4))
101
+ plt.subplot(121)
102
+ plt.plot(sim["e3"].x, sim["e3"][100], label="Simulation", c="tab:orange")
103
+ plt.title("Using Simulation")
104
+ plt.xlabel(sim["e3"].axis[0]["plot_label"])
105
+ plt.legend()
106
+
107
+ plt.subplot(122)
108
+ plt.plot(e3.x, e3[100], label="Diagnostic", c="tab:blue")
109
+ plt.title("Using Diagnostic")
110
+ plt.xlabel(e3.axis[0]["plot_label"])
111
+ plt.legend()
112
+ plt.show()
113
+ ```
114
+
115
+ If we want to load all the data in memory, we can use the `load_all` method, which will load all the data in memory. This is useful to study how diagnostics vary in time, for example.
116
+
117
+ The data is stored in the `data` attribute of the `Diagnostic` class.
118
+
119
+ If we want to unload the data from memory, we can use the `unload` method.
120
+
121
+ From now on, I'll only use `sim[diagnostic]` to show what can be done with `Diagnostic` objects, but remember that you can access the `Diagnostic` object directly if you want to use the `load_all`, `unload`, `time`, `x`, and `axis` attributes.
122
+
123
+
124
+ ```python
125
+ sim["e3"].load_all()
126
+
127
+ # now, the data is loaded in memory
128
+ print(sim["e3"].data.shape) # (n_steps, nx)
129
+
130
+ sim["e3"].unload()
131
+ ```
132
+
133
+ Since diagnostics have operator overloading, we can easily manipulate the data, even when it is not loaded in memory. For example, we can do `sim['vfl1'] + sim['e1']` to get the sum of the two diagnostics, or `sim['vfl1'] / sim['e1']` to get the division of the two diagnostics.
134
+
135
+ When operations are done, a new `Diagnostic` is created, with the new data. This new `Diagnostic` can be accessed through the indexing syntax, and the data can be loaded in memory using the `load_all` method.
136
+
137
+
138
+ ```python
139
+ sum_of_diag = sim["electrons"]["T11"] + sim["electrons"]["vfl1"]
140
+
141
+ print(sum_of_diag)
142
+ print(sum_of_diag.__dict__.keys())
143
+ ```
144
+
145
+ We can use the method of the `Diagnostic` class as usual, for example, `load_all`, and `unload`:
146
+
147
+
148
+ ```python
149
+ # we can load all the data at once
150
+ sum_of_diag.load_all()
151
+ print(sum_of_diag.data.shape) # (n_steps, nx)
152
+ sum_of_diag.unload()
153
+ ```
154
+
155
+ And accessing a specific time step of the new `Diagnostic` is done through indexing, as usual.
156
+
157
+
158
+ ```python
159
+ plt.figure(figsize=(12, 4))
160
+ plt.subplot(121)
161
+ plt.plot(sum_of_diag.x, sum_of_diag[100], label="T11 + vfl1", c="tab:orange")
162
+ plt.title("Diagnostic from sum of two diagnostics")
163
+ plt.xlabel(sum_of_diag.axis[0]["plot_label"])
164
+ plt.legend()
165
+ plt.show()
166
+ ```
167
+
168
+ This is really useful when we want a quantity that OSIRIS doesn't provide. For example, when the pressure is adiabatic, we can calculate the pressure using the formula `P = n * T`, where `P` is the pressure, `n` is the density, and `T` is the temperature. We can calculate the pressure using the formula `P = n * T` using the `Diagnostic` class, and then use the pressure to calculate the adiabatic index `gamma = 5/3` using the formula `gamma = P / (n * T)`.
169
+
170
+
171
+ ```python
172
+ nT = -1 * sim["electrons"]["T11"] * sim["electrons"]["charge"] # -1 because we are dealing with electrons
173
+ ```
174
+
175
+
176
+ ```python
177
+ plt.figure(figsize=(6, 4))
178
+ plt.plot(nT.x, nT[100], label=r"$n_eT_{11}$", c="tab:green")
179
+ plt.title(r"$n_eT_{11}$")
180
+ plt.xlabel(nT.axis[0]["plot_label"])
181
+ plt.legend()
182
+ plt.show()
183
+ ```
184
+
185
+ If the `load_all` method is called before the operations, the whole data will be stored in the new quantity.
186
+
187
+
188
+ ```python
189
+ sim["electrons"]["vfl1"].load_all()
190
+ sim["electrons"]["charge"].load_all()
191
+
192
+ v_times_charge = sim["electrons"]["vfl1"] * sim["electrons"]["charge"]
193
+
194
+ print(v_times_charge)
195
+ print(v_times_charge.__dict__.keys())
196
+ ```
197
+
198
+ The whole data is computed if stored in the diagnostics before the operations
199
+
200
+
201
+ ```python
202
+ print(v_times_charge.data.shape)
203
+ ```
204
+
205
+ And it can be unloaded from memory using the `unload` method.
206
+
207
+
208
+ ```python
209
+ v_times_charge.unload()
210
+
211
+ # print something that checks that data is none
212
+ print("Is `v_times_charge.data` None?", v_times_charge._data is None)
213
+ ```
@@ -0,0 +1,51 @@
1
+ # Quick Start Guide
2
+
3
+ ```python
4
+ %load_ext autoreload
5
+ %autoreload 2
6
+ ```
7
+
8
+
9
+ ```python
10
+ """
11
+ Quick demonstration of osiris_utils:
12
+ • opens an OSIRIS simulation directory
13
+ • plots Ez field at t = 2000
14
+ Run with: python examples/quick_start.py <PATH_TO_RUN>
15
+ """
16
+ ```
17
+
18
+
19
+ ```python
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ import matplotlib.pyplot as plt
24
+
25
+ import osiris_utils as ou
26
+
27
+ ```
28
+
29
+
30
+ ```python
31
+ sim_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("example_data/thermal.1d")
32
+ sim = ou.Simulation(sim_path)
33
+ ```
34
+
35
+
36
+ ```python
37
+ # grab Ez diagnostic
38
+ ez = sim["e3"]
39
+ ```
40
+
41
+
42
+ ```python
43
+ # plot Ez field at iteration 220
44
+ plt.plot(ez.x, ez[220], label=f"${ez.label}$")
45
+ plt.title(rf"${ez.label}$ at t = {ez.time(220)[0]} $[{ez.time(220)[1]}]$")
46
+ plt.xlabel(ez.axis[0]["plot_label"])
47
+ plt.ylabel(f"${ez.units}$")
48
+ plt.legend()
49
+ plt.tight_layout()
50
+ plt.show()
51
+ ```
@@ -0,0 +1,14 @@
1
+ Examples
2
+ ========
3
+
4
+ This section contains examples and tutorials on how to use ``osiris_utils``.
5
+
6
+ .. toctree::
7
+ :maxdepth: 1
8
+ :caption: Tutorials:
9
+
10
+ examples/quick_start
11
+ examples/example_Simulation_Diagnostic
12
+ examples/example_InputDeck
13
+ examples/example_Derivatives
14
+ examples/example_FFT
docs/source/index.rst CHANGED
@@ -5,6 +5,13 @@ OSIRIS Utils Documentation
5
5
 
6
6
  .. include:: ../../README.rst
7
7
 
8
+ .. toctree::
9
+ :maxdepth: 2
10
+ :caption: Examples:
11
+ :hidden:
12
+
13
+ examples
14
+
8
15
  .. toctree::
9
16
  :maxdepth: 2
10
17
  :caption: Simulation and Diagnostic API:
@@ -24,6 +31,7 @@ OSIRIS Utils Documentation
24
31
  :caption: Utilities API:
25
32
  :hidden:
26
33
 
34
+ api/decks
27
35
  api/utilities
28
36
 
29
37
  .. toctree::
examples/edited-deck.1d CHANGED
@@ -55,7 +55,7 @@ diag_emf
55
55
  {
56
56
  ndump_fac = 1,
57
57
  ndump_fac_ene_int = 1,
58
- reports = "e1", "e2", "e3",
58
+ reports = "e3",
59
59
  }
60
60
 
61
61
  particles