void GrainTracker::swapSolutionValues(MooseSharedPointer<FeatureData> grain, unsigned int var_idx, std::map<Node *, CacheValues> & cache, REMAP_CACHE_MODE cache_mode, unsigned int depth) { MeshBase & mesh = _mesh.getMesh(); // Remap the grain std::set<Node *> updated_nodes_tmp; // Used only in the elemental case for (std::set<dof_id_type>::const_iterator entity_it = grain->_local_ids.begin(); entity_it != grain->_local_ids.end(); ++entity_it) { if (_is_elemental) { Elem * elem = mesh.query_elem(*entity_it); if (!elem) continue; for (unsigned int i = 0; i < elem->n_nodes(); ++i) { Node * curr_node = elem->get_node(i); if (updated_nodes_tmp.find(curr_node) == updated_nodes_tmp.end()) { updated_nodes_tmp.insert(curr_node); // cache this node so we don't attempt to remap it again within this loop swapSolutionValuesHelper(curr_node, grain->_var_idx, var_idx, cache, cache_mode); } } } else swapSolutionValuesHelper(mesh.query_node_ptr(*entity_it), grain->_var_idx, var_idx, cache, cache_mode); } // Update the variable index in the unique grain datastructure grain->_var_idx = var_idx; // Close all of the solution vectors (we only need to do this once after all swaps are complete) if (depth == 0) { _nl.solution().close(); _nl.solutionOld().close(); _nl.solutionOlder().close(); _fe_problem.getNonlinearSystem().sys().update(); } }
void GrainTracker::swapSolutionValues(std::map<unsigned int, UniqueGrain *>::iterator & grain_it1, std::map<unsigned int, UniqueGrain *>::iterator & grain_it2, unsigned int attempt_number) { NumericVector<Real> & solution = _nl.solution(); NumericVector<Real> & solution_old = _nl.solutionOld(); NumericVector<Real> & solution_older = _nl.solutionOlder(); unsigned int curr_var_idx = grain_it1->second->variable_idx; /** * 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. */ std::vector<Real> min_distances(_vars.size(), std::numeric_limits<Real>::max()); // Make sure that we don't attempt to remap to the same variable min_distances[curr_var_idx] = -std::numeric_limits<Real>::max(); for (std::map<unsigned int, UniqueGrain *>::iterator grain_it3 = _unique_grains.begin(); grain_it3 != _unique_grains.end(); ++grain_it3) { if (grain_it3->second->status == INACTIVE || grain_it3->second->variable_idx == curr_var_idx) continue; unsigned int potential_var_idx = grain_it3->second->variable_idx; Real curr_bounding_sphere_diff = boundingRegionDistance(grain_it1->second->sphere_ptrs, grain_it3->second->sphere_ptrs, false); if (curr_bounding_sphere_diff < min_distances[potential_var_idx]) min_distances[potential_var_idx] = curr_bounding_sphere_diff; } /** * 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 unecessary since the * min_distance of a variable is explicitly set up above. */ unsigned int nth_largest_idx = min_distances.size() - attempt_number - 1; // nth element destroys the original array so we need to copy it first std::vector<Real> min_distances_copy(min_distances); std::nth_element(min_distances_copy.begin(), min_distances_copy.end()+nth_largest_idx, min_distances_copy.end()); // Now find the location of the nth element in the original vector unsigned int new_variable_idx = std::distance(min_distances.begin(), std::find(min_distances.begin(), min_distances.end(), min_distances_copy[nth_largest_idx])); Moose::out << COLOR_YELLOW << "Grain #: " << grain_it1->first << " intersects Grain #: " << grain_it2->first << " (variable index: " << grain_it1->second->variable_idx << ")\n" << COLOR_DEFAULT; if (min_distances[new_variable_idx] < 0) { Moose::out << COLOR_YELLOW << "*****************************************************************************************************\n" << "Warning: No suitable variable found for remapping. Will attempt to remap in next loop if necessary...\n" << "*****************************************************************************************************\n" << COLOR_DEFAULT; return; } Moose::out << COLOR_GREEN << "Remapping to: " << new_variable_idx << " whose closest grain is at a distance of " << min_distances[new_variable_idx] << "\n" << COLOR_DEFAULT; MeshBase & mesh = _mesh.getMesh(); // Remap the grain std::set<Node *> updated_nodes_tmp; // Used only in the elemental case for (std::set<dof_id_type>::const_iterator entity_it = grain_it1->second->entities_ptr->begin(); entity_it != grain_it1->second->entities_ptr->end(); ++entity_it) { if (_is_elemental) { Elem *elem = mesh.query_elem(*entity_it); if (!elem) continue; for (unsigned int i=0; i < elem->n_nodes(); ++i) { Node *curr_node = elem->get_node(i); if (updated_nodes_tmp.find(curr_node) == updated_nodes_tmp.end()) { updated_nodes_tmp.insert(curr_node); // cache this node so we don't attempt to remap it again within this loop swapSolutionValuesHelper(curr_node, curr_var_idx, new_variable_idx, solution, solution_old, solution_older); } } } else swapSolutionValuesHelper(mesh.query_node_ptr(*entity_it), curr_var_idx, new_variable_idx, solution, solution_old, solution_older); } // Update the variable index in the unique grain datastructure grain_it1->second->variable_idx = new_variable_idx; // Close all of the solution vectors solution.close(); solution_old.close(); solution_older.close(); _fe_problem.getNonlinearSystem().sys().update(); }