|
24 | 24 | """
|
25 | 25 |
|
26 | 26 | from functools import partial
|
| 27 | +from dataclasses import replace |
27 | 28 | import numpy as np
|
28 | 29 | import numpy.linalg as la
|
29 | 30 | import pytest
|
@@ -1130,6 +1131,156 @@ def test_mesh_element_group_constructor(shape_cls, group_cls):
|
1130 | 1131 | # }}}
|
1131 | 1132 |
|
1132 | 1133 |
|
| 1134 | +# {{{ test_node_vertex_consistency_check |
| 1135 | + |
| 1136 | +def test_node_vertex_consistency_check(actx_factory): |
| 1137 | + actx = actx_factory() |
| 1138 | + |
| 1139 | + from meshmode import InconsistentVerticesError |
| 1140 | + |
| 1141 | + dtype = np.float64 |
| 1142 | + tol = 1e3 * np.finfo(dtype).eps |
| 1143 | + |
| 1144 | + # Mesh bounds invariance |
| 1145 | + |
| 1146 | + def gen_rect_mesh_with_perturbed_vertices( |
| 1147 | + a, b, nelements_per_axis, perturb_amount): |
| 1148 | + mesh_unperturbed = mgen.generate_regular_rect_mesh( |
| 1149 | + a=a, b=b, nelements_per_axis=nelements_per_axis) |
| 1150 | + return mesh_unperturbed.copy( # noqa: F841 |
| 1151 | + vertices=( |
| 1152 | + mesh_unperturbed.vertices |
| 1153 | + + perturb_amount*np.ones(mesh_unperturbed.vertices.shape)), |
| 1154 | + node_vertex_consistency_tolerance=tol) |
| 1155 | + |
| 1156 | + # Find critical perturbation amount "w" such that vertices shifted by w works |
| 1157 | + # but 10*w doesn't |
| 1158 | + h = 1 |
| 1159 | + nelems = 8 |
| 1160 | + size = h*nelems |
| 1161 | + crit_perturb = None |
| 1162 | + for p in range(32): |
| 1163 | + w = h*10**(p-16) |
| 1164 | + try: |
| 1165 | + gen_rect_mesh_with_perturbed_vertices( |
| 1166 | + a=(-size/2,), b=(size/2,), nelements_per_axis=(nelems,), |
| 1167 | + perturb_amount=w) |
| 1168 | + except InconsistentVerticesError: |
| 1169 | + if p > 0: |
| 1170 | + crit_perturb = w/10 |
| 1171 | + break |
| 1172 | + if crit_perturb is None: |
| 1173 | + raise RuntimeError("failed to find critical vertex perturbation amount") |
| 1174 | + |
| 1175 | + # Scale invariance |
| 1176 | + nelems = 8 |
| 1177 | + for p in range(32): |
| 1178 | + h = 10**(p-16) |
| 1179 | + size = h*nelems |
| 1180 | + perturb = crit_perturb*h |
| 1181 | + gen_rect_mesh_with_perturbed_vertices( |
| 1182 | + a=(-size/2,)*3, b=(size/2,)*3, nelements_per_axis=(nelems,)*3, |
| 1183 | + perturb_amount=perturb) |
| 1184 | + if 10*perturb > tol: |
| 1185 | + with pytest.raises(InconsistentVerticesError): |
| 1186 | + gen_rect_mesh_with_perturbed_vertices( |
| 1187 | + a=(-size/2,)*3, b=(size/2,)*3, nelements_per_axis=(nelems,)*3, |
| 1188 | + perturb_amount=10*perturb) |
| 1189 | + |
| 1190 | + # Translation invariance |
| 1191 | + h = 1 |
| 1192 | + nelems = 8 |
| 1193 | + size = h*nelems |
| 1194 | + for p in range(10): |
| 1195 | + shift = 10**p-1 |
| 1196 | + perturb = crit_perturb*(size/2 + shift)/(size/2) |
| 1197 | + gen_rect_mesh_with_perturbed_vertices( |
| 1198 | + a=(shift-size/2,)*3, b=(shift+size/2,)*3, |
| 1199 | + nelements_per_axis=(nelems,)*3, |
| 1200 | + perturb_amount=perturb) |
| 1201 | + with pytest.raises(InconsistentVerticesError): |
| 1202 | + gen_rect_mesh_with_perturbed_vertices( |
| 1203 | + a=(shift-size/2,)*3, b=(shift+size/2,)*3, |
| 1204 | + nelements_per_axis=(nelems,)*3, |
| 1205 | + perturb_amount=10*perturb) |
| 1206 | + |
| 1207 | + # Aspect ratio invariance |
| 1208 | + h = 1 |
| 1209 | + nelems = 8 |
| 1210 | + size = h*nelems |
| 1211 | + for p in range(10): |
| 1212 | + h_x = 10**p * h |
| 1213 | + size_x = h_x * nelems |
| 1214 | + perturb = crit_perturb*h_x |
| 1215 | + gen_rect_mesh_with_perturbed_vertices( |
| 1216 | + a=(-size_x/2,) + (-size/2,)*2, |
| 1217 | + b=(size_x/2,) + (size/2,)*2, |
| 1218 | + nelements_per_axis=(nelems,)*3, |
| 1219 | + perturb_amount=perturb) |
| 1220 | + with pytest.raises(InconsistentVerticesError): |
| 1221 | + gen_rect_mesh_with_perturbed_vertices( |
| 1222 | + a=(-size_x/2,) + (-size/2,)*2, |
| 1223 | + b=(size_x/2,) + (size/2,)*2, |
| 1224 | + nelements_per_axis=(nelems,)*3, |
| 1225 | + perturb_amount=10*perturb) |
| 1226 | + |
| 1227 | + # Mesh size relative to element size invariance |
| 1228 | + h = 1 |
| 1229 | + for p in range(5): |
| 1230 | + nelems = 2**(5-p) |
| 1231 | + size = h*nelems |
| 1232 | + perturb = crit_perturb |
| 1233 | + gen_rect_mesh_with_perturbed_vertices( |
| 1234 | + a=(-size/2,)*3, b=(size/2,)*3, nelements_per_axis=(nelems,)*3, |
| 1235 | + perturb_amount=perturb) |
| 1236 | + with pytest.raises(InconsistentVerticesError): |
| 1237 | + gen_rect_mesh_with_perturbed_vertices( |
| 1238 | + a=(-size/2,)*3, b=(size/2,)*3, nelements_per_axis=(nelems,)*3, |
| 1239 | + perturb_amount=10*perturb) |
| 1240 | + |
| 1241 | + # Zero-D elements |
| 1242 | + h = 1 |
| 1243 | + nelems = 7 |
| 1244 | + size = h*nelems |
| 1245 | + vol_mesh = mgen.generate_regular_rect_mesh( |
| 1246 | + a=(-size/2,), b=(size/2,), |
| 1247 | + nelements_per_axis=(nelems,)) |
| 1248 | + from meshmode.discretization import Discretization |
| 1249 | + group_factory = default_simplex_group_factory(1, 1) |
| 1250 | + vol_discr = Discretization(actx, vol_mesh, group_factory) |
| 1251 | + from meshmode.discretization.connection import ( |
| 1252 | + FACE_RESTR_ALL, |
| 1253 | + make_face_restriction) |
| 1254 | + make_face_restriction( |
| 1255 | + actx, vol_discr, group_factory, FACE_RESTR_ALL, per_face_groups=False) |
| 1256 | + |
| 1257 | + # Zero-D elements at the origin |
| 1258 | + h = 1 |
| 1259 | + nelems = 8 |
| 1260 | + size = h*nelems |
| 1261 | + vol_mesh = mgen.generate_regular_rect_mesh( |
| 1262 | + a=(-size/2,), b=(size/2,), |
| 1263 | + nelements_per_axis=(nelems,)) |
| 1264 | + group_factory = default_simplex_group_factory(1, 1) |
| 1265 | + vol_discr = Discretization(actx, vol_mesh, group_factory) |
| 1266 | + make_face_restriction( |
| 1267 | + actx, vol_discr, group_factory, FACE_RESTR_ALL, per_face_groups=False) |
| 1268 | + |
| 1269 | + # Element vertex indices rotated |
| 1270 | + with pytest.raises(InconsistentVerticesError): |
| 1271 | + vol_mesh_unrotated = mgen.generate_regular_rect_mesh( |
| 1272 | + a=(-1,)*2, b=(1,)*2, |
| 1273 | + nelements_per_axis=(8,)*2) |
| 1274 | + vol_mesh = vol_mesh_unrotated.copy( # noqa: F841 |
| 1275 | + groups=[ |
| 1276 | + replace( |
| 1277 | + grp, |
| 1278 | + vertex_indices=np.roll(grp.vertex_indices, 1, axis=1)) |
| 1279 | + for grp in vol_mesh_unrotated.groups]) |
| 1280 | + |
| 1281 | +# }}} |
| 1282 | + |
| 1283 | + |
1133 | 1284 | # {{{ mesh boundary gluing
|
1134 | 1285 |
|
1135 | 1286 | @pytest.mark.parametrize("use_tree", [False, True])
|
|
0 commit comments