www.mooseframework.org
Classes | Public Types | Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Attributes | List of all members
GrainTracker Class Reference

#include <GrainTracker.h>

Inheritance diagram for GrainTracker:
[legend]

Classes

struct  CacheValues
 
struct  PartialFeatureData
 

Public Types

enum  RemapCacheMode { RemapCacheMode::FILL, RemapCacheMode::USE, RemapCacheMode::BYPASS }
 
enum  FieldType {
  FieldType::UNIQUE_REGION, FieldType::VARIABLE_COLORING, FieldType::GHOSTED_ENTITIES, FieldType::HALOS,
  FieldType::CENTROID, FieldType::ACTIVE_BOUNDS
}
 
enum  Status : unsigned char { Status::CLEAR = 0x0, Status::MARKED = 0x1, Status::DIRTY = 0x2, Status::INACTIVE = 0x4 }
 This enumeration is used to indicate status of the grains in the _unique_grains data structure. More...
 
enum  BoundaryIntersection : unsigned char { BoundaryIntersection::NONE = 0x0, BoundaryIntersection::ANY_BOUNDARY = 0x1, BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY = 0x2, BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY = 0x4 }
 This enumeration is used to inidacate status of boundary intersections. More...
 

Public Member Functions

 GrainTracker (const InputParameters &parameters)
 
virtual ~GrainTracker ()
 
virtual void meshChanged () override
 
virtual void initialize () override
 
virtual void execute () override
 
virtual void finalize () override
 
virtual std::size_t getTotalFeatureCount () const override
 Returns the total feature count (active and inactive ids, useful for sizing vectors) More...
 
virtual Real getEntityValue (dof_id_type node_id, FieldType field_type, std::size_t var_index=0) const override
 
virtual const std::vector< unsigned int > & getVarToFeatureVector (dof_id_type elem_id) const override
 Returns a list of active unique feature ids for a particular element. More...
 
virtual unsigned int getFeatureVar (unsigned int feature_id) const override
 Returns the variable representing the passed in feature. More...
 
virtual std::size_t getNumberActiveGrains () const override
 Returns the number of active grains current stored in the GrainTracker. More...
 
virtual Point getGrainCentroid (unsigned int grain_id) const override
 Returns the centroid for the given grain number. More...
 
virtual bool doesFeatureIntersectBoundary (unsigned int feature_id) const override
 Returns a Boolean indicating whether this feature intersects any boundary. More...
 
virtual bool isFeaturePercolated (unsigned int feature_id) const override
 Returns a Boolean indicating whether this feature is percolated (e.g. More...
 
virtual std::vector< unsigned int > getNewGrainIDs () const override
 This method returns all of the new ids generated in an invocation of the GrainTracker. More...
 
virtual void initialSetup () override
 
virtual Real getValue () override
 
std::size_t getNumberActiveFeatures () const
 Return the number of active features. More...
 
virtual Point featureCentroid (unsigned int feature_id) const
 Returns the centroid of the designated feature (only supported without periodic boundaries) More...
 
std::size_t numCoupledVars () const
 Returns the number of coupled varaibles. More...
 
const std::vector< MooseVariable * > & getCoupledVars () const
 Returns a const vector to the coupled variable pointers. More...
 
const std::vector< MooseVariableFEBase * > & getFECoupledVars () const
 Returns a const vector to the coupled MooseVariableFEBase pointers. More...
 
bool isElemental () const
 
const std::vector< FeatureData > & getFeatures () const
 Return a constant reference to the vector of all discovered features. More...
 

Static Public Attributes

static const std::size_t invalid_size_t = std::numeric_limits<std::size_t>::max()
 
static const unsigned int invalid_id = std::numeric_limits<unsigned int>::max()
 

Protected Member Functions

virtual void updateFieldInfo () override
 This method is used to populate any of the data structures used for storing field data (nodal or elemental). More...
 
virtual Real getThreshold (std::size_t current_index) const override
 Return the starting comparison threshold to use when inspecting an entity during the flood stage. More...
 
void prepopulateState (const FeatureFloodCount &ffc_object)
 This method extracts the necessary state from the passed in object necessary to continue tracking grains. More...
 
void communicateHaloMap ()
 
void assignGrains ()
 When the tracking phase starts (_t_step == _tracking_step) it assigns a unique id to every FeatureData object found by the FeatureFloodCount object. More...
 
void trackGrains ()
 On subsequent time_steps, incoming FeatureData objects are compared to previous time_step information to track grains between time steps. More...
 
virtual void newGrainCreated (unsigned int new_grain_id)
 This method is called when a new grain is detected. More...
 
void remapGrains ()
 This method is called after trackGrains to remap grains that are too close to each other. More...
 
void broadcastAndUpdateGrainData ()
 Broadcast essential Grain information to all processors. More...
 
void computeMinDistancesFromGrain (FeatureData &grain, std::vector< std::list< GrainDistance >> &min_distances)
 Populates and sorts a min_distances vector with the minimum distances to all grains in the simulation for a given grain. More...
 
bool attemptGrainRenumber (FeatureData &grain, unsigned int depth, unsigned int max_depth)
 This is the recursive part of the remapping algorithm. More...
 
void swapSolutionValues (FeatureData &grain, std::size_t new_var_index, std::vector< std::map< Node *, CacheValues >> &cache, RemapCacheMode cache_mode)
 A routine for moving all of the solution values from a given grain to a new variable number. More...
 
void swapSolutionValuesHelper (Node *curr_node, std::size_t curr_var_index, std::size_t new_var_index, std::vector< std::map< Node *, CacheValues >> &cache, RemapCacheMode cache_mode)
 Helper method for actually performing the swaps. More...
 
Real boundingRegionDistance (std::vector< MeshTools::BoundingBox > &bboxes1, std::vector< MeshTools::BoundingBox > &bboxes2) const
 This method returns the minimum periodic distance between two vectors of bounding boxes. More...
 
Real centroidRegionDistance (std::vector< MeshTools::BoundingBox > &bboxes1, std::vector< MeshTools::BoundingBox > &bboxes2) const
 This method returns the minimum periodic distance between the centroids of two vectors of bounding boxes. More...
 
unsigned int getNextUniqueID ()
 Retrieve the next unique grain number if a new grain is detected during trackGrains. More...
 
template<typename T >
bool isBoundaryEntity (const T *entity) const
 Returns a Boolean indicating whether the entity is on one of the desired boundaries. More...
 
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. More...
 
virtual Real getConnectingThreshold (std::size_t current_index) const
 Return the "connecting" comparison threshold to use when inspecting an entity during the flood stage. More...
 
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. More...
 
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 is part of the current feature (if one is being explored), or if it's the start of a new feature. More...
 
void expandPointHalos ()
 This method takes all of the partial features and expands the local, ghosted, and halo sets around those regions to account for the diffuse interface. More...
 
void expandEdgeHalos (unsigned int num_layers_to_expand)
 This method expands the existing halo set by some width determined by the passed in value. More...
 
template<typename T >
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. More...
 
void prepareDataForTransfer ()
 This routine uses the local flooded data to build up the local feature data structures (_feature_sets). More...
 
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 communication operations. More...
 
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 series of FeatureSet objects, and appends them to the _feature_sets data structure. More...
 
virtual void mergeSets ()
 This routine is called on the master rank only and stitches together the partial feature pieces seen on any processor. More...
 
virtual bool areFeaturesMergeable (const FeatureData &f1, const FeatureData &f2) const
 Method for determining whether two features are mergeable. More...
 
void communicateAndMerge ()
 This routine handles all of the serialization, communication and deserialization of the data structures containing FeatureData objects. More...
 
void sortAndLabel ()
 Sort and assign ids to features based on their position in the container after sorting. More...
 
void scatterAndUpdateRanks ()
 Calls buildLocalToGlobalIndices to build the individual local to global indicies for each rank and scatters that information to all ranks. More...
 
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 vector for scattering the vector to the ranks. More...
 
void buildFeatureIdToLocalIndices (unsigned int max_id)
 This method builds a lookup map for retrieving the right local feature (by index) given a global index or id. More...
 
virtual void clearDataStructures ()
 Helper routine for clearing up data structures during initialize and prior to parallel communication. More...
 
void updateBoundaryIntersections (FeatureData &feature) const
 Update the feature's attributes to indicate boundary intersections. More...
 
void appendPeriodicNeighborNodes (FeatureData &feature) const
 This routine adds the periodic node information to our data structure prior to packing the data this makes those periodic neighbors appear much like ghosted nodes in a multiprocessor setting. More...
 
void updateRegionOffsets ()
 This routine updates the _region_offsets variable which is useful for quickly determining the proper global number for a feature when using multimap mode. More...
 
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 neighbors. More...
 
void visitElementalNeighbors (const Elem *elem, FeatureData *feature, bool expand_halos_only, bool disjoint_only)
 

Static Protected Member Functions

template<class InputIterator >
static bool setsIntersect (InputIterator first1, InputIterator last1, InputIterator first2, InputIterator last2)
 This method detects whether two sets intersect without building a result set. More...
 

Protected Attributes

const int _tracking_step
 The timestep to begin tracking grains. More...
 
const unsigned short _halo_level
 The thickness of the halo surrounding each grain. More...
 
const unsigned short _max_remap_recursion_depth
 Depth of renumbering recursion (a depth of zero means no recursion) More...
 
const unsigned short _n_reserve_ops
 The number of reserved order parameters. More...
 
const std::size_t _reserve_op_index
 The cutoff index where if variable index >= this number, no remapping TO that variable will occur. More...
 
const Real _reserve_op_threshold
 The threshold above (or below) where a grain may be found on a reserve op field. More...
 
const bool _remap
 Inidicates whether remapping should be done or not (remapping is independent of tracking) More...
 
const bool _tolerate_failure
 Indicates whether we should continue after a remap failure (will result in non-physical results) More...
 
NonlinearSystemBase & _nl
 A reference to the nonlinear system (used for retrieving solution vectors) More...
 
std::vector< FeatureData > _feature_sets_old
 This data structure holds the map of unique grains from the previous time step. More...
 
const PolycrystalUserObjectBase_poly_ic_uo
 An optional IC UserObject which can provide initial data structures to this object. More...
 
const short _verbosity_level
 Verbosity level controlling the amount of information printed to the console. More...
 
bool & _first_time
 Boolean to indicate the first time this object executes. More...
 
const bool _error_on_grain_creation
 Boolean to terminate with an error if a new grain is created during the simulation. More...
 
std::vector< MooseVariableFEBase * > _fe_vars
 The vector of coupled in variables. More...
 
std::vector< MooseVariable * > _vars
 The vector of coupled in variables cast to MooseVariable. More...
 
const DofMap & _dof_map
 Reference to the dof_map containing the coupled variables. More...
 
const Real _threshold
 The threshold above (or below) where an entity may begin a new region (feature) More...
 
Real _step_threshold
 
const Real _connecting_threshold
 The threshold above (or below) which neighboring entities are flooded (where regions can be extended but not started) More...
 
Real _step_connecting_threshold
 
MooseMesh & _mesh
 A reference to the mesh. More...
 
unsigned long _var_number
 This variable is used to build the periodic node map. More...
 
const bool _single_map_mode
 This variable is used to indicate whether or not multiple maps are used during flooding. More...
 
const bool _condense_map_info
 
const bool _global_numbering
 This variable is used to indicate whether or not we identify features with unique numbers on multiple maps. More...
 
const bool _var_index_mode
 This variable is used to indicate whether the maps will contain unique region information or just the variable numbers owning those regions. More...
 
const bool _compute_halo_maps
 Indicates whether or not to communicate halo map information with all ranks. More...
 
const bool _compute_var_to_feature_map
 Indicates whether or not the var to feature map is populated. More...
 
const bool _use_less_than_threshold_comparison
 Use less-than when comparing values against the threshold value. More...
 
const std::size_t _n_vars
 
const std::size_t _maps_size
 Convenience variable holding the size of all the datastructures size by the number of maps. More...
 
const processor_id_type _n_procs
 Convenience variable holding the number of processors in this simulation. More...
 
std::vector< std::set< dof_id_type > > _entities_visited
 This variable keeps track of which nodes have been visited during execution. More...
 
std::vector< std::map< dof_id_type, int > > _var_index_maps
 This map keeps track of which variables own which nodes. More...
 
std::vector< std::vector< const Elem * > > _nodes_to_elem_map
 The data structure used to find neighboring elements give a node ID. More...
 
std::vector< unsigned int > _feature_counts_per_map
 The number of features seen by this object per map. More...
 
unsigned int _feature_count
 The number of features seen by this object (same as summing _feature_counts_per_map) More...
 
std::vector< std::list< FeatureData > > _partial_feature_sets
 The data structure used to hold partial and communicated feature data, during the discovery and merging phases. More...
 
std::vector< FeatureData > & _feature_sets
 The data structure used to hold the globally unique features. More...
 
std::vector< FeatureData > _volatile_feature_sets
 Derived objects (e.g. More...
 
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. More...
 
std::vector< std::size_t > _local_to_global_feature_map
 The vector recording the local to global feature indices. More...
 
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) More...
 
PeriodicBoundaries * _pbs
 A pointer to the periodic boundary constraints object. More...
 
std::unique_ptr< PointLocatorBase > _point_locator
 
const PostprocessorValue & _element_average_value
 Average value of the domain which can optionally be used to find features in a field. More...
 
std::map< dof_id_type, int > _ghosted_entity_ids
 The map for holding reconstructed ghosted element information. More...
 
std::vector< std::map< dof_id_type, int > > _halo_ids
 The data structure for looking up halos around features. More...
 
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 periodic boundary conditions. More...
 
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 boundary. More...
 
std::map< dof_id_type, std::vector< unsigned int > > _entity_var_to_features
 
std::vector< unsigned int > _empty_var_to_features
 
std::vector< BoundaryID > _primary_perc_bnds
 
std::vector< BoundaryID > _secondary_perc_bnds
 
const bool _is_elemental
 Determines if the flood counter is elements or not (nodes) More...
 
bool _is_boundary_restricted
 Indicates that this object should only run on one or more boundaries. More...
 
ConstBndElemRange * _bnd_elem_range
 Boundary element range pointer. More...
 
const bool _is_master
 Convenience variable for testing master rank. More...
 

Private Attributes

unsigned int _reserve_grain_first_index
 Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) More...
 
unsigned int _old_max_grain_id
 The previous max grain id (needed to figure out which ids are new in a given step) More...
 
unsigned int & _max_curr_grain_id
 Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) More...
 
const bool _is_transient
 Boolean to indicate whether this is a Steady or Transient solve. More...
 
std::vector< std::pair< dof_id_type, dof_id_type > > _all_ranges
 Data structure to hold element ID ranges when using Distributed Mesh (populated on rank 0 only) More...
 
const PerfID _finalize_timer
 Timers. More...
 
const PerfID _remap_timer
 
const PerfID _track_grains
 
const PerfID _broadcast_update
 
const PerfID _update_field_info
 

Detailed Description

Definition at line 25 of file GrainTracker.h.

Member Enumeration Documentation

◆ BoundaryIntersection

enum FeatureFloodCount::BoundaryIntersection : unsigned char
stronginherited

This enumeration is used to inidacate status of boundary intersections.

Enumerator
NONE 
ANY_BOUNDARY 
PRIMARY_PERCOLATION_BOUNDARY 
SECONDARY_PERCOLATION_BOUNDARY 

Definition at line 127 of file FeatureFloodCount.h.

127  : unsigned char
128  {
129  NONE = 0x0,
130  ANY_BOUNDARY = 0x1,
131  PRIMARY_PERCOLATION_BOUNDARY = 0x2,
132  SECONDARY_PERCOLATION_BOUNDARY = 0x4
133  };

◆ FieldType

enum FeatureFloodCount::FieldType
stronginherited
Enumerator
UNIQUE_REGION 
VARIABLE_COLORING 
GHOSTED_ENTITIES 
HALOS 
CENTROID 
ACTIVE_BOUNDS 

Definition at line 101 of file FeatureFloodCount.h.

102  {
103  UNIQUE_REGION,
104  VARIABLE_COLORING,
105  GHOSTED_ENTITIES,
106  HALOS,
107  CENTROID,
108  ACTIVE_BOUNDS,
109  };

◆ RemapCacheMode

Enumerator
FILL 
USE 
BYPASS 

Definition at line 54 of file GrainTracker.h.

55  {
56  FILL,
57  USE,
58  BYPASS
59  };

◆ Status

enum FeatureFloodCount::Status : unsigned char
stronginherited

This enumeration is used to indicate status of the grains in the _unique_grains data structure.

Enumerator
CLEAR 
MARKED 
DIRTY 
INACTIVE 

Definition at line 118 of file FeatureFloodCount.h.

118  : unsigned char
119  {
120  CLEAR = 0x0,
121  MARKED = 0x1,
122  DIRTY = 0x2,
123  INACTIVE = 0x4
124  };

Constructor & Destructor Documentation

◆ GrainTracker()

GrainTracker::GrainTracker ( const InputParameters &  parameters)

Definition at line 80 of file GrainTracker.C.

81  : FeatureFloodCount(parameters),
83  _tracking_step(getParam<int>("tracking_step")),
84  _halo_level(getParam<unsigned short>("halo_level")),
85  _max_remap_recursion_depth(getParam<unsigned short>("max_remap_recursion_depth")),
86  _n_reserve_ops(getParam<unsigned short>("reserve_op")),
88  _reserve_op_threshold(getParam<Real>("reserve_op_threshold")),
89  _remap(getParam<bool>("remap_grains")),
90  _tolerate_failure(getParam<bool>("tolerate_failure")),
91  _nl(_fe_problem.getNonlinearSystemBase()),
92  _poly_ic_uo(parameters.isParamValid("polycrystal_ic_uo")
93  ? &getUserObject<PolycrystalUserObjectBase>("polycrystal_ic_uo")
94  : nullptr),
95  _verbosity_level(getParam<short>("verbosity_level")),
96  _first_time(declareRestartableData<bool>("first_time", true)),
97  _error_on_grain_creation(getParam<bool>("error_on_grain_creation")),
100  _max_curr_grain_id(declareRestartableData<unsigned int>("max_curr_grain_id", invalid_id)),
101  _is_transient(_subproblem.isTransient()),
102  _finalize_timer(registerTimedSection("finalize", 1)),
103  _remap_timer(registerTimedSection("remapGrains", 2)),
104  _track_grains(registerTimedSection("trackGrains", 2)),
105  _broadcast_update(registerTimedSection("broadCastUpdate", 2)),
106  _update_field_info(registerTimedSection("updateFieldInfo", 2))
107 {
108  if (_tolerate_failure)
109  paramInfo("tolerate_failure",
110  "Tolerate failure has been set to true. Non-physical simulation results "
111  "are possible, you will be notified in the event of a failed remapping operation.");
112 
113  if (_tracking_step > 0 && _poly_ic_uo)
114  mooseError("Can't start tracking after the initial condition when using a polycrystal_ic_uo");
115 }
FeatureFloodCount(const InputParameters &parameters)
This class defines the interface for the GrainTracking objects.
const std::size_t _n_vars
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
const bool _error_on_grain_creation
Boolean to terminate with an error if a new grain is created during the simulation.
Definition: GrainTracker.h:233
unsigned int _old_max_grain_id
The previous max grain id (needed to figure out which ids are new in a given step) ...
Definition: GrainTracker.h:240
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243
const PerfID _broadcast_update
Definition: GrainTracker.h:255
NonlinearSystemBase & _nl
A reference to the nonlinear system (used for retrieving solution vectors)
Definition: GrainTracker.h:206
const PolycrystalUserObjectBase * _poly_ic_uo
An optional IC UserObject which can provide initial data structures to this object.
Definition: GrainTracker.h:215
const Real _reserve_op_threshold
The threshold above (or below) where a grain may be found on a reserve op field.
Definition: GrainTracker.h:197
const short _verbosity_level
Verbosity level controlling the amount of information printed to the console.
Definition: GrainTracker.h:220
static const unsigned int invalid_id
const PerfID _track_grains
Definition: GrainTracker.h:254
const PerfID _remap_timer
Definition: GrainTracker.h:253
const PerfID _finalize_timer
Timers.
Definition: GrainTracker.h:252
const bool _remap
Inidicates whether remapping should be done or not (remapping is independent of tracking) ...
Definition: GrainTracker.h:200
const PerfID _update_field_info
Definition: GrainTracker.h:256
const bool _is_transient
Boolean to indicate whether this is a Steady or Transient solve.
Definition: GrainTracker.h:246
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181
unsigned int _reserve_grain_first_index
Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) ...
Definition: GrainTracker.h:237
const unsigned short _halo_level
The thickness of the halo surrounding each grain.
Definition: GrainTracker.h:184
const std::size_t _reserve_op_index
The cutoff index where if variable index >= this number, no remapping TO that variable will occur...
Definition: GrainTracker.h:194
const unsigned short _max_remap_recursion_depth
Depth of renumbering recursion (a depth of zero means no recursion)
Definition: GrainTracker.h:187
const bool _tolerate_failure
Indicates whether we should continue after a remap failure (will result in non-physical results) ...
Definition: GrainTracker.h:203
const unsigned short _n_reserve_ops
The number of reserved order parameters.
Definition: GrainTracker.h:190

◆ ~GrainTracker()

GrainTracker::~GrainTracker ( )
virtual

Definition at line 117 of file GrainTracker.C.

117 {}

Member Function Documentation

◆ appendPeriodicNeighborNodes()

void FeatureFloodCount::appendPeriodicNeighborNodes ( FeatureData feature) const
protectedinherited

This routine adds the periodic node information to our data structure prior to packing the data this makes those periodic neighbors appear much like ghosted nodes in a multiprocessor setting.

Definition at line 1726 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::prepareDataForTransfer().

1727 {
1728  if (_is_elemental)
1729  {
1730  for (auto entity : feature._local_ids)
1731  {
1732  Elem * elem = _mesh.elemPtr(entity);
1733 
1734  for (MooseIndex(elem->n_nodes()) node_n = 0; node_n < elem->n_nodes(); ++node_n)
1735  {
1736  auto iters = _periodic_node_map.equal_range(elem->node_id(node_n));
1737 
1738  for (auto it = iters.first; it != iters.second; ++it)
1739  {
1740  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->first);
1741  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->second);
1742  }
1743  }
1744  }
1745  }
1746  else
1747  {
1748  for (auto entity : feature._local_ids)
1749  {
1750  auto iters = _periodic_node_map.equal_range(entity);
1751 
1752  for (auto it = iters.first; it != iters.second; ++it)
1753  {
1754  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->first);
1755  feature._periodic_nodes.insert(feature._periodic_nodes.end(), it->second);
1756  }
1757  }
1758  }
1759 
1760  // TODO: Remove duplicates
1761 }
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 ...
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
MooseMesh & _mesh
A reference to the mesh.

◆ areFeaturesMergeable()

bool FeatureFloodCount::areFeaturesMergeable ( const FeatureData f1,
const FeatureData f2 
) const
protectedvirtualinherited

Method for determining whether two features are mergeable.

This routine exists because derived classes may need to override this function rather than use the mergeable method in the FeatureData object.

Reimplemented in PolycrystalUserObjectBase.

Definition at line 1208 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::mergeSets().

1209 {
1210  return f1.mergeable(f2);
1211 }

◆ assignGrains()

void GrainTracker::assignGrains ( )
protected

When the tracking phase starts (_t_step == _tracking_step) it assigns a unique id to every FeatureData object found by the FeatureFloodCount object.

We need to assign grainIDs to get the simulation going. We'll use the default sorting that doesn't require valid grainIDs (relies on _min_entity_id and _var_index). These will be the unique grain numbers that we must track for remainder of the simulation.

Definition at line 433 of file GrainTracker.C.

Referenced by finalize().

434 {
435  mooseAssert(_first_time, "assignGrains may only be called on the first tracking step");
436 
442  if (_is_master)
443  {
444  // Find the largest grain ID, this requires sorting if the ID is not already set
445  sortAndLabel();
446 
447  if (_feature_sets.empty())
448  {
451  }
452  else
453  {
454  _max_curr_grain_id = _feature_sets.back()._id;
456  }
457 
458  for (auto & grain : _feature_sets)
459  grain._status = Status::MARKED; // Mark the grain
460 
461  } // is_master
462 
463  /*************************************************************
464  ****************** COLLECTIVE WORK SECTION ******************
465  *************************************************************/
466 
467  // Make IDs on all non-master ranks consistent
469 
470  // Build up an id to index map
471  _communicator.broadcast(_max_curr_grain_id);
473 
474  // Now trigger the newGrainCreated() callback on all ranks
476  for (unsigned int new_id = 0; new_id <= _max_curr_grain_id; ++new_id)
477  newGrainCreated(new_id);
478 }
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243
const bool _is_master
Convenience variable for testing master rank.
void sortAndLabel()
Sort and assign ids to features based on their position in the container after sorting.
static const unsigned int invalid_id
unsigned int _reserve_grain_first_index
Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) ...
Definition: GrainTracker.h:237
void buildFeatureIdToLocalIndices(unsigned int max_id)
This method builds a lookup map for retrieving the right local feature (by index) given a global inde...
void scatterAndUpdateRanks()
Calls buildLocalToGlobalIndices to build the individual local to global indicies for each rank and sc...
virtual void newGrainCreated(unsigned int new_grain_id)
This method is called when a new grain is detected.
Definition: GrainTracker.C:865

◆ attemptGrainRenumber()

bool GrainTracker::attemptGrainRenumber ( FeatureData &  grain,
unsigned int  depth,
unsigned int  max_depth 
)
protected

This is the recursive part of the remapping algorithm.

It attempts to remap a grain to a new index and recurses until max_depth is reached.

We have two grains that are getting close represented by the same order parameter. We need to map to the variable whose closest grain to this one is furthest away by bounding region to bounding region distance.

We have a vector of the distances to the closest grains represented by each of our variables. We just need to pick a suitable grain to replace with. We will start with the maximum of this this list: (max of the mins), but will settle for next to largest and so forth as we make more attempts at remapping grains. This is a graph coloring problem so more work will be required to optimize this process.

Note: We don't have an explicit check here to avoid remapping a variable to itself. This is unnecessary since the min_distance of a variable is explicitly set up above.

If we get to this case and the best distance is less than -1, we are in big trouble. This means that grains represented by all of the remaining order parameters are overlapping this one in at least two places. We'd have to maintain multiple recursive chains, or just start over from scratch... Let's just return false and see if there is another remapping option.

Propose a new variable index for the current grain and recurse. We don't need to mark the status as DIRTY here since the recursion may fail. For now, we'll just add MARKED to the status.

Definition at line 1244 of file GrainTracker.C.

Referenced by remapGrains().

1245 {
1246  // End the recursion of our breadth first search
1247  if (depth > max_depth)
1248  return false;
1249 
1250  std::size_t curr_var_index = grain._var_index;
1251 
1252  std::vector<std::map<Node *, CacheValues>> cache;
1253 
1254  std::vector<std::list<GrainDistance>> min_distances(_vars.size());
1255 
1261  computeMinDistancesFromGrain(grain, min_distances);
1262 
1273  // clang-format off
1274  std::sort(min_distances.begin(), min_distances.end(),
1275  [](const std::list<GrainDistance> & lhs, const std::list<GrainDistance> & rhs)
1276  {
1277  // Sort lists in reverse order (largest distance first)
1278  // These empty cases are here to make this comparison stable
1279  if (lhs.empty())
1280  return false;
1281  else if (rhs.empty())
1282  return true;
1283  else
1284  return lhs.begin()->_distance > rhs.begin()->_distance;
1285  });
1286  // clang-format on
1287 
1288  for (auto & list_ref : min_distances)
1289  {
1290  const auto target_it = list_ref.begin();
1291  if (target_it == list_ref.end())
1292  continue;
1293 
1294  // If the distance is positive we can just remap and be done
1295  if (target_it->_distance > 0)
1296  {
1297  if (_verbosity_level > 0)
1298  {
1299  _console << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain._id
1300  << " from variable index " << curr_var_index << " to " << target_it->_var_index;
1301  if (target_it->_distance == std::numeric_limits<Real>::max())
1302  _console << " which currently contains zero grains.\n\n" << COLOR_DEFAULT;
1303  else
1304  _console << " whose closest grain (#" << target_it->_grain_id << ") is at a distance of "
1305  << std::sqrt(target_it->_distance) << "\n\n"
1306  << COLOR_DEFAULT;
1307  }
1308 
1309  grain._status |= Status::DIRTY;
1310  grain._var_index = target_it->_var_index;
1311  return true;
1312  }
1313 
1314  // If the distance isn't positive we just need to make sure that none of the grains represented
1315  // by the target variable index would intersect this one if we were to remap
1316  {
1317  auto next_target_it = target_it;
1318  bool intersection_hit = false;
1319  unsigned short num_close_targets = 0;
1320  std::ostringstream oss;
1321  while (!intersection_hit && next_target_it != list_ref.end())
1322  {
1323  if (next_target_it->_distance > 0)
1324  break;
1325 
1326  mooseAssert(next_target_it->_grain_index < _feature_sets.size(),
1327  "Error in indexing target grain in attemptGrainRenumber");
1328  FeatureData & next_target_grain = _feature_sets[next_target_it->_grain_index];
1329 
1330  // If any grains touch we're done here
1331  if (grain.halosIntersect(next_target_grain))
1332  intersection_hit = true;
1333  else
1334  {
1335  if (num_close_targets > 0)
1336  oss << ", "; // delimiter
1337  oss << "#" << next_target_it->_grain_id;
1338  }
1339 
1340  ++next_target_it;
1341  ++num_close_targets;
1342  }
1343 
1344  if (!intersection_hit)
1345  {
1346  if (_verbosity_level > 0)
1347  {
1348  _console << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain._id
1349  << " from variable index " << curr_var_index << " to " << target_it->_var_index;
1350 
1351  if (num_close_targets == 1)
1352  _console << " whose closest grain (" << oss.str()
1353  << ") is inside our bounding box but whose halo is not touching.\n\n"
1354  << COLOR_DEFAULT;
1355  else
1356  _console << " whose closest grains (" << oss.str()
1357  << ") are inside our bounding box but whose halos are not touching.\n\n"
1358  << COLOR_DEFAULT;
1359  }
1360 
1361  grain._status |= Status::DIRTY;
1362  grain._var_index = target_it->_var_index;
1363  return true;
1364  }
1365  }
1366 
1367  // If we reach this part of the loop, there is no simple renumbering that can be done.
1368  mooseAssert(target_it->_grain_index < _feature_sets.size(),
1369  "Error in indexing target grain in attemptGrainRenumber");
1370  FeatureData & target_grain = _feature_sets[target_it->_grain_index];
1371 
1379  if (target_it->_distance < -1)
1380  return false;
1381 
1382  // Make sure this grain isn't marked. If it is, we can't recurse here
1383  if ((target_grain._status & Status::MARKED) == Status::MARKED)
1384  return false;
1385 
1391  grain._var_index = target_it->_var_index;
1392  grain._status |= Status::MARKED;
1393  if (attemptGrainRenumber(target_grain, depth + 1, max_depth))
1394  {
1395  // SUCCESS!
1396  if (_verbosity_level > 0)
1397  _console << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain._id
1398  << " from variable index " << curr_var_index << " to " << target_it->_var_index
1399  << "\n\n"
1400  << COLOR_DEFAULT;
1401 
1402  // Now we need to mark the grain as DIRTY since the recursion succeeded.
1403  grain._status |= Status::DIRTY;
1404  return true;
1405  }
1406  else
1407  // FAILURE, We need to set our var index back after failed recursive step
1408  grain._var_index = curr_var_index;
1409 
1410  // ALWAYS "unmark" (or clear the MARKED status) after recursion so it can be used by other remap
1411  // operations
1412  grain._status &= ~Status::MARKED;
1413  }
1414 
1415  return false;
1416 }
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure...
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
void computeMinDistancesFromGrain(FeatureData &grain, std::vector< std::list< GrainDistance >> &min_distances)
Populates and sorts a min_distances vector with the minimum distances to all grains in the simulation...
const short _verbosity_level
Verbosity level controlling the amount of information printed to the console.
Definition: GrainTracker.h:220
bool attemptGrainRenumber(FeatureData &grain, unsigned int depth, unsigned int max_depth)
This is the recursive part of the remapping algorithm.

◆ boundingRegionDistance()

Real GrainTracker::boundingRegionDistance ( std::vector< MeshTools::BoundingBox > &  bboxes1,
std::vector< MeshTools::BoundingBox > &  bboxes2 
) const
protected

This method returns the minimum periodic distance between two vectors of bounding boxes.

If the bounding boxes overlap the result is always -1.0.

The region that each grain covers is represented by a bounding box large enough to encompassing all the points within that grain. When using periodic boundaries, we may have several discrete "pieces" of a grain each represented by a bounding box. The distance between any two grains is defined as the minimum distance between any pair of boxes, one selected from each grain.

Definition at line 1730 of file GrainTracker.C.

Referenced by computeMinDistancesFromGrain().

1732 {
1739  auto min_distance = std::numeric_limits<Real>::max();
1740  for (const auto & bbox1 : bboxes1)
1741  {
1742  for (const auto & bbox2 : bboxes2)
1743  {
1744  // AABB squared distance
1745  Real curr_distance = 0.0;
1746  bool boxes_overlap = true;
1747  for (unsigned int dim = 0; dim < LIBMESH_DIM; ++dim)
1748  {
1749  const auto & min1 = bbox1.min()(dim);
1750  const auto & max1 = bbox1.max()(dim);
1751  const auto & min2 = bbox2.min()(dim);
1752  const auto & max2 = bbox2.max()(dim);
1753 
1754  if (min1 > max2)
1755  {
1756  const auto delta = max2 - min1;
1757  curr_distance += delta * delta;
1758  boxes_overlap = false;
1759  }
1760  else if (min2 > max1)
1761  {
1762  const auto delta = max1 - min2;
1763  curr_distance += delta * delta;
1764  boxes_overlap = false;
1765  }
1766  }
1767 
1768  if (boxes_overlap)
1769  return -1.0; /* all overlaps are treated the same */
1770 
1771  if (curr_distance < min_distance)
1772  min_distance = curr_distance;
1773  }
1774  }
1775 
1776  return min_distance;
1777 }

◆ broadcastAndUpdateGrainData()

void GrainTracker::broadcastAndUpdateGrainData ( )
protected

Broadcast essential Grain information to all processors.

This method is used to get certain attributes like centroids distributed and whether or not a grain intersects a boundary updated.

Definition at line 371 of file GrainTracker.C.

Referenced by finalize().

372 {
373  TIME_SECTION(_broadcast_update);
374 
375  std::vector<PartialFeatureData> root_feature_data;
376  std::vector<std::string> send_buffer(1), recv_buffer;
377 
378  if (_is_master)
379  {
380  root_feature_data.reserve(_feature_sets.size());
381 
382  // Populate a subset of the information in a small data structure
383  std::transform(_feature_sets.begin(),
384  _feature_sets.end(),
385  std::back_inserter(root_feature_data),
386  [](FeatureData & feature) {
387  PartialFeatureData partial_feature;
388  partial_feature.boundary_intersection = feature._boundary_intersection;
389  partial_feature.id = feature._id;
390  partial_feature.centroid = feature._centroid;
391  partial_feature.status = feature._status;
392  return partial_feature;
393  });
394 
395  std::ostringstream oss;
396  dataStore(oss, root_feature_data, this);
397  send_buffer[0].assign(oss.str());
398  }
399 
400  // Broadcast the data to all ranks
401  _communicator.broadcast_packed_range((void *)(nullptr),
402  send_buffer.begin(),
403  send_buffer.end(),
404  (void *)(nullptr),
405  std::back_inserter(recv_buffer));
406 
407  // Unpack and update
408  if (!_is_master)
409  {
410  std::istringstream iss;
411  iss.str(recv_buffer[0]);
412  iss.clear();
413 
414  dataLoad(iss, root_feature_data, this);
415 
416  for (const auto & partial_data : root_feature_data)
417  {
418  // See if this processor has a record of this grain
419  if (partial_data.id < _feature_id_to_local_index.size() &&
420  _feature_id_to_local_index[partial_data.id] != invalid_size_t)
421  {
422  auto & grain = _feature_sets[_feature_id_to_local_index[partial_data.id]];
423  grain._boundary_intersection = partial_data.boundary_intersection;
424  grain._centroid = partial_data.centroid;
425  if (partial_data.status == Status::INACTIVE)
426  grain._status = Status::INACTIVE;
427  }
428  }
429  }
430 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
const PerfID _broadcast_update
Definition: GrainTracker.h:255
void dataLoad(std::istream &stream, GrainTracker::PartialFeatureData &feature, void *context)
Definition: GrainTracker.C:38
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) ...
void dataStore(std::ostream &stream, GrainTracker::PartialFeatureData &feature, void *context)
Definition: GrainTracker.C:28

◆ buildFeatureIdToLocalIndices()

void FeatureFloodCount::buildFeatureIdToLocalIndices ( unsigned int  max_id)
protectedinherited

This method builds a lookup map for retrieving the right local feature (by index) given a global index or id.

max_id is passed to size the vector properly and may or may not be a globally consistent number. The assumption is that any id that is later queried from this object that is higher simply doesn't exist on the local processor.

Definition at line 655 of file FeatureFloodCount.C.

Referenced by assignGrains(), FeatureFloodCount::scatterAndUpdateRanks(), and trackGrains().

656 {
657  _feature_id_to_local_index.assign(max_id + 1, invalid_size_t);
658  for (MooseIndex(_feature_sets) feature_index = 0; feature_index < _feature_sets.size();
659  ++feature_index)
660  {
661  if (_feature_sets[feature_index]._status != Status::INACTIVE)
662  {
663  mooseAssert(_feature_sets[feature_index]._id <= max_id,
664  "Feature ID out of range(" << _feature_sets[feature_index]._id << ')');
665  _feature_id_to_local_index[_feature_sets[feature_index]._id] = feature_index;
666  }
667  }
668 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
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) ...

◆ buildLocalToGlobalIndices()

void FeatureFloodCount::buildLocalToGlobalIndices ( std::vector< std::size_t > &  local_to_global_all,
std::vector< int > &  counts 
) const
protectedvirtualinherited

This routine populates a stacked vector of local to global indices per rank and the associated count vector for scattering the vector to the ranks.

The individual vectors can be different sizes. The ith vector will be distributed to the ith processor including the master rank. e.g. [ ... n_0 ] [ ... n_1 ] ... [ ... n_m ]

It is intended to be overridden in derived classes.

Definition at line 609 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::scatterAndUpdateRanks().

611 {
612  mooseAssert(_is_master, "This method must only be called on the root processor");
613 
614  counts.assign(_n_procs, 0);
615  // Now size the individual counts vectors based on the largest index seen per processor
616  for (const auto & feature : _feature_sets)
617  for (const auto & local_index_pair : feature._orig_ids)
618  {
619  // local_index_pair.first = ranks, local_index_pair.second = local_index
620  mooseAssert(local_index_pair.first < _n_procs, "Processor ID is out of range");
621  if (local_index_pair.second >= static_cast<std::size_t>(counts[local_index_pair.first]))
622  counts[local_index_pair.first] = local_index_pair.second + 1;
623  }
624 
625  // Build the offsets vector
626  unsigned int globalsize = 0;
627  std::vector<int> offsets(_n_procs); // Type is signed for use with the MPI API
628  for (MooseIndex(offsets) i = 0; i < offsets.size(); ++i)
629  {
630  offsets[i] = globalsize;
631  globalsize += counts[i];
632  }
633 
634  // Finally populate the master vector
635  local_to_global_all.resize(globalsize, FeatureFloodCount::invalid_size_t);
636  for (const auto & feature : _feature_sets)
637  {
638  // Get the local indices from the feature and build a map
639  for (const auto & local_index_pair : feature._orig_ids)
640  {
641  auto rank = local_index_pair.first;
642  mooseAssert(rank < _n_procs, rank << ", " << _n_procs);
643 
644  auto local_index = local_index_pair.second;
645  auto stacked_local_index = offsets[rank] + local_index;
646 
647  mooseAssert(stacked_local_index < globalsize,
648  "Global index: " << stacked_local_index << " is out of range");
649  local_to_global_all[stacked_local_index] = feature._id;
650  }
651  }
652 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
const processor_id_type _n_procs
Convenience variable holding the number of processors in this simulation.

◆ centroidRegionDistance()

Real GrainTracker::centroidRegionDistance ( std::vector< MeshTools::BoundingBox > &  bboxes1,
std::vector< MeshTools::BoundingBox > &  bboxes2 
) const
protected

This method returns the minimum periodic distance between the centroids of two vectors of bounding boxes.

Find the minimum centroid distance between any to pieces of the grains.

Definition at line 1703 of file GrainTracker.C.

Referenced by trackGrains().

1705 {
1709  auto min_distance = std::numeric_limits<Real>::max();
1710  for (const auto & bbox1 : bboxes1)
1711  {
1712  const auto centroid_point1 = (bbox1.max() + bbox1.min()) / 2.0;
1713 
1714  for (const auto & bbox2 : bboxes2)
1715  {
1716  const auto centroid_point2 = (bbox2.max() + bbox2.min()) / 2.0;
1717 
1718  // Here we'll calculate a distance between the centroids
1719  auto curr_distance = _mesh.minPeriodicDistance(_var_number, centroid_point1, centroid_point2);
1720 
1721  if (curr_distance < min_distance)
1722  min_distance = curr_distance;
1723  }
1724  }
1725 
1726  return min_distance;
1727 }
unsigned long _var_number
This variable is used to build the periodic node map.
MooseMesh & _mesh
A reference to the mesh.

◆ clearDataStructures()

void FeatureFloodCount::clearDataStructures ( )
protectedvirtualinherited

Helper routine for clearing up data structures during initialize and prior to parallel communication.

Definition at line 321 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::communicateAndMerge().

322 {
323 }

◆ communicateAndMerge()

void FeatureFloodCount::communicateAndMerge ( )
protectedinherited

This routine handles all of the serialization, communication and deserialization of the data structures containing FeatureData objects.

The libMesh packed range routines handle the communication of the individual string buffers. Here we need to create a container to hold our type to serialize. It'll always be size one because we are sending a single byte stream of all the data to other processors. The stream need not be the same size on all processors.

Additionally we need to create a different container to hold the received byte buffers. The container type need not match the send container type. However, We do know the number of incoming buffers (num processors) so we'll go ahead and use a vector.

When we distribute merge work, we are reducing computational work by adding more communication. Each of the first _n_vars processors will receive one variable worth of information to merge. After each of those processors has merged that information, it'll be sent to the master processor where final consolidation will occur.

Send the data from all processors to the first _n_vars processors to create a complete global feature maps for each variable.

A call to gather_packed_range seems to populate the receiving buffer on all processors, not just the receiving buffer on the actual receiving processor. If we plan to call this function repeatedly, we must clear the buffers each time on all non-receiving processors. On the actual receiving processor, we'll save off the buffer for use later.

The FeatureFloodCount and derived algorithms rely on having the data structures intact on all non-zero ranks. This is because local-only information (local entities) is never communicated and thus must remain intact. However, the distributed merging will destroy that information. The easiest thing to do is to swap out the data structure while we perform the distributed merge work.

Send the data from the merging processors to the root to create a complete global feature map.

Send the data from all processors to the root to create a complete global feature map.

Definition at line 402 of file FeatureFloodCount.C.

Referenced by finalize(), and FeatureFloodCount::finalize().

403 {
404  TIME_SECTION(_comm_and_merge);
405 
406  // First we need to transform the raw data into a usable data structure
408 
416  std::vector<std::string> send_buffers(1);
417 
424  std::vector<std::string> recv_buffers, deserialize_buffers;
425 
433  {
434  auto rank = processor_id();
435  bool is_merging_processor = rank < _n_vars;
436 
437  if (is_merging_processor)
438  recv_buffers.reserve(_app.n_processors());
439 
440  for (MooseIndex(_n_vars) i = 0; i < _n_vars; ++i)
441  {
442  serialize(send_buffers[0], i);
443 
448  _communicator.gather_packed_range(i,
449  (void *)(nullptr),
450  send_buffers.begin(),
451  send_buffers.end(),
452  std::back_inserter(recv_buffers));
453 
460  if (rank == i)
461  recv_buffers.swap(deserialize_buffers);
462  else
463  recv_buffers.clear();
464  }
465 
466  // Setup a new communicator for doing merging communication operations
467  Parallel::Communicator merge_comm;
468 
469  // TODO: Update to MPI_UNDEFINED when libMesh bug is fixed.
470  _communicator.split(is_merging_processor ? 0 : 1, rank, merge_comm);
471 
472  if (is_merging_processor)
473  {
481  std::vector<std::list<FeatureData>> tmp_data(_partial_feature_sets.size());
482  tmp_data.swap(_partial_feature_sets);
483 
484  deserialize(deserialize_buffers, processor_id());
485 
486  send_buffers[0].clear();
487  recv_buffers.clear();
488  deserialize_buffers.clear();
489 
490  // Merge one variable's worth of data
491  mergeSets();
492 
493  // Now we need to serialize again to send to the master (only the processors who did work)
494  serialize(send_buffers[0]);
495 
496  // Free up as much memory as possible here before we do global communication
498 
503  merge_comm.gather_packed_range(0,
504  (void *)(nullptr),
505  send_buffers.begin(),
506  send_buffers.end(),
507  std::back_inserter(recv_buffers));
508 
509  if (_is_master)
510  {
511  // The root process now needs to deserialize all of the data
512  deserialize(recv_buffers);
513 
514  send_buffers[0].clear();
515  recv_buffers.clear();
516 
517  consolidateMergedFeatures(&tmp_data);
518  }
519  else
520  // Restore our original data on non-zero ranks
521  tmp_data.swap(_partial_feature_sets);
522  }
523  }
524 
525  // Serialized merging (master does all the work)
526  else
527  {
528  if (_is_master)
529  recv_buffers.reserve(_app.n_processors());
530 
531  serialize(send_buffers[0]);
532 
533  // Free up as much memory as possible here before we do global communication
535 
540  _communicator.gather_packed_range(0,
541  (void *)(nullptr),
542  send_buffers.begin(),
543  send_buffers.end(),
544  std::back_inserter(recv_buffers));
545 
546  if (_is_master)
547  {
548  // The root process now needs to deserialize all of the data
549  deserialize(recv_buffers);
550  recv_buffers.clear();
551 
552  mergeSets();
553 
555  }
556  }
557 
558  // Make sure that feature count is communicated to all ranks
559  _communicator.broadcast(_feature_count);
560 }
const std::size_t _n_vars
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...
const PerfID _comm_and_merge
const bool _is_master
Convenience variable for testing master rank.
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...
virtual void clearDataStructures()
Helper routine for clearing up data structures during initialize and prior to parallel communication...
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...
virtual void mergeSets()
This routine is called on the master rank only and stitches together the partial feature pieces seen ...
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
const bool _distribute_merge_work
Keeps track of whether we are distributing the merge work.
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...
void prepareDataForTransfer()
This routine uses the local flooded data to build up the local feature data structures (_feature_sets...

◆ communicateHaloMap()

void GrainTracker::communicateHaloMap ( )
protected

Finally remove halo markings from interior regions. This step is necessary because we expand halos before we do communication but that expansion can and will likely go into the interior of the grain (from a single processor's perspective). We could expand halos after merging, but that would likely be less scalable.

Definition at line 1617 of file GrainTracker.C.

Referenced by updateFieldInfo().

1618 {
1619  if (_compute_halo_maps)
1620  {
1621  // rank var_index entity_id
1622  std::vector<std::pair<std::size_t, dof_id_type>> halo_ids_all;
1623 
1624  std::vector<int> counts;
1625  std::vector<std::pair<std::size_t, dof_id_type>> local_halo_ids;
1626  std::size_t counter = 0;
1627 
1628  const bool isDistributedMesh = _mesh.isDistributedMesh();
1629 
1630  if (_is_master)
1631  {
1632  std::vector<std::vector<std::pair<std::size_t, dof_id_type>>> root_halo_ids(_n_procs);
1633  counts.resize(_n_procs);
1634 
1635  // Loop over the _halo_ids "field" and build minimal lists for all of the other ranks
1636  for (MooseIndex(_halo_ids) var_index = 0; var_index < _halo_ids.size(); ++var_index)
1637  {
1638  for (const auto & entity_pair : _halo_ids[var_index])
1639  {
1640  auto entity_id = entity_pair.first;
1641  if (isDistributedMesh)
1642  {
1643  // Check to see which contiguous range this entity ID falls into
1644  auto range_it =
1645  std::lower_bound(_all_ranges.begin(),
1646  _all_ranges.end(),
1647  entity_id,
1648  [](const std::pair<dof_id_type, dof_id_type> range,
1649  dof_id_type entity_id) { return range.second < entity_id; });
1650 
1651  mooseAssert(range_it != _all_ranges.end(), "No range round?");
1652 
1653  // Recover the index from the iterator
1654  auto proc_id = std::distance(_all_ranges.begin(), range_it);
1655 
1656  // Now add this halo entity to the map for the corresponding proc to scatter latter
1657  root_halo_ids[proc_id].push_back(std::make_pair(var_index, entity_id));
1658  }
1659  else
1660  {
1661  DofObject * halo_entity;
1662  if (_is_elemental)
1663  halo_entity = _mesh.queryElemPtr(entity_id);
1664  else
1665  halo_entity = _mesh.queryNodePtr(entity_id);
1666 
1667  if (halo_entity)
1668  root_halo_ids[halo_entity->processor_id()].push_back(
1669  std::make_pair(var_index, entity_id));
1670  }
1671  }
1672  }
1673 
1674  // Build up the counts vector for MPI scatter
1675  std::size_t global_count = 0;
1676  for (const auto & vector_ref : root_halo_ids)
1677  {
1678  std::copy(vector_ref.begin(), vector_ref.end(), std::back_inserter(halo_ids_all));
1679  counts[counter] = vector_ref.size();
1680  global_count += counts[counter++];
1681  }
1682  }
1683 
1684  _communicator.scatter(halo_ids_all, counts, local_halo_ids);
1685 
1686  // Now add the contributions from the root process to the processor local maps
1687  for (const auto & halo_pair : local_halo_ids)
1688  _halo_ids[halo_pair.first].emplace(std::make_pair(halo_pair.second, halo_pair.first));
1689 
1696  for (const auto & grain : _feature_sets)
1697  for (auto local_id : grain._local_ids)
1698  _halo_ids[grain._var_index].erase(local_id);
1699  }
1700 }
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
std::vector< std::map< dof_id_type, int > > _halo_ids
The data structure for looking up halos around features.
const bool _compute_halo_maps
Indicates whether or not to communicate halo map information with all ranks.
std::vector< std::pair< dof_id_type, dof_id_type > > _all_ranges
Data structure to hold element ID ranges when using Distributed Mesh (populated on rank 0 only) ...
Definition: GrainTracker.h:249
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
const processor_id_type _n_procs
Convenience variable holding the number of processors in this simulation.
MooseMesh & _mesh
A reference to the mesh.
static unsigned int counter

◆ compareValueWithThreshold()

bool FeatureFloodCount::compareValueWithThreshold ( Real  entity_value,
Real  threshold 
) const
protectedinherited

This method is used to determine whether the current entity value is part of a feature or not.

Comparisons can either be greater than or less than the threshold which is controlled via input parameter.

Definition at line 1383 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::isNewFeatureOrConnectedRegion().

1384 {
1385  return ((_use_less_than_threshold_comparison && (entity_value >= threshold)) ||
1386  (!_use_less_than_threshold_comparison && (entity_value <= threshold)));
1387 }
const bool _use_less_than_threshold_comparison
Use less-than when comparing values against the threshold value.

◆ computeMinDistancesFromGrain()

void GrainTracker::computeMinDistancesFromGrain ( FeatureData &  grain,
std::vector< std::list< GrainDistance >> &  min_distances 
)
protected

Populates and sorts a min_distances vector with the minimum distances to all grains in the simulation for a given grain.

There are _vars.size() entries in the outer vector, one for each order parameter. A list of grains with the same OP are ordered in lists per OP.

In the diagram below assume we have 4 order parameters. The grain with the asterisk needs to be remapped. All order parameters are used in neighboring grains. For all "touching" grains, the value of the corresponding entry in min_distances will be a negative integer representing the number of immediate neighbors with that order parameter.

Note: Only the first member of the pair (the distance) is shown in the array below. e.g. [-2.0, -max, -1.0, -2.0]

After sorting, variable index 2 (value: -1.0) be at the end of the array and will be the first variable we attempt to renumber the current grain to.

   __       ___
     \  0  /   \
   2  \___/  1  \___
      /   \     /   \
   __/  1  \___/  2  \
     \  *  /   \     /
   3  \___/  3  \___/
      /   \     /
   __/  0  \___/

See if we have any completely open OPs (excluding reserve order parameters) or the order parameter corresponding to this grain, we need to put them in the list or the grain tracker won't realize that those vars are available for remapping.

Definition at line 1170 of file GrainTracker.C.

Referenced by attemptGrainRenumber().

1172 {
1196  for (MooseIndex(_feature_sets) i = 0; i < _feature_sets.size(); ++i)
1197  {
1198  auto & other_grain = _feature_sets[i];
1199 
1200  if (other_grain._var_index == grain._var_index || other_grain._var_index >= _reserve_op_index)
1201  continue;
1202 
1203  auto target_var_index = other_grain._var_index;
1204  auto target_grain_index = i;
1205  auto target_grain_id = other_grain._id;
1206 
1207  Real curr_bbox_diff = boundingRegionDistance(grain._bboxes, other_grain._bboxes);
1208 
1209  GrainDistance grain_distance_obj(
1210  curr_bbox_diff, target_var_index, target_grain_index, target_grain_id);
1211 
1212  // To handle touching halos we penalize the top pick each time we see another
1213  if (curr_bbox_diff == -1.0 && !min_distances[target_var_index].empty())
1214  {
1215  Real last_distance = min_distances[target_var_index].begin()->_distance;
1216  if (last_distance < 0)
1217  grain_distance_obj._distance += last_distance;
1218  }
1219 
1220  // Insertion sort into a list
1221  auto insert_it = min_distances[target_var_index].begin();
1222  while (insert_it != min_distances[target_var_index].end() && !(grain_distance_obj < *insert_it))
1223  ++insert_it;
1224  min_distances[target_var_index].insert(insert_it, grain_distance_obj);
1225  }
1226 
1232  for (MooseIndex(_vars) var_index = 0; var_index < _reserve_op_index; ++var_index)
1233  {
1234  // Don't put an entry in for matching variable indices (i.e. we can't remap to ourselves)
1235  if (grain._var_index == var_index)
1236  continue;
1237 
1238  if (min_distances[var_index].empty())
1239  min_distances[var_index].emplace_front(std::numeric_limits<Real>::max(), var_index);
1240  }
1241 }
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
This struct is used to hold distance information to other grains in the simulation.
Definition: GrainTracker.h:263
Real boundingRegionDistance(std::vector< MeshTools::BoundingBox > &bboxes1, std::vector< MeshTools::BoundingBox > &bboxes2) const
This method returns the minimum periodic distance between two vectors of bounding boxes...
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
const std::size_t _reserve_op_index
The cutoff index where if variable index >= this number, no remapping TO that variable will occur...
Definition: GrainTracker.h:194

◆ deserialize()

void FeatureFloodCount::deserialize ( std::vector< std::string > &  serialized_buffers,
unsigned int  var_num = invalid_id 
)
protectedinherited

This routine takes the vector of byte buffers (one for each processor), deserializes them into a series of FeatureSet objects, and appends them to the _feature_sets data structure.

Note: It is assumed that local processor information may already be stored in the _feature_sets data structure so it is not cleared before insertion.

Usually we have the local processor data already in the _partial_feature_sets data structure. However, if we are doing distributed merge work, we also need to preserve all of the original data for use in later stages of the algorithm so it'll have been swapped out with clean buffers. This leaves us a choice, either we just duplicate the Features from the original data structure after we've swapped out the buffer, or we go ahead and unpack data that we would normally already have. So during distributed merging, that's exactly what we'll do. Later however when the master is doing the final consolidating, we'll opt to just skip the local unpacking. To tell the difference, between these two modes, we just need to see if a var_num was passed in.

Definition at line 1051 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::communicateAndMerge().

1052 {
1053  // The input string stream used for deserialization
1054  std::istringstream iss;
1055 
1056  auto rank = processor_id();
1057 
1058  for (MooseIndex(serialized_buffers) proc_id = 0; proc_id < serialized_buffers.size(); ++proc_id)
1059  {
1071  if (var_num == invalid_id && proc_id == rank)
1072  continue;
1073 
1074  iss.str(serialized_buffers[proc_id]); // populate the stream with a new buffer
1075  iss.clear(); // reset the string stream state
1076 
1077  // Load the gathered data into the data structure.
1078  if (var_num == invalid_id)
1079  dataLoad(iss, _partial_feature_sets, this);
1080  else
1081  dataLoad(iss, _partial_feature_sets[var_num], this);
1082  }
1083 }
void dataLoad(std::istream &stream, FeatureFloodCount::FeatureData &feature, void *context)
static const unsigned int invalid_id
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...

◆ doesFeatureIntersectBoundary()

bool GrainTracker::doesFeatureIntersectBoundary ( unsigned int  feature_id) const
overridevirtual

Returns a Boolean indicating whether this feature intersects any boundary.

Reimplemented from FeatureFloodCount.

Definition at line 175 of file GrainTracker.C.

176 {
177  // TODO: This data structure may need to be turned into a Multimap
178  mooseAssert(feature_id < _feature_id_to_local_index.size(), "Grain ID out of bounds");
179 
180  auto feature_index = _feature_id_to_local_index[feature_id];
181  if (feature_index != invalid_size_t)
182  {
183  mooseAssert(feature_index < _feature_sets.size(), "Grain index out of bounds");
184  return _feature_sets[feature_index]._boundary_intersection != BoundaryIntersection::NONE;
185  }
186 
187  return false;
188 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
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) ...

◆ execute()

void GrainTracker::execute ( )
overridevirtual

Reimplemented from FeatureFloodCount.

Definition at line 256 of file GrainTracker.C.

257 {
258  // Don't track grains if the current simulation step is before the specified tracking step
259  if (_t_step < _tracking_step)
260  return;
261 
262  if (_poly_ic_uo && _first_time)
263  return;
264 
266 }
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
virtual void execute() override
const PolycrystalUserObjectBase * _poly_ic_uo
An optional IC UserObject which can provide initial data structures to this object.
Definition: GrainTracker.h:215
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181

◆ expandEdgeHalos()

void FeatureFloodCount::expandEdgeHalos ( unsigned int  num_layers_to_expand)
protectedinherited

This method expands the existing halo set by some width determined by the passed in value.

This method does NOT mask off any local IDs.

Create a copy of the halo set so that as we insert new ids into the set we don't continue to iterate on those new ids.

We have to handle disjoint halo IDs slightly differently. Once you are disjoint, you can't go back so make sure that we keep placing these IDs in the disjoint set.

Definition at line 1492 of file FeatureFloodCount.C.

Referenced by finalize(), and PolycrystalUserObjectBase::finalize().

1493 {
1494  if (num_layers_to_expand == 0)
1495  return;
1496 
1497  TIME_SECTION(_expand_halos);
1498 
1499  for (auto & list_ref : _partial_feature_sets)
1500  {
1501  for (auto & feature : list_ref)
1502  {
1503  for (MooseIndex(num_layers_to_expand) halo_level = 0; halo_level < num_layers_to_expand;
1504  ++halo_level)
1505  {
1510  FeatureData::container_type orig_halo_ids(feature._halo_ids);
1511  for (auto entity : orig_halo_ids)
1512  {
1513  if (_is_elemental)
1514  visitElementalNeighbors(_mesh.elemPtr(entity),
1515  &feature,
1516  /*expand_halos_only =*/true,
1517  /*disjoint_only =*/false);
1518  else
1519  visitNodalNeighbors(_mesh.nodePtr(entity),
1520  &feature,
1521  /*expand_halos_only =*/true);
1522  }
1523 
1528  FeatureData::container_type disjoint_orig_halo_ids(feature._disjoint_halo_ids);
1529  for (auto entity : disjoint_orig_halo_ids)
1530  {
1531  if (_is_elemental)
1532  visitElementalNeighbors(_mesh.elemPtr(entity),
1533 
1534  &feature,
1535  /*expand_halos_only =*/true,
1536  /*disjoint_only =*/true);
1537  else
1538  visitNodalNeighbors(_mesh.nodePtr(entity),
1539 
1540  &feature,
1541  /*expand_halos_only =*/true);
1542  }
1543  }
1544  }
1545  }
1546 }
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...
std::set< dof_id_type > container_type
The primary underlying container type used to hold the data in each FeatureData.
void visitElementalNeighbors(const Elem *elem, FeatureData *feature, bool expand_halos_only, bool disjoint_only)
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
const PerfID _expand_halos
MooseMesh & _mesh
A reference to the mesh.

◆ expandPointHalos()

void FeatureFloodCount::expandPointHalos ( )
protectedinherited

This method takes all of the partial features and expands the local, ghosted, and halo sets around those regions to account for the diffuse interface.

Rather than using any kind of recursion here, we simply expand the region by all "point" neighbors from the actual grain cells since all point neighbors will contain contributions to the region.

To expand the feature element region to the actual flooded region (nodal basis) we need to add in all point neighbors of the current local region for each feature. This is because the elemental variable influence spreads from the elemental data out exactly one element from every mesh point.

Definition at line 1430 of file FeatureFloodCount.C.

1431 {
1432  const auto & node_to_elem_map = _mesh.nodeToActiveSemilocalElemMap();
1433  FeatureData::container_type expanded_local_ids;
1434  auto my_processor_id = processor_id();
1435 
1442  for (auto & list_ref : _partial_feature_sets)
1443  {
1444  for (auto & feature : list_ref)
1445  {
1446  expanded_local_ids.clear();
1447 
1448  for (auto entity : feature._local_ids)
1449  {
1450  const Elem * elem = _mesh.elemPtr(entity);
1451  mooseAssert(elem, "elem pointer is NULL");
1452 
1453  // Get the nodes on a current element so that we can add in point neighbors
1454  auto n_nodes = elem->n_vertices();
1455  for (MooseIndex(n_nodes) i = 0; i < n_nodes; ++i)
1456  {
1457  const Node * current_node = elem->node_ptr(i);
1458 
1459  auto elem_vector_it = node_to_elem_map.find(current_node->id());
1460  if (elem_vector_it == node_to_elem_map.end())
1461  mooseError("Error in node to elem map");
1462 
1463  const auto & elem_vector = elem_vector_it->second;
1464 
1465  std::copy(elem_vector.begin(),
1466  elem_vector.end(),
1467  std::insert_iterator<FeatureData::container_type>(expanded_local_ids,
1468  expanded_local_ids.end()));
1469 
1470  // Now see which elements need to go into the ghosted set
1471  for (auto entity : elem_vector)
1472  {
1473  const Elem * neighbor = _mesh.elemPtr(entity);
1474  mooseAssert(neighbor, "neighbor pointer is NULL");
1475 
1476  if (neighbor->processor_id() != my_processor_id)
1477  feature._ghosted_ids.insert(feature._ghosted_ids.end(), elem->id());
1478  }
1479  }
1480  }
1481 
1482  // Replace the existing local ids with the expanded local ids
1483  feature._local_ids.swap(expanded_local_ids);
1484 
1485  // Copy the expanded local_ids into the halo_ids container
1486  feature._halo_ids = feature._local_ids;
1487  }
1488  }
1489 }
std::set< dof_id_type > container_type
The primary underlying container type used to hold the data in each FeatureData.
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
MooseMesh & _mesh
A reference to the mesh.

◆ featureCentroid()

Point FeatureFloodCount::featureCentroid ( unsigned int  feature_id) const
virtualinherited

Returns the centroid of the designated feature (only supported without periodic boundaries)

Definition at line 865 of file FeatureFloodCount.C.

Referenced by FeatureVolumeVectorPostprocessor::execute().

866 {
867  if (feature_id >= _feature_id_to_local_index.size())
868  return invalid_id;
869 
870  auto local_index = _feature_id_to_local_index[feature_id];
871 
872  Real invalid_coord = std::numeric_limits<Real>::max();
873  Point p(invalid_coord, invalid_coord, invalid_coord);
874  if (local_index != invalid_size_t)
875  {
876  mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
877  p = _feature_sets[local_index]._centroid;
878  }
879  return p;
880 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
static const unsigned int invalid_id
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) ...

◆ finalize()

void GrainTracker::finalize ( )
overridevirtual

Assign or Track Grains

Broadcast essential data

Remap Grains

Reimplemented from FeatureFloodCount.

Definition at line 313 of file GrainTracker.C.

314 {
315  // Don't track grains if the current simulation step is before the specified tracking step
316  if (_t_step < _tracking_step)
317  return;
318 
319  TIME_SECTION(_finalize_timer);
320 
321  // Expand the depth of the halos around all grains
322  auto num_halo_layers = _halo_level >= 1
323  ? _halo_level - 1
324  : 0; // The first level of halos already exists so subtract one
325 
326  if (_poly_ic_uo && _first_time)
328  else
329  {
330  expandEdgeHalos(num_halo_layers);
331 
332  // Build up the grain map on the root processor
334  }
335 
339  if (_first_time)
340  assignGrains();
341  else
342  trackGrains();
343 
344  if (_verbosity_level > 1)
345  _console << "Finished inside of trackGrains" << std::endl;
346 
351 
355  if (_remap)
356  remapGrains();
357 
358  updateFieldInfo();
359  if (_verbosity_level > 1)
360  _console << "Finished inside of updateFieldInfo\n";
361 
362  // Set the first time flag false here (after all methods of finalize() have completed)
363  _first_time = false;
364 
365  // TODO: Release non essential memory
366  if (_verbosity_level > 0)
367  _console << "Finished inside of GrainTracker\n" << std::endl;
368 }
void remapGrains()
This method is called after trackGrains to remap grains that are too close to each other...
Definition: GrainTracker.C:898
void expandEdgeHalos(unsigned int num_layers_to_expand)
This method expands the existing halo set by some width determined by the passed in value...
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
void trackGrains()
On subsequent time_steps, incoming FeatureData objects are compared to previous time_step information...
Definition: GrainTracker.C:481
void communicateAndMerge()
This routine handles all of the serialization, communication and deserialization of the data structur...
virtual void updateFieldInfo() override
This method is used to populate any of the data structures used for storing field data (nodal or elem...
const PolycrystalUserObjectBase * _poly_ic_uo
An optional IC UserObject which can provide initial data structures to this object.
Definition: GrainTracker.h:215
void prepopulateState(const FeatureFloodCount &ffc_object)
This method extracts the necessary state from the passed in object necessary to continue tracking gra...
Definition: GrainTracker.C:281
void broadcastAndUpdateGrainData()
Broadcast essential Grain information to all processors.
Definition: GrainTracker.C:371
const short _verbosity_level
Verbosity level controlling the amount of information printed to the console.
Definition: GrainTracker.h:220
const PerfID _finalize_timer
Timers.
Definition: GrainTracker.h:252
const bool _remap
Inidicates whether remapping should be done or not (remapping is independent of tracking) ...
Definition: GrainTracker.h:200
void assignGrains()
When the tracking phase starts (_t_step == _tracking_step) it assigns a unique id to every FeatureDat...
Definition: GrainTracker.C:433
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181
const unsigned short _halo_level
The thickness of the halo surrounding each grain.
Definition: GrainTracker.h:184

◆ flood()

bool FeatureFloodCount::flood ( const DofObject *  dof_object,
std::size_t  current_index 
)
protectedinherited

This method will check if the current entity is above the supplied threshold and "mark" it.

It will then inspect neighboring entities that are above the connecting threshold and add them to the current feature.

Returns
Boolean indicating whether a new feature was found while exploring the current entity.

If we reach this point (i.e. we haven't continued to the next queue entry), we've found a new mesh entity that's part of a feature. We need to mark the entity as visited at this point (and not before!) to avoid infinite recursion. If you mark the node too early you risk not coloring in a whole feature any time a "connecting threshold" is used since we may have already visited this entity earlier but it was in-between two thresholds.

See if this particular entity cell contributes to the centroid calculation. We only deal with elemental floods and only count it if it's owned by the current processor to avoid skewing the result.

Definition at line 1259 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::execute(), and PolycrystalUserObjectBase::execute().

1261 {
1262  // if (dof_object == nullptr || dof_object == libMesh::remote_elem)
1263  // return false;
1264  mooseAssert(dof_object, "DOF object is nullptr");
1265  mooseAssert(_entity_queue.empty(), "Entity queue is not empty when starting a feature");
1266 
1267  // Kick off the exploration of a new feature
1268  _entity_queue.push_front(dof_object);
1269 
1270  bool return_value = false;
1271  FeatureData * feature = nullptr;
1272  while (!_entity_queue.empty())
1273  {
1274  const DofObject * curr_dof_object = _entity_queue.back();
1275  const Elem * elem = _is_elemental ? static_cast<const Elem *>(curr_dof_object) : nullptr;
1276  _entity_queue.pop_back();
1277 
1278  // Retrieve the id of the current entity
1279  auto entity_id = curr_dof_object->id();
1280 
1281  // Has this entity already been marked? - if so move along
1282  if (current_index != invalid_size_t &&
1283  _entities_visited[current_index].find(entity_id) != _entities_visited[current_index].end())
1284  continue;
1285 
1286  // Are we outside of the range we should be working in?
1287  if (_is_elemental && !_dof_map.is_evaluable(*elem))
1288  continue;
1289 
1290  // See if the current entity either starts a new feature or continues an existing feature
1291  auto new_id = invalid_id; // Writable reference to hold an optional id;
1292  Status status =
1293  Status::INACTIVE; // Status is inactive until we find an entity above the starting threshold
1294 
1295  // Make sure that the Assembly object has the right element and subdomain information set
1296  // since we are moving through the mesh in a manual fashion.
1297  if (_is_elemental)
1298  _fe_problem.setCurrentSubdomainID(elem, 0);
1299 
1300  if (!isNewFeatureOrConnectedRegion(curr_dof_object, current_index, feature, status, new_id))
1301  {
1302  // If we have an active feature, we just found a halo entity
1303  if (feature)
1304  feature->_halo_ids.insert(feature->_halo_ids.end(), entity_id);
1305  continue;
1306  }
1307 
1308  mooseAssert(current_index != invalid_size_t, "current_index is invalid");
1309 
1318  return_value = true;
1319  _entities_visited[current_index].insert(entity_id);
1320 
1321  auto map_num = _single_map_mode ? decltype(current_index)(0) : current_index;
1322 
1323  // New Feature (we need to create it and add it to our data structure)
1324  if (!feature)
1325  {
1326  _partial_feature_sets[map_num].emplace_back(
1327  current_index, _feature_count++, processor_id(), status);
1328 
1329  // Get a handle to the feature we will update (always the last feature in the data structure)
1330  feature = &_partial_feature_sets[map_num].back();
1331 
1332  // If new_id is valid, we'll set it in the feature here.
1333  if (new_id != invalid_id)
1334  feature->_id = new_id;
1335  }
1336 
1337  // Insert the current entity into the local ids data structure
1338  feature->_local_ids.insert(feature->_local_ids.end(), entity_id);
1339 
1345  if (_is_elemental && processor_id() == curr_dof_object->processor_id())
1346  {
1347  // Keep track of how many elements participate in the centroid averaging
1348  feature->_vol_count++;
1349 
1350  // Sum the centroid values for now, we'll average them later
1351  feature->_centroid += elem->centroid();
1352 
1353  // // Does the volume intersect the boundary?
1354  // if (_all_boundary_entity_ids.find(elem->id()) != _all_boundary_entity_ids.end())
1355  // feature->_intersects_boundary = true;
1356  }
1357 
1358  if (_is_elemental)
1360  feature,
1361  /*expand_halos_only =*/false,
1362  /*disjoint_only =*/false);
1363  else
1364  visitNodalNeighbors(static_cast<const Node *>(curr_dof_object),
1365  feature,
1366  /*expand_halos_only =*/false);
1367  }
1368 
1369  return return_value;
1370 }
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...
static const std::size_t invalid_size_t
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure...
std::vector< std::set< dof_id_type > > _entities_visited
This variable keeps track of which nodes have been visited during execution.
void visitElementalNeighbors(const Elem *elem, FeatureData *feature, bool expand_halos_only, bool disjoint_only)
const DofMap & _dof_map
Reference to the dof_map containing the coupled variables.
static const unsigned int invalid_id
const bool _single_map_mode
This variable is used to indicate whether or not multiple maps are used during flooding.
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...
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...
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
std::deque< const DofObject * > _entity_queue
The data structure for maintaining entities to flood during discovery.

◆ getConnectingThreshold()

Real FeatureFloodCount::getConnectingThreshold ( std::size_t  current_index) const
protectedvirtualinherited

Return the "connecting" comparison threshold to use when inspecting an entity during the flood stage.

Definition at line 1377 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::isNewFeatureOrConnectedRegion().

1378 {
1380 }

◆ getCoupledVars()

const std::vector<MooseVariable *>& FeatureFloodCount::getCoupledVars ( ) const
inlineinherited

Returns a const vector to the coupled variable pointers.

Definition at line 96 of file FeatureFloodCount.h.

Referenced by AverageGrainVolume::AverageGrainVolume(), and FeatureVolumeVectorPostprocessor::FeatureVolumeVectorPostprocessor().

96 { return _vars; }
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.

◆ getEntityValue()

Real GrainTracker::getEntityValue ( dof_id_type  node_id,
FieldType  field_type,
std::size_t  var_index = 0 
) const
overridevirtual

Reimplemented from FeatureFloodCount.

Definition at line 120 of file GrainTracker.C.

Referenced by OutputEulerAngles::precalculateValue(), and EulerAngleProvider2RGBAux::precalculateValue().

123 {
124  if (_t_step < _tracking_step)
125  return 0;
126 
127  return FeatureFloodCount::getEntityValue(entity_id, field_type, var_index);
128 }
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181
virtual Real getEntityValue(dof_id_type entity_id, FieldType field_type, std::size_t var_index=0) const

◆ getFeatures()

const std::vector<FeatureData>& FeatureFloodCount::getFeatures ( ) const
inlineinherited

Return a constant reference to the vector of all discovered features.

Definition at line 337 of file FeatureFloodCount.h.

Referenced by prepopulateState().

337 { return _feature_sets; }
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.

◆ getFeatureVar()

unsigned int GrainTracker::getFeatureVar ( unsigned int  feature_id) const
overridevirtual

Returns the variable representing the passed in feature.

Reimplemented from FeatureFloodCount.

Definition at line 137 of file GrainTracker.C.

138 {
139  return FeatureFloodCount::getFeatureVar(feature_id);
140 }
virtual unsigned int getFeatureVar(unsigned int feature_id) const
Returns the variable representing the passed in feature.

◆ getFECoupledVars()

const std::vector<MooseVariableFEBase *>& FeatureFloodCount::getFECoupledVars ( ) const
inlineinherited

Returns a const vector to the coupled MooseVariableFEBase pointers.

Definition at line 99 of file FeatureFloodCount.h.

Referenced by AverageGrainVolume::AverageGrainVolume().

99 { return _fe_vars; }
std::vector< MooseVariableFEBase * > _fe_vars
The vector of coupled in variables.

◆ getGrainCentroid()

Point GrainTracker::getGrainCentroid ( unsigned int  grain_id) const
overridevirtual

Returns the centroid for the given grain number.

Implements GrainTrackerInterface.

Definition at line 157 of file GrainTracker.C.

158 {
159  mooseAssert(grain_id < _feature_id_to_local_index.size(), "Grain ID out of bounds");
160  auto grain_index = _feature_id_to_local_index[grain_id];
161 
162  if (grain_index != invalid_size_t)
163  {
164  mooseAssert(_feature_id_to_local_index[grain_id] < _feature_sets.size(),
165  "Grain index out of bounds");
166  // Note: This value is parallel consistent, see GrainTracker::broadcastAndUpdateGrainData()
167  return _feature_sets[_feature_id_to_local_index[grain_id]]._centroid;
168  }
169 
170  // Inactive grain
171  return Point();
172 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
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) ...

◆ getNewGrainIDs()

std::vector< unsigned int > GrainTracker::getNewGrainIDs ( ) const
overridevirtual

This method returns all of the new ids generated in an invocation of the GrainTracker.

Reimplemented from GrainTrackerInterface.

Definition at line 886 of file GrainTracker.C.

887 {
888  std::vector<unsigned int> new_ids(_max_curr_grain_id - _old_max_grain_id);
889  auto new_id = _old_max_grain_id + 1;
890 
891  // Generate the new ids
892  std::iota(new_ids.begin(), new_ids.end(), new_id);
893 
894  return new_ids;
895 }
unsigned int _old_max_grain_id
The previous max grain id (needed to figure out which ids are new in a given step) ...
Definition: GrainTracker.h:240
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243

◆ getNextUniqueID()

unsigned int GrainTracker::getNextUniqueID ( )
protected

Retrieve the next unique grain number if a new grain is detected during trackGrains.

This method handles reserve order parameter indices properly. Direct access to the next index should be avoided.

Get the next unique grain ID but make sure to respect reserve ids. Note, that the first valid ID for a new grain is _reserve_grain_first_index + _n_reserve_ops because _reserve_grain_first_index IS a valid index. It does not point to the last valid index of the non-reserved grains.

Definition at line 1780 of file GrainTracker.C.

Referenced by trackGrains().

1781 {
1790  _reserve_grain_first_index + _n_reserve_ops /* no +1 here!*/);
1791 
1792  return _max_curr_grain_id;
1793 }
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243
static const unsigned int invalid_id
unsigned int _reserve_grain_first_index
Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) ...
Definition: GrainTracker.h:237
const unsigned short _n_reserve_ops
The number of reserved order parameters.
Definition: GrainTracker.h:190

◆ getNumberActiveFeatures()

std::size_t FeatureFloodCount::getNumberActiveFeatures ( ) const
inherited

Return the number of active features.

Definition at line 780 of file FeatureFloodCount.C.

Referenced by AverageGrainVolume::getValue().

781 {
782  // Note: This value is parallel consistent, see FeatureFloodCount::communicateAndMerge()
783  return _feature_count;
784 }
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...

◆ getNumberActiveGrains()

std::size_t GrainTracker::getNumberActiveGrains ( ) const
overridevirtual

Returns the number of active grains current stored in the GrainTracker.

This value is the same value reported when the GrainTracker (FeatureFloodObject) is used as a Postprocessor.

Note: This value will count each piece of a split grain (often encountered in EBSD data sets).

Implements GrainTrackerInterface.

Definition at line 143 of file GrainTracker.C.

144 {
145  // Note: This value is parallel consistent, see FeatureFloodCount::communicateAndMerge()
146  return _feature_count;
147 }
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...

◆ getThreshold()

Real GrainTracker::getThreshold ( std::size_t  current_index) const
overrideprotectedvirtual

Return the starting comparison threshold to use when inspecting an entity during the flood stage.

Reimplemented from FeatureFloodCount.

Definition at line 269 of file GrainTracker.C.

270 {
271  // If we are inspecting a reserve op parameter, we need to make sure
272  // that there is an entity above the reserve_op threshold before
273  // starting the flood of the feature.
274  if (var_index >= _reserve_op_index)
275  return _reserve_op_threshold;
276  else
277  return _step_threshold;
278 }
const Real _reserve_op_threshold
The threshold above (or below) where a grain may be found on a reserve op field.
Definition: GrainTracker.h:197
const std::size_t _reserve_op_index
The cutoff index where if variable index >= this number, no remapping TO that variable will occur...
Definition: GrainTracker.h:194

◆ getTotalFeatureCount()

std::size_t GrainTracker::getTotalFeatureCount ( ) const
overridevirtual

Returns the total feature count (active and inactive ids, useful for sizing vectors)

Since the FeatureFloodCount object doesn't maintain any information about features between invocations. The maximum id in use is simply the number of features.

Reimplemented from FeatureFloodCount.

Definition at line 150 of file GrainTracker.C.

151 {
152  // Note: This value is parallel consistent, see assignGrains()/trackGrains()
154 }
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243
static const unsigned int invalid_id

◆ getValue()

Real FeatureFloodCount::getValue ( )
overridevirtualinherited

Reimplemented in FauxGrainTracker.

Definition at line 774 of file FeatureFloodCount.C.

775 {
776  return static_cast<Real>(_feature_count);
777 }
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...

◆ getVarToFeatureVector()

const std::vector< unsigned int > & GrainTracker::getVarToFeatureVector ( dof_id_type  elem_id) const
overridevirtual

Returns a list of active unique feature ids for a particular element.

The vector is indexed by variable number with each entry containing either an invalid size_t type (no feature active at that location) or a feature id if the variable is non-zero at that location.

Reimplemented from FeatureFloodCount.

Definition at line 131 of file GrainTracker.C.

Referenced by ComputePolycrystalElasticityTensor::computeQpElasticityTensor().

132 {
134 }
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.

◆ initialize()

void GrainTracker::initialize ( )
overridevirtual

If we are passed the first time, we need to save the existing grains before beginning the tracking on the current step. We'll do that with a swap since the _feature_sets contents will be cleared anyway.

Reimplemented from FeatureFloodCount.

Definition at line 213 of file GrainTracker.C.

214 {
215  // Don't track grains if the current simulation step is before the specified tracking step
216  if (_t_step < _tracking_step)
217  return;
218 
224  if (!_first_time)
226 
228 }
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
std::vector< FeatureData > _feature_sets_old
This data structure holds the map of unique grains from the previous time step.
Definition: GrainTracker.h:212
virtual void initialize() override
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181

◆ initialSetup()

void FeatureFloodCount::initialSetup ( )
overridevirtualinherited

Size the empty var to features vector to the number of coupled variables. This empty vector (but properly sized) vector is returned for elements that are queried but are not in the structure (which also shouldn't happen). The user is warned in this case but this helps avoid extra bounds checking in user code and avoids segfaults.

Reimplemented in PolycrystalUserObjectBase.

Definition at line 268 of file FeatureFloodCount.C.

Referenced by PolycrystalUserObjectBase::initialSetup().

269 {
270  // We need one map per coupled variable for normal runs to support overlapping features
271  _entities_visited.resize(_vars.size());
272 
273  // Get a pointer to the PeriodicBoundaries buried in libMesh
274  _pbs = _fe_problem.getNonlinearSystemBase().dofMap().get_periodic_boundaries();
275 
276  meshChanged();
277 
286 }
const std::size_t _n_vars
std::vector< std::set< dof_id_type > > _entities_visited
This variable keeps track of which nodes have been visited during execution.
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
static const unsigned int invalid_id
PeriodicBoundaries * _pbs
A pointer to the periodic boundary constraints object.
std::vector< unsigned int > _empty_var_to_features
virtual void meshChanged() override

◆ isBoundaryEntity()

template<typename T >
bool FeatureFloodCount::isBoundaryEntity ( const T *  entity) const
protectedinherited

Returns a Boolean indicating whether the entity is on one of the desired boundaries.

Definition at line 1765 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::visitNeighborsHelper().

1766 {
1767  mooseAssert(_bnd_elem_range, "Boundary Element Range is nullptr");
1768 
1769  if (entity)
1770  for (const auto & belem : *_bnd_elem_range)
1771  // Only works for Elements
1772  if (belem->_elem->id() == entity->id() && hasBoundary(belem->_bnd_id))
1773  return true;
1774 
1775  return false;
1776 }
ConstBndElemRange * _bnd_elem_range
Boundary element range pointer.

◆ isElemental()

bool FeatureFloodCount::isElemental ( ) const
inlineinherited

Definition at line 115 of file FeatureFloodCount.h.

Referenced by FeatureFloodCountAux::FeatureFloodCountAux().

115 { return _is_elemental; }
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)

◆ isFeaturePercolated()

bool GrainTracker::isFeaturePercolated ( unsigned int  feature_id) const
overridevirtual

Returns a Boolean indicating whether this feature is percolated (e.g.

intersects at least two different boundaries from sets supplied by the user)

Reimplemented from FeatureFloodCount.

Definition at line 191 of file GrainTracker.C.

192 {
193  // TODO: This data structure may need to be turned into a Multimap
194  mooseAssert(feature_id < _feature_id_to_local_index.size(), "Grain ID out of bounds");
195 
196  auto feature_index = _feature_id_to_local_index[feature_id];
197  if (feature_index != invalid_size_t)
198  {
199  mooseAssert(feature_index < _feature_sets.size(), "Grain index out of bounds");
200  bool primary = ((_feature_sets[feature_index]._boundary_intersection &
203  bool secondary = ((_feature_sets[feature_index]._boundary_intersection &
206  return (primary && secondary);
207  }
208 
209  return false;
210 }
static const std::size_t invalid_size_t
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
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) ...

◆ isNewFeatureOrConnectedRegion()

bool FeatureFloodCount::isNewFeatureOrConnectedRegion ( const DofObject *  dof_object,
std::size_t &  current_index,
FeatureData *&  feature,
Status status,
unsigned int &  new_id 
)
protectedvirtualinherited

Method called during the recursive flood routine that should return whether or not the current entity is part of the current feature (if one is being explored), or if it's the start of a new feature.

If the value is only above the connecting threshold, it's still part of a feature but possibly part of one that we'll discard if there is never any starting threshold encountered.

Reimplemented in PolycrystalUserObjectBase.

Definition at line 1390 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::flood().

1395 {
1396  // Get the value of the current variable for the current entity
1397  Real entity_value;
1398  if (_is_elemental)
1399  {
1400  const Elem * elem = static_cast<const Elem *>(dof_object);
1401  std::vector<Point> centroid(1, elem->centroid());
1402  _subproblem.reinitElemPhys(elem, centroid, 0, /* suppress_displaced_init = */ true);
1403  entity_value = _vars[current_index]->sln()[0];
1404  }
1405  else
1406  entity_value = _vars[current_index]->getNodalValue(*static_cast<const Node *>(dof_object));
1407 
1408  // If the value compares against our starting threshold, this is definitely part of a feature
1409  // we'll keep
1410  if (compareValueWithThreshold(entity_value, getThreshold(current_index)))
1411  {
1412  Status * status_ptr = &status;
1413 
1414  if (feature)
1415  status_ptr = &feature->_status;
1416 
1417  // Update an existing feature's status or clear the flag on the passed in status
1418  *status_ptr &= ~Status::INACTIVE;
1419  return true;
1420  }
1421 
1426  return compareValueWithThreshold(entity_value, getConnectingThreshold(current_index));
1427 }
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure...
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
virtual Real getConnectingThreshold(std::size_t current_index) const
Return the "connecting" comparison threshold to use when inspecting an entity during the flood stage...
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
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...
virtual Real getThreshold(std::size_t current_index) const
Return the starting comparison threshold to use when inspecting an entity during the flood stage...

◆ mergeSets()

void FeatureFloodCount::mergeSets ( )
protectedvirtualinherited

This routine is called on the master rank only and stitches together the partial feature pieces seen on any processor.

Insert the new entity at the end of the list so that it may be checked against all other partial features again.

Now remove both halves the merged features: it2 contains the "moved" feature cell just inserted at the back of the list, it1 contains the mostly empty other half. We have to be careful about the order in which these two elements are deleted. We delete it2 first since we don't care where its iterator points after the deletion. We are going to break out of this loop anyway. If we delete it1 first, it may end up pointing at the same location as it2 which after the second deletion would cause both of the iterators to be invalidated.

Reimplemented in PolycrystalUserObjectBase.

Definition at line 1086 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::communicateAndMerge().

1087 {
1088  TIME_SECTION(_merge_timer);
1089 
1090  // When working with _distribute_merge_work all of the maps will be empty except for one
1091  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
1092  {
1093  for (auto it1 = _partial_feature_sets[map_num].begin();
1094  it1 != _partial_feature_sets[map_num].end();
1095  /* No increment on it1 */)
1096  {
1097  bool merge_occured = false;
1098  for (auto it2 = _partial_feature_sets[map_num].begin();
1099  it2 != _partial_feature_sets[map_num].end();
1100  ++it2)
1101  {
1102  if (it1 != it2 && areFeaturesMergeable(*it1, *it2))
1103  {
1104  it2->merge(std::move(*it1));
1105 
1110  _partial_feature_sets[map_num].emplace_back(std::move(*it2));
1111 
1121  _partial_feature_sets[map_num].erase(it2);
1122  it1 = _partial_feature_sets[map_num].erase(it1); // it1 is incremented here!
1123 
1124  // A merge occurred, this is used to determine whether or not we increment the outer
1125  // iterator
1126  merge_occured = true;
1127 
1128  // We need to start the list comparison over for the new it1 so break here
1129  break;
1130  }
1131  } // it2 loop
1132 
1133  if (!merge_occured) // No merges so we need to manually increment the outer iterator
1134  ++it1;
1135 
1136  } // it1 loop
1137  } // map loop
1138 }
const PerfID _merge_timer
virtual bool areFeaturesMergeable(const FeatureData &f1, const FeatureData &f2) const
Method for determining whether two features are mergeable.
const std::size_t _maps_size
Convenience variable holding the size of all the datastructures size by the number of maps...
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...

◆ meshChanged()

void GrainTracker::meshChanged ( )
overridevirtual

Reimplemented from FeatureFloodCount.

Definition at line 231 of file GrainTracker.C.

232 {
233  // Update the element ID ranges for use when computing halo maps
234  if (_compute_halo_maps && _mesh.isDistributedMesh())
235  {
236  _all_ranges.clear();
237 
238  auto range = std::make_pair(std::numeric_limits<dof_id_type>::max(),
239  std::numeric_limits<dof_id_type>::min());
240  for (const auto & current_elem : _mesh.getMesh().active_local_element_ptr_range())
241  {
242  auto id = current_elem->id();
243  if (id < range.first)
244  range.first = id;
245  else if (id > range.second)
246  range.second = id;
247  }
248 
249  _communicator.gather(0, range, _all_ranges);
250  }
251 
253 }
const bool _compute_halo_maps
Indicates whether or not to communicate halo map information with all ranks.
std::vector< std::pair< dof_id_type, dof_id_type > > _all_ranges
Data structure to hold element ID ranges when using Distributed Mesh (populated on rank 0 only) ...
Definition: GrainTracker.h:249
virtual void meshChanged() override
MooseMesh & _mesh
A reference to the mesh.

◆ newGrainCreated()

void GrainTracker::newGrainCreated ( unsigned int  new_grain_id)
protectedvirtual

This method is called when a new grain is detected.

It can be overridden by a derived class to handle setting new properties on the newly created grain.

Reimplemented in GrainDataTracker< T >, GrainDataTracker< RankFourTensorTempl >, and GrainDataTracker< RankFourTensor >.

Definition at line 865 of file GrainTracker.C.

Referenced by assignGrains(), and trackGrains().

866 {
867  if (!_first_time && _is_master)
868  {
869  mooseAssert(new_grain_id < _feature_id_to_local_index.size(), "new_grain_id is out of bounds");
870  auto grain_index = _feature_id_to_local_index[new_grain_id];
871  mooseAssert(grain_index != invalid_size_t && grain_index < _feature_sets.size(),
872  "new_grain_id appears to be invalid");
873 
874  const auto & grain = _feature_sets[grain_index];
875  _console << COLOR_YELLOW
876  << "\n*****************************************************************************"
877  << "\nCouldn't find a matching grain while working on variable index: "
878  << grain._var_index << "\nCreating new unique grain: " << new_grain_id << '\n'
879  << grain
880  << "\n*****************************************************************************\n"
881  << COLOR_DEFAULT;
882  }
883 }
static const std::size_t invalid_size_t
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
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) ...

◆ numCoupledVars()

std::size_t FeatureFloodCount::numCoupledVars ( ) const
inlineinherited

Returns the number of coupled varaibles.

Definition at line 87 of file FeatureFloodCount.h.

87 { return _n_vars; }
const std::size_t _n_vars

◆ prepareDataForTransfer()

void FeatureFloodCount::prepareDataForTransfer ( )
protectedinherited

This routine uses the local flooded data to build up the local feature data structures (_feature_sets).

This routine does not perform any communication so the _feature_sets data structure will only contain information from the local processor after calling this routine. Any existing data in the _feature_sets structure is destroyed by calling this routine.

_feature_sets layout: The outer vector is sized to one when _single_map_mode == true, otherwise it is sized for the number of coupled variables. The inner list represents the flooded regions (local only after this call but fully populated after parallel communication and stitching).

If using a vector container, we need to sort all of the data structures for later operations such as checking for intersection and merging. The following "sort" function does nothing when invoked on a std::set.

Save off the min entity id present in the feature to uniquely identify the feature regardless of n_procs

Definition at line 982 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::communicateAndMerge().

983 {
984  TIME_SECTION(_prepare_for_transfer);
985 
986  MeshBase & mesh = _mesh.getMesh();
987 
988  FeatureData::container_type local_ids_no_ghost, set_difference;
989 
990  for (auto & list_ref : _partial_feature_sets)
991  {
992  for (auto & feature : list_ref)
993  {
994  // See if the feature intersects a boundary or perhaps one of the percolation boundaries.
996 
997  // Periodic node ids
999 
1005  FeatureFloodCount::sort(feature._ghosted_ids);
1006  FeatureFloodCount::sort(feature._local_ids);
1007  FeatureFloodCount::sort(feature._halo_ids);
1008  FeatureFloodCount::sort(feature._disjoint_halo_ids);
1009  FeatureFloodCount::sort(feature._periodic_nodes);
1010 
1011  // Now extend the bounding box by the halo region
1012  if (_is_elemental)
1013  feature.updateBBoxExtremes(mesh);
1014  else
1015  {
1016  for (auto & halo_id : feature._halo_ids)
1017  updateBBoxExtremesHelper(feature._bboxes[0], mesh.node(halo_id));
1018  }
1019 
1020  mooseAssert(!feature._local_ids.empty(), "local entity ids cannot be empty");
1021 
1026  feature._min_entity_id = *feature._local_ids.begin();
1027  }
1028  }
1029 }
void appendPeriodicNeighborNodes(FeatureData &feature) const
This routine adds the periodic node information to our data structure prior to packing the data this ...
static void sort(std::set< T > &)
std::set< dof_id_type > container_type
The primary underlying container type used to hold the data in each FeatureData.
void updateBBoxExtremesHelper(MeshTools::BoundingBox &bbox, const Point &node)
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
void updateBoundaryIntersections(FeatureData &feature) const
Update the feature&#39;s attributes to indicate boundary intersections.
const PerfID _prepare_for_transfer
MooseMesh & _mesh
A reference to the mesh.

◆ prepopulateState()

void GrainTracker::prepopulateState ( const FeatureFloodCount ffc_object)
protected

This method extracts the necessary state from the passed in object necessary to continue tracking grains.

This method is meant to be used with the PolycrystalUserobjectBase class that sets up initial conditions for Polycrystal simulations. We can use the state of that object rather than rediscovering everything ourselves.

The minimum information needed to bootstrap the GrainTracker is as follows: _feature_sets _feature_count

Definition at line 281 of file GrainTracker.C.

Referenced by finalize().

282 {
283  mooseAssert(_first_time, "This method should only be called on the first invocation");
284 
285  _feature_sets.clear();
286 
292  if (_is_master)
293  {
294  const auto & features = ffc_object.getFeatures();
295  for (auto & feature : features)
296  _feature_sets.emplace_back(feature.duplicate());
297 
298  _feature_count = _feature_sets.size();
299  }
300  else
301  {
302  const auto & features = ffc_object.getFeatures();
303  _partial_feature_sets[0].clear();
304  for (auto & feature : features)
305  _partial_feature_sets[0].emplace_back(feature.duplicate());
306  }
307 
308  // Make sure that feature count is communicated to all ranks
309  _communicator.broadcast(_feature_count);
310 }
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const std::vector< FeatureData > & getFeatures() const
Return a constant reference to the vector of all discovered features.
const bool _is_master
Convenience variable for testing master rank.
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...

◆ remapGrains()

void GrainTracker::remapGrains ( )
protected

This method is called after trackGrains to remap grains that are too close to each other.

Map used for communicating remap indices to all ranks This map isn't populated until after the remap loop. It's declared here before we enter the root scope since it's needed by all ranks during the broadcast.

The remapping algorithm is recursive. We will use the status variable in each FeatureData to track which grains are currently being remapped so we don't have runaway recursion. To begin we need to clear all of the active (MARKED) flags (CLEAR).

Additionally we need to record each grain's variable index so that we can communicate changes to the non-root ranks later in a single batch.

We're not going to try very hard to look for a suitable remapping. Just set it to what we want and hope it all works out. Make the GrainTracker great again!

Loop over each grain and see if any grains represented by the same variable are "touching"

The remapping loop is complete but only on the master process. Now we need to build the remap map and communicate it to the remaining processors.

Since the remapping algorithm only runs on the root process, the variable index on the master's grains is inconsistent from the rest of the ranks. These are the grains with a status of DIRTY. As we build this map we will temporarily switch these variable indices back to the correct value so that all processors use the same algorithm to remap.

Definition at line 898 of file GrainTracker.C.

Referenced by finalize().

899 {
900  // Don't remap grains if the current simulation step is before the specified tracking step
901  if (_t_step < _tracking_step)
902  return;
903 
904  TIME_SECTION(_remap_timer);
905 
906  if (_verbosity_level > 1)
907  _console << "Running remap Grains\n" << std::endl;
908 
915  std::map<unsigned int, std::size_t> grain_id_to_new_var;
916 
917  // Items are added to this list when split grains are found
918  std::list<std::pair<std::size_t, std::size_t>> split_pairs;
919 
928  if (_is_master)
929  {
930  // Build the map to detect difference in _var_index mappings after the remap operation
931  std::map<unsigned int, std::size_t> grain_id_to_existing_var_index;
932  for (auto & grain : _feature_sets)
933  {
934  // Unmark the grain so it can be used in the remap loop
935  grain._status = Status::CLEAR;
936 
937  grain_id_to_existing_var_index[grain._id] = grain._var_index;
938  }
939 
940  // Make sure that all split pieces of any grain are on the same OP
941  for (MooseIndex(_feature_sets) i = 0; i < _feature_sets.size(); ++i)
942  {
943  auto & grain1 = _feature_sets[i];
944 
945  for (MooseIndex(_feature_sets) j = 0; j < _feature_sets.size(); ++j)
946  {
947  auto & grain2 = _feature_sets[j];
948  if (i == j)
949  continue;
950 
951  // The first condition below is there to prevent symmetric checks (duplicate values)
952  if (i < j && grain1._id == grain2._id)
953  {
954  split_pairs.push_front(std::make_pair(i, j));
955  if (grain1._var_index != grain2._var_index)
956  {
957  if (_verbosity_level > 0)
958  _console << COLOR_YELLOW << "Split Grain (#" << grain1._id
959  << ") detected on unmatched OPs (" << grain1._var_index << ", "
960  << grain2._var_index << ") attempting to remap to " << grain1._var_index
961  << ".\n"
962  << COLOR_DEFAULT;
963 
968  grain1._var_index = grain2._var_index;
969  grain1._status |= Status::DIRTY;
970  }
971  }
972  }
973  }
974 
978  bool any_grains_remapped = false;
979  bool grains_remapped;
980 
981  std::set<unsigned int> notify_ids;
982  do
983  {
984  grains_remapped = false;
985  notify_ids.clear();
986 
987  for (auto & grain1 : _feature_sets)
988  {
989  // We need to remap any grains represented on any variable index above the cuttoff
990  if (grain1._var_index >= _reserve_op_index)
991  {
992  if (_verbosity_level > 0)
993  _console << COLOR_YELLOW << "\nGrain #" << grain1._id
994  << " detected on a reserved order parameter #" << grain1._var_index
995  << ", remapping to another variable\n"
996  << COLOR_DEFAULT;
997 
998  for (MooseIndex(_max_remap_recursion_depth) max = 0; max <= _max_remap_recursion_depth;
999  ++max)
1000  if (max < _max_remap_recursion_depth)
1001  {
1002  if (attemptGrainRenumber(grain1, 0, max))
1003  break;
1004  }
1005  else if (!attemptGrainRenumber(grain1, 0, max))
1006  {
1007  _console << std::flush;
1008  std::stringstream oss;
1009  oss << "Unable to find any suitable order parameters for remapping while working "
1010  << "with Grain #" << grain1._id << ", which is on a reserve order parameter.\n"
1011  << "\n\nPossible Resolutions:\n"
1012  << "\t- Add more order parameters to your simulation (8 for 2D, 28 for 3D)\n"
1013  << "\t- Increase adaptivity or reduce your grain boundary widths\n"
1014  << "\t- Make sure you are not starting with too many grains for the mesh size\n";
1015  mooseError(oss.str());
1016  }
1017 
1018  grains_remapped = true;
1019  }
1020 
1021  for (auto & grain2 : _feature_sets)
1022  {
1023  // Don't compare a grain with itself and don't try to remap inactive grains
1024  if (&grain1 == &grain2)
1025  continue;
1026 
1027  if (grain1._var_index == grain2._var_index && // grains represented by same variable?
1028  grain1._id != grain2._id && // are they part of different grains?
1029  grain1.boundingBoxesIntersect(grain2) && // do bboxes intersect (coarse level)?
1030  grain1.halosIntersect(grain2)) // do they actually overlap (fine level)?
1031  {
1032  if (_verbosity_level > 0)
1033  _console << COLOR_YELLOW << "Grain #" << grain1._id << " intersects Grain #"
1034  << grain2._id << " (variable index: " << grain1._var_index << ")\n"
1035  << COLOR_DEFAULT;
1036 
1037  for (MooseIndex(_max_remap_recursion_depth) max = 0; max <= _max_remap_recursion_depth;
1038  ++max)
1039  {
1040  if (max < _max_remap_recursion_depth)
1041  {
1042  if (attemptGrainRenumber(grain1, 0, max))
1043  {
1044  grains_remapped = true;
1045  break;
1046  }
1047  }
1048  else if (!attemptGrainRenumber(grain1, 0, max) &&
1049  !attemptGrainRenumber(grain2, 0, max))
1050  {
1051  notify_ids.insert(grain1._id);
1052  notify_ids.insert(grain2._id);
1053  }
1054  }
1055  }
1056  }
1057  }
1058  any_grains_remapped |= grains_remapped;
1059  } while (grains_remapped);
1060 
1061  if (!notify_ids.empty())
1062  {
1063  _console << std::flush;
1064  std::stringstream oss;
1065  oss << "Unable to find any suitable order parameters for remapping while working "
1066  << "with the following grain IDs:\n"
1067  << Moose::stringify(notify_ids, ", ", "", true) << "\n\nPossible Resolutions:\n"
1068  << "\t- Add more order parameters to your simulation (8 for 2D, 28 for 3D)\n"
1069  << "\t- Increase adaptivity or reduce your grain boundary widths\n"
1070  << "\t- Make sure you are not starting with too many grains for the mesh size\n";
1071 
1072  if (_tolerate_failure)
1073  mooseWarning(oss.str());
1074  else
1075  mooseError(oss.str());
1076  }
1077 
1078  // Verify that split grains are still intact
1079  for (auto & split_pair : split_pairs)
1080  if (_feature_sets[split_pair.first]._var_index != _feature_sets[split_pair.first]._var_index)
1081  mooseError("Split grain remapped - This case is currently not handled");
1082 
1088  for (auto & grain : _feature_sets)
1089  {
1090  mooseAssert(grain_id_to_existing_var_index.find(grain._id) !=
1091  grain_id_to_existing_var_index.end(),
1092  "Missing unique ID");
1093 
1094  auto old_var_index = grain_id_to_existing_var_index[grain._id];
1095 
1096  if (old_var_index != grain._var_index)
1097  {
1098  mooseAssert(static_cast<bool>(grain._status & Status::DIRTY), "grain status is incorrect");
1099 
1100  grain_id_to_new_var.emplace_hint(
1101  grain_id_to_new_var.end(),
1102  std::pair<unsigned int, std::size_t>(grain._id, grain._var_index));
1103 
1112  grain._var_index = old_var_index;
1113  // Clear the DIRTY status as well for consistency
1114  grain._status &= ~Status::DIRTY;
1115  }
1116  }
1117 
1118  if (!grain_id_to_new_var.empty())
1119  {
1120  if (_verbosity_level > 1)
1121  {
1122  _console << "Final remapping tally:\n";
1123  for (const auto & remap_pair : grain_id_to_new_var)
1124  _console << "Grain #" << remap_pair.first << " var_index "
1125  << grain_id_to_existing_var_index[remap_pair.first] << " -> "
1126  << remap_pair.second << '\n';
1127  _console << "Communicating swaps with remaining processors..." << std::endl;
1128  }
1129  }
1130  } // root processor
1131 
1132  // Communicate the std::map to all ranks
1133  _communicator.broadcast(grain_id_to_new_var);
1134 
1135  // Perform swaps if any occurred
1136  if (!grain_id_to_new_var.empty())
1137  {
1138  // Cache for holding values during swaps
1139  std::vector<std::map<Node *, CacheValues>> cache(_n_vars);
1140 
1141  // Perform the actual swaps on all processors
1142  for (auto & grain : _feature_sets)
1143  {
1144  // See if this grain was remapped
1145  auto new_var_it = grain_id_to_new_var.find(grain._id);
1146  if (new_var_it != grain_id_to_new_var.end())
1147  swapSolutionValues(grain, new_var_it->second, cache, RemapCacheMode::FILL);
1148  }
1149 
1150  for (auto & grain : _feature_sets)
1151  {
1152  // See if this grain was remapped
1153  auto new_var_it = grain_id_to_new_var.find(grain._id);
1154  if (new_var_it != grain_id_to_new_var.end())
1155  swapSolutionValues(grain, new_var_it->second, cache, RemapCacheMode::USE);
1156  }
1157 
1158  _nl.solution().close();
1159  _nl.solutionOld().close();
1160  _nl.solutionOlder().close();
1161 
1162  _fe_problem.getNonlinearSystemBase().system().update();
1163 
1164  if (_verbosity_level > 1)
1165  _console << "Swaps complete" << std::endl;
1166  }
1167 }
const std::size_t _n_vars
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure...
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
NonlinearSystemBase & _nl
A reference to the nonlinear system (used for retrieving solution vectors)
Definition: GrainTracker.h:206
void swapSolutionValues(FeatureData &grain, std::size_t new_var_index, std::vector< std::map< Node *, CacheValues >> &cache, RemapCacheMode cache_mode)
A routine for moving all of the solution values from a given grain to a new variable number...
const short _verbosity_level
Verbosity level controlling the amount of information printed to the console.
Definition: GrainTracker.h:220
const PerfID _remap_timer
Definition: GrainTracker.h:253
bool attemptGrainRenumber(FeatureData &grain, unsigned int depth, unsigned int max_depth)
This is the recursive part of the remapping algorithm.
const int _tracking_step
The timestep to begin tracking grains.
Definition: GrainTracker.h:181
const std::size_t _reserve_op_index
The cutoff index where if variable index >= this number, no remapping TO that variable will occur...
Definition: GrainTracker.h:194
const unsigned short _max_remap_recursion_depth
Depth of renumbering recursion (a depth of zero means no recursion)
Definition: GrainTracker.h:187
const bool _tolerate_failure
Indicates whether we should continue after a remap failure (will result in non-physical results) ...
Definition: GrainTracker.h:203

◆ scatterAndUpdateRanks()

void FeatureFloodCount::scatterAndUpdateRanks ( )
protectedinherited

Calls buildLocalToGlobalIndices to build the individual local to global indicies for each rank and scatters that information to all ranks.

Finally, the non-master ranks update their own data structures to reflect the global mappings.

On non-root processors we can't maintain the full _feature_sets data structure since we don't have all of the global information. We'll move the items from the partial feature sets into a flat structure maintaining order and update the internal IDs with the proper global ID.

Important: Make sure we clear the local status if we received a valid global index for this feature. It's possible that we have a status of INVALID on the local processor because there was never any starting threshold found. However, the root processor wouldn't have sent an index if it didn't find a starting threshold connected to our local piece.

Definition at line 706 of file FeatureFloodCount.C.

Referenced by assignGrains(), FeatureFloodCount::finalize(), and trackGrains().

707 {
708  // local to global map (one per processor)
709  std::vector<int> counts;
710  std::vector<std::size_t> local_to_global_all;
711  if (_is_master)
712  buildLocalToGlobalIndices(local_to_global_all, counts);
713 
714  // Scatter local_to_global indices to all processors and store in class member variable
715  _communicator.scatter(local_to_global_all, counts, _local_to_global_feature_map);
716 
717  std::size_t largest_global_index = std::numeric_limits<std::size_t>::lowest();
718  if (!_is_master)
719  {
721 
728  for (auto & list_ref : _partial_feature_sets)
729  {
730  for (auto & feature : list_ref)
731  {
732  mooseAssert(feature._orig_ids.size() == 1, "feature._orig_ids length doesn't make sense");
733 
734  auto global_index = FeatureFloodCount::invalid_size_t;
735  auto local_index = feature._orig_ids.begin()->second;
736 
737  if (local_index < _local_to_global_feature_map.size())
738  global_index = _local_to_global_feature_map[local_index];
739 
740  if (global_index != FeatureFloodCount::invalid_size_t)
741  {
742  if (global_index > largest_global_index)
743  largest_global_index = global_index;
744 
745  // Set the correct global index
746  feature._id = global_index;
747 
755  feature._status &= ~Status::INACTIVE;
756 
757  // Move the feature into the correct place
758  _feature_sets[local_index] = std::move(feature);
759  }
760  }
761  }
762  }
763  else
764  {
765  for (auto global_index : local_to_global_all)
766  if (global_index != FeatureFloodCount::invalid_size_t && global_index > largest_global_index)
767  largest_global_index = global_index;
768  }
769 
770  buildFeatureIdToLocalIndices(largest_global_index);
771 }
static const std::size_t invalid_size_t
Status
This enumeration is used to indicate status of the grains in the _unique_grains data structure...
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
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 ...
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...
void buildFeatureIdToLocalIndices(unsigned int max_id)
This method builds a lookup map for retrieving the right local feature (by index) given a global inde...
std::vector< std::size_t > _local_to_global_feature_map
The vector recording the local to global feature indices.

◆ serialize()

void FeatureFloodCount::serialize ( std::string &  serialized_buffer,
unsigned int  var_num = invalid_id 
)
protectedinherited

This routines packs the _partial_feature_sets data into a structure suitable for parallel communication operations.

Definition at line 1032 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::communicateAndMerge().

1033 {
1034  // stream for serializing the _partial_feature_sets data structure to a byte stream
1035  std::ostringstream oss;
1036 
1037  mooseAssert(var_num == invalid_id || var_num < _partial_feature_sets.size(),
1038  "var_num out of range");
1039 
1040  // Serialize everything
1041  if (var_num == invalid_id)
1042  dataStore(oss, _partial_feature_sets, this);
1043  else
1044  dataStore(oss, _partial_feature_sets[var_num], this);
1045 
1046  // Populate the passed in string pointer with the string stream's buffer contents
1047  serialized_buffer.assign(oss.str());
1048 }
void dataStore(std::ostream &stream, FeatureFloodCount::FeatureData &feature, void *context)
static const unsigned int invalid_id
std::vector< std::list< FeatureData > > _partial_feature_sets
The data structure used to hold partial and communicated feature data, during the discovery and mergi...

◆ setsIntersect()

template<class InputIterator >
static bool FeatureFloodCount::setsIntersect ( InputIterator  first1,
InputIterator  last1,
InputIterator  first2,
InputIterator  last2 
)
inlinestaticprotectedinherited

This method detects whether two sets intersect without building a result set.

It exits as soon as any intersection is detected.

Definition at line 540 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::FeatureData::ghostedIntersect(), FeatureFloodCount::FeatureData::halosIntersect(), and FeatureFloodCount::FeatureData::periodicBoundariesIntersect().

544  {
545  while (first1 != last1 && first2 != last2)
546  {
547  if (*first1 == *first2)
548  return true;
549 
550  if (*first1 < *first2)
551  ++first1;
552  else if (*first1 > *first2)
553  ++first2;
554  }
555  return false;
556  }

◆ sortAndLabel()

void FeatureFloodCount::sortAndLabel ( )
protectedinherited

Sort and assign ids to features based on their position in the container after sorting.

Perform a sort to give a parallel unique sorting to the identified features. We use the "min_entity_id" inside each feature to assign it's position in the sorted vector.

Sanity check. Now that we've sorted the flattened vector of features we need to make sure that the counts vector still lines up appropriately with each feature's _var_index.

Definition at line 563 of file FeatureFloodCount.C.

Referenced by assignGrains(), and FeatureFloodCount::finalize().

564 {
565  mooseAssert(_is_master, "sortAndLabel can only be called on the master");
566 
572  std::sort(_feature_sets.begin(), _feature_sets.end());
573 
574 #ifndef NDEBUG
575 
580  unsigned int feature_offset = 0;
581  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
582  {
583  // Skip empty map checks
584  if (_feature_counts_per_map[map_num] == 0)
585  continue;
586 
587  // Check the begin and end of the current range
588  auto range_front = feature_offset;
589  auto range_back = feature_offset + _feature_counts_per_map[map_num] - 1;
590 
591  mooseAssert(range_front <= range_back && range_back < _feature_count,
592  "Indexing error in feature sets");
593 
594  if (!_single_map_mode && (_feature_sets[range_front]._var_index != map_num ||
595  _feature_sets[range_back]._var_index != map_num))
596  mooseError("Error in _feature_sets sorting, map index: ", map_num);
597 
598  feature_offset += _feature_counts_per_map[map_num];
599  }
600 #endif
601 
602  // Label the features with an ID based on the sorting (processor number independent value)
603  for (MooseIndex(_feature_sets) i = 0; i < _feature_sets.size(); ++i)
604  if (_feature_sets[i]._id == invalid_id)
605  _feature_sets[i]._id = i;
606 }
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
const bool _is_master
Convenience variable for testing master rank.
const std::size_t _maps_size
Convenience variable holding the size of all the datastructures size by the number of maps...
static const unsigned int invalid_id
const bool _single_map_mode
This variable is used to indicate whether or not multiple maps are used during flooding.
unsigned int _feature_count
The number of features seen by this object (same as summing _feature_counts_per_map) ...
std::vector< unsigned int > _feature_counts_per_map
The number of features seen by this object per map.

◆ swapSolutionValues()

void GrainTracker::swapSolutionValues ( FeatureData &  grain,
std::size_t  new_var_index,
std::vector< std::map< Node *, CacheValues >> &  cache,
RemapCacheMode  cache_mode 
)
protected

A routine for moving all of the solution values from a given grain to a new variable number.

It is called with different modes to only cache, or actually do the work, or bypass the cache altogether.

Definition at line 1419 of file GrainTracker.C.

Referenced by remapGrains().

1423 {
1424  MeshBase & mesh = _mesh.getMesh();
1425 
1426  // Remap the grain
1427  std::set<Node *> updated_nodes_tmp; // Used only in the elemental case
1428  for (auto entity : grain._local_ids)
1429  {
1430  if (_is_elemental)
1431  {
1432  Elem * elem = mesh.query_elem(entity);
1433  if (!elem)
1434  continue;
1435 
1436  for (unsigned int i = 0; i < elem->n_nodes(); ++i)
1437  {
1438  Node * curr_node = elem->node_ptr(i);
1439  if (updated_nodes_tmp.find(curr_node) == updated_nodes_tmp.end())
1440  {
1441  // cache this node so we don't attempt to remap it again within this loop
1442  updated_nodes_tmp.insert(curr_node);
1443  swapSolutionValuesHelper(curr_node, grain._var_index, new_var_index, cache, cache_mode);
1444  }
1445  }
1446  }
1447  else
1449  mesh.query_node_ptr(entity), grain._var_index, new_var_index, cache, cache_mode);
1450  }
1451 
1452  // Update the variable index in the unique grain datastructure after swaps are complete
1453  if (cache_mode == RemapCacheMode::USE || cache_mode == RemapCacheMode::BYPASS)
1454  grain._var_index = new_var_index;
1455 }
void swapSolutionValuesHelper(Node *curr_node, std::size_t curr_var_index, std::size_t new_var_index, std::vector< std::map< Node *, CacheValues >> &cache, RemapCacheMode cache_mode)
Helper method for actually performing the swaps.
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
MooseMesh & _mesh
A reference to the mesh.

◆ swapSolutionValuesHelper()

void GrainTracker::swapSolutionValuesHelper ( Node *  curr_node,
std::size_t  curr_var_index,
std::size_t  new_var_index,
std::vector< std::map< Node *, CacheValues >> &  cache,
RemapCacheMode  cache_mode 
)
protected

Helper method for actually performing the swaps.

Finally zero out the old variable. When using the FILL/USE combination to read/write variables, it's important to zero the variable on the FILL stage and not the USE stage. The reason for this is handling swaps as illustrated in the following diagram


/ \/ \ If adjacent grains (overlapping flood region) end up / 1 /\ 2 \ swapping variable indices and variables are zeroed on \ 2*\/ 1* / "USE", the overlap region will be incorrectly zeroed ___/___/ by whichever variable is written to second.

Definition at line 1458 of file GrainTracker.C.

Referenced by swapSolutionValues().

1463 {
1464  if (curr_node && curr_node->processor_id() == processor_id())
1465  {
1466  // Reinit the node so we can get and set values of the solution here
1467  _subproblem.reinitNode(curr_node, 0);
1468 
1469  // Local variables to hold values being transferred
1470  Real current, old = 0, older = 0;
1471  // Retrieve the value either from the old variable or cache
1472  if (cache_mode == RemapCacheMode::FILL || cache_mode == RemapCacheMode::BYPASS)
1473  {
1474  current = _vars[curr_var_index]->dofValues()[0];
1475  if (_is_transient)
1476  {
1477  old = _vars[curr_var_index]->dofValuesOld()[0];
1478  older = _vars[curr_var_index]->dofValuesOlder()[0];
1479  }
1480  }
1481  else // USE
1482  {
1483  const auto cache_it = cache[curr_var_index].find(curr_node);
1484  mooseAssert(cache_it != cache[curr_var_index].end(), "Error in cache");
1485  current = cache_it->second.current;
1486  old = cache_it->second.old;
1487  older = cache_it->second.older;
1488  }
1489 
1490  // Cache the value or use it!
1491  if (cache_mode == RemapCacheMode::FILL)
1492  {
1493  cache[curr_var_index][curr_node].current = current;
1494  cache[curr_var_index][curr_node].old = old;
1495  cache[curr_var_index][curr_node].older = older;
1496  }
1497  else // USE or BYPASS
1498  {
1499  const auto & dof_index = _vars[new_var_index]->nodalDofIndex();
1500 
1501  // Transfer this solution from the old to the current
1502  _nl.solution().set(dof_index, current);
1503  if (_is_transient)
1504  {
1505  _nl.solutionOld().set(dof_index, old);
1506  _nl.solutionOlder().set(dof_index, older);
1507  }
1508  }
1509 
1522  if (cache_mode == RemapCacheMode::FILL || cache_mode == RemapCacheMode::BYPASS)
1523  {
1524  const auto & dof_index = _vars[curr_var_index]->nodalDofIndex();
1525 
1526  // Set the DOF for the current variable to zero
1527  _nl.solution().set(dof_index, 0.0);
1528  if (_is_transient)
1529  {
1530  _nl.solutionOld().set(dof_index, 0.0);
1531  _nl.solutionOlder().set(dof_index, 0.0);
1532  }
1533  }
1534  }
1535 }
NonlinearSystemBase & _nl
A reference to the nonlinear system (used for retrieving solution vectors)
Definition: GrainTracker.h:206
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
const bool _is_transient
Boolean to indicate whether this is a Steady or Transient solve.
Definition: GrainTracker.h:246

◆ trackGrains()

void GrainTracker::trackGrains ( )
protected

On subsequent time_steps, incoming FeatureData objects are compared to previous time_step information to track grains between time steps.

This method updates the _feature_sets data structure. This method should only be called on the root processor

Only the master rank does tracking, the remaining ranks wait to receive local to global indices from the master.

To track grains across time steps, we will loop over our unique grains and link each one up with one of our new unique grains. The criteria for doing this will be to find the unique grain in the new list with a matching variable index whose centroid is closest to this unique grain.

The _feature_sets vector is constructed by _var_index so we can avoid looping over all indices. We can quickly jump to the first matching index to reduce the number of comparisons and terminate our loop when our variable index stops matching.

Don't try to do any matching unless the bounding boxes at least overlap. This is to avoid the corner case of having a grain split and a grain disappear during the same time step!

It's possible that multiple existing grains will map to a single new grain (indicated by finding multiple matches when we are building this map). This will happen any time a grain disappears during this time step. We need to figure out the rightful owner in this case and inactivate the old grain.

If the grain we just marked inactive was the one whose index was in the new grain to existing grain map (other_old_grain). Then we need to update the map to point to the new match winner.

At this point we have should have only two cases left to handle: Case 1: A grain in the new set who has an unset status (These are new grains, previously untracked) This case is easy to understand. Since we are matching up grains by looking at the old set and finding closest matches in the new set, any grain in the new set that isn't matched up is simply new since some other grain satisfied each and every request from the old set.

Case 2: A grain in the old set who has an unset status (These are inactive grains that haven't been marked) We can only fall into this case when the very last grain on a given variable disappears during the current time step. In that case we never have a matching _var_index in the comparison loop above so that old grain never competes for any new grain which means it can't be marked inactive in the loop above.

Now we need to figure out what kind of "new" grain this is. Is it a nucleating grain that we're just barely seeing for the first time or is it a "splitting" grain. A grain that gets pinched into two or more pieces usually as it is being absorbed by other grains or possibly due to external forces. We have to handle splitting grains this way so as to no confuse them with regular grains that just happen to be in contact in this step.

Splitting Grain: An grain that is unmatched by any old grain on the same order parameter with touching halos.

Nucleating Grain: A completely new grain appearing somewhere in the domain not overlapping any other grain's halo.

To figure out which case we are dealing with, we have to make another pass over all of the existing grains with matching variable indices to see if any of them have overlapping halos.

The "try-harder loop": OK so we still have an extra grain in the new set that isn't matched up against the old set and since the order parameter isn't reserved. We aren't really expecting a new grain. Let's try to make a few more attempts to see if this is a split grain even though it failed to match the criteria above. This might happen if the halo front is advancing too fast!

In this loop we'll make an attempt to match up this new grain to the old halos. If adaptivity is happening this could fail as elements in the new set may be at a different level than in the old set. If we get multiple matches, we'll compare the grain volumes (based on elements, not integrated to choose the closest).

Future ideas: Look at the volume fraction of the new grain and overlay it over the volume fraction of the old grain (would require more saved information, or an aux field hanging around (subject to projection problems).

Note that the old grains we are looking at will already be marked from the earlier tracking phase. We are trying to see if this unmatched grain is part of a larger whole. To do that we'll look at the halos across the time step.

Trigger callback for new grains

Definition at line 481 of file GrainTracker.C.

Referenced by finalize().

482 {
483  TIME_SECTION(_track_grains);
484 
485  mooseAssert(!_first_time, "Track grains may only be called when _tracking_step > _t_step");
486 
487  // Used to track indices for which to trigger the new grain callback on (used on all ranks)
489 
494  if (_is_master)
495  {
496  // Reset Status on active unique grains
497  std::vector<unsigned int> map_sizes(_maps_size);
498  for (auto & grain : _feature_sets_old)
499  {
500  if (grain._status != Status::INACTIVE)
501  {
502  grain._status = Status::CLEAR;
503  map_sizes[grain._var_index]++;
504  }
505  }
506 
507  // Print out stats on overall tracking changes per var_index
508  if (_verbosity_level > 0)
509  {
510  _console << "\nGrain Tracker Status:";
511  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
512  {
513  _console << "\nGrains active index " << map_num << ": " << map_sizes[map_num] << " -> "
514  << _feature_counts_per_map[map_num];
515  if (map_sizes[map_num] > _feature_counts_per_map[map_num])
516  _console << "--";
517  else if (map_sizes[map_num] < _feature_counts_per_map[map_num])
518  _console << "++";
519  }
520  _console << '\n' << std::endl;
521  }
522 
523  // Before we track grains, lets sort them so that we get parallel consistent answers
524  std::sort(_feature_sets.begin(), _feature_sets.end());
525 
532  std::vector<std::size_t> new_grain_index_to_existing_grain_index(_feature_sets.size(),
534 
535  for (MooseIndex(_feature_sets_old) old_grain_index = 0;
536  old_grain_index < _feature_sets_old.size();
537  ++old_grain_index)
538  {
539  auto & old_grain = _feature_sets_old[old_grain_index];
540 
541  if (old_grain._status == Status::INACTIVE) // Don't try to find matches for inactive grains
542  continue;
543 
544  std::size_t closest_match_index = invalid_size_t;
545  Real min_centroid_diff = std::numeric_limits<Real>::max();
546 
552  // clang-format off
553  auto start_it =
554  std::lower_bound(_feature_sets.begin(), _feature_sets.end(), old_grain._var_index,
555  [](const FeatureData & item, std::size_t var_index)
556  {
557  return item._var_index < var_index;
558  });
559  // clang-format on
560 
561  // We only need to examine grains that have matching variable indices
562  bool any_boxes_intersect = false;
563  for (MooseIndex(_feature_sets)
564  new_grain_index = std::distance(_feature_sets.begin(), start_it);
565  new_grain_index < _feature_sets.size() &&
566  _feature_sets[new_grain_index]._var_index == old_grain._var_index;
567  ++new_grain_index)
568  {
569  auto & new_grain = _feature_sets[new_grain_index];
570 
575  if (new_grain.boundingBoxesIntersect(old_grain))
576  {
577  any_boxes_intersect = true;
578  Real curr_centroid_diff = centroidRegionDistance(old_grain._bboxes, new_grain._bboxes);
579  if (curr_centroid_diff <= min_centroid_diff)
580  {
581  closest_match_index = new_grain_index;
582  min_centroid_diff = curr_centroid_diff;
583  }
584  }
585  }
586 
587  if (_verbosity_level > 2 && !any_boxes_intersect)
588  _console << "\nNo intersecting bounding boxes found while trying to match grain "
589  << old_grain;
590 
591  // found a match
592  if (closest_match_index != invalid_size_t)
593  {
600  auto curr_index = new_grain_index_to_existing_grain_index[closest_match_index];
601  if (curr_index != invalid_size_t)
602  {
603  // The new feature being competed for
604  auto & new_grain = _feature_sets[closest_match_index];
605 
606  // The other old grain competing to match up to the same new grain
607  auto & other_old_grain = _feature_sets_old[curr_index];
608 
609  auto centroid_diff1 = centroidRegionDistance(new_grain._bboxes, old_grain._bboxes);
610  auto centroid_diff2 = centroidRegionDistance(new_grain._bboxes, other_old_grain._bboxes);
611 
612  auto & inactive_grain = (centroid_diff1 < centroid_diff2) ? other_old_grain : old_grain;
613 
614  inactive_grain._status = Status::INACTIVE;
615  if (_verbosity_level > 0)
616  {
617  _console << COLOR_GREEN << "Marking Grain " << inactive_grain._id
618  << " as INACTIVE (variable index: " << inactive_grain._var_index << ")\n"
619  << COLOR_DEFAULT;
620  if (_verbosity_level > 1)
621  _console << inactive_grain;
622  }
623 
629  if (&inactive_grain == &other_old_grain)
630  new_grain_index_to_existing_grain_index[closest_match_index] = old_grain_index;
631  }
632  else
633  new_grain_index_to_existing_grain_index[closest_match_index] = old_grain_index;
634  }
635  }
636 
637  // Mark all resolved grain matches
638  for (MooseIndex(new_grain_index_to_existing_grain_index) new_index = 0;
639  new_index < new_grain_index_to_existing_grain_index.size();
640  ++new_index)
641  {
642  auto curr_index = new_grain_index_to_existing_grain_index[new_index];
643 
644  // This may be a new grain, we'll handle that case below
645  if (curr_index == invalid_size_t)
646  continue;
647 
648  mooseAssert(_feature_sets_old[curr_index]._id != invalid_id,
649  "Invalid ID in old grain structure");
650 
651  _feature_sets[new_index]._id = _feature_sets_old[curr_index]._id; // Transfer ID
652  _feature_sets[new_index]._status = Status::MARKED; // Mark the status in the new set
653  _feature_sets_old[curr_index]._status = Status::MARKED; // Mark the status in the old set
654  }
655 
670  // Case 1 (new grains in _feature_sets):
671  for (MooseIndex(_feature_sets) grain_num = 0; grain_num < _feature_sets.size(); ++grain_num)
672  {
673  auto & grain = _feature_sets[grain_num];
674 
675  // New Grain
676  if (grain._status == Status::CLEAR)
677  {
696  // clang-format off
697  auto start_it =
698  std::lower_bound(_feature_sets.begin(), _feature_sets.end(), grain._var_index,
699  [](const FeatureData & item, std::size_t var_index)
700  {
701  return item._var_index < var_index;
702  });
703  // clang-format on
704 
705  // Loop over matching variable indices
706  for (MooseIndex(_feature_sets)
707  new_grain_index = std::distance(_feature_sets.begin(), start_it);
708  new_grain_index < _feature_sets.size() &&
709  _feature_sets[new_grain_index]._var_index == grain._var_index;
710  ++new_grain_index)
711  {
712  auto & other_grain = _feature_sets[new_grain_index];
713 
714  // Splitting grain?
715  if (grain_num != new_grain_index && // Make sure indices aren't pointing at the same grain
716  other_grain._status == Status::MARKED && // and that the other grain is indeed marked
717  other_grain.boundingBoxesIntersect(grain) && // and the bboxes intersect
718  other_grain.halosIntersect(grain)) // and the halos also intersect
719  // TODO: Inspect combined volume and see if it's "close" to the expected value
720  {
721  grain._id = other_grain._id; // Set the duplicate ID
722  grain._status = Status::MARKED; // Mark it
723 
724  if (_verbosity_level > 0)
725  _console << COLOR_YELLOW << "Split Grain Detected #" << grain._id
726  << " (variable index: " << grain._var_index << ")\n"
727  << COLOR_DEFAULT;
728  if (_verbosity_level > 1)
729  _console << grain << other_grain;
730  }
731  }
732 
733  if (grain._var_index < _reserve_op_index)
734  {
753  if (_verbosity_level > 1)
754  _console << COLOR_YELLOW
755  << "Trying harder to detect a split grain while examining grain on variable "
756  "index "
757  << grain._var_index << '\n'
758  << COLOR_DEFAULT;
759 
760  std::vector<std::size_t> old_grain_indices;
761  for (MooseIndex(_feature_sets_old) old_grain_index = 0;
762  old_grain_index < _feature_sets_old.size();
763  ++old_grain_index)
764  {
765  auto & old_grain = _feature_sets_old[old_grain_index];
766 
767  if (old_grain._status == Status::INACTIVE)
768  continue;
769 
775  if (grain._var_index == old_grain._var_index &&
776  grain.boundingBoxesIntersect(old_grain) && grain.halosIntersect(old_grain))
777  old_grain_indices.push_back(old_grain_index);
778  }
779 
780  if (old_grain_indices.size() == 1)
781  {
782  grain._id = _feature_sets_old[old_grain_indices[0]]._id;
783  grain._status = Status::MARKED;
784 
785  if (_verbosity_level > 0)
786  _console << COLOR_YELLOW << "Split Grain Detected #" << grain._id
787  << " (variable index: " << grain._var_index << ")\n"
788  << COLOR_DEFAULT;
789  }
790  else if (old_grain_indices.size() > 1)
791  _console
792  << COLOR_RED << "Split Grain Likely Detected #" << grain._id
793  << " Need more information to find correct candidate - contact a developer!\n\n"
794  << COLOR_DEFAULT;
795  }
796 
797  // Must be a nucleating grain (status is still not set)
798  if (grain._status == Status::CLEAR)
799  {
800  auto new_index = getNextUniqueID();
801  grain._id = new_index; // Set the ID
802  grain._status = Status::MARKED; // Mark it
803 
804  if (_verbosity_level > 0)
805  _console << COLOR_YELLOW << "Nucleating Grain Detected "
806  << " (variable index: " << grain._var_index << ")\n"
807  << COLOR_DEFAULT;
808  if (_verbosity_level > 1)
809  _console << grain;
810  }
811  }
812  }
813 
814  // Case 2 (inactive grains in _feature_sets_old)
815  for (auto & grain : _feature_sets_old)
816  {
817  if (grain._status == Status::CLEAR)
818  {
819  grain._status = Status::INACTIVE;
820  if (_verbosity_level > 0)
821  {
822  _console << COLOR_GREEN << "Marking Grain " << grain._id
823  << " as INACTIVE (variable index: " << grain._var_index << ")\n"
824  << COLOR_DEFAULT;
825  if (_verbosity_level > 1)
826  _console << grain;
827  }
828  }
829  }
830  } // is_master
831 
832  /*************************************************************
833  ****************** COLLECTIVE WORK SECTION ******************
834  *************************************************************/
835 
836  // Make IDs on all non-master ranks consistent
838 
839  // Build up an id to index map
840  _communicator.broadcast(_max_curr_grain_id);
842 
847  {
848  for (auto new_id = _old_max_grain_id + 1; new_id <= _max_curr_grain_id; ++new_id)
849  {
850  // Don't trigger the callback on the reserve IDs
852  {
853  // See if we've been instructed to terminate with an error
855  mooseError(
856  "Error: New grain detected and \"error_on_new_grain_creation\" is set to true");
857  else
858  newGrainCreated(new_id);
859  }
860  }
861  }
862 }
static const std::size_t invalid_size_t
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
std::vector< FeatureData > _feature_sets_old
This data structure holds the map of unique grains from the previous time step.
Definition: GrainTracker.h:212
const bool _error_on_grain_creation
Boolean to terminate with an error if a new grain is created during the simulation.
Definition: GrainTracker.h:233
unsigned int _old_max_grain_id
The previous max grain id (needed to figure out which ids are new in a given step) ...
Definition: GrainTracker.h:240
unsigned int & _max_curr_grain_id
Holds the next "regular" grain ID (a grain found or remapped to the standard op vars) ...
Definition: GrainTracker.h:243
const bool _is_master
Convenience variable for testing master rank.
Real centroidRegionDistance(std::vector< MeshTools::BoundingBox > &bboxes1, std::vector< MeshTools::BoundingBox > &bboxes2) const
This method returns the minimum periodic distance between the centroids of two vectors of bounding bo...
const std::size_t _maps_size
Convenience variable holding the size of all the datastructures size by the number of maps...
const short _verbosity_level
Verbosity level controlling the amount of information printed to the console.
Definition: GrainTracker.h:220
static const unsigned int invalid_id
const PerfID _track_grains
Definition: GrainTracker.h:254
std::vector< unsigned int > _feature_counts_per_map
The number of features seen by this object per map.
unsigned int _reserve_grain_first_index
Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) ...
Definition: GrainTracker.h:237
const std::size_t _reserve_op_index
The cutoff index where if variable index >= this number, no remapping TO that variable will occur...
Definition: GrainTracker.h:194
void buildFeatureIdToLocalIndices(unsigned int max_id)
This method builds a lookup map for retrieving the right local feature (by index) given a global inde...
void scatterAndUpdateRanks()
Calls buildLocalToGlobalIndices to build the individual local to global indicies for each rank and sc...
virtual void newGrainCreated(unsigned int new_grain_id)
This method is called when a new grain is detected.
Definition: GrainTracker.C:865
unsigned int getNextUniqueID()
Retrieve the next unique grain number if a new grain is detected during trackGrains.
const unsigned short _n_reserve_ops
The number of reserved order parameters.
Definition: GrainTracker.h:190

◆ updateBoundaryIntersections()

void FeatureFloodCount::updateBoundaryIntersections ( FeatureData feature) const
protectedinherited

Update the feature's attributes to indicate boundary intersections.

Definition at line 1689 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::prepareDataForTransfer().

1690 {
1691  if (_is_elemental)
1692  {
1693  for (auto entity : feature._local_ids)
1694  {
1695  // See if this feature is on a boundary if we haven't already figured that out
1696  if ((feature._boundary_intersection & BoundaryIntersection::ANY_BOUNDARY) ==
1698  {
1699  Elem * elem = _mesh.elemPtr(entity);
1700  if (elem && elem->on_boundary())
1701  feature._boundary_intersection |= BoundaryIntersection::ANY_BOUNDARY;
1702  }
1703 
1704  // Now see if the feature touches the primary and/or secondary boundary IDs if we haven't
1705  // figured that out already
1706  if ((feature._boundary_intersection & BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY) ==
1708  {
1709  for (auto primary_id : _primary_perc_bnds)
1710  if (_mesh.isBoundaryElem(entity, primary_id))
1711  feature._boundary_intersection |= BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY;
1712  }
1713 
1714  if ((feature._boundary_intersection & BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY) ==
1716  {
1717  for (auto secondary_id : _secondary_perc_bnds)
1718  if (_mesh.isBoundaryElem(entity, secondary_id))
1719  feature._boundary_intersection |= BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY;
1720  }
1721  }
1722  }
1723 }
std::vector< BoundaryID > _primary_perc_bnds
std::vector< BoundaryID > _secondary_perc_bnds
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
MooseMesh & _mesh
A reference to the mesh.

◆ updateFieldInfo()

void GrainTracker::updateFieldInfo ( )
overrideprotectedvirtual

This method is used to populate any of the data structures used for storing field data (nodal or elemental).

It is called at the end of finalize and can make use of any of the data structures created during the execution of this postprocessor.

Reimplemented from FeatureFloodCount.

Definition at line 1538 of file GrainTracker.C.

Referenced by finalize().

1539 {
1540  TIME_SECTION(_update_field_info);
1541 
1542  for (MooseIndex(_maps_size) map_num = 0; map_num < _maps_size; ++map_num)
1543  _feature_maps[map_num].clear();
1544 
1545  std::map<dof_id_type, Real> tmp_map;
1546 
1547  for (const auto & grain : _feature_sets)
1548  {
1549  std::size_t curr_var = grain._var_index;
1550  std::size_t map_index = (_single_map_mode || _condense_map_info) ? 0 : curr_var;
1551 
1552  for (auto entity : grain._local_ids)
1553  {
1554  // Highest variable value at this entity wins
1555  Real entity_value = std::numeric_limits<Real>::lowest();
1556  if (_is_elemental)
1557  {
1558  const Elem * elem = _mesh.elemPtr(entity);
1559  std::vector<Point> centroid(1, elem->centroid());
1560  if (_poly_ic_uo && _first_time)
1561  {
1562  entity_value = _poly_ic_uo->getVariableValue(grain._var_index, centroid[0]);
1563  }
1564  else
1565  {
1566  _fe_problem.reinitElemPhys(elem, centroid, 0, /* suppress_displaced_init = */ true);
1567  entity_value = _vars[curr_var]->sln()[0];
1568  }
1569  }
1570  else
1571  {
1572  auto node_ptr = _mesh.nodePtr(entity);
1573  entity_value = _vars[curr_var]->getNodalValue(*node_ptr);
1574  }
1575 
1576  if (entity_value != std::numeric_limits<Real>::lowest() &&
1577  (tmp_map.find(entity) == tmp_map.end() || entity_value > tmp_map[entity]))
1578  {
1579  mooseAssert(grain._id != invalid_id, "Missing Grain ID");
1580  _feature_maps[map_index][entity] = grain._id;
1581 
1582  if (_var_index_mode)
1583  _var_index_maps[map_index][entity] = grain._var_index;
1584 
1585  tmp_map[entity] = entity_value;
1586  }
1587 
1589  {
1590  auto insert_pair = moose_try_emplace(
1591  _entity_var_to_features, entity, std::vector<unsigned int>(_n_vars, invalid_id));
1592  auto & vec_ref = insert_pair.first->second;
1593 
1594  if (insert_pair.second)
1595  {
1596  // insert the reserve op numbers (if appropriate)
1597  for (MooseIndex(_n_reserve_ops) reserve_index = 0; reserve_index < _n_reserve_ops;
1598  ++reserve_index)
1599  vec_ref[reserve_index] = _reserve_grain_first_index + reserve_index;
1600  }
1601  vec_ref[grain._var_index] = grain._id;
1602  }
1603  }
1604 
1605  if (_compute_halo_maps)
1606  for (auto entity : grain._halo_ids)
1607  _halo_ids[grain._var_index][entity] = grain._var_index;
1608 
1609  for (auto entity : grain._ghosted_ids)
1610  _ghosted_entity_ids[entity] = 1;
1611  }
1612 
1614 }
const std::size_t _n_vars
const bool _condense_map_info
virtual Real getVariableValue(unsigned int op_index, const Point &p) const =0
Returns the variable value for a given op_index and mesh point.
bool & _first_time
Boolean to indicate the first time this object executes.
Definition: GrainTracker.h:226
std::vector< FeatureData > & _feature_sets
The data structure used to hold the globally unique features.
std::map< dof_id_type, std::vector< unsigned int > > _entity_var_to_features
std::map< dof_id_type, int > _ghosted_entity_ids
The map for holding reconstructed ghosted element information.
void communicateHaloMap()
std::vector< std::map< dof_id_type, int > > _halo_ids
The data structure for looking up halos around features.
std::vector< MooseVariable * > _vars
The vector of coupled in variables cast to MooseVariable.
const PolycrystalUserObjectBase * _poly_ic_uo
An optional IC UserObject which can provide initial data structures to this object.
Definition: GrainTracker.h:215
const std::size_t _maps_size
Convenience variable holding the size of all the datastructures size by the number of maps...
static const unsigned int invalid_id
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...
const bool _single_map_mode
This variable is used to indicate whether or not multiple maps are used during flooding.
const bool _compute_halo_maps
Indicates whether or not to communicate halo map information with all ranks.
const bool _is_elemental
Determines if the flood counter is elements or not (nodes)
const PerfID _update_field_info
Definition: GrainTracker.h:256
unsigned int _reserve_grain_first_index
Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential) ...
Definition: GrainTracker.h:237
MooseMesh & _mesh
A reference to the mesh.
const bool _compute_var_to_feature_map
Indicates whether or not the var to feature map is populated.
const bool _var_index_mode
This variable is used to indicate whether the maps will contain unique region information or just the...
std::vector< std::map< dof_id_type, int > > _var_index_maps
This map keeps track of which variables own which nodes.
const unsigned short _n_reserve_ops
The number of reserved order parameters.
Definition: GrainTracker.h:190

◆ updateRegionOffsets()

void FeatureFloodCount::updateRegionOffsets ( )
protectedinherited

This routine updates the _region_offsets variable which is useful for quickly determining the proper global number for a feature when using multimap mode.

◆ visitElementalNeighbors()

void FeatureFloodCount::visitElementalNeighbors ( const Elem *  elem,
FeatureData feature,
bool  expand_halos_only,
bool  disjoint_only 
)
protectedinherited

Retrieve only the active neighbors for each side of this element, append them to the list of active neighbors

If the current element (passed into this method) doesn't have a connected neighbor but does have a topological neighbor, this might be a new disjoint region that we'll need to represent with a separate bounding box. To find out for sure, we'll need see if the new neighbors are present in any of the halo or disjoint halo sets. If they are not present, this is a new region.

This neighbor is NULL which means we need to expand the bounding box here in case this grain is up against multiple domain edges so we don't end up with a degenerate bounding box.

Definition at line 1549 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::expandEdgeHalos(), and FeatureFloodCount::flood().

1553 {
1554  mooseAssert(elem, "Elem is NULL");
1555 
1556  std::vector<const Elem *> all_active_neighbors;
1557  MeshBase & mesh = _mesh.getMesh();
1558 
1559  // Loop over all neighbors (at the the same level as the current element)
1560  for (MooseIndex(elem->n_neighbors()) i = 0; i < elem->n_neighbors(); ++i)
1561  {
1562  const Elem * neighbor_ancestor = nullptr;
1563  bool topological_neighbor = false;
1564 
1569  neighbor_ancestor = elem->neighbor_ptr(i);
1570  if (neighbor_ancestor)
1571  {
1572  if (neighbor_ancestor == libMesh::remote_elem)
1573  continue;
1574 
1575  neighbor_ancestor->active_family_tree_by_neighbor(all_active_neighbors, elem, false);
1576  }
1577  else
1578  {
1579  neighbor_ancestor = elem->topological_neighbor(i, mesh, *_point_locator, _pbs);
1580 
1588  if (neighbor_ancestor)
1589  {
1590  neighbor_ancestor->active_family_tree_by_topological_neighbor(
1591  all_active_neighbors, elem, mesh, *_point_locator, _pbs, false);
1592 
1593  topological_neighbor = true;
1594  }
1595  else
1596  {
1602  updateBBoxExtremesHelper(feature->_bboxes[0], *elem);
1603  }
1604  }
1605 
1606  visitNeighborsHelper(elem,
1607  all_active_neighbors,
1608  feature,
1609  expand_halos_only,
1610  topological_neighbor,
1611  disjoint_only);
1612 
1613  all_active_neighbors.clear();
1614  }
1615 }
void updateBBoxExtremesHelper(MeshTools::BoundingBox &bbox, const Point &node)
std::unique_ptr< PointLocatorBase > _point_locator
PeriodicBoundaries * _pbs
A pointer to the periodic boundary constraints object.
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.
MooseMesh & _mesh
A reference to the mesh.

◆ visitNeighborsHelper()

template<typename T >
void FeatureFloodCount::visitNeighborsHelper ( const T *  curr_entity,
std::vector< const T *>  neighbor_entities,
FeatureData feature,
bool  expand_halos_only,
bool  topological_neighbor,
bool  disjoint_only 
)
protectedinherited

The actual logic for visiting neighbors is abstracted out here.

This method is templated to handle the Nodal and Elemental cases together.

Only recurse where we own this entity and it's a topologically connected entity. We shouldn't even attempt to flood to the periodic boundary because we won't have solution information and if we are using DistributedMesh we probably won't have geometric information either.

When we only recurse on entities we own, we can never get more than one away from a local entity which should be in the ghosted zone.

Premark neighboring entities with a halo mark. These entities may or may not end up being part of the feature. We will not update the _entities_visited data structure here.

Definition at line 1632 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::visitElementalNeighbors(), and FeatureFloodCount::visitNodalNeighbors().

1638 {
1639  // Loop over all active element neighbors
1640  for (const auto neighbor : neighbor_entities)
1641  {
1642  if (neighbor && (!_is_boundary_restricted || isBoundaryEntity(neighbor)))
1643  {
1644  if (expand_halos_only)
1645  {
1646  auto entity_id = neighbor->id();
1647 
1648  if (topological_neighbor || disjoint_only)
1649  feature->_disjoint_halo_ids.insert(feature->_disjoint_halo_ids.end(), entity_id);
1650  else if (feature->_local_ids.find(entity_id) == feature->_local_ids.end())
1651  feature->_halo_ids.insert(feature->_halo_ids.end(), entity_id);
1652  }
1653  else
1654  {
1655  auto my_processor_id = processor_id();
1656 
1657  if (!topological_neighbor && neighbor->processor_id() != my_processor_id)
1658  feature->_ghosted_ids.insert(feature->_ghosted_ids.end(), curr_entity->id());
1659 
1669  if (curr_entity->processor_id() == my_processor_id ||
1670  neighbor->processor_id() == my_processor_id)
1671  {
1678  if (topological_neighbor || disjoint_only)
1679  feature->_disjoint_halo_ids.insert(feature->_disjoint_halo_ids.end(), neighbor->id());
1680  else
1681  _entity_queue.push_front(neighbor);
1682  }
1683  }
1684  }
1685  }
1686 }
bool isBoundaryEntity(const T *entity) const
Returns a Boolean indicating whether the entity is on one of the desired boundaries.
bool _is_boundary_restricted
Indicates that this object should only run on one or more boundaries.
std::deque< const DofObject * > _entity_queue
The data structure for maintaining entities to flood during discovery.

◆ visitNodalNeighbors()

void FeatureFloodCount::visitNodalNeighbors ( const Node *  node,
FeatureData feature,
bool  expand_halos_only 
)
protectedinherited

These two routines are utility routines used by the flood routine and by derived classes for visiting neighbors.

Since the logic is different for the elemental versus nodal case it's easier to split them up.

Definition at line 1618 of file FeatureFloodCount.C.

Referenced by FeatureFloodCount::expandEdgeHalos(), and FeatureFloodCount::flood().

1621 {
1622  mooseAssert(node, "Node is NULL");
1623 
1624  std::vector<const Node *> all_active_neighbors;
1625  MeshTools::find_nodal_neighbors(_mesh.getMesh(), *node, _nodes_to_elem_map, all_active_neighbors);
1626 
1627  visitNeighborsHelper(node, all_active_neighbors, feature, expand_halos_only, false, false);
1628 }
std::vector< std::vector< const Elem * > > _nodes_to_elem_map
The data structure used to find neighboring elements give a node ID.
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.
MooseMesh & _mesh
A reference to the mesh.

Member Data Documentation

◆ _all_boundary_entity_ids

std::unordered_set<dof_id_type> FeatureFloodCount::_all_boundary_entity_ids
protectedinherited

The set of entities on the boundary of the domain used for determining if features intersect any boundary.

Definition at line 709 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::meshChanged().

◆ _all_ranges

std::vector<std::pair<dof_id_type, dof_id_type> > GrainTracker::_all_ranges
private

Data structure to hold element ID ranges when using Distributed Mesh (populated on rank 0 only)

Definition at line 249 of file GrainTracker.h.

Referenced by communicateHaloMap(), and meshChanged().

◆ _bnd_elem_range

ConstBndElemRange* FeatureFloodCount::_bnd_elem_range
protectedinherited

Boundary element range pointer.

Definition at line 725 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::execute(), and FeatureFloodCount::isBoundaryEntity().

◆ _broadcast_update

const PerfID GrainTracker::_broadcast_update
private

Definition at line 255 of file GrainTracker.h.

Referenced by broadcastAndUpdateGrainData().

◆ _compute_halo_maps

const bool FeatureFloodCount::_compute_halo_maps
protectedinherited

Indicates whether or not to communicate halo map information with all ranks.

Definition at line 602 of file FeatureFloodCount.h.

Referenced by communicateHaloMap(), meshChanged(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _compute_var_to_feature_map

const bool FeatureFloodCount::_compute_var_to_feature_map
protectedinherited

Indicates whether or not the var to feature map is populated.

Definition at line 605 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::getVarToFeatureVector(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _condense_map_info

const bool FeatureFloodCount::_condense_map_info
protectedinherited

Definition at line 591 of file FeatureFloodCount.h.

Referenced by updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _connecting_threshold

const Real FeatureFloodCount::_connecting_threshold
protectedinherited

The threshold above (or below) which neighboring entities are flooded (where regions can be extended but not started)

Definition at line 575 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::initialize().

◆ _dof_map

const DofMap& FeatureFloodCount::_dof_map
protectedinherited

Reference to the dof_map containing the coupled variables.

Definition at line 567 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::flood().

◆ _element_average_value

const PostprocessorValue& FeatureFloodCount::_element_average_value
protectedinherited

Average value of the domain which can optionally be used to find features in a field.

Definition at line 690 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::initialize().

◆ _empty_var_to_features

std::vector<unsigned int> FeatureFloodCount::_empty_var_to_features
protectedinherited

◆ _entities_visited

std::vector<std::set<dof_id_type> > FeatureFloodCount::_entities_visited
protectedinherited

This variable keeps track of which nodes have been visited during execution.

We don't use the _feature_map for this since we don't want to explicitly store data for all the unmarked nodes in a serialized datastructures. This keeps our overhead down since this variable never needs to be communicated.

Definition at line 629 of file FeatureFloodCount.h.

Referenced by PolycrystalUserObjectBase::execute(), FeatureFloodCount::flood(), FeatureFloodCount::initialize(), FeatureFloodCount::initialSetup(), and PolycrystalUserObjectBase::isNewFeatureOrConnectedRegion().

◆ _entity_var_to_features

std::map<dof_id_type, std::vector<unsigned int> > FeatureFloodCount::_entity_var_to_features
protectedinherited

◆ _error_on_grain_creation

const bool GrainTracker::_error_on_grain_creation
protected

Boolean to terminate with an error if a new grain is created during the simulation.

This is for simulations where new grains are not expected. Note, this does not impact the initial callback to newGrainCreated() nor does it get triggered for splitting grains.

Definition at line 233 of file GrainTracker.h.

Referenced by trackGrains().

◆ _fe_vars

std::vector<MooseVariableFEBase *> FeatureFloodCount::_fe_vars
protectedinherited

The vector of coupled in variables.

Definition at line 562 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::FeatureFloodCount(), and FeatureFloodCount::getFECoupledVars().

◆ _feature_count

unsigned int FeatureFloodCount::_feature_count
protectedinherited

◆ _feature_counts_per_map

std::vector<unsigned int> FeatureFloodCount::_feature_counts_per_map
protectedinherited

The number of features seen by this object per map.

Definition at line 643 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::consolidateMergedFeatures(), FeatureFloodCount::sortAndLabel(), and trackGrains().

◆ _feature_id_to_local_index

std::vector<std::size_t> FeatureFloodCount::_feature_id_to_local_index
protectedinherited

◆ _feature_maps

std::vector<std::map<dof_id_type, int> > FeatureFloodCount::_feature_maps
protectedinherited

The feature maps contain the raw flooded node information and eventually the unique grain numbers.

We have a vector of them so we can create one per variable if that level of detail is desired.

Definition at line 676 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::getEntityValue(), FeatureFloodCount::initialize(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _feature_sets

std::vector<FeatureData>& FeatureFloodCount::_feature_sets
protectedinherited

◆ _feature_sets_old

std::vector<FeatureData> GrainTracker::_feature_sets_old
protected

This data structure holds the map of unique grains from the previous time step.

The information is updated each timestep to track grains over time.

Definition at line 212 of file GrainTracker.h.

Referenced by initialize(), and trackGrains().

◆ _finalize_timer

const PerfID GrainTracker::_finalize_timer
private

Timers.

Definition at line 252 of file GrainTracker.h.

Referenced by finalize().

◆ _first_time

bool& GrainTracker::_first_time
protected

Boolean to indicate the first time this object executes.

Note: _tracking_step isn't enough if people skip initial or execute more than once per step.

Definition at line 226 of file GrainTracker.h.

Referenced by assignGrains(), execute(), finalize(), initialize(), newGrainCreated(), prepopulateState(), trackGrains(), and updateFieldInfo().

◆ _ghosted_entity_ids

std::map<dof_id_type, int> FeatureFloodCount::_ghosted_entity_ids
protectedinherited

The map for holding reconstructed ghosted element information.

Definition at line 693 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::getEntityValue(), FeatureFloodCount::initialize(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _global_numbering

const bool FeatureFloodCount::_global_numbering
protectedinherited

This variable is used to indicate whether or not we identify features with unique numbers on multiple maps.

Definition at line 595 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::updateFieldInfo().

◆ _halo_ids

std::vector<std::map<dof_id_type, int> > FeatureFloodCount::_halo_ids
protectedinherited

The data structure for looking up halos around features.

The outer vector is for splitting out the information per variable. The inner map holds the actual halo information

Definition at line 699 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::FeatureData::clear(), communicateHaloMap(), FeatureFloodCount::getEntityValue(), FeatureFloodCount::FeatureData::halosIntersect(), FeatureFloodCount::initialize(), FeatureFloodCount::FeatureData::merge(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _halo_level

const unsigned short GrainTracker::_halo_level
protected

The thickness of the halo surrounding each grain.

Definition at line 184 of file GrainTracker.h.

Referenced by finalize().

◆ _is_boundary_restricted

bool FeatureFloodCount::_is_boundary_restricted
protectedinherited

Indicates that this object should only run on one or more boundaries.

Definition at line 722 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::execute(), FeatureFloodCount::FeatureFloodCount(), and FeatureFloodCount::visitNeighborsHelper().

◆ _is_elemental

const bool FeatureFloodCount::_is_elemental
protectedinherited

◆ _is_master

const bool FeatureFloodCount::_is_master
protectedinherited

◆ _is_transient

const bool GrainTracker::_is_transient
private

Boolean to indicate whether this is a Steady or Transient solve.

Definition at line 246 of file GrainTracker.h.

Referenced by swapSolutionValuesHelper().

◆ _local_to_global_feature_map

std::vector<std::size_t> FeatureFloodCount::_local_to_global_feature_map
protectedinherited

The vector recording the local to global feature indices.

Definition at line 679 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::scatterAndUpdateRanks().

◆ _maps_size

const std::size_t FeatureFloodCount::_maps_size
protectedinherited

◆ _max_curr_grain_id

unsigned int& GrainTracker::_max_curr_grain_id
private

Holds the next "regular" grain ID (a grain found or remapped to the standard op vars)

Definition at line 243 of file GrainTracker.h.

Referenced by assignGrains(), getNewGrainIDs(), getNextUniqueID(), getTotalFeatureCount(), and trackGrains().

◆ _max_remap_recursion_depth

const unsigned short GrainTracker::_max_remap_recursion_depth
protected

Depth of renumbering recursion (a depth of zero means no recursion)

Definition at line 187 of file GrainTracker.h.

Referenced by remapGrains().

◆ _mesh

MooseMesh& FeatureFloodCount::_mesh
protectedinherited

◆ _n_procs

const processor_id_type FeatureFloodCount::_n_procs
protectedinherited

Convenience variable holding the number of processors in this simulation.

Definition at line 621 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::buildLocalToGlobalIndices(), and communicateHaloMap().

◆ _n_reserve_ops

const unsigned short GrainTracker::_n_reserve_ops
protected

The number of reserved order parameters.

Definition at line 190 of file GrainTracker.h.

Referenced by getNextUniqueID(), trackGrains(), and updateFieldInfo().

◆ _n_vars

const std::size_t FeatureFloodCount::_n_vars
protectedinherited

◆ _nl

NonlinearSystemBase& GrainTracker::_nl
protected

A reference to the nonlinear system (used for retrieving solution vectors)

Definition at line 206 of file GrainTracker.h.

Referenced by remapGrains(), and swapSolutionValuesHelper().

◆ _nodes_to_elem_map

std::vector<std::vector<const Elem *> > FeatureFloodCount::_nodes_to_elem_map
protectedinherited

The data structure used to find neighboring elements give a node ID.

Definition at line 640 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::meshChanged(), and FeatureFloodCount::visitNodalNeighbors().

◆ _old_max_grain_id

unsigned int GrainTracker::_old_max_grain_id
private

The previous max grain id (needed to figure out which ids are new in a given step)

Definition at line 240 of file GrainTracker.h.

Referenced by getNewGrainIDs(), and trackGrains().

◆ _partial_feature_sets

std::vector<std::list<FeatureData> > FeatureFloodCount::_partial_feature_sets
protectedinherited

The data structure used to hold partial and communicated feature data, during the discovery and merging phases.

The outer vector is indexed by map number (often variable number). The inner list is an unordered list of partially discovered features.

Definition at line 653 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::communicateAndMerge(), FeatureFloodCount::consolidateMergedFeatures(), FeatureFloodCount::deserialize(), FeatureFloodCount::expandEdgeHalos(), FeatureFloodCount::expandPointHalos(), FeatureFloodCount::flood(), FeatureFloodCount::initialize(), PolycrystalUserObjectBase::mergeSets(), FeatureFloodCount::mergeSets(), FeatureFloodCount::prepareDataForTransfer(), prepopulateState(), FeatureFloodCount::scatterAndUpdateRanks(), and FeatureFloodCount::serialize().

◆ _pbs

PeriodicBoundaries* FeatureFloodCount::_pbs
protectedinherited

◆ _periodic_node_map

std::multimap<dof_id_type, dof_id_type> FeatureFloodCount::_periodic_node_map
protectedinherited

The data structure which is a list of nodes that are constrained to other nodes based on the imposed periodic boundary conditions.

Definition at line 705 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::appendPeriodicNeighborNodes(), FauxGrainTracker::getEntityValue(), FeatureFloodCount::getEntityValue(), and FeatureFloodCount::meshChanged().

◆ _point_locator

std::unique_ptr<PointLocatorBase> FeatureFloodCount::_point_locator
protectedinherited

◆ _poly_ic_uo

const PolycrystalUserObjectBase* GrainTracker::_poly_ic_uo
protected

An optional IC UserObject which can provide initial data structures to this object.

Definition at line 215 of file GrainTracker.h.

Referenced by execute(), finalize(), GrainTracker(), and updateFieldInfo().

◆ _primary_perc_bnds

std::vector<BoundaryID> FeatureFloodCount::_primary_perc_bnds
protectedinherited

◆ _remap

const bool GrainTracker::_remap
protected

Inidicates whether remapping should be done or not (remapping is independent of tracking)

Definition at line 200 of file GrainTracker.h.

Referenced by finalize().

◆ _remap_timer

const PerfID GrainTracker::_remap_timer
private

Definition at line 253 of file GrainTracker.h.

Referenced by remapGrains().

◆ _reserve_grain_first_index

unsigned int GrainTracker::_reserve_grain_first_index
private

Holds the first unique grain index when using _reserve_op (all the remaining indices are sequential)

Definition at line 237 of file GrainTracker.h.

Referenced by assignGrains(), getNextUniqueID(), trackGrains(), and updateFieldInfo().

◆ _reserve_op_index

const std::size_t GrainTracker::_reserve_op_index
protected

The cutoff index where if variable index >= this number, no remapping TO that variable will occur.

Definition at line 194 of file GrainTracker.h.

Referenced by computeMinDistancesFromGrain(), getThreshold(), remapGrains(), and trackGrains().

◆ _reserve_op_threshold

const Real GrainTracker::_reserve_op_threshold
protected

The threshold above (or below) where a grain may be found on a reserve op field.

Definition at line 197 of file GrainTracker.h.

Referenced by getThreshold().

◆ _secondary_perc_bnds

std::vector<BoundaryID> FeatureFloodCount::_secondary_perc_bnds
protectedinherited

◆ _single_map_mode

const bool FeatureFloodCount::_single_map_mode
protectedinherited

This variable is used to indicate whether or not multiple maps are used during flooding.

Definition at line 589 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::flood(), PolycrystalUserObjectBase::PolycrystalUserObjectBase(), FeatureFloodCount::sortAndLabel(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _step_connecting_threshold

Real FeatureFloodCount::_step_connecting_threshold
protectedinherited

◆ _step_threshold

Real FeatureFloodCount::_step_threshold
protectedinherited

◆ _threshold

const Real FeatureFloodCount::_threshold
protectedinherited

The threshold above (or below) where an entity may begin a new region (feature)

Definition at line 570 of file FeatureFloodCount.h.

Referenced by FauxGrainTracker::execute(), and FeatureFloodCount::initialize().

◆ _tolerate_failure

const bool GrainTracker::_tolerate_failure
protected

Indicates whether we should continue after a remap failure (will result in non-physical results)

Definition at line 203 of file GrainTracker.h.

Referenced by GrainTracker(), and remapGrains().

◆ _track_grains

const PerfID GrainTracker::_track_grains
private

Definition at line 254 of file GrainTracker.h.

Referenced by trackGrains().

◆ _tracking_step

const int GrainTracker::_tracking_step
protected

The timestep to begin tracking grains.

Definition at line 181 of file GrainTracker.h.

Referenced by execute(), finalize(), getEntityValue(), GrainTracker(), initialize(), and remapGrains().

◆ _update_field_info

const PerfID GrainTracker::_update_field_info
private

Definition at line 256 of file GrainTracker.h.

Referenced by updateFieldInfo().

◆ _use_less_than_threshold_comparison

const bool FeatureFloodCount::_use_less_than_threshold_comparison
protectedinherited

Use less-than when comparing values against the threshold value.

True by default. If false, then greater-than comparison is used instead.

Definition at line 612 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::compareValueWithThreshold(), and FauxGrainTracker::execute().

◆ _var_index_maps

std::vector<std::map<dof_id_type, int> > FeatureFloodCount::_var_index_maps
protectedinherited

This map keeps track of which variables own which nodes.

We need a vector of them for multimap mode where multiple variables can own a single mode.

Note: This map is only populated when "show_var_coloring" is set to true.

Definition at line 637 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::FeatureFloodCount(), FeatureFloodCount::getEntityValue(), FeatureFloodCount::initialize(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _var_index_mode

const bool FeatureFloodCount::_var_index_mode
protectedinherited

This variable is used to indicate whether the maps will contain unique region information or just the variable numbers owning those regions.

Definition at line 599 of file FeatureFloodCount.h.

Referenced by FeatureFloodCount::FeatureFloodCount(), FeatureFloodCount::getEntityValue(), FeatureFloodCount::initialize(), updateFieldInfo(), and FeatureFloodCount::updateFieldInfo().

◆ _var_number

unsigned long FeatureFloodCount::_var_number
protectedinherited

This variable is used to build the periodic node map.

Assumption: We are going to assume that either all variables are periodic or none are. This assumption can be relaxed at a later time if necessary.

Definition at line 586 of file FeatureFloodCount.h.

Referenced by centroidRegionDistance(), and FeatureFloodCount::meshChanged().

◆ _vars

std::vector<MooseVariable *> FeatureFloodCount::_vars
protectedinherited

◆ _verbosity_level

const short GrainTracker::_verbosity_level
protected

Verbosity level controlling the amount of information printed to the console.

Definition at line 220 of file GrainTracker.h.

Referenced by attemptGrainRenumber(), finalize(), remapGrains(), and trackGrains().

◆ _volatile_feature_sets

std::vector<FeatureData> FeatureFloodCount::_volatile_feature_sets
protectedinherited

Derived objects (e.g.

the GrainTracker) may require restartable data to track information across time steps. The FeatureFloodCounter however does not. This container is here so that we have the flexabilty to switch between volatile and non-volatile storage. The _feature_sets data structure can conditionally refer to this structure or a MOOSE-provided structure, which is backed up.

Definition at line 669 of file FeatureFloodCount.h.

◆ invalid_id

const unsigned int FeatureFloodCount::invalid_id = std::numeric_limits<unsigned int>::max()
staticinherited

◆ invalid_size_t

const std::size_t FeatureFloodCount::invalid_size_t = std::numeric_limits<std::size_t>::max()
staticinherited

The documentation for this class was generated from the following files: