Skip to content

Commit 15f51ca

Browse files
committed
optimize generate_box_mesh
1 parent 261474e commit 15f51ca

File tree

1 file changed

+194
-114
lines changed

1 file changed

+194
-114
lines changed

meshmode/mesh/generation.py

Lines changed: 194 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,21 +1254,34 @@ def generate_box_mesh(
12541254

12551255
shape_m1 = tuple(max(si-1, 0) for si in shape)
12561256

1257+
box_faces = [
1258+
side + str(axis)
1259+
for axis in range(dim)
1260+
for side in ["-", "+"]]
1261+
12571262
if dim == 1:
12581263
if mesh_type is not None:
12591264
raise ValueError(f"unsupported mesh type: '{mesh_type}'")
12601265

12611266
nelements = shape_m1[0]
12621267
nvertices_per_element = 2
1263-
el_vertices = np.empty((nelements, nvertices_per_element), dtype=np.int32)
12641268

1265-
for i in range(shape_m1[0]):
1266-
# a--b
1269+
if nelements > 0:
1270+
i0 = np.arange(shape_m1[0])
1271+
1272+
a0 = vertex_indices[i0]
1273+
a1 = vertex_indices[i0+1]
12671274

1268-
a = vertex_indices[i]
1269-
b = vertex_indices[i+1]
1275+
el_vertices = np.array([a0, a1], dtype=np.int32).T
1276+
box_face_to_elements = {
1277+
"-0": np.array([0], dtype=np.int32),
1278+
"+0": np.array([shape_m1[0]-1], dtype=np.int32)}
12701279

1271-
el_vertices[i, :] = (a, b)
1280+
else:
1281+
el_vertices = np.empty((0, nvertices_per_element), dtype=np.int32)
1282+
box_face_to_elements = {
1283+
box_face: np.array([], dtype=np.int32)
1284+
for box_face in box_faces}
12721285

12731286
elif dim == 2:
12741287
if is_tp:
@@ -1306,38 +1319,76 @@ def generate_box_mesh(
13061319
raise ValueError(f"unsupported mesh type: '{mesh_type}'")
13071320

13081321
nelements = nsubelements * product(shape_m1)
1309-
el_vertices = np.empty((nelements, nvertices_per_element), dtype=np.int32)
1310-
1311-
iel = 0
1312-
for i in range(shape_m1[0]):
1313-
for j in range(shape_m1[1]):
1314-
1315-
# c--d
1316-
# | |
1317-
# a--b
1318-
1319-
a = vertex_indices[i, j]
1320-
b = vertex_indices[i+1, j]
1321-
c = vertex_indices[i, j+1]
1322-
d = vertex_indices[i+1, j+1]
13231322

1324-
if is_tp:
1325-
el_vertices[iel, :] = (a, b, c, d)
1326-
1327-
elif mesh_type == "X":
1328-
m = midpoint_indices[i, j]
1329-
el_vertices[iel:iel+4, :] = [
1330-
(a, b, m),
1331-
(b, d, m),
1332-
(d, c, m),
1333-
(c, a, m)]
1334-
1335-
else:
1336-
el_vertices[iel:iel+2, :] = [
1337-
(a, b, c),
1338-
(d, c, b)]
1339-
1340-
iel += nsubelements
1323+
if nelements > 0:
1324+
base_idx_tuples = np.array(list(np.ndindex(shape_m1)))
1325+
1326+
i0 = base_idx_tuples[:, 0]
1327+
j0 = base_idx_tuples[:, 1]
1328+
1329+
a00 = vertex_indices[i0, j0]
1330+
a01 = vertex_indices[i0, j0+1]
1331+
a10 = vertex_indices[i0+1, j0]
1332+
a11 = vertex_indices[i0+1, j0+1]
1333+
1334+
if is_tp:
1335+
el_vertices = np.array([a00, a10, a01, a11], dtype=np.int32).T
1336+
1337+
box_face_to_elements = {}
1338+
for box_face in box_faces:
1339+
side, axis = box_face
1340+
axis = int(axis)
1341+
idx_crit = 0 if side == "-" else shape_m1[axis] - 1
1342+
elements, = np.where(base_idx_tuples[:, axis] == idx_crit)
1343+
box_face_to_elements[box_face] = elements
1344+
1345+
elif mesh_type == "X":
1346+
m = midpoint_indices[i0, j0]
1347+
el_vertices = np.empty(
1348+
(nelements, nvertices_per_element), dtype=np.int32)
1349+
el_vertices[0::4, :] = np.array([a00, a10, m]).T
1350+
el_vertices[1::4, :] = np.array([a10, a11, m]).T
1351+
el_vertices[2::4, :] = np.array([a11, a01, m]).T
1352+
el_vertices[3::4, :] = np.array([a01, a00, m]).T
1353+
1354+
box_face_to_subelement_offset = {
1355+
"-0": 3,
1356+
"+0": 1,
1357+
"-1": 0,
1358+
"+1": 2}
1359+
1360+
box_face_to_elements = {}
1361+
for box_face in box_faces:
1362+
side, axis = box_face
1363+
axis = int(axis)
1364+
idx_crit = 0 if side == "-" else shape_m1[axis] - 1
1365+
box_elements, = np.where(base_idx_tuples[:, axis] == idx_crit)
1366+
box_face_to_elements[box_face] = \
1367+
4*box_elements + box_face_to_subelement_offset[box_face]
1368+
1369+
else:
1370+
el_vertices = np.empty(
1371+
(nelements, nvertices_per_element), dtype=np.int32)
1372+
el_vertices[0::2, :] = np.array([a00, a10, a01]).T
1373+
el_vertices[1::2, :] = np.array([a11, a01, a10]).T
1374+
1375+
side_to_subelement_offset = {
1376+
"-": 0,
1377+
"+": 1}
1378+
1379+
box_face_to_elements = {}
1380+
for box_face in box_faces:
1381+
side, axis = box_face
1382+
axis = int(axis)
1383+
idx_crit = 0 if side == "-" else shape_m1[axis] - 1
1384+
box_elements, = np.where(base_idx_tuples[:, axis] == idx_crit)
1385+
box_face_to_elements[box_face] = \
1386+
2*box_elements + side_to_subelement_offset[side]
1387+
else:
1388+
el_vertices = np.empty((0, nvertices_per_element), dtype=np.int32)
1389+
box_face_to_elements = {
1390+
box_face: np.array([], dtype=np.int32)
1391+
for box_face in box_faces}
13411392

13421393
elif dim == 3:
13431394
if is_tp:
@@ -1355,38 +1406,68 @@ def generate_box_mesh(
13551406
raise ValueError(f"unsupported mesh type: '{mesh_type}'")
13561407

13571408
nelements = nsubelements * product(shape_m1)
1358-
el_vertices = np.empty((nelements, nvertices_per_element), dtype=np.int32)
1359-
1360-
iel = 0
1361-
for i in range(shape_m1[0]):
1362-
for j in range(shape_m1[1]):
1363-
for k in range(shape_m1[2]):
1364-
1365-
a000 = vertex_indices[i, j, k]
1366-
a001 = vertex_indices[i, j, k+1]
1367-
a010 = vertex_indices[i, j+1, k]
1368-
a011 = vertex_indices[i, j+1, k+1]
1369-
1370-
a100 = vertex_indices[i+1, j, k]
1371-
a101 = vertex_indices[i+1, j, k+1]
1372-
a110 = vertex_indices[i+1, j+1, k]
1373-
a111 = vertex_indices[i+1, j+1, k+1]
1374-
1375-
if is_tp:
1376-
el_vertices[iel, :] = (
1377-
a000, a100, a010, a110,
1378-
a001, a101, a011, a111)
1379-
1380-
else:
1381-
el_vertices[iel:iel+6, :] = [
1382-
(a000, a100, a010, a001),
1383-
(a101, a100, a001, a010),
1384-
(a101, a011, a010, a001),
1385-
(a100, a010, a101, a110),
1386-
(a011, a010, a110, a101),
1387-
(a011, a111, a101, a110)]
1388-
1389-
iel += nsubelements
1409+
1410+
if nelements > 0:
1411+
base_idx_tuples = np.array(list(np.ndindex(shape_m1)))
1412+
1413+
i0 = base_idx_tuples[:, 0]
1414+
j0 = base_idx_tuples[:, 1]
1415+
k0 = base_idx_tuples[:, 2]
1416+
1417+
a000 = vertex_indices[i0, j0, k0]
1418+
a001 = vertex_indices[i0, j0, k0+1]
1419+
a010 = vertex_indices[i0, j0+1, k0]
1420+
a011 = vertex_indices[i0, j0+1, k0+1]
1421+
a100 = vertex_indices[i0+1, j0, k0]
1422+
a101 = vertex_indices[i0+1, j0, k0+1]
1423+
a110 = vertex_indices[i0+1, j0+1, k0]
1424+
a111 = vertex_indices[i0+1, j0+1, k0+1]
1425+
1426+
if is_tp:
1427+
el_vertices = np.array([
1428+
a000, a100, a010, a110,
1429+
a001, a101, a011, a111], dtype=np.int32).T
1430+
1431+
box_face_to_elements = {}
1432+
for box_face in box_faces:
1433+
side, axis = box_face
1434+
axis = int(axis)
1435+
idx_crit = 0 if side == "-" else shape_m1[axis] - 1
1436+
elements, = np.where(base_idx_tuples[:, axis] == idx_crit)
1437+
box_face_to_elements[box_face] = elements
1438+
1439+
else:
1440+
el_vertices = np.empty(
1441+
(nelements, nvertices_per_element), dtype=np.int32)
1442+
el_vertices[0::6, :] = np.array([a000, a100, a010, a001]).T
1443+
el_vertices[1::6, :] = np.array([a101, a100, a001, a010]).T
1444+
el_vertices[2::6, :] = np.array([a101, a011, a010, a001]).T
1445+
el_vertices[3::6, :] = np.array([a100, a010, a101, a110]).T
1446+
el_vertices[4::6, :] = np.array([a011, a010, a110, a101]).T
1447+
el_vertices[5::6, :] = np.array([a011, a111, a101, a110]).T
1448+
1449+
box_face_to_subelement_offsets = {
1450+
"-0": (0, 2),
1451+
"+0": (3, 5),
1452+
"-1": (0, 1),
1453+
"+1": (4, 5),
1454+
"-2": (0, 3),
1455+
"+2": (2, 5)}
1456+
1457+
box_face_to_elements = {}
1458+
for box_face in box_faces:
1459+
side, axis = box_face
1460+
axis = int(axis)
1461+
idx_crit = 0 if side == "-" else shape_m1[axis] - 1
1462+
box_elements, = np.where(base_idx_tuples[:, axis] == idx_crit)
1463+
box_face_to_elements[box_face] = np.concatenate([
1464+
6*box_elements + offset
1465+
for offset in box_face_to_subelement_offsets[box_face]])
1466+
else:
1467+
el_vertices = np.empty((0, nvertices_per_element), dtype=np.int32)
1468+
box_face_to_elements = {
1469+
box_face: np.array([], dtype=np.int32)
1470+
for box_face in box_faces}
13901471

13911472
else:
13921473
raise NotImplementedError("box meshes of dimension %d" % dim)
@@ -1408,57 +1489,56 @@ def generate_box_mesh(
14081489

14091490
facial_adjacency_groups = None
14101491
face_vertex_indices_to_tags = {}
1411-
boundary_tags = list(boundary_tag_to_face.keys())
1412-
nbnd_tags = len(boundary_tags)
14131492

1414-
if nbnd_tags > 0:
1493+
if boundary_tag_to_face:
14151494
vert_index_to_tuple = {
14161495
vertex_indices[itup]: itup
14171496
for itup in np.ndindex(shape)}
14181497

1419-
for ielem in range(0, grp.nelements):
1420-
for ref_fvi in grp.face_vertex_indices():
1421-
fvi = grp.vertex_indices[ielem, ref_fvi]
1498+
box_face_to_tags = {}
1499+
for tag, tagged_box_faces in boundary_tag_to_face.items():
1500+
for box_face in tagged_box_faces:
1501+
if len(box_face) != 2:
1502+
raise ValueError(
1503+
f"face identifier '{box_face}' does not "
1504+
"consist of exactly two characters")
1505+
side, axis = box_face
14221506
try:
1423-
fvi_tuples = [vert_index_to_tuple[i] for i in fvi]
1424-
except KeyError:
1425-
# Happens for interior faces of "X" meshes because
1426-
# midpoints aren't in vert_index_to_tuple. We don't
1427-
# care about them.
1428-
continue
1429-
1430-
for tag in boundary_tags:
1431-
# Need to map the correct face vertices to the boundary tags
1432-
for face in boundary_tag_to_face[tag]:
1433-
if len(face) != 2:
1434-
raise ValueError(
1435-
"face identifier '%s' does not "
1436-
"consist of exactly two characters" % face)
1437-
1438-
side, axis = face
1439-
try:
1440-
axis = axes.index(axis)
1441-
except ValueError as exc:
1442-
raise ValueError(
1443-
"unrecognized axis in face identifier "
1444-
f"'{face}'") from exc
1445-
if axis >= dim:
1446-
raise ValueError("axis in face identifier '%s' "
1447-
"does not exist in %dD" % (face, dim))
1448-
1449-
if side == "-":
1450-
vert_crit = 0
1451-
elif side == "+":
1452-
vert_crit = shape[axis] - 1
1453-
else:
1454-
raise ValueError("first character of face identifier"
1455-
" '%s' is not '+' or '-'" % face)
1456-
1457-
if all(fvi_tuple[axis] == vert_crit
1458-
for fvi_tuple in fvi_tuples):
1459-
key = frozenset(fvi)
1460-
face_vertex_indices_to_tags.setdefault(key,
1461-
[]).append(tag)
1507+
axis = axes.index(axis)
1508+
except ValueError as exc:
1509+
raise ValueError(
1510+
"unrecognized axis in face identifier "
1511+
f"'{box_face}'") from exc
1512+
if axis >= dim:
1513+
raise ValueError(f"axis in face identifier '{box_face}' "
1514+
f"does not exist in {dim}D")
1515+
if side not in ("-", "+"):
1516+
raise ValueError("first character of face identifier"
1517+
f" '{box_face}' is not '+' or '-'")
1518+
box_face_to_tags.setdefault(f"{side}{axis}", []).append(tag)
1519+
1520+
for box_face, elements in box_face_to_elements.items():
1521+
try:
1522+
tags = box_face_to_tags[box_face]
1523+
except KeyError:
1524+
continue
1525+
side, axis = box_face
1526+
axis = int(axis)
1527+
vert_crit = 0 if side == "-" else shape[axis] - 1
1528+
for ielem in elements:
1529+
for ref_fvi in grp.face_vertex_indices():
1530+
fvi = grp.vertex_indices[ielem, ref_fvi]
1531+
try:
1532+
fvi_tuples = [vert_index_to_tuple[i] for i in fvi]
1533+
except KeyError:
1534+
# Happens for interior faces of "X" meshes because
1535+
# midpoints aren't in vert_index_to_tuple. We don't
1536+
# care about them.
1537+
continue
1538+
1539+
if all(fvi_tuple[axis] == vert_crit
1540+
for fvi_tuple in fvi_tuples):
1541+
face_vertex_indices_to_tags[frozenset(fvi)] = tags
14621542

14631543
from meshmode.mesh import _compute_facial_adjacency_from_vertices
14641544
facial_adjacency_groups = _compute_facial_adjacency_from_vertices(

0 commit comments

Comments
 (0)