www.mooseframework.org
PolycrystalUserObjectBase.C
Go to the documentation of this file.
1 /****************************************************************/
2 /* MOOSE - Multiphysics Object Oriented Simulation Environment */
3 /* */
4 /* All contents are licensed under LGPL V2.1 */
5 /* See LICENSE for full restrictions */
6 /****************************************************************/
7 
9 #include "NonlinearSystemBase.h"
10 #include "MooseMesh.h"
11 #include "MooseVariable.h"
12 
13 #include "libmesh/dense_matrix.h"
14 
15 #include <vector>
16 #include <map>
17 #include <algorithm>
18 
19 template <>
20 InputParameters
22 {
23  InputParameters params = validParams<FeatureFloodCount>();
24  params.addClassDescription("This object provides the base capability for creating proper reduced "
25  "order parameter polycrystal initial conditions.");
26  params.addRequiredCoupledVarWithAutoBuild(
27  "variable", "var_name_base", "op_num", "Array of coupled variables");
28  params.addParam<bool>("output_adjacency_matrix",
29  false,
30  "Output the Grain Adjacency Matrix used in the coloring algorithms. "
31  "Additionally, the grain to OP assignments will be printed");
32  params.addParam<MooseEnum>("coloring_algorithm",
35 
36  // Hide the output of the IC objects by default, it doesn't change over time
37  params.set<std::vector<OutputName>>("outputs") = {"none"};
38 
40  params.set<bool>("allow_duplicate_execution_on_initial") = true;
41 
42  // This object should only be executed _before_ the initial condition
43  MultiMooseEnum execute_options(SetupInterface::getExecuteOptions());
44  execute_options = "initial";
45  params.set<MultiMooseEnum>("execute_on") = execute_options;
46 
47  return params;
48 }
49 
50 PolycrystalUserObjectBase::PolycrystalUserObjectBase(const InputParameters & parameters)
51  : FeatureFloodCount(parameters),
52  _dim(_mesh.dimension()),
53  _op_num(_vars.size()),
54  _coloring_algorithm(getParam<MooseEnum>("coloring_algorithm")),
55  _colors_assigned(false),
56  _output_adjacency_matrix(getParam<bool>("output_adjacency_matrix"))
57 {
58  mooseAssert(_single_map_mode, "Do not turn off single_map_mode with this class");
59 }
60 
61 void
63 {
68  if (_op_num < 1)
69  mooseError("No coupled variables found");
70 
71  for (unsigned int dim = 0; dim < _dim; ++dim)
72  {
73  bool first_variable_value = _mesh.isTranslatedPeriodic(_vars[0]->number(), dim);
74 
75  for (unsigned int i = 1; i < _vars.size(); ++i)
76  if (_mesh.isTranslatedPeriodic(_vars[i]->number(), dim) != first_variable_value)
77  mooseError("Coupled polycrystal variables differ in periodicity");
78  }
79 
81 }
82 
83 void
85 {
86  if (_colors_assigned && !_fe_problem.hasInitialAdaptivity())
87  return;
88 
90 }
91 
92 void
94 {
95  if (!_colors_assigned)
97  // No need to rerun the object if the mesh hasn't changed
98  else if (!_fe_problem.hasInitialAdaptivity())
99  return;
100 
106 
119  const auto end = _mesh.getMesh().active_local_elements_end();
120  for (auto el = _mesh.getMesh().active_local_elements_begin(); el != end; ++el)
121  {
122  const Elem * current_elem = *el;
123 
124  // Loop over elements or nodes
125  if (_is_elemental)
126  while (flood(current_elem, invalid_size_t, nullptr))
127  ;
128  else
129  {
130  auto n_nodes = current_elem->n_vertices();
131  for (auto i = decltype(n_nodes)(0); i < n_nodes; ++i)
132  {
133  const Node * current_node = current_elem->get_node(i);
134 
135  while (flood(current_node, invalid_size_t, nullptr))
136  ;
137  }
138  }
139  }
140 }
141 
142 void
144 {
145  if (_colors_assigned && !_fe_problem.hasInitialAdaptivity())
146  return;
147 
148  // TODO: Possibly retrieve the halo thickness from the active GrainTracker object?
149  constexpr unsigned int halo_thickness = 2;
150 
151  expandEdgeHalos(halo_thickness - 1);
152 
154 
155  if (!_colors_assigned)
156  {
157  // Resize the color assignment vector here. All ranks need a copy of this
159  if (_is_master)
160  {
162 
164 
167  }
168 
169  // Communicate the coloring with all ranks
170  _communicator.broadcast(_grain_to_op);
171 
176  for (auto & grain : _feature_sets)
177  grain._var_index = _grain_to_op[grain._id];
178  }
179 
180  _colors_assigned = true;
181 }
182 
183 bool
185  std::size_t & current_index,
186  FeatureData *& feature,
187  Status & status,
188  unsigned int & new_id)
189 {
190  mooseAssert(_t_step == 0, "PolyIC only works if we begin in the initial condition");
191 
192  if (_is_elemental)
193  getGrainsBasedOnElem(*static_cast<const Elem *>(dof_object), _prealloc_tmp_grains);
194  else
195  getGrainsBasedOnPoint(*static_cast<const Node *>(dof_object), _prealloc_tmp_grains);
196 
197  // Retrieve the id of the current entity
198  auto entity_id = dof_object->id();
199 
209  auto saved_grain_id = invalid_id;
210  if (current_index == invalid_size_t)
211  {
212  for (auto grain_id : _prealloc_tmp_grains)
213  {
214  mooseAssert(!_colors_assigned || grain_id < _grain_to_op.size(), "grain_id out of range");
215  auto map_num = _colors_assigned ? _grain_to_op[grain_id] : grain_id;
216  if (_entities_visited[map_num].find(entity_id) == _entities_visited[map_num].end())
217  {
218  saved_grain_id = grain_id;
219 
220  if (!_colors_assigned)
221  current_index = grain_id;
222  else
223  current_index = _grain_to_op[grain_id];
224 
225  break;
226  }
227  }
228 
229  if (current_index == invalid_size_t)
230  return false;
231  }
232  else if (_entities_visited[current_index].find(entity_id) !=
233  _entities_visited[current_index].end())
234  return false;
235 
236  if (!feature)
237  {
238  new_id = saved_grain_id;
239  status &= ~Status::INACTIVE;
240 
241  return true;
242  }
243  else
244  return std::find(_prealloc_tmp_grains.begin(), _prealloc_tmp_grains.end(), feature->_id) !=
245  _prealloc_tmp_grains.end();
246 }
247 
248 bool
250  const FeatureData & f2) const
251 {
252  return _colors_assigned ? f1.mergeable(f2) : f1._id == f2._id;
253 }
254 
255 void
257 {
258  mooseAssert(_is_master, "This routine should only be called on the master rank");
259 
260  _adjacency_matrix = libmesh_make_unique<DenseMatrix<Real>>(_feature_count, _feature_count);
261  for (auto & grain1 : _feature_sets)
262  {
263  for (auto & grain2 : _feature_sets)
264  {
265  if (&grain1 == &grain2)
266  continue;
267 
268  if (grain1.boundingBoxesIntersect(grain2) && grain1.halosIntersect(grain2))
269  {
270  (*_adjacency_matrix)(grain1._id, grain2._id) = 1.;
271  (*_adjacency_matrix)(grain1._id, grain2._id) = 1.;
272  }
273  }
274  }
275 }
276 
277 void
279 {
280  mooseAssert(_is_master, "This routine should only be called on the master rank");
281 
282  // Moose::perf_log.push("assignOpsToGrains()", "PolycrystalICTools");
283  //
284  // Use a simple backtracking coloring algorithm
285  if (_coloring_algorithm == "bt")
286  {
287  if (!colorGraph(0))
288  mooseError("Unable to find a valid grain to op coloring, do you have enough op variables?");
289  }
290  else // PETSc Coloring algorithms
291  {
292 #ifdef LIBMESH_HAVE_PETSC
293  const std::string & ca_str = _coloring_algorithm;
294  Real * am_data = _adjacency_matrix->get_values().data();
295  Moose::PetscSupport::colorAdjacencyMatrix(
296  am_data, _feature_count, _vars.size(), _grain_to_op, ca_str.c_str());
297 #else
298  mooseError("Selected coloring algorithm requires PETSc");
299 #endif
300  }
301 
302  // Moose::perf_log.pop("assignOpsToGrains()", "PolycrystalICTools");
303 }
304 
305 bool
307 {
308  // Base case: All grains are assigned
309  if (vertex == _feature_count)
310  return true;
311 
312  // Consider this grain and try different ops
313  for (unsigned int color_idx = 0; color_idx < _op_num; ++color_idx)
314  {
315  // We'll try to spread these colors around a bit rather than
316  // packing them all on the first few colors if we have several colors.
317  unsigned int color = (vertex + color_idx) % _op_num;
318 
319  if (isGraphValid(vertex, color))
320  {
321  _grain_to_op[vertex] = color;
322 
323  if (colorGraph(vertex + 1))
324  return true;
325 
326  // Backtrack...
328  }
329  }
330 
331  return false;
332 }
333 
334 bool
335 PolycrystalUserObjectBase::isGraphValid(unsigned int vertex, unsigned int color)
336 {
337  // See if the proposed color is valid based on the current neighbor colors
338  for (unsigned int neighbor = 0; neighbor < _feature_count; ++neighbor)
339  if ((*_adjacency_matrix)(vertex, neighbor) && color == _grain_to_op[neighbor])
340  return false;
341  return true;
342 }
343 
344 void
346 {
347  _console << "Grain Adjacency Matrix:\n";
348  for (unsigned int i = 0; i < _adjacency_matrix->m(); i++)
349  {
350  for (unsigned int j = 0; j < _adjacency_matrix->n(); j++)
351  _console << _adjacency_matrix->el(i, j) << " ";
352  _console << '\n';
353  }
354 
355  _console << "Grain to OP assignments:\n";
356  for (auto op : _grain_to_op)
357  _console << op << " ";
358  _console << '\n' << std::endl;
359 }
360 
361 MooseEnum
363 {
364  return MooseEnum("jp power greedy bt", "jp");
365 }
366 
367 std::string
369 {
370  return "The grain neighbor graph coloring algorithm to use: \"jp\" (DEFAULT) Jones and "
371  "Plassmann, an efficient coloring algorithm, \"power\" an alternative stochastic "
372  "algorithm, \"greedy\", a greedy assignment algorithm with stochastic updates to "
373  "guarantee a valid coloring, \"bt\", a back tracking algorithm that produces good "
374  "distributions but may experience exponential run time in the worst case scenario "
375  "(works well on medium to large 2D problems)";
376 }
377 
378 const unsigned int PolycrystalUserObjectBase::INVALID_COLOR =
379  std::numeric_limits<unsigned int>::max();
380 const unsigned int PolycrystalUserObjectBase::HALO_THICKNESS = 4;
std::vector< unsigned int > _prealloc_tmp_grains
Temporary storage area for current grains at a point to avoid memory churn.
virtual void finalize() override
std::unique_ptr< DenseMatrix< Real > > _adjacency_matrix
The dense adjacency matrix.
void buildGrainAdjacencyMatrix()
Builds a dense adjacency matrix based on the discovery of grain neighbors and halos surrounding each ...
void expandEdgeHalos(unsigned int num_layers_to_expand)
This method expands the existing halo set by some width determined by the passed in value...
static std::string coloringAlgorithmDescriptions()
Returns corresponding descriptions of available coloring algorithms.
virtual void getGrainsBasedOnElem(const Elem &elem, std::vector< unsigned int > &grains) const
This method may be defined in addition to the point based initialization to speed up lookups...
static const std::size_t invalid_size_t
PolycrystalUserObjectBase(const InputParameters &parameters)
virtual unsigned int getNumGrains() const =0
Must be overridden by the deriving class to provide the number of grains in the polycrystal structure...
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 printGrainAdjacencyMatrix() const
Prints out the adjacency matrix in a nicely spaced integer format.
virtual void finalize() override
void assignOpsToGrains()
Method that runs a coloring algorithm to assign OPs to grains.
InputParameters validParams< FeatureFloodCount >()
virtual void initialize() override
bool mergeable(const FeatureData &rhs) const
The routine called to see if two features are mergeable:
std::vector< unsigned int > _grain_to_op
A vector indicating which op is assigned to each grain.
const unsigned int _op_num
The maximum number of order parameters (colors) available to assign to the grain structure.
const unsigned int _dim
mesh dimension
std::vector< MooseVariable * > _vars
The vector of coupled in variables.
static const unsigned int HALO_THICKNESS
Used to hold the thickness of the halo that should be constructed for detecting adjacency.
bool _is_elemental
Determines if the flood counter is elements or not (nodes)
bool isGraphValid(unsigned int vertex, unsigned int color)
Helper method for the back-tracking graph coloring algorithm.
bool _is_master
Convenience variable for testing master rank.
virtual void precomputeGrainStructure()
This callback is triggered after the object is initialized and may be optionally overridden to do pre...
std::vector< FeatureData > _feature_sets
The data structure used to hold the globally unique features.
bool _colors_assigned
A Boolean indicating whether the object has assigned colors to grains (internal use) ...
This object will mark nodes or elements of continuous regions all with a unique number for the purpos...
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 void getGrainsBasedOnPoint(const Point &point, std::vector< unsigned int > &grains) const =0
Method for retrieving active grain IDs based on some point in the mesh.
bool colorGraph(unsigned int vertex)
Built-in simple "back-tracking" algorithm to assign colors to a graph.
virtual bool isNewFeatureOrConnectedRegion(const DofObject *dof_object, std::size_t &current_index, FeatureData *&feature, Status &status, unsigned int &new_id) override
Method called during the recursive flood routine that should return whether or not the current entity...
static MooseEnum coloringAlgorithms()
Returns all available coloring algorithms as an enumeration type for input files. ...
virtual bool areFeaturesMergeable(const FeatureData &f1, const FeatureData &f2) const override
Method for determining whether two features are mergeable.
virtual void execute() override
virtual void initialSetup() override
virtual void initialize() override
const bool _output_adjacency_matrix
A user controllable Boolean which can be used to print the adjacency matrix to the console...
bool flood(const DofObject *dof_object, std::size_t current_index, FeatureData *feature)
This method will "mark" all entities on neighboring elements that are above the supplied threshold...
static const unsigned int INVALID_COLOR
Used to indicate an invalid coloring for the built-in back-tracking algorithm.
MooseMesh & _mesh
A reference to the mesh.
unsigned int _id
An ID for this feature.
const MooseEnum _coloring_algorithm
The selected graph coloring algorithm used by this object.
virtual void initialSetup() override
UserObject interface overrides.
InputParameters validParams< PolycrystalUserObjectBase >()