14 #include "GeneratedMesh.h"
15 #include "MooseMesh.h"
16 #include "MooseVariable.h"
17 #include "NonlinearSystem.h"
19 #include "libmesh/periodic_boundary_base.h"
31 storeHelper(stream, feature.
id, context);
32 storeHelper(stream, feature.
centroid, context);
33 storeHelper(stream, feature.
status, context);
41 loadHelper(stream, feature.
id, context);
42 loadHelper(stream, feature.
centroid, context);
43 loadHelper(stream, feature.
status, context);
56 params.clearRelationshipManagers();
58 params.addRelationshipManager(
59 "ElementSideNeighborLayers",
60 Moose::RelationshipManagerType::GEOMETRIC,
62 [](
const InputParameters & obj_params, InputParameters & rm_params) {
63 rm_params.set<
unsigned short>(
"layers") = obj_params.get<
unsigned short>(
"halo_level");
68 params.addRelationshipManager(
"ElementSideNeighborLayers",
69 Moose::RelationshipManagerType::ALGEBRAIC);
72 params.set<
bool>(
"restartable_required") =
true;
74 params.addClassDescription(
"Grain Tracker object for running reduced order parameter simulations "
75 "without grain coalescence.");
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")),
87 _reserve_op_index(_n_reserve_ops <= _n_vars ? _n_vars - _n_reserve_ops : 0),
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")
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")),
98 _reserve_grain_first_index(0),
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))
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.");
114 mooseError(
"Can't start tracking after the initial condition when using a polycrystal_ic_uo");
122 std::size_t var_index)
const
130 const std::vector<unsigned int> &
165 "Grain index out of bounds");
183 mooseAssert(feature_index <
_feature_sets.size(),
"Grain index out of bounds");
199 mooseAssert(feature_index <
_feature_sets.size(),
"Grain index out of bounds");
200 return ((
_feature_sets[feature_index]._boundary_intersection &
216 mooseAssert(feature_index <
_feature_sets.size(),
"Grain index out of bounds");
217 bool primary = ((
_feature_sets[feature_index]._boundary_intersection &
220 bool secondary = ((
_feature_sets[feature_index]._boundary_intersection &
223 return (primary && secondary);
255 auto range = std::make_pair(std::numeric_limits<dof_id_type>::max(),
256 std::numeric_limits<dof_id_type>::min());
257 for (
const auto & current_elem :
_mesh.getMesh().active_local_element_ptr_range())
259 auto id = current_elem->id();
260 if (
id < range.first)
262 else if (
id > range.second)
300 mooseAssert(
_first_time,
"This method should only be called on the first invocation");
312 for (
auto & feature : features)
321 for (
auto & feature : features)
362 _console <<
"Finished inside of trackGrains" << std::endl;
377 _console <<
"Finished inside of updateFieldInfo\n";
384 _console <<
"Finished inside of GrainTracker\n" << std::endl;
392 std::vector<PartialFeatureData> root_feature_data;
393 std::vector<std::string> send_buffer(1), recv_buffer;
402 std::back_inserter(root_feature_data),
406 partial_feature.
id = feature._id;
407 partial_feature.
centroid = feature._centroid;
408 partial_feature.
status = feature._status;
409 return partial_feature;
412 std::ostringstream oss;
414 send_buffer[0].assign(oss.str());
418 _communicator.broadcast_packed_range((
void *)(
nullptr),
422 std::back_inserter(recv_buffer));
427 std::istringstream iss;
428 iss.str(recv_buffer[0]);
431 dataLoad(iss, root_feature_data,
this);
433 for (
const auto & partial_data : root_feature_data)
440 grain._boundary_intersection = partial_data.boundary_intersection;
441 grain._centroid = partial_data.centroid;
452 mooseAssert(
_first_time,
"assignGrains may only be called on the first tracking step");
502 mooseAssert(!
_first_time,
"Track grains may only be called when _tracking_step > _t_step");
514 std::vector<unsigned int> map_sizes(
_maps_size);
520 map_sizes[grain._var_index]++;
527 _console <<
"\nGrain Tracker Status:";
530 _console <<
"\nGrains active index " << map_num <<
": " << map_sizes[map_num] <<
" -> "
537 _console <<
'\n' << std::endl;
549 std::vector<std::size_t> new_grain_index_to_existing_grain_index(
_feature_sets.size(),
562 Real min_centroid_diff = std::numeric_limits<Real>::max();
572 [](
const FeatureData & item, std::size_t var_index)
579 bool any_boxes_intersect =
false;
581 new_grain_index = std::distance(
_feature_sets.begin(), start_it);
583 _feature_sets[new_grain_index]._var_index == old_grain._var_index;
592 if (new_grain.boundingBoxesIntersect(old_grain))
594 any_boxes_intersect =
true;
596 if (curr_centroid_diff <= min_centroid_diff)
598 closest_match_index = new_grain_index;
599 min_centroid_diff = curr_centroid_diff;
605 _console <<
"\nNo intersecting bounding boxes found while trying to match grain "
617 auto curr_index = new_grain_index_to_existing_grain_index[closest_match_index];
629 auto & inactive_grain = (centroid_diff1 < centroid_diff2) ? other_old_grain : old_grain;
634 _console << COLOR_GREEN <<
"Marking Grain " << inactive_grain._id
635 <<
" as INACTIVE (variable index: " << inactive_grain._var_index <<
")\n"
638 _console << inactive_grain;
646 if (&inactive_grain == &other_old_grain)
647 new_grain_index_to_existing_grain_index[closest_match_index] = old_grain_index;
650 new_grain_index_to_existing_grain_index[closest_match_index] = old_grain_index;
655 for (MooseIndex(new_grain_index_to_existing_grain_index) new_index = 0;
656 new_index < new_grain_index_to_existing_grain_index.size();
659 auto curr_index = new_grain_index_to_existing_grain_index[new_index];
666 "Invalid ID in old grain structure");
716 [](
const FeatureData & item, std::size_t var_index)
724 new_grain_index = std::distance(
_feature_sets.begin(), start_it);
726 _feature_sets[new_grain_index]._var_index == grain._var_index;
732 if (grain_num != new_grain_index &&
734 other_grain.boundingBoxesIntersect(grain) &&
735 other_grain.halosIntersect(grain))
738 grain._id = other_grain._id;
742 _console << COLOR_YELLOW <<
"Split Grain Detected #" << grain._id
743 <<
" (variable index: " << grain._var_index <<
")\n"
746 _console << grain << other_grain;
771 _console << COLOR_YELLOW
772 <<
"Trying harder to detect a split grain while examining grain on variable "
774 << grain._var_index <<
'\n'
777 std::vector<std::size_t> old_grain_indices;
792 if (grain._var_index == old_grain._var_index &&
793 grain.boundingBoxesIntersect(old_grain) && grain.halosIntersect(old_grain))
794 old_grain_indices.push_back(old_grain_index);
797 if (old_grain_indices.size() == 1)
803 _console << COLOR_YELLOW <<
"Split Grain Detected #" << grain._id
804 <<
" (variable index: " << grain._var_index <<
")\n"
807 else if (old_grain_indices.size() > 1)
809 << COLOR_RED <<
"Split Grain Likely Detected #" << grain._id
810 <<
" Need more information to find correct candidate - contact a developer!\n\n"
818 grain._id = new_index;
822 _console << COLOR_YELLOW <<
"Nucleating Grain Detected "
823 <<
" (variable index: " << grain._var_index <<
")\n"
839 _console << COLOR_GREEN <<
"Marking Grain " << grain._id
840 <<
" as INACTIVE (variable index: " << grain._var_index <<
")\n"
873 "Error: New grain detected and \"error_on_new_grain_creation\" is set to true");
889 "new_grain_id appears to be invalid");
892 _console << COLOR_YELLOW
893 <<
"\n*****************************************************************************"
894 <<
"\nCouldn't find a matching grain while working on variable index: "
895 << grain._var_index <<
"\nCreating new unique grain: " << new_grain_id <<
'\n'
897 <<
"\n*****************************************************************************\n"
902 std::vector<unsigned int>
909 std::iota(new_ids.begin(), new_ids.end(), new_id);
924 _console <<
"Running remap Grains\n" << std::endl;
932 std::map<unsigned int, std::size_t> grain_id_to_new_var;
935 std::list<std::pair<std::size_t, std::size_t>> split_pairs;
948 std::map<unsigned int, std::size_t> grain_id_to_existing_var_index;
954 grain_id_to_existing_var_index[grain._id] = grain._var_index;
969 if (i < j && grain1._id == grain2._id)
971 split_pairs.push_front(std::make_pair(i, j));
972 if (grain1._var_index != grain2._var_index)
975 _console << COLOR_YELLOW <<
"Split Grain (#" << grain1._id
976 <<
") detected on unmatched OPs (" << grain1._var_index <<
", "
977 << grain2._var_index <<
") attempting to remap to " << grain1._var_index
985 grain1._var_index = grain2._var_index;
995 bool any_grains_remapped =
false;
996 bool grains_remapped;
998 std::set<unsigned int> notify_ids;
1001 grains_remapped =
false;
1010 _console << COLOR_YELLOW <<
"\nGrain #" << grain1._id
1011 <<
" detected on a reserved order parameter #" << grain1._var_index
1012 <<
", remapping to another variable\n"
1024 _console << std::flush;
1025 std::stringstream oss;
1026 oss <<
"Unable to find any suitable order parameters for remapping while working "
1027 <<
"with Grain #" << grain1._id <<
", which is on a reserve order parameter.\n"
1028 <<
"\n\nPossible Resolutions:\n"
1029 <<
"\t- Add more order parameters to your simulation (8 for 2D, 28 for 3D)\n"
1030 <<
"\t- Increase adaptivity or reduce your grain boundary widths\n"
1031 <<
"\t- Make sure you are not starting with too many grains for the mesh size\n";
1032 mooseError(oss.str());
1035 grains_remapped =
true;
1041 if (&grain1 == &grain2)
1044 if (grain1._var_index == grain2._var_index &&
1045 grain1._id != grain2._id &&
1046 grain1.boundingBoxesIntersect(grain2) &&
1047 grain1.halosIntersect(grain2))
1050 _console << COLOR_YELLOW <<
"Grain #" << grain1._id <<
" intersects Grain #"
1051 << grain2._id <<
" (variable index: " << grain1._var_index <<
")\n"
1061 grains_remapped =
true;
1068 notify_ids.insert(grain1._id);
1069 notify_ids.insert(grain2._id);
1075 any_grains_remapped |= grains_remapped;
1076 }
while (grains_remapped);
1078 if (!notify_ids.empty())
1080 _console << std::flush;
1081 std::stringstream oss;
1082 oss <<
"Unable to find any suitable order parameters for remapping while working "
1083 <<
"with the following grain IDs:\n"
1084 << Moose::stringify(notify_ids,
", ",
"",
true) <<
"\n\nPossible Resolutions:\n"
1085 <<
"\t- Add more order parameters to your simulation (8 for 2D, 28 for 3D)\n"
1086 <<
"\t- Increase adaptivity or reduce your grain boundary widths\n"
1087 <<
"\t- Make sure you are not starting with too many grains for the mesh size\n";
1090 mooseWarning(oss.str());
1092 mooseError(oss.str());
1096 for (
auto & split_pair : split_pairs)
1098 mooseError(
"Split grain remapped - This case is currently not handled");
1107 mooseAssert(grain_id_to_existing_var_index.find(grain._id) !=
1108 grain_id_to_existing_var_index.end(),
1109 "Missing unique ID");
1111 auto old_var_index = grain_id_to_existing_var_index[grain._id];
1113 if (old_var_index != grain._var_index)
1115 mooseAssert(static_cast<bool>(grain._status &
Status::DIRTY),
"grain status is incorrect");
1117 grain_id_to_new_var.emplace_hint(
1118 grain_id_to_new_var.end(),
1119 std::pair<unsigned int, std::size_t>(grain._id, grain._var_index));
1129 grain._var_index = old_var_index;
1131 grain._status &= ~
Status::DIRTY;
1135 if (!grain_id_to_new_var.empty())
1139 _console <<
"Final remapping tally:\n";
1140 for (
const auto & remap_pair : grain_id_to_new_var)
1141 _console <<
"Grain #" << remap_pair.first <<
" var_index "
1142 << grain_id_to_existing_var_index[remap_pair.first] <<
" -> "
1143 << remap_pair.second <<
'\n';
1144 _console <<
"Communicating swaps with remaining processors..." << std::endl;
1150 _communicator.broadcast(grain_id_to_new_var);
1153 if (!grain_id_to_new_var.empty())
1156 std::vector<std::map<Node *, CacheValues>> cache(
_n_vars);
1162 auto new_var_it = grain_id_to_new_var.find(grain._id);
1163 if (new_var_it != grain_id_to_new_var.end())
1170 auto new_var_it = grain_id_to_new_var.find(grain._id);
1171 if (new_var_it != grain_id_to_new_var.end())
1175 _nl.solution().close();
1176 _nl.solutionOld().close();
1177 _nl.solutionOlder().close();
1179 _fe_problem.getNonlinearSystemBase().system().update();
1182 _console <<
"Swaps complete" << std::endl;
1188 std::vector<std::list<GrainDistance>> & min_distances)
1220 auto target_var_index = other_grain._var_index;
1221 auto target_grain_index = i;
1222 auto target_grain_id = other_grain._id;
1227 curr_bbox_diff, target_var_index, target_grain_index, target_grain_id);
1230 if (curr_bbox_diff == -1.0 && !min_distances[target_var_index].empty())
1232 Real last_distance = min_distances[target_var_index].begin()->_distance;
1233 if (last_distance < 0)
1234 grain_distance_obj.
_distance += last_distance;
1238 auto insert_it = min_distances[target_var_index].begin();
1239 while (insert_it != min_distances[target_var_index].end() && !(grain_distance_obj < *insert_it))
1241 min_distances[target_var_index].insert(insert_it, grain_distance_obj);
1255 if (min_distances[var_index].empty())
1256 min_distances[var_index].emplace_front(std::numeric_limits<Real>::max(), var_index);
1264 if (depth > max_depth)
1267 std::size_t curr_var_index = grain.
_var_index;
1269 std::vector<std::map<Node *, CacheValues>> cache;
1271 std::vector<std::list<GrainDistance>> min_distances(
_vars.size());
1291 std::sort(min_distances.begin(), min_distances.end(),
1292 [](
const std::list<GrainDistance> & lhs,
const std::list<GrainDistance> & rhs)
1298 else if (rhs.empty())
1301 return lhs.begin()->_distance > rhs.begin()->_distance;
1305 for (
auto & list_ref : min_distances)
1307 const auto target_it = list_ref.begin();
1308 if (target_it == list_ref.end())
1312 if (target_it->_distance > 0)
1316 _console << COLOR_GREEN <<
"- Depth " << depth <<
": Remapping grain #" << grain.
_id
1317 <<
" from variable index " << curr_var_index <<
" to " << target_it->_var_index;
1318 if (target_it->_distance == std::numeric_limits<Real>::max())
1319 _console <<
" which currently contains zero grains.\n\n" << COLOR_DEFAULT;
1321 _console <<
" whose closest grain (#" << target_it->_grain_id <<
") is at a distance of "
1322 << std::sqrt(target_it->_distance) <<
"\n\n"
1334 auto next_target_it = target_it;
1335 bool intersection_hit =
false;
1336 unsigned short num_close_targets = 0;
1337 std::ostringstream oss;
1338 while (!intersection_hit && next_target_it != list_ref.end())
1340 if (next_target_it->_distance > 0)
1343 mooseAssert(next_target_it->_grain_index <
_feature_sets.size(),
1344 "Error in indexing target grain in attemptGrainRenumber");
1349 intersection_hit =
true;
1352 if (num_close_targets > 0)
1354 oss <<
"#" << next_target_it->_grain_id;
1358 ++num_close_targets;
1361 if (!intersection_hit)
1365 _console << COLOR_GREEN <<
"- Depth " << depth <<
": Remapping grain #" << grain.
_id
1366 <<
" from variable index " << curr_var_index <<
" to " << target_it->_var_index;
1368 if (num_close_targets == 1)
1369 _console <<
" whose closest grain (" << oss.str()
1370 <<
") is inside our bounding box but whose halo is not touching.\n\n"
1373 _console <<
" whose closest grains (" << oss.str()
1374 <<
") are inside our bounding box but whose halos are not touching.\n\n"
1386 "Error in indexing target grain in attemptGrainRenumber");
1396 if (target_it->_distance < -1)
1414 _console << COLOR_GREEN <<
"- Depth " << depth <<
": Remapping grain #" << grain.
_id
1415 <<
" from variable index " << curr_var_index <<
" to " << target_it->_var_index
1437 std::size_t new_var_index,
1438 std::vector<std::map<Node *, CacheValues>> & cache,
1441 MeshBase & mesh =
_mesh.getMesh();
1444 std::set<Node *> updated_nodes_tmp;
1449 Elem * elem = mesh.query_elem_ptr(entity);
1453 for (
unsigned int i = 0; i < elem->n_nodes(); ++i)
1455 Node * curr_node = elem->node_ptr(i);
1456 if (updated_nodes_tmp.find(curr_node) == updated_nodes_tmp.end())
1459 updated_nodes_tmp.insert(curr_node);
1466 mesh.query_node_ptr(entity), grain.
_var_index, new_var_index, cache, cache_mode);
1476 std::size_t curr_var_index,
1477 std::size_t new_var_index,
1478 std::vector<std::map<Node *, CacheValues>> & cache,
1481 if (curr_node && curr_node->processor_id() == processor_id())
1484 _subproblem.reinitNode(curr_node, 0);
1487 Real current, old = 0, older = 0;
1491 current =
_vars[curr_var_index]->dofValues()[0];
1494 old =
_vars[curr_var_index]->dofValuesOld()[0];
1495 older =
_vars[curr_var_index]->dofValuesOlder()[0];
1500 const auto cache_it = cache[curr_var_index].find(curr_node);
1501 mooseAssert(cache_it != cache[curr_var_index].end(),
"Error in cache");
1502 current = cache_it->second.current;
1503 old = cache_it->second.old;
1504 older = cache_it->second.older;
1510 cache[curr_var_index][curr_node].current = current;
1511 cache[curr_var_index][curr_node].old = old;
1512 cache[curr_var_index][curr_node].older = older;
1516 const auto & dof_index =
_vars[new_var_index]->nodalDofIndex();
1519 _nl.solution().set(dof_index, current);
1522 _nl.solutionOld().set(dof_index, old);
1523 _nl.solutionOlder().set(dof_index, older);
1541 const auto & dof_index =
_vars[curr_var_index]->nodalDofIndex();
1544 _nl.solution().set(dof_index, 0.0);
1547 _nl.solutionOld().set(dof_index, 0.0);
1548 _nl.solutionOlder().set(dof_index, 0.0);
1562 std::map<dof_id_type, Real> tmp_map;
1566 std::size_t curr_var = grain._var_index;
1569 for (
auto entity : grain._local_ids)
1572 Real entity_value = std::numeric_limits<Real>::lowest();
1575 const Elem * elem =
_mesh.elemPtr(entity);
1576 std::vector<Point> centroid(1, elem->centroid());
1583 _fe_problem.reinitElemPhys(elem, centroid, 0,
true);
1584 entity_value =
_vars[curr_var]->sln()[0];
1589 auto node_ptr =
_mesh.nodePtr(entity);
1590 entity_value =
_vars[curr_var]->getNodalValue(*node_ptr);
1593 if (entity_value != std::numeric_limits<Real>::lowest() &&
1594 (tmp_map.find(entity) == tmp_map.end() || entity_value > tmp_map[entity]))
1596 mooseAssert(grain._id !=
invalid_id,
"Missing Grain ID");
1602 tmp_map[entity] = entity_value;
1607 auto insert_pair = moose_try_emplace(
1609 auto & vec_ref = insert_pair.first->second;
1611 if (insert_pair.second)
1618 vec_ref[grain._var_index] = grain._id;
1623 for (
auto entity : grain._halo_ids)
1624 _halo_ids[grain._var_index][entity] = grain._var_index;
1626 for (
auto entity : grain._ghosted_ids)
1639 std::vector<std::pair<std::size_t, dof_id_type>> halo_ids_all;
1641 std::vector<int> counts;
1642 std::vector<std::pair<std::size_t, dof_id_type>> local_halo_ids;
1645 const bool isDistributedMesh =
_mesh.isDistributedMesh();
1649 std::vector<std::vector<std::pair<std::size_t, dof_id_type>>> root_halo_ids(
_n_procs);
1655 for (
const auto & entity_pair :
_halo_ids[var_index])
1657 auto entity_id = entity_pair.first;
1658 if (isDistributedMesh)
1665 [](
const std::pair<dof_id_type, dof_id_type> range,
1666 dof_id_type entity_id) {
return range.second < entity_id; });
1668 mooseAssert(range_it !=
_all_ranges.end(),
"No range round?");
1671 auto proc_id = std::distance(
_all_ranges.begin(), range_it);
1674 root_halo_ids[proc_id].push_back(std::make_pair(var_index, entity_id));
1678 DofObject * halo_entity;
1680 halo_entity =
_mesh.queryElemPtr(entity_id);
1682 halo_entity =
_mesh.queryNodePtr(entity_id);
1685 root_halo_ids[halo_entity->processor_id()].push_back(
1686 std::make_pair(var_index, entity_id));
1692 std::size_t global_count = 0;
1693 for (
const auto & vector_ref : root_halo_ids)
1695 std::copy(vector_ref.begin(), vector_ref.end(), std::back_inserter(halo_ids_all));
1696 counts[
counter] = vector_ref.size();
1697 global_count += counts[
counter++];
1701 _communicator.scatter(halo_ids_all, counts, local_halo_ids);
1704 for (
const auto & halo_pair : local_halo_ids)
1705 _halo_ids[halo_pair.first].emplace(std::make_pair(halo_pair.second, halo_pair.first));
1714 for (
auto local_id : grain._local_ids)
1715 _halo_ids[grain._var_index].erase(local_id);
1721 std::vector<BoundingBox> & bboxes2)
const
1726 auto min_distance = std::numeric_limits<Real>::max();
1727 for (
const auto & bbox1 : bboxes1)
1729 const auto centroid_point1 = (bbox1.max() + bbox1.min()) / 2.0;
1731 for (
const auto & bbox2 : bboxes2)
1733 const auto centroid_point2 = (bbox2.max() + bbox2.min()) / 2.0;
1736 auto curr_distance =
_mesh.minPeriodicDistance(
_var_number, centroid_point1, centroid_point2);
1738 if (curr_distance < min_distance)
1739 min_distance = curr_distance;
1743 return min_distance;
1748 std::vector<BoundingBox> & bboxes2)
const
1756 auto min_distance = std::numeric_limits<Real>::max();
1757 for (
const auto & bbox1 : bboxes1)
1759 for (
const auto & bbox2 : bboxes2)
1762 Real curr_distance = 0.0;
1763 bool boxes_overlap =
true;
1764 for (
unsigned int dim = 0; dim < LIBMESH_DIM; ++dim)
1766 const auto & min1 = bbox1.min()(dim);
1767 const auto & max1 = bbox1.max()(dim);
1768 const auto & min2 = bbox2.min()(dim);
1769 const auto & max2 = bbox2.max()(dim);
1773 const auto delta = max2 - min1;
1774 curr_distance += delta * delta;
1775 boxes_overlap =
false;
1777 else if (min2 > max1)
1779 const auto delta = max1 - min2;
1780 curr_distance += delta * delta;
1781 boxes_overlap =
false;
1788 if (curr_distance < min_distance)
1789 min_distance = curr_distance;
1793 return min_distance;
1818 std::numeric_limits<std::size_t>::max(),
1819 std::numeric_limits<unsigned int>::max())
1824 std::size_t var_index,
1825 std::size_t grain_index,
1826 unsigned int grain_id)
1827 : _distance(distance), _var_index(var_index), _grain_index(grain_index), _grain_id(grain_id)