py-pluto 1.1.4__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.
- pyPLUTO/__init__.py +22 -0
- pyPLUTO/amr.py +745 -0
- pyPLUTO/baseloadmixin.py +258 -0
- pyPLUTO/baseloadstate.py +45 -0
- pyPLUTO/codes/echo_load.py +161 -0
- pyPLUTO/configure.py +261 -0
- pyPLUTO/gui/config.py +174 -0
- pyPLUTO/gui/custom_var.py +435 -0
- pyPLUTO/gui/globals.py +108 -0
- pyPLUTO/gui/main.py +17 -0
- pyPLUTO/gui/main_window.py +177 -0
- pyPLUTO/gui/panels.py +66 -0
- pyPLUTO/gui/utils.py +273 -0
- pyPLUTO/h_pypluto.py +84 -0
- pyPLUTO/image.py +302 -0
- pyPLUTO/imagefuncs/colorbar.py +240 -0
- pyPLUTO/imagefuncs/contour.py +254 -0
- pyPLUTO/imagefuncs/create_axes.py +464 -0
- pyPLUTO/imagefuncs/display.py +306 -0
- pyPLUTO/imagefuncs/figure.py +395 -0
- pyPLUTO/imagefuncs/imagetools.py +487 -0
- pyPLUTO/imagefuncs/interactive.py +403 -0
- pyPLUTO/imagefuncs/legend.py +250 -0
- pyPLUTO/imagefuncs/plot.py +311 -0
- pyPLUTO/imagefuncs/range.py +242 -0
- pyPLUTO/imagefuncs/scatter.py +270 -0
- pyPLUTO/imagefuncs/set_axis.py +497 -0
- pyPLUTO/imagefuncs/streamplot.py +297 -0
- pyPLUTO/imagefuncs/zoom.py +428 -0
- pyPLUTO/imagemixin.py +259 -0
- pyPLUTO/imagestate.py +45 -0
- pyPLUTO/load.py +447 -0
- pyPLUTO/loadfuncs/baseloadtools.py +71 -0
- pyPLUTO/loadfuncs/codeselection.py +48 -0
- pyPLUTO/loadfuncs/defpluto.py +123 -0
- pyPLUTO/loadfuncs/descriptor.py +102 -0
- pyPLUTO/loadfuncs/findfiles.py +182 -0
- pyPLUTO/loadfuncs/findformat.py +245 -0
- pyPLUTO/loadfuncs/initload.py +203 -0
- pyPLUTO/loadfuncs/loadvars.py +227 -0
- pyPLUTO/loadfuncs/offsetdata.py +87 -0
- pyPLUTO/loadfuncs/offsetfluid.py +408 -0
- pyPLUTO/loadfuncs/read_files.py +213 -0
- pyPLUTO/loadfuncs/readdata.py +619 -0
- pyPLUTO/loadfuncs/readdata_old.py +567 -0
- pyPLUTO/loadfuncs/readdefplini.py +101 -0
- pyPLUTO/loadfuncs/readfluid.py +479 -0
- pyPLUTO/loadfuncs/readformat.py +277 -0
- pyPLUTO/loadfuncs/readgridalone.py +224 -0
- pyPLUTO/loadfuncs/readgridfile.py +255 -0
- pyPLUTO/loadfuncs/readgridout.py +451 -0
- pyPLUTO/loadfuncs/readpart.py +419 -0
- pyPLUTO/loadfuncs/readtab.py +105 -0
- pyPLUTO/loadfuncs/write_files.py +283 -0
- pyPLUTO/loadmixin.py +419 -0
- pyPLUTO/loadpart.py +233 -0
- pyPLUTO/loadstate.py +68 -0
- pyPLUTO/newload.py +81 -0
- pyPLUTO/pytools.py +145 -0
- pyPLUTO/toolfuncs/findlines.py +551 -0
- pyPLUTO/toolfuncs/fourier.py +149 -0
- pyPLUTO/toolfuncs/nabla.py +676 -0
- pyPLUTO/toolfuncs/parttools.py +152 -0
- pyPLUTO/toolfuncs/transform.py +638 -0
- pyPLUTO/utils/annotator.py +27 -0
- pyPLUTO/utils/inspector.py +145 -0
- pyPLUTO/utils/make_docstrings.py +3 -0
- py_pluto-1.1.4.dist-info/METADATA +218 -0
- py_pluto-1.1.4.dist-info/RECORD +73 -0
- py_pluto-1.1.4.dist-info/WHEEL +5 -0
- py_pluto-1.1.4.dist-info/entry_points.txt +2 -0
- py_pluto-1.1.4.dist-info/licenses/LICENSE +27 -0
- py_pluto-1.1.4.dist-info/top_level.txt +1 -0
pyPLUTO/loadpart.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LoadPart:
|
|
8
|
+
"""Load the particles from the simulation. The class is used to load
|
|
9
|
+
the particles from the simulation and store the data in the class
|
|
10
|
+
attributes. The data are loaded in a memory mapped numpy
|
|
11
|
+
multidimensional array. Such approach does not load the full data
|
|
12
|
+
until needed. Basic operations (i.e. no numpy) are possible, as well
|
|
13
|
+
as slicing the arrays, without fully loading the data. At the
|
|
14
|
+
moment, only one output can be loaded at a time.
|
|
15
|
+
|
|
16
|
+
Returns
|
|
17
|
+
-------
|
|
18
|
+
- None
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
- datatype: str, default None
|
|
23
|
+
The format of the data files to be loaded. If None, the code
|
|
24
|
+
finds the format between dbl, flt and vtk.
|
|
25
|
+
- endian: str | None, default None
|
|
26
|
+
The endianess of the data files. If None, the code finds the
|
|
27
|
+
endianess.
|
|
28
|
+
- nfile_lp: int | None, default None
|
|
29
|
+
The file number for the lp methods. If None, the code finds the
|
|
30
|
+
file number.
|
|
31
|
+
- nout: int | str | list | None, default 'last'
|
|
32
|
+
The output number to be loaded. If 'last' the last output is loaded.
|
|
33
|
+
If None, the data are not loaded.
|
|
34
|
+
- path: str, default './'
|
|
35
|
+
The path to the simulation directory.
|
|
36
|
+
- text: bool, default True
|
|
37
|
+
If True, the folder and output are printed.
|
|
38
|
+
In case the user needs a more detailed information of the structure
|
|
39
|
+
and attributes loaded from the class, the __str__ method provides a
|
|
40
|
+
easy display of all the important information.
|
|
41
|
+
- vars: str | list | bool | None, default True
|
|
42
|
+
The variables to be loaded. If True, all the variables are loaded.
|
|
43
|
+
If None, the data are not loaded.
|
|
44
|
+
|
|
45
|
+
----
|
|
46
|
+
|
|
47
|
+
Examples
|
|
48
|
+
--------
|
|
49
|
+
- Example #1: Load the last output from the simulation
|
|
50
|
+
|
|
51
|
+
>>> LoadPart()
|
|
52
|
+
|
|
53
|
+
- Example #2: Load the last output from the simulation with a specific
|
|
54
|
+
endianess
|
|
55
|
+
|
|
56
|
+
>>> LoadPart(endian="big")
|
|
57
|
+
|
|
58
|
+
- Example #3: Load the last output from the simulation with a specific
|
|
59
|
+
set of variables
|
|
60
|
+
|
|
61
|
+
>>> LoadPart(vars=["rho", "vx", "vy", "vz"])
|
|
62
|
+
|
|
63
|
+
- Example #4: Load the last output from the simulation without printing
|
|
64
|
+
the folder and the specific output loaded
|
|
65
|
+
|
|
66
|
+
>>> LoadPart(0, text=False)
|
|
67
|
+
|
|
68
|
+
- Example #5: Load the last output from the simulation without loading
|
|
69
|
+
the data
|
|
70
|
+
|
|
71
|
+
>>> LoadPart(nout=None)
|
|
72
|
+
|
|
73
|
+
- Example #6: Load the last output from the simulation with a specific
|
|
74
|
+
file number for the lp methods
|
|
75
|
+
|
|
76
|
+
>>> LoadPart(nfile_lp=1)
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
nout: int | str | None = "last",
|
|
83
|
+
path: str | Path = "./",
|
|
84
|
+
datatype: str | None = None,
|
|
85
|
+
vars: str | list[str] | bool | None = True,
|
|
86
|
+
text: bool = True,
|
|
87
|
+
endian: str | None = None,
|
|
88
|
+
nfile_lp: int | None = None,
|
|
89
|
+
) -> None:
|
|
90
|
+
# Check if the user wants to load the data
|
|
91
|
+
if nout is None:
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
# Initialization or declaration of variables (used in this file)
|
|
95
|
+
self.nout: NDArray # Output to be loaded
|
|
96
|
+
self._d_end: dict[str | None, str | None] # Endianess dictionary
|
|
97
|
+
self._multiple: bool # Bool for single or multiple files
|
|
98
|
+
self._alone: bool = True # Bool for standalone files
|
|
99
|
+
self._info: bool # Bool for info (linked to alone)
|
|
100
|
+
self._d_vars: dict = {} # The dictionary of variables
|
|
101
|
+
|
|
102
|
+
# Initialization or declaration of variables (used in other files)
|
|
103
|
+
self.pathdir: Path # Path to the simulation directory
|
|
104
|
+
self.format: str | None = None # The format of the files to be loaded
|
|
105
|
+
self._charsize: int # The data size in the files
|
|
106
|
+
self.outlist: NDArray # The list of outputs to be loaded
|
|
107
|
+
self.timelist: NDArray # The list of times to be loaded
|
|
108
|
+
self._lennout: int # The number of outputs to be loaded
|
|
109
|
+
self.ntime: NDArray # The time array
|
|
110
|
+
self._d_info: dict[str, Any] # Info dictionary
|
|
111
|
+
self.set_vars: set[str] # The set of variables to be loaded
|
|
112
|
+
self.set_outs: set[int] # The set of outputs to be loaded
|
|
113
|
+
self._matching_files: list[str] # The list of files to be loaded
|
|
114
|
+
self._pathgrid: Path # Path to the grid file
|
|
115
|
+
self._pathdata: Path | None = (
|
|
116
|
+
None # Path to the data files to be loaded
|
|
117
|
+
)
|
|
118
|
+
self._filepath: Path # The filepath to be loaded
|
|
119
|
+
self._load_vars: list[str] # The list of variables to be loaded
|
|
120
|
+
self._offset: dict[str, int] # The offset of the variables
|
|
121
|
+
self._shape: dict[str, tuple[int, ...]] # The shape of the variables
|
|
122
|
+
self.geom: str # The geometry of the simulation
|
|
123
|
+
self.dim: int # The dimension of the simulation
|
|
124
|
+
self.nshp: int | tuple[int, ...] # The shape of the grid
|
|
125
|
+
self._dictdim: dict # The dictionary of dimensions
|
|
126
|
+
self.nfile_lp: int | None = nfile_lp # File number for the lp methods
|
|
127
|
+
self.maxpart: int = 0 # Max number of particles in the simulation
|
|
128
|
+
self._vardim: NDArray # The dimension of the variables
|
|
129
|
+
|
|
130
|
+
# Check the input endianess
|
|
131
|
+
self._d_end = {
|
|
132
|
+
"big": ">",
|
|
133
|
+
"little": "<",
|
|
134
|
+
">": ">",
|
|
135
|
+
"<": "<",
|
|
136
|
+
None: None,
|
|
137
|
+
} # Endianess dictionary
|
|
138
|
+
|
|
139
|
+
if endian not in self._d_end.keys():
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"Invalid endianess. \
|
|
142
|
+
Valid values are {self._d_end.keys()}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if not isinstance(nfile_lp, int) and nfile_lp is not None:
|
|
146
|
+
raise ValueError(
|
|
147
|
+
"Invalid value for nfile_lp. \
|
|
148
|
+
Valid values are int or None"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Check the path and verify that it is a folder
|
|
152
|
+
self._check_pathformat(path)
|
|
153
|
+
|
|
154
|
+
# Find the format of the data files
|
|
155
|
+
self._find_format(datatype, True)
|
|
156
|
+
|
|
157
|
+
# Find relevant informations without opening the files (e.g.
|
|
158
|
+
# the number of files to be loaded)
|
|
159
|
+
self._findfiles(nout)
|
|
160
|
+
|
|
161
|
+
# For every output, load the desired variables and store
|
|
162
|
+
# them in the class
|
|
163
|
+
for i, exout in enumerate(self.nout):
|
|
164
|
+
self._load_variables(vars, i, exout, endian)
|
|
165
|
+
if self.format != "vtk":
|
|
166
|
+
self._store_bin_particles(i)
|
|
167
|
+
else:
|
|
168
|
+
self._store_vtk_particles(i)
|
|
169
|
+
|
|
170
|
+
# Assign the variables to the class
|
|
171
|
+
for key in self._d_vars:
|
|
172
|
+
setattr(self, key, self._d_vars[key])
|
|
173
|
+
|
|
174
|
+
# Change the id variable to int depending on the format loaded
|
|
175
|
+
if self.format != "vtk":
|
|
176
|
+
self.id = self.id.astype("int")
|
|
177
|
+
else:
|
|
178
|
+
self.id = self.id.view(">i4")
|
|
179
|
+
|
|
180
|
+
# Print loaded folder and output
|
|
181
|
+
if text is not False:
|
|
182
|
+
_nout_out = self.nout[0] if len(self.nout) == 1 else list(self.nout)
|
|
183
|
+
print(f"LoadPart: folder {path}, output {_nout_out}")
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
def __str__(self):
|
|
187
|
+
text = f"""
|
|
188
|
+
LoadPart class.
|
|
189
|
+
It loads the particles.
|
|
190
|
+
|
|
191
|
+
File properties:
|
|
192
|
+
- Current path loaded (pathdir) {self.pathdir}
|
|
193
|
+
- Format loaded (format) {self.format}
|
|
194
|
+
|
|
195
|
+
Simulation properties
|
|
196
|
+
- N. particles (maxpart) {self.maxpart}
|
|
197
|
+
- Output loaded (nout) {self.nout}
|
|
198
|
+
- Time loaded (ntime) {self.ntime}
|
|
199
|
+
|
|
200
|
+
Variables loaded:
|
|
201
|
+
{self._d_vars.keys()}
|
|
202
|
+
|
|
203
|
+
Public methods available:
|
|
204
|
+
|
|
205
|
+
- select
|
|
206
|
+
- spectrum
|
|
207
|
+
|
|
208
|
+
Please refrain from using "private" methods and attributes.
|
|
209
|
+
"""
|
|
210
|
+
return text
|
|
211
|
+
|
|
212
|
+
def __getattr__(self, name):
|
|
213
|
+
try:
|
|
214
|
+
return object.__getattribute__(self, f"_{name}")
|
|
215
|
+
except AttributeError:
|
|
216
|
+
raise AttributeError(f"'LoadPart' object has no attribute '{name}'")
|
|
217
|
+
|
|
218
|
+
from .loadfuncs.readdata_old import (
|
|
219
|
+
_assign_var,
|
|
220
|
+
_check_nout,
|
|
221
|
+
_findfiles,
|
|
222
|
+
_init_vardict,
|
|
223
|
+
_load_variables,
|
|
224
|
+
)
|
|
225
|
+
from .loadfuncs.readformat import _check_pathformat, _find_format
|
|
226
|
+
from .loadfuncs.readpart import (
|
|
227
|
+
_compute_offset,
|
|
228
|
+
_inspect_bin,
|
|
229
|
+
_inspect_vtk,
|
|
230
|
+
_store_bin_particles,
|
|
231
|
+
_store_vtk_particles,
|
|
232
|
+
)
|
|
233
|
+
from .toolfuncs.parttools import select, spectrum
|
pyPLUTO/loadstate.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Module that contains the LoadState class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
from pyPLUTO.baseloadstate import BaseLoadState
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class LoadState(BaseLoadState):
|
|
13
|
+
"""Class that stores the state of the Load class.
|
|
14
|
+
|
|
15
|
+
Its purpose is to keep track of the current state of the data loading,
|
|
16
|
+
such as the file paths, data arrays, and other properties and update the
|
|
17
|
+
key attributes through all the different classes that handle the data
|
|
18
|
+
loading at runtime.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# pylint: disable=too-many-instance-attributes
|
|
22
|
+
|
|
23
|
+
defh: dict = field(init=False, repr=False)
|
|
24
|
+
dim: int = field(init=False)
|
|
25
|
+
dx1: NDArray[Any] = field(init=False)
|
|
26
|
+
dx2: NDArray[Any] = field(init=False)
|
|
27
|
+
dx3: NDArray[Any] = field(init=False)
|
|
28
|
+
full3D: bool = False
|
|
29
|
+
geom: str = field(init=False)
|
|
30
|
+
|
|
31
|
+
gridsize: int = field(init=False)
|
|
32
|
+
gridsize_st1: int = field(init=False)
|
|
33
|
+
gridsize_st2: int = field(init=False)
|
|
34
|
+
gridsize_st3: int = field(init=False)
|
|
35
|
+
level: int = 0
|
|
36
|
+
|
|
37
|
+
nshp: int | tuple[int, ...] = field(init=False)
|
|
38
|
+
nshp_st1: int | tuple[int, ...] | None = field(init=False)
|
|
39
|
+
nshp_st2: tuple[int, ...] | None = field(init=False)
|
|
40
|
+
nshp_st3: tuple[int, ...] | None = field(init=False)
|
|
41
|
+
nx1: int = field(init=False)
|
|
42
|
+
nx2: int = field(init=False)
|
|
43
|
+
nx3: int = field(init=False)
|
|
44
|
+
|
|
45
|
+
plini: dict = field(init=False, repr=False)
|
|
46
|
+
|
|
47
|
+
x1: NDArray[Any] = field(init=False)
|
|
48
|
+
x1c: NDArray[Any] = field(init=False, repr=False)
|
|
49
|
+
x1p: NDArray[Any] = field(init=False, repr=False)
|
|
50
|
+
x1r: NDArray[Any] = field(init=False)
|
|
51
|
+
x1rc: NDArray[Any] = field(init=False, repr=False)
|
|
52
|
+
x1rp: NDArray[Any] = field(init=False, repr=False)
|
|
53
|
+
x1rt: NDArray[Any] = field(init=False, repr=False)
|
|
54
|
+
x1t: NDArray[Any] = field(init=False, repr=False)
|
|
55
|
+
|
|
56
|
+
x2: NDArray[Any] = field(init=False)
|
|
57
|
+
x2c: NDArray[Any] = field(init=False, repr=False)
|
|
58
|
+
x2p: NDArray[Any] = field(init=False, repr=False)
|
|
59
|
+
x2r: NDArray[Any] = field(init=False)
|
|
60
|
+
x2rc: NDArray[Any] = field(init=False, repr=False)
|
|
61
|
+
x2rp: NDArray[Any] = field(init=False, repr=False)
|
|
62
|
+
|
|
63
|
+
x3: NDArray[Any] = field(init=False)
|
|
64
|
+
x3c: NDArray[Any] = field(init=False, repr=False)
|
|
65
|
+
x3r: NDArray[Any] = field(init=False)
|
|
66
|
+
x3rc: NDArray[Any] = field(init=False, repr=False)
|
|
67
|
+
x3rt: NDArray[Any] = field(init=False, repr=False)
|
|
68
|
+
x3t: NDArray[Any] = field(init=False, repr=False)
|
pyPLUTO/newload.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""The Load class loads the data (fluid) from the output files."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pyPLUTO.loadfuncs.initload import InitLoadManager
|
|
6
|
+
from pyPLUTO.loadfuncs.readdefplini import FiledefpliniManager
|
|
7
|
+
from pyPLUTO.loadmixin import LoadMixin
|
|
8
|
+
from pyPLUTO.loadstate import LoadState
|
|
9
|
+
from pyPLUTO.utils.inspector import track_kwargs
|
|
10
|
+
|
|
11
|
+
# mypy: ignore-errors
|
|
12
|
+
|
|
13
|
+
#'''
|
|
14
|
+
# from pathlib import Path
|
|
15
|
+
# from typing import TypedDict, Unpack
|
|
16
|
+
# class MyKwargs(TypedDict, total=False):
|
|
17
|
+
# """TypedDict for keyword arguments."""
|
|
18
|
+
|
|
19
|
+
# code: str
|
|
20
|
+
# endian: str | None
|
|
21
|
+
# level: int
|
|
22
|
+
# multiple: bool
|
|
23
|
+
# nout: str | int | None
|
|
24
|
+
# path: str | Path
|
|
25
|
+
#'''
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Load(LoadMixin):
|
|
29
|
+
"""The Load class loads the data (fluid) from the output files.
|
|
30
|
+
|
|
31
|
+
The initialization corresponds to the loading, if wanted, of one or more
|
|
32
|
+
datafiles for the fluid. The data are loaded in a memory mapped numpy
|
|
33
|
+
multidimensional array. Such approach does not load the full data
|
|
34
|
+
until needed. Basic operations (i.e. no numpy) are possible, as well
|
|
35
|
+
as slicing the arrays, without fully loading the data.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@track_kwargs
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
nout: int | str | list[int | str] | None = "last",
|
|
42
|
+
check: bool = True,
|
|
43
|
+
**kwargs: Any,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Initialize the Load class."""
|
|
46
|
+
kwargs.pop("kwargscheck", check)
|
|
47
|
+
|
|
48
|
+
self.state: LoadState = LoadState()
|
|
49
|
+
self.text: bool | None = kwargs.get("text", self.text)
|
|
50
|
+
self.class_name: str = self.__class__.__name__
|
|
51
|
+
self.full3D: bool = kwargs.get("full3D", self.full3D)
|
|
52
|
+
self.level: int = kwargs.get("level", self.level)
|
|
53
|
+
InitLoadManager(self.state, nout, **kwargs)
|
|
54
|
+
FiledefpliniManager(self.state, **kwargs)
|
|
55
|
+
|
|
56
|
+
if self.text is not False:
|
|
57
|
+
print("Load: Load class initialized.")
|
|
58
|
+
|
|
59
|
+
def __getattr__(self, name: str) -> object:
|
|
60
|
+
"""Get the attribute of the Image class."""
|
|
61
|
+
return getattr(self.state, name)
|
|
62
|
+
|
|
63
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
64
|
+
"""Set the attribute of the Image class."""
|
|
65
|
+
if name == "state" or not hasattr(self, "state"):
|
|
66
|
+
return super().__setattr__(name, value)
|
|
67
|
+
return setattr(self.state, name, value)
|
|
68
|
+
|
|
69
|
+
from .loadfuncs.read_files import _read_dat, _read_h5, read_file
|
|
70
|
+
from .loadfuncs.write_files import _write_h5, write_file
|
|
71
|
+
from .toolfuncs.findlines import _check_var, find_contour, find_fieldlines
|
|
72
|
+
from .toolfuncs.fourier import fourier
|
|
73
|
+
from .toolfuncs.nabla import curl, divergence, gradient
|
|
74
|
+
from .toolfuncs.transform import (
|
|
75
|
+
_congrid,
|
|
76
|
+
cartesian_vector,
|
|
77
|
+
mirror,
|
|
78
|
+
reshape_cartesian,
|
|
79
|
+
reshape_uniform,
|
|
80
|
+
slices,
|
|
81
|
+
)
|
pyPLUTO/pytools.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""PyPLUTO general tools."""
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import inspect
|
|
5
|
+
import os
|
|
6
|
+
import warnings
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
|
|
11
|
+
windows = bool(importlib.util.find_spec("winsound"))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def find_example(name: str) -> Path:
|
|
15
|
+
"""Resolve the path to a test problem.
|
|
16
|
+
|
|
17
|
+
The file location is based on the *calling script's*
|
|
18
|
+
location, or fall back to $PLUTO_DIR.
|
|
19
|
+
"""
|
|
20
|
+
# Get the path of the calling file
|
|
21
|
+
caller_file = Path(inspect.stack()[1].filename).resolve()
|
|
22
|
+
base_dir = caller_file.parent
|
|
23
|
+
|
|
24
|
+
# Check if the test problem exists in the PyPLUTO Example directory
|
|
25
|
+
local_path = base_dir / "Test_Problems" / name
|
|
26
|
+
if local_path.exists():
|
|
27
|
+
return local_path
|
|
28
|
+
|
|
29
|
+
# Check if the test problem exists in the PLUTO directory
|
|
30
|
+
env_path = os.environ.get("PLUTO_DIR")
|
|
31
|
+
if env_path:
|
|
32
|
+
fallback = Path(env_path) / "Test_Problems" / name
|
|
33
|
+
if fallback.exists():
|
|
34
|
+
return fallback
|
|
35
|
+
|
|
36
|
+
# If the test problem is not found, raise an error
|
|
37
|
+
raise FileNotFoundError(
|
|
38
|
+
f"Test problem '{name}' not found near {base_dir} or in $PLUTO_DIR."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def savefig(**_kwargs: object) -> None:
|
|
43
|
+
"""Save the figure created.
|
|
44
|
+
|
|
45
|
+
This function is deprecated and will be removed in future versions.
|
|
46
|
+
Please call savefig from the Image class instead.
|
|
47
|
+
"""
|
|
48
|
+
raise NotImplementedError(
|
|
49
|
+
"pyPLUTO.savefig is deprecated.\n"
|
|
50
|
+
"Please call savefig from the Image class instead"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def show(block: bool = True) -> None:
|
|
55
|
+
"""Show the figures created.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
- None
|
|
60
|
+
|
|
61
|
+
Parameters
|
|
62
|
+
----------
|
|
63
|
+
- block: bool, default True
|
|
64
|
+
If True, the function blocks until the figure is closed.
|
|
65
|
+
|
|
66
|
+
----
|
|
67
|
+
|
|
68
|
+
Examples
|
|
69
|
+
--------
|
|
70
|
+
- Example #1: Shows the image created
|
|
71
|
+
|
|
72
|
+
>>> pp.show()
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
plt.show(block=block)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def ring(length: float = 0.5, freq: int = 440) -> None:
|
|
79
|
+
"""Make a sound for a given length and frequency.
|
|
80
|
+
|
|
81
|
+
It works on Linux, macOS and Windows.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
- length: float, default 0.5
|
|
86
|
+
The length of the sound in seconds.
|
|
87
|
+
- freq: int, default 440
|
|
88
|
+
The frequency of the sound in Hz.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
- None
|
|
93
|
+
|
|
94
|
+
----
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
- Example #1: Make a sound with a frequency of 440 Hz and a length
|
|
99
|
+
of 0.5 seconds
|
|
100
|
+
|
|
101
|
+
>>> ring()
|
|
102
|
+
|
|
103
|
+
- Example #2: Make a sound with a frequency of 880 Hz and a length
|
|
104
|
+
of 1 second
|
|
105
|
+
|
|
106
|
+
>>> ring(freq=880)
|
|
107
|
+
|
|
108
|
+
- Example #3: Make a sound with a frequency of 220 Hz and a length
|
|
109
|
+
of 0.2 seconds
|
|
110
|
+
|
|
111
|
+
>>> ring(length=0.2, freq=220)
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
# Check the OS
|
|
115
|
+
if windows is not None:
|
|
116
|
+
try:
|
|
117
|
+
# Check if the 'winsound' package is available on Windows
|
|
118
|
+
winsound = importlib.import_module("winsound")
|
|
119
|
+
if hasattr(winsound, "Beep"):
|
|
120
|
+
winsound.Beep(freq, int(length * 1000))
|
|
121
|
+
except UserWarning:
|
|
122
|
+
# If the 'winsound' package is not available, raise a warning
|
|
123
|
+
text = (
|
|
124
|
+
"pyPLUTO.ring requires the 'winsound' package.\n"
|
|
125
|
+
"Please install it through the command"
|
|
126
|
+
"\n\npip install winsound\n\nand try again."
|
|
127
|
+
)
|
|
128
|
+
warnings.warn(text, UserWarning, stacklevel=2)
|
|
129
|
+
elif os.name == "posix":
|
|
130
|
+
# Check if the 'play' command is available on Linux and macOS
|
|
131
|
+
try:
|
|
132
|
+
os.system(f"play -nq -t alsa synth {length} sine {freq}")
|
|
133
|
+
except UserWarning:
|
|
134
|
+
# If the 'play' command is not available, raise a warning
|
|
135
|
+
text = (
|
|
136
|
+
"pyPLUTO.ring requires the 'play' command from the"
|
|
137
|
+
"'sox' package. \nPlease install it through the command"
|
|
138
|
+
"\n\nsudo apt install sox \n\nand try again."
|
|
139
|
+
)
|
|
140
|
+
warnings.warn(text, UserWarning, stacklevel=2)
|
|
141
|
+
|
|
142
|
+
else:
|
|
143
|
+
# If the OS is not Linux, macOS or Windows, raise a warning
|
|
144
|
+
text = f"pyPLUTO.ring is not implemented for this OS: {os.name}"
|
|
145
|
+
warnings.warn(text, UserWarning, stacklevel=2)
|