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,123 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _convert_value(value):
|
|
5
|
+
"""Convert a string value to its appropriate type. This function
|
|
6
|
+
attempts to convert a string value into a boolean, integer, float,
|
|
7
|
+
or leave it as a string if it cannot be converted.
|
|
8
|
+
|
|
9
|
+
Returns
|
|
10
|
+
-------
|
|
11
|
+
bool | int | float | str
|
|
12
|
+
The converted value, which can be a boolean, integer, float, or the
|
|
13
|
+
original string if conversion is not possible.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
value : str
|
|
18
|
+
The string value to convert.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
# Convert the value to uppercase to handle case-insensitive comparisons
|
|
22
|
+
value_upper = value.upper()
|
|
23
|
+
|
|
24
|
+
# Check for boolean values first
|
|
25
|
+
if value_upper in {"YES", "TRUE"}:
|
|
26
|
+
return True
|
|
27
|
+
if value_upper in {"NO", "FALSE"}:
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
# Try to convert to an integer or float, if possible
|
|
31
|
+
try:
|
|
32
|
+
return float(value) if "." in value or "e" in value else int(value)
|
|
33
|
+
except ValueError:
|
|
34
|
+
return value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _read_defh(self, filepath):
|
|
38
|
+
"""Read a header file and extract definitions.
|
|
39
|
+
|
|
40
|
+
This function reads a header file, extracts lines that start with
|
|
41
|
+
'#define', and converts the values to their appropriate types (boolean,
|
|
42
|
+
integer, float, or string).
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
dict
|
|
47
|
+
A dictionary where keys are the defined names and values are the
|
|
48
|
+
converted values.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
filepath : str
|
|
53
|
+
The path to the header file to read.
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
# Read the file, check if a line starts with '#define',
|
|
57
|
+
# and split the line into key and value.
|
|
58
|
+
# Convert the value using _convert_value function.
|
|
59
|
+
with open(filepath) as file:
|
|
60
|
+
# Return a dictionary comprehension that processes each line
|
|
61
|
+
return {
|
|
62
|
+
key: _convert_value(value)
|
|
63
|
+
for line in file
|
|
64
|
+
if line.strip().startswith("#define")
|
|
65
|
+
for _, key, value in [re.split(r"\s+", line.strip(), maxsplit=2)]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _read_plini(self, path):
|
|
70
|
+
"""Read the pluto.ini file and extract relevant sections.
|
|
71
|
+
|
|
72
|
+
This function reads the pluto.ini file, extracts sections that are of
|
|
73
|
+
interest (Solver, Parameters, Boundary, Time), and converts the values to
|
|
74
|
+
their appropriate types (boolean, integer, float, or string).
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
dict
|
|
79
|
+
A dictionary where keys are the parameter names and values are the
|
|
80
|
+
converted values.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
path : str
|
|
85
|
+
The path to the pluto.ini file to read.
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
# Define the sections we are interested in
|
|
89
|
+
wanted_sections = {"Solver", "Parameters", "Boundary", "Time"}
|
|
90
|
+
plini = {}
|
|
91
|
+
|
|
92
|
+
# Regular expressions to match sections and entries in the pluto.ini file
|
|
93
|
+
section_re = re.compile(r"\[(.+)]")
|
|
94
|
+
entry_re = re.compile(r"^(\w[\w\-\d]*)\s+(.*)$")
|
|
95
|
+
|
|
96
|
+
current_sec = None
|
|
97
|
+
|
|
98
|
+
# Open the file and read it line by line
|
|
99
|
+
with open(path) as f:
|
|
100
|
+
for line in f:
|
|
101
|
+
line = line.strip()
|
|
102
|
+
|
|
103
|
+
if not line or line.startswith("#"):
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
# Check if the line is a section header or an entry
|
|
107
|
+
if section_match := section_re.match(line):
|
|
108
|
+
section = section_match.group(1)
|
|
109
|
+
current_sec = section if section in wanted_sections else None
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
# If we are not in a wanted section, skip the line
|
|
113
|
+
if not current_sec:
|
|
114
|
+
continue
|
|
115
|
+
|
|
116
|
+
# If we are in a wanted section, check for entries
|
|
117
|
+
# and convert the values using _convert_value function
|
|
118
|
+
if entry_match := entry_re.match(line):
|
|
119
|
+
key, value = entry_match.groups()
|
|
120
|
+
plini[key] = _convert_value(value.strip())
|
|
121
|
+
|
|
122
|
+
# Return the dictionary containing the extracted parameters
|
|
123
|
+
return plini
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Descriptor management utilities for reading PLUTO descriptor files."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from pyPLUTO.loadfuncs.baseloadtools import BaseLoadTools
|
|
9
|
+
from pyPLUTO.loadmixin import LoadMixin
|
|
10
|
+
from pyPLUTO.loadstate import LoadState
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DescriptorManager(LoadMixin):
|
|
14
|
+
"""Class that manages the descriptor files for loading data."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
state: LoadState,
|
|
19
|
+
nout: int | str | list[int | str],
|
|
20
|
+
**kwargs: Any,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Initialize the DescriptorManager class."""
|
|
23
|
+
self.state = state
|
|
24
|
+
self.LoadToolManager = BaseLoadTools(self.state)
|
|
25
|
+
self.load_descriptor(nout, **kwargs)
|
|
26
|
+
|
|
27
|
+
def load_descriptor(
|
|
28
|
+
self, nout: int | str | list[int | str], **kwargs: Any
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Read the datatype.out file and stores the information.
|
|
31
|
+
|
|
32
|
+
Such information are the time array, the output variables, the file type
|
|
33
|
+
(single or multiples), the endianess, the simulation path and the bin
|
|
34
|
+
format. All these information are relevant in order to open the output
|
|
35
|
+
files and access the data.
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
- None
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
- endian (not optional): str
|
|
44
|
+
The endianess of the files.
|
|
45
|
+
- nout (not optional): int
|
|
46
|
+
The output file to be opened. If default ('last'), the code assumes
|
|
47
|
+
the last file should be opened. Other options available are 'last'
|
|
48
|
+
(all the files should be opened) and -1 (same as 'last').
|
|
49
|
+
|
|
50
|
+
----
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
- Example #1: Read the 'filetype'.out file
|
|
55
|
+
|
|
56
|
+
>>> _read_outfile(0, "big")
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
if self.format is None:
|
|
60
|
+
raise ValueError("Format not defined. Cannot read descriptor file.")
|
|
61
|
+
|
|
62
|
+
# Read and parse the 'filetype'.out file — pure Python split, no Pandas
|
|
63
|
+
pathdata = self.pathdir / Path(self.format + ".out")
|
|
64
|
+
rows = [
|
|
65
|
+
line.split()
|
|
66
|
+
for line in pathdata.read_text().splitlines()
|
|
67
|
+
if line.strip()
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
# Store the output and the time full list
|
|
71
|
+
self.outlist = np.array([r[0] for r in rows], dtype=np.int32)
|
|
72
|
+
self.timelist = np.array([r[1] for r in rows], dtype=np.float64)
|
|
73
|
+
self.lennoutlist = len(self.outlist)
|
|
74
|
+
|
|
75
|
+
# Check the output lines
|
|
76
|
+
self.LoadToolManager.check_nout(nout)
|
|
77
|
+
self.ntimelist = self.timelist[self.noutlist]
|
|
78
|
+
self.lennout = len(self.noutlist)
|
|
79
|
+
|
|
80
|
+
# Initialize the info dictionary
|
|
81
|
+
self.d_info = {
|
|
82
|
+
"typefile": np.array([rows[k][4] for k in self.outlist]),
|
|
83
|
+
"endianess": np.array(
|
|
84
|
+
[">" if rows[k][5] == "big" else "<" for k in self.outlist]
|
|
85
|
+
),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Compute the endianess (vtk always big endian).
|
|
89
|
+
# If endian is given, it is used instead of the one in the file.
|
|
90
|
+
self.d_info["endianess"][:] = (
|
|
91
|
+
">" if self.format == "vtk" else self.d_info["endianess"]
|
|
92
|
+
)
|
|
93
|
+
self.d_info["endianess"][:] = (
|
|
94
|
+
self.endian if self.endian is not None else self.d_info["endianess"]
|
|
95
|
+
)
|
|
96
|
+
self.d_info["varslist"] = [rows[k][6:] for k in self.outlist]
|
|
97
|
+
|
|
98
|
+
self.d_info["binformat"] = np.char.add(
|
|
99
|
+
self.d_info["endianess"], "f" + str(self.charsize)
|
|
100
|
+
)
|
|
101
|
+
format_string = f".%04d.{self.format}"
|
|
102
|
+
self.d_info["endpath"] = np.char.mod(format_string, self.outlist)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Docstring for findfiles.py."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from pyPLUTO.baseloadmixin import BaseLoadMixin
|
|
9
|
+
from pyPLUTO.baseloadstate import BaseLoadState
|
|
10
|
+
from pyPLUTO.loadfuncs.baseloadtools import BaseLoadTools
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FindFilesManager(BaseLoadMixin[BaseLoadState]):
|
|
14
|
+
"""Class that manages file finding operations."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
state: BaseLoadState,
|
|
19
|
+
nout: int | str | list[int | str],
|
|
20
|
+
**kwargs: Any,
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Initialize the FindFilesManager class."""
|
|
23
|
+
self.state = state
|
|
24
|
+
self.LoadToolManager = BaseLoadTools(self.state)
|
|
25
|
+
self.find_files(nout, **kwargs)
|
|
26
|
+
|
|
27
|
+
def find_files(
|
|
28
|
+
self, nout: int | str | list[int | str], **kwargs: Any
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Find the files to be loaded.
|
|
31
|
+
|
|
32
|
+
If nout is a list, the function loops over the list and finds the
|
|
33
|
+
corresponding files. If nout is an integer, the function finds the
|
|
34
|
+
corresponding file. If nout is 'last', the function finds the last file.
|
|
35
|
+
If nout is 'all', the function finds all the files. Then, the function
|
|
36
|
+
stores the relevant information in a dictionary d_info.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
- None
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
- nout (not optional): int | str | list[int|str]
|
|
45
|
+
The output file to be loaded
|
|
46
|
+
|
|
47
|
+
----
|
|
48
|
+
|
|
49
|
+
Examples
|
|
50
|
+
--------
|
|
51
|
+
- Example #1: Load the last file
|
|
52
|
+
|
|
53
|
+
>>> _findfiles("last")
|
|
54
|
+
|
|
55
|
+
- Example #2: Load the first file
|
|
56
|
+
|
|
57
|
+
>>> _findfiles(0)
|
|
58
|
+
|
|
59
|
+
- Example #3: Load all the files
|
|
60
|
+
|
|
61
|
+
>>> _findfiles("all")
|
|
62
|
+
|
|
63
|
+
- Example #4: Load multiple specific files
|
|
64
|
+
|
|
65
|
+
>>> _findfiles([0, 1, 2, 3])
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
# Initialization or declaration of variables
|
|
69
|
+
set_vars: set[str] = set()
|
|
70
|
+
set_outs: set[str] = set()
|
|
71
|
+
self.d_info = {}
|
|
72
|
+
|
|
73
|
+
if self.matching_files is None:
|
|
74
|
+
raise ValueError("No files are found! Cannot proceed.")
|
|
75
|
+
# Find the files to be loaded
|
|
76
|
+
for elem in self.matching_files:
|
|
77
|
+
self.varsout(elem, set_vars, set_outs)
|
|
78
|
+
|
|
79
|
+
# Check if the files are present
|
|
80
|
+
if len(set_vars) == 0 or len(set_outs) == 0:
|
|
81
|
+
raise FileNotFoundError(f"No files found in {self.pathdir}!")
|
|
82
|
+
|
|
83
|
+
self.outlist = np.array(sorted(set_outs))
|
|
84
|
+
self.lennoutlist = len(self.outlist)
|
|
85
|
+
self.LoadToolManager.check_nout(nout)
|
|
86
|
+
self.lennout = len(self.noutlist)
|
|
87
|
+
self.ntimelist = np.full(self.lennout, np.nan)
|
|
88
|
+
self.timelist = np.full(len(self.outlist), np.nan)
|
|
89
|
+
|
|
90
|
+
# Find the max size of the output numbers to allow for loading if some
|
|
91
|
+
# files are missing
|
|
92
|
+
d_info_size = int(np.max(self.outlist)) + 1
|
|
93
|
+
|
|
94
|
+
# Initialize the info dictionary and initialize some relevant variables
|
|
95
|
+
self.d_info["typefile"] = np.empty(d_info_size, dtype="U20")
|
|
96
|
+
self.d_info["endianess"] = np.empty(d_info_size, dtype="U20")
|
|
97
|
+
self.d_info["binformat"] = np.empty(d_info_size, dtype="U20")
|
|
98
|
+
if self.class_name == "LoadPart":
|
|
99
|
+
raise NotImplementedError(
|
|
100
|
+
"FindFilesManager for LoadPart is not implemented yet."
|
|
101
|
+
)
|
|
102
|
+
elif self.class_name == "Load":
|
|
103
|
+
# Check if the fluid files are present as multiple files
|
|
104
|
+
if "data" not in set_vars or self.multiple is True:
|
|
105
|
+
# If the files are multiple, the typefile is set accordingly
|
|
106
|
+
self.d_info["typefile"][:] = "multiple_files"
|
|
107
|
+
self.d_info["varslist"] = [[] for _ in range(d_info_size)]
|
|
108
|
+
for elem in self.matching_files:
|
|
109
|
+
raw_str = Path(elem).name.split(".")
|
|
110
|
+
self.d_info["varslist"][int(raw_str[1])].append(raw_str[0])
|
|
111
|
+
else:
|
|
112
|
+
# If the files are single, the typefile is set to 'single_file'
|
|
113
|
+
self.d_info["typefile"][:] = "single_file"
|
|
114
|
+
self.d_info["varslist"] = [[] for _ in range(d_info_size)]
|
|
115
|
+
else:
|
|
116
|
+
raise ValueError(f"Unknown class name: {self.class_name}")
|
|
117
|
+
|
|
118
|
+
# Sparse map indexed by output number
|
|
119
|
+
endpath = np.empty(d_info_size, dtype=f"<U{len(self.format) + 6}")
|
|
120
|
+
endpath[:] = ""
|
|
121
|
+
for out in self.outlist:
|
|
122
|
+
endpath[int(out)] = f".{int(out):04d}.{self.format}"
|
|
123
|
+
self.d_info["endpath"] = endpath
|
|
124
|
+
|
|
125
|
+
def varsout(
|
|
126
|
+
self,
|
|
127
|
+
elem: str,
|
|
128
|
+
set_vars: set,
|
|
129
|
+
set_outs: set,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Find the variables and the outputs for the fluid and particles files.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
- None
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
- class_name (not optional): str
|
|
140
|
+
The name of the class. Supported classes are 'Load' or 'LoadPart'.
|
|
141
|
+
- elem (not optional): str
|
|
142
|
+
The matching file.
|
|
143
|
+
|
|
144
|
+
----
|
|
145
|
+
|
|
146
|
+
Examples
|
|
147
|
+
--------
|
|
148
|
+
- Example #1: Find the outputs (particles, non LP)
|
|
149
|
+
|
|
150
|
+
>>> _varsouts_p("particles.0000.dbl")
|
|
151
|
+
|
|
152
|
+
- Example #2: Find the outputs (fluid)
|
|
153
|
+
|
|
154
|
+
>>> _varsouts_f("rho.0000.dbl")
|
|
155
|
+
|
|
156
|
+
- Example #3: Find the outputs (LP)
|
|
157
|
+
|
|
158
|
+
>>> _varsouts_lp("particles.0000_ch_00.dbl")
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
# Splits the matching filename (variable/data and output number)
|
|
162
|
+
raw_str = Path(elem).name.split(".")
|
|
163
|
+
var = raw_str[0]
|
|
164
|
+
out = raw_str[1]
|
|
165
|
+
|
|
166
|
+
# Set the conditions if the file is fluid or particles
|
|
167
|
+
isfluid = var != "particles" and self.class_name == "Load"
|
|
168
|
+
ispart = var == "particles" and self.class_name == "LoadPart"
|
|
169
|
+
|
|
170
|
+
if isfluid or (ispart and "_" not in out):
|
|
171
|
+
# Control variable set to True
|
|
172
|
+
outc = True
|
|
173
|
+
elif ispart and "_" in out:
|
|
174
|
+
pass
|
|
175
|
+
else:
|
|
176
|
+
# Control variable set to False
|
|
177
|
+
outc = False
|
|
178
|
+
|
|
179
|
+
# Add the variables and the outputs
|
|
180
|
+
if outc is True:
|
|
181
|
+
set_vars.add(var)
|
|
182
|
+
set_outs.add(int(out))
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""Module to find the format of the PLUTO output files."""
|
|
2
|
+
|
|
3
|
+
import glob
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from pyPLUTO.baseloadmixin import BaseLoadMixin
|
|
9
|
+
from pyPLUTO.baseloadstate import BaseLoadState
|
|
10
|
+
from pyPLUTO.utils.inspector import track_kwargs
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FindFormat(BaseLoadMixin[BaseLoadState]):
|
|
14
|
+
"""Class to find the format of the PLUTO output files."""
|
|
15
|
+
|
|
16
|
+
@track_kwargs
|
|
17
|
+
def __init__(self, state: BaseLoadState, **kwargs: Any) -> None:
|
|
18
|
+
"""Initialize the FindFormat class."""
|
|
19
|
+
self.state = state
|
|
20
|
+
|
|
21
|
+
datatype = kwargs.get("datatype")
|
|
22
|
+
alone = kwargs.get("alone")
|
|
23
|
+
self.check_format(datatype, alone)
|
|
24
|
+
|
|
25
|
+
def check_format(
|
|
26
|
+
self,
|
|
27
|
+
datatype: str | None,
|
|
28
|
+
alone: bool | None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Find the format of the data files to load.
|
|
31
|
+
|
|
32
|
+
This checks whether outputs are fluid or particles and searches for
|
|
33
|
+
available filetypes in the target directory. Depending on the requested
|
|
34
|
+
datatype and whether files are standalone, it probes formats in order
|
|
35
|
+
and sets self.format, self._alone and self._charsize accordingly.
|
|
36
|
+
Supported types are dbl, flt, vtk, dbl.h5 and flt.h5; hdf5 and tab are
|
|
37
|
+
not implemented.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
alone: bool | None
|
|
42
|
+
If the output files are standalone or they require a .out
|
|
43
|
+
file to be loaded. Only suggested for fluid files, .vtk
|
|
44
|
+
format and standalone files, otherwise the code finds
|
|
45
|
+
the alone property by itself.
|
|
46
|
+
datatype: str | None
|
|
47
|
+
The file format. If None the format is recovered between
|
|
48
|
+
(in order) dbl, flt, vtk, dbl.h5 and flt.h5.
|
|
49
|
+
Formats hdf5 (AMR) and tab have not been implemented yet.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
None
|
|
54
|
+
|
|
55
|
+
Examples
|
|
56
|
+
--------
|
|
57
|
+
- Example #1: Find the format of the fluid files
|
|
58
|
+
|
|
59
|
+
>>> find_format("dbl", False)
|
|
60
|
+
|
|
61
|
+
- Example #2: Find the format of the standalone files
|
|
62
|
+
|
|
63
|
+
>>> find_format("vtk", True)
|
|
64
|
+
|
|
65
|
+
- Example #3: Find the format of the fluid files (no format given)
|
|
66
|
+
|
|
67
|
+
>>> find_format(None, False)
|
|
68
|
+
|
|
69
|
+
- Example #4: Find the format of the particles files
|
|
70
|
+
|
|
71
|
+
>>> find_format("dbl", True) --------
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
# Initialization or declaration of variables
|
|
75
|
+
dbl = {"dbl", "dbl.h5"} # The set of double filetypes
|
|
76
|
+
|
|
77
|
+
# Define the possible filetypes and set the keyword "alone" accordingly
|
|
78
|
+
if self.class_name == "Load":
|
|
79
|
+
# Divide the formats between standalone and not standalone
|
|
80
|
+
type_out = ["dbl", "flt", "vtk", "dbl.h5", "flt.h5", "tab"]
|
|
81
|
+
type_lon = ["vtk", "dbl.h5", "flt.h5", "tab", "hdf5"]
|
|
82
|
+
# If datatype is dbl or flt the files are not standalone
|
|
83
|
+
if datatype in {"dbl", "flt"}:
|
|
84
|
+
alone = False
|
|
85
|
+
elif self.class_name == "LoadPart":
|
|
86
|
+
# Particle files are always standalone
|
|
87
|
+
alone = True
|
|
88
|
+
type_out = []
|
|
89
|
+
type_lon = ["dbl", "flt", "vtk"]
|
|
90
|
+
else:
|
|
91
|
+
# If the class name is not recognized, raise an error
|
|
92
|
+
raise NameError("Invalid class name.")
|
|
93
|
+
|
|
94
|
+
# Check if the given datatype is valid, if not raise an error
|
|
95
|
+
if datatype not in type_out + type_lon + [None]:
|
|
96
|
+
if self.class_name == "Load":
|
|
97
|
+
err = (
|
|
98
|
+
f"Invalid datatype {datatype}.\n"
|
|
99
|
+
f"Possible formats are: dbl, flt, vtk, dbl.h5, flt.h5, tab"
|
|
100
|
+
)
|
|
101
|
+
elif self.class_name == "LoadPart":
|
|
102
|
+
err = (
|
|
103
|
+
f"Invalid datatype {datatype}.\n"
|
|
104
|
+
f"Possible formats are: dbl, flt, vtk"
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
err = f"Invalid class name: {self.class_name}"
|
|
108
|
+
raise ValueError(err)
|
|
109
|
+
|
|
110
|
+
# Create the list of types to iterate over. If the datatype is None
|
|
111
|
+
# then the list is the full list of types, otherwise the list is the
|
|
112
|
+
# datatype itself.
|
|
113
|
+
typeout0, typelon0 = (
|
|
114
|
+
([], []) if datatype is not None else (type_out, type_lon)
|
|
115
|
+
)
|
|
116
|
+
type_out = [datatype] if datatype in type_out else typeout0
|
|
117
|
+
type_lon = [datatype] if datatype in type_lon else typelon0
|
|
118
|
+
|
|
119
|
+
if alone is True:
|
|
120
|
+
type_out = []
|
|
121
|
+
|
|
122
|
+
# Create the list of functions to be called (.out or alone)
|
|
123
|
+
funcf: list[Callable[[list[str]], None]] = []
|
|
124
|
+
funcf += (
|
|
125
|
+
[self.check_typeout]
|
|
126
|
+
if len(type_out) > 0 and alone is not True
|
|
127
|
+
else []
|
|
128
|
+
)
|
|
129
|
+
funcf += (
|
|
130
|
+
[self.check_typelon]
|
|
131
|
+
if len(type_lon) > 0 and alone is not False
|
|
132
|
+
else []
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Iterate over the functions to be called
|
|
136
|
+
for do_check, arg in (
|
|
137
|
+
(self.check_typeout, type_out),
|
|
138
|
+
(self.check_typelon, type_lon),
|
|
139
|
+
):
|
|
140
|
+
do_check([x for x in arg if x is not None])
|
|
141
|
+
# Check if the format has been found
|
|
142
|
+
if self.format != "Unknown":
|
|
143
|
+
# Store the charsize depending on the format
|
|
144
|
+
self.charsize = 8 if self.format in dbl else 4
|
|
145
|
+
# If the format is found, end the function
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
# No file has been found, so raise an error depending on the case.
|
|
149
|
+
# If the datatype is None, raise a general error, otherwise raise
|
|
150
|
+
# an error for the specific datatype.
|
|
151
|
+
scrh = f"No available type has been found in {self.pathdir}."
|
|
152
|
+
|
|
153
|
+
if datatype is not None:
|
|
154
|
+
scrh = f"Type {datatype} not found."
|
|
155
|
+
raise FileNotFoundError(scrh)
|
|
156
|
+
|
|
157
|
+
def check_typeout(self, type_out: list[str]) -> None:
|
|
158
|
+
"""Loop over possible formats in order to findthe descriptor files.
|
|
159
|
+
|
|
160
|
+
If the datatype.out file is found, the file format is selected and the
|
|
161
|
+
flag alone is set to False.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
- None
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
- type_out (not optional): list[str]
|
|
170
|
+
The list of possible formats for the output file.
|
|
171
|
+
|
|
172
|
+
----
|
|
173
|
+
|
|
174
|
+
Examples
|
|
175
|
+
--------
|
|
176
|
+
- Example #1: Check the format of the output files
|
|
177
|
+
|
|
178
|
+
>>> _check_typeout(["dbl", "flt", "vtk", "dbl.h5", "flt.h5", "tab"])
|
|
179
|
+
|
|
180
|
+
- Example #2: Check the format of the output files (no format given)
|
|
181
|
+
|
|
182
|
+
>>> _check_typeout([])
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
# Loop over the possible formats
|
|
186
|
+
for try_type in type_out:
|
|
187
|
+
# Create the path to the grid.out and datatype.out files
|
|
188
|
+
pathgrid = self.pathdir / Path("grid.out")
|
|
189
|
+
pathdata = self.pathdir / Path(try_type + ".out")
|
|
190
|
+
|
|
191
|
+
# Check if the datatype.out file is present
|
|
192
|
+
if pathdata.is_file() and pathgrid.is_file():
|
|
193
|
+
# Store the format and set the flag alone to False
|
|
194
|
+
self.format = try_type
|
|
195
|
+
self.alone = False
|
|
196
|
+
# Format is found, break the loop
|
|
197
|
+
break
|
|
198
|
+
|
|
199
|
+
# End of the function
|
|
200
|
+
|
|
201
|
+
def check_typelon(self, type_lon: list[str]) -> None:
|
|
202
|
+
"""Loop over possible formats in order to find the datatype.
|
|
203
|
+
|
|
204
|
+
If the file is found, the file format is selected and the flag alone is
|
|
205
|
+
set to True.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
- None
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
- type_lon (not optional): list[str]
|
|
214
|
+
The list of possible formats for the output file.
|
|
215
|
+
|
|
216
|
+
----
|
|
217
|
+
|
|
218
|
+
Examples
|
|
219
|
+
--------
|
|
220
|
+
- Example #1: Check the format of the output files
|
|
221
|
+
|
|
222
|
+
>>> _check_typelon(["dbl", "flt", "vtk"])
|
|
223
|
+
|
|
224
|
+
- Example #2: Check the format of the output files (no format given)
|
|
225
|
+
|
|
226
|
+
>>> _check_typelon([])
|
|
227
|
+
|
|
228
|
+
"""
|
|
229
|
+
# Loop over the possible formats
|
|
230
|
+
for try_type in type_lon:
|
|
231
|
+
# Create the pattern to be searched
|
|
232
|
+
pattern = self.pathdir / Path("*.*." + try_type)
|
|
233
|
+
|
|
234
|
+
# Find the files matching the pattern
|
|
235
|
+
self.matching_files = glob.glob(str(pattern))
|
|
236
|
+
|
|
237
|
+
# Check if the file is present
|
|
238
|
+
if self.matching_files:
|
|
239
|
+
# Store the format and set the flag alone to True
|
|
240
|
+
self.format = try_type
|
|
241
|
+
self.alone = True
|
|
242
|
+
# Format is found, break the loop
|
|
243
|
+
break
|
|
244
|
+
|
|
245
|
+
# End of the function
|