Skip to content

Commit 7dc50cf

Browse files
committed
Factor out ExodusII_IO_Helper::build_subdomain_map
With the "local" option added it works for Nemesis too. Hopefully this will let us get add_sides support into Nemesis eventually, but also let me get multi-block-subdomain support into both at once.
1 parent f8a1758 commit 7dc50cf

4 files changed

Lines changed: 91 additions & 105 deletions

File tree

include/mesh/exodusII_io_helper.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,13 +1104,30 @@ class ExodusII_IO_Helper : public ParallelObject
11041104
int & count,
11051105
std::vector<std::string> & result);
11061106

1107-
private:
1107+
protected:
11081108

11091109
/**
11101110
* Set to true iff we want to write separate "side" elements too.
11111111
*/
11121112
bool _add_sides = false;
11131113

1114+
/**
1115+
* Map of subdomains to element numbers.
1116+
*/
1117+
std::map<subdomain_id_type, std::vector<dof_id_type>> _subdomain_map;
1118+
1119+
/**
1120+
* One beyond the last "real" subdomain id, in cases where we have
1121+
* "fake" subdomain ids for added sides
1122+
*/
1123+
subdomain_id_type _subdomain_id_end;
1124+
1125+
/**
1126+
* Method for constructing _subdomain_map
1127+
*/
1128+
void build_subdomain_map(const MeshBase & mesh, bool local);
1129+
1130+
private:
11141131
/**
11151132
* write_var_names() dispatches to this function.
11161133
*/

include/mesh/nemesis_io_helper.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,6 @@ class Nemesis_IO_Helper : public ExodusII_IO_Helper
435435
*/
436436
std::set<int> nodes_attached_to_local_elems;
437437

438-
/**
439-
* Map of subdomains to element numbers.
440-
*/
441-
std::map<subdomain_id_type, std::vector<dof_id_type>> subdomain_map;
442-
443438
/**
444439
* This is the block connectivity, i.e. for each subdomain (block) there
445440
* is an element connectivity list. This map associates the block ID to that vector.

src/mesh/exodusII_io_helper.C

Lines changed: 68 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -198,57 +198,6 @@ const std::vector<int> prism_inverse_face_map = {4, 1, 2, 3, 5};
198198
#endif
199199
}
200200

201-
202-
std::map<subdomain_id_type, std::vector<unsigned int>>
203-
build_subdomain_map(const MeshBase & mesh, bool add_sides, subdomain_id_type & subdomain_id_end)
204-
{
205-
std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
206-
207-
// If we've been asked to add side elements, those will go in
208-
// their own blocks.
209-
if (add_sides)
210-
{
211-
std::set<subdomain_id_type> sbd_ids;
212-
mesh.subdomain_ids(sbd_ids);
213-
if (!sbd_ids.empty())
214-
subdomain_id_end = *sbd_ids.rbegin()+1;
215-
}
216-
217-
// Loop through element and map between block and element vector.
218-
for (const auto & elem : mesh.active_element_ptr_range())
219-
{
220-
// We skip writing infinite elements to the Exodus file, so
221-
// don't put them in the subdomain_map. That way the number of
222-
// blocks should be correct.
223-
if (elem->infinite())
224-
continue;
225-
226-
subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
227-
228-
// If we've been asked to add side elements, those will go in their own
229-
// blocks. We don't have any ids to list for elements that don't
230-
// explicitly exist in the mesh, but we do an entry to keep
231-
// track of the number of elements we'll add in each new block.
232-
if (add_sides)
233-
for (auto s : elem->side_index_range())
234-
{
235-
if (EquationSystems::redundant_added_side(*elem,s))
236-
continue;
237-
238-
auto & marker =
239-
subdomain_map[subdomain_id_end + elem->side_type(s)];
240-
if (marker.empty())
241-
marker.push_back(1);
242-
else
243-
++marker[0];
244-
}
245-
}
246-
247-
if (!add_sides && !subdomain_map.empty())
248-
subdomain_id_end = subdomain_map.rbegin()->first + 1;
249-
250-
return subdomain_map;
251-
}
252201
} // end anonymous namespace
253202

254203

@@ -2356,8 +2305,7 @@ void ExodusII_IO_Helper::initialize(std::string str_title, const MeshBase & mesh
23562305
num_edge = bi.n_edge_conds();
23572306

23582307
// We need to know about all processors' subdomains
2359-
subdomain_id_type subdomain_id_end = 0;
2360-
auto subdomain_map = build_subdomain_map(mesh, _add_sides, subdomain_id_end);
2308+
build_subdomain_map(mesh, false);
23612309

23622310
num_elem = n_active_elem;
23632311
num_nodes = 0;
@@ -2478,7 +2426,7 @@ void ExodusII_IO_Helper::initialize(std::string str_title, const MeshBase & mesh
24782426
num_side_sets = cast_int<int>(unique_side_boundaries.size());
24792427
num_node_sets = cast_int<int>(unique_node_boundaries.size());
24802428

2481-
num_elem_blk = cast_int<int>(subdomain_map.size());
2429+
num_elem_blk = cast_int<int>(this->_subdomain_map.size());
24822430

24832431
if (str_title.size() > MAX_LINE_LENGTH)
24842432
{
@@ -2702,16 +2650,11 @@ void ExodusII_IO_Helper::write_elements(const MeshBase & mesh, bool use_disconti
27022650
{
27032651
LOG_SCOPE("write_elements()", "ExodusII_IO_Helper");
27042652

2705-
// Map from block ID to a vector of element IDs in that block. Element
2706-
// IDs are now of type dof_id_type, subdomain IDs are of type subdomain_id_type.
2707-
subdomain_id_type subdomain_id_end = 0;
2708-
auto subdomain_map = build_subdomain_map(mesh, _add_sides, subdomain_id_end);
2709-
27102653
if ((_run_only_on_proc0) && (this->processor_id() != 0))
27112654
return;
27122655

27132656
// element map vector
2714-
num_elem_blk = cast_int<int>(subdomain_map.size());
2657+
num_elem_blk = cast_int<int>(this->_subdomain_map.size());
27152658
block_ids.resize(num_elem_blk);
27162659

27172660
std::vector<int> elem_blk_id;
@@ -2732,15 +2675,15 @@ void ExodusII_IO_Helper::write_elements(const MeshBase & mesh, bool use_disconti
27322675

27332676
// counter indexes into the block_ids vector
27342677
unsigned int counter = 0;
2735-
for (auto & [subdomain_id, element_id_vec] : subdomain_map)
2678+
for (auto & [subdomain_id, element_id_vec] : this->_subdomain_map)
27362679
{
27372680
block_ids[counter] = subdomain_id;
27382681

2739-
const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
2740-
ElemType(subdomain_id - subdomain_id_end) :
2682+
const ElemType elem_t = (subdomain_id >= this->_subdomain_id_end) ?
2683+
ElemType(subdomain_id - this->_subdomain_id_end) :
27412684
mesh.elem_ref(element_id_vec[0]).type();
27422685

2743-
if (subdomain_id >= subdomain_id_end)
2686+
if (subdomain_id >= this->_subdomain_id_end)
27442687
{
27452688
libmesh_assert(_add_sides);
27462689
libmesh_assert(element_id_vec.size() == 1);
@@ -2993,14 +2936,14 @@ void ExodusII_IO_Helper::write_elements(const MeshBase & mesh, bool use_disconti
29932936
next_fake_id = mesh.next_unique_id();
29942937
#endif
29952938

2996-
for (auto & [subdomain_id, element_id_vec] : subdomain_map)
2939+
for (auto & [subdomain_id, element_id_vec] : this->_subdomain_map)
29972940
{
29982941
// Use the first element in the block to get representative
29992942
// information for a "real" block. Note that Exodus assumes all
30002943
// elements in a block are of the same type! We are using that
30012944
// same assumption here!
3002-
const ElemType elem_t = (subdomain_id >= subdomain_id_end) ?
3003-
ElemType(subdomain_id - subdomain_id_end) :
2945+
const ElemType elem_t = (subdomain_id >= this->_subdomain_id_end) ?
2946+
ElemType(subdomain_id - this->_subdomain_id_end) :
30042947
mesh.elem_ref(element_id_vec[0]).type();
30052948

30062949
const auto & conv = get_conversion(elem_t);
@@ -3010,7 +2953,7 @@ void ExodusII_IO_Helper::write_elements(const MeshBase & mesh, bool use_disconti
30102953

30112954
// If this is a *real* block, we just loop over vectors of
30122955
// element ids to add.
3013-
if (subdomain_id < subdomain_id_end)
2956+
if (subdomain_id < this->_subdomain_id_end)
30142957
{
30152958
connect.resize(element_id_vec.size()*num_nodes_per_elem);
30162959

@@ -3130,7 +3073,7 @@ void ExodusII_IO_Helper::write_elements(const MeshBase & mesh, bool use_disconti
31303073
nullptr, // elem_edge_conn (unused)
31313074
nullptr); // elem_face_conn (unused)
31323075
EX_CHECK_ERR(ex_err, "Error writing element connectivities");
3133-
} // end for (auto & [subdomain_id, element_id_vec] : subdomain_map)
3076+
} // end for (auto & [subdomain_id, element_id_vec] : this->_subdomain_map)
31343077

31353078
// write out the element number map that we created
31363079
ex_err = exII::ex_put_elem_num_map(ex_id, elem_num_map.data());
@@ -4509,12 +4452,7 @@ void ExodusII_IO_Helper::write_element_values
45094452
ex_err = exII::ex_get_variable_param(ex_id, exII::EX_ELEM_BLOCK, &num_elem_vars);
45104453
EX_CHECK_ERR(ex_err, "Error reading number of elemental variables.");
45114454

4512-
// We will eventually loop over the element blocks (subdomains) and
4513-
// write the data one block at a time. Build a data structure that
4514-
// maps each subdomain to a list of element ids it contains.
4515-
std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
4516-
for (const auto & elem : mesh.active_element_ptr_range())
4517-
subdomain_map[elem->subdomain_id()].push_back(elem->id());
4455+
this->build_subdomain_map(mesh, false);
45184456

45194457
// Use mesh.n_elem() to access into the values vector rather than
45204458
// the number of elements the Exodus writer thinks the mesh has,
@@ -4533,13 +4471,13 @@ void ExodusII_IO_Helper::write_element_values
45334471
for (unsigned int var_id=0; var_id<static_cast<unsigned>(num_elem_vars); ++var_id)
45344472
{
45354473
// The size of the subdomain map is the number of blocks.
4536-
auto it = subdomain_map.begin();
4474+
auto it = this->_subdomain_map.begin();
45374475

45384476
// Reference to the set of active subdomains for the current variable.
45394477
const auto & active_subdomains
45404478
= vars_active_subdomains[var_id];
45414479

4542-
for (unsigned int j=0; it!=subdomain_map.end(); ++it, ++j)
4480+
for (unsigned int j=0; it!=this->_subdomain_map.end(); ++it, ++j)
45434481
{
45444482
// Skip any variable/subdomain pairs that are inactive.
45454483
// Note that if active_subdomains is empty, it is interpreted
@@ -4957,6 +4895,59 @@ get_complex_subdomain_to_var_names
49574895

49584896

49594897

4898+
void ExodusII_IO_Helper::build_subdomain_map(const MeshBase & mesh, bool local)
4899+
{
4900+
// Start from scratch
4901+
this->_subdomain_map.clear();
4902+
this->_subdomain_id_end = 0;
4903+
4904+
// If we've been asked to add side elements, those will go in
4905+
// their own blocks.
4906+
if (this->_add_sides)
4907+
{
4908+
std::set<subdomain_id_type> sbd_ids;
4909+
mesh.subdomain_ids(sbd_ids);
4910+
if (!sbd_ids.empty())
4911+
this->_subdomain_id_end = *sbd_ids.rbegin()+1;
4912+
}
4913+
4914+
// Loop through element and map between block and element vector.
4915+
const auto range = local ? mesh.active_local_element_ptr_range() :
4916+
mesh.active_element_ptr_range();
4917+
for (const auto & elem : range)
4918+
{
4919+
// We skip writing infinite elements to the Exodus file, so
4920+
// don't put them in the subdomain_map. That way the number of
4921+
// blocks should be correct.
4922+
if (elem->infinite())
4923+
continue;
4924+
4925+
this->_subdomain_map[ elem->subdomain_id() ].push_back(elem->id());
4926+
4927+
// If we've been asked to add side elements, those will go in their own
4928+
// blocks. We don't have any ids to list for elements that don't
4929+
// explicitly exist in the mesh, but we do an entry to keep
4930+
// track of the number of elements we'll add in each new block.
4931+
if (this->_add_sides)
4932+
for (auto s : elem->side_index_range())
4933+
{
4934+
if (EquationSystems::redundant_added_side(*elem,s))
4935+
continue;
4936+
4937+
auto & marker =
4938+
this->_subdomain_map[this->_subdomain_id_end + elem->side_type(s)];
4939+
if (marker.empty())
4940+
marker.push_back(1);
4941+
else
4942+
++marker[0];
4943+
}
4944+
}
4945+
4946+
if (!this->_add_sides && !this->_subdomain_map.empty())
4947+
this->_subdomain_id_end = this->_subdomain_map.rbegin()->first + 1;
4948+
}
4949+
4950+
49604951
int ExodusII_IO_Helper::Conversion::get_node_map(int i) const
49614952
{
49624953
if (!node_map)

src/mesh/nemesis_io_helper.C

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,31 +1666,14 @@ void Nemesis_IO_Helper::build_element_and_node_maps(const MeshBase & pmesh)
16661666

16671667
// Make sure there is no leftover information in the subdomain_map, and reserve
16681668
// enough space to store the elements we need.
1669-
this->subdomain_map.clear();
1670-
for (const auto & [sbd_id, cnt] : local_subdomain_counts)
1671-
{
1672-
if (verbose)
1673-
{
1674-
libMesh::out << "[" << this->processor_id() << "] "
1675-
<< "local_subdomain_counts [" << static_cast<unsigned>(sbd_id) << "]= "
1676-
<< cnt
1677-
<< std::endl;
1678-
}
1679-
1680-
this->subdomain_map[sbd_id].reserve(cnt);
1681-
}
1682-
1669+
this->build_subdomain_map(pmesh, true);
16831670

16841671
// First loop over the elements to figure out which elements are in which subdomain
16851672
for (const auto & elem : pmesh.active_local_element_ptr_range())
16861673
{
16871674
// Grab the nodes while we're here.
16881675
for (auto n : elem->node_index_range())
16891676
this->nodes_attached_to_local_elems.insert( elem->node_id(n) );
1690-
1691-
subdomain_id_type cur_subdomain = elem->subdomain_id();
1692-
1693-
this->subdomain_map[cur_subdomain].push_back(elem->id());
16941677
}
16951678

16961679
// Set num_nodes which is used by exodusII_io_helper
@@ -1736,7 +1719,7 @@ void Nemesis_IO_Helper::build_element_and_node_maps(const MeshBase & pmesh)
17361719
this->libmesh_elem_num_to_exodus.clear();
17371720

17381721
// Now loop over each subdomain and get a unique numbering for the elements
1739-
for (auto & [block_id, elem_ids_this_subdomain] : subdomain_map)
1722+
for (auto & [block_id, elem_ids_this_subdomain] : this->_subdomain_map)
17401723
{
17411724
block_ids.push_back(block_id);
17421725

@@ -2308,7 +2291,7 @@ void Nemesis_IO_Helper::write_elements(const MeshBase & mesh, bool /*use_discont
23082291
subdomain_id_type block =
23092292
cast_int<subdomain_id_type>(it->first);
23102293
const std::vector<int> & this_block_connectivity = it->second;
2311-
std::vector<dof_id_type> & elements_in_this_block = subdomain_map[block];
2294+
std::vector<dof_id_type> & elements_in_this_block = this->_subdomain_map[block];
23122295

23132296
// Use the first element in this block to get representative information.
23142297
// Note that Exodus assumes all elements in a block are of the same type!
@@ -2662,10 +2645,10 @@ Nemesis_IO_Helper::write_element_values(const MeshBase & mesh,
26622645
{
26632646
const subdomain_id_type sbd_id =
26642647
cast_int<subdomain_id_type>(sbd_id_int);
2665-
auto it = subdomain_map.find(sbd_id);
2648+
auto it = this->_subdomain_map.find(sbd_id);
26662649
const std::vector<dof_id_type> empty_vec;
26672650
const std::vector<dof_id_type> & elem_ids =
2668-
(it == subdomain_map.end()) ? empty_vec : it->second;
2651+
(it == this->_subdomain_map.end()) ? empty_vec : it->second;
26692652

26702653
// Possibly skip this (variable, subdomain) combination. Also, check that there is at
26712654
// least one element on the subdomain... Indeed, it is possible to have zero elements,

0 commit comments

Comments
 (0)