void GrainTracker::remapGrains() { // Don't remap grains if the current simulation step is before the specified tracking step if (_t_step < _tracking_step) return; /** * Loop over each grain and see if the bounding spheres of the current grain intersect with the spheres of any other grains * represented by the same variable. */ unsigned times_through_loop = 0; bool variables_remapped; do { Moose::out << "Remap Loop: " << times_through_loop << std::endl; variables_remapped = false; for (std::map<unsigned int, UniqueGrain *>::iterator grain_it1 = _unique_grains.begin(); grain_it1 != _unique_grains.end(); ++grain_it1) { if (grain_it1->second->status == INACTIVE) continue; for (std::map<unsigned int, UniqueGrain *>::iterator grain_it2 = _unique_grains.begin(); grain_it2 != _unique_grains.end(); ++grain_it2) { // Don't compare a grain with itself and don't try to remap inactive grains if (grain_it1 == grain_it2 || grain_it2->second->status == INACTIVE) continue; if (grain_it1->second->variable_idx == grain_it2->second->variable_idx && // Are the grains represented by the same variable? boundingRegionDistance(grain_it1->second->sphere_ptrs, grain_it2->second->sphere_ptrs, false) < 0) // If so, do their spheres intersect? { // If so, remap one of them swapSolutionValues(grain_it1, grain_it2, times_through_loop); // Since something was remapped, we need to inspect all the grains again to make sure that previously ok grains // aren't in some new nearly intersecting state. Setting this Boolean to true will trigger the loop again variables_remapped = true; // Since the current grain has just been remapped we don't want to loop over any more potential grains (the inner for loop) break; } } } if (++times_through_loop >= 5 && processor_id() == 0) mooseError(COLOR_RED << "Five passes through the remapping loop and grains are still being remapped, perhaps you need more op variables?" << COLOR_DEFAULT); } while (variables_remapped); Moose::out << "Done Remapping" << std::endl; }
bool GrainTracker::attemptGrainRenumber(MooseSharedPointer<FeatureData> grain, unsigned int grain_id, unsigned int depth, unsigned int max) { // End the recursion of our breadth first search if (depth > max) return false; unsigned int curr_var_idx = grain->_var_idx; std::map<Node *, CacheValues> cache; std::vector<std::list<GrainDistance> > min_distances(_vars.size()); /** * 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 sphere to sphere distance. */ computeMinDistancesFromGrain(grain, min_distances); /** * 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. */ std::sort(min_distances.begin(), min_distances.end(), GrainDistanceSorter()); _console << "\n********************************************\nDistances list for grain " << grain_id << '\n'; for (unsigned int i = 0; i < min_distances.size(); ++i) { for (std::list<GrainDistance>::iterator min_it = min_distances[i].begin(); min_it != min_distances[i].end(); ++min_it) _console << min_it->_distance << ": " << min_it->_grain_id << ": " << min_it->_var_index << '\n'; _console << '\n'; } for (unsigned int i = 0; i < min_distances.size(); ++i) { std::list<GrainDistance>::const_iterator target_it = min_distances[i].begin(); if (target_it == min_distances[i].end()) continue; // If the distance is positive we can just remap and be done if (target_it->_distance > 0) { Moose::out << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain_id << " from variable index " << curr_var_idx << " to " << target_it->_var_index << " whose closest grain (#" << target_it->_grain_id << ") is at a distance of " << target_it->_distance << "\n" << COLOR_DEFAULT; swapSolutionValues(grain, target_it->_var_index, cache, BYPASS, depth); return true; } // If the distance isn't positive we just need to make sure that none of the grains represented by the // target variable index would intersect this one if we were to remap std::list<GrainDistance>::const_iterator next_target_it = target_it; bool intersection_hit = false; std::ostringstream oss; while (!intersection_hit && next_target_it != min_distances[i].end()) { if (next_target_it->_distance > 0) break; mooseAssert(_unique_grains.find(next_target_it->_grain_id) != _unique_grains.end(), "Error in indexing target grain in attemptGrainRenumber"); MooseSharedPointer<FeatureData> next_target_grain = _unique_grains[next_target_it->_grain_id]; // If any grains touch we're done here if (setsIntersect(grain->_halo_ids.begin(), grain->_halo_ids.end(), next_target_grain->_halo_ids.begin(), next_target_grain->_halo_ids.end())) intersection_hit = true; else oss << " #" << next_target_it->_grain_id; ++next_target_it; } if (!intersection_hit) { Moose::out << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain_id << " from variable index " << curr_var_idx << " to " << target_it->_var_index << " whose closest grain(s):" << oss.str() << " are inside our bounding sphere but whose halo(s) are not touching.\n" << COLOR_DEFAULT; swapSolutionValues(grain, target_it->_var_index, cache, BYPASS, depth); return true; } // If we reach this part of the loop, there is no simple renumbering that can be done. mooseAssert(_unique_grains.find(target_it->_grain_id) != _unique_grains.end(), "Error in indexing target grain in attemptGrainRenumber"); MooseSharedPointer<FeatureData> target_grain = _unique_grains[target_it->_grain_id]; // Make sure this grain isn't marked. If it is, we can't recurse here if (target_grain->_merged) return false; // Save the solution values in case we overright them during recursion swapSolutionValues(grain, target_it->_var_index, cache, FILL, depth); // TODO: Make sure this distance is -1 or higher or fine intersections only exist for a single variable // Propose a new variable index for the current grain and recurse grain->_var_idx = target_it->_var_index; grain->_merged = true; if (attemptGrainRenumber(target_grain, target_it->_grain_id, depth+1, max)) { // SUCCESS! Moose::out << COLOR_GREEN << "- Depth " << depth << ": Remapping grain #" << grain_id << " from variable index " << curr_var_idx << " to " << target_it->_var_index << '\n' << COLOR_DEFAULT; // NOTE: swapSolutionValues currently reads the current variable index off the grain. We need to set // back here before calling this method. grain->_var_idx = curr_var_idx; swapSolutionValues(grain, target_it->_var_index, cache, USE, depth); return true; } else // Need to set our var index back after failed recursive step grain->_var_idx = curr_var_idx; // Always "unmark" the grain after the recursion so it can be used by other remap operations grain->_merged = false; } return false; }