Skip to content

Commit 80afaf7

Browse files
garth-wellsjorgensdschnellerhase
authored
Fix dofmap builder performance fixes (#4081)
* Dofmap builder performance fixes * Fix * Simplify * Simplify * Update cpp/dolfinx/mesh/cell_types.cpp Co-authored-by: Jørgen Schartum Dokken <dokken92@gmail.com> * Apply suggestions from code review Co-authored-by: Paul T. Kühner <56360279+schnellerhase@users.noreply.github.com> --------- Co-authored-by: Jørgen Schartum Dokken <dokken92@gmail.com> Co-authored-by: Paul T. Kühner <56360279+schnellerhase@users.noreply.github.com>
1 parent 141d911 commit 80afaf7

File tree

4 files changed

+149
-113
lines changed

4 files changed

+149
-113
lines changed

cpp/dolfinx/fem/dofmapbuilder.cpp

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ build_basic_dofmaps(
155155
const std::vector<fem::ElementDofLayout>& element_dof_layouts)
156156
{
157157
// Start timer for dofmap initialization
158-
common::Timer t0("Init dofmap from element dofmap");
158+
common::Timer t0("Dofmap builder: init dofmap from element dofmap");
159159

160160
// Topological dimension
161161
const std::size_t D = topology.dim();
@@ -208,7 +208,6 @@ build_basic_dofmaps(
208208
local_entity_offsets.push_back(
209209
local_entity_offsets.back()
210210
+ num_entity_dofs * (im->size_local() + im->num_ghosts()));
211-
212211
if (d < D
213212
and !topology.connectivity({int(D), int(i)},
214213
{int(d), int(et_index)}))
@@ -263,6 +262,15 @@ build_basic_dofmaps(
263262
dofs[i].array.resize(num_cells * dofmap_width);
264263
spdlog::info("Cell type: {} dofmap: {}x{}", i, num_cells, dofmap_width);
265264

265+
std::vector<std::vector<mesh::CellType>> cell_entity_types(D + 1);
266+
for (std::size_t d = 0; d < D + 1; ++d)
267+
{
268+
int entities_d = mesh::cell_num_entities(cell_type, d);
269+
cell_entity_types[d].reserve(entities_d);
270+
for (int e = 0; e < entities_d; ++e)
271+
cell_entity_types[d].push_back(mesh::cell_entity_type(cell_type, d, e));
272+
}
273+
266274
std::int32_t dofmap_offset = 0;
267275
for (std::int32_t c = 0; c < num_cells; ++c)
268276
{
@@ -279,12 +287,12 @@ build_basic_dofmaps(
279287
std::size_t et = required_dim_et[k].second;
280288
mesh::CellType e_type = topology.entity_types(d)[et];
281289

282-
const std::vector<std::vector<int>>& e_dofs_d = entity_dofs[d];
283-
284290
// Skip over undefined topology, e.g. quad facets of tetrahedra
285291
if (d < D
286292
and !topology.connectivity({int(D), int(i)}, {int(d), int(et)}))
293+
{
287294
continue;
295+
}
288296

289297
// Iterate over each entity of current dimension d and type et
290298
std::span<const std::int32_t> c_to_e
@@ -293,13 +301,15 @@ build_basic_dofmaps(
293301
->links(c)
294302
: std::span<const std::int32_t>(&c, 1);
295303

304+
const std::vector<std::vector<int>>& e_dofs_d = entity_dofs[d];
305+
const std::vector<mesh::CellType>& e_types = cell_entity_types[d];
296306
int w = 0;
297307
for (std::size_t e = 0; e < e_dofs_d.size(); ++e)
298308
{
299309
// Skip entities of wrong type (e.g. for facets of prism)
300310
// Use separate connectivity index 'w' which only advances for
301311
// correct entities
302-
if (mesh::cell_entity_type(cell_type, d, e) == e_type)
312+
if (e_type == e_types[e])
303313
{
304314
const std::vector<int>& e_dofs_d_e = e_dofs_d[e];
305315
std::size_t num_entity_dofs = e_dofs_d_e.size();
@@ -347,7 +357,6 @@ build_basic_dofmaps(
347357
auto& map = topo_index_maps[k];
348358
assert(map);
349359
std::vector<std::int64_t> global_indices = map->global_indices();
350-
351360
for (std::size_t e_index = 0; e_index < global_indices.size(); ++e_index)
352361
{
353362
auto e_index_global = global_indices[e_index];
@@ -369,16 +378,19 @@ build_basic_dofmaps(
369378
}
370379
//-----------------------------------------------------------------------------
371380

372-
/// Compute re-ordering map from old local index to new local index. The
373-
/// M dofs owned by this process are reordered for locality and fill the
374-
/// positions [0, ..., M). Dof owned by another process are placed at
375-
/// the end, i.e. in the positions [M, ..., N), where N is the total
381+
/// @brief Compute re-ordering map from old local index to new local
382+
/// index.
383+
///
384+
/// The M dofs owned by this process are reordered for locality and fill
385+
/// the positions [0, ..., M). Dof owned by another process are placed
386+
/// at the end, i.e. in the positions [M, ..., N), where N is the total
376387
/// number of dofs on this process.
377388
///
378-
/// @param [in] dofmaps The basic dofmap data in multiple dofmaps sharing the
379-
/// same range
380-
/// @param [in] dof_entity Map from dof index to (index_map, entity_index),
381-
/// where entity_index is the local mesh entity index in the given index_map
389+
/// @param [in] dofmaps The basic dofmap data in multiple dofmaps
390+
/// sharing the same range
391+
/// @param [in] dof_entity Map from dof index to (index_map,
392+
/// entity_index), where entity_index is the local mesh entity index in
393+
/// the given index_map
382394
/// @param [in] index_maps The set of IndexMaps, one for each
383395
/// topological entity type used in the dofmap. The location in this
384396
/// array is referred to by the first item in each entry of
@@ -394,7 +406,7 @@ std::pair<std::vector<std::int32_t>, std::int32_t> compute_reordering_map(
394406
const std::function<std::vector<int>(
395407
const graph::AdjacencyList<std::int32_t>&)>& reorder_fn)
396408
{
397-
common::Timer t0("Compute dof reordering map");
409+
common::Timer t0("Dofmap builder: compute dof reordering map");
398410

399411
// Get mesh entity ownership offset for each IndexMap
400412
std::vector<std::int32_t> offset(index_maps.size(), -1);
@@ -427,10 +439,10 @@ std::pair<std::vector<std::int32_t>, std::int32_t> compute_reordering_map(
427439
}
428440
}
429441

430-
// Check for any -1's remaining in `original_to_contiguous` due to vertices
431-
// on the process that don't belong to a cell. Determine if the dof is owned
432-
// or a ghost and map to the ends of the owned and ghost "parts" of the
433-
// contiguous array respectively.
442+
// Check for any -1's remaining in `original_to_contiguous` due to
443+
// vertices on the process that don't belong to a cell. Determine if
444+
// the dof is owned or a ghost and map to the ends of the owned and
445+
// ghost "parts" of the contiguous array respectively.
434446
for (std::size_t dof = 0; dof < original_to_contiguous.size(); ++dof)
435447
{
436448
if (original_to_contiguous[dof] == -1)
@@ -459,18 +471,18 @@ std::pair<std::vector<std::int32_t>, std::int32_t> compute_reordering_map(
459471
}
460472
//-----------------------------------------------------------------------------
461473

462-
/// Get global indices for unowned dofs
463-
/// @param [in] index_maps Set of index maps corresponding to dofs in @p
464-
/// dof_entity, below.
465-
/// @param [in] num_owned The number of nodes owned by this process
466-
/// @param [in] process_offset The node offset for this process, i.e.
467-
/// the global index of owned node i is i + process_offset
468-
/// @param [in] global_indices_old The old global index of the old local
474+
/// @brief Get global indices for unowned dofs
475+
///
476+
/// @param[in] index_maps Set of index maps corresponding to dofs in
477+
/// `dof_entity`, below.
478+
/// @param[in] num_owned The number of nodes owned by this process
479+
/// @param[in] process_offset The node offset for this process, i.e. the
480+
/// global index of owned node i is i + process_offset
481+
/// @param[in] global_indices_old The old global index of the old local
469482
/// node i
470-
/// @param [in] old_to_new The old local index to new local index map
471-
/// @param [in] dof_entity The ith entry gives (index_map, local
472-
/// index) of the mesh entity to which node i (old local index) is
473-
/// associated.
483+
/// @param[in] old_to_new The old local index to new local index map
484+
/// @param[in] dof_entity The ith entry gives (index_map, local index)
485+
/// of the mesh entity to which node i (old local index) is associated.
474486
/// @returns The (0) global indices for unowned dofs, (1) owner rank of
475487
/// each unowned dof
476488
std::pair<std::vector<std::int64_t>, std::vector<int>> get_global_indices(
@@ -480,6 +492,8 @@ std::pair<std::vector<std::int64_t>, std::vector<int>> get_global_indices(
480492
const std::vector<std::int32_t>& old_to_new,
481493
const std::vector<std::pair<std::int8_t, std::int32_t>>& dof_entity)
482494
{
495+
common::Timer t0("Dofmap builder: get dofmap global indices");
496+
483497
assert(dof_entity.size() == global_indices_old.size());
484498

485499
// Build list of flags for owned mesh entities that are shared, i.e.
@@ -630,7 +644,7 @@ fem::build_dofmap_data(
630644
const std::function<std::vector<int>(
631645
const graph::AdjacencyList<std::int32_t>&)>& reorder_fn)
632646
{
633-
common::Timer t0("Build dofmap data");
647+
common::Timer t0("Dofmap builder: build dofmap data");
634648

635649
// Build a simple dofmap based on mesh entity numbering, returning (i)
636650
// a local dofmap, (ii) local-to-global map for dof indices, and (iii)

cpp/dolfinx/mesh/cell_types.cpp

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2006-2019 Anders Logg and Garth N. Wells
1+
// Copyright (C) 2006-2026 Anders Logg and Garth N. Wells
22
//
33
// This file is part of DOLFINx (https://www.fenicsproject.org)
44
//
@@ -61,53 +61,9 @@ mesh::CellType mesh::to_type(const std::string& cell)
6161
throw std::runtime_error("Unknown cell type (" + cell + ")");
6262
}
6363
//-----------------------------------------------------------------------------
64-
mesh::CellType mesh::cell_entity_type(CellType type, int d, int index)
65-
{
66-
const int dim = cell_dim(type);
67-
if (d == dim)
68-
return type;
69-
else if (d == 1)
70-
return CellType::interval;
71-
else if (d == (dim - 1))
72-
return cell_facet_type(type, index);
73-
else
74-
return CellType::point;
75-
}
76-
//-----------------------------------------------------------------------------
77-
mesh::CellType mesh::cell_facet_type(CellType type, int index)
78-
{
79-
switch (type)
80-
{
81-
case CellType::point:
82-
return CellType::point;
83-
case CellType::interval:
84-
return CellType::point;
85-
case CellType::triangle:
86-
return CellType::interval;
87-
case CellType::tetrahedron:
88-
return CellType::triangle;
89-
case CellType::quadrilateral:
90-
return CellType::interval;
91-
case CellType::pyramid:
92-
if (index == 0)
93-
return CellType::quadrilateral;
94-
else
95-
return CellType::triangle;
96-
case CellType::prism:
97-
if (index == 0 or index == 4)
98-
return CellType::triangle;
99-
else
100-
return CellType::quadrilateral;
101-
case CellType::hexahedron:
102-
return CellType::quadrilateral;
103-
default:
104-
throw std::runtime_error("Unknown cell type.");
105-
}
106-
}
107-
//-----------------------------------------------------------------------------
10864
graph::AdjacencyList<int> mesh::get_entity_vertices(CellType type, int dim)
10965
{
110-
const std::vector<std::vector<int>> topology
66+
std::vector<std::vector<int>> topology
11167
= basix::cell::topology(cell_type_to_basix_type(type))[dim];
11268
return graph::AdjacencyList<int>(topology);
11369
}
@@ -121,7 +77,7 @@ graph::AdjacencyList<int> mesh::get_sub_entities(CellType type, int dim0,
12177
else if (type == CellType::point)
12278
return graph::AdjacencyList<int>(0);
12379

124-
const std::vector<std::vector<std::vector<int>>> connectivity
80+
std::vector<std::vector<std::vector<int>>> connectivity
12581
= basix::cell::sub_entity_connectivity(
12682
cell_type_to_basix_type(type))[dim0];
12783
std::vector<std::vector<int>> subset;
@@ -131,11 +87,6 @@ graph::AdjacencyList<int> mesh::get_sub_entities(CellType type, int dim0,
13187
return graph::AdjacencyList<int>(subset);
13288
}
13389
//-----------------------------------------------------------------------------
134-
int mesh::cell_dim(CellType type)
135-
{
136-
return basix::cell::topological_dimension(cell_type_to_basix_type(type));
137-
}
138-
//-----------------------------------------------------------------------------
13990
int mesh::cell_num_entities(CellType type, int dim)
14091
{
14192
assert(dim <= 3);

cpp/dolfinx/mesh/cell_types.h

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2019-2020 Garth N. Wells
1+
// Copyright (C) 2019-2026 Garth N. Wells
22
//
33
// This file is part of DOLFINx (https://www.fenicsproject.org)
44
//
@@ -41,42 +41,110 @@ std::string to_string(CellType type);
4141
/// @return The cell type
4242
CellType to_type(const std::string& cell);
4343

44-
/// Return type of cell for entity of dimension d at given entity index.
45-
CellType cell_entity_type(CellType type, int d, int index);
44+
/// Return topological dimension of cell type
45+
inline int cell_dim(CellType type)
46+
{
47+
switch (type)
48+
{
49+
case CellType::point:
50+
return 0;
51+
case CellType::interval:
52+
return 1;
53+
case CellType::triangle:
54+
return 2;
55+
case CellType::quadrilateral:
56+
return 2;
57+
case CellType::tetrahedron:
58+
return 3;
59+
case CellType::hexahedron:
60+
return 3;
61+
case CellType::prism:
62+
return 3;
63+
case CellType::pyramid:
64+
return 3;
65+
default:
66+
throw std::runtime_error("Unsupported cell type");
67+
}
68+
}
69+
70+
/// @brief Return facet type of cell.
71+
///
72+
/// For simplex and hypercube cell types, this is independent of the
73+
/// facet index, but for prism and pyramid, it can be triangle or
74+
/// quadrilateral.
75+
///
76+
/// @param[in] type Cell type.
77+
/// @param[in] index Facet index (relative to the cell).
78+
/// @return Type of facet for this cell at this index.
79+
inline CellType cell_facet_type(CellType type, int index)
80+
{
81+
switch (type)
82+
{
83+
case CellType::point:
84+
return CellType::point;
85+
case CellType::interval:
86+
return CellType::point;
87+
case CellType::triangle:
88+
return CellType::interval;
89+
case CellType::tetrahedron:
90+
return CellType::triangle;
91+
case CellType::quadrilateral:
92+
return CellType::interval;
93+
case CellType::pyramid:
94+
if (index == 0)
95+
return CellType::quadrilateral;
96+
else
97+
return CellType::triangle;
98+
case CellType::prism:
99+
if (index == 0 or index == 4)
100+
return CellType::triangle;
101+
else
102+
return CellType::quadrilateral;
103+
case CellType::hexahedron:
104+
return CellType::quadrilateral;
105+
default:
106+
throw std::runtime_error("Unknown cell type.");
107+
}
108+
}
46109

47-
/// Return facet type of cell
48-
/// For simplex and hypercube cell types, this is independent of the facet
49-
/// index, but for prism and pyramid, it can be triangle or quadrilateral.
50-
/// @param[in] type The cell type
51-
/// @param[in] index The facet index
52-
/// @return The type of facet for this cell at this index
53-
CellType cell_facet_type(CellType type, int index);
110+
/// Return type of cell for entity of dimension d at given entity index.
111+
inline CellType cell_entity_type(CellType type, int d, int index)
112+
{
113+
if (int dim = mesh::cell_dim(type); d == dim)
114+
return type;
115+
else if (d == 1)
116+
return CellType::interval;
117+
else if (d == (dim - 1))
118+
return mesh::cell_facet_type(type, index);
119+
else
120+
return CellType::point;
121+
}
54122

55123
/// Return list of entities, where entities(e, k) is the local vertex
56124
/// index for the kth vertex of entity e of dimension dim
57125
graph::AdjacencyList<int> get_entity_vertices(CellType type, int dim);
58126

59127
/// Get entities of dimension dim1 and that make up entities of dimension
60-
/// dim0
128+
/// dim0.
61129
graph::AdjacencyList<int> get_sub_entities(CellType type, int dim0, int dim1);
62130

63-
/// Return topological dimension of cell type
64-
int cell_dim(CellType type);
65-
66-
/// Number of entities of dimension dim
67-
/// @param[in] dim Entity dimension
68-
/// @param[in] type Cell type
69-
/// @return Number of entities in cell
131+
/// @brief Number of entities of dimension.
132+
///
133+
/// @param[in] dim Entity dimension.
134+
/// @param[in] type Cell type.
135+
/// @return Number of entities in cell.
70136
int cell_num_entities(CellType type, int dim);
71137

72-
/// Check if cell is a simplex
73-
/// @param[in] type Cell type
74-
/// @return True is the cell type is a simplex
138+
/// @brief Check if cell is a simplex.
139+
///
140+
/// @param[in] type Cell type.
141+
/// @return True is the cell type is a simplex.
75142
bool is_simplex(CellType type);
76143

77-
/// Number vertices for a cell type
144+
/// @brief Number vertices for a cell type.
145+
///
78146
/// @param[in] type Cell type
79-
/// @return The number of cell vertices
147+
/// @return Number of cell vertices
80148
int num_cell_vertices(CellType type);
81149

82150
// [dim, entity] -> closure{sub_dim, (sub_entities)}

0 commit comments

Comments
 (0)