Skip to content

Commit a1e9116

Browse files
committed
optimize generate_box_mesh
1 parent 261474e commit a1e9116

File tree

1 file changed

+212
-108
lines changed

1 file changed

+212
-108
lines changed

meshmode/mesh/generation.py

Lines changed: 212 additions & 108 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+
base_i = np.arange(shape_m1[0])
1271+
1272+
a0 = vertex_indices[base_i]
1273+
a1 = vertex_indices[base_i+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,87 @@ 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]):
13141322

1315-
# c--d
1316-
# | |
1317-
# a--b
1323+
if nelements > 0:
1324+
base_idx_tuples = np.array(list(np.ndindex(shape_m1)))
13181325

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]
1326+
base_i = base_idx_tuples[:, 0]
1327+
base_j = base_idx_tuples[:, 1]
13231328

1324-
if is_tp:
1325-
el_vertices[iel, :] = (a, b, c, d)
1329+
a00 = vertex_indices[base_i, base_j]
1330+
a01 = vertex_indices[base_i, base_j+1]
1331+
a10 = vertex_indices[base_i+1, base_j]
1332+
a11 = vertex_indices[base_i+1, base_j+1]
13261333

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+
if is_tp:
1335+
el_vertices = np.array([a00, a10, a01, a11], dtype=np.int32).T
13341336

1335-
else:
1336-
el_vertices[iel:iel+2, :] = [
1337-
(a, b, c),
1338-
(d, c, b)]
1339-
1340-
iel += nsubelements
1337+
box_face_to_elements = {}
1338+
for box_face in box_faces:
1339+
side, axis = box_face
1340+
axis = int(axis)
1341+
if side == "-":
1342+
elements, = np.where(base_idx_tuples[:, axis] == 0)
1343+
else:
1344+
elements, = np.where(
1345+
base_idx_tuples[:, axis] == shape_m1[axis]-1)
1346+
box_face_to_elements[box_face] = elements
1347+
1348+
elif mesh_type == "X":
1349+
m = midpoint_indices[base_i, base_j]
1350+
el_vertices = np.empty(
1351+
(nelements, nvertices_per_element), dtype=np.int32)
1352+
el_vertices[0::4, :] = np.array([a00, a10, m]).T
1353+
el_vertices[1::4, :] = np.array([a10, a11, m]).T
1354+
el_vertices[2::4, :] = np.array([a11, a01, m]).T
1355+
el_vertices[3::4, :] = np.array([a01, a00, m]).T
1356+
1357+
box_face_to_elements = {}
1358+
for box_face in box_faces:
1359+
side, axis = box_face
1360+
axis = int(axis)
1361+
if side == "-":
1362+
box_elements, = np.where(base_idx_tuples[:, axis] == 0)
1363+
else:
1364+
box_elements, = np.where(
1365+
base_idx_tuples[:, axis] == shape_m1[axis]-1)
1366+
if box_face == "-0":
1367+
subelement_offset = 3
1368+
if box_face == "+0":
1369+
subelement_offset = 1
1370+
if box_face == "-1":
1371+
subelement_offset = 0
1372+
if box_face == "+1":
1373+
subelement_offset = 2
1374+
box_face_to_elements[box_face] = \
1375+
4*box_elements + subelement_offset
1376+
1377+
else:
1378+
el_vertices = np.empty(
1379+
(nelements, nvertices_per_element), dtype=np.int32)
1380+
el_vertices[0::2, :] = np.array([a00, a10, a01]).T
1381+
el_vertices[1::2, :] = np.array([a11, a01, a10]).T
1382+
1383+
box_face_to_elements = {}
1384+
for box_face in box_faces:
1385+
side, axis = box_face
1386+
axis = int(axis)
1387+
if side == "-":
1388+
box_elements, = np.where(base_idx_tuples[:, axis] == 0)
1389+
else:
1390+
box_elements, = np.where(
1391+
base_idx_tuples[:, axis] == shape_m1[axis]-1)
1392+
if side == "-":
1393+
subelement_offset = 0
1394+
if side == "+":
1395+
subelement_offset = 1
1396+
box_face_to_elements[box_face] = \
1397+
2*box_elements + subelement_offset
1398+
else:
1399+
el_vertices = np.empty((0, nvertices_per_element), dtype=np.int32)
1400+
box_face_to_elements = {
1401+
box_face: np.array([], dtype=np.int32)
1402+
for box_face in box_faces}
13411403

13421404
elif dim == 3:
13431405
if is_tp:
@@ -1355,38 +1417,78 @@ def generate_box_mesh(
13551417
raise ValueError(f"unsupported mesh type: '{mesh_type}'")
13561418

13571419
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)
13791420

1421+
if nelements > 0:
1422+
base_idx_tuples = np.array(list(np.ndindex(shape_m1)))
1423+
1424+
base_i = base_idx_tuples[:, 0]
1425+
base_j = base_idx_tuples[:, 1]
1426+
base_k = base_idx_tuples[:, 2]
1427+
1428+
a000 = vertex_indices[base_i, base_j, base_k]
1429+
a001 = vertex_indices[base_i, base_j, base_k+1]
1430+
a010 = vertex_indices[base_i, base_j+1, base_k]
1431+
a011 = vertex_indices[base_i, base_j+1, base_k+1]
1432+
a100 = vertex_indices[base_i+1, base_j, base_k]
1433+
a101 = vertex_indices[base_i+1, base_j, base_k+1]
1434+
a110 = vertex_indices[base_i+1, base_j+1, base_k]
1435+
a111 = vertex_indices[base_i+1, base_j+1, base_k+1]
1436+
1437+
if is_tp:
1438+
el_vertices = np.array([
1439+
a000, a100, a010, a110,
1440+
a001, a101, a011, a111], dtype=np.int32).T
1441+
1442+
box_face_to_elements = {}
1443+
for box_face in box_faces:
1444+
side, axis = box_face
1445+
axis = int(axis)
1446+
if side == "-":
1447+
elements, = np.where(base_idx_tuples[:, axis] == 0)
13801448
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
1449+
elements, = np.where(
1450+
base_idx_tuples[:, axis] == shape_m1[axis]-1)
1451+
box_face_to_elements[box_face] = elements
1452+
1453+
else:
1454+
el_vertices = np.empty(
1455+
(nelements, nvertices_per_element), dtype=np.int32)
1456+
el_vertices[0::6, :] = np.array([a000, a100, a010, a001]).T
1457+
el_vertices[1::6, :] = np.array([a101, a100, a001, a010]).T
1458+
el_vertices[2::6, :] = np.array([a101, a011, a010, a001]).T
1459+
el_vertices[3::6, :] = np.array([a100, a010, a101, a110]).T
1460+
el_vertices[4::6, :] = np.array([a011, a010, a110, a101]).T
1461+
el_vertices[5::6, :] = np.array([a011, a111, a101, a110]).T
1462+
1463+
box_face_to_elements = {}
1464+
for box_face in box_faces:
1465+
side, axis = box_face
1466+
axis = int(axis)
1467+
if side == "-":
1468+
box_elements, = np.where(base_idx_tuples[:, axis] == 0)
1469+
else:
1470+
box_elements, = np.where(
1471+
base_idx_tuples[:, axis] == shape_m1[axis]-1)
1472+
if box_face == "-0":
1473+
subelement_offsets = (0, 2)
1474+
if box_face == "+0":
1475+
subelement_offsets = (3, 5)
1476+
if box_face == "-1":
1477+
subelement_offsets = (0, 1)
1478+
if box_face == "+1":
1479+
subelement_offsets = (4, 5)
1480+
if box_face == "-2":
1481+
subelement_offsets = (0, 3)
1482+
if box_face == "+2":
1483+
subelement_offsets = (2, 5)
1484+
box_face_to_elements[box_face] = np.concatenate([
1485+
6*box_elements + offset
1486+
for offset in subelement_offsets])
1487+
else:
1488+
el_vertices = np.empty((0, nvertices_per_element), dtype=np.int32)
1489+
box_face_to_elements = {
1490+
box_face: np.array([], dtype=np.int32)
1491+
for box_face in box_faces}
13901492

13911493
else:
13921494
raise NotImplementedError("box meshes of dimension %d" % dim)
@@ -1408,57 +1510,59 @@ def generate_box_mesh(
14081510

14091511
facial_adjacency_groups = None
14101512
face_vertex_indices_to_tags = {}
1411-
boundary_tags = list(boundary_tag_to_face.keys())
1412-
nbnd_tags = len(boundary_tags)
14131513

1414-
if nbnd_tags > 0:
1514+
if boundary_tag_to_face:
14151515
vert_index_to_tuple = {
14161516
vertex_indices[itup]: itup
14171517
for itup in np.ndindex(shape)}
14181518

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]
1519+
box_face_to_tags = {}
1520+
for tag, tagged_box_faces in boundary_tag_to_face.items():
1521+
for box_face in tagged_box_faces:
1522+
if len(box_face) != 2:
1523+
raise ValueError(
1524+
f"face identifier '{box_face}' does not "
1525+
"consist of exactly two characters")
1526+
side, axis = box_face
14221527
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)
1528+
axis = axes.index(axis)
1529+
except ValueError as exc:
1530+
raise ValueError(
1531+
"unrecognized axis in face identifier "
1532+
f"'{box_face}'") from exc
1533+
if axis >= dim:
1534+
raise ValueError(f"axis in face identifier '{box_face}' "
1535+
f"does not exist in {dim}D")
1536+
if side not in ("-", "+"):
1537+
raise ValueError("first character of face identifier"
1538+
f" '{box_face}' is not '+' or '-'")
1539+
box_face_to_tags.setdefault(f"{side}{axis}", []).append(tag)
1540+
1541+
for box_face, elements in box_face_to_elements.items():
1542+
try:
1543+
tags = box_face_to_tags[box_face]
1544+
except KeyError:
1545+
continue
1546+
side, axis = box_face
1547+
axis = int(axis)
1548+
if side == "-":
1549+
vert_crit = 0
1550+
elif side == "+":
1551+
vert_crit = shape[axis] - 1
1552+
for ielem in elements:
1553+
for ref_fvi in grp.face_vertex_indices():
1554+
fvi = grp.vertex_indices[ielem, ref_fvi]
1555+
try:
1556+
fvi_tuples = [vert_index_to_tuple[i] for i in fvi]
1557+
except KeyError:
1558+
# Happens for interior faces of "X" meshes because
1559+
# midpoints aren't in vert_index_to_tuple. We don't
1560+
# care about them.
1561+
continue
1562+
1563+
if all(fvi_tuple[axis] == vert_crit
1564+
for fvi_tuple in fvi_tuples):
1565+
face_vertex_indices_to_tags[frozenset(fvi)] = tags
14621566

14631567
from meshmode.mesh import _compute_facial_adjacency_from_vertices
14641568
facial_adjacency_groups = _compute_facial_adjacency_from_vertices(

0 commit comments

Comments
 (0)