Skip to content
Permalink
Browse files

Merge pull request #13179 from laagesen/grain_tracker_percolation_13169

Add GrainTracker/FeatureFloodCount percolation detection
  • Loading branch information...
permcody committed Apr 8, 2019
2 parents ecd3198 + 2f95b7c commit 3c6a5d9abe0f08b0f2f545c6fe0b881866a93384
@@ -18,6 +18,8 @@
#include "PerfGraphInterface.h"

#include <memory> //std::unique_ptr
#include <unordered_map>
#include <unordered_set>

// libMesh
#include "libmesh/elem_range.h"
@@ -351,6 +353,7 @@ class MooseMesh : public MooseObject, public Restartable, public PerfGraphInterf
*/
bool isSemiLocal(Node * node);

///@{
/**
* Return pointers to range objects for various types of ranges
* (local nodes, boundary elems, etc.).
@@ -361,6 +364,13 @@ class MooseMesh : public MooseObject, public Restartable, public PerfGraphInterf
ConstNodeRange * getLocalNodeRange();
StoredRange<MooseMesh::const_bnd_node_iterator, const BndNode *> * getBoundaryNodeRange();
StoredRange<MooseMesh::const_bnd_elem_iterator, const BndElement *> * getBoundaryElementRange();
///@}

/**
* Returns a map of boundaries to elements.
*/
const std::unordered_map<boundary_id_type, std::unordered_set<dof_id_type>> &
getBoundariesToElems() const;

/**
* Returns a read-only reference to the set of subdomains currently
@@ -979,8 +989,9 @@ class MooseMesh : public MooseObject, public Restartable, public PerfGraphInterf
std::vector<BndElement *> _bnd_elems;
typedef std::vector<BndElement *>::iterator bnd_elem_iterator_imp;
typedef std::vector<BndElement *>::const_iterator const_bnd_elem_iterator_imp;

/// Map of set of elem IDs connected to each boundary
std::map<boundary_id_type, std::set<dof_id_type>> _bnd_elem_ids;
std::unordered_map<boundary_id_type, std::unordered_set<dof_id_type>> _bnd_elem_ids;

std::map<dof_id_type, Node *> _quadrature_nodes;
std::map<dof_id_type, std::map<unsigned int, std::map<dof_id_type, Node *>>>
@@ -811,6 +811,12 @@ MooseMesh::getBoundaryElementRange()
return _bnd_elem_range.get();
}

const std::unordered_map<boundary_id_type, std::unordered_set<dof_id_type>> &
MooseMesh::getBoundariesToElems() const
{
return _bnd_elem_ids;
}

void
MooseMesh::cacheInfo()
{
@@ -2669,7 +2675,7 @@ bool
MooseMesh::isBoundaryElem(dof_id_type elem_id, BoundaryID bnd_id) const
{
bool found_elem = false;
std::map<boundary_id_type, std::set<dof_id_type>>::const_iterator it = _bnd_elem_ids.find(bnd_id);
auto it = _bnd_elem_ids.find(bnd_id);
if (it != _bnd_elem_ids.end())
if (it->second.find(elem_id) != it->second.end())
found_elem = true;
@@ -49,7 +49,6 @@ class FeatureFloodCount : public GeneralPostprocessor,
{
public:
FeatureFloodCount(const InputParameters & parameters);
~FeatureFloodCount();

virtual void initialSetup() override;
virtual void meshChanged() override;
@@ -67,7 +66,11 @@ class FeatureFloodCount : public GeneralPostprocessor,
/// Returns a Boolean indicating whether this feature intersects _any_ boundary
virtual bool doesFeatureIntersectBoundary(unsigned int feature_id) const;

/// Returns the centroid of the designated feature (only suppored without periodic boundaries)
/// Returns a Boolean indicating whether this feature is percolated (e.g. intersects at least two
/// different boundaries from sets supplied by the user)
virtual bool isFeaturePercolated(unsigned int feature_id) const;

/// Returns the centroid of the designated feature (only supported without periodic boundaries)
virtual Point featureCentroid(unsigned int feature_id) const;

/**
@@ -120,6 +123,15 @@ class FeatureFloodCount : public GeneralPostprocessor,
INACTIVE = 0x4
};

/// This enumeration is used to inidacate status of boundary intersections.
enum class BoundaryIntersection : unsigned char
{
NONE = 0x0,
ANY_BOUNDARY = 0x1,
PRIMARY_PERCOLATION_BOUNDARY = 0x2,
SECONDARY_PERCOLATION_BOUNDARY = 0x4
};

class FeatureData
{
public:
@@ -154,7 +166,7 @@ class FeatureFloodCount : public GeneralPostprocessor,
_min_entity_id(DofObject::invalid_id),
_vol_count(0),
_status(status),
_intersects_boundary(false)
_boundary_intersection(BoundaryIntersection::NONE)
{
}

@@ -291,8 +303,8 @@ class FeatureFloodCount : public GeneralPostprocessor,
/// The status of a feature (used mostly in derived classes like the GrainTracker)
Status _status;

/// Flag indicating whether this feature intersects a boundary
bool _intersects_boundary;
/// Enumaration indicating boundary intersection status
BoundaryIntersection _boundary_intersection;

FeatureData duplicate() const { return FeatureData(*this); }

@@ -503,6 +515,11 @@ class FeatureFloodCount : public GeneralPostprocessor,
*/
virtual void clearDataStructures();

/**
* Update the feature's attributes to indicate boundary intersections
*/
void updateBoundaryIntersections(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
@@ -689,19 +706,22 @@ class FeatureFloodCount : public GeneralPostprocessor,

/// The set of entities on the boundary of the domain used for determining
/// if features intersect any boundary
std::set<dof_id_type> _all_boundary_entity_ids;
std::unordered_set<dof_id_type> _all_boundary_entity_ids;

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;

/// Determines if the flood counter is elements or not (nodes)
const bool _is_elemental;

/// Indicates that this object should only run on one or more boundaries
bool _is_boundary_restricted;

/// Boundary element range pointer (used when boundary restricting this object
/// Boundary element range pointer
ConstBndElemRange * _bnd_elem_range;

/// Convenience variable for testing master rank
@@ -771,4 +791,10 @@ struct enable_bitmask_operators<FeatureFloodCount::Status>
static const bool enable = true;
};

template <>
struct enable_bitmask_operators<FeatureFloodCount::BoundaryIntersection>
{
static const bool enable = true;
};

#endif // FEATUREFLOODCOUNT_H
@@ -38,7 +38,7 @@ class GrainTracker : public FeatureFloodCount, public GrainTrackerInterface
// Struct used to transfer minimal data to all ranks
struct PartialFeatureData
{
bool intersects_boundary;
BoundaryIntersection boundary_intersection;
unsigned int id;
Point centroid;
Status status;
@@ -68,6 +68,7 @@ class GrainTracker : public FeatureFloodCount, public GrainTrackerInterface
virtual std::size_t getNumberActiveGrains() const override;
virtual Point getGrainCentroid(unsigned int grain_id) const override;
virtual bool doesFeatureIntersectBoundary(unsigned int feature_id) const override;
virtual bool isFeaturePercolated(unsigned int feature_id) const override;
virtual std::vector<unsigned int> getNewGrainIDs() const override;

protected:
@@ -56,6 +56,7 @@ class FeatureVolumeVectorPostprocessor : public GeneralVectorPostprocessor,
VectorPostprocessorValue & _var_num;
VectorPostprocessorValue & _feature_volumes;
VectorPostprocessorValue & _intersects_bounds;
VectorPostprocessorValue & _percolated;

private:
/// Add volume contributions to one or entries in the feature volume vector
@@ -47,7 +47,7 @@ dataStore(std::ostream & stream, FeatureFloodCount::FeatureData & feature, void
storeHelper(stream, feature._vol_count, context);
storeHelper(stream, feature._centroid, context);
storeHelper(stream, feature._status, context);
storeHelper(stream, feature._intersects_boundary, context);
storeHelper(stream, feature._boundary_intersection, context);
}

template <>
@@ -78,7 +78,7 @@ dataLoad(std::istream & stream, FeatureFloodCount::FeatureData & feature, void *
loadHelper(stream, feature._vol_count, context);
loadHelper(stream, feature._centroid, context);
loadHelper(stream, feature._status, context);
loadHelper(stream, feature._intersects_boundary, context);
loadHelper(stream, feature._boundary_intersection, context);
}

template <>
@@ -142,6 +142,15 @@ validParams<FeatureFloodCount>()
true,
"Controls whether features are defined to be less than or greater than the threshold value.");

params.addParam<std::vector<BoundaryName>>(
"primary_percolation_boundaries",
"A list of boundaries used in conjunction with the corresponding "
"\"secondary_percolation_boundaries\" parameter for determining if a feature creates a path "
"connecting any pair of boundaries");
params.addParam<std::vector<BoundaryName>>(
"secondary_percolation_boundaries",
"Paired boundaries with \"primaryary_percolation_boundaries\" parameter");

/**
* The FeatureFloodCount and derived objects should not to operate on the displaced mesh. These
* objects consume variable values from the nonlinear system and use a lot of raw geometric
@@ -153,10 +162,13 @@ validParams<FeatureFloodCount>()

// The FeatureFloodCount object does not require that any state (restartable information) is
// maintained. This Boolean is set to false so that we don't ask MOOSE to save a potentially
// large data structure for no reason.
// large data structure for no reason. It is set for true in at least one derived class
// (GrainTracker).
params.addPrivateParam<bool>("restartable_required", false);

params.addParamNamesToGroup("use_single_map condense_map_info use_global_numbering", "Advanced");
params.addParamNamesToGroup(
"use_single_map condense_map_info use_global_numbering primary_percolation_boundaries",
"Advanced");

MooseEnum flood_type("NODAL ELEMENTAL", "ELEMENTAL");
params.addParam<MooseEnum>("flood_entity_type",
@@ -223,9 +235,19 @@ FeatureFloodCount::FeatureFloodCount(const InputParameters & parameters)
addMooseVariableDependency(_fe_vars);

_is_boundary_restricted = boundaryRestricted();
}

FeatureFloodCount::~FeatureFloodCount() {}
if (parameters.isParamValid("primary_percolation_boundaries"))
_primary_perc_bnds = _mesh.getBoundaryIDs(
parameters.get<std::vector<BoundaryName>>("primary_percolation_boundaries"));
if (parameters.isParamValid("secondary_percolation_boundaries"))
_secondary_perc_bnds = _mesh.getBoundaryIDs(
parameters.get<std::vector<BoundaryName>>("secondary_percolation_boundaries"));

if (_primary_perc_bnds.empty() != _secondary_perc_bnds.empty())
paramError("primary_percolation_boundaries",
"primary_percolation_boundaries and secondary_percolation_boundaries must both be "
"supplied when checking for percolation");
}

void
FeatureFloodCount::initialSetup()
@@ -791,8 +813,34 @@ FeatureFloodCount::doesFeatureIntersectBoundary(unsigned int feature_id) const
{
mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
return _feature_sets[local_index]._status != Status::INACTIVE
? _feature_sets[local_index]._intersects_boundary
: invalid_id;
? _feature_sets[local_index]._boundary_intersection != BoundaryIntersection::NONE
: false;
}

return false;
}

bool
FeatureFloodCount::isFeaturePercolated(unsigned int feature_id) const
{
// TODO: This information is not parallel consistent when using FeatureFloodCounter

// Some processors don't contain the largest feature id, in that case we just return invalid_id
if (feature_id >= _feature_id_to_local_index.size())
return false;

auto local_index = _feature_id_to_local_index[feature_id];

if (local_index != invalid_size_t)
{
mooseAssert(local_index < _feature_sets.size(), "local_index out of bounds");
bool primary = ((_feature_sets[local_index]._boundary_intersection &
BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY) ==
BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY);
bool secondary = ((_feature_sets[local_index]._boundary_intersection &
BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY) ==
BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY);
return _feature_sets[local_index]._status != Status::INACTIVE ? (primary && secondary) : false;
}

return false;
@@ -928,6 +976,9 @@ FeatureFloodCount::prepareDataForTransfer()
{
for (auto & feature : list_ref)
{
// See if the feature intersects a boundary or perhaps one of the percolation boundaries.
updateBoundaryIntersections(feature);

// Periodic node ids
appendPeriodicNeighborNodes(feature);

@@ -1285,9 +1336,9 @@ FeatureFloodCount::flood(const DofObject * dof_object, std::size_t current_index
// Sum the centroid values for now, we'll average them later
feature->_centroid += elem->centroid();

// Does the volume intersect the boundary?
if (_all_boundary_entity_ids.find(elem->id()) != _all_boundary_entity_ids.end())
feature->_intersects_boundary = true;
// // Does the volume intersect the boundary?
// if (_all_boundary_entity_ids.find(elem->id()) != _all_boundary_entity_ids.end())
// feature->_intersects_boundary = true;
}

if (_is_elemental)
@@ -1620,6 +1671,43 @@ FeatureFloodCount::visitNeighborsHelper(const T * curr_entity,
}
}

void
FeatureFloodCount::updateBoundaryIntersections(FeatureData & feature) const
{
if (_is_elemental)
{
for (auto entity : feature._local_ids)
{
// See if this feature is on a boundary if we haven't already figured that out
if ((feature._boundary_intersection & BoundaryIntersection::ANY_BOUNDARY) ==
BoundaryIntersection::NONE)
{
Elem * elem = _mesh.elemPtr(entity);
if (elem && elem->on_boundary())
feature._boundary_intersection |= BoundaryIntersection::ANY_BOUNDARY;
}

// Now see if the feature touches the primary and/or secondary boundary IDs if we haven't
// figured that out already
if ((feature._boundary_intersection & BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY) ==
BoundaryIntersection::NONE)
{
for (auto primary_id : _primary_perc_bnds)
if (_mesh.isBoundaryElem(entity, primary_id))
feature._boundary_intersection |= BoundaryIntersection::PRIMARY_PERCOLATION_BOUNDARY;
}

if ((feature._boundary_intersection & BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY) ==
BoundaryIntersection::NONE)
{
for (auto secondary_id : _secondary_perc_bnds)
if (_mesh.isBoundaryElem(entity, secondary_id))
feature._boundary_intersection |= BoundaryIntersection::SECONDARY_PERCOLATION_BOUNDARY;
}
}
}
}

void
FeatureFloodCount::appendPeriodicNeighborNodes(FeatureData & feature) const
{
@@ -1912,7 +2000,7 @@ FeatureFloodCount::FeatureData::merge(FeatureData && rhs)
_status &= rhs._status;

// Logical OR here to make sure we maintain boundary intersection attribute when joining
_intersects_boundary |= rhs._intersects_boundary;
_boundary_intersection |= rhs._boundary_intersection;

_vol_count += rhs._vol_count;
_centroid += rhs._centroid;
Oops, something went wrong.

0 comments on commit 3c6a5d9

Please sign in to comment.
You can’t perform that action at this time.