www.mooseframework.org
FeatureFloodCount.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "FeatureFloodCount.h"
11 #include "IndirectSort.h"
12 #include "MooseMesh.h"
13 #include "MooseUtils.h"
14 #include "MooseVariable.h"
15 #include "SubProblem.h"
16 
17 #include "Assembly.h"
18 #include "FEProblem.h"
19 #include "NonlinearSystem.h"
20 #include "TimedPrint.h"
21 
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"
27 
28 #include <algorithm>
29 #include <limits>
30 
31 template <>
32 void
33 dataStore(std::ostream & stream, FeatureFloodCount::FeatureData & feature, void * context)
34 {
39  storeHelper(stream, feature._ghosted_ids, context);
40  storeHelper(stream, feature._halo_ids, context);
41  storeHelper(stream, feature._disjoint_halo_ids, context);
42  storeHelper(stream, feature._periodic_nodes, 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);
47  storeHelper(stream, feature._min_entity_id, context);
48  storeHelper(stream, feature._vol_count, context);
49  storeHelper(stream, feature._centroid, context);
50  storeHelper(stream, feature._status, context);
51  storeHelper(stream, feature._boundary_intersection, context);
52 }
53 
54 template <>
55 void
56 dataStore(std::ostream & stream, BoundingBox & bbox, void * context)
57 {
58  storeHelper(stream, bbox.min(), context);
59  storeHelper(stream, bbox.max(), context);
60 }
61 
62 template <>
63 void
64 dataLoad(std::istream & stream, FeatureFloodCount::FeatureData & feature, void * context)
65 {
70  loadHelper(stream, feature._ghosted_ids, context);
71  loadHelper(stream, feature._halo_ids, context);
72  loadHelper(stream, feature._disjoint_halo_ids, context);
73  loadHelper(stream, feature._periodic_nodes, 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);
78  loadHelper(stream, feature._min_entity_id, context);
79  loadHelper(stream, feature._vol_count, context);
80  loadHelper(stream, feature._centroid, context);
81  loadHelper(stream, feature._status, context);
82  loadHelper(stream, feature._boundary_intersection, context);
83 }
84 
85 template <>
86 void
87 dataLoad(std::istream & stream, BoundingBox & bbox, void * context)
88 {
89  loadHelper(stream, bbox.min(), context);
90  loadHelper(stream, bbox.max(), context);
91 }
92 
93 // Utility routines
94 void updateBBoxExtremesHelper(BoundingBox & bbox, const Point & node);
95 void updateBBoxExtremesHelper(BoundingBox & bbox, const Elem & elem);
96 bool areElemListsMergeable(const std::list<dof_id_type> & elem_list1,
97  const std::list<dof_id_type> & elem_list2,
98  MeshBase & mesh);
99 
100 registerMooseObject("PhaseFieldApp", FeatureFloodCount);
101 
102 template <>
103 InputParameters
105 {
106  InputParameters params = validParams<GeneralPostprocessor>();
107  params += validParams<BoundaryRestrictable>();
108 
109  params.addRequiredCoupledVar(
110  "variable",
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",
118  true,
119  "Determine whether information is tracked per "
120  "coupled variable or consolidated into one "
121  "(default: true)");
122  params.addParam<bool>(
123  "condense_map_info",
124  false,
125  "Determines whether we condense all the node values when in multimap mode (default: false)");
126  params.addParam<bool>("use_global_numbering",
127  true,
128  "Determine whether or not global numbers are "
129  "used to label features on multiple maps "
130  "(default: true)");
131  params.addParam<bool>("enable_var_coloring",
132  false,
133  "Instruct the Postprocessor to populate the variable index map.");
134  params.addParam<bool>(
135  "compute_halo_maps",
136  false,
137  "Instruct the Postprocessor to communicate proper halo information to all ranks");
138  params.addParam<bool>("compute_var_to_feature_map",
139  false,
140  "Instruct the Postprocessor to compute the active vars to features map");
141  params.addParam<bool>(
142  "use_less_than_threshold_comparison",
143  true,
144  "Controls whether features are defined to be less than or greater than the threshold value.");
145 
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.");
158 
166  params.set<bool>("use_displaced_mesh") = false;
167 
168  // The FeatureFloodCount object does not require that any state (restartable information) is
169  // maintained. This Boolean is set to false so that we don't ask MOOSE to save a potentially
170  // large data structure for no reason. It is set for true in at least one derived class
171  // (GrainTracker).
172  params.addPrivateParam<bool>("restartable_required", false);
173 
174  params.addParamNamesToGroup(
175  "use_single_map condense_map_info use_global_numbering primary_percolation_boundaries",
176  "Advanced");
177 
178  MooseEnum flood_type("NODAL ELEMENTAL", "ELEMENTAL");
179  params.addParam<MooseEnum>("flood_entity_type",
180  flood_type,
181  "Determines whether the flood algorithm runs on nodes or elements");
182 
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\".");
186 
187  params.addRelationshipManager("ElementSideNeighborLayers",
188  Moose::RelationshipManagerType::GEOMETRIC |
189  Moose::RelationshipManagerType::ALGEBRAIC);
190 
191  return params;
192 }
193 
194 FeatureFloodCount::FeatureFloodCount(const InputParameters & parameters)
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),
219  _feature_count(0),
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),
225  _pbs(nullptr),
226  _element_average_value(parameters.isParamValid("elem_avg_value")
227  ? getPostprocessorValue("elem_avg_value")
228  : _real_zero),
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))
241 {
242  if (_var_index_mode)
243  _var_index_maps.resize(_maps_size);
244 
245  addMooseVariableDependency(_fe_vars);
246 
247  _is_boundary_restricted = boundaryRestricted();
248 
249  if (_subproblem.isTransient())
250  {
251  // tell MOOSE that we are going to need old and older DoF values
252  for (auto & var : _vars)
253  {
254  var->dofValuesOld();
255  var->dofValuesOlder();
256  }
257  }
258 
259  if (parameters.isParamValid("primary_percolation_boundaries"))
260  _primary_perc_bnds = _mesh.getBoundaryIDs(
261  parameters.get<std::vector<BoundaryName>>("primary_percolation_boundaries"));
262  if (parameters.isParamValid("secondary_percolation_boundaries"))
263  _secondary_perc_bnds = _mesh.getBoundaryIDs(
264  parameters.get<std::vector<BoundaryName>>("secondary_percolation_boundaries"));
265 
266  if (_primary_perc_bnds.empty() != _secondary_perc_bnds.empty())
267  paramError("primary_percolation_boundaries",
268  "primary_percolation_boundaries and secondary_percolation_boundaries must both be "
269  "supplied when checking for percolation");
270 
271  if (parameters.isParamValid("specified_boundaries"))
273  _mesh.getBoundaryIDs(parameters.get<std::vector<BoundaryName>>("specified_boundaries"));
274 }
275 
276 void
278 {
279  // We need one map per coupled variable for normal runs to support overlapping features
280  _entities_visited.resize(_vars.size());
281 
282  // Get a pointer to the PeriodicBoundaries buried in libMesh
283  _pbs = _fe_problem.getNonlinearSystemBase().dofMap().get_periodic_boundaries();
284 
285  meshChanged();
286 
295 }
296 
297 void
299 {
300  // Clear the feature marking maps and region counters and other data structures
301  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
302  {
303  _feature_maps[map_num].clear();
304  _partial_feature_sets[map_num].clear();
305 
306  if (_var_index_mode)
307  _var_index_maps[map_num].clear();
308 
309  _halo_ids[map_num].clear();
310  }
311 
312  _feature_sets.clear();
313 
314  // Calculate the thresholds for this iteration
317 
318  _ghosted_entity_ids.clear();
319 
320  // Reset the feature count and max local size
321  _feature_count = 0;
322 
323  _entity_var_to_features.clear();
324 
325  for (auto & map_ref : _entities_visited)
326  map_ref.clear();
327 }
328 
329 void
331 {
332 }
333 
334 void
336 {
337  _point_locator = _mesh.getMesh().sub_point_locator();
338 
339  _mesh.buildPeriodicNodeMap(_periodic_node_map, _var_number, _pbs);
340 
341  // Build a new node to element map
342  _nodes_to_elem_map.clear();
343  MeshTools::build_nodes_to_elem_map(_mesh.getMesh(), _nodes_to_elem_map);
344 
350  _all_boundary_entity_ids.clear();
351  if (_is_elemental)
352  for (auto elem_it = _mesh.bndElemsBegin(), elem_end = _mesh.bndElemsEnd(); elem_it != elem_end;
353  ++elem_it)
354  _all_boundary_entity_ids.insert((*elem_it)->_elem->id());
355 }
356 
357 void
359 {
360  TIME_SECTION(_execute_timer);
361  CONSOLE_TIMED_PRINT("Flooding Features");
362 
363  // Iterate only over boundaries if restricted
365  {
366  mooseInfo("Using EXPERIMENTAL boundary restricted FeatureFloodCount object!\n");
367 
368  // Set the boundary range pointer for use during flooding
369  _bnd_elem_range = _mesh.getBoundaryElementRange();
370 
371  auto rank = processor_id();
372 
373  for (const auto & belem : *_bnd_elem_range)
374  {
375  const Elem * elem = belem->_elem;
376  BoundaryID boundary_id = belem->_bnd_id;
377 
378  if (elem->processor_id() == rank)
379  {
380  if (hasBoundary(boundary_id))
381  for (MooseIndex(_vars) var_num = 0; var_num < _vars.size(); ++var_num)
382  flood(elem, var_num);
383  }
384  }
385  }
386  else // Normal volumetric operation
387  {
388  for (const auto & current_elem : _mesh.getMesh().active_local_element_ptr_range())
389  {
390  // Loop over elements or nodes
391  if (_is_elemental)
392  {
393  for (MooseIndex(_vars) var_num = 0; var_num < _vars.size(); ++var_num)
394  flood(current_elem, var_num);
395  }
396  else
397  {
398  auto n_nodes = current_elem->n_vertices();
399  for (MooseIndex(n_nodes) i = 0; i < n_nodes; ++i)
400  {
401  const Node * current_node = current_elem->node_ptr(i);
402 
403  for (MooseIndex(_vars) var_num = 0; var_num < _vars.size(); ++var_num)
404  flood(current_node, var_num);
405  }
406  }
407  }
408  }
409 }
410 
411 void
413 {
414  TIME_SECTION(_comm_and_merge);
415 
416  // First we need to transform the raw data into a usable data structure
418 
426  std::vector<std::string> send_buffers(1);
427 
434  std::vector<std::string> recv_buffers, deserialize_buffers;
435 
443  {
444  auto rank = processor_id();
445  bool is_merging_processor = rank < _n_vars;
446 
447  if (is_merging_processor)
448  recv_buffers.reserve(_app.n_processors());
449 
450  for (MooseIndex(_n_vars) i = 0; i < _n_vars; ++i)
451  {
452  serialize(send_buffers[0], i);
453 
458  _communicator.gather_packed_range(i,
459  (void *)(nullptr),
460  send_buffers.begin(),
461  send_buffers.end(),
462  std::back_inserter(recv_buffers));
463 
470  if (rank == i)
471  recv_buffers.swap(deserialize_buffers);
472  else
473  recv_buffers.clear();
474  }
475 
476  // Setup a new communicator for doing merging communication operations
477  Parallel::Communicator merge_comm;
478 
479  // TODO: Update to MPI_UNDEFINED when libMesh bug is fixed.
480  _communicator.split(is_merging_processor ? 0 : 1, rank, merge_comm);
481 
482  if (is_merging_processor)
483  {
491  std::vector<std::list<FeatureData>> tmp_data(_partial_feature_sets.size());
492  tmp_data.swap(_partial_feature_sets);
493 
494  deserialize(deserialize_buffers, processor_id());
495 
496  send_buffers[0].clear();
497  recv_buffers.clear();
498  deserialize_buffers.clear();
499 
500  // Merge one variable's worth of data
501  mergeSets();
502 
503  // Now we need to serialize again to send to the master (only the processors who did work)
504  serialize(send_buffers[0]);
505 
506  // Free up as much memory as possible here before we do global communication
508 
513  merge_comm.gather_packed_range(0,
514  (void *)(nullptr),
515  send_buffers.begin(),
516  send_buffers.end(),
517  std::back_inserter(recv_buffers));
518 
519  if (_is_master)
520  {
521  // The root process now needs to deserialize all of the data
522  deserialize(recv_buffers);
523 
524  send_buffers[0].clear();
525  recv_buffers.clear();
526 
527  consolidateMergedFeatures(&tmp_data);
528  }
529  else
530  // Restore our original data on non-zero ranks
531  tmp_data.swap(_partial_feature_sets);
532  }
533  }
534 
535  // Serialized merging (master does all the work)
536  else
537  {
538  if (_is_master)
539  recv_buffers.reserve(_app.n_processors());
540 
541  serialize(send_buffers[0]);
542 
543  // Free up as much memory as possible here before we do global communication
545 
550  _communicator.gather_packed_range(0,
551  (void *)(nullptr),
552  send_buffers.begin(),
553  send_buffers.end(),
554  std::back_inserter(recv_buffers));
555 
556  if (_is_master)
557  {
558  // The root process now needs to deserialize all of the data
559  deserialize(recv_buffers);
560  recv_buffers.clear();
561 
562  mergeSets();
563 
565  }
566  }
567 
568  // Make sure that feature count is communicated to all ranks
569  _communicator.broadcast(_feature_count);
570 }
571 
572 void
574 {
575  mooseAssert(_is_master, "sortAndLabel can only be called on the master");
576 
582  std::sort(_feature_sets.begin(), _feature_sets.end());
583 
584 #ifndef NDEBUG
585 
590  unsigned int feature_offset = 0;
591  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
592  {
593  // Skip empty map checks
594  if (_feature_counts_per_map[map_num] == 0)
595  continue;
596 
597  // Check the begin and end of the current range
598  auto range_front = feature_offset;
599  auto range_back = feature_offset + _feature_counts_per_map[map_num] - 1;
600 
601  mooseAssert(range_front <= range_back && range_back < _feature_count,
602  "Indexing error in feature sets");
603 
604  if (!_single_map_mode && (_feature_sets[range_front]._var_index != map_num ||
605  _feature_sets[range_back]._var_index != map_num))
606  mooseError("Error in _feature_sets sorting, map index: ", map_num);
607 
608  feature_offset += _feature_counts_per_map[map_num];
609  }
610 #endif
611 
612  // Label the features with an ID based on the sorting (processor number independent value)
613  for (MooseIndex(_feature_sets) i = 0; i < _feature_sets.size(); ++i)
614  if (_feature_sets[i]._id == invalid_id)
615  _feature_sets[i]._id = i;
616 }
617 
618 void
619 FeatureFloodCount::buildLocalToGlobalIndices(std::vector<std::size_t> & local_to_global_all,
620  std::vector<int> & counts) const
621 {
622  mooseAssert(_is_master, "This method must only be called on the root processor");
623 
624  counts.assign(_n_procs, 0);
625  // Now size the individual counts vectors based on the largest index seen per processor
626  for (const auto & feature : _feature_sets)
627  for (const auto & local_index_pair : feature._orig_ids)
628  {
629  // local_index_pair.first = ranks, local_index_pair.second = local_index
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;
633  }
634 
635  // Build the offsets vector
636  unsigned int globalsize = 0;
637  std::vector<int> offsets(_n_procs); // Type is signed for use with the MPI API
638  for (MooseIndex(offsets) i = 0; i < offsets.size(); ++i)
639  {
640  offsets[i] = globalsize;
641  globalsize += counts[i];
642  }
643 
644  // Finally populate the master vector
645  local_to_global_all.resize(globalsize, FeatureFloodCount::invalid_size_t);
646  for (const auto & feature : _feature_sets)
647  {
648  // Get the local indices from the feature and build a map
649  for (const auto & local_index_pair : feature._orig_ids)
650  {
651  auto rank = local_index_pair.first;
652  mooseAssert(rank < _n_procs, rank << ", " << _n_procs);
653 
654  auto local_index = local_index_pair.second;
655  auto stacked_local_index = offsets[rank] + local_index;
656 
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;
660  }
661  }
662 }
663 
664 void
666 {
667  _feature_id_to_local_index.assign(max_id + 1, invalid_size_t);
668  for (MooseIndex(_feature_sets) feature_index = 0; feature_index < _feature_sets.size();
669  ++feature_index)
670  {
671  if (_feature_sets[feature_index]._status != Status::INACTIVE)
672  {
673  mooseAssert(_feature_sets[feature_index]._id <= max_id,
674  "Feature ID out of range(" << _feature_sets[feature_index]._id << ')');
675  _feature_id_to_local_index[_feature_sets[feature_index]._id] = feature_index;
676  }
677  }
678 }
679 
680 void
682 {
683  TIME_SECTION(_finalize_timer);
684  CONSOLE_TIMED_PRINT("Finalizing Feature Identification");
685 
686  // Gather all information on processor zero and merge
688 
689  // Sort and label the features
690  if (_is_master)
691  sortAndLabel();
692 
693  // Send out the local to global mappings
695 
696  // Populate _feature_maps and _var_index_maps
697  updateFieldInfo();
698 }
699 
700 const std::vector<unsigned int> &
702 {
703  mooseDoOnce(if (!_compute_var_to_feature_map) mooseError(
704  "Please set \"compute_var_to_feature_map = true\" to use this interface method"));
705 
706  const auto pos = _entity_var_to_features.find(elem_id);
707  if (pos != _entity_var_to_features.end())
708  {
709  mooseAssert(pos->second.size() == _n_vars, "Variable to feature vector not sized properly");
710  return pos->second;
711  }
712  else
713  return _empty_var_to_features;
714 }
715 
716 void
718 {
719  // local to global map (one per processor)
720  std::vector<int> counts;
721  std::vector<std::size_t> local_to_global_all;
722  if (_is_master)
723  buildLocalToGlobalIndices(local_to_global_all, counts);
724 
725  // Scatter local_to_global indices to all processors and store in class member variable
726  _communicator.scatter(local_to_global_all, counts, _local_to_global_feature_map);
727 
728  std::size_t largest_global_index = std::numeric_limits<std::size_t>::lowest();
729  if (!_is_master)
730  {
732 
739  for (auto & list_ref : _partial_feature_sets)
740  {
741  for (auto & feature : list_ref)
742  {
743  mooseAssert(feature._orig_ids.size() == 1, "feature._orig_ids length doesn't make sense");
744 
745  auto global_index = FeatureFloodCount::invalid_size_t;
746  auto local_index = feature._orig_ids.begin()->second;
747 
748  if (local_index < _local_to_global_feature_map.size())
749  global_index = _local_to_global_feature_map[local_index];
750 
751  if (global_index != FeatureFloodCount::invalid_size_t)
752  {
753  if (global_index > largest_global_index)
754  largest_global_index = global_index;
755 
756  // Set the correct global index
757  feature._id = global_index;
758 
766  feature._status &= ~Status::INACTIVE;
767 
768  // Move the feature into the correct place
769  _feature_sets[local_index] = std::move(feature);
770  }
771  }
772  }
773  }
774  else
775  {
776  for (auto global_index : local_to_global_all)
777  if (global_index != FeatureFloodCount::invalid_size_t && global_index > largest_global_index)
778  largest_global_index = global_index;
779  }
780 
781  buildFeatureIdToLocalIndices(largest_global_index);
782 }
783 
784 Real
786 {
787  return static_cast<Real>(_feature_count);
788 }
789 
790 std::size_t
792 {
793  // Note: This value is parallel consistent, see FeatureFloodCount::communicateAndMerge()
794  return _feature_count;
795 }
796 
797 std::size_t
799 {
805  return _feature_count;
806 }
807 
808 unsigned int
809 FeatureFloodCount::getFeatureVar(unsigned int feature_id) const
810 {
811  // Some processors don't contain the largest feature id, in that case we just return invalid_id
812  if (feature_id >= _feature_id_to_local_index.size())
813  return invalid_id;
814 
815  auto local_index = _feature_id_to_local_index[feature_id];
816  if (local_index != invalid_size_t)
817  {
818  mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
819  return _feature_sets[local_index]._status != Status::INACTIVE
820  ? _feature_sets[local_index]._var_index
821  : invalid_id;
822  }
823 
824  return invalid_id;
825 }
826 
827 bool
829 {
830  // TODO: This information is not parallel consistent when using FeatureFloodCounter
831 
832  // Some processors don't contain the largest feature id, in that case we just return invalid_id
833  if (feature_id >= _feature_id_to_local_index.size())
834  return false;
835 
836  auto local_index = _feature_id_to_local_index[feature_id];
837 
838  if (local_index != invalid_size_t)
839  {
840  mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
841  return _feature_sets[local_index]._status != Status::INACTIVE
842  ? _feature_sets[local_index]._boundary_intersection != BoundaryIntersection::NONE
843  : false;
844  }
845 
846  return false;
847 }
848 
849 bool
851 {
852  // TODO: This information is not parallel consistent when using FeatureFloodCounter
853 
854  // Some processors don't contain the largest feature id, in that case we just return invalid_id
855  if (feature_id >= _feature_id_to_local_index.size())
856  return false;
857 
858  auto local_index = _feature_id_to_local_index[feature_id];
859 
860  if (local_index != invalid_size_t)
861  {
862  mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
863  return _feature_sets[local_index]._status != Status::INACTIVE
864  ? ((_feature_sets[local_index]._boundary_intersection &
867  : false;
868  }
869 
870  return false;
871 }
872 
873 bool
874 FeatureFloodCount::isFeaturePercolated(unsigned int feature_id) const
875 {
876  // TODO: This information is not parallel consistent when using FeatureFloodCounter
877 
878  // Some processors don't contain the largest feature id, in that case we just return invalid_id
879  if (feature_id >= _feature_id_to_local_index.size())
880  return false;
881 
882  auto local_index = _feature_id_to_local_index[feature_id];
883 
884  if (local_index != invalid_size_t)
885  {
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 &
893  return _feature_sets[local_index]._status != Status::INACTIVE ? (primary && secondary) : false;
894  }
895 
896  return false;
897 }
898 
899 Point
900 FeatureFloodCount::featureCentroid(unsigned int feature_id) const
901 {
902  if (feature_id >= _feature_id_to_local_index.size())
903  return invalid_id;
904 
905  auto local_index = _feature_id_to_local_index[feature_id];
906 
907  Real invalid_coord = std::numeric_limits<Real>::max();
908  Point p(invalid_coord, invalid_coord, invalid_coord);
909  if (local_index != invalid_size_t)
910  {
911  mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
912  p = _feature_sets[local_index]._centroid;
913  }
914  return p;
915 }
916 
917 Real
918 FeatureFloodCount::getEntityValue(dof_id_type entity_id,
919  FieldType field_type,
920  std::size_t var_index) const
921 {
922  auto use_default = false;
923  if (var_index == invalid_size_t)
924  {
925  use_default = true;
926  var_index = 0;
927  }
928 
929  mooseAssert(var_index < _maps_size, "Index out of range");
930 
931  switch (field_type)
932  {
934  {
935  const auto entity_it = _feature_maps[var_index].find(entity_id);
936 
937  if (entity_it != _feature_maps[var_index].end())
938  return entity_it->second; // + _region_offsets[var_index];
939  else
940  return -1;
941  }
942 
944  {
945  mooseAssert(
947  "\"enable_var_coloring\" must be set to true to pull back the VARIABLE_COLORING field");
948 
949  const auto entity_it = _var_index_maps[var_index].find(entity_id);
950 
951  if (entity_it != _var_index_maps[var_index].end())
952  return entity_it->second;
953  else
954  return -1;
955  }
956 
958  {
959  const auto entity_it = _ghosted_entity_ids.find(entity_id);
960 
961  if (entity_it != _ghosted_entity_ids.end())
962  return entity_it->second;
963  else
964  return -1;
965  }
966 
967  case FieldType::HALOS:
968  {
969  if (!use_default)
970  {
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;
974  }
975  else
976  {
977  // Showing halos in reverse order for backwards compatibility
978  for (auto map_num = _maps_size;
979  map_num-- /* don't compare greater than zero for unsigned */;)
980  {
981  const auto entity_it = _halo_ids[map_num].find(entity_id);
982 
983  if (entity_it != _halo_ids[map_num].end())
984  return entity_it->second;
985  }
986  }
987  return -1;
988  }
989 
990  case FieldType::CENTROID:
991  {
992  if (_periodic_node_map.size())
993  mooseDoOnce(mooseWarning(
994  "Centroids are not correct when using periodic boundaries, contact the MOOSE team"));
995 
996  // If this element contains the centroid of one of features, return one
997  const auto * elem_ptr = _mesh.elemPtr(entity_id);
998 
999  for (const auto & feature : _feature_sets)
1000  {
1001  if (feature._status == Status::INACTIVE)
1002  continue;
1003 
1004  if (elem_ptr->contains_point(feature._centroid))
1005  return 1;
1006  }
1007 
1008  return 0;
1009  }
1010 
1011  default:
1012  return 0;
1013  }
1014 }
1015 
1016 void
1018 {
1019  TIME_SECTION(_prepare_for_transfer);
1020 
1021  MeshBase & mesh = _mesh.getMesh();
1022 
1023  FeatureData::container_type local_ids_no_ghost, set_difference;
1024 
1025  for (auto & list_ref : _partial_feature_sets)
1026  {
1027  for (auto & feature : list_ref)
1028  {
1029  // See if the feature intersects a boundary or perhaps one of the percolation boundaries.
1030  updateBoundaryIntersections(feature);
1031 
1032  // Periodic node ids
1033  appendPeriodicNeighborNodes(feature);
1034 
1040  FeatureFloodCount::sort(feature._ghosted_ids);
1041  FeatureFloodCount::sort(feature._local_ids);
1042  FeatureFloodCount::sort(feature._halo_ids);
1043  FeatureFloodCount::sort(feature._disjoint_halo_ids);
1044  FeatureFloodCount::sort(feature._periodic_nodes);
1045 
1046  // Now extend the bounding box by the halo region
1047  if (_is_elemental)
1048  feature.updateBBoxExtremes(mesh);
1049  else
1050  {
1051  for (auto & halo_id : feature._halo_ids)
1052  updateBBoxExtremesHelper(feature._bboxes[0], mesh.point(halo_id));
1053  }
1054 
1055  mooseAssert(!feature._local_ids.empty(), "local entity ids cannot be empty");
1056 
1061  feature._min_entity_id = *feature._local_ids.begin();
1062  }
1063  }
1064 }
1065 
1066 void
1067 FeatureFloodCount::serialize(std::string & serialized_buffer, unsigned int var_num)
1068 {
1069  // stream for serializing the _partial_feature_sets data structure to a byte stream
1070  std::ostringstream oss;
1071 
1072  mooseAssert(var_num == invalid_id || var_num < _partial_feature_sets.size(),
1073  "var_num out of range");
1074 
1075  // Serialize everything
1076  if (var_num == invalid_id)
1077  dataStore(oss, _partial_feature_sets, this);
1078  else
1079  dataStore(oss, _partial_feature_sets[var_num], this);
1080 
1081  // Populate the passed in string pointer with the string stream's buffer contents
1082  serialized_buffer.assign(oss.str());
1083 }
1084 
1085 void
1086 FeatureFloodCount::deserialize(std::vector<std::string> & serialized_buffers, unsigned int var_num)
1087 {
1088  // The input string stream used for deserialization
1089  std::istringstream iss;
1090 
1091  auto rank = processor_id();
1092 
1093  for (MooseIndex(serialized_buffers) proc_id = 0; proc_id < serialized_buffers.size(); ++proc_id)
1094  {
1106  if (var_num == invalid_id && proc_id == rank)
1107  continue;
1108 
1109  iss.str(serialized_buffers[proc_id]); // populate the stream with a new buffer
1110  iss.clear(); // reset the string stream state
1111 
1112  // Load the gathered data into the data structure.
1113  if (var_num == invalid_id)
1114  dataLoad(iss, _partial_feature_sets, this);
1115  else
1116  dataLoad(iss, _partial_feature_sets[var_num], this);
1117  }
1118 }
1119 
1120 void
1122 {
1123  TIME_SECTION(_merge_timer);
1124 
1125  // When working with _distribute_merge_work all of the maps will be empty except for one
1126  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
1127  {
1128  for (auto it1 = _partial_feature_sets[map_num].begin();
1129  it1 != _partial_feature_sets[map_num].end();
1130  /* No increment on it1 */)
1131  {
1132  bool merge_occured = false;
1133  for (auto it2 = _partial_feature_sets[map_num].begin();
1134  it2 != _partial_feature_sets[map_num].end();
1135  ++it2)
1136  {
1137  if (it1 != it2 && areFeaturesMergeable(*it1, *it2))
1138  {
1139  it2->merge(std::move(*it1));
1140 
1145  _partial_feature_sets[map_num].emplace_back(std::move(*it2));
1146 
1156  _partial_feature_sets[map_num].erase(it2);
1157  it1 = _partial_feature_sets[map_num].erase(it1); // it1 is incremented here!
1158 
1159  // A merge occurred, this is used to determine whether or not we increment the outer
1160  // iterator
1161  merge_occured = true;
1162 
1163  // We need to start the list comparison over for the new it1 so break here
1164  break;
1165  }
1166  } // it2 loop
1167 
1168  if (!merge_occured) // No merges so we need to manually increment the outer iterator
1169  ++it1;
1170 
1171  } // it1 loop
1172  } // map loop
1173 }
1174 
1175 void
1176 FeatureFloodCount::consolidateMergedFeatures(std::vector<std::list<FeatureData>> * saved_data)
1177 {
1178  TIME_SECTION(_consolidate_merged_features);
1179 
1187  mooseAssert(_is_master, "cosolidateMergedFeatures() may only be called on the master processor");
1188 
1189  // Offset where the current set of features with the same variable id starts in the flat vector
1190  unsigned int feature_offset = 0;
1191  // Set the member feature count to zero and start counting the actual features
1192  _feature_count = 0;
1193 
1194  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
1195  {
1196  for (auto & feature : _partial_feature_sets[map_num])
1197  {
1198  if (saved_data)
1199  {
1200  for (auto it = (*saved_data)[map_num].begin(); it != (*saved_data)[map_num].end();
1201  /* no increment */)
1202  {
1203  if (feature.canConsolidate(*it))
1204  {
1205  feature.consolidate(std::move(*it));
1206  it = (*saved_data)[map_num].erase(it); // increment
1207  }
1208  else
1209  ++it;
1210  }
1211  }
1212 
1213  // If after merging we still have an inactive feature, discard it
1214  if (feature._status == Status::CLEAR)
1215  {
1216  // First we need to calculate the centroid now that we are doing merging all partial
1217  // features
1218  if (feature._vol_count != 0)
1219  feature._centroid /= feature._vol_count;
1220 
1221  _feature_sets.emplace_back(std::move(feature));
1222  ++_feature_count;
1223  }
1224  }
1225 
1226  // Record the feature numbers just for the current map
1227  _feature_counts_per_map[map_num] = _feature_count - feature_offset;
1228 
1229  // Now update the running feature count so we can calculate the next map's contribution
1230  feature_offset = _feature_count;
1231 
1232  // Clean up the "moved" objects
1233  _partial_feature_sets[map_num].clear();
1234  }
1235 
1240 }
1241 
1242 bool
1244 {
1245  return f1.mergeable(f2);
1246 }
1247 
1248 void
1250 {
1251  for (MooseIndex(_feature_sets) i = 0; i < _feature_sets.size(); ++i)
1252  {
1253  auto & feature = _feature_sets[i];
1254 
1255  // If the developer has requested _condense_map_info we'll make sure we only update the zeroth
1256  // map
1257  auto map_index = (_single_map_mode || _condense_map_info) ? decltype(feature._var_index)(0)
1258  : feature._var_index;
1259 
1260  // Loop over the entity ids of this feature and update our local map
1261  for (auto entity : feature._local_ids)
1262  {
1263  _feature_maps[map_index][entity] = static_cast<int>(feature._id);
1264 
1265  if (_var_index_mode)
1266  _var_index_maps[map_index][entity] = feature._var_index;
1267 
1268  // Fill in the data structure that keeps track of all features per elem
1270  {
1271  auto insert_pair = moose_try_emplace(
1272  _entity_var_to_features, entity, std::vector<unsigned int>(_n_vars, invalid_id));
1273  auto & vec_ref = insert_pair.first->second;
1274  vec_ref[feature._var_index] = feature._id;
1275  }
1276  }
1277 
1278  if (_compute_halo_maps)
1279  // Loop over the halo ids to update cells with halo information
1280  for (auto entity : feature._halo_ids)
1281  _halo_ids[map_index][entity] = static_cast<int>(feature._id);
1282 
1283  // Loop over the ghosted ids to update cells with ghost information
1284  for (auto entity : feature._ghosted_ids)
1285  _ghosted_entity_ids[entity] = 1;
1286 
1287  // TODO: Fixme
1288  if (!_global_numbering)
1289  mooseError("Local numbering currently disabled");
1290  }
1291 }
1292 
1293 bool
1294 FeatureFloodCount::flood(const DofObject * dof_object, std::size_t current_index)
1295 
1296 {
1297  // if (dof_object == nullptr || dof_object == libMesh::remote_elem)
1298  // return false;
1299  mooseAssert(dof_object, "DOF object is nullptr");
1300  mooseAssert(_entity_queue.empty(), "Entity queue is not empty when starting a feature");
1301 
1302  // Kick off the exploration of a new feature
1303  _entity_queue.push_front(dof_object);
1304 
1305  bool return_value = false;
1306  FeatureData * feature = nullptr;
1307  while (!_entity_queue.empty())
1308  {
1309  const DofObject * curr_dof_object = _entity_queue.back();
1310  const Elem * elem = _is_elemental ? static_cast<const Elem *>(curr_dof_object) : nullptr;
1311  _entity_queue.pop_back();
1312 
1313  // Retrieve the id of the current entity
1314  auto entity_id = curr_dof_object->id();
1315 
1316  // Has this entity already been marked? - if so move along
1317  if (current_index != invalid_size_t &&
1318  _entities_visited[current_index].find(entity_id) != _entities_visited[current_index].end())
1319  continue;
1320 
1321  // Are we outside of the range we should be working in?
1322  if (_is_elemental && !_dof_map.is_evaluable(*elem))
1323  continue;
1324 
1325  // See if the current entity either starts a new feature or continues an existing feature
1326  auto new_id = invalid_id; // Writable reference to hold an optional id;
1327  Status status =
1328  Status::INACTIVE; // Status is inactive until we find an entity above the starting threshold
1329 
1330  // Make sure that the Assembly object has the right element and subdomain information set
1331  // since we are moving through the mesh in a manual fashion.
1332  if (_is_elemental)
1333  _fe_problem.setCurrentSubdomainID(elem, 0);
1334 
1335  if (!isNewFeatureOrConnectedRegion(curr_dof_object, current_index, feature, status, new_id))
1336  {
1337  // If we have an active feature, we just found a halo entity
1338  if (feature)
1339  feature->_halo_ids.insert(feature->_halo_ids.end(), entity_id);
1340  continue;
1341  }
1342 
1343  mooseAssert(current_index != invalid_size_t, "current_index is invalid");
1344 
1353  return_value = true;
1354  _entities_visited[current_index].insert(entity_id);
1355 
1356  auto map_num = _single_map_mode ? decltype(current_index)(0) : current_index;
1357 
1358  // New Feature (we need to create it and add it to our data structure)
1359  if (!feature)
1360  {
1361  _partial_feature_sets[map_num].emplace_back(
1362  current_index, _feature_count++, processor_id(), status);
1363 
1364  // Get a handle to the feature we will update (always the last feature in the data structure)
1365  feature = &_partial_feature_sets[map_num].back();
1366 
1367  // If new_id is valid, we'll set it in the feature here.
1368  if (new_id != invalid_id)
1369  feature->_id = new_id;
1370  }
1371 
1372  // Insert the current entity into the local ids data structure
1373  feature->_local_ids.insert(feature->_local_ids.end(), entity_id);
1374 
1380  if (_is_elemental && processor_id() == curr_dof_object->processor_id())
1381  {
1382  // Keep track of how many elements participate in the centroid averaging
1383  feature->_vol_count++;
1384 
1385  // Sum the centroid values for now, we'll average them later
1386  feature->_centroid += elem->centroid();
1387 
1388  // // Does the volume intersect the boundary?
1389  // if (_all_boundary_entity_ids.find(elem->id()) != _all_boundary_entity_ids.end())
1390  // feature->_intersects_boundary = true;
1391  }
1392 
1393  if (_is_elemental)
1395  feature,
1396  /*expand_halos_only =*/false,
1397  /*disjoint_only =*/false);
1398  else
1399  visitNodalNeighbors(static_cast<const Node *>(curr_dof_object),
1400  feature,
1401  /*expand_halos_only =*/false);
1402  }
1403 
1404  return return_value;
1405 }
1406 
1407 Real FeatureFloodCount::getThreshold(std::size_t /*current_index*/) const
1408 {
1409  return _step_threshold;
1410 }
1411 
1412 Real FeatureFloodCount::getConnectingThreshold(std::size_t /*current_index*/) const
1413 {
1415 }
1416 
1417 bool
1418 FeatureFloodCount::compareValueWithThreshold(Real entity_value, Real threshold) const
1419 {
1420  return ((_use_less_than_threshold_comparison && (entity_value >= threshold)) ||
1421  (!_use_less_than_threshold_comparison && (entity_value <= threshold)));
1422 }
1423 
1424 bool
1426  std::size_t & current_index,
1427  FeatureData *& feature,
1428  Status & status,
1429  unsigned int & /*new_id*/)
1430 {
1431  // Get the value of the current variable for the current entity
1432  Real entity_value;
1433  if (_is_elemental)
1434  {
1435  const Elem * elem = static_cast<const Elem *>(dof_object);
1436  std::vector<Point> centroid(1, elem->centroid());
1437  _subproblem.reinitElemPhys(elem, centroid, 0, /* suppress_displaced_init = */ true);
1438  entity_value = _vars[current_index]->sln()[0];
1439  }
1440  else
1441  entity_value = _vars[current_index]->getNodalValue(*static_cast<const Node *>(dof_object));
1442 
1443  // If the value compares against our starting threshold, this is definitely part of a feature
1444  // we'll keep
1445  if (compareValueWithThreshold(entity_value, getThreshold(current_index)))
1446  {
1447  Status * status_ptr = &status;
1448 
1449  if (feature)
1450  status_ptr = &feature->_status;
1451 
1452  // Update an existing feature's status or clear the flag on the passed in status
1453  *status_ptr &= ~Status::INACTIVE;
1454  return true;
1455  }
1456 
1461  return compareValueWithThreshold(entity_value, getConnectingThreshold(current_index));
1462 }
1463 
1464 void
1466 {
1467  const auto & node_to_elem_map = _mesh.nodeToActiveSemilocalElemMap();
1468  FeatureData::container_type expanded_local_ids;
1469  auto my_processor_id = processor_id();
1470 
1477  for (auto & list_ref : _partial_feature_sets)
1478  {
1479  for (auto & feature : list_ref)
1480  {
1481  expanded_local_ids.clear();
1482 
1483  for (auto entity : feature._local_ids)
1484  {
1485  const Elem * elem = _mesh.elemPtr(entity);
1486  mooseAssert(elem, "elem pointer is NULL");
1487 
1488  // Get the nodes on a current element so that we can add in point neighbors
1489  auto n_nodes = elem->n_vertices();
1490  for (MooseIndex(n_nodes) i = 0; i < n_nodes; ++i)
1491  {
1492  const Node * current_node = elem->node_ptr(i);
1493 
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");
1497 
1498  const auto & elem_vector = elem_vector_it->second;
1499 
1500  std::copy(elem_vector.begin(),
1501  elem_vector.end(),
1502  std::insert_iterator<FeatureData::container_type>(expanded_local_ids,
1503  expanded_local_ids.end()));
1504 
1505  // Now see which elements need to go into the ghosted set
1506  for (auto entity : elem_vector)
1507  {
1508  const Elem * neighbor = _mesh.elemPtr(entity);
1509  mooseAssert(neighbor, "neighbor pointer is NULL");
1510 
1511  if (neighbor->processor_id() != my_processor_id)
1512  feature._ghosted_ids.insert(feature._ghosted_ids.end(), elem->id());
1513  }
1514  }
1515  }
1516 
1517  // Replace the existing local ids with the expanded local ids
1518  feature._local_ids.swap(expanded_local_ids);
1519 
1520  // Copy the expanded local_ids into the halo_ids container
1521  feature._halo_ids = feature._local_ids;
1522  }
1523  }
1524 }
1525 
1526 void
1527 FeatureFloodCount::expandEdgeHalos(unsigned int num_layers_to_expand)
1528 {
1529  if (num_layers_to_expand == 0)
1530  return;
1531 
1532  TIME_SECTION(_expand_halos);
1533 
1534  for (auto & list_ref : _partial_feature_sets)
1535  {
1536  for (auto & feature : list_ref)
1537  {
1538  for (MooseIndex(num_layers_to_expand) halo_level = 0; halo_level < num_layers_to_expand;
1539  ++halo_level)
1540  {
1545  FeatureData::container_type orig_halo_ids(feature._halo_ids);
1546  for (auto entity : orig_halo_ids)
1547  {
1548  if (_is_elemental)
1549  visitElementalNeighbors(_mesh.elemPtr(entity),
1550  &feature,
1551  /*expand_halos_only =*/true,
1552  /*disjoint_only =*/false);
1553  else
1554  visitNodalNeighbors(_mesh.nodePtr(entity),
1555  &feature,
1556  /*expand_halos_only =*/true);
1557  }
1558 
1563  FeatureData::container_type disjoint_orig_halo_ids(feature._disjoint_halo_ids);
1564  for (auto entity : disjoint_orig_halo_ids)
1565  {
1566  if (_is_elemental)
1567  visitElementalNeighbors(_mesh.elemPtr(entity),
1568 
1569  &feature,
1570  /*expand_halos_only =*/true,
1571  /*disjoint_only =*/true);
1572  else
1573  visitNodalNeighbors(_mesh.nodePtr(entity),
1574 
1575  &feature,
1576  /*expand_halos_only =*/true);
1577  }
1578  }
1579  }
1580  }
1581 }
1582 
1583 void
1585  FeatureData * feature,
1586  bool expand_halos_only,
1587  bool disjoint_only)
1588 {
1589  mooseAssert(elem, "Elem is NULL");
1590 
1591  std::vector<const Elem *> all_active_neighbors;
1592  MeshBase & mesh = _mesh.getMesh();
1593 
1594  // Loop over all neighbors (at the the same level as the current element)
1595  for (MooseIndex(elem->n_neighbors()) i = 0; i < elem->n_neighbors(); ++i)
1596  {
1597  const Elem * neighbor_ancestor = nullptr;
1598  bool topological_neighbor = false;
1599 
1604  neighbor_ancestor = elem->neighbor_ptr(i);
1605  if (neighbor_ancestor)
1606  {
1607  if (neighbor_ancestor == libMesh::remote_elem)
1608  continue;
1609 
1610  neighbor_ancestor->active_family_tree_by_neighbor(all_active_neighbors, elem, false);
1611  }
1612  else
1613  {
1614  neighbor_ancestor = elem->topological_neighbor(i, mesh, *_point_locator, _pbs);
1615 
1623  if (neighbor_ancestor)
1624  {
1625  neighbor_ancestor->active_family_tree_by_topological_neighbor(
1626  all_active_neighbors, elem, mesh, *_point_locator, _pbs, false);
1627 
1628  topological_neighbor = true;
1629  }
1630  else
1631  {
1637  updateBBoxExtremesHelper(feature->_bboxes[0], *elem);
1638  }
1639  }
1640 
1641  visitNeighborsHelper(elem,
1642  all_active_neighbors,
1643  feature,
1644  expand_halos_only,
1645  topological_neighbor,
1646  disjoint_only);
1647 
1648  all_active_neighbors.clear();
1649  }
1650 }
1651 
1652 void
1654  FeatureData * feature,
1655  bool expand_halos_only)
1656 {
1657  mooseAssert(node, "Node is NULL");
1658 
1659  std::vector<const Node *> all_active_neighbors;
1660  MeshTools::find_nodal_neighbors(_mesh.getMesh(), *node, _nodes_to_elem_map, all_active_neighbors);
1661 
1662  visitNeighborsHelper(node, all_active_neighbors, feature, expand_halos_only, false, false);
1663 }
1664 
1665 template <typename T>
1666 void
1668  std::vector<const T *> neighbor_entities,
1669  FeatureData * feature,
1670  bool expand_halos_only,
1671  bool topological_neighbor,
1672  bool disjoint_only)
1673 {
1674  // Loop over all active element neighbors
1675  for (const auto neighbor : neighbor_entities)
1676  {
1677  if (neighbor && (!_is_boundary_restricted || isBoundaryEntity(neighbor)))
1678  {
1679  if (expand_halos_only)
1680  {
1681  auto entity_id = neighbor->id();
1682 
1683  if (topological_neighbor || disjoint_only)
1684  feature->_disjoint_halo_ids.insert(feature->_disjoint_halo_ids.end(), entity_id);
1685  else if (feature->_local_ids.find(entity_id) == feature->_local_ids.end())
1686  feature->_halo_ids.insert(feature->_halo_ids.end(), entity_id);
1687  }
1688  else
1689  {
1690  auto my_processor_id = processor_id();
1691 
1692  if (!topological_neighbor && neighbor->processor_id() != my_processor_id)
1693  feature->_ghosted_ids.insert(feature->_ghosted_ids.end(), curr_entity->id());
1694 
1704  if (curr_entity->processor_id() == my_processor_id ||
1705  neighbor->processor_id() == my_processor_id)
1706  {
1713  if (topological_neighbor || disjoint_only)
1714  feature->_disjoint_halo_ids.insert(feature->_disjoint_halo_ids.end(), neighbor->id());
1715  else
1716  _entity_queue.push_front(neighbor);
1717  }
1718  }
1719  }
1720  }
1721 }
1722 
1723 void
1725 {
1726  if (_is_elemental)
1727  {
1728  for (auto entity : feature._local_ids)
1729  {
1730  // See if this feature is on a boundary if we haven't already figured that out
1733  {
1734  Elem * elem = _mesh.elemPtr(entity);
1735  if (elem && elem->on_boundary())
1737  }
1738 
1739  // Now see if the feature touches the primary and/or secondary boundary IDs if we haven't
1740  // figured that out already
1743  {
1744  for (auto primary_id : _primary_perc_bnds)
1745  if (_mesh.isBoundaryElem(entity, primary_id))
1747  }
1748 
1751  {
1752  for (auto secondary_id : _secondary_perc_bnds)
1753  if (_mesh.isBoundaryElem(entity, secondary_id))
1755  }
1756 
1757  // See if the feature contacts any of the user-specified boundaries if we haven't
1758  // done so already
1761  {
1762  for (auto specified_id : _specified_bnds)
1763  if (_mesh.isBoundaryElem(entity, specified_id))
1765  }
1766  }
1767  }
1768 }
1769 
1770 void
1772 {
1773  if (_is_elemental)
1774  {
1775  for (auto entity : feature._local_ids)
1776  {
1777  Elem * elem = _mesh.elemPtr(entity);
1778 
1779  for (MooseIndex(elem->n_nodes()) node_n = 0; node_n < elem->n_nodes(); ++node_n)
1780  {
1781  auto iters = _periodic_node_map.equal_range(elem->node_id(node_n));
1782 
1783  for (auto it = iters.first; it != iters.second; ++it)
1784  {
1785  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->first);
1786  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->second);
1787  }
1788  }
1789  }
1790  }
1791  else
1792  {
1793  for (auto entity : feature._local_ids)
1794  {
1795  auto iters = _periodic_node_map.equal_range(entity);
1796 
1797  for (auto it = iters.first; it != iters.second; ++it)
1798  {
1799  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->first);
1800  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->second);
1801  }
1802  }
1803  }
1804 
1805  // TODO: Remove duplicates
1806 }
1807 
1808 template <typename T>
1809 bool
1811 {
1812  mooseAssert(_bnd_elem_range, "Boundary Element Range is nullptr");
1813 
1814  if (entity)
1815  for (const auto & belem : *_bnd_elem_range)
1816  // Only works for Elements
1817  if (belem->_elem->id() == entity->id() && hasBoundary(belem->_bnd_id))
1818  return true;
1819 
1820  return false;
1821 }
1822 
1823 void
1825 {
1826  // First update the primary bounding box (all topologically connected)
1827  for (auto & halo_id : _halo_ids)
1828  updateBBoxExtremesHelper(_bboxes[0], mesh.elem_ref(halo_id));
1829  for (auto & ghost_id : _ghosted_ids)
1830  updateBBoxExtremesHelper(_bboxes[0], mesh.elem_ref(ghost_id));
1831 
1832  // Remove all of the IDs that are in the primary region
1833  std::list<dof_id_type> disjoint_elem_id_list;
1834  std::set_difference(_disjoint_halo_ids.begin(),
1835  _disjoint_halo_ids.end(),
1836  _halo_ids.begin(),
1837  _halo_ids.end(),
1838  std::insert_iterator<std::list<dof_id_type>>(disjoint_elem_id_list,
1839  disjoint_elem_id_list.begin()));
1840 
1841  if (!disjoint_elem_id_list.empty())
1842  {
1851  std::list<std::list<dof_id_type>> disjoint_regions;
1852  for (auto elem_id : _disjoint_halo_ids)
1853  {
1854  disjoint_regions.emplace_back(std::list<dof_id_type>({elem_id}));
1855  }
1856 
1857  for (auto it1 = disjoint_regions.begin(); it1 != disjoint_regions.end(); /* No increment */)
1858  {
1859  bool merge_occured = false;
1860  for (auto it2 = disjoint_regions.begin(); it2 != disjoint_regions.end(); ++it2)
1861  {
1862  if (it1 != it2 && areElemListsMergeable(*it1, *it2, mesh))
1863  {
1864  it2->splice(it2->begin(), *it1);
1865 
1866  disjoint_regions.emplace_back(std::move(*it2));
1867  disjoint_regions.erase(it2);
1868  it1 = disjoint_regions.erase(it1);
1869 
1870  merge_occured = true;
1871 
1872  break;
1873  }
1874  }
1875 
1876  if (!merge_occured)
1877  ++it1;
1878  }
1879 
1880  // Finally create new bounding boxes for each disjoint region
1881  auto num_regions = disjoint_regions.size();
1882  // We have num_regions *new* bounding boxes plus the existing bounding box
1883  _bboxes.resize(num_regions + 1);
1884 
1885  decltype(num_regions) region = 1;
1886  for (const auto list_ref : disjoint_regions)
1887  {
1888  for (const auto elem_id : list_ref)
1889  updateBBoxExtremesHelper(_bboxes[region], *mesh.elem_ptr(elem_id));
1890 
1891  FeatureData::container_type set_union;
1892  FeatureFloodCount::reserve(set_union, _halo_ids.size() + _disjoint_halo_ids.size());
1893  std::set_union(
1894  _halo_ids.begin(),
1895  _halo_ids.end(),
1896  _disjoint_halo_ids.begin(),
1897  _disjoint_halo_ids.end(),
1898  std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
1899  _halo_ids.swap(set_union);
1900 
1901  _disjoint_halo_ids.clear();
1902  ++region;
1903  }
1904  }
1905 }
1906 
1907 void
1908 FeatureFloodCount::FeatureData::updateBBoxExtremes(BoundingBox & bbox, const BoundingBox & rhs_bbox)
1909 {
1910  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1911  {
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));
1914  }
1915 }
1916 
1917 bool
1919 {
1920  // See if any of the bounding boxes in either FeatureData object intersect
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))
1924  return true;
1925 
1926  return false;
1927 }
1928 
1929 bool
1931 {
1932  return setsIntersect(
1933  _halo_ids.begin(), _halo_ids.end(), rhs._halo_ids.begin(), rhs._halo_ids.end());
1934 }
1935 
1936 bool
1938 {
1939  return setsIntersect(_periodic_nodes.begin(),
1940  _periodic_nodes.end(),
1941  rhs._periodic_nodes.begin(),
1942  rhs._periodic_nodes.end());
1943 }
1944 
1945 bool
1947 {
1948  return setsIntersect(
1949  _ghosted_ids.begin(), _ghosted_ids.end(), rhs._ghosted_ids.begin(), rhs._ghosted_ids.end());
1950 }
1951 
1952 bool
1954 {
1955  return (_var_index == rhs._var_index && // the sets have matching variable indices and
1956  ((boundingBoxesIntersect(rhs) && // (if the feature's bboxes intersect and
1957  ghostedIntersect(rhs)) // the ghosted entities also intersect)
1958  || // or
1959  periodicBoundariesIntersect(rhs))); // periodic node sets intersect)
1960 }
1961 
1962 bool
1964 {
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)
1968  return true;
1969 
1970  return false;
1971 }
1972 
1973 void
1975 {
1976  mooseAssert(_var_index == rhs._var_index, "Mismatched variable index in merge");
1977  mooseAssert(_id == rhs._id, "Mismatched auxiliary id in merge");
1978 
1979  FeatureData::container_type set_union;
1980 
1981  FeatureFloodCount::reserve(set_union, _local_ids.size() + rhs._local_ids.size());
1982  std::set_union(_local_ids.begin(),
1983  _local_ids.end(),
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);
1988 
1989  set_union.clear();
1990  FeatureFloodCount::reserve(set_union, _periodic_nodes.size() + rhs._periodic_nodes.size());
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);
1997 
1998  set_union.clear();
1999  FeatureFloodCount::reserve(set_union, _ghosted_ids.size() + rhs._ghosted_ids.size());
2000  std::set_union(_ghosted_ids.begin(),
2001  _ghosted_ids.end(),
2002  rhs._ghosted_ids.begin(),
2003  rhs._ghosted_ids.end(),
2004  std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2005 
2013  bool physical_intersection = (_ghosted_ids.size() + rhs._ghosted_ids.size() > set_union.size());
2014  _ghosted_ids.swap(set_union);
2015 
2020  if (physical_intersection)
2021  expandBBox(rhs);
2022  else
2023  std::move(rhs._bboxes.begin(), rhs._bboxes.end(), std::back_inserter(_bboxes));
2024 
2025  set_union.clear();
2026  FeatureFloodCount::reserve(set_union, _disjoint_halo_ids.size() + rhs._disjoint_halo_ids.size());
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);
2033 
2034  set_union.clear();
2035  FeatureFloodCount::reserve(set_union, _halo_ids.size() + rhs._halo_ids.size());
2036  std::set_union(_halo_ids.begin(),
2037  _halo_ids.end(),
2038  rhs._halo_ids.begin(),
2039  rhs._halo_ids.end(),
2040  std::insert_iterator<FeatureData::container_type>(set_union, set_union.begin()));
2041  _halo_ids.swap(set_union);
2042 
2043  // Keep track of the original ids so we can notify other processors of the local to global mapping
2044  _orig_ids.splice(_orig_ids.end(), std::move(rhs._orig_ids));
2045 
2046  // Update the min feature id
2047  _min_entity_id = std::min(_min_entity_id, rhs._min_entity_id);
2048 
2054  mooseAssert((_status & Status::MARKED & Status::DIRTY) == Status::CLEAR,
2055  "Flags in invalid state");
2056 
2057  // Logical AND here to combine flags (INACTIVE & INACTIVE == INACTIVE, all other combos are CLEAR)
2058  _status &= rhs._status;
2059 
2060  // Logical OR here to make sure we maintain boundary intersection attribute when joining
2061  _boundary_intersection |= rhs._boundary_intersection;
2062 
2063  _vol_count += rhs._vol_count;
2064  _centroid += rhs._centroid;
2065 }
2066 
2067 void
2069 {
2070  mooseAssert(_var_index == rhs._var_index, "Mismatched variable index in merge");
2071  mooseAssert(_id == rhs._id, "Mismatched auxiliary id in merge");
2072 
2073  FeatureData::container_type set_union;
2074  FeatureFloodCount::reserve(_local_ids, _local_ids.size() + rhs._local_ids.size());
2075  std::set_union(_local_ids.begin(),
2076  _local_ids.end(),
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);
2081 
2082  mooseAssert((_status & Status::MARKED & Status::DIRTY) == Status::CLEAR,
2083  "Flags in invalid state");
2084 }
2085 
2086 void
2088 {
2089  _local_ids.clear();
2090  _periodic_nodes.clear();
2091  _halo_ids.clear();
2092  _disjoint_halo_ids.clear();
2093  _ghosted_ids.clear();
2094  _bboxes.clear();
2095  _orig_ids.clear();
2096 }
2097 
2098 void
2100 {
2101  std::vector<bool> intersected_boxes(rhs._bboxes.size(), false);
2102 
2103  auto box_expanded = false;
2104  for (auto & bbox : _bboxes)
2105  for (MooseIndex(rhs._bboxes) j = 0; j < rhs._bboxes.size(); ++j)
2106  {
2107  if (bbox.intersects(rhs._bboxes[j], libMesh::TOLERANCE * libMesh::TOLERANCE))
2108  {
2109  updateBBoxExtremes(bbox, rhs._bboxes[j]);
2110  intersected_boxes[j] = true;
2111  box_expanded = true;
2112  }
2113  }
2114 
2115  // Error check
2116  if (!box_expanded)
2117  {
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';
2122 
2123  oss << "RHS BBoxes:\n";
2124  for (MooseIndex(rhs._bboxes) i = 0; i < rhs._bboxes.size(); ++i)
2125  oss << "Max: " << rhs._bboxes[i].max() << " Min: " << rhs._bboxes[i].min() << '\n';
2126 
2127  ::mooseError("No Bounding Boxes Expanded - This is a catastrophic error!\n", oss.str());
2128  }
2129 
2130  // Any bounding box in the rhs vector that doesn't intersect
2131  // needs to be appended to the lhs vector
2132  for (MooseIndex(intersected_boxes) j = 0; j < intersected_boxes.size(); ++j)
2133  if (!intersected_boxes[j])
2134  _bboxes.push_back(rhs._bboxes[j]);
2135 }
2136 
2137 std::ostream &
2138 operator<<(std::ostream & out, const FeatureFloodCount::FeatureData & feature)
2139 {
2140  static const bool debug = true;
2141 
2142  out << "Grain ID: ";
2143  if (feature._id != FeatureFloodCount::invalid_id)
2144  out << feature._id;
2145  else
2146  out << "invalid";
2147 
2148  if (debug)
2149  {
2150  out << "\nGhosted Entities: ";
2151  for (auto ghosted_id : feature._ghosted_ids)
2152  out << ghosted_id << " ";
2153 
2154  out << "\nLocal Entities: ";
2155  for (auto local_id : feature._local_ids)
2156  out << local_id << " ";
2157 
2158  out << "\nHalo Entities: ";
2159  for (auto halo_id : feature._halo_ids)
2160  out << halo_id << " ";
2161 
2162  out << "\nPeriodic Node IDs: ";
2163  for (auto periodic_node : feature._periodic_nodes)
2164  out << periodic_node << " ";
2165  }
2166 
2167  out << "\nBBoxes:";
2168  Real volume = 0;
2169  for (const auto & bbox : feature._bboxes)
2170  {
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))
2174  ? 1
2175  : bbox.max()(2) - bbox.min()(2));
2176  }
2177 
2178  out << "\nStatus: ";
2180  out << "CLEAR";
2181  if (static_cast<bool>(feature._status & FeatureFloodCount::Status::MARKED))
2182  out << " MARKED";
2183  if (static_cast<bool>(feature._status & FeatureFloodCount::Status::DIRTY))
2184  out << " DIRTY";
2185  if (static_cast<bool>(feature._status & FeatureFloodCount::Status::INACTIVE))
2186  out << " INACTIVE";
2187 
2188  if (debug)
2189  {
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;
2194  out << "\nMin Entity ID: " << feature._min_entity_id;
2195  }
2196  out << "\n\n";
2197 
2198  return out;
2199 }
2200 
2201 /*****************************************************************************************
2202  ******************************* Utility Routines ****************************************
2203  *****************************************************************************************
2204  */
2205 void
2206 updateBBoxExtremesHelper(BoundingBox & bbox, const Point & node)
2207 {
2208  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
2209  {
2210  bbox.min()(i) = std::min(bbox.min()(i), node(i));
2211  bbox.max()(i) = std::max(bbox.max()(i), node(i));
2212  }
2213 }
2214 
2215 void
2216 updateBBoxExtremesHelper(BoundingBox & bbox, const Elem & elem)
2217 {
2218  for (MooseIndex(elem.n_nodes()) node_n = 0; node_n < elem.n_nodes(); ++node_n)
2219  updateBBoxExtremesHelper(bbox, *(elem.node_ptr(node_n)));
2220 }
2221 
2222 bool
2223 areElemListsMergeable(const std::list<dof_id_type> & elem_list1,
2224  const std::list<dof_id_type> & elem_list2,
2225  MeshBase & mesh)
2226 {
2227  for (const auto elem_id1 : elem_list1)
2228  {
2229  const auto * elem1 = mesh.elem_ptr(elem_id1);
2230  for (const auto elem_id2 : elem_list2)
2231  {
2232  const auto * elem2 = mesh.elem_ptr(elem_id2);
2233  if (elem1->has_neighbor(elem2))
2234  return true;
2235  }
2236  }
2237  return false;
2238 }
2239 
2240 // Constants
2241 const std::size_t FeatureFloodCount::invalid_size_t = std::numeric_limits<std::size_t>::max();
2242 const unsigned int FeatureFloodCount::invalid_id = std::numeric_limits<unsigned int>::max();
FeatureFloodCount::FeatureData::consolidate
void consolidate(FeatureData &&rhs)
Consolidates features, i.e.
Definition: FeatureFloodCount.C:2068
FeatureFloodCount::expandEdgeHalos
void expandEdgeHalos(unsigned int num_layers_to_expand)
This method expands the existing halo set by some width determined by the passed in value.
Definition: FeatureFloodCount.C:1527
FeatureFloodCount::_var_index_mode
const bool _var_index_mode
This variable is used to indicate whether the maps will contain unique region information or just the...
Definition: FeatureFloodCount.h:601
FeatureFloodCount::_condense_map_info
const bool _condense_map_info
Definition: FeatureFloodCount.h:593
FeatureFloodCount::_secondary_perc_bnds
std::vector< BoundaryID > _secondary_perc_bnds
Definition: FeatureFloodCount.h:718
FeatureFloodCount::FieldType::UNIQUE_REGION
FeatureFloodCount::invalid_size_t
static const std::size_t invalid_size_t
Definition: FeatureFloodCount.h:93
FeatureFloodCount::scatterAndUpdateRanks
void scatterAndUpdateRanks()
Calls buildLocalToGlobalIndices to build the individual local to global indicies for each rank and sc...
Definition: FeatureFloodCount.C:717
FeatureFloodCount::_mesh
MooseMesh & _mesh
A reference to the mesh.
Definition: FeatureFloodCount.h:581
FeatureFloodCount::FeatureData::_id
unsigned int _id
An ID for this feature.
Definition: FeatureFloodCount.h:287
FeatureFloodCount::prepareDataForTransfer
void prepareDataForTransfer()
This routine uses the local flooded data to build up the local feature data structures (_feature_sets...
Definition: FeatureFloodCount.C:1017
FeatureFloodCount::getEntityValue
virtual Real getEntityValue(dof_id_type entity_id, FieldType field_type, std::size_t var_index=0) const
Definition: FeatureFloodCount.C:918
FeatureFloodCount::FeatureFloodCount
FeatureFloodCount(const InputParameters &parameters)
Definition: FeatureFloodCount.C:194
FeatureFloodCount::doesFeatureIntersectBoundary
virtual bool doesFeatureIntersectBoundary(unsigned int feature_id) const
Returns a Boolean indicating whether this feature intersects any boundary.
Definition: FeatureFloodCount.C:828
FeatureFloodCount::BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY
FeatureFloodCount::getVarToFeatureVector
virtual const std::vector< unsigned int > & getVarToFeatureVector(dof_id_type elem_id) const
Returns a list of active unique feature ids for a particular element.
Definition: FeatureFloodCount.C:701
registerMooseObject
registerMooseObject("PhaseFieldApp", FeatureFloodCount)
FeatureFloodCount::FeatureData::_disjoint_halo_ids
container_type _disjoint_halo_ids
Holds halo ids that extend onto a non-topologically connected surface.
Definition: FeatureFloodCount.h:278
FeatureFloodCount::_merge_timer
const PerfID _merge_timer
Definition: FeatureFloodCount.h:773
FeatureFloodCount::FeatureData::clear
void clear()
Definition: FeatureFloodCount.C:2087
FeatureFloodCount::FeatureData::container_type
std::set< dof_id_type > container_type
The primary underlying container type used to hold the data in each FeatureData.
Definition: FeatureFloodCount.h:149
FeatureFloodCount::featureCentroid
virtual Point featureCentroid(unsigned int feature_id) const
Returns the centroid of the designated feature (only supported without periodic boundaries)
Definition: FeatureFloodCount.C:900
FeatureFloodCount::FeatureData::mergeable
bool mergeable(const FeatureData &rhs) const
The routine called to see if two features are mergeable:
Definition: FeatureFloodCount.C:1953
FeatureFloodCount::FieldType::CENTROID
FeatureFloodCount::_comm_and_merge
const PerfID _comm_and_merge
Definition: FeatureFloodCount.h:775
FeatureFloodCount::Status
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure.
Definition: FeatureFloodCount.h:120
FeatureFloodCount::communicateAndMerge
void communicateAndMerge()
This routine handles all of the serialization, communication and deserialization of the data structur...
Definition: FeatureFloodCount.C:412
FeatureFloodCount::_entities_visited
std::vector< std::set< dof_id_type > > _entities_visited
This variable keeps track of which nodes have been visited during execution.
Definition: FeatureFloodCount.h:631
FeatureFloodCount::_execute_timer
const PerfID _execute_timer
Timers.
Definition: FeatureFloodCount.h:772
FeatureFloodCount::getThreshold
virtual Real getThreshold(std::size_t current_index) const
Return the starting comparison threshold to use when inspecting an entity during the flood stage.
Definition: FeatureFloodCount.C:1407
FeatureFloodCount::FieldType
FieldType
Definition: FeatureFloodCount.h:103
FeatureFloodCount::FeatureData::periodicBoundariesIntersect
bool periodicBoundariesIntersect(const FeatureData &rhs) const
Definition: FeatureFloodCount.C:1937
FeatureFloodCount::areFeaturesMergeable
virtual bool areFeaturesMergeable(const FeatureData &f1, const FeatureData &f2) const
Method for determining whether two features are mergeable.
Definition: FeatureFloodCount.C:1243
FeatureFloodCount::isBoundaryEntity
bool isBoundaryEntity(const T *entity) const
Returns a Boolean indicating whether the entity is on one of the desired boundaries.
Definition: FeatureFloodCount.C:1810
FeatureFloodCount::FieldType::GHOSTED_ENTITIES
FeatureFloodCount::visitNodalNeighbors
void visitNodalNeighbors(const Node *node, FeatureData *feature, bool expand_halos_only)
These two routines are utility routines used by the flood routine and by derived classes for visiting...
Definition: FeatureFloodCount.C:1653
FeatureFloodCount::FeatureData::_boundary_intersection
BoundaryIntersection _boundary_intersection
Enumaration indicating boundary intersection status.
Definition: FeatureFloodCount.h:310
FeatureFloodCount::_is_master
const bool _is_master
Convenience variable for testing master rank.
Definition: FeatureFloodCount.h:732
FeatureFloodCount::_finalize_timer
const PerfID _finalize_timer
Definition: FeatureFloodCount.h:774
FeatureFloodCount::isFeaturePercolated
virtual bool isFeaturePercolated(unsigned int feature_id) const
Returns a Boolean indicating whether this feature is percolated (e.g.
Definition: FeatureFloodCount.C:874
FeatureFloodCount::buildLocalToGlobalIndices
virtual void buildLocalToGlobalIndices(std::vector< std::size_t > &local_to_global_all, std::vector< int > &counts) const
This routine populates a stacked vector of local to global indices per rank and the associated count ...
Definition: FeatureFloodCount.C:619
FeatureFloodCount::_specified_bnds
std::vector< BoundaryID > _specified_bnds
Definition: FeatureFloodCount.h:720
FeatureFloodCount
This object will mark nodes or elements of continuous regions all with a unique number for the purpos...
Definition: FeatureFloodCount.h:44
FeatureFloodCount::FeatureData::_min_entity_id
dof_id_type _min_entity_id
The minimum entity seen in the _local_ids, used for sorting features.
Definition: FeatureFloodCount.h:297
FeatureFloodCount::getTotalFeatureCount
virtual std::size_t getTotalFeatureCount() const
Returns the total feature count (active and inactive ids, useful for sizing vectors)
Definition: FeatureFloodCount.C:798
FeatureFloodCount::expandPointHalos
void expandPointHalos()
This method takes all of the partial features and expands the local, ghosted, and halo sets around th...
Definition: FeatureFloodCount.C:1465
FeatureFloodCount::initialize
virtual void initialize() override
Definition: FeatureFloodCount.C:298
FeatureFloodCount::Status::CLEAR
FeatureFloodCount::BoundaryIntersection::SPECIFIED_BOUNDARY
FeatureFloodCount::sortAndLabel
void sortAndLabel()
Sort and assign ids to features based on their position in the container after sorting.
Definition: FeatureFloodCount.C:573
FeatureFloodCount::FeatureData::expandBBox
void expandBBox(const FeatureData &rhs)
Located the overlapping bounding box between this Feature and the other Feature and expands that over...
Definition: FeatureFloodCount.C:2099
dataLoad
void dataLoad(std::istream &stream, FeatureFloodCount::FeatureData &feature, void *context)
Definition: FeatureFloodCount.C:64
FeatureFloodCount::consolidateMergedFeatures
void consolidateMergedFeatures(std::vector< std::list< FeatureData >> *saved_data=nullptr)
This method consolidates all of the merged information from _partial_feature_sets into the _feature_s...
Definition: FeatureFloodCount.C:1176
areElemListsMergeable
bool areElemListsMergeable(const std::list< dof_id_type > &elem_list1, const std::list< dof_id_type > &elem_list2, MeshBase &mesh)
Definition: FeatureFloodCount.C:2222
FeatureFloodCount::sort
static void sort(std::set< T > &)
Definition: FeatureFloodCount.h:736
FeatureFloodCount::appendPeriodicNeighborNodes
void appendPeriodicNeighborNodes(FeatureData &feature) const
This routine adds the periodic node information to our data structure prior to packing the data this ...
Definition: FeatureFloodCount.C:1771
FeatureFloodCount::finalize
virtual void finalize() override
Definition: FeatureFloodCount.C:681
FeatureFloodCount::FeatureData::_ghosted_ids
container_type _ghosted_ids
Holds the ghosted ids for a feature (the ids which will be used for stitching.
Definition: FeatureFloodCount.h:268
FeatureFloodCount::_step_connecting_threshold
Real _step_connecting_threshold
Definition: FeatureFloodCount.h:578
FeatureFloodCount::_consolidate_merged_features
const PerfID _consolidate_merged_features
Definition: FeatureFloodCount.h:779
validParams< FeatureFloodCount >
InputParameters validParams< FeatureFloodCount >()
Definition: FeatureFloodCount.C:104
FeatureFloodCount::visitNeighborsHelper
void visitNeighborsHelper(const T *curr_entity, std::vector< const T * > neighbor_entities, FeatureData *feature, bool expand_halos_only, bool topological_neighbor, bool disjoint_only)
The actual logic for visiting neighbors is abstracted out here.
Definition: FeatureFloodCount.C:1667
FeatureFloodCount::_var_number
unsigned long _var_number
This variable is used to build the periodic node map.
Definition: FeatureFloodCount.h:588
FeatureFloodCount.h
FeatureFloodCount::_feature_sets
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
Definition: FeatureFloodCount.h:662
FeatureFloodCount::_entity_var_to_features
std::map< dof_id_type, std::vector< unsigned int > > _entity_var_to_features
Definition: FeatureFloodCount.h:713
FeatureFloodCount::_global_numbering
const bool _global_numbering
This variable is used to indicate whether or not we identify features with unique numbers on multiple...
Definition: FeatureFloodCount.h:597
FeatureFloodCount::FeatureData::_halo_ids
container_type _halo_ids
Holds the ids surrounding the feature.
Definition: FeatureFloodCount.h:275
FeatureFloodCount::FeatureData::_orig_ids
std::list< std::pair< processor_id_type, unsigned int > > _orig_ids
Original processor/local ids.
Definition: FeatureFloodCount.h:294
FeatureFloodCount::getFeatureVar
virtual unsigned int getFeatureVar(unsigned int feature_id) const
Returns the variable representing the passed in feature.
Definition: FeatureFloodCount.C:809
FeatureFloodCount::FeatureData::canConsolidate
bool canConsolidate(const FeatureData &rhs) const
This routine indicates whether two features can be consolidated, that is, one feature is reasonably e...
Definition: FeatureFloodCount.C:1963
FeatureFloodCount::_nodes_to_elem_map
std::vector< std::vector< const Elem * > > _nodes_to_elem_map
The data structure used to find neighboring elements give a node ID.
Definition: FeatureFloodCount.h:642
FeatureFloodCount::_single_map_mode
const bool _single_map_mode
This variable is used to indicate whether or not multiple maps are used during flooding.
Definition: FeatureFloodCount.h:591
FeatureFloodCount::_point_locator
std::unique_ptr< PointLocatorBase > _point_locator
Definition: FeatureFloodCount.h:689
FeatureFloodCount::_use_less_than_threshold_comparison
const bool _use_less_than_threshold_comparison
Use less-than when comparing values against the threshold value.
Definition: FeatureFloodCount.h:614
FeatureFloodCount::doesFeatureIntersectSpecifiedBoundary
virtual bool doesFeatureIntersectSpecifiedBoundary(unsigned int feature_id) const
Returns a Boolean indicating whether this feature intersects boundaries in a user-supplied list.
Definition: FeatureFloodCount.C:850
FeatureFloodCount::_ghosted_entity_ids
std::map< dof_id_type, int > _ghosted_entity_ids
The map for holding reconstructed ghosted element information.
Definition: FeatureFloodCount.h:695
FeatureFloodCount::_maps_size
const std::size_t _maps_size
Convenience variable holding the size of all the datastructures size by the number of maps.
Definition: FeatureFloodCount.h:620
FeatureFloodCount::_partial_feature_sets
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
Definition: FeatureFloodCount.h:655
FeatureFloodCount::_dof_map
const DofMap & _dof_map
Reference to the dof_map containing the coupled variables.
Definition: FeatureFloodCount.h:569
FeatureFloodCount::FeatureData::merge
void merge(FeatureData &&rhs)
Merges another Feature Data into this one.
Definition: FeatureFloodCount.C:1974
FeatureFloodCount::_fe_vars
std::vector< MooseVariableFEBase * > _fe_vars
The vector of coupled in variables.
Definition: FeatureFloodCount.h:564
FeatureFloodCount::FeatureData::boundingBoxesIntersect
bool boundingBoxesIntersect(const FeatureData &rhs) const
Determines if any of this FeatureData's bounding boxes overlap with the other FeatureData's bounding ...
Definition: FeatureFloodCount.C:1918
FeatureFloodCount::_is_elemental
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
Definition: FeatureFloodCount.h:723
updateBBoxExtremesHelper
void updateBBoxExtremesHelper(BoundingBox &bbox, const Point &node)
Definition: FeatureFloodCount.C:2205
FeatureFloodCount::_empty_var_to_features
std::vector< unsigned int > _empty_var_to_features
Definition: FeatureFloodCount.h:715
operator<<
std::ostream & operator<<(std::ostream &out, const FeatureFloodCount::FeatureData &feature)
Definition: FeatureFloodCount.C:2138
FeatureFloodCount::visitElementalNeighbors
void visitElementalNeighbors(const Elem *elem, FeatureData *feature, bool expand_halos_only, bool disjoint_only)
Definition: FeatureFloodCount.C:1584
FeatureFloodCount::FeatureData
Definition: FeatureFloodCount.h:138
FeatureFloodCount::_vars
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
Definition: FeatureFloodCount.h:566
FeatureFloodCount::_connecting_threshold
const Real _connecting_threshold
The threshold above (or below) which neighboring entities are flooded (where regions can be extended ...
Definition: FeatureFloodCount.h:577
FeatureFloodCount::_halo_ids
std::vector< std::map< dof_id_type, int > > _halo_ids
The data structure for looking up halos around features.
Definition: FeatureFloodCount.h:701
FeatureFloodCount::FeatureData::ghostedIntersect
bool ghostedIntersect(const FeatureData &rhs) const
Definition: FeatureFloodCount.C:1946
FeatureFloodCount::execute
virtual void execute() override
Definition: FeatureFloodCount.C:358
FeatureFloodCount::invalid_id
static const unsigned int invalid_id
Definition: FeatureFloodCount.h:94
FeatureFloodCount::mergeSets
virtual void mergeSets()
This routine is called on the master rank only and stitches together the partial feature pieces seen ...
Definition: FeatureFloodCount.C:1121
FeatureFloodCount::_pbs
PeriodicBoundaries * _pbs
A pointer to the periodic boundary constraints object.
Definition: FeatureFloodCount.h:687
FeatureFloodCount::clearDataStructures
virtual void clearDataStructures()
Helper routine for clearing up data structures during initialize and prior to parallel communication.
Definition: FeatureFloodCount.C:330
FeatureFloodCount::Status::INACTIVE
FeatureFloodCount::_feature_maps
std::vector< std::map< dof_id_type, int > > _feature_maps
The feature maps contain the raw flooded node information and eventually the unique grain numbers.
Definition: FeatureFloodCount.h:678
FeatureFloodCount::initialSetup
virtual void initialSetup() override
Definition: FeatureFloodCount.C:277
FeatureFloodCount::FeatureData::_periodic_nodes
container_type _periodic_nodes
Holds the nodes that belong to the feature on a periodic boundary.
Definition: FeatureFloodCount.h:281
FeatureFloodCount::compareValueWithThreshold
bool compareValueWithThreshold(Real entity_value, Real threshold) const
This method is used to determine whether the current entity value is part of a feature or not.
Definition: FeatureFloodCount.C:1418
FeatureFloodCount::FeatureData::_var_index
std::size_t _var_index
The Moose variable where this feature was found (often the "order parameter")
Definition: FeatureFloodCount.h:284
FeatureFloodCount::deserialize
void deserialize(std::vector< std::string > &serialized_buffers, unsigned int var_num=invalid_id)
This routine takes the vector of byte buffers (one for each processor), deserializes them into a seri...
Definition: FeatureFloodCount.C:1086
FeatureFloodCount::_feature_id_to_local_index
std::vector< std::size_t > _feature_id_to_local_index
The vector recording the grain_id to local index (several indices will contain invalid_size_t)
Definition: FeatureFloodCount.h:684
FeatureFloodCount::_distribute_merge_work
const bool _distribute_merge_work
Keeps track of whether we are distributing the merge work.
Definition: FeatureFloodCount.h:769
FeatureFloodCount::_compute_halo_maps
const bool _compute_halo_maps
Indicates whether or not to communicate halo map information with all ranks.
Definition: FeatureFloodCount.h:604
FeatureFloodCount::BoundaryIntersection::ANY_BOUNDARY
FeatureFloodCount::FeatureData::_centroid
Point _centroid
The centroid of the feature (average of coordinates from entities participating in the volume calcula...
Definition: FeatureFloodCount.h:304
FeatureFloodCount::getConnectingThreshold
virtual Real getConnectingThreshold(std::size_t current_index) const
Return the "connecting" comparison threshold to use when inspecting an entity during the flood stage.
Definition: FeatureFloodCount.C:1412
FeatureFloodCount::FeatureData::halosIntersect
bool halosIntersect(const FeatureData &rhs) const
Determine if one of this FeaturesData's member sets intersects the other FeatureData's corresponding ...
Definition: FeatureFloodCount.C:1930
FeatureFloodCount::flood
bool flood(const DofObject *dof_object, std::size_t current_index)
This method will check if the current entity is above the supplied threshold and "mark" it.
Definition: FeatureFloodCount.C:1294
FeatureFloodCount::_feature_count
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map)
Definition: FeatureFloodCount.h:648
FeatureFloodCount::FeatureData::_local_ids
container_type _local_ids
Holds the local ids in the interior of a feature.
Definition: FeatureFloodCount.h:272
FeatureFloodCount::_threshold
const Real _threshold
The threshold above (or below) where an entity may begin a new region (feature)
Definition: FeatureFloodCount.h:572
FeatureFloodCount::_is_boundary_restricted
bool _is_boundary_restricted
Indicates that this object should only run on one or more boundaries.
Definition: FeatureFloodCount.h:726
FeatureFloodCount::isNewFeatureOrConnectedRegion
virtual bool isNewFeatureOrConnectedRegion(const DofObject *dof_object, std::size_t &current_index, FeatureData *&feature, Status &status, unsigned int &new_id)
Method called during the recursive flood routine that should return whether or not the current entity...
Definition: FeatureFloodCount.C:1425
FeatureFloodCount::reserve
static void reserve(std::set< T > &, std::size_t)
Definition: FeatureFloodCount.h:748
FeatureFloodCount::Status::DIRTY
FeatureFloodCount::FeatureData::updateBBoxExtremes
void updateBBoxExtremes(MeshBase &mesh)
Update the minimum and maximum coordinates of a bounding box given a Point, Elem or BBox parameter.
Definition: FeatureFloodCount.C:1824
FeatureFloodCount::FeatureData::_vol_count
std::size_t _vol_count
The count of entities contributing to the volume calculation.
Definition: FeatureFloodCount.h:300
FeatureFloodCount::FieldType::VARIABLE_COLORING
FeatureFloodCount::_bnd_elem_range
ConstBndElemRange * _bnd_elem_range
Boundary element range pointer.
Definition: FeatureFloodCount.h:729
FeatureFloodCount::buildFeatureIdToLocalIndices
void buildFeatureIdToLocalIndices(unsigned int max_id)
This method builds a lookup map for retrieving the right local feature (by index) given a global inde...
Definition: FeatureFloodCount.C:665
FeatureFloodCount::BoundaryIntersection::NONE
FeatureFloodCount::_entity_queue
std::deque< const DofObject * > _entity_queue
The data structure for maintaining entities to flood during discovery.
Definition: FeatureFloodCount.h:766
FeatureFloodCount::_compute_var_to_feature_map
const bool _compute_var_to_feature_map
Indicates whether or not the var to feature map is populated.
Definition: FeatureFloodCount.h:607
FeatureFloodCount::_element_average_value
const PostprocessorValue & _element_average_value
Average value of the domain which can optionally be used to find features in a field.
Definition: FeatureFloodCount.h:692
FeatureFloodCount::_periodic_node_map
std::multimap< dof_id_type, dof_id_type > _periodic_node_map
The data structure which is a list of nodes that are constrained to other nodes based on the imposed ...
Definition: FeatureFloodCount.h:707
FeatureFloodCount::FeatureData::_bboxes
std::vector< BoundingBox > _bboxes
The vector of bounding boxes completely enclosing this feature (multiple used with periodic constrain...
Definition: FeatureFloodCount.h:291
FeatureFloodCount::_all_boundary_entity_ids
std::unordered_set< dof_id_type > _all_boundary_entity_ids
The set of entities on the boundary of the domain used for determining if features intersect any boun...
Definition: FeatureFloodCount.h:711
FeatureFloodCount::_step_threshold
Real _step_threshold
Definition: FeatureFloodCount.h:573
FeatureFloodCount::_prepare_for_transfer
const PerfID _prepare_for_transfer
Definition: FeatureFloodCount.h:778
dataStore
void dataStore(std::ostream &stream, FeatureFloodCount::FeatureData &feature, void *context)
Definition: FeatureFloodCount.C:33
FeatureFloodCount::setsIntersect
static bool setsIntersect(InputIterator first1, InputIterator last1, InputIterator first2, InputIterator last2)
This method detects whether two sets intersect without building a result set.
Definition: FeatureFloodCount.h:543
FeatureFloodCount::_n_procs
const processor_id_type _n_procs
Convenience variable holding the number of processors in this simulation.
Definition: FeatureFloodCount.h:623
FeatureFloodCount::getValue
virtual Real getValue() override
Definition: FeatureFloodCount.C:785
FeatureFloodCount::_expand_halos
const PerfID _expand_halos
Definition: FeatureFloodCount.h:776
FeatureFloodCount::_var_index_maps
std::vector< std::map< dof_id_type, int > > _var_index_maps
This map keeps track of which variables own which nodes.
Definition: FeatureFloodCount.h:639
FeatureFloodCount::_n_vars
const std::size_t _n_vars
Definition: FeatureFloodCount.h:617
FeatureFloodCount::_local_to_global_feature_map
std::vector< std::size_t > _local_to_global_feature_map
The vector recording the local to global feature indices.
Definition: FeatureFloodCount.h:681
FeatureFloodCount::updateBoundaryIntersections
void updateBoundaryIntersections(FeatureData &feature) const
Update the feature's attributes to indicate boundary intersections.
Definition: FeatureFloodCount.C:1724
FeatureFloodCount::meshChanged
virtual void meshChanged() override
Definition: FeatureFloodCount.C:335
FeatureFloodCount::_feature_counts_per_map
std::vector< unsigned int > _feature_counts_per_map
The number of features seen by this object per map.
Definition: FeatureFloodCount.h:645
FeatureFloodCount::BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY
FeatureFloodCount::FeatureData::_status
Status _status
The status of a feature (used mostly in derived classes like the GrainTracker)
Definition: FeatureFloodCount.h:307
FeatureFloodCount::updateFieldInfo
virtual void updateFieldInfo()
This method is used to populate any of the data structures used for storing field data (nodal or elem...
Definition: FeatureFloodCount.C:1249
FeatureFloodCount::_primary_perc_bnds
std::vector< BoundaryID > _primary_perc_bnds
Definition: FeatureFloodCount.h:717
FeatureFloodCount::FieldType::HALOS
FeatureFloodCount::serialize
void serialize(std::string &serialized_buffer, unsigned int var_num=invalid_id)
This routines packs the _partial_feature_sets data into a structure suitable for parallel communicati...
Definition: FeatureFloodCount.C:1067
FeatureFloodCount::Status::MARKED
FeatureFloodCount::getNumberActiveFeatures
std::size_t getNumberActiveFeatures() const
Return the number of active features.
Definition: FeatureFloodCount.C:791