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
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.typing import NDArray
|
|
5
|
+
from scipy.interpolate import RectBivariateSpline, RegularGridInterpolator
|
|
6
|
+
from scipy.ndimage import map_coordinates
|
|
7
|
+
|
|
8
|
+
from ..h_pypluto import check_par
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def slices(
|
|
12
|
+
self,
|
|
13
|
+
var: NDArray,
|
|
14
|
+
check: bool = True,
|
|
15
|
+
diag: bool | None = None,
|
|
16
|
+
x1: int | list | None = None,
|
|
17
|
+
x2: int | list | None = None,
|
|
18
|
+
x3: int | list | None = None,
|
|
19
|
+
**kwargs: Any,
|
|
20
|
+
) -> np.ndarray:
|
|
21
|
+
"""Function that slices the variable in the 3 directions. Also, it
|
|
22
|
+
can slice the diagonal of the variable.
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
- newvar: NDArray
|
|
27
|
+
The sliced variable.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
- axis1: int | None, default None
|
|
32
|
+
Axis to be used as the first axis of the 2-D sub-arrays from which the
|
|
33
|
+
diagonals should be taken. Defaults to first axis (0).
|
|
34
|
+
- axis2: int | None, default None
|
|
35
|
+
Axis to be used as the second axis of the 2-D sub-arrays from which the
|
|
36
|
+
diagonals should be taken. Defaults to second axis (1).
|
|
37
|
+
- diag: bool | None, default None
|
|
38
|
+
If not None (or 'min'), slice the main diagonal of the variable.
|
|
39
|
+
If 'min', slice the opposite diagonal.
|
|
40
|
+
- offset: int | None, default None
|
|
41
|
+
Offset of the diagonal from the main diagonal. Can be positive or
|
|
42
|
+
negative. Defaults to main diagonal (0).
|
|
43
|
+
- var: np.ndarray
|
|
44
|
+
The variable to slice.
|
|
45
|
+
- x1: int | list | None, default None
|
|
46
|
+
The slice in the 1st direction.
|
|
47
|
+
- x2: int | list | None, default None
|
|
48
|
+
The slice in the 2nd direction.
|
|
49
|
+
- x3: int | list | None, default None
|
|
50
|
+
The slice in the 3rd direction.
|
|
51
|
+
|
|
52
|
+
----
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
- Example #1: Slice the variable in the 3 directions
|
|
57
|
+
|
|
58
|
+
>>> slices(var, x1=0, x2=0, x3=0)
|
|
59
|
+
|
|
60
|
+
- Example #2: Slice the variable in the diagonal
|
|
61
|
+
|
|
62
|
+
>>> slices(var, diag=True)
|
|
63
|
+
|
|
64
|
+
- Example #3: Slice the variable in the opposite diagonal
|
|
65
|
+
|
|
66
|
+
>>> slices(var, diag="min")
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
# Check the kwargs parameters
|
|
70
|
+
param = {"axis1", "axis2", "offset"}
|
|
71
|
+
if check is True:
|
|
72
|
+
check_par(param, "slice", **kwargs)
|
|
73
|
+
|
|
74
|
+
# Make a copy to not modify the variable
|
|
75
|
+
newvar = np.copy(var)
|
|
76
|
+
|
|
77
|
+
# Slice the diagonal
|
|
78
|
+
if diag is not None:
|
|
79
|
+
if diag == "min":
|
|
80
|
+
newvar = np.diagonal(np.flipud(newvar), **kwargs)
|
|
81
|
+
else:
|
|
82
|
+
newvar = np.diagonal(newvar, **kwargs)
|
|
83
|
+
|
|
84
|
+
# Slice 3rd direction
|
|
85
|
+
if x3 is not None:
|
|
86
|
+
newvar = newvar[:, :, x3]
|
|
87
|
+
|
|
88
|
+
# Slice 2nd direction
|
|
89
|
+
if x2 is not None:
|
|
90
|
+
newvar = newvar[:, x2]
|
|
91
|
+
|
|
92
|
+
# Slice 1st direction
|
|
93
|
+
if x1 is not None:
|
|
94
|
+
newvar = newvar[x1]
|
|
95
|
+
|
|
96
|
+
# End of the function, return the sliced array
|
|
97
|
+
return newvar
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def mirror(
|
|
101
|
+
self, var: NDArray, dirs="l", xax=None, yax=None
|
|
102
|
+
) -> list[np.ndarray]:
|
|
103
|
+
"""Function that mirrors the variable in the specified directions.
|
|
104
|
+
Multiple directions can be specified.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
- newvar: np.ndarray
|
|
109
|
+
The mirrored variable.
|
|
110
|
+
- xax: np.ndarray
|
|
111
|
+
The mirrored x-axis.
|
|
112
|
+
- yax: np.ndarray
|
|
113
|
+
The mirrored y-axis.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
- dirs: str | list, default 'l'
|
|
118
|
+
The directions to mirror the variable. Can be 'l', 'r', 't', 'b' or a
|
|
119
|
+
list or combination of them.
|
|
120
|
+
- var: np.ndarray
|
|
121
|
+
The variable to mirror.
|
|
122
|
+
- xax: np.ndarray | None, default None
|
|
123
|
+
The x-axis to mirror.
|
|
124
|
+
- yax: np.ndarray | None, default None
|
|
125
|
+
The y-axis to mirror.
|
|
126
|
+
|
|
127
|
+
----
|
|
128
|
+
|
|
129
|
+
Examples
|
|
130
|
+
--------
|
|
131
|
+
- Example #1: Mirror the variable in the left direction
|
|
132
|
+
|
|
133
|
+
>>> mirror(var, dirs="l")
|
|
134
|
+
|
|
135
|
+
- Example #2: Mirror the variable in the right direction with axis
|
|
136
|
+
|
|
137
|
+
>>> mirror(var, dirs="r", xax=xax)
|
|
138
|
+
|
|
139
|
+
- Example #3: Mirror the variable in the top and left directions
|
|
140
|
+
|
|
141
|
+
>>> mirror(var, dirs=["t", "l"])
|
|
142
|
+
|
|
143
|
+
- Example #4: Mirror the variable in the top and left directions (no list)
|
|
144
|
+
|
|
145
|
+
>>> mirror(var, dirs="tl")
|
|
146
|
+
|
|
147
|
+
- Example #5: Mirror the variable in the left direction three times
|
|
148
|
+
|
|
149
|
+
>>> mirror(var, dirs="lll")
|
|
150
|
+
|
|
151
|
+
"""
|
|
152
|
+
spp = [*dirs] if not isinstance(dirs, list) else dirs
|
|
153
|
+
newvar, axx, axy = np.copy(var), np.copy(xax), np.copy(yax)
|
|
154
|
+
dim = np.ndim(var) - 1
|
|
155
|
+
if dim > 1:
|
|
156
|
+
raise ValueError("Mirror function does not works for 3D arrays")
|
|
157
|
+
nax = []
|
|
158
|
+
for dir in spp:
|
|
159
|
+
lvx = len(newvar[:, 0]) if dim == 1 else len(var)
|
|
160
|
+
lvy = len(newvar[0, :]) if dim == 1 else len(var)
|
|
161
|
+
choices = {
|
|
162
|
+
"l": [(lvx, 0), ((lvx, 0), (0, 0))],
|
|
163
|
+
"r": [(0, lvx), ((0, lvx), (0, 0))],
|
|
164
|
+
"t": [(0, lvy), ((0, 0), (0, lvy))],
|
|
165
|
+
"b": [(lvy, 0), ((0, 0), (lvy, 0))],
|
|
166
|
+
}
|
|
167
|
+
newvar = np.pad(newvar, choices[dir][dim], "symmetric")
|
|
168
|
+
if xax is not None and dir in {"l", "r"}:
|
|
169
|
+
axx = np.pad(axx, choices[dir][0], "reflect", reflect_type="odd")
|
|
170
|
+
if yax is not None and dir in {"t", "b"}:
|
|
171
|
+
axy = np.pad(axy, choices[dir][0], "reflect", reflect_type="odd")
|
|
172
|
+
xax is not None and nax.append(axx)
|
|
173
|
+
yax is not None and nax.append(axy)
|
|
174
|
+
if len(nax) > 1:
|
|
175
|
+
return newvar, nax
|
|
176
|
+
elif len(nax) > 0:
|
|
177
|
+
return newvar, nax[0]
|
|
178
|
+
else:
|
|
179
|
+
return newvar
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def repeat(
|
|
183
|
+
self,
|
|
184
|
+
var: NDArray,
|
|
185
|
+
dirs: str | list,
|
|
186
|
+
xax: NDArray | None = None,
|
|
187
|
+
yax: NDArray | None = None,
|
|
188
|
+
) -> np.ndarray:
|
|
189
|
+
"""Function that repeats the variable in the specified directions.
|
|
190
|
+
Multiple directions can be specified.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
- newvar: np.ndarray
|
|
195
|
+
The repeated variable.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
- dirs: str | list
|
|
200
|
+
The directions to repeat the variable. Can be 'l', 'r', 't', 'b' or a
|
|
201
|
+
list or combination of them.
|
|
202
|
+
- var: np.ndarray
|
|
203
|
+
The variable to repeat.
|
|
204
|
+
- xax: np.ndarray | None, default None
|
|
205
|
+
The x-axis to repeat.
|
|
206
|
+
- yax: np.ndarray | None, default None
|
|
207
|
+
The y-axis to repeat.
|
|
208
|
+
|
|
209
|
+
----
|
|
210
|
+
|
|
211
|
+
Examples
|
|
212
|
+
--------
|
|
213
|
+
- Example #1: Repeat the variable in the left direction
|
|
214
|
+
|
|
215
|
+
>>> repeat(var, dirs="l")
|
|
216
|
+
|
|
217
|
+
- Example #2: Repeat the variable in the right direction with axis
|
|
218
|
+
|
|
219
|
+
>>> repeat(var, dirs="r", xax=xax)
|
|
220
|
+
|
|
221
|
+
- Example #3: Repeat the variable in the top and left directions
|
|
222
|
+
|
|
223
|
+
>>> repeat(var, dirs=["t", "l"])
|
|
224
|
+
|
|
225
|
+
- Example #4: Repeat the variable in the top and left directions (no list)
|
|
226
|
+
|
|
227
|
+
>>> repeat(var, dirs="tl")
|
|
228
|
+
|
|
229
|
+
"""
|
|
230
|
+
raise NotImplementedError("Function repeat not implemented yet")
|
|
231
|
+
|
|
232
|
+
spp = [*dirs] if not isinstance(dirs, list) else dirs
|
|
233
|
+
newvar, axx, axy = np.copy(var), np.copy(xax), np.copy(yax)
|
|
234
|
+
|
|
235
|
+
for dir in spp:
|
|
236
|
+
lvx = len(newvar[:, 0])
|
|
237
|
+
lvy = len(newvar[0, :])
|
|
238
|
+
choices = {
|
|
239
|
+
"l": [(lvx, 0), ((lvx, 0), (0, 0))],
|
|
240
|
+
"r": [(0, lvx), ((0, lvx), (0, 0))],
|
|
241
|
+
"t": [(0, lvy), ((0, 0), (0, lvy))],
|
|
242
|
+
"b": [(lvy, 0), ((0, 0), (lvy, 0))],
|
|
243
|
+
}
|
|
244
|
+
newvar = np.pad(newvar, choices[dir][1], "wrap")
|
|
245
|
+
if xax is not None and dir in {"l", "r"}:
|
|
246
|
+
axx = np.pad(axx, choices[dir][0], "wrap")
|
|
247
|
+
if yax is not None and dir in {"t", "b"}:
|
|
248
|
+
axy = np.pad(axy, choices[dir][0], "wrap")
|
|
249
|
+
|
|
250
|
+
if xax is not None and yax is not None:
|
|
251
|
+
return newvar, axx, axy
|
|
252
|
+
elif xax is not None:
|
|
253
|
+
return newvar, axx
|
|
254
|
+
elif yax is not None:
|
|
255
|
+
return newvar, axy
|
|
256
|
+
else:
|
|
257
|
+
return newvar
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def cartesian_vector(
|
|
261
|
+
self, var: str | None = None, **kwargs: Any
|
|
262
|
+
) -> tuple[NDArray, ...]:
|
|
263
|
+
"""Function that converts a vector from spherical or polar
|
|
264
|
+
components to cartesian components.
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
- newvar: tuple(np.ndarray)
|
|
269
|
+
The converted vector components.
|
|
270
|
+
|
|
271
|
+
Parameters
|
|
272
|
+
----------
|
|
273
|
+
- transpose: bool, default False
|
|
274
|
+
If True, the variable is transposed.
|
|
275
|
+
- var: np.ndarray
|
|
276
|
+
The variable to convert.
|
|
277
|
+
- var1: np.ndarray
|
|
278
|
+
The first variable to convert if var is not used.
|
|
279
|
+
- var2: np.ndarray
|
|
280
|
+
The second variable to convert if var is not used.
|
|
281
|
+
- var3: np.ndarray
|
|
282
|
+
The third variable to convert if var is not used.
|
|
283
|
+
- x1: int
|
|
284
|
+
The first index of the variable.
|
|
285
|
+
- x2: int
|
|
286
|
+
The second index of the variable.
|
|
287
|
+
|
|
288
|
+
----
|
|
289
|
+
|
|
290
|
+
Examples
|
|
291
|
+
--------
|
|
292
|
+
- Example #1: Convert the vector from spherical to cartesian components
|
|
293
|
+
|
|
294
|
+
>>> Bx, By, Bz = cartesian_vector(var="B")
|
|
295
|
+
|
|
296
|
+
- Example #2: Convert the vector from polar to cartesian components
|
|
297
|
+
|
|
298
|
+
>>> Bx, By = cartesian_vector(var1=D.Bx1, var2=D.Bx2)
|
|
299
|
+
|
|
300
|
+
"""
|
|
301
|
+
vars = {
|
|
302
|
+
"B": ["Bx1", "Bx2", "Bx3"],
|
|
303
|
+
"E": ["Ex1", "Ex2", "Ex3"],
|
|
304
|
+
"v": ["vx1", "vx2", "vx3"],
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if var is not None:
|
|
308
|
+
var_0 = [
|
|
309
|
+
self._check_var(v, kwargs.get("transpose", False))
|
|
310
|
+
for v in vars[var]
|
|
311
|
+
]
|
|
312
|
+
elif "var1" in kwargs and "var2" in kwargs:
|
|
313
|
+
var_0 = [
|
|
314
|
+
self._check_var(kwargs["var1"], kwargs.get("transpose", False)),
|
|
315
|
+
self._check_var(kwargs["var2"], kwargs.get("transpose", False)),
|
|
316
|
+
]
|
|
317
|
+
else:
|
|
318
|
+
raise ValueError("Either var or var1 and var2 must be specified.")
|
|
319
|
+
|
|
320
|
+
if "var3" in kwargs:
|
|
321
|
+
var_0.append(
|
|
322
|
+
self._check_var(kwargs["var3"], kwargs.get("transpose", False))
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# x1 = kwargs.get("x1", self.x1)
|
|
326
|
+
x2 = kwargs.get("x2", self.x2)
|
|
327
|
+
x3 = kwargs.get("x3", self.x3)
|
|
328
|
+
|
|
329
|
+
if self.geom == "SPHERICAL":
|
|
330
|
+
varr = var_0[0] * np.sin(x2) + var_0[1] * np.cos(x2)
|
|
331
|
+
varz = var_0[0] * np.cos(x2) - var_0[1] * np.sin(x2)
|
|
332
|
+
if self.dim == 3:
|
|
333
|
+
varx = varr * np.cos(x3) - var_0[2] * np.sin(x3)
|
|
334
|
+
vary = varr * np.sin(x3) + var_0[2] * np.cos(x3)
|
|
335
|
+
if kwargs.get("fullout", False):
|
|
336
|
+
return varx, vary, varz, varr
|
|
337
|
+
else:
|
|
338
|
+
return varx, vary, varz
|
|
339
|
+
else:
|
|
340
|
+
return varr, varz
|
|
341
|
+
|
|
342
|
+
elif self.geom == "POLAR":
|
|
343
|
+
varx = var_0[0] * np.cos(x2) - var_0[1] * np.sin(x2)
|
|
344
|
+
vary = var_0[0] * np.sin(x2) + var_0[1] * np.cos(x2)
|
|
345
|
+
return varx, vary
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def reshape_cartesian(self, *args: Any, **kwargs: Any) -> tuple[NDArray, ...]:
|
|
349
|
+
"""Function that reshapes a variable from a cylindrical or spherical
|
|
350
|
+
grid into a cartesian grid. Zones not covered by the original domain
|
|
351
|
+
(e.g. the very inner radial regions) are also interpolated. At the
|
|
352
|
+
current stage, the transformation is only in 2D.
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
- newvar: tuple(np.ndarray)
|
|
357
|
+
The converted variable.
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
- nx1: int, default len(x1)
|
|
362
|
+
The number of grid points in the first direction.
|
|
363
|
+
- nx2: int, default len(x2)
|
|
364
|
+
The number of grid points in the second direction.
|
|
365
|
+
- transpose: bool, default False
|
|
366
|
+
If True, the variable is transposed.
|
|
367
|
+
- var: np.ndarray
|
|
368
|
+
The variable to convert.
|
|
369
|
+
- x1: int
|
|
370
|
+
The first index of the variable.
|
|
371
|
+
- x2: int
|
|
372
|
+
The second index of the variable.
|
|
373
|
+
|
|
374
|
+
----
|
|
375
|
+
|
|
376
|
+
Examples
|
|
377
|
+
--------
|
|
378
|
+
- Example #1: Convert the vector from spherical to cartesian components
|
|
379
|
+
|
|
380
|
+
>>> Bx, By, Bz = cartesian_vector(var="B")
|
|
381
|
+
|
|
382
|
+
- Example #2: Convert the vector from polar to cartesian components
|
|
383
|
+
|
|
384
|
+
>>> Bx, By = cartesian_vector(var1=D.Bx1, var2=D.Bx2)
|
|
385
|
+
|
|
386
|
+
"""
|
|
387
|
+
# Get the variable, if it is a string, get the variable from the dataset.
|
|
388
|
+
# The .T is used to transpose the variable to the correct shape.
|
|
389
|
+
vars = []
|
|
390
|
+
newv = []
|
|
391
|
+
for i in args:
|
|
392
|
+
vars.append(self._check_var(i, kwargs.get("transpose", False)))
|
|
393
|
+
|
|
394
|
+
# Get the grid information
|
|
395
|
+
x1 = kwargs.pop("x1", self.x1)
|
|
396
|
+
x2 = kwargs.pop("x2", self.x2)
|
|
397
|
+
|
|
398
|
+
# Get the grid limits
|
|
399
|
+
xx = x1[:, np.newaxis] * np.cos(x2)
|
|
400
|
+
yy = x1[:, np.newaxis] * np.sin(x2)
|
|
401
|
+
|
|
402
|
+
xmin, xmax = xx.min(), xx.max()
|
|
403
|
+
ymin, ymax = yy.min(), yy.max()
|
|
404
|
+
|
|
405
|
+
del xx, yy
|
|
406
|
+
|
|
407
|
+
# Get the number of grid points of the new grid
|
|
408
|
+
nx1 = int(kwargs.get("nx1", len(x1)))
|
|
409
|
+
nx2 = int(kwargs.get("nx2", nx1 * (ymax - ymin) / (xmax - xmin)))
|
|
410
|
+
# nx2 = int(kwargs.get('nx2', nx1*(ymax-ymin)//(xmax-xmin)))
|
|
411
|
+
|
|
412
|
+
# Get the cartesian grid
|
|
413
|
+
|
|
414
|
+
if self.geom == "SPHERICAL":
|
|
415
|
+
xc0 = np.linspace(xmin, xmax, nx2)
|
|
416
|
+
yc0 = np.linspace(ymin, ymax, nx1)
|
|
417
|
+
xc, yc = np.meshgrid(xc0, yc0, indexing="xy")
|
|
418
|
+
else:
|
|
419
|
+
xc0 = np.linspace(xmin, xmax, nx1)
|
|
420
|
+
yc0 = np.linspace(ymin, ymax, nx2)
|
|
421
|
+
xc, yc = np.meshgrid(xc0, yc0, indexing="ij")
|
|
422
|
+
|
|
423
|
+
# Create the new grid
|
|
424
|
+
x1, x2, vars = self.reshape_uniform(x1, x2, *vars, **kwargs)
|
|
425
|
+
|
|
426
|
+
# Convert grid
|
|
427
|
+
ww, nn = _convert2cartgrid(xc, yc, x1, x2)
|
|
428
|
+
|
|
429
|
+
xcong = self._congrid(xc, (nx1, nx2), method="linear")
|
|
430
|
+
ycong = self._congrid(yc, (nx1, nx2), method="linear")
|
|
431
|
+
|
|
432
|
+
for i, var in enumerate(vars):
|
|
433
|
+
newv.append(np.sum([ww[j] * var.flat[nn[j]] for j in range(4)], axis=0))
|
|
434
|
+
newv[i] = self._congrid(newv[i], (nx1, nx2), method="linear")
|
|
435
|
+
|
|
436
|
+
if self.geom == "SPHERICAL":
|
|
437
|
+
return ycong[:, 0], xcong[0], *newv
|
|
438
|
+
else:
|
|
439
|
+
return xcong[:, 0], ycong[0], *newv
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def reshape_uniform(self, x1, x2, *args, **kwargs):
|
|
443
|
+
"""Reshapes a non-uniform (cartesian) 2D grid into a uniform grid.
|
|
444
|
+
|
|
445
|
+
Returns
|
|
446
|
+
-------
|
|
447
|
+
tuple: A tuple containing the reshaped x1, x2, varx, and vary.
|
|
448
|
+
|
|
449
|
+
Parameters
|
|
450
|
+
----------
|
|
451
|
+
- nx1: int, default len(x1)
|
|
452
|
+
The number of grid points in the first direction.
|
|
453
|
+
- nx2: int, default len(x2)
|
|
454
|
+
The number of grid points in the second direction.
|
|
455
|
+
- transpose: bool, default False
|
|
456
|
+
If True, the variable is transposed.
|
|
457
|
+
- var: np.ndarray
|
|
458
|
+
The variable to convert.
|
|
459
|
+
- x1: int
|
|
460
|
+
The first index of the variable.
|
|
461
|
+
- x2: int
|
|
462
|
+
The second index of the variable.
|
|
463
|
+
|
|
464
|
+
----
|
|
465
|
+
|
|
466
|
+
Examples
|
|
467
|
+
--------
|
|
468
|
+
- Example #1: Reshape the grid into a uniform grid
|
|
469
|
+
|
|
470
|
+
>>> x1new, x2new, varx = reshape_uniform(x1, x2, var)
|
|
471
|
+
|
|
472
|
+
"""
|
|
473
|
+
uniform_x = all(np.diff(x1) == np.diff(x1)[0])
|
|
474
|
+
uniform_y = all(np.diff(x2) == np.diff(x2)[0])
|
|
475
|
+
|
|
476
|
+
nx1new = kwargs.get("nx1", len(x1))
|
|
477
|
+
nx2new = kwargs.get("nx2", len(x2))
|
|
478
|
+
|
|
479
|
+
uniform_x = False if nx1new != len(x1) else uniform_x
|
|
480
|
+
uniform_y = False if nx2new != len(x2) else uniform_y
|
|
481
|
+
|
|
482
|
+
newvars = []
|
|
483
|
+
|
|
484
|
+
if not uniform_x or not uniform_y:
|
|
485
|
+
x1new = np.linspace(x1.min(), x1.max(), nx1new) if not uniform_x else x1
|
|
486
|
+
x2new = np.linspace(x2.min(), x2.max(), nx2new) if not uniform_y else x2
|
|
487
|
+
|
|
488
|
+
for i in args:
|
|
489
|
+
interp = RectBivariateSpline(x2, x1, i.T)
|
|
490
|
+
newvars.append(interp(x2new, x1new))
|
|
491
|
+
|
|
492
|
+
else:
|
|
493
|
+
x1new = x1
|
|
494
|
+
x2new = x2
|
|
495
|
+
newvars = [arg for arg in args]
|
|
496
|
+
|
|
497
|
+
return x1new, x2new, newvars
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _convert2cartgrid(R, Z, new_r, new_t):
|
|
501
|
+
"""Function that converts a grid from spherical to cartesian
|
|
502
|
+
coordinates.
|
|
503
|
+
|
|
504
|
+
Returns
|
|
505
|
+
-------
|
|
506
|
+
- newvar: tuple(np.ndarray)
|
|
507
|
+
The new grid.
|
|
508
|
+
|
|
509
|
+
Parameters
|
|
510
|
+
----------
|
|
511
|
+
- R: np.ndarray
|
|
512
|
+
The radial grid.
|
|
513
|
+
- Z: np.ndarray
|
|
514
|
+
The vertical grid.
|
|
515
|
+
- new_r: np.ndarray
|
|
516
|
+
The new radial grid.
|
|
517
|
+
- new_t: np.ndarray
|
|
518
|
+
The new vertical grid.
|
|
519
|
+
|
|
520
|
+
----
|
|
521
|
+
|
|
522
|
+
Examples
|
|
523
|
+
--------
|
|
524
|
+
- Example #1: Convert the grid from spherical to cartesian coordinates
|
|
525
|
+
|
|
526
|
+
>>> new_r, new_t, newvar = _convert2cartgrid(R, Z, new_r, new_t)
|
|
527
|
+
|
|
528
|
+
"""
|
|
529
|
+
# Convert Cartesian coordinates (R, Z) to polar (Rs, Th)
|
|
530
|
+
Rs = np.sqrt(R**2 + Z**2)
|
|
531
|
+
|
|
532
|
+
Th = np.arctan2(Z, R)
|
|
533
|
+
Th = np.where(Th < 0, Th + 2 * np.pi, Th) # Ensure Th is in [0, 2pi]
|
|
534
|
+
|
|
535
|
+
# Clip Rs and Th to the range of the new grid
|
|
536
|
+
Rs_clipped = np.clip(Rs, new_r[0], new_r[-1])
|
|
537
|
+
Th_clipped = np.clip(Th, new_t[0], new_t[-1])
|
|
538
|
+
|
|
539
|
+
# Normalize Rs and Th to the new grid indices
|
|
540
|
+
ra = (len(new_r) - 1) * (Rs_clipped - new_r[0]) / (new_r[-1] - new_r[0])
|
|
541
|
+
tha = (len(new_t) - 1) * (Th_clipped - new_t[0]) / (new_t[-1] - new_t[0])
|
|
542
|
+
|
|
543
|
+
# Get the integer and fractional parts of the grid indices
|
|
544
|
+
rn, dra = np.divmod(ra, 1)
|
|
545
|
+
thn, dtha = np.divmod(tha, 1)
|
|
546
|
+
rn, thn = rn.astype(int), thn.astype(int)
|
|
547
|
+
|
|
548
|
+
# Ensure indices are within bounds
|
|
549
|
+
rn = np.clip(rn, 0, len(new_r) - 2)
|
|
550
|
+
thn = np.clip(thn, 0, len(new_t) - 2)
|
|
551
|
+
|
|
552
|
+
# Bilinear interpolation
|
|
553
|
+
lrx = len(new_r)
|
|
554
|
+
NN1 = rn + thn * lrx
|
|
555
|
+
NN2 = (rn + 1) + thn * lrx
|
|
556
|
+
NN3 = rn + (thn + 1) * lrx
|
|
557
|
+
NN4 = (rn + 1) + (thn + 1) * lrx
|
|
558
|
+
|
|
559
|
+
w1 = (1 - dra) * (1 - dtha)
|
|
560
|
+
w2 = dra * (1 - dtha)
|
|
561
|
+
w3 = (1 - dra) * dtha
|
|
562
|
+
w4 = dra * dtha
|
|
563
|
+
|
|
564
|
+
return [w1, w2, w3, w4], [NN1, NN2, NN3, NN4]
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def _congrid(self, a, newdims, method="linear", center=False, minusone=False):
|
|
568
|
+
"""Arbitrary resampling of source array to new dimension sizes.
|
|
569
|
+
|
|
570
|
+
Returns
|
|
571
|
+
-------
|
|
572
|
+
- The resampled array.
|
|
573
|
+
|
|
574
|
+
Parameters
|
|
575
|
+
----------
|
|
576
|
+
- a: np.ndarray
|
|
577
|
+
The array to be resampled.
|
|
578
|
+
- newdims: tuple
|
|
579
|
+
The new dimension sizes.
|
|
580
|
+
- method: str, default 'linear'
|
|
581
|
+
The interpolation method to be used.
|
|
582
|
+
- center: bool, default False
|
|
583
|
+
If True, centers the resampled array at the new dimensions.
|
|
584
|
+
- minusone: bool, default False
|
|
585
|
+
If True, the new dimensions should be larger by 1 in each dimension.
|
|
586
|
+
|
|
587
|
+
----
|
|
588
|
+
|
|
589
|
+
Examples
|
|
590
|
+
--------
|
|
591
|
+
- Example #1: Resample the grid
|
|
592
|
+
|
|
593
|
+
>>> newvar = _congrid(newvar, (10, 10))
|
|
594
|
+
|
|
595
|
+
"""
|
|
596
|
+
# Based on IDL's congrid routine
|
|
597
|
+
# Ensure input is a floating-point array for interpolation
|
|
598
|
+
a = a.astype(float, copy=False)
|
|
599
|
+
|
|
600
|
+
olddims = np.array(a.shape)
|
|
601
|
+
newdims = np.asarray(newdims, dtype=int)
|
|
602
|
+
|
|
603
|
+
if olddims.size != newdims.size:
|
|
604
|
+
raise ValueError(
|
|
605
|
+
"Dimension mismatch: newdims must have the same number \
|
|
606
|
+
of dimensions as the input array."
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
m1 = int(minusone)
|
|
610
|
+
ofs = 0.5 if center else 0.0
|
|
611
|
+
|
|
612
|
+
# Generate the original grid
|
|
613
|
+
old_grid = [np.arange(n) for n in olddims]
|
|
614
|
+
|
|
615
|
+
# Generate the new grid, scaled to match the new dimensions
|
|
616
|
+
new_grid = np.meshgrid(
|
|
617
|
+
*[
|
|
618
|
+
np.linspace(ofs, olddims[i] - 1 - ofs, num=newdims[i])
|
|
619
|
+
for i in range(len(olddims))
|
|
620
|
+
],
|
|
621
|
+
indexing="ij",
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
# Stack the coordinates for RegularGridInterpolator
|
|
625
|
+
new_coords = np.stack(new_grid, axis=-1)
|
|
626
|
+
|
|
627
|
+
if method == "spline":
|
|
628
|
+
# Use spline interpolation with map_coordinates
|
|
629
|
+
scale = (olddims - m1) / (newdims - m1)
|
|
630
|
+
coords = np.array(new_grid) * scale[:, None, None]
|
|
631
|
+
return map_coordinates(a, coords, order=3, mode="nearest")
|
|
632
|
+
|
|
633
|
+
else:
|
|
634
|
+
# Use RegularGridInterpolator for 'linear' and 'nearest' methods
|
|
635
|
+
interpolator = RegularGridInterpolator(
|
|
636
|
+
old_grid, a, method=method, bounds_error=False, fill_value=None
|
|
637
|
+
)
|
|
638
|
+
return interpolator(new_coords)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Docstring for pyPLUTO.annotator."""
|
|
2
|
+
|
|
3
|
+
from typing import TypedDict
|
|
4
|
+
|
|
5
|
+
from matplotlib.figure import Figure
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AllKwargs(TypedDict, total=False):
|
|
9
|
+
"""Docstring for AllKwargs."""
|
|
10
|
+
|
|
11
|
+
close: bool
|
|
12
|
+
fig: Figure | None
|
|
13
|
+
figsize: list[float]
|
|
14
|
+
fontsize: int
|
|
15
|
+
fontweight: str
|
|
16
|
+
kwargscheck: bool
|
|
17
|
+
LaTeX: bool | str
|
|
18
|
+
numcolors: int
|
|
19
|
+
nwin: int
|
|
20
|
+
oldcolor: bool
|
|
21
|
+
replace: bool
|
|
22
|
+
style: str
|
|
23
|
+
suptitle: str | None
|
|
24
|
+
suptitlesize: int | str
|
|
25
|
+
tight: bool
|
|
26
|
+
withblack: bool
|
|
27
|
+
withwhite: bool
|