T * LocationMap<T>::find(const Point & p, const Real tol) { LOG_SCOPE("find()", "LocationMap"); // Look for a likely key in the multimap unsigned int pointkey = this->key(p); // Look for the exact key first for (const auto & pr : as_range(_map.equal_range(pointkey))) if (p.absolute_fuzzy_equals(this->point_of(*(pr.second)), tol)) return pr.second; // Look for neighboring bins' keys next for (int xoffset = -1; xoffset != 2; ++xoffset) { for (int yoffset = -1; yoffset != 2; ++yoffset) { for (int zoffset = -1; zoffset != 2; ++zoffset) { std::pair<typename map_type::iterator, typename map_type::iterator> key_pos = _map.equal_range(pointkey + xoffset*chunkmax*chunkmax + yoffset*chunkmax + zoffset); for (const auto & pr : as_range(key_pos)) if (p.absolute_fuzzy_equals(this->point_of(*(pr.second)), tol)) return pr.second; } } } return libmesh_nullptr; }
std::vector<std::string> Syntax::getSyntaxByAction(const std::string & action, const std::string & task) { // See if the reverse multimap has been built yet, if not build it now if (!_actions_to_syntax_valid) { std::transform(_syntax_to_actions.begin(), _syntax_to_actions.end(), std::inserter(_actions_to_syntax, _actions_to_syntax.begin()), [](const std::pair<std::string, ActionInfo> pair) { return std::make_pair(pair.second._action, std::make_pair(pair.first, pair.second._task)); }); _actions_to_syntax_valid = true; } std::vector<std::string> syntax; auto it_pair = _actions_to_syntax.equal_range(action); for (const auto & syntax_pair : as_range(it_pair)) // If task is blank, return all syntax, otherwise filter by task if (task == "" || syntax_pair.second.second == task) syntax.emplace_back(syntax_pair.second.first); return syntax; }
void SiblingCoupling::operator() (const MeshBase::const_element_iterator & range_begin, const MeshBase::const_element_iterator & range_end, processor_id_type p, map_type & coupled_elements) { LOG_SCOPE("operator()", "SiblingCoupling"); for (const auto & elem : as_range(range_begin, range_end)) { std::vector<const Elem *> active_siblings; const Elem * parent = elem->parent(); if (!parent) continue; #ifdef LIBMESH_ENABLE_AMR parent->active_family_tree(active_siblings); #endif for (const Elem * sibling : active_siblings) if (sibling->processor_id() != p) coupled_elements.insert (std::make_pair(sibling, _dof_coupling)); } }
LazyCoupleable::LazyCoupleable(const MooseObject * moose_object) : _l_parameters(moose_object->parameters()), _l_name(_l_parameters.get<std::string>("_object_name")), _l_fe_problem(nullptr), _l_app(moose_object->getMooseApp()) { for (const auto & var_name : as_range(std::make_pair(_l_parameters.coupledVarsBegin(), _l_parameters.coupledVarsEnd()))) _coupled_var_numbers[var_name] = libmesh_make_unique<unsigned int>(0); }
void PlotBorderPixels(Eigen::MatrixXf& mat, const Graph& graph, WeightMap weights, BorderPixelMap border_pixels) { float* p = mat.data(); for(auto eid : as_range(boost::edges(graph))) { float v = weights[eid]; for(unsigned int pid : boost::get(border_pixels, eid)) { p[pid] = v; } } }
bool Syntax::verifyMooseObjectTask(const std::string & base, const std::string & task) const { auto iters = _moose_systems_to_tasks.equal_range(base); for (const auto & task_it : as_range(iters)) if (task == task_it.second) return true; return false; }
Node * MultiAppNearestNodeTransfer::getNearestNode(const Point & p, Real & distance, MooseMesh * mesh, bool local) { distance = std::numeric_limits<Real>::max(); Node * nearest = NULL; if (isParamValid("source_boundary")) { BoundaryID src_bnd_id = mesh->getBoundaryID(getParam<BoundaryName>("source_boundary")); ConstBndNodeRange & bnd_nodes = *mesh->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) { if (bnode->_bnd_id == src_bnd_id) { Node * node = bnode->_node; Real current_distance = (p - *node).norm(); if (current_distance < distance) { distance = current_distance; nearest = node; } } } } else { for (auto & node : as_range(local ? mesh->localNodesBegin() : mesh->getMesh().nodes_begin(), local ? mesh->localNodesEnd() : mesh->getMesh().nodes_end())) { Real current_distance = (p - *node).norm(); if (current_distance < distance) { distance = current_distance; nearest = node; } } } return nearest; }
void MultiAppNearestNodeTransfer::getLocalNodes(MooseMesh * mesh, std::vector<Node *> & local_nodes) { if (isParamValid("source_boundary")) { BoundaryID src_bnd_id = mesh->getBoundaryID(getParam<BoundaryName>("source_boundary")); ConstBndNodeRange & bnd_nodes = *mesh->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) if (bnode->_bnd_id == src_bnd_id && bnode->_node->processor_id() == processor_id()) local_nodes.push_back(bnode->_node); } else { local_nodes.resize(mesh->getMesh().n_local_nodes()); unsigned int i = 0; for (auto & node : as_range(mesh->localNodesBegin(), mesh->localNodesEnd())) local_nodes[i++] = node; } }
UndirectedWeightedGraph ComputeEdgeWeightsFromMetricWeighted(const Superpixels& superpixels, const NeighbourhoodGraph& graph, const Metric& metric) { std::vector<unsigned int> cluster_border_length_px(boost::num_vertices(graph)); for(auto eid : as_range(boost::edges(graph))) { const unsigned int ea = boost::source(eid, graph); const unsigned int eb = boost::target(eid, graph); const unsigned int num = graph[eid].num_border_pixels; cluster_border_length_px[ea] += num; cluster_border_length_px[eb] += num; } UndirectedWeightedGraph result; boost::copy_graph(graph, result, boost::edge_copy([&superpixels, &graph, &result, &metric, &cluster_border_length_px](typename NeighbourhoodGraph::edge_descriptor src, UndirectedWeightedGraph::edge_descriptor dst) { const unsigned int ea = boost::source(src, graph); const unsigned int eb = boost::target(src, graph); const float w = static_cast<float>(graph[src].num_border_pixels) / static_cast<float>(cluster_border_length_px[ea] + cluster_border_length_px[eb]); const float d = metric(ea, eb); result[dst] = 12.0f * w * d; })); return result; }
std::unique_ptr<MeshBase> BoundingBoxNodeSetGenerator::generate() { std::unique_ptr<MeshBase> mesh = std::move(_input); // Get the BoundaryIDs from the mesh std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("new_boundary"); std::vector<BoundaryID> boundary_ids = MooseMeshUtils::getBoundaryIDs(*mesh, boundary_names, true); if (boundary_ids.size() != 1) mooseError("Only one boundary ID can be assigned to a nodeset using a bounding box!"); // Get a reference to our BoundaryInfo object BoundaryInfo & boundary_info = mesh->get_boundary_info(); bool found_node = false; const bool inside = (_location == "INSIDE"); // Loop over the elements and assign node set id to nodes within the bounding box for (auto & node : as_range(mesh->active_nodes_begin(), mesh->active_nodes_end())) if (_bounding_box.contains_point(*node) == inside) { boundary_info.add_node(node, boundary_ids[0]); found_node = true; } // Unless at least one processor found a node in the bounding box, // the user probably specified it incorrectly. this->comm().max(found_node); if (!found_node) mooseError("No nodes found within the bounding box"); boundary_info.nodeset_name(boundary_ids[0]) = boundary_names[0]; return dynamic_pointer_cast<MeshBase>(mesh); }
void ActionWarehouse::buildBuildableActions(const std::string & task) { if (_syntax.shouldAutoBuild(task) && _action_blocks[task].empty()) { bool ret_value = false; auto it_pair = _action_factory.getActionsByTask(task); for (const auto & action_pair : as_range(it_pair)) { InputParameters params = _action_factory.getValidParams(action_pair.second); params.set<ActionWarehouse *>("awh") = this; if (params.areAllRequiredParamsValid()) { params.set<std::string>("registered_identifier") = "(AutoBuilt)"; addActionBlock(_action_factory.create(action_pair.second, "", params)); ret_value = true; } } if (!ret_value) _unsatisfied_dependencies.insert(task); } }
void MultiAppNearestNodeTransfer::execute() { _console << "Beginning NearestNodeTransfer " << name() << std::endl; getAppInfo(); // Get the bounding boxes for the "from" domains. std::vector<BoundingBox> bboxes = getFromBoundingBoxes(); // Figure out how many "from" domains each processor owns. std::vector<unsigned int> froms_per_proc = getFromsPerProc(); //////////////////// // For every point in the local "to" domain, figure out which "from" domains // might contain it's nearest neighbor, and send that point to the processors // that own those "from" domains. // // How do we know which "from" domains might contain the nearest neighbor, you // ask? Well, consider two "from" domains, A and B. If every point in A is // closer than every point in B, then we know that B cannot possibly contain // the nearest neighbor. Hence, we'll only check A for the nearest neighbor. // We'll use the functions bboxMaxDistance and bboxMinDistance to figure out // if every point in A is closer than every point in B. //////////////////// // outgoing_qps = nodes/centroids we'll send to other processors. std::vector<std::vector<Point>> outgoing_qps(n_processors()); // When we get results back, node_index_map will tell us which results go with // which points std::vector<std::map<std::pair<unsigned int, unsigned int>, unsigned int>> node_index_map( n_processors()); if (!_neighbors_cached) { for (unsigned int i_to = 0; i_to < _to_problems.size(); i_to++) { System * to_sys = find_sys(*_to_es[i_to], _to_var_name); unsigned int sys_num = to_sys->number(); unsigned int var_num = to_sys->variable_number(_to_var_name); MeshBase * to_mesh = &_to_meshes[i_to]->getMesh(); bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_nodal) { std::vector<Node *> target_local_nodes; if (isParamValid("target_boundary")) { BoundaryID target_bnd_id = _to_meshes[i_to]->getBoundaryID(getParam<BoundaryName>("target_boundary")); ConstBndNodeRange & bnd_nodes = *(_to_meshes[i_to])->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) if (bnode->_bnd_id == target_bnd_id && bnode->_node->processor_id() == processor_id()) target_local_nodes.push_back(bnode->_node); } else { target_local_nodes.resize(to_mesh->n_local_nodes()); unsigned int i = 0; for (auto & node : to_mesh->local_node_ptr_range()) target_local_nodes[i++] = node; } for (const auto & node : target_local_nodes) { // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; // Find which bboxes might have the nearest node to this point. Real nearest_max_distance = std::numeric_limits<Real>::max(); for (const auto & bbox : bboxes) { Real distance = bboxMaxDistance(*node, bbox); if (distance < nearest_max_distance) nearest_max_distance = distance; } unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool qp_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && !qp_found; i_from++) { Real distance = bboxMinDistance(*node, bboxes[i_from]); if (distance < nearest_max_distance || bboxes[i_from].contains_point(*node)) { std::pair<unsigned int, unsigned int> key(i_to, node->id()); node_index_map[i_proc][key] = outgoing_qps[i_proc].size(); outgoing_qps[i_proc].push_back(*node + _to_positions[i_to]); qp_found = true; } } } } } else // Elemental { for (auto & elem : as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end())) { Point centroid = elem->centroid(); // Skip this element if the variable has no dofs at it. if (elem->n_dofs(sys_num, var_num) < 1) continue; // Find which bboxes might have the nearest node to this point. Real nearest_max_distance = std::numeric_limits<Real>::max(); for (const auto & bbox : bboxes) { Real distance = bboxMaxDistance(centroid, bbox); if (distance < nearest_max_distance) nearest_max_distance = distance; } unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool qp_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && !qp_found; i_from++) { Real distance = bboxMinDistance(centroid, bboxes[i_from]); if (distance < nearest_max_distance || bboxes[i_from].contains_point(centroid)) { std::pair<unsigned int, unsigned int> key(i_to, elem->id()); node_index_map[i_proc][key] = outgoing_qps[i_proc].size(); outgoing_qps[i_proc].push_back(centroid + _to_positions[i_to]); qp_found = true; } } } } } } } //////////////////// // Send local node/centroid positions off to the other processors and take // care of points sent to this processor. We'll need to check the points // against all of the "from" domains that this processor owns. For each // point, we'll find the nearest node, then we'll send the value at that node // and the distance between the node and the point back to the processor that // requested that point. //////////////////// std::vector<std::vector<Real>> incoming_evals(n_processors()); std::vector<Parallel::Request> send_qps(n_processors()); std::vector<Parallel::Request> send_evals(n_processors()); // Create these here so that they live the entire life of this function // and are NOT reused per processor. std::vector<std::vector<Real>> processor_outgoing_evals(n_processors()); if (!_neighbors_cached) { for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; _communicator.send(i_proc, outgoing_qps[i_proc], send_qps[i_proc]); } // Build an array of pointers to all of this processor's local nodes. We // need to do this to avoid the expense of using LibMesh iterators. This // step also takes care of limiting the search to boundary nodes, if // applicable. std::vector<std::vector<Node *>> local_nodes(froms_per_proc[processor_id()]); for (unsigned int i = 0; i < froms_per_proc[processor_id()]; i++) { getLocalNodes(_from_meshes[i], local_nodes[i]); } if (_fixed_meshes) { _cached_froms.resize(n_processors()); _cached_dof_ids.resize(n_processors()); } for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { std::vector<Point> incoming_qps; if (i_proc == processor_id()) incoming_qps = outgoing_qps[i_proc]; else _communicator.receive(i_proc, incoming_qps); if (_fixed_meshes) { _cached_froms[i_proc].resize(incoming_qps.size()); _cached_dof_ids[i_proc].resize(incoming_qps.size()); } std::vector<Real> & outgoing_evals = processor_outgoing_evals[i_proc]; outgoing_evals.resize(2 * incoming_qps.size()); for (unsigned int qp = 0; qp < incoming_qps.size(); qp++) { Point qpt = incoming_qps[qp]; outgoing_evals[2 * qp] = std::numeric_limits<Real>::max(); for (unsigned int i_local_from = 0; i_local_from < froms_per_proc[processor_id()]; i_local_from++) { MooseVariableFEBase & from_var = _from_problems[i_local_from]->getVariable(0, _from_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD); System & from_sys = from_var.sys().system(); unsigned int from_sys_num = from_sys.number(); unsigned int from_var_num = from_sys.variable_number(from_var.name()); for (unsigned int i_node = 0; i_node < local_nodes[i_local_from].size(); i_node++) { Real current_distance = (qpt - *(local_nodes[i_local_from][i_node]) - _from_positions[i_local_from]).norm(); if (current_distance < outgoing_evals[2 * qp]) { // Assuming LAGRANGE! if (local_nodes[i_local_from][i_node]->n_dofs(from_sys_num, from_var_num) > 0) { dof_id_type from_dof = local_nodes[i_local_from][i_node]->dof_number(from_sys_num, from_var_num, 0); outgoing_evals[2 * qp] = current_distance; outgoing_evals[2 * qp + 1] = (*from_sys.solution)(from_dof); if (_fixed_meshes) { // Cache the nearest nodes. _cached_froms[i_proc][qp] = i_local_from; _cached_dof_ids[i_proc][qp] = from_dof; } } } } } } if (i_proc == processor_id()) incoming_evals[i_proc] = outgoing_evals; else _communicator.send(i_proc, outgoing_evals, send_evals[i_proc]); } } else // We've cached the nearest nodes. { for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { std::vector<Real> & outgoing_evals = processor_outgoing_evals[i_proc]; outgoing_evals.resize(_cached_froms[i_proc].size()); for (unsigned int qp = 0; qp < outgoing_evals.size(); qp++) { MooseVariableFEBase & from_var = _from_problems[_cached_froms[i_proc][qp]]->getVariable( 0, _from_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD); System & from_sys = from_var.sys().system(); dof_id_type from_dof = _cached_dof_ids[i_proc][qp]; // outgoing_evals[qp] = (*from_sys.solution)(_cached_dof_ids[i_proc][qp]); outgoing_evals[qp] = (*from_sys.solution)(from_dof); } if (i_proc == processor_id()) incoming_evals[i_proc] = outgoing_evals; else _communicator.send(i_proc, outgoing_evals, send_evals[i_proc]); } } //////////////////// // Gather all of the evaluations, find the nearest one for each node/element, // and apply the values. //////////////////// for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; _communicator.receive(i_proc, incoming_evals[i_proc]); } for (unsigned int i_to = 0; i_to < _to_problems.size(); i_to++) { // Loop over the master nodes and set the value of the variable System * to_sys = find_sys(*_to_es[i_to], _to_var_name); unsigned int sys_num = to_sys->number(); unsigned int var_num = to_sys->variable_number(_to_var_name); NumericVector<Real> * solution = nullptr; switch (_direction) { case TO_MULTIAPP: solution = &getTransferVector(i_to, _to_var_name); break; case FROM_MULTIAPP: solution = to_sys->solution.get(); break; default: mooseError("Unknown direction"); } MeshBase * to_mesh = &_to_meshes[i_to]->getMesh(); bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_nodal) { std::vector<Node *> target_local_nodes; if (isParamValid("target_boundary")) { BoundaryID target_bnd_id = _to_meshes[i_to]->getBoundaryID(getParam<BoundaryName>("target_boundary")); ConstBndNodeRange & bnd_nodes = *(_to_meshes[i_to])->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) if (bnode->_bnd_id == target_bnd_id && bnode->_node->processor_id() == processor_id()) target_local_nodes.push_back(bnode->_node); } else { target_local_nodes.resize(to_mesh->n_local_nodes()); unsigned int i = 0; for (auto & node : to_mesh->local_node_ptr_range()) target_local_nodes[i++] = node; } for (const auto & node : target_local_nodes) { // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; Real best_val = 0; if (!_neighbors_cached) { Real min_dist = std::numeric_limits<Real>::max(); for (unsigned int i_from = 0; i_from < incoming_evals.size(); i_from++) { std::pair<unsigned int, unsigned int> key(i_to, node->id()); if (node_index_map[i_from].find(key) == node_index_map[i_from].end()) continue; unsigned int qp_ind = node_index_map[i_from][key]; if (incoming_evals[i_from][2 * qp_ind] >= min_dist) continue; min_dist = incoming_evals[i_from][2 * qp_ind]; best_val = incoming_evals[i_from][2 * qp_ind + 1]; if (_fixed_meshes) { // Cache these indices. _cached_from_inds[node->id()] = i_from; _cached_qp_inds[node->id()] = qp_ind; } } } else { best_val = incoming_evals[_cached_from_inds[node->id()]][_cached_qp_inds[node->id()]]; } dof_id_type dof = node->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } else // Elemental { for (auto & elem : as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end())) { // Skip this element if the variable has no dofs at it. if (elem->n_dofs(sys_num, var_num) < 1) continue; Real best_val = 0; if (!_neighbors_cached) { Real min_dist = std::numeric_limits<Real>::max(); for (unsigned int i_from = 0; i_from < incoming_evals.size(); i_from++) { std::pair<unsigned int, unsigned int> key(i_to, elem->id()); if (node_index_map[i_from].find(key) == node_index_map[i_from].end()) continue; unsigned int qp_ind = node_index_map[i_from][key]; if (incoming_evals[i_from][2 * qp_ind] >= min_dist) continue; min_dist = incoming_evals[i_from][2 * qp_ind]; best_val = incoming_evals[i_from][2 * qp_ind + 1]; if (_fixed_meshes) { // Cache these indices. _cached_from_inds[elem->id()] = i_from; _cached_qp_inds[elem->id()] = qp_ind; } } } else { best_val = incoming_evals[_cached_from_inds[elem->id()]][_cached_qp_inds[elem->id()]]; } dof_id_type dof = elem->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } solution->close(); to_sys->update(); } if (_fixed_meshes) _neighbors_cached = true; // Make sure all our sends succeeded. for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; send_qps[i_proc].wait(); send_evals[i_proc].wait(); } _console << "Finished NearestNodeTransfer " << name() << std::endl; }
Eigen::VectorXf ev_to_graph_weights(const Graph& graph, const std::vector<EigenComponent>& solution) { typedef Eigen::Matrix<float,-1,-1> matrix_t; typedef Eigen::Matrix<float,-1,1> vector_t; vector_t edge_weight = vector_t::Zero(boost::num_edges(graph)); // // later we weight by eigenvalues // // find a positive eigenvalue (need to do this because of ugly instabilities ... // Real ew_pos = -1.0f; // for(unsigned int i=0; ; i++) { // if(solver.eigenvalues()[i] > 0) { // // F IXME magic to get a not too small eigenvalue //// unsigned int x = (n_used_ew + i)/2; // unsigned int x = i + 5; // ew_pos = solver.eigenvalues()[x]; // break; // } // } // // compute normalized weights from eigenvalues // Vec weights = Vec::Zero(n_used_ew); // for(unsigned int k=0; k<n_used_ew; k++) { // Real ew = solver.eigenvalues()[k + 1]; // if(ew <= ew_pos) { // ew = ew_pos; // } // weights[k] = 1.0f / std::sqrt(ew); // } // std::cout << "Weights = " << weights.transpose() << std::endl; // look into first eigenvectors // skip first component for(unsigned int k=0; k<solution.size(); k++) { const EigenComponent& eigen = solution[k]; // omit if eigenvalue is not positive float ew = eigen.eigenvalue; // FIXME this is due to numerical instabilities if(ew <= 0.0001f) { continue; } // weight by eigenvalue float w = 1.0f / std::sqrt(ew); // get eigenvector and normalize vector_t ev = eigen.eigenvector; ev = (ev - ev.minCoeff() * vector_t::Ones(ev.rows())) / (ev.maxCoeff() - ev.minCoeff()); // for each edge compute difference of eigenvector values vector_t e_k = vector_t::Zero(edge_weight.rows()); // FIXME proper edge indexing unsigned int eid_index = 0; for(auto eid : as_range(boost::edges(graph))) { e_k[eid_index] = std::abs(ev[boost::source(eid, graph)] - ev[boost::target(eid, graph)]); eid_index++; } #ifdef SPECTRAL_VERBOSE std::cout << "DEBUG w=" << w << " e_k.maxCoeff()=" << e_k.maxCoeff() << std::endl; #endif // e_k /= e_k.maxCoeff(); // for(unsigned int i=0; i<e_k.rows(); i++) { // e_k[i] = std::exp(-e_k[i]); // } e_k *= w; #ifdef SEGS_DBG_PRINT { std::ofstream ofs((boost::format("/tmp/edge_weights_%03d.txt") % k).str()); for(unsigned int i=0; i<e_k.rows(); i++) { ofs << e_k[i] << std::endl; } } #endif // edge_weight += e_k; } return edge_weight; }
DenseGev<K> dense_graph_to_gev(const Graph& graph, EdgeWeightMap edge_weights) { typedef Eigen::Matrix<K,-1,-1> matrix_t; typedef Eigen::Matrix<K,-1,1> vector_t; const unsigned int dim = boost::num_vertices(graph); // creating matrices matrix_t W = matrix_t::Zero(dim,dim); vector_t D = vector_t::Zero(dim); #ifdef SPECTRAL_VERBOSE std::cout << "DEBUG: Number of vertices = " << boost::num_vertices(graph) << std::endl; std::cout << "DEBUG: Number of edges = " << boost::num_edges(graph) << std::endl; #endif for(auto eid : as_range(boost::edges(graph))) { unsigned int ea = boost::source(eid, graph); unsigned int eb = boost::target(eid, graph); K ew = edge_weights[eid]; if(std::isnan(ew)) { std::cerr << "ERROR: Weight for edge (" << ea << "," << eb << ") is nan!" << std::endl; continue; } if(ew < 0) { std::cerr << "ERROR: Weight for edge (" << ea << "," << eb << ") is negative!" << std::endl; continue; } W(ea, eb) = ew; W(eb, ea) = ew; D[ea] += ew; D[eb] += ew; } // connect disconnected segments to everything // FIXME why is this necessary? #ifdef SPECTRAL_VERBOSE std::vector<int> nodes_with_no_connection; #endif for(unsigned int i=0; i<dim; i++) { K& di = D[i]; if(di < c_D_min) { #ifdef SPECTRAL_VERBOSE nodes_with_no_connection.push_back(i); #endif // connect the disconnected cluster to all other clusters with a very small weight di = static_cast<K>(1); K q = di / static_cast<K>(dim-1); for(unsigned int j=0; j<dim; j++) { if(j == i) continue; W(i,j) = q; W(j,i) = q; } } } #ifdef SPECTRAL_VERBOSE if(!nodes_with_no_connection.empty()) { std::cout << "DEBUG: Nodes without connections (#=" << nodes_with_no_connection.size() << "): "; for(int i : nodes_with_no_connection) { std::cout << i << ", "; } std::cout << std::endl; } #endif // compute matrix L = D - W matrix_t L = -W; for(unsigned int i=0; i<dim; i++) { L(i,i) += D[i]; } // ready return { L, D }; }
void MultiAppUserObjectTransfer::execute() { _console << "Beginning MultiAppUserObjectTransfer " << name() << std::endl; switch (_direction) { case TO_MULTIAPP: { for (unsigned int i = 0; i < _multi_app->numGlobalApps(); i++) { if (_multi_app->hasLocalApp(i)) { Moose::ScopedCommSwapper swapper(_multi_app->comm()); // Loop over the master nodes and set the value of the variable System * to_sys = find_sys(_multi_app->appProblemBase(i).es(), _to_var_name); unsigned int sys_num = to_sys->number(); unsigned int var_num = to_sys->variable_number(_to_var_name); NumericVector<Real> & solution = _multi_app->appTransferVector(i, _to_var_name); MeshBase * mesh = NULL; if (_displaced_target_mesh && _multi_app->appProblemBase(i).getDisplacedProblem()) { mesh = &_multi_app->appProblemBase(i).getDisplacedProblem()->mesh().getMesh(); } else mesh = &_multi_app->appProblemBase(i).mesh().getMesh(); bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE; const UserObject & user_object = _multi_app->problemBase().getUserObjectBase(_user_object_name); if (is_nodal) { for (auto & node : mesh->local_node_ptr_range()) { if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node { // The zero only works for LAGRANGE! dof_id_type dof = node->dof_number(sys_num, var_num, 0); swapper.forceSwap(); Real from_value = user_object.spatialValue(*node + _multi_app->position(i)); swapper.forceSwap(); solution.set(dof, from_value); } } } else // Elemental { for (auto & elem : as_range(mesh->local_elements_begin(), mesh->local_elements_end())) { Point centroid = elem->centroid(); if (elem->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this elem { // The zero only works for LAGRANGE! dof_id_type dof = elem->dof_number(sys_num, var_num, 0); swapper.forceSwap(); Real from_value = user_object.spatialValue(centroid + _multi_app->position(i)); swapper.forceSwap(); solution.set(dof, from_value); } } } solution.close(); to_sys->update(); } } break; } case FROM_MULTIAPP: { FEProblemBase & to_problem = _multi_app->problemBase(); MooseVariableFEBase & to_var = to_problem.getVariable( 0, _to_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD); SystemBase & to_system_base = to_var.sys(); System & to_sys = to_system_base.system(); unsigned int to_sys_num = to_sys.number(); // Only works with a serialized mesh to transfer to! mooseAssert(to_sys.get_mesh().is_serial(), "MultiAppUserObjectTransfer only works with ReplicatedMesh!"); unsigned int to_var_num = to_sys.variable_number(to_var.name()); _console << "Transferring to: " << to_var.name() << std::endl; // EquationSystems & to_es = to_sys.get_equation_systems(); // Create a serialized version of the solution vector NumericVector<Number> * to_solution = to_sys.solution.get(); MeshBase * to_mesh = NULL; if (_displaced_target_mesh && to_problem.getDisplacedProblem()) to_mesh = &to_problem.getDisplacedProblem()->mesh().getMesh(); else to_mesh = &to_problem.mesh().getMesh(); bool is_nodal = to_sys.variable_type(to_var_num).family == LAGRANGE; for (unsigned int i = 0; i < _multi_app->numGlobalApps(); i++) { if (!_multi_app->hasLocalApp(i)) continue; Point app_position = _multi_app->position(i); BoundingBox app_box = _multi_app->getBoundingBox(i, _displaced_source_mesh); const UserObject & user_object = _multi_app->appUserObjectBase(i, _user_object_name); if (is_nodal) { for (auto & node : to_mesh->node_ptr_range()) { if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node { // See if this node falls in this bounding box if (app_box.contains_point(*node)) { dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0); Real from_value = 0; { Moose::ScopedCommSwapper swapper(_multi_app->comm()); from_value = user_object.spatialValue(*node - app_position); } to_solution->set(dof, from_value); } } } } else // Elemental { for (auto & elem : as_range(to_mesh->elements_begin(), to_mesh->elements_end())) { if (elem->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this elem { Point centroid = elem->centroid(); // See if this elem falls in this bounding box if (app_box.contains_point(centroid)) { dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, 0); Real from_value = 0; { Moose::ScopedCommSwapper swapper(_multi_app->comm()); from_value = user_object.spatialValue(centroid - app_position); } to_solution->set(dof, from_value); } } } } } to_solution->close(); to_sys.update(); break; } } _console << "Finished MultiAppUserObjectTransfer " << name() << std::endl; }
void MetisPartitioner::partition_range(MeshBase & mesh, MeshBase::element_iterator beg, MeshBase::element_iterator end, unsigned int n_pieces) { libmesh_assert_greater (n_pieces, 0); // We don't yet support distributed meshes with this Partitioner if (!mesh.is_serial()) libmesh_not_implemented(); // Check for an easy return if (n_pieces == 1) { this->single_partition_range (beg, end); return; } // What to do if the Metis library IS NOT present #ifndef LIBMESH_HAVE_METIS libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Metis support. Using a space-filling curve" << std::endl << "partitioner instead!" << std::endl; SFCPartitioner sfcp; sfcp.partition_range (mesh, beg, end, n_pieces); // What to do if the Metis library IS present #else LOG_SCOPE("partition_range()", "MetisPartitioner"); const dof_id_type n_range_elem = std::distance(beg, end); // Metis will only consider the elements in the range. // We need to map the range element ids into a // contiguous range. Further, we want the unique range indexing to be // independent of the element ordering, otherwise a circular dependency // can result in which the partitioning depends on the ordering which // depends on the partitioning... vectormap<dof_id_type, dof_id_type> global_index_map; global_index_map.reserve (n_range_elem); { std::vector<dof_id_type> global_index; MeshCommunication().find_global_indices (mesh.comm(), MeshTools::create_bounding_box(mesh), beg, end, global_index); libmesh_assert_equal_to (global_index.size(), n_range_elem); MeshBase::element_iterator it = beg; for (std::size_t cnt=0; it != end; ++it) { const Elem * elem = *it; global_index_map.insert (std::make_pair(elem->id(), global_index[cnt++])); } libmesh_assert_equal_to (global_index_map.size(), n_range_elem); } // If we have boundary elements in this mesh, we want to account for // the connectivity between them and interior elements. We can find // interior elements from boundary elements, but we need to build up // a lookup map to do the reverse. typedef std::unordered_multimap<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::element_iterator it = beg; for (; it != end; ++it) { const Elem * elem = *it; // If we don't have an interior_parent then there's nothing // to look us up. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; // get all relevant interior elements std::set<const Elem *> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem *>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the std::set<const Elem // *> returning methods would be nice Elem * neighbor = const_cast<Elem *>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MULTIMAP) || \ defined(LIBMESH_HAVE_TR1_UNORDERED_MULTIMAP) || \ defined(LIBMESH_HAVE_HASH_MULTIMAP) || \ defined(LIBMESH_HAVE_EXT_HASH_MULTIMAP) interior_to_boundary_map.insert(std::make_pair(neighbor, elem)); #else interior_to_boundary_map.insert(interior_to_boundary_map.begin(), std::make_pair(neighbor, elem)); #endif } } } // Data structure that Metis will fill up on processor 0 and broadcast. std::vector<Metis::idx_t> part(n_range_elem); // Invoke METIS, but only on processor 0. // Then broadcast the resulting decomposition if (mesh.processor_id() == 0) { // Data structures and parameters needed only on processor 0 by Metis. // std::vector<Metis::idx_t> options(5); std::vector<Metis::idx_t> vwgt(n_range_elem); Metis::idx_t n = static_cast<Metis::idx_t>(n_range_elem), // number of "nodes" (elements) in the graph // wgtflag = 2, // weights on vertices only, none on edges // numflag = 0, // C-style 0-based numbering nparts = static_cast<Metis::idx_t>(n_pieces), // number of subdomains to create edgecut = 0; // the numbers of edges cut by the resulting partition // Set the options // options[0] = 0; // use default options // build the graph METIS_CSR_Graph<Metis::idx_t> csr_graph; csr_graph.offsets.resize(n_range_elem + 1, 0); // Local scope for these { // build the graph in CSR format. Note that // the edges in the graph will correspond to // face neighbors #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem *> neighbors_offspring; #endif #ifndef NDEBUG std::size_t graph_size=0; #endif // (1) first pass - get the row sizes for each element by counting the number // of face neighbors. Also populate the vwght array if necessary MeshBase::element_iterator it = beg; for (; it != end; ++it) { const Elem * elem = *it; const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, vwgt.size()); // maybe there is a better weight? // The weight is used to define what a balanced graph is if (!_weights) vwgt[elem_global_index] = elem->n_nodes(); else vwgt[elem_global_index] = static_cast<Metis::idx_t>((*_weights)[elem->id()]); unsigned int num_neighbors = 0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (auto neighbor : elem->neighbor_ptr_range()) { if (neighbor != libmesh_nullptr) { // If the neighbor is active, but is not in the // range of elements being partitioned, treat it // as a NULL neighbor. if (neighbor->active() && !global_index_map.count(neighbor->id())) continue; // If the neighbor is active treat it // as a connection if (neighbor->active()) num_neighbors++; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. // FIXME - this is the wrong thing, since we // should be getting the active family tree on // our side only. But adding too many graph // links may cause hanging nodes to tend to be // on partition interiors, which would reduce // communication overhead for constraint // equations, so we'll leave it. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (std::size_t nc=0; nc<neighbors_offspring.size(); nc++) { const Elem * child = neighbors_offspring[nc]; // Skip neighbor offspring which are not in the range of elements being partitioned. if (!global_index_map.count(child->id())) continue; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor_ptr(ns) == elem) { libmesh_assert (child->active()); num_neighbors++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } // Check for any interior neighbors if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem *> neighbor_set; elem->find_interior_neighbors(neighbor_set); num_neighbors += neighbor_set.size(); } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); num_neighbors += std::distance(bounds.first, bounds.second); csr_graph.prep_n_nonzeros(elem_global_index, num_neighbors); #ifndef NDEBUG graph_size += num_neighbors; #endif } csr_graph.prepare_for_use(); // (2) second pass - fill the compressed adjacency array it = beg; for (; it != end; ++it) { const Elem * elem = *it; const dof_id_type elem_global_index = global_index_map[elem->id()]; unsigned int connection=0; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (auto neighbor : elem->neighbor_ptr_range()) { if (neighbor != libmesh_nullptr) { // If the neighbor is active, but is not in the // range of elements being partitioned, treat it // as a NULL neighbor. if (neighbor->active() && !global_index_map.count(neighbor->id())) continue; // If the neighbor is active treat it // as a connection if (neighbor->active()) csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (std::size_t nc=0; nc<neighbors_offspring.size(); nc++) { const Elem * child = neighbors_offspring[nc]; // Skip neighbor offspring which are not in the range of elements being partitioned. if (!global_index_map.count(child->id())) continue; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor_ptr(ns) == elem) { libmesh_assert (child->active()); csr_graph(elem_global_index, connection++) = global_index_map[child->id()]; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem *> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem *>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { const Elem * neighbor = *n_it; // Not all interior neighbors are necessarily in // the same Mesh (hence not in the global_index_map). // This will be the case when partitioning a // BoundaryMesh, whose elements all have // interior_parents() that belong to some other // Mesh. const Elem * queried_elem = mesh.query_elem_ptr(neighbor->id()); // Compare the neighbor and the queried_elem // pointers, make sure they are the same. if (queried_elem && queried_elem == neighbor) { vectormap<dof_id_type, dof_id_type>::iterator global_index_map_it = global_index_map.find(neighbor->id()); // If the interior_neighbor is in the Mesh but // not in the global_index_map, we have other issues. if (global_index_map_it == global_index_map.end()) libmesh_error_msg("Interior neighbor with id " << neighbor->id() << " not found in global_index_map."); else csr_graph(elem_global_index, connection++) = global_index_map_it->second; } } } // Check for any boundary neighbors for (const auto & pr : as_range(interior_to_boundary_map.equal_range(elem))) { const Elem * neighbor = pr.second; csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()]; } } // We create a non-empty vals for a disconnected graph, to // work around a segfault from METIS. libmesh_assert_equal_to (csr_graph.vals.size(), std::max(graph_size, std::size_t(1))); } // done building the graph Metis::idx_t ncon = 1; // Select which type of partitioning to create // Use recursive if the number of partitions is less than or equal to 8 if (n_pieces <= 8) Metis::METIS_PartGraphRecursive(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr, libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr, &edgecut, &part[0]); // Otherwise use kway else Metis::METIS_PartGraphKway(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr, libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr, &edgecut, &part[0]); } // end processor 0 part // Broadcast the resulting partition mesh.comm().broadcast(part); // Assign the returned processor ids. The part array contains // the processor id for each active element, but in terms of // the contiguous indexing we defined above { MeshBase::element_iterator it = beg; for (; it!=end; ++it) { Elem * elem = *it; libmesh_assert (global_index_map.count(elem->id())); const dof_id_type elem_global_index = global_index_map[elem->id()]; libmesh_assert_less (elem_global_index, part.size()); const processor_id_type elem_procid = static_cast<processor_id_type>(part[elem_global_index]); elem->processor_id() = elem_procid; } } #endif }
void DefaultCoupling::operator() (const MeshBase::const_element_iterator & range_begin, const MeshBase::const_element_iterator & range_end, processor_id_type p, map_type & coupled_elements) { LOG_SCOPE("operator()", "DefaultCoupling"); #ifdef LIBMESH_ENABLE_PERIODIC bool check_periodic_bcs = (_periodic_bcs && !_periodic_bcs->empty()); std::unique_ptr<PointLocatorBase> point_locator; if (check_periodic_bcs) { libmesh_assert(_mesh); point_locator = _mesh->sub_point_locator(); } #endif if (!this->_n_levels) { for (const auto & elem : as_range(range_begin, range_end)) if (elem->processor_id() != p) coupled_elements.insert (std::make_pair(elem,_dof_coupling)); return; } typedef std::unordered_set<const Elem*> set_type; set_type next_elements_to_check(range_begin, range_end); set_type elements_to_check; set_type elements_checked; for (unsigned int i=0; i != this->_n_levels; ++i) { elements_to_check.swap(next_elements_to_check); next_elements_to_check.clear(); elements_checked.insert(elements_to_check.begin(), elements_to_check.end()); for (const auto & elem : elements_to_check) { std::vector<const Elem *> active_neighbors; if (elem->processor_id() != p) coupled_elements.insert (std::make_pair(elem,_dof_coupling)); for (auto s : elem->side_index_range()) { const Elem * neigh = elem->neighbor_ptr(s); // If we have a neighbor here if (neigh) { // Mesh ghosting might ask us about what we want to // distribute along with non-local elements, and those // non-local elements might have remote neighbors, and // if they do then we can't say anything about them. if (neigh == remote_elem) continue; } #ifdef LIBMESH_ENABLE_PERIODIC // We might still have a periodic neighbor here else if (check_periodic_bcs) { libmesh_assert(_mesh); neigh = elem->topological_neighbor (s, *_mesh, *point_locator, _periodic_bcs); } #endif // With no regular *or* periodic neighbors we have nothing // to do. if (!neigh) continue; // With any kind of neighbor, we need to couple to all the // active descendants on our side. #ifdef LIBMESH_ENABLE_AMR if (neigh == elem->neighbor_ptr(s)) neigh->active_family_tree_by_neighbor(active_neighbors,elem); # ifdef LIBMESH_ENABLE_PERIODIC else neigh->active_family_tree_by_topological_neighbor (active_neighbors,elem,*_mesh,*point_locator,_periodic_bcs); # endif #else active_neighbors.clear(); active_neighbors.push_back(neigh); #endif for (const auto & neighbor : active_neighbors) { if (!elements_checked.count(neighbor)) next_elements_to_check.insert(neighbor); if (neighbor->processor_id() != p) coupled_elements.insert (std::make_pair(neighbor, _dof_coupling)); } } } } }
/* static char * pyobject_to_str(PyObject * py_obj) { if ( PyStr_Check(py_obj) ) { return PyStr_AsString(py_obj); } else { return NULL; } } */ static int AerospikeQuery_Where_Add(AerospikeQuery * self, as_predicate_type predicate, as_index_datatype in_datatype, PyObject * py_bin, PyObject * py_val1, PyObject * py_val2, int index_type) { as_error err; char * val = NULL, * bin = NULL; PyObject * py_ubin = NULL; switch (predicate) { case AS_PREDICATE_EQUAL: { if ( in_datatype == AS_INDEX_STRING ){ if (PyUnicode_Check(py_bin)){ py_ubin = PyUnicode_AsUTF8String(py_bin); bin = PyStr_AsString(py_ubin); } else if (PyStr_Check(py_bin) ){ bin = PyStr_AsString(py_bin); } else { return 1; } if (PyUnicode_Check(py_val1)){ val = strdup(PyStr_AsString( StoreUnicodePyObject( self, PyUnicode_AsUTF8String(py_val1) ))); } else if (PyStr_Check(py_val1) ){ val = strdup(PyStr_AsString(py_val1)); } else { return 1; } as_query_where_init(&self->query, 1); if(index_type == 0) { as_query_where(&self->query, bin, as_equals( STRING, val )); } else if(index_type == 1) { as_query_where(&self->query, bin, as_contains( LIST, STRING, val )); } else if(index_type == 2) { as_query_where(&self->query, bin, as_contains( MAPKEYS, STRING, val )); } else if(index_type == 3) { as_query_where(&self->query, bin, as_contains( MAPVALUES, STRING, val )); } else { return 1; } if (py_ubin){ Py_DECREF(py_ubin); py_ubin = NULL; } } else if ( in_datatype == AS_INDEX_NUMERIC ){ if (PyUnicode_Check(py_bin)){ py_ubin = PyUnicode_AsUTF8String(py_bin); bin = PyStr_AsString(py_ubin); } else if (PyStr_Check(py_bin) ){ bin = PyStr_AsString(py_bin); } else { return 1; } int64_t val = pyobject_to_int64(py_val1); as_query_where_init(&self->query, 1); if(index_type == 0) { as_query_where(&self->query, bin, as_equals( NUMERIC, val )); } else if(index_type == 1) { as_query_where(&self->query, bin, as_contains( LIST, NUMERIC, val )); } else if(index_type == 2) { as_query_where(&self->query, bin, as_contains( MAPKEYS, NUMERIC, val )); } else if(index_type == 3) { as_query_where(&self->query, bin, as_contains( MAPVALUES, NUMERIC, val )); } else { return 1; } if (py_ubin){ Py_DECREF(py_ubin); py_ubin = NULL; } } else { // If it ain't expected, raise and error as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'equals' expects a string or integer value."); PyObject * py_err = NULL; error_to_pyobject(&err, &py_err); PyErr_SetObject(PyExc_Exception, py_err); return 1; } break; } case AS_PREDICATE_RANGE: { if ( in_datatype == AS_INDEX_NUMERIC) { if (PyUnicode_Check(py_bin)){ py_ubin = PyUnicode_AsUTF8String(py_bin); bin = PyStr_AsString(py_ubin); } else if (PyStr_Check(py_bin)){ bin = PyStr_AsString(py_bin); } else { return 1; } int64_t min = pyobject_to_int64(py_val1); int64_t max = pyobject_to_int64(py_val2); as_query_where_init(&self->query, 1); if(index_type == 0) { as_query_where(&self->query, bin, as_range( DEFAULT, NUMERIC, min, max )); } else if(index_type == 1) { as_query_where(&self->query, bin, as_range( LIST, NUMERIC, min, max )); } else if(index_type == 2) { as_query_where(&self->query, bin, as_range( MAPKEYS, NUMERIC, min, max )); } else if(index_type == 3) { as_query_where(&self->query, bin, as_range( MAPVALUES, NUMERIC, min, max )); } else { return 1; } if (py_ubin){ Py_DECREF(py_ubin); py_ubin = NULL; } } else if ( in_datatype == AS_INDEX_STRING) { // NOT IMPLEMENTED } else { // If it ain't right, raise and error as_error_update(&err, AEROSPIKE_ERR_PARAM, "predicate 'between' expects two integer values."); PyObject * py_err = NULL; error_to_pyobject(&err, &py_err); PyErr_SetObject(PyExc_Exception, py_err); return 1; } break; } default: { // If it ain't supported, raise and error as_error_update(&err, AEROSPIKE_ERR_PARAM, "unknown predicate type"); PyObject * py_err = NULL; error_to_pyobject(&err, &py_err); PyErr_SetObject(PyExc_Exception, py_err); return 1; } } return 0; }
void MultiAppNearestNodeTransfer::execute() { _console << "Beginning NearestNodeTransfer " << name() << std::endl; getAppInfo(); // Get the bounding boxes for the "from" domains. std::vector<BoundingBox> bboxes; if (isParamValid("source_boundary")) bboxes = getFromBoundingBoxes( _from_meshes[0]->getBoundaryID(getParam<BoundaryName>("source_boundary"))); else bboxes = getFromBoundingBoxes(); // Figure out how many "from" domains each processor owns. std::vector<unsigned int> froms_per_proc = getFromsPerProc(); //////////////////// // For every point in the local "to" domain, figure out which "from" domains // might contain it's nearest neighbor, and send that point to the processors // that own those "from" domains. // // How do we know which "from" domains might contain the nearest neighbor, you // ask? Well, consider two "from" domains, A and B. If every point in A is // closer than every point in B, then we know that B cannot possibly contain // the nearest neighbor. Hence, we'll only check A for the nearest neighbor. // We'll use the functions bboxMaxDistance and bboxMinDistance to figure out // if every point in A is closer than every point in B. //////////////////// // outgoing_qps = nodes/centroids we'll send to other processors. std::vector<std::vector<Point>> outgoing_qps(n_processors()); // When we get results back, node_index_map will tell us which results go with // which points std::vector<std::map<std::pair<unsigned int, unsigned int>, unsigned int>> node_index_map( n_processors()); if (!_neighbors_cached) { for (unsigned int i_to = 0; i_to < _to_problems.size(); i_to++) { System * to_sys = find_sys(*_to_es[i_to], _to_var_name); unsigned int sys_num = to_sys->number(); unsigned int var_num = to_sys->variable_number(_to_var_name); MeshBase * to_mesh = &_to_meshes[i_to]->getMesh(); bool is_to_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_to_nodal) { std::vector<Node *> target_local_nodes; if (isParamValid("target_boundary")) { BoundaryID target_bnd_id = _to_meshes[i_to]->getBoundaryID(getParam<BoundaryName>("target_boundary")); ConstBndNodeRange & bnd_nodes = *(_to_meshes[i_to])->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) if (bnode->_bnd_id == target_bnd_id && bnode->_node->processor_id() == processor_id()) target_local_nodes.push_back(bnode->_node); } else { target_local_nodes.resize(to_mesh->n_local_nodes()); unsigned int i = 0; for (auto & node : to_mesh->local_node_ptr_range()) target_local_nodes[i++] = node; } // For error checking: keep track of all target_local_nodes // which are successfully mapped to at least one domain where // the nearest neighbor might be found. std::set<Node *> local_nodes_found; for (const auto & node : target_local_nodes) { // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; // Find which bboxes might have the nearest node to this point. Real nearest_max_distance = std::numeric_limits<Real>::max(); for (const auto & bbox : bboxes) { Real distance = bboxMaxDistance(*node, bbox); if (distance < nearest_max_distance) nearest_max_distance = distance; } unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool qp_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && !qp_found; i_from++) { Real distance = bboxMinDistance(*node, bboxes[i_from]); if (distance <= nearest_max_distance || bboxes[i_from].contains_point(*node)) { std::pair<unsigned int, unsigned int> key(i_to, node->id()); node_index_map[i_proc][key] = outgoing_qps[i_proc].size(); outgoing_qps[i_proc].push_back(*node + _to_positions[i_to]); qp_found = true; local_nodes_found.insert(node); } } } } // By the time we get to here, we should have found at least // one candidate BoundingBox for every node in the // target_local_nodes array that has dofs for the current // variable in the current System. for (const auto & node : target_local_nodes) if (node->n_dofs(sys_num, var_num) && !local_nodes_found.count(node)) mooseError("In ", name(), ": No candidate BoundingBoxes found for node ", node->id(), " at position ", *node); } else // Elemental { // For error checking: keep track of all local elements // which are successfully mapped to at least one domain where // the nearest neighbor might be found. std::set<Elem *> local_elems_found; for (auto & elem : as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end())) { Point centroid = elem->centroid(); // Skip this element if the variable has no dofs at it. if (elem->n_dofs(sys_num, var_num) < 1) continue; // Find which bboxes might have the nearest node to this point. Real nearest_max_distance = std::numeric_limits<Real>::max(); for (const auto & bbox : bboxes) { Real distance = bboxMaxDistance(centroid, bbox); if (distance < nearest_max_distance) nearest_max_distance = distance; } unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool qp_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && !qp_found; i_from++) { Real distance = bboxMinDistance(centroid, bboxes[i_from]); if (distance <= nearest_max_distance || bboxes[i_from].contains_point(centroid)) { std::pair<unsigned int, unsigned int> key(i_to, elem->id()); node_index_map[i_proc][key] = outgoing_qps[i_proc].size(); outgoing_qps[i_proc].push_back(centroid + _to_positions[i_to]); qp_found = true; local_elems_found.insert(elem); } } } } // Verify that we found at least one candidate bounding // box for each local element with dofs for the current // variable in the current System. for (auto & elem : as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end())) if (elem->n_dofs(sys_num, var_num) && !local_elems_found.count(elem)) mooseError("In ", name(), ": No candidate BoundingBoxes found for Elem ", elem->id(), ", centroid = ", elem->centroid()); } } } //////////////////// // Send local node/centroid positions off to the other processors and take // care of points sent to this processor. We'll need to check the points // against all of the "from" domains that this processor owns. For each // point, we'll find the nearest node, then we'll send the value at that node // and the distance between the node and the point back to the processor that // requested that point. //////////////////// std::vector<std::vector<Real>> incoming_evals(n_processors()); std::vector<Parallel::Request> send_qps(n_processors()); std::vector<Parallel::Request> send_evals(n_processors()); // Create these here so that they live the entire life of this function // and are NOT reused per processor. std::vector<std::vector<Real>> processor_outgoing_evals(n_processors()); if (!_neighbors_cached) { for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; _communicator.send(i_proc, outgoing_qps[i_proc], send_qps[i_proc]); } // Build an array of pointers to all of this processor's local entities (nodes or // elements). We need to do this to avoid the expense of using LibMesh iterators. // This step also takes care of limiting the search to boundary nodes, if // applicable. std::vector<std::vector<std::pair<Point, DofObject *>>> local_entities( froms_per_proc[processor_id()]); // Local array of all from Variable references std::vector<std::reference_wrapper<MooseVariableFEBase>> _from_vars; for (unsigned int i = 0; i < froms_per_proc[processor_id()]; i++) { MooseVariableFEBase & from_var = _from_problems[i]->getVariable( 0, _from_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD); bool is_to_nodal = from_var.feType().family == LAGRANGE; _from_vars.emplace_back(from_var); getLocalEntities(_from_meshes[i], local_entities[i], is_to_nodal); } if (_fixed_meshes) { _cached_froms.resize(n_processors()); _cached_dof_ids.resize(n_processors()); } for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { // We either use our own outgoing_qps or receive them from // another processor. std::vector<Point> incoming_qps; if (i_proc == processor_id()) incoming_qps = outgoing_qps[i_proc]; else _communicator.receive(i_proc, incoming_qps); if (_fixed_meshes) { _cached_froms[i_proc].resize(incoming_qps.size()); _cached_dof_ids[i_proc].resize(incoming_qps.size()); } std::vector<Real> & outgoing_evals = processor_outgoing_evals[i_proc]; // Resize this vector to two times the size of the incoming_qps // vector because we are going to store both the value from the nearest // local node *and* the distance between the incoming_qp and that node // for later comparison purposes. outgoing_evals.resize(2 * incoming_qps.size()); for (unsigned int qp = 0; qp < incoming_qps.size(); qp++) { const Point & qpt = incoming_qps[qp]; outgoing_evals[2 * qp] = std::numeric_limits<Real>::max(); for (unsigned int i_local_from = 0; i_local_from < froms_per_proc[processor_id()]; i_local_from++) { MooseVariableFEBase & from_var = _from_vars[i_local_from]; System & from_sys = from_var.sys().system(); unsigned int from_sys_num = from_sys.number(); unsigned int from_var_num = from_sys.variable_number(from_var.name()); for (unsigned int i_node = 0; i_node < local_entities[i_local_from].size(); i_node++) { // Compute distance between the current incoming_qp to local node i_node. Real current_distance = (qpt - local_entities[i_local_from][i_node].first - _from_positions[i_local_from]) .norm(); // If an incoming_qp is equally close to two or more local nodes, then // the first one we test will "win", even though any of the others could // also potentially be chosen instead... there's no way to decide among // the set of all equidistant points. // // outgoing_evals[2 * qp] is the current closest distance between a local point and // the incoming_qp. if (current_distance < outgoing_evals[2 * qp]) { // Assuming LAGRANGE! if (local_entities[i_local_from][i_node].second->n_dofs(from_sys_num, from_var_num) > 0) { dof_id_type from_dof = local_entities[i_local_from][i_node].second->dof_number( from_sys_num, from_var_num, 0); // The indexing of the outgoing_evals vector looks // like [(distance, value), (distance, value), ...] // for each incoming_qp. We only keep the value from // the node with the smallest distance to the // incoming_qp, and then we compare across all // processors later and pick the closest one. outgoing_evals[2 * qp] = current_distance; outgoing_evals[2 * qp + 1] = (*from_sys.solution)(from_dof); if (_fixed_meshes) { // Cache the nearest nodes. _cached_froms[i_proc][qp] = i_local_from; _cached_dof_ids[i_proc][qp] = from_dof; } } } } } } if (i_proc == processor_id()) incoming_evals[i_proc] = outgoing_evals; else _communicator.send(i_proc, outgoing_evals, send_evals[i_proc]); } } else // We've cached the nearest nodes. { for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { std::vector<Real> & outgoing_evals = processor_outgoing_evals[i_proc]; outgoing_evals.resize(_cached_froms[i_proc].size()); for (unsigned int qp = 0; qp < outgoing_evals.size(); qp++) { MooseVariableFEBase & from_var = _from_problems[_cached_froms[i_proc][qp]]->getVariable( 0, _from_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD); System & from_sys = from_var.sys().system(); dof_id_type from_dof = _cached_dof_ids[i_proc][qp]; // outgoing_evals[qp] = (*from_sys.solution)(_cached_dof_ids[i_proc][qp]); outgoing_evals[qp] = (*from_sys.solution)(from_dof); } if (i_proc == processor_id()) incoming_evals[i_proc] = outgoing_evals; else _communicator.send(i_proc, outgoing_evals, send_evals[i_proc]); } } //////////////////// // Gather all of the evaluations, find the nearest one for each node/element, // and apply the values. //////////////////// for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; _communicator.receive(i_proc, incoming_evals[i_proc]); } for (unsigned int i_to = 0; i_to < _to_problems.size(); i_to++) { // Loop over the master nodes and set the value of the variable System * to_sys = find_sys(*_to_es[i_to], _to_var_name); unsigned int sys_num = to_sys->number(); unsigned int var_num = to_sys->variable_number(_to_var_name); NumericVector<Real> * solution = nullptr; switch (_direction) { case TO_MULTIAPP: solution = &getTransferVector(i_to, _to_var_name); break; case FROM_MULTIAPP: solution = to_sys->solution.get(); break; default: mooseError("Unknown direction"); } const MeshBase & to_mesh = _to_meshes[i_to]->getMesh(); bool is_to_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_to_nodal) { std::vector<Node *> target_local_nodes; if (isParamValid("target_boundary")) { BoundaryID target_bnd_id = _to_meshes[i_to]->getBoundaryID(getParam<BoundaryName>("target_boundary")); ConstBndNodeRange & bnd_nodes = *(_to_meshes[i_to])->getBoundaryNodeRange(); for (const auto & bnode : bnd_nodes) if (bnode->_bnd_id == target_bnd_id && bnode->_node->processor_id() == processor_id()) target_local_nodes.push_back(bnode->_node); } else { target_local_nodes.resize(to_mesh.n_local_nodes()); unsigned int i = 0; for (auto & node : to_mesh.local_node_ptr_range()) target_local_nodes[i++] = node; } for (const auto & node : target_local_nodes) { // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; // If nothing is in the node_index_map for a given local node, // it will get the value 0. Real best_val = 0; if (!_neighbors_cached) { // Search through all the incoming evaluation points from // different processors for the one with the closest // point. If there are multiple values from other processors // which are equidistant, the first one we check will "win". Real min_dist = std::numeric_limits<Real>::max(); for (unsigned int i_from = 0; i_from < incoming_evals.size(); i_from++) { std::pair<unsigned int, unsigned int> key(i_to, node->id()); if (node_index_map[i_from].find(key) == node_index_map[i_from].end()) continue; unsigned int qp_ind = node_index_map[i_from][key]; if (incoming_evals[i_from][2 * qp_ind] >= min_dist) continue; // If we made it here, we are going set a new value and // distance because we found one that was closer. min_dist = incoming_evals[i_from][2 * qp_ind]; best_val = incoming_evals[i_from][2 * qp_ind + 1]; if (_fixed_meshes) { // Cache these indices. _cached_from_inds[node->id()] = i_from; _cached_qp_inds[node->id()] = qp_ind; } } } else { best_val = incoming_evals[_cached_from_inds[node->id()]][_cached_qp_inds[node->id()]]; } dof_id_type dof = node->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } else // Elemental { for (auto & elem : to_mesh.active_local_element_ptr_range()) { // Skip this element if the variable has no dofs at it. if (elem->n_dofs(sys_num, var_num) < 1) continue; Real best_val = 0; if (!_neighbors_cached) { Real min_dist = std::numeric_limits<Real>::max(); for (unsigned int i_from = 0; i_from < incoming_evals.size(); i_from++) { std::pair<unsigned int, unsigned int> key(i_to, elem->id()); if (node_index_map[i_from].find(key) == node_index_map[i_from].end()) continue; unsigned int qp_ind = node_index_map[i_from][key]; if (incoming_evals[i_from][2 * qp_ind] >= min_dist) continue; min_dist = incoming_evals[i_from][2 * qp_ind]; best_val = incoming_evals[i_from][2 * qp_ind + 1]; if (_fixed_meshes) { // Cache these indices. _cached_from_inds[elem->id()] = i_from; _cached_qp_inds[elem->id()] = qp_ind; } } } else { best_val = incoming_evals[_cached_from_inds[elem->id()]][_cached_qp_inds[elem->id()]]; } dof_id_type dof = elem->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } solution->close(); to_sys->update(); } if (_fixed_meshes) _neighbors_cached = true; // Make sure all our sends succeeded. for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; send_qps[i_proc].wait(); send_evals[i_proc].wait(); } _console << "Finished NearestNodeTransfer " << name() << std::endl; }
SparseGEVT<K> sparse_graph_entries(const Graph& graph, EdgeWeightMap edge_weights) { // We want to solve the EV problem: (D - W) x = \lamda D x. // Each edge of the graph defines two entries into the symmetric matrix W. // The diagonal matrix D is defined via d_i = sum_j{w_ij}. // As D is a diagonal matrix the the general problem can be easily transformed // into a normal eigenvalue problem by decomposing D = L L^t, which yields L = sqrt(D). // Thus the EV problem is: L^{-1} (D - W) L^{-T} y = \lambda y. // Eigenvectors can be transformed using x = L^{-T} y. // The dimension of the problem const int n = boost::num_vertices(graph); // Each edge defines two entries (one in the upper and one in the lower). // In addition all diagonal entries are non-zero. // Thus the number of non-zero entries in the lower triangle is equal to // the number of edges plus the number of nodes. // This is not entirely true as some connections are possibly rejected. // Additionally some connections may be added to assure global connectivity. const int nnz_guess = boost::num_edges(graph) + n; // collect all non-zero elements SparseGEVT<K> sgevt; sgevt.A.dim = n; std::vector<SparseEntry>& entries = sgevt.A.entries; entries.reserve(nnz_guess); // also collect diagonal entries Eigen::VectorXf& diag = sgevt.D_inv_sqrt; diag = Eigen::VectorXf(n); // no collect entries for(auto eid : as_range(boost::edges(graph))) { int ea = static_cast<int>(boost::source(eid, graph)); int eb = static_cast<int>(boost::target(eid, graph)); K ew = edge_weights[eid]; // assure correct edge weight if(std::isnan(ew)) { std::cerr << "ERROR: Weight for edge (" << ea << "," << eb << ") is nan!" << std::endl; continue; } if(ew < 0) { std::cerr << "ERROR: Weight for edge (" << ea << "," << eb << ") is negative!" << std::endl; continue; } // assure that no vertices is connected to self if(ea == eb) { std::cerr << "ERROR: Vertex " << ea << " is connected to self!" << std::endl; continue; } // In the lower triangle the row index i is bigger or equal than the column index j. // The next statement fullfills this requirement. if(ea < eb) { std::swap(ea, eb); } entries.push_back(SparseEntry{static_cast<unsigned int>(ea), static_cast<unsigned int>(eb), ew}); diag[ea] += ew; diag[eb] += ew; } // do the conversion to a normal ev problem // assure global connectivity for(unsigned int i=0; i<diag.size(); i++) { K& v = diag[i]; if(v == 0) { // connect the disconnected cluster to all other clusters with a very small weight v = static_cast<K>(1); K q = static_cast<K>(1) / static_cast<K>(n-1); for(unsigned int j=0; j<i; j++) { auto it = std::find_if(entries.begin(), entries.end(), [i, j](const SparseEntry& e) { return e.i == i && e.j == j; }); if(it == entries.end()) { entries.push_back(SparseEntry{i, j, q}); } } for(unsigned int j=i+1; j<n; j++) { auto it = std::find_if(entries.begin(), entries.end(), [j, i](const SparseEntry& e) { return e.i == j && e.j == i; }); if(it == entries.end()) { entries.push_back(SparseEntry{j, i, q}); } } std::cerr << "ERROR: Diagonal is 0! (i=" << i << ")" << std::endl; } else { v = static_cast<K>(1) / std::sqrt(v); } } // a_ij for the transformed "normal" EV problem // A x = \lambda x // is computed as follow from the diagonal matrix D and the weight // matrix W of the general EV problem // (D - W) x = \lambda D x // as follows: // a_ij = - w_ij / sqrt(d_i * d_j) if i != j // a_ii = 1 for(SparseEntry& e : entries) { e.weight = - e.weight * diag[e.i] * diag[e.j]; } for(unsigned int i=0; i<n; i++) { entries.push_back(SparseEntry{i, i, static_cast<K>(1)}); } // sort entries to form a lower triangle matrix std::sort(entries.begin(), entries.end(), [](const SparseEntry& a, const SparseEntry& b) { return (a.j != b.j) ? (a.j < b.j) : (a.i < b.i); }); return sgevt; }