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
pyPLUTO/configure.py ADDED
@@ -0,0 +1,261 @@
1
+ """Module to configure the pyPLUTO package."""
2
+
3
+ import importlib
4
+ import sys
5
+ import traceback
6
+ import warnings
7
+ from collections.abc import Callable
8
+ from types import TracebackType
9
+ from typing import TYPE_CHECKING, cast
10
+
11
+ if TYPE_CHECKING:
12
+ from IPython.core.interactiveshell import InteractiveShell
13
+
14
+ FormatWarning = Callable[
15
+ [Warning | str, type[Warning], str, int, str | None], str
16
+ ]
17
+
18
+
19
+ class Configure:
20
+ """Handle the init tools for pyPLUTO.
21
+
22
+ Tools include finding the session, setting up the handlers, and other
23
+ initialization tasks.
24
+ """
25
+
26
+ greeted = False
27
+
28
+ def __init__(
29
+ self, colorerr: bool = True, colorwarn: bool = True, greet: bool = True
30
+ ) -> None:
31
+ """Initialize the Configure class.
32
+
33
+ Parameters
34
+ ----------
35
+ - colorerr: bool, default True
36
+ If True, color the errors in red.
37
+ - colorwarn: bool, default True
38
+ If True, color the warnings in yellow.
39
+ - greet: bool, default True
40
+ If True, print a greeting message with the version and session.
41
+
42
+ Returns
43
+ -------
44
+ - None
45
+
46
+ """
47
+ self.version: str = "1.1.1"
48
+ self.colorerr: bool = colorerr
49
+ self.colorwarn: bool = colorwarn
50
+ self.session: str = self._find_session()
51
+ self._setup_handlers(colorwarn, colorerr)
52
+ if greet and not Configure.greeted:
53
+ print(f"PyPLUTO version: {self.version} session: {self.session}")
54
+ Configure.greeted = True
55
+
56
+ def _find_session(self) -> str:
57
+ """Find the session in which the code is running.
58
+
59
+ Returns
60
+ -------
61
+ - session: str
62
+ The name of the session.
63
+
64
+ Parameters
65
+ ----------
66
+ - None
67
+
68
+ ----
69
+
70
+ Examples
71
+ --------
72
+ - Example #1: Standard Python interpreter
73
+
74
+ >>> find_session()
75
+ 'Standard Python interpreter'
76
+
77
+ - Example #2: Jupyter notebook or qtconsole
78
+
79
+ >>> find_session()
80
+ 'Jupyter notebook or qtconsole'
81
+
82
+ - Example #3: Terminal running IPython
83
+
84
+ >>> find_session()
85
+ 'Terminal running IPython'
86
+
87
+ - Example #4: Unknown session
88
+
89
+ >>> find_session()
90
+ 'Unknown session'
91
+
92
+ """
93
+
94
+ # Try to get IPython. If not available, it's not an IPython session.
95
+ # Note the quotes around the return type of the get_ipython_wrapper
96
+ # function. This is because pylint would throw an error.
97
+ def get_ipython_wrapper() -> "InteractiveShell | None":
98
+ """Return the IPython instance, or None if not available."""
99
+ warnings.filterwarnings(
100
+ "ignore",
101
+ message=r".*importing 'Const' from 'astroid' is deprecated.*",
102
+ category=DeprecationWarning,
103
+ )
104
+
105
+ try:
106
+ ipy_mod = importlib.import_module("IPython.core.getipython")
107
+ get_ipython = ipy_mod.get_ipython
108
+ return cast("InteractiveShell | None", get_ipython())
109
+ except (ImportError, AttributeError):
110
+ return None
111
+
112
+ # Get the ipython method (from IPthon or from the ImportError)
113
+
114
+ ipython = get_ipython_wrapper()
115
+
116
+ # Standard Python interpreter
117
+ if ipython is None:
118
+ return "Standard Python interpreter"
119
+
120
+ # Find the session name
121
+ shell = ipython.__class__.__name__
122
+
123
+ # Jupyter notebook or qtconsole
124
+ if shell == "ZMQInteractiveShell":
125
+ return "Jupyter notebook or qtconsole"
126
+ # Terminal running IPython
127
+ elif shell == "TerminalInteractiveShell":
128
+ return "Terminal running IPython"
129
+ # Unknown session
130
+ return "Unknown session"
131
+
132
+ def color_warning(
133
+ self,
134
+ message: Warning | str,
135
+ category: type[Warning],
136
+ filename: str,
137
+ lineno: int,
138
+ _file: str | None = None,
139
+ _line: str | None = None,
140
+ ) -> str:
141
+ """Color the warnings in yellow.
142
+
143
+ Parameters
144
+ ----------
145
+ - message: Warning | str
146
+ The warning message.
147
+ - category: type[Warning]
148
+ The category of the warning.
149
+ - filename: str
150
+ The name of the file where the warning occurred.
151
+ - lineno: int
152
+ The line number where the warning occurred.
153
+ - _file: str | None, optional
154
+ Not used, kept for compatibility.
155
+ - _line: str | None, optional
156
+ Not used, kept for compatibility.
157
+
158
+ Returns
159
+ -------
160
+ - str
161
+ The formatted warning message with color codes.
162
+
163
+ """
164
+ # Format the warning message with color codes
165
+ msg = str(message)
166
+
167
+ return f"\33[33m{category.__name__}: {msg}[{filename}:{lineno}]\33[0m\n"
168
+
169
+ def color_error(
170
+ self,
171
+ _type: type[BaseException] | None,
172
+ value: BaseException | None,
173
+ tb: TracebackType | None,
174
+ ) -> None:
175
+ """Color the errors in red.
176
+
177
+ Parameters
178
+ ----------
179
+ - _type: type[BaseException] | None
180
+ The type of the exception.
181
+ - value: BaseException | None
182
+ The exception instance.
183
+ - tb: TracebackType | None
184
+ The traceback object.
185
+
186
+ Returns
187
+ -------
188
+ - None
189
+
190
+ """
191
+ # Traces the error and writes it in red
192
+ traceback_str = "".join(traceback.format_tb(tb))
193
+ sys.stderr.write(f"\033[91m{traceback_str}\033[0m")
194
+ sys.stderr.write(f"\33[31m{value}\33[0m\n") # Red color for errors
195
+
196
+ def _setup_handlers(
197
+ self, colorwarn: bool = True, colorerr: bool = True
198
+ ) -> None:
199
+ """Set up the handlers for the warnings and errors.
200
+
201
+ Note that a type ignore is placed on the line where the warning handler
202
+ is set up because mypy and pyrefly would throw the following error:
203
+
204
+ (Warning | str, type[Warning], str, int, str | None) -> str is not
205
+ assignable to attribute formatwarning with type (message: Warning | str,
206
+ category: type[Warning], filename: str, lineno: int, line: str |
207
+ None = None) -> str
208
+ Incompatible types in assignment (expression has type
209
+ "Callable[[Warning | str, type[Warning], str, int, str | None], str]",
210
+ variable has type "Callable[[Arg(Warning | str, 'message'),
211
+ Arg(type[Warning], 'category'), Arg(str, 'filename'),
212
+ Arg(int, 'lineno'), DefaultArg(str | None, 'line')], str]")
213
+
214
+ This is because the signature of the color_warning method does not
215
+ exactly match the expected signature of the formatwarning attribute.
216
+ However, since the color_warning method is designed to be compatible
217
+ with the formatwarning attribute, we can safely ignore this type error.
218
+
219
+ The correct approach would be to use the following piece of code:
220
+
221
+ if colorwarn:
222
+ def _formatwarning(
223
+ message: Warning | str,
224
+ category: type[Warning],
225
+ filename: str,
226
+ lineno: int,
227
+ line: str | None = None,
228
+ ) -> str:
229
+ return self.color_warning(
230
+ message,
231
+ category,
232
+ filename,
233
+ lineno,
234
+ line
235
+ )
236
+
237
+ warnings.formatwarning = _formatwarning
238
+
239
+ but, for simplicity, we directly assign the color_warning method to the
240
+ formatwarning attribute and ignore the type error.
241
+
242
+ Parameters
243
+ ----------
244
+ - colorwarn: bool, default True
245
+ If True, color the warnings in yellow.
246
+ - colorerr: bool, default True
247
+ If True, color the errors in red.
248
+
249
+ Returns
250
+ -------
251
+ - None
252
+
253
+ """
254
+ # Set up the "always" filter for warnings
255
+ warnings.simplefilter("always")
256
+
257
+ # Set up the handlers for warnings and errors
258
+ if colorwarn:
259
+ warnings.formatwarning = self.color_warning # type: ignore
260
+ if colorerr:
261
+ sys.excepthook = self.color_error
pyPLUTO/gui/config.py ADDED
@@ -0,0 +1,174 @@
1
+ """Configure the Load object for th GUI."""
2
+
3
+ import os
4
+
5
+ import numpy as np
6
+ from PySide6.QtWidgets import QFileDialog
7
+
8
+ import pyPLUTO as pp
9
+
10
+ from .custom_var import setup_var_selector
11
+
12
+
13
+ def load_data(self):
14
+ """Load the data from the selected folder."""
15
+ try:
16
+ if self.varstext.text():
17
+ vars = self.varstext.text().replace(" ", "")
18
+ vars = vars.replace("-", ",").split(",")
19
+ else:
20
+ vars = True
21
+ self.D = pp.Load(
22
+ self.nout,
23
+ path=self.folder_path,
24
+ datatype=self.datatype,
25
+ vars=vars,
26
+ full3d=None,
27
+ )
28
+ self.data_loaded = True
29
+
30
+ self.var_selector.clear()
31
+ self.xaxis_selector.clear()
32
+ self.yaxis_selector.clear()
33
+
34
+ keep = []
35
+ self.D.nshp = (
36
+ self.D.nshp[::-1]
37
+ if isinstance(self.D.nshp, tuple)
38
+ else (int(self.D.nshp),)
39
+ )
40
+ for v in list(map(str, self.D._load_vars)):
41
+ a = getattr(self.D, v, None)
42
+
43
+ # keep only full-grid arrays
44
+ if isinstance(a, np.ndarray) and (a.shape == self.D.nshp):
45
+ keep.append(v)
46
+ self.D._load_vars = keep
47
+ self.var_selector.addItems(self.D._load_vars)
48
+
49
+ self.var_selector.addItems(["Custom var..."])
50
+ setup_var_selector(self.var_selector, self.D)
51
+
52
+ if self.D.geom == "POLAR":
53
+ xaxis_labels = ["R", "phi", "z", "x", "y"]
54
+ yaxis_labels = ["phi", "z", "R", "x", "y"]
55
+ elif self.D.geom == "SPHERICAL":
56
+ xaxis_labels = ["r", "theta", "phi", "R", "z", "Rt", "zt"]
57
+ yaxis_labels = ["theta", "phi", "r", "R", "z", "Rt", "zt"]
58
+ else:
59
+ xaxis_labels = ["x", "y", "z"]
60
+ yaxis_labels = ["y", "z", "x"]
61
+
62
+ self.xaxis_selector.addItems(xaxis_labels)
63
+ self.yaxis_selector.addItems(yaxis_labels)
64
+
65
+ # Base info
66
+ base = (
67
+ f"Loaded folder: {self.folder_path}\n"
68
+ f"Format file: {self.D.format}\n"
69
+ f"Geometry: {self.D.geom}\n"
70
+ f"Domain: {self.D.nx1} x {self.D.nx2} x {self.D.nx3}\n"
71
+ f"Loaded step = {self.D.nout[0]}\nPresent Time = {self.D.ntime}\n"
72
+ f"Variables: {', '.join(self.D._load_vars)}"
73
+ )
74
+
75
+ # Append custom vars defined in this session (if any)
76
+ defs = self.var_selector.property("_cv_defs") or []
77
+ CUSTOM_VAR_TUPLE_LENGTH = 3
78
+ if defs:
79
+ lines = []
80
+ for tup in defs:
81
+ if len(tup) == CUSTOM_VAR_TUPLE_LENGTH:
82
+ name, _clean, disp = tup
83
+ lines.append(f"{name} = {disp}")
84
+ else:
85
+ # backward-compat: (name, expr)
86
+ name, expr = tup
87
+ lines.append(f"{name} = {expr}")
88
+ base += "\n\nCustom variables:\n" + "\n".join(lines)
89
+
90
+ self.info_label.setPlainText(base)
91
+
92
+ except Exception as e:
93
+ print(f"Error loading data: {e}")
94
+ self.data_loaded = False
95
+
96
+
97
+ def select_folder(self):
98
+ """Open a dialog to select the folder containing the data."""
99
+ format_name = self.format_selector.currentText()
100
+ formats_list = {
101
+ "dbl": "*.dbl",
102
+ "flt": "*.flt",
103
+ "vtk": "*.vtk",
104
+ "dbl,h5": "*.dbl,h5",
105
+ "flt.h5": "*.flt.h5",
106
+ "hdf5": "*.hdf5",
107
+ "tab": "*.tab",
108
+ "None": None,
109
+ }
110
+ bigstr = (
111
+ f"Preferred format: {format_name} Files ({formats_list[format_name]});;"
112
+ if format_name != "None"
113
+ else ""
114
+ )
115
+ starting_dir = self.folder_path if self.folder_path else os.getcwd()
116
+ bigstr += (
117
+ "PLUTO Files (*.dbl *.vtk *.flt *.dbl.h5 *.flt.h5 *.out "
118
+ "*.hdf5 *.tab);;All Files (*)"
119
+ )
120
+ dialog = QFileDialog(self, "Select a File or Folder", starting_dir, bigstr)
121
+ dialog.setOption(QFileDialog.Option.DontUseNativeDialog, True)
122
+ dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
123
+
124
+ def on_accept():
125
+ selected = dialog.selectedFiles()
126
+ if selected:
127
+ file_path = selected[0]
128
+ self._finalize_load_path(file_path)
129
+
130
+ dialog.accepted.connect(on_accept)
131
+ dialog.open()
132
+ self._file_dialog = dialog # Save for automation access
133
+
134
+
135
+ def reload_data(self):
136
+ """Reload the data from the selected folder."""
137
+ var_name = self.var_selector.currentText()
138
+ self.nout = int(self.outtext.text()) if self.outtext.text() else "last"
139
+ self.folder_path = "./" if self.folder_path is None else self.folder_path
140
+ self.load_data()
141
+ defs = self.var_selector.property("_cv_defs") or []
142
+ custom_names = []
143
+ for item in defs:
144
+ display_name = item[0]
145
+ clean_name = (
146
+ display_name[1:]
147
+ if str(display_name).startswith("!")
148
+ else display_name
149
+ )
150
+ custom_names.append(clean_name)
151
+
152
+ if var_name in self.D._load_vars or var_name in custom_names:
153
+ self.var_selector.setCurrentText(var_name)
154
+
155
+
156
+ def clearload(self):
157
+ """Clear the loaded data and reset the GUI fields."""
158
+ self.folder_path = "./"
159
+ self.format_selector.setCurrentIndex(0)
160
+ self.outtext.clear()
161
+ self.varstext.clear()
162
+
163
+
164
+ def _finalize_load_path(self, file_path):
165
+ """Finalize the load path and extract relevant information."""
166
+ self.folder_path = os.path.dirname(file_path)
167
+ filename = os.path.basename(file_path)
168
+ parts = filename.split(".")
169
+ self.datatype = parts[-1]
170
+ try:
171
+ self.nout = int(parts[1])
172
+ except Exception:
173
+ self.nout = "last"
174
+ self.load_data()