11 #include "IndirectSort.h"
12 #include "MooseMesh.h"
13 #include "MooseUtils.h"
14 #include "MooseVariable.h"
15 #include "SubProblem.h"
18 #include "FEProblem.h"
19 #include "NonlinearSystem.h"
20 #include "TimedPrint.h"
22 #include "libmesh/dof_map.h"
23 #include "libmesh/mesh_tools.h"
24 #include "libmesh/periodic_boundaries.h"
25 #include "libmesh/point_locator_base.h"
26 #include "libmesh/remote_elem.h"
40 storeHelper(stream, feature.
_halo_ids, context);
43 storeHelper(stream, feature.
_var_index, context);
44 storeHelper(stream, feature.
_id, context);
45 storeHelper(stream, feature.
_bboxes, context);
46 storeHelper(stream, feature.
_orig_ids, context);
48 storeHelper(stream, feature.
_vol_count, context);
49 storeHelper(stream, feature.
_centroid, context);
50 storeHelper(stream, feature.
_status, context);
56 dataStore(std::ostream & stream, BoundingBox & bbox,
void * context)
58 storeHelper(stream, bbox.min(), context);
59 storeHelper(stream, bbox.max(), context);
71 loadHelper(stream, feature.
_halo_ids, context);
74 loadHelper(stream, feature.
_var_index, context);
75 loadHelper(stream, feature.
_id, context);
76 loadHelper(stream, feature.
_bboxes, context);
77 loadHelper(stream, feature.
_orig_ids, context);
79 loadHelper(stream, feature.
_vol_count, context);
80 loadHelper(stream, feature.
_centroid, context);
81 loadHelper(stream, feature.
_status, context);
87 dataLoad(std::istream & stream, BoundingBox & bbox,
void * context)
89 loadHelper(stream, bbox.min(), context);
90 loadHelper(stream, bbox.max(), context);
97 const std::list<dof_id_type> & elem_list2,
106 InputParameters params = validParams<GeneralPostprocessor>();
107 params += validParams<BoundaryRestrictable>();
109 params.addRequiredCoupledVar(
111 "The variable(s) for which to find connected regions of interests, i.e. \"features\".");
112 params.addParam<Real>(
113 "threshold", 0.5,
"The threshold value for which a new feature may be started");
114 params.addParam<Real>(
115 "connecting_threshold",
116 "The threshold for which an existing feature may be extended (defaults to \"threshold\")");
117 params.addParam<
bool>(
"use_single_map",
119 "Determine whether information is tracked per "
120 "coupled variable or consolidated into one "
122 params.addParam<
bool>(
125 "Determines whether we condense all the node values when in multimap mode (default: false)");
126 params.addParam<
bool>(
"use_global_numbering",
128 "Determine whether or not global numbers are "
129 "used to label features on multiple maps "
131 params.addParam<
bool>(
"enable_var_coloring",
133 "Instruct the Postprocessor to populate the variable index map.");
134 params.addParam<
bool>(
137 "Instruct the Postprocessor to communicate proper halo information to all ranks");
138 params.addParam<
bool>(
"compute_var_to_feature_map",
140 "Instruct the Postprocessor to compute the active vars to features map");
141 params.addParam<
bool>(
142 "use_less_than_threshold_comparison",
144 "Controls whether features are defined to be less than or greater than the threshold value.");
146 params.addParam<std::vector<BoundaryName>>(
147 "primary_percolation_boundaries",
148 "A list of boundaries used in conjunction with the corresponding "
149 "\"secondary_percolation_boundaries\" parameter for determining if a feature creates a path "
150 "connecting any pair of boundaries");
151 params.addParam<std::vector<BoundaryName>>(
152 "secondary_percolation_boundaries",
153 "Paired boundaries with \"primaryary_percolation_boundaries\" parameter");
154 params.addParam<std::vector<BoundaryName>>(
155 "specified_boundaries",
156 "An optional list of boundaries; if supplied, each feature is checked to determine whether "
157 "it intersects any of the specified boundaries in this list.");
166 params.set<
bool>(
"use_displaced_mesh") =
false;
172 params.addPrivateParam<
bool>(
"restartable_required",
false);
174 params.addParamNamesToGroup(
175 "use_single_map condense_map_info use_global_numbering primary_percolation_boundaries",
178 MooseEnum flood_type(
"NODAL ELEMENTAL",
"ELEMENTAL");
179 params.addParam<MooseEnum>(
"flood_entity_type",
181 "Determines whether the flood algorithm runs on nodes or elements");
183 params.addClassDescription(
"The object is able to find and count \"connected components\" in any "
184 "solution field or number of solution fields. A primary example would "
185 "be to count \"bubbles\".");
187 params.addRelationshipManager(
"ElementSideNeighborLayers",
188 Moose::RelationshipManagerType::GEOMETRIC |
189 Moose::RelationshipManagerType::ALGEBRAIC);
195 : GeneralPostprocessor(parameters),
196 Coupleable(this, false),
197 MooseVariableDependencyInterface(),
198 BoundaryRestrictable(this, false),
199 _fe_vars(getCoupledMooseVars()),
200 _vars(getCoupledStandardMooseVars()),
201 _dof_map(_vars[0]->dofMap()),
202 _threshold(getParam<Real>(
"threshold")),
203 _connecting_threshold(isParamValid(
"connecting_threshold")
204 ? getParam<Real>(
"connecting_threshold")
205 : getParam<Real>(
"threshold")),
206 _mesh(_subproblem.mesh()),
207 _var_number(_fe_vars[0]->number()),
208 _single_map_mode(getParam<bool>(
"use_single_map")),
209 _condense_map_info(getParam<bool>(
"condense_map_info")),
210 _global_numbering(getParam<bool>(
"use_global_numbering")),
211 _var_index_mode(getParam<bool>(
"enable_var_coloring")),
212 _compute_halo_maps(getParam<bool>(
"compute_halo_maps")),
213 _compute_var_to_feature_map(getParam<bool>(
"compute_var_to_feature_map")),
214 _use_less_than_threshold_comparison(getParam<bool>(
"use_less_than_threshold_comparison")),
215 _n_vars(_fe_vars.size()),
216 _maps_size(_single_map_mode ? 1 : _fe_vars.size()),
217 _n_procs(_app.n_processors()),
218 _feature_counts_per_map(_maps_size),
220 _partial_feature_sets(_maps_size),
221 _feature_sets(getParam<bool>(
"restartable_required")
222 ? declareRestartableData<std::vector<
FeatureData>>(
"feature_sets")
223 : _volatile_feature_sets),
224 _feature_maps(_maps_size),
226 _element_average_value(parameters.isParamValid(
"elem_avg_value")
227 ? getPostprocessorValue(
"elem_avg_value")
229 _halo_ids(_maps_size),
230 _is_elemental(getParam<MooseEnum>(
"flood_entity_type") ==
"ELEMENTAL"),
231 _is_master(processor_id() == 0),
232 _distribute_merge_work(_app.n_processors() >= _maps_size && _maps_size > 1),
233 _execute_timer(registerTimedSection(
"execute", 1)),
234 _merge_timer(registerTimedSection(
"mergeFeatures", 2)),
235 _finalize_timer(registerTimedSection(
"finalize", 1)),
236 _comm_and_merge(registerTimedSection(
"communicateAndMerge", 2)),
237 _expand_halos(registerTimedSection(
"expandEdgeHalos", 2)),
238 _update_field_info(registerTimedSection(
"updateFieldInfo", 2)),
239 _prepare_for_transfer(registerTimedSection(
"prepareDataForTransfer", 2)),
240 _consolidate_merged_features(registerTimedSection(
"consolidateMergedFeatures", 2))
245 addMooseVariableDependency(
_fe_vars);
249 if (_subproblem.isTransient())
252 for (
auto & var :
_vars)
255 var->dofValuesOlder();
259 if (parameters.isParamValid(
"primary_percolation_boundaries"))
261 parameters.get<std::vector<BoundaryName>>(
"primary_percolation_boundaries"));
262 if (parameters.isParamValid(
"secondary_percolation_boundaries"))
264 parameters.get<std::vector<BoundaryName>>(
"secondary_percolation_boundaries"));
267 paramError(
"primary_percolation_boundaries",
268 "primary_percolation_boundaries and secondary_percolation_boundaries must both be "
269 "supplied when checking for percolation");
271 if (parameters.isParamValid(
"specified_boundaries"))
273 _mesh.getBoundaryIDs(parameters.get<std::vector<BoundaryName>>(
"specified_boundaries"));
283 _pbs = _fe_problem.getNonlinearSystemBase().dofMap().get_periodic_boundaries();
352 for (
auto elem_it =
_mesh.bndElemsBegin(), elem_end =
_mesh.bndElemsEnd(); elem_it != elem_end;
361 CONSOLE_TIMED_PRINT(
"Flooding Features");
366 mooseInfo(
"Using EXPERIMENTAL boundary restricted FeatureFloodCount object!\n");
371 auto rank = processor_id();
375 const Elem * elem = belem->_elem;
376 BoundaryID boundary_id = belem->_bnd_id;
378 if (elem->processor_id() == rank)
380 if (hasBoundary(boundary_id))
381 for (MooseIndex(
_vars) var_num = 0; var_num <
_vars.size(); ++var_num)
382 flood(elem, var_num);
388 for (
const auto & current_elem :
_mesh.getMesh().active_local_element_ptr_range())
393 for (MooseIndex(
_vars) var_num = 0; var_num <
_vars.size(); ++var_num)
394 flood(current_elem, var_num);
398 auto n_nodes = current_elem->n_vertices();
399 for (MooseIndex(n_nodes) i = 0; i < n_nodes; ++i)
401 const Node * current_node = current_elem->node_ptr(i);
403 for (MooseIndex(
_vars) var_num = 0; var_num <
_vars.size(); ++var_num)
404 flood(current_node, var_num);
426 std::vector<std::string> send_buffers(1);
434 std::vector<std::string> recv_buffers, deserialize_buffers;
444 auto rank = processor_id();
445 bool is_merging_processor = rank <
_n_vars;
447 if (is_merging_processor)
448 recv_buffers.reserve(_app.n_processors());
458 _communicator.gather_packed_range(i,
460 send_buffers.begin(),
462 std::back_inserter(recv_buffers));
471 recv_buffers.swap(deserialize_buffers);
473 recv_buffers.clear();
477 Parallel::Communicator merge_comm;
480 _communicator.split(is_merging_processor ? 0 : 1, rank, merge_comm);
482 if (is_merging_processor)
496 send_buffers[0].clear();
497 recv_buffers.clear();
498 deserialize_buffers.clear();
513 merge_comm.gather_packed_range(0,
515 send_buffers.begin(),
517 std::back_inserter(recv_buffers));
524 send_buffers[0].clear();
525 recv_buffers.clear();
539 recv_buffers.reserve(_app.n_processors());
550 _communicator.gather_packed_range(0,
552 send_buffers.begin(),
554 std::back_inserter(recv_buffers));
560 recv_buffers.clear();
575 mooseAssert(
_is_master,
"sortAndLabel can only be called on the master");
590 unsigned int feature_offset = 0;
598 auto range_front = feature_offset;
601 mooseAssert(range_front <= range_back && range_back <
_feature_count,
602 "Indexing error in feature sets");
606 mooseError(
"Error in _feature_sets sorting, map index: ", map_num);
620 std::vector<int> & counts)
const
622 mooseAssert(
_is_master,
"This method must only be called on the root processor");
627 for (
const auto & local_index_pair : feature._orig_ids)
630 mooseAssert(local_index_pair.first <
_n_procs,
"Processor ID is out of range");
631 if (local_index_pair.second >= static_cast<std::size_t>(counts[local_index_pair.first]))
632 counts[local_index_pair.first] = local_index_pair.second + 1;
636 unsigned int globalsize = 0;
638 for (MooseIndex(offsets) i = 0; i < offsets.size(); ++i)
640 offsets[i] = globalsize;
641 globalsize += counts[i];
649 for (
const auto & local_index_pair : feature._orig_ids)
651 auto rank = local_index_pair.first;
654 auto local_index = local_index_pair.second;
655 auto stacked_local_index = offsets[rank] + local_index;
657 mooseAssert(stacked_local_index < globalsize,
658 "Global index: " << stacked_local_index <<
" is out of range");
659 local_to_global_all[stacked_local_index] = feature._id;
674 "Feature ID out of range(" <<
_feature_sets[feature_index]._id <<
')');
684 CONSOLE_TIMED_PRINT(
"Finalizing Feature Identification");
700 const std::vector<unsigned int> &
704 "Please set \"compute_var_to_feature_map = true\" to use this interface method"));
709 mooseAssert(pos->second.size() ==
_n_vars,
"Variable to feature vector not sized properly");
720 std::vector<int> counts;
721 std::vector<std::size_t> local_to_global_all;
728 std::size_t largest_global_index = std::numeric_limits<std::size_t>::lowest();
741 for (
auto & feature : list_ref)
743 mooseAssert(feature._orig_ids.size() == 1,
"feature._orig_ids length doesn't make sense");
746 auto local_index = feature._orig_ids.begin()->second;
753 if (global_index > largest_global_index)
754 largest_global_index = global_index;
757 feature._id = global_index;
766 feature._status &= ~
Status::INACTIVE;
776 for (
auto global_index : local_to_global_all)
778 largest_global_index = global_index;
818 mooseAssert(local_index <
_feature_sets.size(),
"local_index out of bounds");
840 mooseAssert(local_index <
_feature_sets.size(),
"local_index out of bounds");
862 mooseAssert(local_index <
_feature_sets.size(),
"local_index out of bounds");
886 mooseAssert(local_index <
_feature_sets.size(),
"local_index out of bounds");
887 bool primary = ((
_feature_sets[local_index]._boundary_intersection &
890 bool secondary = ((
_feature_sets[local_index]._boundary_intersection &
907 Real invalid_coord = std::numeric_limits<Real>::max();
908 Point p(invalid_coord, invalid_coord, invalid_coord);
911 mooseAssert(local_index <
_feature_sets.size(),
"local_index out of bounds");
920 std::size_t var_index)
const
922 auto use_default =
false;
929 mooseAssert(var_index <
_maps_size,
"Index out of range");
935 const auto entity_it =
_feature_maps[var_index].find(entity_id);
938 return entity_it->second;
947 "\"enable_var_coloring\" must be set to true to pull back the VARIABLE_COLORING field");
952 return entity_it->second;
962 return entity_it->second;
971 const auto entity_it =
_halo_ids[var_index].find(entity_id);
972 if (entity_it !=
_halo_ids[var_index].end())
973 return entity_it->second;
981 const auto entity_it =
_halo_ids[map_num].find(entity_id);
983 if (entity_it !=
_halo_ids[map_num].end())
984 return entity_it->second;
993 mooseDoOnce(mooseWarning(
994 "Centroids are not correct when using periodic boundaries, contact the MOOSE team"));
997 const auto * elem_ptr =
_mesh.elemPtr(entity_id);
1004 if (elem_ptr->contains_point(feature._centroid))
1021 MeshBase & mesh =
_mesh.getMesh();
1027 for (
auto & feature : list_ref)
1048 feature.updateBBoxExtremes(mesh);
1051 for (
auto & halo_id : feature._halo_ids)
1055 mooseAssert(!feature._local_ids.empty(),
"local entity ids cannot be empty");
1061 feature._min_entity_id = *feature._local_ids.begin();
1070 std::ostringstream oss;
1073 "var_num out of range");
1082 serialized_buffer.assign(oss.str());
1089 std::istringstream iss;
1091 auto rank = processor_id();
1093 for (MooseIndex(serialized_buffers) proc_id = 0; proc_id < serialized_buffers.size(); ++proc_id)
1106 if (var_num ==
invalid_id && proc_id == rank)
1109 iss.str(serialized_buffers[proc_id]);
1132 bool merge_occured =
false;
1139 it2->merge(std::move(*it1));
1161 merge_occured =
true;
1187 mooseAssert(
_is_master,
"cosolidateMergedFeatures() may only be called on the master processor");
1190 unsigned int feature_offset = 0;
1200 for (
auto it = (*saved_data)[map_num].begin(); it != (*saved_data)[map_num].end();
1203 if (feature.canConsolidate(*it))
1205 feature.consolidate(std::move(*it));
1206 it = (*saved_data)[map_num].erase(it);
1218 if (feature._vol_count != 0)
1219 feature._centroid /= feature._vol_count;
1258 : feature._var_index;
1261 for (
auto entity : feature._local_ids)
1263 _feature_maps[map_index][entity] = static_cast<int>(feature._id);
1271 auto insert_pair = moose_try_emplace(
1273 auto & vec_ref = insert_pair.first->second;
1274 vec_ref[feature._var_index] = feature._id;
1280 for (
auto entity : feature._halo_ids)
1281 _halo_ids[map_index][entity] = static_cast<int>(feature._id);
1284 for (
auto entity : feature._ghosted_ids)
1289 mooseError(
"Local numbering currently disabled");
1299 mooseAssert(dof_object,
"DOF object is nullptr");
1300 mooseAssert(
_entity_queue.empty(),
"Entity queue is not empty when starting a feature");
1305 bool return_value =
false;
1310 const Elem * elem =
_is_elemental ? static_cast<const Elem *>(curr_dof_object) :
nullptr;
1314 auto entity_id = curr_dof_object->id();
1333 _fe_problem.setCurrentSubdomainID(elem, 0);
1343 mooseAssert(current_index !=
invalid_size_t,
"current_index is invalid");
1353 return_value =
true;
1356 auto map_num =
_single_map_mode ? decltype(current_index)(0) : current_index;
1369 feature->
_id = new_id;
1380 if (
_is_elemental && processor_id() == curr_dof_object->processor_id())
1404 return return_value;
1426 std::size_t & current_index,
1435 const Elem * elem = static_cast<const Elem *>(dof_object);
1436 std::vector<Point> centroid(1, elem->centroid());
1437 _subproblem.reinitElemPhys(elem, centroid, 0,
true);
1438 entity_value =
_vars[current_index]->sln()[0];
1441 entity_value =
_vars[current_index]->getNodalValue(*static_cast<const Node *>(dof_object));
1447 Status * status_ptr = &status;
1450 status_ptr = &feature->
_status;
1453 *status_ptr &= ~
Status::INACTIVE;
1467 const auto & node_to_elem_map =
_mesh.nodeToActiveSemilocalElemMap();
1469 auto my_processor_id = processor_id();
1479 for (
auto & feature : list_ref)
1481 expanded_local_ids.clear();
1483 for (
auto entity : feature._local_ids)
1485 const Elem * elem =
_mesh.elemPtr(entity);
1486 mooseAssert(elem,
"elem pointer is NULL");
1489 auto n_nodes = elem->n_vertices();
1490 for (MooseIndex(n_nodes) i = 0; i < n_nodes; ++i)
1492 const Node * current_node = elem->node_ptr(i);
1494 auto elem_vector_it = node_to_elem_map.find(current_node->id());
1495 if (elem_vector_it == node_to_elem_map.end())
1496 mooseError(
"Error in node to elem map");
1498 const auto & elem_vector = elem_vector_it->second;
1500 std::copy(elem_vector.begin(),
1502 std::insert_iterator<FeatureData::container_type>(expanded_local_ids,
1503 expanded_local_ids.end()));
1506 for (
auto entity : elem_vector)
1508 const Elem * neighbor =
_mesh.elemPtr(entity);
1509 mooseAssert(neighbor,
"neighbor pointer is NULL");
1511 if (neighbor->processor_id() != my_processor_id)
1512 feature._ghosted_ids.insert(feature._ghosted_ids.end(), elem->id());
1518 feature._local_ids.swap(expanded_local_ids);
1521 feature._halo_ids = feature._local_ids;
1529 if (num_layers_to_expand == 0)
1536 for (
auto & feature : list_ref)
1538 for (MooseIndex(num_layers_to_expand) halo_level = 0; halo_level < num_layers_to_expand;
1546 for (
auto entity : orig_halo_ids)
1564 for (
auto entity : disjoint_orig_halo_ids)
1586 bool expand_halos_only,
1589 mooseAssert(elem,
"Elem is NULL");
1591 std::vector<const Elem *> all_active_neighbors;
1592 MeshBase & mesh =
_mesh.getMesh();
1595 for (MooseIndex(elem->n_neighbors()) i = 0; i < elem->n_neighbors(); ++i)
1597 const Elem * neighbor_ancestor =
nullptr;
1598 bool topological_neighbor =
false;
1604 neighbor_ancestor = elem->neighbor_ptr(i);
1605 if (neighbor_ancestor)
1607 if (neighbor_ancestor == libMesh::remote_elem)
1610 neighbor_ancestor->active_family_tree_by_neighbor(all_active_neighbors, elem,
false);
1623 if (neighbor_ancestor)
1625 neighbor_ancestor->active_family_tree_by_topological_neighbor(
1628 topological_neighbor =
true;
1642 all_active_neighbors,
1645 topological_neighbor,
1648 all_active_neighbors.clear();
1655 bool expand_halos_only)
1657 mooseAssert(node,
"Node is NULL");
1659 std::vector<const Node *> all_active_neighbors;
1665 template <
typename T>
1668 std::vector<const T *> neighbor_entities,
1670 bool expand_halos_only,
1671 bool topological_neighbor,
1675 for (
const auto neighbor : neighbor_entities)
1679 if (expand_halos_only)
1681 auto entity_id = neighbor->id();
1683 if (topological_neighbor || disjoint_only)
1690 auto my_processor_id = processor_id();
1692 if (!topological_neighbor && neighbor->processor_id() != my_processor_id)
1704 if (curr_entity->processor_id() == my_processor_id ||
1705 neighbor->processor_id() == my_processor_id)
1713 if (topological_neighbor || disjoint_only)
1734 Elem * elem =
_mesh.elemPtr(entity);
1735 if (elem && elem->on_boundary())
1745 if (
_mesh.isBoundaryElem(entity, primary_id))
1753 if (
_mesh.isBoundaryElem(entity, secondary_id))
1763 if (
_mesh.isBoundaryElem(entity, specified_id))
1777 Elem * elem =
_mesh.elemPtr(entity);
1779 for (MooseIndex(elem->n_nodes()) node_n = 0; node_n < elem->n_nodes(); ++node_n)
1783 for (
auto it = iters.first; it != iters.second; ++it)
1797 for (
auto it = iters.first; it != iters.second; ++it)
1808 template <
typename T>
1817 if (belem->_elem->id() == entity->id() && hasBoundary(belem->_bnd_id))
1833 std::list<dof_id_type> disjoint_elem_id_list;
1838 std::insert_iterator<std::list<dof_id_type>>(disjoint_elem_id_list,
1839 disjoint_elem_id_list.begin()));
1841 if (!disjoint_elem_id_list.empty())
1851 std::list<std::list<dof_id_type>> disjoint_regions;
1854 disjoint_regions.emplace_back(std::list<dof_id_type>({elem_id}));
1857 for (
auto it1 = disjoint_regions.begin(); it1 != disjoint_regions.end(); )
1859 bool merge_occured =
false;
1860 for (
auto it2 = disjoint_regions.begin(); it2 != disjoint_regions.end(); ++it2)
1864 it2->splice(it2->begin(), *it1);
1866 disjoint_regions.emplace_back(std::move(*it2));
1867 disjoint_regions.erase(it2);
1868 it1 = disjoint_regions.erase(it1);
1870 merge_occured =
true;
1881 auto num_regions = disjoint_regions.size();
1883 _bboxes.resize(num_regions + 1);
1885 decltype(num_regions) region = 1;
1886 for (
const auto list_ref : disjoint_regions)
1888 for (
const auto elem_id : list_ref)
1898 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
1910 for (
unsigned int i = 0; i < LIBMESH_DIM; ++i)
1912 bbox.min()(i) = std::min(bbox.min()(i), rhs_bbox.min()(i));
1913 bbox.max()(i) = std::max(bbox.max()(i), rhs_bbox.max()(i));
1921 for (
const auto & bbox_lhs : _bboxes)
1922 for (
const auto & bbox_rhs : rhs.
_bboxes)
1923 if (bbox_lhs.intersects(bbox_rhs, libMesh::TOLERANCE * libMesh::TOLERANCE))
1940 _periodic_nodes.end(),
1956 ((boundingBoxesIntersect(rhs) &&
1957 ghostedIntersect(rhs))
1959 periodicBoundariesIntersect(rhs)));
1965 for (
const auto & orig_id_pair1 : _orig_ids)
1966 for (
const auto & orig_id_pair2 : rhs.
_orig_ids)
1967 if (orig_id_pair1 == orig_id_pair2)
1976 mooseAssert(_var_index == rhs._var_index,
"Mismatched variable index in merge");
1977 mooseAssert(_id == rhs._id,
"Mismatched auxiliary id in merge");
1982 std::set_union(_local_ids.begin(),
1984 rhs._local_ids.begin(),
1985 rhs._local_ids.end(),
1986 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
1987 _local_ids.swap(set_union);
1991 std::set_union(_periodic_nodes.begin(),
1992 _periodic_nodes.end(),
1993 rhs._periodic_nodes.begin(),
1994 rhs._periodic_nodes.end(),
1995 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
1996 _periodic_nodes.swap(set_union);
2000 std::set_union(_ghosted_ids.begin(),
2002 rhs._ghosted_ids.begin(),
2003 rhs._ghosted_ids.end(),
2004 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2013 bool physical_intersection = (_ghosted_ids.size() + rhs._ghosted_ids.size() > set_union.size());
2014 _ghosted_ids.swap(set_union);
2020 if (physical_intersection)
2023 std::move(rhs._bboxes.begin(), rhs._bboxes.end(), std::back_inserter(_bboxes));
2027 std::set_union(_disjoint_halo_ids.begin(),
2028 _disjoint_halo_ids.end(),
2029 rhs._disjoint_halo_ids.begin(),
2030 rhs._disjoint_halo_ids.end(),
2031 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2032 _disjoint_halo_ids.swap(set_union);
2038 rhs._halo_ids.begin(),
2039 rhs._halo_ids.end(),
2040 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2044 _orig_ids.splice(_orig_ids.end(), std::move(rhs._orig_ids));
2047 _min_entity_id = std::min(_min_entity_id, rhs._min_entity_id);
2055 "Flags in invalid state");
2058 _status &= rhs._status;
2061 _boundary_intersection |= rhs._boundary_intersection;
2063 _vol_count += rhs._vol_count;
2064 _centroid += rhs._centroid;
2070 mooseAssert(_var_index == rhs._var_index,
"Mismatched variable index in merge");
2071 mooseAssert(_id == rhs._id,
"Mismatched auxiliary id in merge");
2075 std::set_union(_local_ids.begin(),
2077 rhs._local_ids.begin(),
2078 rhs._local_ids.end(),
2079 std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2080 _local_ids.swap(set_union);
2083 "Flags in invalid state");
2090 _periodic_nodes.clear();
2092 _disjoint_halo_ids.clear();
2093 _ghosted_ids.clear();
2101 std::vector<bool> intersected_boxes(rhs.
_bboxes.size(),
false);
2103 auto box_expanded =
false;
2104 for (
auto & bbox : _bboxes)
2107 if (bbox.intersects(rhs.
_bboxes[j], libMesh::TOLERANCE * libMesh::TOLERANCE))
2109 updateBBoxExtremes(bbox, rhs.
_bboxes[j]);
2110 intersected_boxes[j] =
true;
2111 box_expanded =
true;
2118 std::ostringstream oss;
2119 oss <<
"LHS BBoxes:\n";
2120 for (MooseIndex(_bboxes) i = 0; i < _bboxes.size(); ++i)
2121 oss <<
"Max: " << _bboxes[i].max() <<
" Min: " << _bboxes[i].min() <<
'\n';
2123 oss <<
"RHS BBoxes:\n";
2125 oss <<
"Max: " << rhs.
_bboxes[i].max() <<
" Min: " << rhs.
_bboxes[i].min() <<
'\n';
2127 ::mooseError(
"No Bounding Boxes Expanded - This is a catastrophic error!\n", oss.str());
2132 for (MooseIndex(intersected_boxes) j = 0; j < intersected_boxes.size(); ++j)
2133 if (!intersected_boxes[j])
2134 _bboxes.push_back(rhs.
_bboxes[j]);
2140 static const bool debug =
true;
2142 out <<
"Grain ID: ";
2150 out <<
"\nGhosted Entities: ";
2152 out << ghosted_id <<
" ";
2154 out <<
"\nLocal Entities: ";
2156 out << local_id <<
" ";
2158 out <<
"\nHalo Entities: ";
2160 out << halo_id <<
" ";
2162 out <<
"\nPeriodic Node IDs: ";
2164 out << periodic_node <<
" ";
2169 for (
const auto & bbox : feature.
_bboxes)
2171 out <<
"\nMax: " << bbox.max() <<
" Min: " << bbox.min();
2172 volume += (bbox.max()(0) - bbox.min()(0)) * (bbox.max()(1) - bbox.min()(1)) *
2173 (MooseUtils::absoluteFuzzyEqual(bbox.max()(2), bbox.min()(2))
2175 : bbox.max()(2) - bbox.min()(2));
2178 out <<
"\nStatus: ";
2190 out <<
"\nOrig IDs (rank, index): ";
2191 for (
const auto & orig_pair : feature.
_orig_ids)
2192 out <<
'(' << orig_pair.first <<
", " << orig_pair.second <<
") ";
2193 out <<
"\nVar_index: " << feature.
_var_index;
2208 for (
unsigned int i = 0; i < LIBMESH_DIM; ++i)
2210 bbox.min()(i) = std::min(bbox.min()(i), node(i));
2211 bbox.max()(i) = std::max(bbox.max()(i), node(i));
2218 for (MooseIndex(elem.n_nodes()) node_n = 0; node_n < elem.n_nodes(); ++node_n)
2224 const std::list<dof_id_type> & elem_list2,
2227 for (
const auto elem_id1 : elem_list1)
2229 const auto * elem1 = mesh.elem_ptr(elem_id1);
2230 for (
const auto elem_id2 : elem_list2)
2232 const auto * elem2 = mesh.elem_ptr(elem_id2);
2233 if (elem1->has_neighbor(elem2))