cffview 0.4.2__tar.gz → 0.4.4__tar.gz
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.
- {cffview-0.4.2/src/cffview.egg-info → cffview-0.4.4}/PKG-INFO +1 -1
- {cffview-0.4.2 → cffview-0.4.4}/pyproject.toml +1 -1
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview/boundary.py +1 -22
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview/main.py +1 -1
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview/plotter.py +23 -23
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview/reader.py +192 -138
- {cffview-0.4.2 → cffview-0.4.4/src/cffview.egg-info}/PKG-INFO +1 -1
- {cffview-0.4.2 → cffview-0.4.4}/LICENSE +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/README.md +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/setup.cfg +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview/utils.py +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview.egg-info/SOURCES.txt +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview.egg-info/dependency_links.txt +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview.egg-info/entry_points.txt +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview.egg-info/requires.txt +0 -0
- {cffview-0.4.2 → cffview-0.4.4}/src/cffview.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cffview"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.4"
|
|
8
8
|
description = "A Python CLI tool to view Ansys Fluent .cas.h5/.msh.h5/.dat.h5 files without opening Fluent"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -115,31 +115,10 @@ class BoundaryFactory:
|
|
|
115
115
|
boundary_cls = cls._REGISTRY.get(type_, NotImplementedBoundary)
|
|
116
116
|
return boundary_cls(name, id_)
|
|
117
117
|
|
|
118
|
-
@staticmethod
|
|
119
|
-
def match_property(property_list: list[str | list[str]]) -> str | dict[str, str]:
|
|
120
|
-
match property_list:
|
|
121
|
-
case [_]:
|
|
122
|
-
return ''
|
|
123
|
-
case [_, expr] | [_, '.', expr] if isinstance(expr, str):
|
|
124
|
-
return expr
|
|
125
|
-
case [_, x, y, z] if all(isinstance(i, str) for i in (x, y, z)):
|
|
126
|
-
return f'{x} {y} {z}'
|
|
127
|
-
case [_, [sel, '.', expr], *_]:
|
|
128
|
-
return f'{sel}/{expr}'
|
|
129
|
-
case [_, ['profile', sel, expr], *_]:
|
|
130
|
-
return f'profile/{sel}/{expr}'
|
|
131
|
-
case ['source-terms', *source_terms_list]:
|
|
132
|
-
for source_term in (st for st in source_terms_list if len(st) == 2):
|
|
133
|
-
eq_name, source_property_list = source_term
|
|
134
|
-
source_property = source_property_list[0]
|
|
135
|
-
if source_property[1] == '.':
|
|
136
|
-
return {eq_name: f'{source_property[0]}/{source_property[2]}'}
|
|
137
|
-
elif source_property[0] == 'profile' and source_property[1]:
|
|
138
|
-
return {eq_name: f'profile/{source_property[1]}/{source_property[2]}'}
|
|
139
|
-
|
|
140
118
|
|
|
141
119
|
# ------------------------------------------------- shared to_dict helpers
|
|
142
120
|
|
|
121
|
+
|
|
143
122
|
TURBULENCE_KEYS = (
|
|
144
123
|
'ke_spec', 'turb_intensity', 'turb_length_scale',
|
|
145
124
|
'turb_hydraulic_diam', 'turb_viscosity_ratio',
|
|
@@ -243,7 +243,7 @@ def plot(file_path: str, out: bool = False, xy: bool = False, dat: bool = False)
|
|
|
243
243
|
raise ValueError("Please specify --out, --xy or --dat")
|
|
244
244
|
|
|
245
245
|
|
|
246
|
-
def plot_data(file_path: str):
|
|
246
|
+
def plot_data(file_path: str) -> None:
|
|
247
247
|
"""Visualize Fluent .cas.h5 + .dat.h5 solution data with interactive cross-sections.
|
|
248
248
|
|
|
249
249
|
Uses PyVista's built-in VTK FLUENTCFF Reader to load both mesh and solution data
|
|
@@ -8,7 +8,7 @@ variable switching, opacity and clip-plane widgets.
|
|
|
8
8
|
import sys
|
|
9
9
|
from functools import wraps
|
|
10
10
|
|
|
11
|
-
from pyvista import _vtk, Plotter, MultiBlock, PolyData, UnstructuredGrid, DataSetMapper
|
|
11
|
+
from pyvista import _vtk, Actor, Plotter, MultiBlock, PolyData, UnstructuredGrid, DataSetMapper
|
|
12
12
|
|
|
13
13
|
from .utils import print_colored_dict
|
|
14
14
|
|
|
@@ -32,7 +32,7 @@ KEYBOARD_SHORTCUTS = {
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class BasePlotter:
|
|
35
|
-
def __init__(self, mesh: MultiBlock | PolyData):
|
|
35
|
+
def __init__(self, mesh: MultiBlock | PolyData) -> None:
|
|
36
36
|
self.mesh = mesh.combine() if isinstance(mesh, MultiBlock) else mesh
|
|
37
37
|
|
|
38
38
|
# Monkey patch to fix clip plane error
|
|
@@ -55,7 +55,7 @@ class BasePlotter:
|
|
|
55
55
|
self.keyboard_shortcuts = KEYBOARD_SHORTCUTS
|
|
56
56
|
|
|
57
57
|
@wraps(Plotter.show)
|
|
58
|
-
def show(self, *args, **kwargs):
|
|
58
|
+
def show(self, *args, **kwargs) -> None:
|
|
59
59
|
print_colored_dict(self.keyboard_shortcuts)
|
|
60
60
|
self.pl.show(*args, **kwargs)
|
|
61
61
|
|
|
@@ -63,7 +63,7 @@ class BasePlotter:
|
|
|
63
63
|
self,
|
|
64
64
|
checkbox_params: dict = None,
|
|
65
65
|
text_params: dict = None,
|
|
66
|
-
):
|
|
66
|
+
) -> _vtk.vtkButtonWidget:
|
|
67
67
|
checkbox_params = checkbox_params or {}
|
|
68
68
|
text_params = text_params or {}
|
|
69
69
|
|
|
@@ -73,17 +73,17 @@ class BasePlotter:
|
|
|
73
73
|
checkbox_params['position'][1] + 10,
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
-
check_box_widget = self.pl.add_checkbox_button_widget(**checkbox_params)
|
|
76
|
+
check_box_widget: _vtk.vtkButtonWidget = self.pl.add_checkbox_button_widget(**checkbox_params)
|
|
77
77
|
check_box_widget.callback = checkbox_params['callback']
|
|
78
78
|
self.pl.add_text(**text_params)
|
|
79
79
|
|
|
80
80
|
return check_box_widget
|
|
81
81
|
|
|
82
|
-
def _add_grid_cb(self):
|
|
83
|
-
def toggle_grid(state: bool):
|
|
82
|
+
def _add_grid_cb(self) -> _vtk.vtkButtonWidget:
|
|
83
|
+
def toggle_grid(state: bool) -> None:
|
|
84
84
|
self.pl.show_grid(font_size=10, fmt='%.2f') if state else self.pl.remove_bounds_axes()
|
|
85
85
|
|
|
86
|
-
grid_cb = self._add_checkbox_and_text(
|
|
86
|
+
grid_cb: _vtk.vtkButtonWidget = self._add_checkbox_and_text(
|
|
87
87
|
checkbox_params=dict(
|
|
88
88
|
callback=toggle_grid,
|
|
89
89
|
value=False,
|
|
@@ -98,13 +98,13 @@ class BasePlotter:
|
|
|
98
98
|
return grid_cb
|
|
99
99
|
|
|
100
100
|
def _add_keyboard_shortcuts(self, key_widget_dict: dict[str, tuple[_vtk.vtkButtonWidget | _vtk.vtkSliderWidget, str]]):
|
|
101
|
-
def reverse(checkbox_button_widget: _vtk.vtkButtonWidget):
|
|
101
|
+
def reverse(checkbox_button_widget: _vtk.vtkButtonWidget) -> None:
|
|
102
102
|
rep = checkbox_button_widget.button_representation
|
|
103
103
|
new_state = not rep.state
|
|
104
104
|
rep.state = new_state
|
|
105
105
|
checkbox_button_widget.callback(new_state)
|
|
106
106
|
|
|
107
|
-
def set_value(slider_widget: _vtk.vtkSliderWidget, new_value: int):
|
|
107
|
+
def set_value(slider_widget: _vtk.vtkSliderWidget, new_value: int) -> None:
|
|
108
108
|
slider_widget.slider_representation.value = new_value
|
|
109
109
|
slider_widget.callback(new_value)
|
|
110
110
|
|
|
@@ -117,7 +117,7 @@ class BasePlotter:
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
class MeshPlotter(BasePlotter):
|
|
120
|
-
def __init__(self, mesh, dimension: int = None):
|
|
120
|
+
def __init__(self, mesh, dimension: int = None) -> None:
|
|
121
121
|
super().__init__(mesh)
|
|
122
122
|
self.dimension = dimension
|
|
123
123
|
self.mesh_actor = self._add_mesh()
|
|
@@ -132,7 +132,7 @@ class MeshPlotter(BasePlotter):
|
|
|
132
132
|
}
|
|
133
133
|
)
|
|
134
134
|
|
|
135
|
-
def _add_mesh(self):
|
|
135
|
+
def _add_mesh(self) -> Actor:
|
|
136
136
|
mesh_actor = self.pl.add_mesh(
|
|
137
137
|
self.mesh,
|
|
138
138
|
show_edges=True,
|
|
@@ -140,8 +140,8 @@ class MeshPlotter(BasePlotter):
|
|
|
140
140
|
)
|
|
141
141
|
return mesh_actor
|
|
142
142
|
|
|
143
|
-
def _add_opcatity_slider(self):
|
|
144
|
-
opacity_slider_widget = self.pl.add_slider_widget(
|
|
143
|
+
def _add_opcatity_slider(self) -> _vtk.vtkSliderWidget:
|
|
144
|
+
opacity_slider_widget: _vtk.vtkSliderWidget = self.pl.add_slider_widget(
|
|
145
145
|
lambda value: setattr(self.mesh_actor.prop, 'opacity', value),
|
|
146
146
|
rng=(0.1, 1.0),
|
|
147
147
|
value=1.0,
|
|
@@ -155,14 +155,14 @@ class MeshPlotter(BasePlotter):
|
|
|
155
155
|
)
|
|
156
156
|
return opacity_slider_widget
|
|
157
157
|
|
|
158
|
-
def _add_mesh_clip_plane(self):
|
|
158
|
+
def _add_mesh_clip_plane(self) -> None:
|
|
159
159
|
self.mesh_clip_plane_actor = self.pl.add_mesh_clip_plane(self.mesh, show_edges=True)
|
|
160
160
|
self.mesh_clip_plane_actor.visibility = False
|
|
161
161
|
self.clip_plane = self.pl.widgets.plane_widgets[-1]
|
|
162
162
|
self.clip_plane.Off()
|
|
163
163
|
|
|
164
|
-
def _add_clip_plane_cb(self):
|
|
165
|
-
def toggle_clip_plane(state):
|
|
164
|
+
def _add_clip_plane_cb(self) -> _vtk.vtkButtonWidget:
|
|
165
|
+
def toggle_clip_plane(state) -> None:
|
|
166
166
|
if state:
|
|
167
167
|
self.mesh_actor.visibility = False
|
|
168
168
|
self.opacity_slider_widget.Off()
|
|
@@ -190,7 +190,7 @@ class MeshPlotter(BasePlotter):
|
|
|
190
190
|
|
|
191
191
|
|
|
192
192
|
class DataPlotter(BasePlotter):
|
|
193
|
-
def __init__(self, mesh: MultiBlock | PolyData, var_names: tuple[str]):
|
|
193
|
+
def __init__(self, mesh: MultiBlock | PolyData, var_names: tuple[str]) -> None:
|
|
194
194
|
super().__init__(mesh)
|
|
195
195
|
self.var_names = var_names
|
|
196
196
|
|
|
@@ -254,11 +254,11 @@ class DataPlotter(BasePlotter):
|
|
|
254
254
|
self.scalar_bar.title = name
|
|
255
255
|
self.pl.render()
|
|
256
256
|
|
|
257
|
-
def _add_scalar_slider_widget(self):
|
|
258
|
-
def change_scalar(value: float):
|
|
257
|
+
def _add_scalar_slider_widget(self) -> _vtk.vtkSliderWidget:
|
|
258
|
+
def change_scalar(value: float) -> None:
|
|
259
259
|
self._set_scalars(self.var_names[int(value)])
|
|
260
260
|
|
|
261
|
-
scalar_slider = self.pl.add_slider_widget(
|
|
261
|
+
scalar_slider: _vtk.vtkSliderWidget = self.pl.add_slider_widget(
|
|
262
262
|
change_scalar,
|
|
263
263
|
rng=(0, len(self.var_names) - 1),
|
|
264
264
|
value=0,
|
|
@@ -274,8 +274,8 @@ class DataPlotter(BasePlotter):
|
|
|
274
274
|
scalar_slider.callback = change_scalar
|
|
275
275
|
return scalar_slider
|
|
276
276
|
|
|
277
|
-
def _add_clip_plane_cb(self):
|
|
278
|
-
def toggle_clip_plane(state):
|
|
277
|
+
def _add_clip_plane_cb(self) -> _vtk.vtkButtonWidget:
|
|
278
|
+
def toggle_clip_plane(state) -> None:
|
|
279
279
|
if state:
|
|
280
280
|
self.mesh_actor.visibility = False
|
|
281
281
|
self.mesh_clip_plane_actor.visibility = True
|
|
@@ -15,6 +15,7 @@ import sexpdata
|
|
|
15
15
|
|
|
16
16
|
NestedStrList: TypeAlias = list[Union[str, 'NestedStrList']]
|
|
17
17
|
CaseTexts = namedtuple('CaseTexts', ['general', 'boundary', 'cortex'])
|
|
18
|
+
ReaderFunc: TypeAlias = Callable[[CaseTexts], dict[str, Any]]
|
|
18
19
|
|
|
19
20
|
# from Ansys Fluent sg.h
|
|
20
21
|
DISCRETIZATION_SCHEME = {
|
|
@@ -165,6 +166,30 @@ def _get_reference_values(general: str) -> dict[str, str]:
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
|
|
169
|
+
@lru_cache(maxsize=None)
|
|
170
|
+
def _get_flow_scheme(general: str) -> str:
|
|
171
|
+
"""Return the pressure-velocity coupling scheme name (e.g. ``SIMPLE``)."""
|
|
172
|
+
scheme = re.search(r'\(flow/scheme\s+(\d+)\)', general).group(1)
|
|
173
|
+
return DISCRETIZATION_SCHEME.get(scheme, scheme)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@lru_cache(maxsize=None)
|
|
177
|
+
def _get_pseudo_time_method(general: str, flow_scheme: str) -> str:
|
|
178
|
+
"""Return the pseudo time method state: ``Off``, ``Global Time Step`` or ``Local Time Step``.
|
|
179
|
+
|
|
180
|
+
Disabled when ``user-defined-settings?`` is ``#f``; for the Coupled
|
|
181
|
+
scheme a global pseudo time step is used, otherwise a local one.
|
|
182
|
+
"""
|
|
183
|
+
if flow_scheme == 'Coupled':
|
|
184
|
+
key = 'pseudo-time-method/coupled-pbns/user-defined-settings?'
|
|
185
|
+
else:
|
|
186
|
+
key = 'pseudo-time-method/segregated-pbns/user-defined-settings?'
|
|
187
|
+
enabled = re.search(rf'\({re.escape(key)}\s+([^)]+)\)', general).group(1)
|
|
188
|
+
if enabled == '#f':
|
|
189
|
+
return 'Off'
|
|
190
|
+
return 'Global Time Step' if flow_scheme == 'Coupled' else 'Local Time Step'
|
|
191
|
+
|
|
192
|
+
|
|
168
193
|
@singledispatch
|
|
169
194
|
def _sel_expr(arg, *args) -> str:
|
|
170
195
|
"""Unsupported first-argument type for :func:`_sel_expr`."""
|
|
@@ -196,12 +221,12 @@ def _(lst: list[str], return_expr: bool = False) -> str:
|
|
|
196
221
|
# ------------------------------------------------------------- dispatcher
|
|
197
222
|
|
|
198
223
|
|
|
199
|
-
READERS: dict[str,
|
|
224
|
+
READERS: dict[str, ReaderFunc] = {}
|
|
200
225
|
|
|
201
226
|
|
|
202
|
-
def register_reader(name: str):
|
|
227
|
+
def register_reader(name: str) -> Callable[[ReaderFunc], ReaderFunc]:
|
|
203
228
|
"""Register a reader function under a flag name."""
|
|
204
|
-
def decorator(func:
|
|
229
|
+
def decorator(func: ReaderFunc) -> ReaderFunc:
|
|
205
230
|
READERS[name] = func
|
|
206
231
|
return func
|
|
207
232
|
return decorator
|
|
@@ -215,6 +240,7 @@ def _read_solver(texts: CaseTexts) -> dict[str, Any]:
|
|
|
215
240
|
general = texts.general
|
|
216
241
|
kvs = _parse_case_config(general)
|
|
217
242
|
dimension = '3d' if kvs['rp-3d?'] == '#t' else '2d'
|
|
243
|
+
flow_scheme = _get_flow_scheme(general)
|
|
218
244
|
|
|
219
245
|
solver: dict[str, Any] = {
|
|
220
246
|
'type': 'pbns' if kvs['rp-seg?'] == '#t' else 'dbns',
|
|
@@ -223,6 +249,8 @@ def _read_solver(texts: CaseTexts) -> dict[str, Any]:
|
|
|
223
249
|
'precision': 'double' if kvs['rp-double?'] == '#t' else 'single',
|
|
224
250
|
'axi': 'true' if kvs['rp-axi?'] == '#t' else 'false',
|
|
225
251
|
'init': 'hybrid' if kvs['hyb-init?'] == '#t' else 'standard',
|
|
252
|
+
'flow-scheme': flow_scheme,
|
|
253
|
+
'pseudo-time-method': _get_pseudo_time_method(general, flow_scheme),
|
|
226
254
|
'turb': _get_turb_model(general),
|
|
227
255
|
'energy': 'true' if kvs['rf-energy?'] == '#t' else 'false',
|
|
228
256
|
'radiation': _get_radiation_model(general),
|
|
@@ -250,29 +278,33 @@ def _read_materials(texts: CaseTexts) -> dict[str, Any]:
|
|
|
250
278
|
data[name] = {'type': material[1]}
|
|
251
279
|
for property_ in material[2:]:
|
|
252
280
|
property_name = property_[0]
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
data[name][property_name] = f'{
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
data[name][property_name] = {
|
|
264
|
-
|
|
281
|
+
match property_[1:]:
|
|
282
|
+
case ['.', value]:
|
|
283
|
+
data[name][property_name] = value
|
|
284
|
+
case [[sel, '.', expr], *_]:
|
|
285
|
+
data[name][property_name] = f'{sel}/{expr}'
|
|
286
|
+
case [['polynomial', 'piecewise-linear', *values_list], *_]:
|
|
287
|
+
data[name][property_name] = {
|
|
288
|
+
f'polynomial/piecewise-linear': [f'{v[0]}, {v[2]}' for v in values_list]
|
|
289
|
+
}
|
|
290
|
+
case [['polynomial', polynomial_type, *values_list], *_] if polynomial_type in ('piecewise-polynomial', 'nasa-9-piecewise-polynomial'):
|
|
291
|
+
data[name][property_name] = {
|
|
292
|
+
f'polynomial/{polynomial_type}': [str(v).strip('[]') for v in values_list]
|
|
293
|
+
}
|
|
294
|
+
case [['polynomial', *values_list], *_]:
|
|
295
|
+
data[name][property_name] = {f'polynomial': [str(v).strip('[]') for v in values_list]}
|
|
296
|
+
case [['orthotropic', *orth_properties], *_]:
|
|
265
297
|
value = {}
|
|
266
|
-
for
|
|
267
|
-
orth_property_name =
|
|
268
|
-
if orth_property_name in
|
|
269
|
-
value[orth_property_name] = [int(i) for i in
|
|
270
|
-
elif orth_property_name in
|
|
271
|
-
value[orth_property_name] = _sel_expr(
|
|
272
|
-
data[name][property_name] =
|
|
273
|
-
|
|
274
|
-
value = ' '.join(str(p) for p in
|
|
275
|
-
data[name][property_name] = f'{
|
|
298
|
+
for orth_property in orth_properties:
|
|
299
|
+
orth_property_name = orth_property[0]
|
|
300
|
+
if orth_property_name in ('direction-0', 'direction-1', 'direction-2'):
|
|
301
|
+
value[orth_property_name] = str([int(i) for i in orth_property[1:]]).strip('[]')
|
|
302
|
+
elif orth_property_name in ('k0', 'k1', 'k2'):
|
|
303
|
+
value[orth_property_name] = _sel_expr(orth_property[1])
|
|
304
|
+
data[name][property_name] = value
|
|
305
|
+
case _:
|
|
306
|
+
value = ' '.join(str(p) for p in property_[1:])
|
|
307
|
+
data[name][property_name] = f'{property_[0]}/{value}'
|
|
276
308
|
return {'materials': data}
|
|
277
309
|
|
|
278
310
|
|
|
@@ -293,7 +325,27 @@ def _read_boundary(texts: CaseTexts) -> dict[str, Any]:
|
|
|
293
325
|
for property_list in boundary_info[2]:
|
|
294
326
|
property_name = property_list[0].replace('-', '_').replace('?', '').replace('/', '_')
|
|
295
327
|
if hasattr(new_boundary, property_name):
|
|
296
|
-
|
|
328
|
+
match property_list:
|
|
329
|
+
case [_, expr] | [_, '.', expr] if isinstance(expr, str):
|
|
330
|
+
value = expr
|
|
331
|
+
case [_, x, y, z] if all(isinstance(i, str) for i in (x, y, z)):
|
|
332
|
+
value = f'{x} {y} {z}'
|
|
333
|
+
case [_, [sel, '.', expr], *_]:
|
|
334
|
+
value = f'{sel}/{expr}'
|
|
335
|
+
case [_, ['profile', sel, expr], *_]:
|
|
336
|
+
value = f'profile/{sel}/{expr}'
|
|
337
|
+
case ['source-terms', *source_terms_list]:
|
|
338
|
+
value = {}
|
|
339
|
+
for source_term in (st for st in source_terms_list if len(st) == 2):
|
|
340
|
+
eq_name, source_property_list = source_term
|
|
341
|
+
source_property = source_property_list[0]
|
|
342
|
+
if source_property[1] == '.':
|
|
343
|
+
value[eq_name] = f'{source_property[0]}/{source_property[2]}'
|
|
344
|
+
elif source_property[0] == 'profile' and source_property[1]:
|
|
345
|
+
value[eq_name] = f'profile/{source_property[1]}/{source_property[2]}'
|
|
346
|
+
case _:
|
|
347
|
+
value = ''
|
|
348
|
+
setattr(new_boundary, property_name, value)
|
|
297
349
|
|
|
298
350
|
b_list.append(
|
|
299
351
|
new_boundary.to_dict(_get_turb_model(texts.general), _get_radiation_model(texts.general))
|
|
@@ -316,10 +368,13 @@ def _read_interfaces(texts: CaseTexts) -> dict[str, Any]:
|
|
|
316
368
|
data: dict[str, Any] = {}
|
|
317
369
|
for interface in interfaces_list:
|
|
318
370
|
name = interface[0]
|
|
319
|
-
data[name] = {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
371
|
+
data[name] = {}
|
|
372
|
+
for interface_property in interface[1:]:
|
|
373
|
+
match interface_property:
|
|
374
|
+
case [property_name, '.', value] | [property_name, value]:
|
|
375
|
+
data[name][property_name] = value
|
|
376
|
+
case _:
|
|
377
|
+
continue
|
|
323
378
|
return {'interfaces': data}
|
|
324
379
|
|
|
325
380
|
|
|
@@ -395,6 +450,13 @@ def _read_disc(texts: CaseTexts) -> dict[str, Any]:
|
|
|
395
450
|
}
|
|
396
451
|
|
|
397
452
|
data: dict[str, Any] = {'disc-scheme': {}, 'relax-factor': {}}
|
|
453
|
+
cell_lsq = re.search(r'\(recon/cell-lsq\?\s+([^)]+)\)', general).group(1)
|
|
454
|
+
node_lsq = re.search(r'\(recon/node-lsq\?\s+([^)]+)\)', general).group(1)
|
|
455
|
+
data['disc-scheme']['gradient'] = (
|
|
456
|
+
'Least Squares Cell-Based' if cell_lsq == '#t'
|
|
457
|
+
else 'Green-Gauss Node-Based' if node_lsq == '#t'
|
|
458
|
+
else 'Green-Gauss Cell-Based'
|
|
459
|
+
)
|
|
398
460
|
for eq in ['flow', 'pressure', 'mom', 'temperature', 'k', 'omega', 'epsilon']:
|
|
399
461
|
data['disc-scheme'][eq] = disc_scheme.get(eq)
|
|
400
462
|
|
|
@@ -410,13 +472,27 @@ def _read_disc(texts: CaseTexts) -> dict[str, Any]:
|
|
|
410
472
|
general
|
|
411
473
|
).group(1)
|
|
412
474
|
else:
|
|
475
|
+
pseudo_time_method = _get_pseudo_time_method(general, data['disc-scheme']['flow'])
|
|
476
|
+
relax_prefix = '' if pseudo_time_method == 'Off' else 'dual-ts-implicit-'
|
|
413
477
|
relax_factor = {
|
|
414
478
|
ur[0]: ur[1]
|
|
415
|
-
for ur in re.findall(
|
|
479
|
+
for ur in re.findall(rf'\((.*)/{relax_prefix}relax\s+([\d.]+)\)', general)
|
|
416
480
|
}
|
|
417
481
|
for eq in ['pressure', 'mom', 'temperature', 'k', 'omega', 'epsilon', 'turb-viscosity', 'density', 'body-force']:
|
|
418
482
|
data['relax-factor'][eq] = relax_factor.get(eq, '')
|
|
419
483
|
|
|
484
|
+
turb_model = _get_turb_model(general)
|
|
485
|
+
if turb_model == 'lam':
|
|
486
|
+
for eq in ['k', 'omega', 'epsilon', 'turb-viscosity']:
|
|
487
|
+
data['disc-scheme'].pop(eq, None)
|
|
488
|
+
data['relax-factor'].pop(eq, None)
|
|
489
|
+
elif turb_model == 'kw':
|
|
490
|
+
data['disc-scheme'].pop('epsilon', None)
|
|
491
|
+
data['relax-factor'].pop('epsilon', None)
|
|
492
|
+
elif turb_model == 'ke':
|
|
493
|
+
data['disc-scheme'].pop('omega', None)
|
|
494
|
+
data['relax-factor'].pop('omega', None)
|
|
495
|
+
|
|
420
496
|
return data
|
|
421
497
|
|
|
422
498
|
|
|
@@ -435,34 +511,26 @@ def _read_report_definitions(texts: CaseTexts) -> dict[str, Any]:
|
|
|
435
511
|
report_def = rd[1]
|
|
436
512
|
type_ = report_def[1]
|
|
437
513
|
data[name] = {'type': type_}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
data[name]['zone-names'] = [zone for zone in report_def[6][1:]]
|
|
447
|
-
elif 'surface' in type_:
|
|
448
|
-
data[name]['surface-ids'] = [surface for surface in report_def[4][1:]]
|
|
449
|
-
data[name]['surface-names'] = [surface for surface in report_def[5][1:]]
|
|
450
|
-
elif 'flux' in type_:
|
|
451
|
-
data[name]['zone-ids'] = [zone for zone in report_def[2][1:]]
|
|
452
|
-
data[name]['zone-names'] = [zone for zone in report_def[3][1:]]
|
|
514
|
+
for report_property in report_def[2:]:
|
|
515
|
+
match report_property:
|
|
516
|
+
case [prop_name, '.', value]:
|
|
517
|
+
data[name][prop_name] = value
|
|
518
|
+
case [prop_name, *values] if prop_name not in ('old-props', 'locations'):
|
|
519
|
+
data[name][prop_name] = values
|
|
520
|
+
case _:
|
|
521
|
+
continue
|
|
453
522
|
|
|
454
523
|
avg_over_state = re.search(r'(\(monitor/average-over-state.*)', general, re.M).group(1)
|
|
455
524
|
avg_over_state_list = stringify_nested_list(sexpdata.loads(avg_over_state, true=None)[1])
|
|
456
525
|
for rd in avg_over_state_list:
|
|
457
526
|
name = rd[0]
|
|
458
|
-
|
|
459
|
-
iter_range = rd[2][:2]
|
|
460
|
-
data[name]['iter-range'] = ' -> '.join(iter_range)
|
|
527
|
+
data[name]['iter-range'] = rd[2][0] + ' -> ' + rd[2][1]
|
|
461
528
|
|
|
462
529
|
if data[name].get('per-zone?') == '#f' or data[name].get('per-surface?') == '#f':
|
|
463
530
|
value = rd[2][2]
|
|
464
531
|
data[name]['average-over-state'] = value
|
|
465
532
|
else:
|
|
533
|
+
ids = [id_.split('.')[0] for id_ in rd[1]]
|
|
466
534
|
values = sum(rd[2][2:], [])
|
|
467
535
|
right_order_ids = data[name].get('zone-list') or data[name].get('surface-ids') or data[name].get('zone-ids')
|
|
468
536
|
sorted_values = [0] * len(values)
|
|
@@ -484,13 +552,16 @@ def _read_plotsets(texts: CaseTexts) -> dict[str, Any]:
|
|
|
484
552
|
|
|
485
553
|
data: dict[str, Any] = {}
|
|
486
554
|
for plotset in plotsets_list:
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
555
|
+
name = plotset[0][2]
|
|
556
|
+
data[name] = {}
|
|
557
|
+
for plotset_property in plotset[1:]:
|
|
558
|
+
match plotset_property:
|
|
559
|
+
case [prop_name, '.', value]:
|
|
560
|
+
data[name][prop_name] = value
|
|
561
|
+
case [prop_name, *values] if prop_name not in ('old-props'):
|
|
562
|
+
data[name][prop_name] = values
|
|
563
|
+
case _:
|
|
564
|
+
continue
|
|
494
565
|
return {'plotsets': data}
|
|
495
566
|
|
|
496
567
|
|
|
@@ -502,13 +573,16 @@ def _read_monitorsets(texts: CaseTexts) -> dict[str, Any]:
|
|
|
502
573
|
|
|
503
574
|
data: dict[str, Any] = {}
|
|
504
575
|
for monitorset in monitorsets_list:
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
576
|
+
name = monitorset[0][2]
|
|
577
|
+
data[name] = {}
|
|
578
|
+
for monitorset_property in monitorset[1:]:
|
|
579
|
+
match monitorset_property:
|
|
580
|
+
case [prop_name, '.', value]:
|
|
581
|
+
data[name][prop_name] = value
|
|
582
|
+
case [prop_name, *values] if prop_name not in ('old-props'):
|
|
583
|
+
data[name][prop_name] = values
|
|
584
|
+
case _:
|
|
585
|
+
continue
|
|
512
586
|
return {'monitorsets': data}
|
|
513
587
|
|
|
514
588
|
|
|
@@ -596,31 +670,29 @@ def _read_surfaces(texts: CaseTexts) -> dict[str, Any]:
|
|
|
596
670
|
data: dict[str, Any] = {}
|
|
597
671
|
for surface_def in surface_def_list:
|
|
598
672
|
surface = surface_def[2]
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
case 'line-surface':
|
|
602
|
-
virtual_id = surface[1]
|
|
673
|
+
match surface:
|
|
674
|
+
case ['line-surface', virtual_id, start, end]:
|
|
603
675
|
data[virtual_id_name_map[virtual_id]] = {
|
|
604
|
-
'type':
|
|
605
|
-
'start':
|
|
606
|
-
'end':
|
|
676
|
+
'type': 'line-surface',
|
|
677
|
+
'start': start,
|
|
678
|
+
'end': end,
|
|
607
679
|
}
|
|
608
|
-
case 'plane-surface':
|
|
609
|
-
virtual_id = surface[1]
|
|
680
|
+
case ['plane-surface', virtual_id, point1, point2, point3, bounded, [ref_plane, direction_vector, ref_point]]:
|
|
610
681
|
data[virtual_id_name_map[virtual_id]] = {
|
|
611
|
-
'type':
|
|
612
|
-
'point 1':
|
|
613
|
-
'point 2':
|
|
614
|
-
'point 3':
|
|
615
|
-
'bounded':
|
|
682
|
+
'type': 'plane-surface',
|
|
683
|
+
'point 1': point1,
|
|
684
|
+
'point 2': point2,
|
|
685
|
+
'point 3': point3,
|
|
686
|
+
'bounded': bounded,
|
|
616
687
|
'method': {
|
|
617
|
-
'
|
|
618
|
-
'direction vector':
|
|
619
|
-
'reference point':
|
|
620
|
-
}
|
|
688
|
+
'reference plane': ref_plane,
|
|
689
|
+
'direction vector': direction_vector,
|
|
690
|
+
'reference point': ref_point,
|
|
691
|
+
}
|
|
621
692
|
}
|
|
622
693
|
case _:
|
|
623
694
|
continue
|
|
695
|
+
|
|
624
696
|
return {'surfaces': data}
|
|
625
697
|
|
|
626
698
|
|
|
@@ -635,25 +707,19 @@ def _read_contours(texts: CaseTexts) -> dict[str, Any]:
|
|
|
635
707
|
|
|
636
708
|
data: dict[str, Any] = {}
|
|
637
709
|
for contour in contours_list:
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
contour_dict['color-map'] = {
|
|
653
|
-
color_map[0]: color_map[2]
|
|
654
|
-
for color_map in contour[-7][1:]
|
|
655
|
-
}
|
|
656
|
-
data[contour_dict['name']] = contour_dict
|
|
710
|
+
name = contour[0][2]
|
|
711
|
+
data[name] = {}
|
|
712
|
+
for contour_property in contour[1:]:
|
|
713
|
+
match contour_property:
|
|
714
|
+
case [property_name, '.', value]:
|
|
715
|
+
data[name][property_name] = value
|
|
716
|
+
case ['surfaces-list', *surfaces_list]:
|
|
717
|
+
data[name]['surfaces-list'] = surfaces_list
|
|
718
|
+
case [property_name, *values] if property_name in ('range-options', 'color-map'):
|
|
719
|
+
data[name][property_name] = {value[0]: value[2] for value in values}
|
|
720
|
+
case _:
|
|
721
|
+
continue
|
|
722
|
+
|
|
657
723
|
return {'contours': data}
|
|
658
724
|
|
|
659
725
|
|
|
@@ -665,33 +731,19 @@ def _read_vectors(texts: CaseTexts) -> dict[str, Any]:
|
|
|
665
731
|
|
|
666
732
|
data: dict[str, Any] = {}
|
|
667
733
|
for vector in vectors_list:
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
}
|
|
682
|
-
vector_dict['scale'] = {
|
|
683
|
-
scale[0]: scale[2]
|
|
684
|
-
for scale in vector[9][1:]
|
|
685
|
-
}
|
|
686
|
-
vector_dict['vector-opt'] = {
|
|
687
|
-
vector_opt[0]: vector_opt[2]
|
|
688
|
-
for vector_opt in vector[-6][1:]
|
|
689
|
-
}
|
|
690
|
-
vector_dict['color-map'] = {
|
|
691
|
-
color_map[0]: color_map[2]
|
|
692
|
-
for color_map in vector[-5][1:]
|
|
693
|
-
}
|
|
694
|
-
data[vector_dict['name']] = vector_dict
|
|
734
|
+
name = vector[0][2]
|
|
735
|
+
data[name] = {}
|
|
736
|
+
for vector_property in vector[1:]:
|
|
737
|
+
match vector_property:
|
|
738
|
+
case [property_name, '.', value]:
|
|
739
|
+
data[name][property_name] = value
|
|
740
|
+
case ['surfaces-list', *surfaces_list]:
|
|
741
|
+
data[name]['surfaces-list'] = surfaces_list
|
|
742
|
+
case [property_name, *values] if property_name in ('range-options', 'scale', 'vector-opt', 'color-map'):
|
|
743
|
+
data[name][property_name] = {value[0]: value[2] for value in values}
|
|
744
|
+
case _:
|
|
745
|
+
continue
|
|
746
|
+
|
|
695
747
|
return {'vectors': data}
|
|
696
748
|
|
|
697
749
|
|
|
@@ -703,17 +755,19 @@ def _read_xy_plot(texts: CaseTexts) -> dict[str, Any]:
|
|
|
703
755
|
|
|
704
756
|
data: dict[str, Any] = {}
|
|
705
757
|
for xy_plot in xy_plots_list:
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
758
|
+
name = xy_plot[0][2]
|
|
759
|
+
data[name] = {}
|
|
760
|
+
for xy_plot_property in xy_plot[1:]:
|
|
761
|
+
match xy_plot_property:
|
|
762
|
+
case [property_name, '.', value]:
|
|
763
|
+
data[name][property_name] = value
|
|
764
|
+
case ['surfaces-list', *surfaces_list]:
|
|
765
|
+
data[name]['surfaces-list'] = surfaces_list
|
|
766
|
+
case [property_name, *values] if property_name == 'options':
|
|
767
|
+
data[name][property_name] = {value[0]: value[2] for value in values}
|
|
768
|
+
case _:
|
|
769
|
+
continue
|
|
770
|
+
|
|
717
771
|
return {'xy-plot': data}
|
|
718
772
|
|
|
719
773
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|