https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PolycrystalICTools.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "PolycrystalICTools.h"
11
12// MOOSE includes
13#include "MooseMesh.h"
14#include "MooseVariable.h"
15#include "PetscSupport.h"
16
17#include "libmesh/mesh_tools.h"
18#include "libmesh/periodic_boundaries.h"
19#include "libmesh/point_locator_base.h"
20
22{
23const unsigned int INVALID_COLOR = std::numeric_limits<unsigned int>::max();
24}
25
26namespace PolycrystalICTools
27{
28const unsigned int HALO_THICKNESS = 4;
29}
30
31// Forward declarations
32bool colorGraph(const PolycrystalICTools::AdjacencyMatrix<Real> & adjacency_matrix,
33 std::vector<unsigned int> & colors,
34 unsigned int n_vertices,
35 unsigned int n_ops,
36 unsigned int vertex);
38 std::vector<unsigned int> & colors,
39 unsigned int n_vertices,
40 unsigned int vertex,
41 unsigned int color);
42void visitElementalNeighbors(const Elem * elem,
43 const MeshBase & mesh,
44 const PointLocatorBase & point_locator,
45 const PeriodicBoundaries * pb,
46 std::set<dof_id_type> & halo_ids);
47
48std::vector<unsigned int>
49PolycrystalICTools::assignPointsToVariables(const std::vector<Point> & centerpoints,
50 const Real op_num,
51 const MooseMesh & mesh,
52 const MooseVariable & var)
53{
54 Real grain_num = centerpoints.size();
55
56 std::vector<unsigned int> assigned_op(grain_num);
57 std::vector<int> min_op_ind(op_num);
58 std::vector<Real> min_op_dist(op_num);
59
60 // Assign grains to specific order parameters in a way that maximizes the distance
61 for (unsigned int grain = 0; grain < grain_num; grain++)
62 {
63 // Determine the distance to the closest center assigned to each order parameter
64 if (grain >= op_num)
65 {
66 // We can set the array to the distances to the grains 0..op_num-1 (see assignment in the else
67 // case)
68 for (unsigned int i = 0; i < op_num; ++i)
69 {
70 min_op_dist[i] = mesh.minPeriodicDistance(var, centerpoints[grain], centerpoints[i]);
71 min_op_ind[assigned_op[i]] = i;
72 }
73
74 // Now check if any of the extra grains are even closer
75 for (unsigned int i = op_num; i < grain; ++i)
76 {
77 Real dist = mesh.minPeriodicDistance(var, centerpoints[grain], centerpoints[i]);
78 if (min_op_dist[assigned_op[i]] > dist)
79 {
80 min_op_dist[assigned_op[i]] = dist;
81 min_op_ind[assigned_op[i]] = i;
82 }
83 }
84 }
85 else
86 {
87 assigned_op[grain] = grain;
88 continue;
89 }
90
91 // Assign the current center point to the order parameter that is furthest away.
92 unsigned int mx_ind = 0;
93 for (unsigned int i = 1; i < op_num; ++i) // Find index of max
94 if (min_op_dist[mx_ind] < min_op_dist[i])
95 mx_ind = i;
96
97 assigned_op[grain] = mx_ind;
98 }
99
100 return assigned_op;
101}
102
103unsigned int
105 const std::vector<Point> & centerpoints,
106 const MooseMesh & mesh,
107 const MooseVariable & var,
108 const Real maxsize)
109{
110 unsigned int grain_num = centerpoints.size();
111
112 Real min_distance = maxsize;
113 unsigned int min_index = grain_num;
114 // Loops through all of the grain centers and finds the center that is closest to the point p
115 for (unsigned int grain = 0; grain < grain_num; grain++)
116 {
117 Real distance = mesh.minPeriodicDistance(var, centerpoints[grain], p);
118
119 if (min_distance > distance)
120 {
121 min_distance = distance;
122 min_index = grain;
123 }
124 }
125
126 if (min_index >= grain_num)
127 mooseError("ERROR in PolycrystalVoronoiVoidIC: didn't find minimum values in grain_value_calc");
128
129 return min_index;
130}
131
134 const std::map<dof_id_type, unsigned int> & entity_to_grain,
135 MooseMesh & mesh,
136 const PeriodicBoundaries * pb,
137 unsigned int n_grains,
138 bool is_elemental)
139{
140 if (is_elemental)
141 return buildElementalGrainAdjacencyMatrix(entity_to_grain, mesh, pb, n_grains);
142 else
143 return buildNodalGrainAdjacencyMatrix(entity_to_grain, mesh, pb, n_grains);
144}
145
148 const std::map<dof_id_type, unsigned int> & element_to_grain,
149 MooseMesh & mesh,
150 const PeriodicBoundaries * pb,
151 unsigned int n_grains)
152{
153 AdjacencyMatrix<Real> adjacency_matrix(n_grains);
154
155 // We can't call this in the constructor, it appears that _mesh_ptr is always NULL there.
156 mesh.errorIfDistributedMesh("advanced_op_assignment = true");
157
158 std::vector<const Elem *> all_active_neighbors;
159
160 std::vector<std::set<dof_id_type>> local_ids(n_grains);
161 std::vector<std::set<dof_id_type>> halo_ids(n_grains);
162
163 std::unique_ptr<PointLocatorBase> point_locator = mesh.getMesh().sub_point_locator();
164 for (const auto & elem : mesh.getMesh().active_element_ptr_range())
165 {
166 std::map<dof_id_type, unsigned int>::const_iterator grain_it =
167 element_to_grain.find(elem->id());
168 mooseAssert(grain_it != element_to_grain.end(), "Element not found in map");
169 unsigned int my_grain = grain_it->second;
170
171 all_active_neighbors.clear();
172 // Loop over all neighbors (at the the same level as the current element)
173 for (unsigned int i = 0; i < elem->n_neighbors(); ++i)
174 {
175 const Elem * neighbor_ancestor = elem->topological_neighbor(i, mesh, *point_locator, pb);
176 if (neighbor_ancestor)
177 // Retrieve only the active neighbors for each side of this element, append them to the list
178 // of active neighbors
179 neighbor_ancestor->active_family_tree_by_topological_neighbor(
180 all_active_neighbors, elem, mesh, *point_locator, pb, false);
181 }
182
183 // Loop over all active element neighbors
184 for (std::vector<const Elem *>::const_iterator neighbor_it = all_active_neighbors.begin();
185 neighbor_it != all_active_neighbors.end();
186 ++neighbor_it)
187 {
188 const Elem * neighbor = *neighbor_it;
189 std::map<dof_id_type, unsigned int>::const_iterator grain_it2 =
190 element_to_grain.find(neighbor->id());
191 mooseAssert(grain_it2 != element_to_grain.end(), "Element not found in map");
192 unsigned int their_grain = grain_it2->second;
193
194 if (my_grain != their_grain)
195 {
204 // First add corresponding element and grain information
205 local_ids[my_grain].insert(elem->id());
206 local_ids[their_grain].insert(neighbor->id());
207
208 // Now add opposing element and grain information
209 halo_ids[my_grain].insert(neighbor->id());
210 halo_ids[their_grain].insert(elem->id());
211 }
212 // adjacency_matrix[my_grain][their_grain] = 1;
213 }
214 }
215
216 // Build up the halos
217 std::set<dof_id_type> set_difference;
218 for (unsigned int i = 0; i < n_grains; ++i)
219 {
220 std::set<dof_id_type> orig_halo_ids(halo_ids[i]);
221
222 for (unsigned int halo_level = 0; halo_level < PolycrystalICTools::HALO_THICKNESS; ++halo_level)
223 {
224 for (std::set<dof_id_type>::iterator entity_it = orig_halo_ids.begin();
225 entity_it != orig_halo_ids.end();
226 ++entity_it)
227 {
228 if (true)
230 mesh.elemPtr(*entity_it), mesh.getMesh(), *point_locator, pb, halo_ids[i]);
231 else
232 mooseError("Unimplemented");
233 }
234
235 set_difference.clear();
236 std::set_difference(
237 halo_ids[i].begin(),
238 halo_ids[i].end(),
239 local_ids[i].begin(),
240 local_ids[i].end(),
241 std::insert_iterator<std::set<dof_id_type>>(set_difference, set_difference.begin()));
242
243 halo_ids[i].swap(set_difference);
244 }
245 }
246
247 // Finally look at the halo intersections to build the connectivity graph
248 std::set<dof_id_type> set_intersection;
249 for (unsigned int i = 0; i < n_grains; ++i)
250 for (unsigned int j = i + 1; j < n_grains; ++j)
251 {
252 set_intersection.clear();
253 std::set_intersection(
254 halo_ids[i].begin(),
255 halo_ids[i].end(),
256 halo_ids[j].begin(),
257 halo_ids[j].end(),
258 std::insert_iterator<std::set<dof_id_type>>(set_intersection, set_intersection.begin()));
259
260 if (!set_intersection.empty())
261 {
262 adjacency_matrix(i, j) = 1.;
263 adjacency_matrix(j, i) = 1.;
264 }
265 }
266
267 return adjacency_matrix;
268}
269
272 const std::map<dof_id_type, unsigned int> & node_to_grain,
273 MooseMesh & mesh,
274 const PeriodicBoundaries * /*pb*/,
275 unsigned int n_grains)
276{
277 // Build node to elem map
278 std::vector<std::vector<const Elem *>> nodes_to_elem_map;
279 MeshTools::build_nodes_to_elem_map(mesh.getMesh(), nodes_to_elem_map);
280
281 AdjacencyMatrix<Real> adjacency_matrix(n_grains);
282
283 const auto end = mesh.getMesh().active_nodes_end();
284 for (auto nl = mesh.getMesh().active_nodes_begin(); nl != end; ++nl)
285 {
286 const Node * node = *nl;
287 std::map<dof_id_type, unsigned int>::const_iterator grain_it = node_to_grain.find(node->id());
288 mooseAssert(grain_it != node_to_grain.end(), "Node not found in map");
289 unsigned int my_grain = grain_it->second;
290
291 std::vector<const Node *> nodal_neighbors;
292 MeshTools::find_nodal_neighbors(mesh.getMesh(), *node, nodes_to_elem_map, nodal_neighbors);
293
294 // Loop over all nodal neighbors
295 for (unsigned int i = 0; i < nodal_neighbors.size(); ++i)
296 {
297 const Node * neighbor_node = nodal_neighbors[i];
298 std::map<dof_id_type, unsigned int>::const_iterator grain_it2 =
299 node_to_grain.find(neighbor_node->id());
300 mooseAssert(grain_it2 != node_to_grain.end(), "Node not found in map");
301 unsigned int their_grain = grain_it2->second;
302
303 if (my_grain != their_grain)
311 adjacency_matrix(my_grain, their_grain) = 1.;
312 }
313 }
314
315 return adjacency_matrix;
316}
317
318std::vector<unsigned int>
320 unsigned int n_grains,
321 unsigned int n_ops,
322 const MooseEnum & coloring_algorithm)
323{
324 std::vector<unsigned int> grain_to_op(n_grains, GraphColoring::INVALID_COLOR);
325
326 // Use a simple backtracking coloring algorithm
327 if (coloring_algorithm == "bt")
328 {
329 if (!colorGraph(adjacency_matrix, grain_to_op, n_grains, n_ops, 0))
331 "Unable to find a valid Grain to op configuration, do you have enough op variables?");
332 }
333 else // PETSc Coloring algorithms
334 {
335 const std::string & ca_str = coloring_algorithm;
336 Real * am_data = adjacency_matrix.rawDataPtr();
338 am_data, n_grains, n_ops, grain_to_op, ca_str.c_str());
339 }
340
341 return grain_to_op;
342}
343
346{
347 return MooseEnum("legacy bt jp power greedy", "legacy");
348}
349
350std::string
352{
353 return "The grain neighbor graph coloring algorithm to use. \"legacy\" is the original "
354 "algorithm "
355 "which does not guarantee a valid coloring. \"bt\" is a simple backtracking algorithm "
356 "which will produce a valid coloring but has potential exponential run time. The "
357 "remaining algorithms require PETSc but are recommended for larger problems (See "
358 "MatColoringType)";
359}
360
364void
365visitElementalNeighbors(const Elem * elem,
366 const MeshBase & mesh,
367 const PointLocatorBase & point_locator,
368 const PeriodicBoundaries * pb,
369 std::set<dof_id_type> & halo_ids)
370{
371 mooseAssert(elem, "Elem is NULL");
372
373 std::vector<const Elem *> all_active_neighbors;
374
375 // Loop over all neighbors (at the the same level as the current element)
376 for (unsigned int i = 0; i < elem->n_neighbors(); ++i)
377 {
378 const Elem * neighbor_ancestor = elem->topological_neighbor(i, mesh, point_locator, pb);
379 if (neighbor_ancestor)
380 // Retrieve only the active neighbors for each side of this element, append them to the list
381 // of active neighbors
382 neighbor_ancestor->active_family_tree_by_topological_neighbor(
383 all_active_neighbors, elem, mesh, point_locator, pb, false);
384 }
385
386 // Loop over all active element neighbors
387 for (std::vector<const Elem *>::const_iterator neighbor_it = all_active_neighbors.begin();
388 neighbor_it != all_active_neighbors.end();
389 ++neighbor_it)
390 if (*neighbor_it)
391 halo_ids.insert((*neighbor_it)->id());
392}
393
397bool
399 std::vector<unsigned int> & colors,
400 unsigned int n_vertices,
401 unsigned int n_colors,
402 unsigned int vertex)
403{
404 // Base case: All grains are assigned
405 if (vertex == n_vertices)
406 return true;
407
408 // Consider this grain and try different ops
409 for (unsigned int color_idx = 0; color_idx < n_colors; ++color_idx)
410 {
411 // We'll try to spread these colors around a bit rather than
412 // packing them all on the first few colors if we have several colors.
413 unsigned int color = (vertex + color_idx) % n_colors;
414
415 if (isGraphValid(adjacency_matrix, colors, n_vertices, vertex, color))
416 {
417 colors[vertex] = color;
418
419 if (colorGraph(adjacency_matrix, colors, n_vertices, n_colors, vertex + 1))
420 return true;
421
422 // Backtrack...
423 colors[vertex] = GraphColoring::INVALID_COLOR;
424 }
425 }
426
427 return false;
428}
429
430bool
432 std::vector<unsigned int> & colors,
433 unsigned int n_vertices,
434 unsigned int vertex,
435 unsigned int color)
436{
437 // See if the proposed color is valid based on the current neighbor colors
438 for (unsigned int neighbor = 0; neighbor < n_vertices; ++neighbor)
439 if (adjacency_matrix(vertex, neighbor) && color == colors[neighbor])
440 return false;
441 return true;
442}
const Real p
void mooseError(Args &&... args)
void visitElementalNeighbors(const Elem *elem, const MeshBase &mesh, const PointLocatorBase &point_locator, const PeriodicBoundaries *pb, std::set< dof_id_type > &halo_ids)
Utility routines.
bool isGraphValid(const PolycrystalICTools::AdjacencyMatrix< Real > &adjacency_matrix, std::vector< unsigned int > &colors, unsigned int n_vertices, unsigned int vertex, unsigned int color)
bool colorGraph(const PolycrystalICTools::AdjacencyMatrix< Real > &adjacency_matrix, std::vector< unsigned int > &colors, unsigned int n_vertices, unsigned int n_ops, unsigned int vertex)
Backtracking graph coloring routines.
Simple 2D block matrix indicating graph adjacency.
MeshBase & mesh
const unsigned int INVALID_COLOR
void colorAdjacencyMatrix(PetscScalar *adjacency_matrix, unsigned int size, unsigned int colors, std::vector< unsigned int > &vertex_colors, const char *coloring_algorithm)
AdjacencyMatrix< Real > buildNodalGrainAdjacencyMatrix(const std::map< dof_id_type, unsigned int > &node_to_grain, MooseMesh &mesh, const libMesh::PeriodicBoundaries *pb, unsigned int n_grains)
std::vector< unsigned int > assignPointsToVariables(const std::vector< Point > &centerpoints, const Real op_num, const MooseMesh &mesh, const MooseVariable &var)
AdjacencyMatrix< Real > buildElementalGrainAdjacencyMatrix(const std::map< dof_id_type, unsigned int > &element_to_grain, MooseMesh &mesh, const libMesh::PeriodicBoundaries *pb, unsigned int n_grains)
AdjacencyMatrix< Real > buildGrainAdjacencyMatrix(const std::map< dof_id_type, unsigned int > &entity_to_grain, MooseMesh &mesh, const libMesh::PeriodicBoundaries *pb, unsigned int n_grains, bool is_elemental)
std::vector< unsigned int > assignOpsToGrains(AdjacencyMatrix< Real > &adjacency_matrix, unsigned int n_grains, unsigned int n_ops, const MooseEnum &coloring_algorithm)
std::string coloringAlgorithmDescriptions()
const unsigned int HALO_THICKNESS
unsigned int assignPointToGrain(const Point &p, const std::vector< Point > &centerpoints, const MooseMesh &mesh, const MooseVariable &var, const Real maxsize)
T & getMesh(MooseMesh &mesh)
function to cast mesh
Definition SCM.h:35
Real distance(const Point &p)