zoomy-core 0.1.14__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.
- decorators/decorators.py +25 -0
- fvm/__init__.py +0 -0
- fvm/flux.py +52 -0
- fvm/nonconservative_flux.py +97 -0
- fvm/ode.py +55 -0
- fvm/solver_numpy.py +297 -0
- fvm/timestepping.py +13 -0
- mesh/__init__.py +0 -0
- mesh/mesh.py +1239 -0
- mesh/mesh_extrude.py +168 -0
- mesh/mesh_util.py +487 -0
- misc/__init__.py +0 -0
- misc/custom_types.py +6 -0
- misc/interpolation.py +140 -0
- misc/io.py +448 -0
- misc/logger_config.py +18 -0
- misc/misc.py +218 -0
- model/__init__.py +0 -0
- model/analysis.py +147 -0
- model/basefunction.py +113 -0
- model/basemodel.py +513 -0
- model/boundary_conditions.py +193 -0
- model/initial_conditions.py +171 -0
- model/model.py +65 -0
- model/models/GN.py +70 -0
- model/models/advection.py +53 -0
- model/models/basisfunctions.py +181 -0
- model/models/basismatrices.py +381 -0
- model/models/coupled_constrained.py +60 -0
- model/models/poisson.py +41 -0
- model/models/shallow_moments.py +757 -0
- model/models/shallow_moments_sediment.py +378 -0
- model/models/shallow_moments_topo.py +423 -0
- model/models/shallow_moments_variants.py +1509 -0
- model/models/shallow_water.py +266 -0
- model/models/shallow_water_topo.py +111 -0
- model/models/shear_shallow_flow.py +594 -0
- model/models/sme_turbulent.py +613 -0
- model/models/vam.py +455 -0
- postprocessing/__init__.py +0 -0
- postprocessing/plotting.py +244 -0
- postprocessing/postprocessing.py +75 -0
- preprocessing/__init__.py +0 -0
- preprocessing/openfoam_moments.py +453 -0
- transformation/__init__.py +0 -0
- transformation/helpers.py +25 -0
- transformation/to_amrex.py +241 -0
- transformation/to_c.py +185 -0
- transformation/to_jax.py +14 -0
- transformation/to_numpy.py +118 -0
- transformation/to_openfoam.py +258 -0
- transformation/to_ufl.py +67 -0
- zoomy_core-0.1.14.dist-info/METADATA +52 -0
- zoomy_core-0.1.14.dist-info/RECORD +57 -0
- zoomy_core-0.1.14.dist-info/WHEEL +5 -0
- zoomy_core-0.1.14.dist-info/licenses/LICENSE +674 -0
- zoomy_core-0.1.14.dist-info/top_level.txt +8 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
import h5py
|
|
6
|
+
|
|
7
|
+
_HAVE_H5PY = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
_HAVE_H5PY = False
|
|
10
|
+
|
|
11
|
+
import zoomy_core.mesh.mesh as petscMesh
|
|
12
|
+
import zoomy_core.misc.io as io
|
|
13
|
+
from zoomy_core.misc.logger_config import logger
|
|
14
|
+
from zoomy_core.transformation.to_numpy import NumpyRuntimeModel
|
|
15
|
+
from zoomy_core.misc import misc as misc
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def vtk_project_2d_to_3d(
|
|
19
|
+
model, settings, start_at_time=0, scale_h=1.0, filename='out_3d'
|
|
20
|
+
):
|
|
21
|
+
if not _HAVE_H5PY:
|
|
22
|
+
raise ImportError("h5py is required for vtk_project_2d_to_3d function.")
|
|
23
|
+
Nz = model.number_of_points_3d
|
|
24
|
+
main_dir = misc.get_main_directory()
|
|
25
|
+
|
|
26
|
+
path_to_simulation = os.path.join(main_dir, os.path.join(settings.output.directory, f"{settings.output.filename}.h5"))
|
|
27
|
+
sim = h5py.File(path_to_simulation, "r")
|
|
28
|
+
settings = io.load_settings(settings.output.directory)
|
|
29
|
+
fields = sim["fields"]
|
|
30
|
+
mesh = petscMesh.Mesh.from_hdf5(path_to_simulation)
|
|
31
|
+
n_snapshots = len(list(fields.keys()))
|
|
32
|
+
|
|
33
|
+
Z = np.linspace(0, 1, Nz)
|
|
34
|
+
|
|
35
|
+
mesh_extr = petscMesh.Mesh.extrude_mesh(mesh, Nz)
|
|
36
|
+
output_path = os.path.join(main_dir, settings.output.directory + f"/{filename}.h5")
|
|
37
|
+
mesh_extr.write_to_hdf5(output_path)
|
|
38
|
+
save_fields = io.get_save_fields_simple(output_path, True)
|
|
39
|
+
|
|
40
|
+
#mesh = GradientMesh.fromMesh(mesh)
|
|
41
|
+
i_count = 0
|
|
42
|
+
pde = NumpyRuntimeModel(model)
|
|
43
|
+
for i_snapshot in range(n_snapshots):
|
|
44
|
+
group_name = "iteration_" + str(i_snapshot)
|
|
45
|
+
group = fields[group_name]
|
|
46
|
+
time = group["time"][()]
|
|
47
|
+
if time < start_at_time:
|
|
48
|
+
continue
|
|
49
|
+
Q = group["Q"][()]
|
|
50
|
+
Qaux = group["Qaux"][()]
|
|
51
|
+
|
|
52
|
+
rhoUVWP = np.zeros((Q.shape[1] * Nz, 6), dtype=float)
|
|
53
|
+
|
|
54
|
+
#for i_elem, (q, qaux) in enumerate(zip(Q.T, Qaux.T)):
|
|
55
|
+
# for iz, z in enumerate(Z):
|
|
56
|
+
# rhoUVWP[i_elem + (iz * mesh.n_cells), :] = pde.project_2d_to_3d(np.array([0, 0, z]), q, qaux, parameters)
|
|
57
|
+
|
|
58
|
+
for iz, z in enumerate(Z):
|
|
59
|
+
Qnew = pde.project_2d_to_3d(z, Q[:, :mesh.n_inner_cells], Qaux[:, :mesh.n_inner_cells], model.parameter_values).T
|
|
60
|
+
|
|
61
|
+
#rhoUVWP[i_elem + (iz * mesh.n_cells), :] = pde.project_2d_to_3d(np.array([0, 0, z]), q, qaux, parameters)
|
|
62
|
+
# rhoUVWP[(iz * mesh.n_inner_cells):((iz+1) * mesh.n_inner_cells), 0] = Q[0, :mesh.n_inner_cells]
|
|
63
|
+
rhoUVWP[(iz * mesh.n_inner_cells):((iz+1) * mesh.n_inner_cells), :] = Qnew[iz, :]
|
|
64
|
+
|
|
65
|
+
# rhoUVWP[mesh.n_inner_cells:mesh.n_inner_cells+mesh.n_inner_cells, 0] = Q[0, :mesh.n_inner_cells]
|
|
66
|
+
|
|
67
|
+
qaux = np.zeros((Q.shape[1]*Nz, 1), dtype=float)
|
|
68
|
+
_ = save_fields(i_snapshot, time, rhoUVWP.T, qaux.T)
|
|
69
|
+
i_count += 1
|
|
70
|
+
|
|
71
|
+
logger.info(f"Converted snapshot {i_snapshot}/{n_snapshots}")
|
|
72
|
+
|
|
73
|
+
io.generate_vtk(output_path, filename=filename)
|
|
74
|
+
logger.info(f"Output is written to: {output_path}/{filename}.*.vtk")
|
|
75
|
+
|
|
File without changes
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
try:
|
|
2
|
+
_HAVE_MATPLOTLIB = True
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
except ImportError:
|
|
5
|
+
_HAVE_MATPLOTLIB = False
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
import os
|
|
10
|
+
from scipy.spatial import KDTree
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
import pyvista as pv
|
|
14
|
+
|
|
15
|
+
_HAVE_PYVISTA = True
|
|
16
|
+
except ImportError:
|
|
17
|
+
_HAVE_PYVISTA = False
|
|
18
|
+
|
|
19
|
+
from zoomy_core.mesh.fvm_mesh import Mesh
|
|
20
|
+
from zoomy_core.misc.io import _save_fields_to_hdf5 as save_fields_to_hdf5
|
|
21
|
+
import zoomy_core.misc.io as io
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
main_dir = misc.get_main_directory()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def load_file(filename):
|
|
29
|
+
if not _HAVE_PYVISTA:
|
|
30
|
+
raise ImportError("pyvista is required for load_file function.")
|
|
31
|
+
reader = pv.get_reader(filename)
|
|
32
|
+
# get(0) gets us the internal (not boundary) data. The boundary data is non-existant anyways in our case
|
|
33
|
+
vtkfile = reader.read().get(0)
|
|
34
|
+
return vtkfile
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_fields(vtkfile, fieldnames):
|
|
38
|
+
fields = []
|
|
39
|
+
for fieldname in fieldnames:
|
|
40
|
+
# point field)s
|
|
41
|
+
# field = vtkfile.point_data[fieldname]
|
|
42
|
+
field = vtkfile.cell_data[fieldname]
|
|
43
|
+
fields.append(np.array(field))
|
|
44
|
+
return fields
|
|
45
|
+
# return np.array(fields)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_coordinates(vtkfile):
|
|
49
|
+
# point coordinates
|
|
50
|
+
# return np.array(vtkfile.points)
|
|
51
|
+
# cell centers
|
|
52
|
+
return vtkfile.cell_centers().points
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_time(vtkfile):
|
|
56
|
+
return vtkfile.field_data["TimeValue"][0]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def sort_data(coordinates, fields):
|
|
60
|
+
# Sort by z, y, x
|
|
61
|
+
order = np.lexsort((coordinates[:, 0], coordinates[:, 1], coordinates[:, 2]))
|
|
62
|
+
return order
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def apply_order(coordinates, fields, order):
|
|
66
|
+
coordinates_copy = np.array(coordinates)
|
|
67
|
+
fields_copy = deepcopy(fields)
|
|
68
|
+
for d in range(coordinates.shape[1]):
|
|
69
|
+
coordinates[:, d] = coordinates_copy[order, d]
|
|
70
|
+
for field, field_copy in zip(fields, fields_copy):
|
|
71
|
+
field[:] = field_copy[order]
|
|
72
|
+
return coordinates, fields
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_number_of_layers_and_elements_in_plane(coordinates):
|
|
76
|
+
layers = len(np.unique(coordinates[:, 2]))
|
|
77
|
+
n_elements_plane = int(coordinates[:, 0].size / layers)
|
|
78
|
+
return layers, n_elements_plane
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_layer(data, layer, n_elements_plane):
|
|
82
|
+
return data[layer * n_elements_plane : (layer + 1) * n_elements_plane]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def compute_height(
|
|
86
|
+
alpha, n_layers, n_elements_per_layer, total_height=1.0, threshold=0.5
|
|
87
|
+
):
|
|
88
|
+
height = np.zeros(n_elements_per_layer)
|
|
89
|
+
active = np.ones(n_elements_per_layer, dtype=bool)
|
|
90
|
+
dh = total_height / n_layers
|
|
91
|
+
for i in range(n_layers):
|
|
92
|
+
alpha_layer = get_layer(alpha, i, n_elements_per_layer)
|
|
93
|
+
height += np.where(np.logical_and((alpha_layer >= threshold), active), dh, 0)
|
|
94
|
+
return height
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def extract_faces(mesh):
|
|
98
|
+
faces = []
|
|
99
|
+
i, offset = 0, 0
|
|
100
|
+
cc = mesh.cells # fetch up front
|
|
101
|
+
while i < mesh.n_cells:
|
|
102
|
+
nn = cc[offset]
|
|
103
|
+
faces.append(cc[offset + 1 : offset + 1 + nn])
|
|
104
|
+
offset += nn + 1
|
|
105
|
+
i += 1
|
|
106
|
+
return np.array(faces)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def sort_faces(faces, order):
|
|
110
|
+
for face in faces:
|
|
111
|
+
for i, point in enumerate(face):
|
|
112
|
+
face[i] = order[point]
|
|
113
|
+
faces = faces[order]
|
|
114
|
+
return faces
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def add_noslip_layer(U, n_elements_per_layer):
|
|
118
|
+
Unew = np.zeros((U.shape[0] + n_elements_per_layer, U.shape[1]))
|
|
119
|
+
for d in range(U.shape[1]):
|
|
120
|
+
Unew[n_elements_per_layer:, d] = U[:, d]
|
|
121
|
+
return Unew
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def extract_velocity_column_at_coordinate(U, n_elements_per_layer, n_layer, coordinate):
|
|
125
|
+
u = np.array(
|
|
126
|
+
[
|
|
127
|
+
get_layer(U[:, 0], i, n_elements_per_layer)[coordinate]
|
|
128
|
+
for i in range(n_layer + 1)
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
v = np.array(
|
|
132
|
+
[
|
|
133
|
+
get_layer(U[:, 1], i, n_elements_per_layer)[coordinate]
|
|
134
|
+
for i in range(n_layer + 1)
|
|
135
|
+
]
|
|
136
|
+
)
|
|
137
|
+
w = np.array(
|
|
138
|
+
[
|
|
139
|
+
get_layer(U[:, 2], i, n_elements_per_layer)[coordinate]
|
|
140
|
+
for i in range(n_layer + 1)
|
|
141
|
+
]
|
|
142
|
+
)
|
|
143
|
+
return u, v, w
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def shift_integration_interval(xi):
|
|
147
|
+
return (xi + 1) / 2
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def plot_basis(basis_generator):
|
|
151
|
+
fig, ax = plt.subplots()
|
|
152
|
+
basis = [basis_generator(n) for n in range(0, 8)]
|
|
153
|
+
X = np.linspace(0, 1, 100)
|
|
154
|
+
for i in range(8):
|
|
155
|
+
ax.plot(basis[i](X), X)
|
|
156
|
+
return fig, ax
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def moment_projection(field, n_layers, basis, integration_order=None):
|
|
160
|
+
if integration_order is None:
|
|
161
|
+
integration_order = max(len(basis), n_layers)
|
|
162
|
+
xi, wi = np.polynomial.legendre.leggauss(integration_order)
|
|
163
|
+
xi = shift_integration_interval(xi)
|
|
164
|
+
dz = 1 / (n_layers)
|
|
165
|
+
xp = np.arange(dz / 2, 1 - dz / 2, dz)
|
|
166
|
+
xp = np.insert(xp, 0, 0)
|
|
167
|
+
fp = field
|
|
168
|
+
field_xi = np.interp(xi, xp, fp)
|
|
169
|
+
basis_xi = [basis[i](xi) for i in range(len(basis))]
|
|
170
|
+
projections = np.zeros(len(basis))
|
|
171
|
+
for i in range(len(basis)):
|
|
172
|
+
projections[i] = np.sum(field_xi * basis_xi[i] * wi)
|
|
173
|
+
return projections
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def convert_openfoam_to_moments_single(filename, n_levels):
|
|
177
|
+
vtkfile = load_file(filename)
|
|
178
|
+
coordinates = get_coordinates(vtkfile)
|
|
179
|
+
n_layer, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
180
|
+
coordinates
|
|
181
|
+
)
|
|
182
|
+
fields = get_fields(vtkfile, ["alpha.water", "U"])
|
|
183
|
+
sort_order = sort_data(coordinates, fields)
|
|
184
|
+
coordinates, fields = apply_order(coordinates, fields, sort_order)
|
|
185
|
+
fields[1] = add_noslip_layer(fields[1], n_elements_per_layer)
|
|
186
|
+
time = get_time(vtkfile)
|
|
187
|
+
Q, basis = compute_shallow_moment_projection(fields, coordinates, n_levels)
|
|
188
|
+
return coordinates, Q, time, basis
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def convert_openfoam_to_moments(
|
|
192
|
+
filepath, n_levels, filepath_mesh_for_order, meshtype_order="triganle"
|
|
193
|
+
):
|
|
194
|
+
filepath_vtk = os.path.join(filepath, "VTK")
|
|
195
|
+
filename = "fields_openfoam.hdf5"
|
|
196
|
+
sort_order = None
|
|
197
|
+
|
|
198
|
+
# file order
|
|
199
|
+
file_number_list = []
|
|
200
|
+
file_start = ""
|
|
201
|
+
for i_file, file in enumerate(os.listdir(filepath_vtk)):
|
|
202
|
+
if file.endswith(".vtm"):
|
|
203
|
+
file_start = file.split("_")[0]
|
|
204
|
+
file_start = file.rsplit("_", 1)[0]
|
|
205
|
+
index = int(file.rsplit("_", 1)[1].split(".")[0])
|
|
206
|
+
# index = int(re.findall(r'\d+', file)[-1])
|
|
207
|
+
file_number_list.append(index)
|
|
208
|
+
|
|
209
|
+
file_number_list.sort()
|
|
210
|
+
print(file_number_list)
|
|
211
|
+
|
|
212
|
+
# first iteration
|
|
213
|
+
file0 = (
|
|
214
|
+
os.path.join(filepath_vtk, file_start) + "_" + str(file_number_list[0]) + ".vtm"
|
|
215
|
+
)
|
|
216
|
+
coordinates, Q, time, basis = convert_openfoam_to_moments_single(file0, n_levels)
|
|
217
|
+
mesh_order = Mesh.load_gmsh(filepath_mesh_for_order, meshtype_order)
|
|
218
|
+
Q, sort_order = sort_fields_by_mesh(mesh_order, coordinates, Q)
|
|
219
|
+
if os.path.exists(os.path.join(filepath, filename)):
|
|
220
|
+
os.remove(os.path.join(filepath, filename))
|
|
221
|
+
save_fields_to_hdf5(filepath, 0, time, Q.T, Qaux=None, filename=filename)
|
|
222
|
+
|
|
223
|
+
# loop iterations
|
|
224
|
+
iter = 1
|
|
225
|
+
total = len(file_number_list)
|
|
226
|
+
print(f"Conversion {iter}/{total} completed.")
|
|
227
|
+
iter += 1
|
|
228
|
+
# loop iterations
|
|
229
|
+
for i, i_file in enumerate(file_number_list[1:]):
|
|
230
|
+
file = os.path.join(filepath_vtk, file_start) + "_" + str(i_file) + ".vtm"
|
|
231
|
+
coordinates, Q, time, basis = convert_openfoam_to_moments_single(file, n_levels)
|
|
232
|
+
Q = apply_order_to_fields(sort_order, Q)
|
|
233
|
+
save_fields_to_hdf5(filepath, i + 1, time, Q.T, Qaux=None, filename=filename)
|
|
234
|
+
print(f"Conversion {iter}/{total} completed.")
|
|
235
|
+
iter += 1
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def sort_fields_by_mesh(mesh, coordinates, Q):
|
|
239
|
+
# coordinates are still 3d, while Q is 2d and the mesh is 2d
|
|
240
|
+
n_layers, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
241
|
+
coordinates
|
|
242
|
+
)
|
|
243
|
+
coords_2d = coordinates[:n_elements_per_layer, :2]
|
|
244
|
+
coords_ordered = mesh.element_center
|
|
245
|
+
# Construct a KDTree from coords_2d
|
|
246
|
+
tree = KDTree(coords_2d)
|
|
247
|
+
|
|
248
|
+
# Find the indices of the nearest points in coords_2d to the points in coords_ordered
|
|
249
|
+
_, indices = tree.query(coords_ordered)
|
|
250
|
+
|
|
251
|
+
# Use these indices to sort Q and coords_2d
|
|
252
|
+
Q_sorted = Q[:, indices]
|
|
253
|
+
return Q_sorted, indices
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def apply_order_to_fields(order, Q):
|
|
257
|
+
return Q[:, order]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def plot_contour(coordinates, field):
|
|
261
|
+
if not _HAVE_MATPLOTLIB:
|
|
262
|
+
raise ImportError("matplotlib is required for plot_contour function.")
|
|
263
|
+
fig, ax = plt.subplots()
|
|
264
|
+
n_layer, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
265
|
+
coordinates
|
|
266
|
+
)
|
|
267
|
+
X = get_layer(coordinates[:, 0], 0, n_elements_per_layer)
|
|
268
|
+
Y = get_layer(coordinates[:, 1], 0, n_elements_per_layer)
|
|
269
|
+
# Z = get_layer(fields[1][:, 0], 1, n_elements_per_layer)
|
|
270
|
+
# Z = get_layer(fields[0], 12, n_elements_per_layer)
|
|
271
|
+
# Z = compute_height(fields[0], n_layer, n_elements_per_layer)
|
|
272
|
+
Z = field
|
|
273
|
+
colorbar = ax.tricontourf(X, Y, Z)
|
|
274
|
+
ax.set_aspect("equal")
|
|
275
|
+
|
|
276
|
+
circle = plt.Circle((0.5, 1), radius=0.2, fc="silver", zorder=10, edgecolor="k")
|
|
277
|
+
plt.gca().add_patch(circle)
|
|
278
|
+
fig.colorbar(colorbar)
|
|
279
|
+
return fig, ax
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def basis_legendre(i):
|
|
283
|
+
def f(x):
|
|
284
|
+
basis = np.polynomial.legendre.Legendre.basis(i, domain=[0, 1], window=[-1, 1])
|
|
285
|
+
return basis(x) * basis(0)
|
|
286
|
+
|
|
287
|
+
return f
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def compute_shallow_moment_projection(
|
|
291
|
+
fields, coordinates, n_levels, basis_generator=basis_legendre
|
|
292
|
+
):
|
|
293
|
+
n_layers, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
294
|
+
coordinates
|
|
295
|
+
)
|
|
296
|
+
height = compute_height(fields[0], n_layers, n_elements_per_layer)
|
|
297
|
+
basis = [basis_generator(n) for n in range(0, n_levels + 1)]
|
|
298
|
+
alphas = np.zeros((n_elements_per_layer, n_levels + 1))
|
|
299
|
+
betas = np.zeros((n_elements_per_layer, n_levels + 1))
|
|
300
|
+
for i in range(n_elements_per_layer):
|
|
301
|
+
u, v, w = extract_velocity_column_at_coordinate(
|
|
302
|
+
fields[1], n_elements_per_layer, n_layers, i
|
|
303
|
+
)
|
|
304
|
+
alphas[i] = moment_projection(u, n_layers + 1, basis)
|
|
305
|
+
betas[i] = moment_projection(v, n_layers + 1, basis)
|
|
306
|
+
return np.concatenate(
|
|
307
|
+
(height.reshape((n_elements_per_layer, 1)), alphas, betas), axis=1
|
|
308
|
+
).T, basis
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def plot_data_vs_moments(fields, coordinates, Q, basis, coordinate_index):
|
|
312
|
+
if _HAVE_MATPLOTLIB is False:
|
|
313
|
+
raise ImportError("matplotlib is required for plot_data_vs_moments function.")
|
|
314
|
+
n_layers, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
315
|
+
coordinates
|
|
316
|
+
)
|
|
317
|
+
n_levels = int((Q.shape[0] - 1) / 2) - 1
|
|
318
|
+
X = np.linspace(0, 1, 100)
|
|
319
|
+
U = np.array(
|
|
320
|
+
[basis[i](X) * Q[1 + i, coordinate_index] for i in range(len(basis))]
|
|
321
|
+
).sum(axis=0)
|
|
322
|
+
V = np.array(
|
|
323
|
+
[
|
|
324
|
+
basis[i](X) * Q[1 + n_levels + 1 + i, coordinate_index]
|
|
325
|
+
for i in range(len(basis))
|
|
326
|
+
]
|
|
327
|
+
).sum(axis=0)
|
|
328
|
+
dz = 1 / (n_layers)
|
|
329
|
+
x = np.linspace(dz / 2, 1 - dz / 2, n_layers)
|
|
330
|
+
x = np.insert(x, 0, 0)
|
|
331
|
+
u, v, w = extract_velocity_column_at_coordinate(
|
|
332
|
+
fields[1], n_elements_per_layer, n_layers, coordinate_index
|
|
333
|
+
)
|
|
334
|
+
fig, ax = plt.subplots(2)
|
|
335
|
+
ax[0].plot(U, X)
|
|
336
|
+
ax[0].plot(u, x)
|
|
337
|
+
ax[1].plot(V, X)
|
|
338
|
+
ax[1].plot(v, x)
|
|
339
|
+
return fig, ax
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def load_openfoam_file(filepath):
|
|
343
|
+
vtkfile = load_file(filepath)
|
|
344
|
+
coordinates = get_coordinates(vtkfile)
|
|
345
|
+
n_layer, n_elements_per_layer = get_number_of_layers_and_elements_in_plane(
|
|
346
|
+
coordinates
|
|
347
|
+
)
|
|
348
|
+
fields = get_fields(vtkfile, ["alpha.water", "U"])
|
|
349
|
+
sort_order = sort_data(coordinates, fields)
|
|
350
|
+
coordinates, fields = apply_order(coordinates, fields, sort_order)
|
|
351
|
+
fields[1] = add_noslip_layer(fields[1], n_elements_per_layer)
|
|
352
|
+
time = get_time(vtkfile)
|
|
353
|
+
return coordinates, fields, time
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def test_load():
|
|
357
|
+
filepath = os.path.join(
|
|
358
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse"),
|
|
359
|
+
"channelflow_coarse_0.vtm",
|
|
360
|
+
)
|
|
361
|
+
coordinates, fields, time = load_openfoam_file(filepath)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def test_moment_projection():
|
|
365
|
+
filepath = os.path.join(
|
|
366
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse"),
|
|
367
|
+
"channelflow_coarse_0.vtm",
|
|
368
|
+
)
|
|
369
|
+
coordinates, fields, time = load_openfoam_file(filepath)
|
|
370
|
+
Q, basis = compute_shallow_moment_projection(fields, coordinates, 3)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def test_convert_openfoam_single():
|
|
374
|
+
filepath = os.path.join(
|
|
375
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse"),
|
|
376
|
+
"channelflow_coarse_0.vtm",
|
|
377
|
+
)
|
|
378
|
+
X, Q, t, basis = convert_openfoam_to_moments_single(filepath, 3)
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def test_plots():
|
|
382
|
+
if _HAVE_MATPLOTLIB is False:
|
|
383
|
+
raise ImportError("matplotlib is required for test_plots function.")
|
|
384
|
+
filepath = os.path.join(
|
|
385
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse"),
|
|
386
|
+
"channelflow_coarse_0.vtm",
|
|
387
|
+
)
|
|
388
|
+
coordinates, fields, time = load_openfoam_file(filepath)
|
|
389
|
+
X, Q, t, basis = convert_openfoam_to_moments_single(filepath, 3)
|
|
390
|
+
fig, ax = plot_data_vs_moments(fields, coordinates, Q, basis, 0)
|
|
391
|
+
plt.show()
|
|
392
|
+
fig, ax = plot_basis(basis_legendre)
|
|
393
|
+
plt.show()
|
|
394
|
+
fig, ax = plot_contour(coordinates, Q[0])
|
|
395
|
+
plt.show()
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def test_sort():
|
|
399
|
+
filepath = os.path.join(
|
|
400
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse"),
|
|
401
|
+
"channelflow_coarse_0.vtm",
|
|
402
|
+
)
|
|
403
|
+
filepath_gmsh = os.path.join(
|
|
404
|
+
os.path.join(main_dir, "meshes/channel_openfoam/mesh_coarse_2d.msh")
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
mesh_gmsh = Mesh.load_gmsh(filepath_gmsh, "triangle")
|
|
408
|
+
mesh_gmsh.write_to_hdf5(
|
|
409
|
+
os.path.join(os.path.join(main_dir, "openfoam_data/channelflow_coarse"))
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
filepath_hdf_mesh = os.path.join(
|
|
413
|
+
os.path.join(main_dir, "openfoam_data/channelflow_coarse/mesh.hdf5")
|
|
414
|
+
)
|
|
415
|
+
mesh = Mesh.from_hdf5(filepath_hdf_mesh)
|
|
416
|
+
|
|
417
|
+
coordinates, fields, time = load_openfoam_file(filepath)
|
|
418
|
+
Q, basis = compute_shallow_moment_projection(fields, coordinates, 3)
|
|
419
|
+
|
|
420
|
+
# mesh_comparison = Mesh.load_gmsh(os.path.join(main_dir, 'meshes/channel_openfoam/mesh_coarse_3d.msh'), 'tetra')
|
|
421
|
+
|
|
422
|
+
sort_fields_by_mesh(mesh, coordinates, Q)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def test_convert_openfoam_to_moments(level=0):
|
|
426
|
+
# filepath = os.path.join(main_dir, 'openfoam_data/channelflow_coarse')
|
|
427
|
+
foam_sim = os.getenv("FOAM_SIM")
|
|
428
|
+
filepath = os.path.join(foam_sim, "multiphase/interFoam/RAS/channelflow_mid")
|
|
429
|
+
filepath_target_mesh = os.path.join(
|
|
430
|
+
os.path.join(main_dir, "meshes/simple_openfoam/mesh_2d_mid.msh")
|
|
431
|
+
)
|
|
432
|
+
convert_openfoam_to_moments(
|
|
433
|
+
filepath, level, filepath_target_mesh, meshtype_order="triangle"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
if __name__ == "__main__":
|
|
438
|
+
# test_load()
|
|
439
|
+
# test_moment_projection()
|
|
440
|
+
# test_convert_openfoam_single()
|
|
441
|
+
# test_plots()
|
|
442
|
+
# test_sort()
|
|
443
|
+
test_convert_openfoam_to_moments(level=1)
|
|
444
|
+
filepath = os.path.join(main_dir, "openfoam_data/channelflow_mid")
|
|
445
|
+
filepath_mesh = os.path.join(main_dir, "meshes/simple_openfoam/mesh_2d_mid.msh")
|
|
446
|
+
io.generate_vtk(
|
|
447
|
+
filepath,
|
|
448
|
+
filepath_gmsh=filepath_mesh,
|
|
449
|
+
gmsh_mesh_type="triangle",
|
|
450
|
+
filename_fields="fields_openfoam.hdf5",
|
|
451
|
+
filename_out="fields_openfoam_vtk",
|
|
452
|
+
skip_aux=True,
|
|
453
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from sympy import MatrixSymbol, fraction, cancel, Matrix
|
|
2
|
+
|
|
3
|
+
from zoomy_core.misc.misc import Zstruct
|
|
4
|
+
|
|
5
|
+
def regularize_denominator(expr, regularization_constant = 10**(-4), regularize = False):
|
|
6
|
+
if not regularize:
|
|
7
|
+
return expr
|
|
8
|
+
def regularize(expr):
|
|
9
|
+
(nom, den) = fraction(cancel(expr))
|
|
10
|
+
return nom * den / (den*2 + regularization_constant)
|
|
11
|
+
for i in range(expr.shape[0]):
|
|
12
|
+
for j in range(expr.shape[1]):
|
|
13
|
+
expr[i,j] = regularize(expr[i,j])
|
|
14
|
+
return expr
|
|
15
|
+
|
|
16
|
+
def substitute_sympy_attributes_with_symbol_matrix(expr: Matrix, attr: Zstruct, attr_matrix: MatrixSymbol):
|
|
17
|
+
if expr is None:
|
|
18
|
+
return None
|
|
19
|
+
if type(attr) is Zstruct:
|
|
20
|
+
assert attr.length() <= attr_matrix.shape[0]
|
|
21
|
+
for i, k in enumerate(attr.get_list()):
|
|
22
|
+
expr = Matrix(expr).subs(k, attr_matrix[i])
|
|
23
|
+
else:
|
|
24
|
+
expr = Matrix(expr).subs(attr, attr_matrix)
|
|
25
|
+
return expr
|