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.
Files changed (73) hide show
  1. pyPLUTO/__init__.py +22 -0
  2. pyPLUTO/amr.py +745 -0
  3. pyPLUTO/baseloadmixin.py +258 -0
  4. pyPLUTO/baseloadstate.py +45 -0
  5. pyPLUTO/codes/echo_load.py +161 -0
  6. pyPLUTO/configure.py +261 -0
  7. pyPLUTO/gui/config.py +174 -0
  8. pyPLUTO/gui/custom_var.py +435 -0
  9. pyPLUTO/gui/globals.py +108 -0
  10. pyPLUTO/gui/main.py +17 -0
  11. pyPLUTO/gui/main_window.py +177 -0
  12. pyPLUTO/gui/panels.py +66 -0
  13. pyPLUTO/gui/utils.py +273 -0
  14. pyPLUTO/h_pypluto.py +84 -0
  15. pyPLUTO/image.py +302 -0
  16. pyPLUTO/imagefuncs/colorbar.py +240 -0
  17. pyPLUTO/imagefuncs/contour.py +254 -0
  18. pyPLUTO/imagefuncs/create_axes.py +464 -0
  19. pyPLUTO/imagefuncs/display.py +306 -0
  20. pyPLUTO/imagefuncs/figure.py +395 -0
  21. pyPLUTO/imagefuncs/imagetools.py +487 -0
  22. pyPLUTO/imagefuncs/interactive.py +403 -0
  23. pyPLUTO/imagefuncs/legend.py +250 -0
  24. pyPLUTO/imagefuncs/plot.py +311 -0
  25. pyPLUTO/imagefuncs/range.py +242 -0
  26. pyPLUTO/imagefuncs/scatter.py +270 -0
  27. pyPLUTO/imagefuncs/set_axis.py +497 -0
  28. pyPLUTO/imagefuncs/streamplot.py +297 -0
  29. pyPLUTO/imagefuncs/zoom.py +428 -0
  30. pyPLUTO/imagemixin.py +259 -0
  31. pyPLUTO/imagestate.py +45 -0
  32. pyPLUTO/load.py +447 -0
  33. pyPLUTO/loadfuncs/baseloadtools.py +71 -0
  34. pyPLUTO/loadfuncs/codeselection.py +48 -0
  35. pyPLUTO/loadfuncs/defpluto.py +123 -0
  36. pyPLUTO/loadfuncs/descriptor.py +102 -0
  37. pyPLUTO/loadfuncs/findfiles.py +182 -0
  38. pyPLUTO/loadfuncs/findformat.py +245 -0
  39. pyPLUTO/loadfuncs/initload.py +203 -0
  40. pyPLUTO/loadfuncs/loadvars.py +227 -0
  41. pyPLUTO/loadfuncs/offsetdata.py +87 -0
  42. pyPLUTO/loadfuncs/offsetfluid.py +408 -0
  43. pyPLUTO/loadfuncs/read_files.py +213 -0
  44. pyPLUTO/loadfuncs/readdata.py +619 -0
  45. pyPLUTO/loadfuncs/readdata_old.py +567 -0
  46. pyPLUTO/loadfuncs/readdefplini.py +101 -0
  47. pyPLUTO/loadfuncs/readfluid.py +479 -0
  48. pyPLUTO/loadfuncs/readformat.py +277 -0
  49. pyPLUTO/loadfuncs/readgridalone.py +224 -0
  50. pyPLUTO/loadfuncs/readgridfile.py +255 -0
  51. pyPLUTO/loadfuncs/readgridout.py +451 -0
  52. pyPLUTO/loadfuncs/readpart.py +419 -0
  53. pyPLUTO/loadfuncs/readtab.py +105 -0
  54. pyPLUTO/loadfuncs/write_files.py +283 -0
  55. pyPLUTO/loadmixin.py +419 -0
  56. pyPLUTO/loadpart.py +233 -0
  57. pyPLUTO/loadstate.py +68 -0
  58. pyPLUTO/newload.py +81 -0
  59. pyPLUTO/pytools.py +145 -0
  60. pyPLUTO/toolfuncs/findlines.py +551 -0
  61. pyPLUTO/toolfuncs/fourier.py +149 -0
  62. pyPLUTO/toolfuncs/nabla.py +676 -0
  63. pyPLUTO/toolfuncs/parttools.py +152 -0
  64. pyPLUTO/toolfuncs/transform.py +638 -0
  65. pyPLUTO/utils/annotator.py +27 -0
  66. pyPLUTO/utils/inspector.py +145 -0
  67. pyPLUTO/utils/make_docstrings.py +3 -0
  68. py_pluto-1.1.4.dist-info/METADATA +218 -0
  69. py_pluto-1.1.4.dist-info/RECORD +73 -0
  70. py_pluto-1.1.4.dist-info/WHEEL +5 -0
  71. py_pluto-1.1.4.dist-info/entry_points.txt +2 -0
  72. py_pluto-1.1.4.dist-info/licenses/LICENSE +27 -0
  73. py_pluto-1.1.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,203 @@
1
+ """Module for initialization loading functions."""
2
+
3
+ import warnings
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ import numpy as np
8
+
9
+ from pyPLUTO.baseloadmixin import BaseLoadMixin
10
+ from pyPLUTO.baseloadstate import BaseLoadState
11
+ from pyPLUTO.loadfuncs.codeselection import CodeManager
12
+ from pyPLUTO.loadfuncs.descriptor import DescriptorManager
13
+ from pyPLUTO.loadfuncs.findfiles import FindFilesManager
14
+ from pyPLUTO.loadfuncs.findformat import FindFormat
15
+ from pyPLUTO.loadfuncs.loadvars import LoadVariables
16
+ from pyPLUTO.loadstate import LoadState
17
+ from pyPLUTO.utils.inspector import track_kwargs
18
+
19
+
20
+ @track_kwargs
21
+ class InitLoadManager(BaseLoadMixin[BaseLoadState]):
22
+ """Class that handles the initialization loading process."""
23
+
24
+ def __init__(
25
+ self,
26
+ state: BaseLoadState,
27
+ nout: int | str | list[int | str] | None,
28
+ **kwargs: Any, # Unpack[MyKwargs]
29
+ ) -> None:
30
+ """Initialize the InitLoadManager class."""
31
+ self.state = state
32
+
33
+ if nout is None:
34
+ warnings.warn("No output is loaded!", UserWarning, stacklevel=2)
35
+ return
36
+
37
+ # Check the endianess
38
+ self.check_endian(kwargs.get("endian", self.endian))
39
+
40
+ # Check the input multiple
41
+ self.multiple = kwargs.get("multiple", self.multiple)
42
+ if not isinstance(self.multiple, bool):
43
+ raise TypeError("Invalid data type. 'multiple' must be a boolean.")
44
+
45
+ # Check the path
46
+ self.check_path(kwargs.get("path", self.pathdir))
47
+
48
+ self.code = kwargs.get("code", self.code)
49
+ if self.code.lower() not in {"pluto", "gpluto"}:
50
+ self.CodeManager = CodeManager(state, nout, **kwargs)
51
+ return
52
+
53
+ self.FindFormat = FindFormat(state, **kwargs)
54
+
55
+ if isinstance(state, LoadState) and not self.alone:
56
+ try:
57
+ self.Descriptor = DescriptorManager(state, nout, **kwargs)
58
+ except UserWarning:
59
+ warnings.warn(
60
+ "Failed to initialize descriptor manager.", stacklevel=2
61
+ )
62
+ self.alone = True
63
+
64
+ if not isinstance(state, LoadState) or self.alone:
65
+ self.findfile = FindFilesManager(state, nout, **kwargs)
66
+
67
+ loadvars = True
68
+ if kwargs.get("vars") is not None:
69
+ warnings.warn(
70
+ "'vars' argument is deprecated. Use 'var' instead.",
71
+ DeprecationWarning,
72
+ stacklevel=2,
73
+ )
74
+ loadvars = kwargs.get("vars", loadvars)
75
+ loadvars = kwargs.get("var", loadvars)
76
+
77
+ for i, exout in enumerate(self.noutlist):
78
+ LoadVariables(state, loadvars, i, exout)
79
+
80
+ for key in self.d_vars:
81
+ setattr(self.state, str(key), self.d_vars[key])
82
+
83
+ if isinstance(self.ntimelist, np.ndarray) and len(self.ntimelist) == 1:
84
+ self.ntime = self.ntimelist[0]
85
+ self.nout = self.noutlist[0]
86
+ else:
87
+ self.ntime = self.ntimelist
88
+ self.nout = self.noutlist
89
+
90
+ def check_endian(self, endian: str | None) -> None:
91
+ """Check the endian format.
92
+
93
+ If the endian is given, check if it is valid (either 'little' or
94
+ 'big'). If not given, set it to 'little' by default.
95
+
96
+ Parameters
97
+ ----------
98
+ endian: str | None
99
+ The endian format. If None, it is set to 'little' by default.
100
+
101
+ Returns
102
+ -------
103
+ None
104
+
105
+ Examples
106
+ --------
107
+ - Example #1: Set endian to 'big'
108
+
109
+ >>> check_endian("big")
110
+
111
+ - Example #2: Set endian to 'little'
112
+
113
+ >>> check_endian("little")
114
+
115
+ - Example #3: Set endian to default ('little')
116
+
117
+ >>> check_endian(None)
118
+
119
+ - Example #4: Invalid endian value
120
+
121
+ >>> check_endian("invalid")
122
+ ValueError: Invalid endian value. Must be 'little' or 'big'.
123
+
124
+ """
125
+ # Check the input endianess
126
+ d_end = {
127
+ "big": ">",
128
+ "little": "<",
129
+ ">": ">",
130
+ "<": "<",
131
+ None: None,
132
+ }
133
+
134
+ self.endian = endian
135
+ if endian not in d_end:
136
+ error = f"Invalid endianess. Valid values are {d_end.keys()}"
137
+ raise ValueError(error)
138
+ self.endian = d_end[endian]
139
+
140
+ def check_path(self, path: str | Path) -> None:
141
+ """Check if the given path is consistent.
142
+
143
+ If the path is given through a non- empty string or set to the default
144
+ value, If the path is consistent, it is converted to a Path object.
145
+ Then, a check is performed to see if the path is a directory. The path
146
+ is stored in the class as a Path object self.pathdir.
147
+
148
+ Returns
149
+ -------
150
+ - None
151
+
152
+ Parameters
153
+ ----------
154
+ - path (not optional): str | Path
155
+ The path to the simulation directory.
156
+
157
+ ----
158
+
159
+ Examples
160
+ --------
161
+ - Example #1: path is a string
162
+
163
+ >>> _check_pathformat("path/to/simulation")
164
+
165
+ - Example #2: path is not a string
166
+
167
+ >>> _check_pathformat(1)
168
+ TypeError: Invalid data type. 'path' must be a non-empty string.
169
+
170
+ - Example #3: path is an empty string
171
+
172
+ >>> _check_pathformat("")
173
+ ValueError: 'path' cannot be an empty string.
174
+
175
+ - Example #4: path is not a directory
176
+
177
+ >>> _check_pathformat("path/to/simulation")
178
+ NotADirectoryError: Directory path/to/simulation not found.
179
+
180
+ """
181
+ # Check if the path is a non-empty string.
182
+ if not isinstance(path, str) and not isinstance(path, Path):
183
+ error = TypeError(
184
+ "Invalid data type. 'path' must be path or string"
185
+ )
186
+ raise TypeError(error)
187
+ # Check if the path is not empty
188
+ elif not isinstance(path, Path) and not path.strip():
189
+ raise ValueError("'path' cannot be an empty string.")
190
+ # Convert the path to a Path object and store it
191
+
192
+ self.pathdir = Path(path)
193
+
194
+ if not isinstance(self.pathdir, Path):
195
+ raise TypeError(
196
+ "Invalid data type. 'path' must be or converted to Path object."
197
+ )
198
+
199
+ # Check that the path is a directory
200
+ if not self.pathdir.is_dir():
201
+ raise NotADirectoryError(f"Directory {self.pathdir} not found.")
202
+
203
+ # End of the function
@@ -0,0 +1,227 @@
1
+ """Docstring for pyPLUTO.loadfuncs.loadvars module."""
2
+
3
+ import mmap
4
+ import warnings
5
+
6
+ import numpy as np
7
+
8
+ from pyPLUTO.baseloadmixin import BaseLoadMixin
9
+ from pyPLUTO.baseloadstate import BaseLoadState
10
+ from pyPLUTO.loadfuncs.offsetdata import OffsetData
11
+
12
+
13
+ class LoadVariables(BaseLoadMixin[BaseLoadState]):
14
+ """Class that handles the loading of variables from PLUTO output files."""
15
+
16
+ def __init__(
17
+ self,
18
+ state: BaseLoadState,
19
+ variables: str | list[str] | bool | None,
20
+ index: int,
21
+ exout: int,
22
+ ) -> None:
23
+ """Initialize the LoadVariables class."""
24
+ self.state = state
25
+ self.offsetdata = OffsetData(state)
26
+ self.load_variables(variables, index, exout)
27
+
28
+ def load_variables(
29
+ self, variables: str | list[str] | bool | None, i: int, exout: int
30
+ ) -> None:
31
+ """Load the variables in the class.
32
+
33
+ The function checks if the variables to be loaded are valid and then
34
+ loads them. If the variables are not valid, an error is raised. If the
35
+ variables are valid, the function loads them in the class through memory
36
+ mapping. The offset and shape of each variable is computed depenging on
37
+ the format and typefile characteristics. In case the files are
38
+ standalone, the relevand time and grid information is loaded.
39
+
40
+ Returns
41
+ -------
42
+ - None
43
+
44
+ Parameters
45
+ ----------
46
+ - endian (not optional): bool
47
+ The endianess of the files. If True the endianess is big, otherwise
48
+ it is little.
49
+ - exout (not optional): int
50
+ The index of the output to be loaded.
51
+ - i (not optional): int
52
+ The index of the file to be loaded.
53
+ - vars (not optional): str | list[str] | bool | None, default True
54
+ If True all the variables are loaded, otherwise just a selection is
55
+ loaded.
56
+
57
+ ----
58
+
59
+ Examples
60
+ --------
61
+ - Example #1: Load all the variables
62
+
63
+ >>> _load_variables(True, 0, 0, True)
64
+
65
+ - Example #2: Load only the selected variables
66
+
67
+ >>> _load_variables(["rho", "vx1"], 0, 0, True)
68
+
69
+ - Example #3: Load all the variables (little endian)
70
+
71
+ >>> _load_variables(True, 0, 0, False)
72
+
73
+ - Example #4: Load all the variables from a specific output file
74
+
75
+ >>> _load_variables(True, 0, 1, True)
76
+
77
+ """
78
+ # Initialize mm variable to None to avoid uninitialized variable error
79
+ mm = None
80
+
81
+ # Find the class name and find the single_file filepath
82
+ if self.class_name == "Load":
83
+ # If the class name is Load (single file), the filepath is data
84
+ self.filepath = self.pathdir / (
85
+ "data" + self.d_info["endpath"][exout]
86
+ )
87
+ elif self.class_name == "LoadPart":
88
+ # If the class name is LoadPart, the filepath is particles
89
+ self.filepath = self.pathdir / (
90
+ "particles" + self.d_info["endpath"][exout]
91
+ )
92
+ else:
93
+ # If the class name is not recognized, raise an error
94
+ raise NameError("Invalid class name.")
95
+
96
+ # If files in single_file format, inspect the file
97
+ # or compute the offset and shape
98
+
99
+ if self.d_info["typefile"][exout] == "single_file":
100
+ with open(self.filepath, "rb") as fd:
101
+ kwargs = {"access": mmap.ACCESS_READ}
102
+ # if sys.version_info >= (3, 13):
103
+ # kwargs["trackfd"] = False
104
+ mm = mmap.mmap(fd.fileno(), 0, **kwargs)
105
+ self.offsetdata.compute_offset(i, exout, None, mm)
106
+ if self.format in ("hdf5", "tab"):
107
+ return None
108
+
109
+ # Check if only specific variables should be loaded
110
+ if variables is True:
111
+ # If all the variables are to be loaded, the load_vars
112
+ # is set to the variables list
113
+ load_vars = self.d_info["varslist"][exout]
114
+ elif isinstance(variables, list | str):
115
+ # If only specific variables are to be loaded, the load_vars
116
+ # becomes the list of the selected variables
117
+ load_vars = (
118
+ variables if isinstance(variables, list) else [variables]
119
+ )
120
+ else:
121
+ # If no variables are to be loaded, return None (WIP)
122
+ return None
123
+
124
+ for j in load_vars:
125
+ if self.d_info["typefile"][exout] == "multiple_files":
126
+ self.filepath = self.pathdir / (
127
+ j + self.d_info["endpath"][exout]
128
+ )
129
+ try:
130
+ with open(self.filepath, "rb") as fd:
131
+ kwargs = {"access": mmap.ACCESS_READ}
132
+ # if sys.version_info >= (3, 13):
133
+ # kwargs["trackfd"] = False
134
+ mm = mmap.mmap(fd.fileno(), 0, **kwargs)
135
+ except (OSError, ValueError) as e:
136
+ warnings.warn(
137
+ f"AttributeError: Unable to open {self.filepath}.\n"
138
+ f"{e}\nSkipping variable {j}.",
139
+ UserWarning,
140
+ stacklevel=2,
141
+ )
142
+ continue
143
+ self.offsetdata.compute_offset(i, exout, j, mm)
144
+
145
+ if self.lennout != 1:
146
+ self.init_vardict(j)
147
+
148
+ if mm is None:
149
+ raise RuntimeError("memmap object not initialized")
150
+
151
+ dtype = np.dtype(self.d_info["binformat"][exout])
152
+ shape = self.varshape[j]
153
+ offset = self.varoffset[j]
154
+ scrh = np.ndarray(
155
+ shape=shape, dtype=dtype, buffer=mm, offset=offset, order="C"
156
+ ).T
157
+
158
+ self.assign_var(exout, j, scrh)
159
+
160
+ # ... then after the variable loop ...
161
+
162
+ def assign_var(self, time: int, var: str, scrh: np.ndarray) -> None:
163
+ """Assign the variable data to the class variable.
164
+
165
+ The function assigns the data to the class variable. The variable name
166
+ is constructed based on the variable name and the output index.
167
+
168
+ Returns
169
+ -------
170
+ - None
171
+
172
+ Parameters
173
+ ----------
174
+ - exout (not optional): int
175
+ The index of the output to be loaded.
176
+ - var (not optional): str
177
+ The variable name.
178
+ - data (not optional): np.ndarray
179
+ The data to be assigned to the variable.
180
+
181
+ ----
182
+
183
+ Examples
184
+ --------
185
+ - Example #1: Assign data to a variable
186
+
187
+ >>> _assign_var(0, "rho", data)
188
+
189
+ """
190
+ # Assign the memmap object to the dictionary
191
+ if self.lennout != 1:
192
+ # If the number of outputs is not 1, the variable is stored at the
193
+ # corresponding output
194
+ self.d_vars[var][time] = scrh
195
+ else:
196
+ # If the number of outputs is 1, the variable is stored directly
197
+ self.d_vars[var] = scrh
198
+
199
+ # End of the function
200
+
201
+ def init_vardict(self, var: str) -> None:
202
+ """If not initialized, a new dictionary is created to store the vars.
203
+
204
+ The dictionary is stored in the class. The shape of the dictionary is
205
+ computed depending on the number of outputs and the variable shape.
206
+
207
+ Returns
208
+ -------
209
+ - None
210
+
211
+ Parameters
212
+ ----------
213
+ - var (not optional): str
214
+ The variable to be loaded.
215
+
216
+ ----
217
+
218
+ Examples
219
+ --------
220
+ - Example #1: Initialize the dictionary of a non-initialized variable
221
+
222
+ >>> _init_vardict("rho")
223
+
224
+ """
225
+ # If the variable is not initialized, create a new dictionary
226
+ if var not in self.d_vars:
227
+ self.d_vars[var] = {}
@@ -0,0 +1,87 @@
1
+ """Docstring for pyPLUTO.loadfuncs.offsetdata."""
2
+
3
+ import mmap
4
+
5
+ from pyPLUTO.baseloadmixin import BaseLoadMixin
6
+ from pyPLUTO.baseloadstate import BaseLoadState
7
+ from pyPLUTO.loadfuncs.offsetfluid import OffsetFluid
8
+ from pyPLUTO.loadfuncs.readgridfile import GridFileManager
9
+ from pyPLUTO.loadfuncs.readtab import ReadtabManager
10
+ from pyPLUTO.loadstate import LoadState
11
+
12
+
13
+ class OffsetData(BaseLoadMixin[BaseLoadState]):
14
+ """Class that computes the offset of variables in single_file format."""
15
+
16
+ def __init__(self, state: BaseLoadState) -> None:
17
+ self.state = state
18
+ if isinstance(state, LoadState):
19
+ self.GridFileManager = GridFileManager(state)
20
+ self.Offsetclass = OffsetFluid(state)
21
+ self.ReadtabManager = ReadtabManager(state)
22
+
23
+ def compute_offset(
24
+ self,
25
+ i: int,
26
+ exout: int,
27
+ varname: str | None,
28
+ mm: mmap.mmap,
29
+ ) -> None:
30
+ """Compute the offset and shape of the variable in single_file format.
31
+
32
+ The function computes the offset and shape of the variable in
33
+ single_file format. The offset is computed based on the variable name,
34
+ output index, and file index. The shape is computed based on the
35
+ variable characteristics and the grid information.
36
+
37
+ Returns
38
+ -------
39
+ - None
40
+
41
+ Parameters
42
+ ----------
43
+ - i (not optional): int
44
+ The index of the file to be loaded.
45
+ - exout (not optional): int
46
+ The index of the output to be loaded.
47
+ - varname (not optional): str | None
48
+ The name of the variable to be loaded. If None, all variables are
49
+ considered.
50
+
51
+ ----
52
+
53
+ Examples
54
+ --------
55
+ - Example #1: Compute offset for a specific variable
56
+
57
+ >>> _compute_offset(0, 0, "rho")
58
+
59
+ - Example #2: Compute offset for all variables
60
+
61
+ >>> _compute_offset(0, 0, None)
62
+ """
63
+ if (
64
+ self.alone is not True
65
+ and isinstance(self.state, LoadState)
66
+ and self.infogrid is True
67
+ ):
68
+ self.GridFileManager.read_gridfile()
69
+ self.infogrid = False
70
+
71
+ fmt = "h5" if self.format in {"dbl.h5", "flt.h5"} else self.format
72
+ fmt = "bin" if fmt in {"dbl", "flt"} else fmt
73
+
74
+ if isinstance(self.state, LoadState):
75
+ handlers = {
76
+ "tab": self.ReadtabManager.read_tab,
77
+ "bin": self.Offsetclass.offset_bin,
78
+ "vtk": self.Offsetclass.offset_vtk,
79
+ "h5": self.Offsetclass.offset_h5,
80
+ "hdf5": self.Offsetclass.offset_hdf5,
81
+ }
82
+ else:
83
+ raise TypeError(
84
+ "OffsetData requires LoadState for now "
85
+ "(particles still not implemented)."
86
+ )
87
+ handlers.get(fmt, self.Offsetclass.offset_bin)(i, varname, exout, mm)