void MeshRefinement::flag_elements_by_error_tolerance (const ErrorVector & error_per_cell_in) { parallel_object_only(); libmesh_assert_greater (_coarsen_threshold, 0); // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // How much error per cell will we tolerate? const Real local_refinement_tolerance = _absolute_global_tolerance / std::sqrt(static_cast<Real>(_mesh.n_active_elem())); const Real local_coarsening_tolerance = local_refinement_tolerance * _coarsen_threshold; // Prepare another error vector if we need to sum parent errors ErrorVector error_per_parent; if (_coarsen_by_parents) { Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell_in, error_per_parent, parent_error_min, parent_error_max); } for (auto & elem : _mesh.active_element_ptr_range()) { Elem * parent = elem->parent(); const dof_id_type elem_number = elem->id(); const ErrorVectorReal elem_error = error_per_cell_in[elem_number]; if (elem_error > local_refinement_tolerance && elem->level() < _max_h_level) elem->set_refinement_flag(Elem::REFINE); if (!_coarsen_by_parents && elem_error < local_coarsening_tolerance) elem->set_refinement_flag(Elem::COARSEN); if (_coarsen_by_parents && parent) { ErrorVectorReal parent_error = error_per_parent[parent->id()]; if (parent_error >= 0.) { const Real parent_coarsening_tolerance = std::sqrt(parent->n_children() * local_coarsening_tolerance * local_coarsening_tolerance); if (parent_error < parent_coarsening_tolerance) elem->set_refinement_flag(Elem::COARSEN); } } } }
int main (int argc, char** argv){ LibMeshInit init (argc, argv); //initialize libmesh library std::cout << "Running " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; Mesh mesh(init.comm()); mesh.read("channel_long.exo"); std::string stash_assign = "divvy.txt"; std::ofstream output(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; if(output.is_open()){ output << elem->id() << " " << elem->subdomain_id() << "\n"; } } output.close(); return 0; }
void GrainTracker::calculateBubbleVolumes() { Moose::perf_log.push("calculateBubbleVolumes()", "GrainTracker"); // The size of the bubble array will be sized to the max index of the unique grains map unsigned int max_id = _unique_grains.size() ? _unique_grains.rbegin()->first + 1: 0; _all_feature_volumes.resize(max_id, 0); const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end(); for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el) { Elem * elem = *el; unsigned int elem_n_nodes = elem->n_nodes(); Real curr_volume = elem->volume(); for (std::map<unsigned int, MooseSharedPointer<FeatureData> >::iterator it = _unique_grains.begin(); it != _unique_grains.end(); ++it) { if (it->second->_status == INACTIVE) continue; if (_is_elemental) { dof_id_type elem_id = elem->id(); if (it->second->_local_ids.find(elem_id) != it->second->_local_ids.end()) { mooseAssert(it->first < _all_feature_volumes.size(), "_all_feature_volumes access out of bounds"); _all_feature_volumes[it->first] += curr_volume; break; } } else { // Count the number of nodes on this element which are flooded. unsigned int flooded_nodes = 0; for (unsigned int node = 0; node < elem_n_nodes; ++node) { dof_id_type node_id = elem->node(node); if (it->second->_local_ids.find(node_id) != it->second->_local_ids.end()) ++flooded_nodes; } // If a majority of the nodes for this element are flooded, // assign its volume to the current bubble_counter entry. if (flooded_nodes >= elem_n_nodes / 2) _all_feature_volumes[it->first] += curr_volume; } } } // do all the sums! _communicator.sum(_all_feature_volumes); Moose::perf_log.pop("calculateBubbleVolumes()", "GrainTracker"); }
Elem* SerialMesh::insert_elem (Elem* e) { unsigned int eid = e->id(); libmesh_assert(eid < _elements.size()); Elem *oldelem = _elements[eid]; if (oldelem) { libmesh_assert(oldelem->id() == eid); this->delete_elem(oldelem); } _elements[e->id()] = e; return e; }
void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Get the mean value from the error vector const Real mean = error_per_cell.mean(); // Get the standard deviation. This equals the // square-root of the variance const Real stddev = std::sqrt (error_per_cell.variance()); // Check for valid fractions libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // The refine and coarsen cutoff const Real refine_cutoff = mean + _refine_fraction * stddev; const Real coarsen_cutoff = std::max(mean - _coarsen_fraction * stddev, 0.); // Loop over the elements and flag them for coarsening or // refinement based on the element error MeshBase::element_iterator elem_it = _mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; const unsigned int id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const float elem_error = error_per_cell[id]; // Possibly flag the element for coarsening ... if (elem_error <= coarsen_cutoff) elem->set_refinement_flag(Elem::COARSEN); // ... or refinement if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level)) elem->set_refinement_flag(Elem::REFINE); } }
//----------------------------------------------------------------- // Mesh refinement methods void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { parallel_only(); // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // We're getting the minimum and maximum error values // for the ACTIVE elements Real error_min = 1.e30; Real error_max = 0.; // And, if necessary, for their parents Real parent_error_min = 1.e30; Real parent_error_max = 0.; // Prepare another error vector if we need to sum parent errors ErrorVector error_per_parent; if (_coarsen_by_parents) { create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); } // We need to loop over all active elements to find the minimum MeshBase::element_iterator el_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator el_end = _mesh.active_local_elements_end(); for (; el_it != el_end; ++el_it) { const unsigned int id = (*el_it)->id(); libmesh_assert_less (id, error_per_cell.size()); error_max = std::max (error_max, error_per_cell[id]); error_min = std::min (error_min, error_per_cell[id]); } CommWorld.max(error_max); CommWorld.min(error_min); // Compute the cutoff values for coarsening and refinement const Real error_delta = (error_max - error_min); const Real parent_error_delta = parent_error_max - parent_error_min; const Real refine_cutoff = (1.- _refine_fraction)*error_max; const Real coarsen_cutoff = _coarsen_fraction*error_delta + error_min; const Real parent_cutoff = _coarsen_fraction*parent_error_delta + error_min; // // Print information about the error // libMesh::out << " Error Information:" << std::endl // << " ------------------" << std::endl // << " min: " << error_min << std::endl // << " max: " << error_max << std::endl // << " delta: " << error_delta << std::endl // << " refine_cutoff: " << refine_cutoff << std::endl // << " coarsen_cutoff: " << coarsen_cutoff << std::endl; // Loop over the elements and flag them for coarsening or // refinement based on the element error MeshBase::element_iterator e_it = _mesh.active_elements_begin(); const MeshBase::element_iterator e_end = _mesh.active_elements_end(); for (; e_it != e_end; ++e_it) { Elem* elem = *e_it; const unsigned int id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const float elem_error = error_per_cell[id]; if (_coarsen_by_parents) { Elem* parent = elem->parent(); if (parent) { const unsigned int parentid = parent->id(); if (error_per_parent[parentid] >= 0. && error_per_parent[parentid] <= parent_cutoff) elem->set_refinement_flag(Elem::COARSEN); } } // Flag the element for coarsening if its error // is <= coarsen_fraction*delta + error_min else if (elem_error <= coarsen_cutoff) { elem->set_refinement_flag(Elem::COARSEN); } // Flag the element for refinement if its error // is >= refinement_cutoff. if (elem_error >= refine_cutoff) if (elem->level() < _max_h_level) elem->set_refinement_flag(Elem::REFINE); } }
void MeshRefinement::flag_elements_by_elem_fraction (const ErrorVector& error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { parallel_only(); // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Check for valid fractions.. // The fraction values must be in [0,1] libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // The number of active elements in the mesh const unsigned int n_active_elem = _mesh.n_elem(); // The number of elements to flag for coarsening const unsigned int n_elem_coarsen = static_cast<unsigned int>(_coarsen_fraction * n_active_elem); // The number of elements to flag for refinement const unsigned int n_elem_refine = static_cast<unsigned int>(_refine_fraction * n_active_elem); // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // This vector stores the error and element number for all the // active elements. It will be sorted and the top & bottom // elements will then be flagged for coarsening & refinement std::vector<float> sorted_error; sorted_error.reserve (n_active_elem); // Loop over the active elements and create the entry // in the sorted_error vector MeshBase::element_iterator elem_it = _mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) sorted_error.push_back (error_per_cell[(*elem_it)->id()]); CommWorld.allgather(sorted_error); // Now sort the sorted_error vector std::sort (sorted_error.begin(), sorted_error.end()); // If we're coarsening by parents: // Create a sorted error vector with coarsenable parent elements // only, sorted by lowest errors first ErrorVector error_per_parent, sorted_parent_error; if (_coarsen_by_parents) { Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); sorted_parent_error = error_per_parent; std::sort (sorted_parent_error.begin(), sorted_parent_error.end()); // All the other error values will be 0., so get rid of them. sorted_parent_error.erase (std::remove(sorted_parent_error.begin(), sorted_parent_error.end(), 0.), sorted_parent_error.end()); } float top_error= 0., bottom_error = 0.; // Get the maximum error value corresponding to the // bottom n_elem_coarsen elements if (_coarsen_by_parents && n_elem_coarsen) { const unsigned int dim = _mesh.mesh_dimension(); unsigned int twotodim = 1; for (unsigned int i=0; i!=dim; ++i) twotodim *= 2; unsigned int n_parent_coarsen = n_elem_coarsen / (twotodim - 1); if (n_parent_coarsen) bottom_error = sorted_parent_error[n_parent_coarsen - 1]; } else if (n_elem_coarsen) { bottom_error = sorted_error[n_elem_coarsen - 1]; } if (n_elem_refine) top_error = sorted_error[sorted_error.size() - n_elem_refine]; // Finally, let's do the element flagging elem_it = _mesh.active_elements_begin(); for (; elem_it != elem_end; ++elem_it) { Elem* elem = *elem_it; Elem* parent = elem->parent(); if (_coarsen_by_parents && parent && n_elem_coarsen && error_per_parent[parent->id()] <= bottom_error) elem->set_refinement_flag(Elem::COARSEN); if (!_coarsen_by_parents && n_elem_coarsen && error_per_cell[elem->id()] <= bottom_error) elem->set_refinement_flag(Elem::COARSEN); if (n_elem_refine && elem->level() < _max_h_level && error_per_cell[elem->id()] >= top_error) elem->set_refinement_flag(Elem::REFINE); } }
void HPCoarsenTest::select_refinement (System & system) { START_LOG("select_refinement()", "HPCoarsenTest"); // The current mesh MeshBase & mesh = system.get_mesh(); // The dimensionality of the mesh const unsigned int dim = mesh.mesh_dimension(); // The number of variables in the system const unsigned int n_vars = system.n_vars(); // The DofMap for this system const DofMap & dof_map = system.get_dof_map(); // The system number (for doing bad hackery) const unsigned int sys_num = system.number(); // Check for a valid component_scale if (!component_scale.empty()) { if (component_scale.size() != n_vars) libmesh_error_msg("ERROR: component_scale is the wrong size:\n" \ << " component_scale.size()=" \ << component_scale.size() \ << "\n n_vars=" \ << n_vars); } else { // No specified scaling. Scale all variables by one. component_scale.resize (n_vars, 1.0); } // Resize the error_per_cell vectors to handle // the number of elements, initialize them to 0. std::vector<ErrorVectorReal> h_error_per_cell(mesh.max_elem_id(), 0.); std::vector<ErrorVectorReal> p_error_per_cell(mesh.max_elem_id(), 0.); // Loop over all the variables in the system for (unsigned int var=0; var<n_vars; var++) { // Possibly skip this variable if (!component_scale.empty()) if (component_scale[var] == 0.0) continue; // The type of finite element to use for this variable const FEType & fe_type = dof_map.variable_type (var); // Finite element objects for a fine (and probably a coarse) // element will be needed fe = FEBase::build (dim, fe_type); fe_coarse = FEBase::build (dim, fe_type); // Any cached coarse element results have expired coarse = libmesh_nullptr; unsigned int cached_coarse_p_level = 0; const FEContinuity cont = fe->get_continuity(); libmesh_assert (cont == DISCONTINUOUS || cont == C_ZERO || cont == C_ONE); // Build an appropriate quadrature rule qrule = fe_type.default_quadrature_rule(dim); // Tell the refined finite element about the quadrature // rule. The coarse finite element need not know about it fe->attach_quadrature_rule (qrule.get()); // We will always do the integration // on the fine elements. Get their Jacobian values, etc.. JxW = &(fe->get_JxW()); xyz_values = &(fe->get_xyz()); // The shape functions phi = &(fe->get_phi()); phi_coarse = &(fe_coarse->get_phi()); // The shape function derivatives if (cont == C_ZERO || cont == C_ONE) { dphi = &(fe->get_dphi()); dphi_coarse = &(fe_coarse->get_dphi()); } #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES // The shape function second derivatives if (cont == C_ONE) { d2phi = &(fe->get_d2phi()); d2phi_coarse = &(fe_coarse->get_d2phi()); } #endif // defined (LIBMESH_ENABLE_SECOND_DERIVATIVES) // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; // We're only checking elements that are already flagged for h // refinement if (elem->refinement_flag() != Elem::REFINE) continue; const dof_id_type e_id = elem->id(); // Find the projection onto the parent element, // if necessary if (elem->parent() && (coarse != elem->parent() || cached_coarse_p_level != elem->p_level())) { Uc.resize(0); coarse = elem->parent(); cached_coarse_p_level = elem->p_level(); unsigned int old_parent_level = coarse->p_level(); (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); this->add_projection(system, coarse, var); (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); // Solve the h-coarsening projection problem Ke.cholesky_solve(Fe, Uc); } fe->reinit(elem); // Get the DOF indices for the fine element dof_map.dof_indices (elem, dof_indices, var); // The number of quadrature points const unsigned int n_qp = qrule->n_points(); // The number of DOFS on the fine element const unsigned int n_dofs = cast_int<unsigned int>(dof_indices.size()); // The number of nodes on the fine element const unsigned int n_nodes = elem->n_nodes(); // The average element value (used as an ugly hack // when we have nothing p-coarsened to compare to) // Real average_val = 0.; Number average_val = 0.; // Calculate this variable's contribution to the p // refinement error if (elem->p_level() == 0) { unsigned int n_vertices = 0; for (unsigned int n = 0; n != n_nodes; ++n) if (elem->is_vertex(n)) { n_vertices++; const Node * const node = elem->get_node(n); average_val += system.current_solution (node->dof_number(sys_num,var,0)); } average_val /= n_vertices; } else { unsigned int old_elem_level = elem->p_level(); (const_cast<Elem *>(elem))->hack_p_level(old_elem_level - 1); fe_coarse->reinit(elem, &(qrule->get_points())); const unsigned int n_coarse_dofs = cast_int<unsigned int>(phi_coarse->size()); (const_cast<Elem *>(elem))->hack_p_level(old_elem_level); Ke.resize(n_coarse_dofs, n_coarse_dofs); Ke.zero(); Fe.resize(n_coarse_dofs); Fe.zero(); // Loop over the quadrature points for (unsigned int qp=0; qp<qrule->n_points(); qp++) { // The solution value at the quadrature point Number val = libMesh::zero; Gradient grad; Tensor hess; for (unsigned int i=0; i != n_dofs; i++) { dof_id_type dof_num = dof_indices[i]; val += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hess += (*d2phi)[i][qp] * // system.current_solution(dof_num); } // The projection matrix and vector for (unsigned int i=0; i != Fe.size(); ++i) { Fe(i) += (*JxW)[qp] * (*phi_coarse)[i][qp]*val; if (cont == C_ZERO || cont == C_ONE) Fe(i) += (*JxW)[qp] * grad * (*dphi_coarse)[i][qp]; if (cont == C_ONE) Fe(i) += (*JxW)[qp] * hess.contract((*d2phi_coarse)[i][qp]); for (unsigned int j=0; j != Fe.size(); ++j) { Ke(i,j) += (*JxW)[qp] * (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp]; if (cont == C_ZERO || cont == C_ONE) Ke(i,j) += (*JxW)[qp] * (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp]; if (cont == C_ONE) Ke(i,j) += (*JxW)[qp] * ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp])); } } } // Solve the p-coarsening projection problem Ke.cholesky_solve(Fe, Up); } // loop over the integration points on the fine element for (unsigned int qp=0; qp<n_qp; qp++) { Number value_error = 0.; Gradient grad_error; Tensor hessian_error; for (unsigned int i=0; i<n_dofs; i++) { const dof_id_type dof_num = dof_indices[i]; value_error += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad_error += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hessian_error += (*d2phi)[i][qp] * // system.current_solution(dof_num); } if (elem->p_level() == 0) { value_error -= average_val; } else { for (unsigned int i=0; i<Up.size(); i++) { value_error -= (*phi_coarse)[i][qp] * Up(i); if (cont == C_ZERO || cont == C_ONE) grad_error.subtract_scaled((*dphi_coarse)[i][qp], Up(i)); // grad_error -= (*dphi_coarse)[i][qp] * Up(i); if (cont == C_ONE) hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Up(i)); // hessian_error -= (*d2phi_coarse)[i][qp] * Up(i); } } p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * TensorTools::norm_sq(value_error)); if (cont == C_ZERO || cont == C_ONE) p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * grad_error.norm_sq()); if (cont == C_ONE) p_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * hessian_error.norm_sq()); } // Calculate this variable's contribution to the h // refinement error if (!elem->parent()) { // For now, we'll always start with an h refinement h_error_per_cell[e_id] = std::numeric_limits<ErrorVectorReal>::max() / 2; } else { FEInterface::inverse_map (dim, fe_type, coarse, *xyz_values, coarse_qpoints); unsigned int old_parent_level = coarse->p_level(); (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level()); fe_coarse->reinit(coarse, &coarse_qpoints); (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level); // The number of DOFS on the coarse element unsigned int n_coarse_dofs = cast_int<unsigned int>(phi_coarse->size()); // Loop over the quadrature points for (unsigned int qp=0; qp<n_qp; qp++) { // The solution difference at the quadrature point Number value_error = libMesh::zero; Gradient grad_error; Tensor hessian_error; for (unsigned int i=0; i != n_dofs; ++i) { const dof_id_type dof_num = dof_indices[i]; value_error += (*phi)[i][qp] * system.current_solution(dof_num); if (cont == C_ZERO || cont == C_ONE) grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num)); // grad_error += (*dphi)[i][qp] * // system.current_solution(dof_num); if (cont == C_ONE) hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num)); // hessian_error += (*d2phi)[i][qp] * // system.current_solution(dof_num); } for (unsigned int i=0; i != n_coarse_dofs; ++i) { value_error -= (*phi_coarse)[i][qp] * Uc(i); if (cont == C_ZERO || cont == C_ONE) // grad_error -= (*dphi_coarse)[i][qp] * Uc(i); grad_error.subtract_scaled((*dphi_coarse)[i][qp], Uc(i)); if (cont == C_ONE) hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Uc(i)); // hessian_error -= (*d2phi_coarse)[i][qp] * Uc(i); } h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * TensorTools::norm_sq(value_error)); if (cont == C_ZERO || cont == C_ONE) h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * grad_error.norm_sq()); if (cont == C_ONE) h_error_per_cell[e_id] += static_cast<ErrorVectorReal> (component_scale[var] * (*JxW)[qp] * hessian_error.norm_sq()); } } } } // Now that we've got our approximations for p_error and h_error, let's see // if we want to switch any h refinement flags to p refinement // Iterate over all the active elements in the mesh // that live on this processor. MeshBase::element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; // We're only checking elements that are already flagged for h // refinement if (elem->refinement_flag() != Elem::REFINE) continue; const dof_id_type e_id = elem->id(); unsigned int dofs_per_elem = 0, dofs_per_p_elem = 0; // Loop over all the variables in the system for (unsigned int var=0; var<n_vars; var++) { // The type of finite element to use for this variable const FEType & fe_type = dof_map.variable_type (var); // FIXME: we're overestimating the number of DOFs added by h // refinement FEType elem_fe_type = fe_type; elem_fe_type.order = static_cast<Order>(fe_type.order + elem->p_level()); dofs_per_elem += FEInterface::n_dofs(dim, elem_fe_type, elem->type()); elem_fe_type.order = static_cast<Order>(fe_type.order + elem->p_level() + 1); dofs_per_p_elem += FEInterface::n_dofs(dim, elem_fe_type, elem->type()); } const unsigned int new_h_dofs = dofs_per_elem * (elem->n_children() - 1); const unsigned int new_p_dofs = dofs_per_p_elem - dofs_per_elem; /* libMesh::err << "Cell " << e_id << ": h = " << elem->hmax() << ", p = " << elem->p_level() + 1 << "," << std::endl << " h_error = " << h_error_per_cell[e_id] << ", p_error = " << p_error_per_cell[e_id] << std::endl << " new_h_dofs = " << new_h_dofs << ", new_p_dofs = " << new_p_dofs << std::endl; */ const Real p_value = std::sqrt(p_error_per_cell[e_id]) * p_weight / new_p_dofs; const Real h_value = std::sqrt(h_error_per_cell[e_id]) / static_cast<Real>(new_h_dofs); if (p_value > h_value) { elem->set_p_refinement_flag(Elem::REFINE); elem->set_refinement_flag(Elem::DO_NOTHING); } } STOP_LOG("select_refinement()", "HPCoarsenTest"); }
std::unique_ptr<MeshBase> SpiralAnnularMeshGenerator::generate() { std::unique_ptr<ReplicatedMesh> mesh = libmesh_make_unique<ReplicatedMesh>(comm(), 2); { // Compute the radial bias given: // .) the inner radius // .) the outer radius // .) the initial_delta_r // .) the desired number of intervals // Note: the exponent n used in the formula is one less than the // number of rings the user requests. Real alpha = 1.1; int n = _num_rings - 1; // lambda used to compute the residual and Jacobian for the Newton iterations. // We capture parameters which don't need to change from the current scope at // the time this lambda is declared. The values are not updated later, so we // can't use this for e.g. f, df, and alpha. auto newton = [this, n](Real & f, Real & df, const Real & alpha) { f = (1. - std::pow(alpha, n + 1)) / (1. - alpha) - (_outer_radius - _inner_radius) / _initial_delta_r; df = (-(n + 1) * (1 - alpha) * std::pow(alpha, n) + (1. - std::pow(alpha, n + 1))) / (1. - alpha) / (1. - alpha); }; Real f, df; int num_iter = 1; newton(f, df, alpha); while (std::abs(f) > 1.e-9 && num_iter <= 25) { // Compute and apply update. Real dx = -f / df; alpha += dx; newton(f, df, alpha); num_iter++; } // In case the Newton iteration fails to converge. if (num_iter > 25) mooseError("Newton iteration failed to converge (more than 25 iterations)."); // Set radial basis to the value of alpha that we computed with Newton. _radial_bias = alpha; } // The number of rings specified by the user does not include the ring at // the surface of the cylinder itself, so we increment it by one now. _num_rings += 1; // Data structure that holds pointers to the Nodes of each ring. std::vector<std::vector<Node *>> ring_nodes(_num_rings); // Initialize radius and delta_r variables. Real radius = _inner_radius; Real delta_r = _initial_delta_r; // Node id counter. unsigned int current_node_id = 0; for (std::size_t r = 0; r < _num_rings; ++r) { ring_nodes[r].resize(_nodes_per_ring); // Add nodes starting from either theta=0 or theta=pi/nodes_per_ring Real theta = r % 2 == 0 ? 0 : (libMesh::pi / _nodes_per_ring); for (std::size_t n = 0; n < _nodes_per_ring; ++n) { ring_nodes[r][n] = mesh->add_point(Point(radius * std::cos(theta), radius * std::sin(theta)), current_node_id++); // Update angle theta += 2 * libMesh::pi / _nodes_per_ring; } // Go to next ring radius += delta_r; delta_r *= _radial_bias; } // Add elements for (std::size_t r = 0; r < _num_rings - 1; ++r) { // even -> odd ring if (r % 2 == 0) { // Inner ring (n, n*, n+1) // Starred indices refer to nodes on the "outer" ring of this pair. for (std::size_t n = 0; n < _nodes_per_ring; ++n) { // Wrap around unsigned int np1 = (n == _nodes_per_ring - 1) ? 0 : n + 1; Elem * elem = mesh->add_elem(new Tri3); elem->set_node(0) = ring_nodes[r][n]; elem->set_node(1) = ring_nodes[r + 1][n]; elem->set_node(2) = ring_nodes[r][np1]; // Add interior faces to 'cylinder' sideset if we are on ring 0. if (r == 0) mesh->boundary_info->add_side(elem->id(), /*side=*/2, _cylinder_bid); } // Outer ring (n*, n+1*, n+1) for (std::size_t n = 0; n < _nodes_per_ring; ++n) { // Wrap around unsigned int np1 = (n == _nodes_per_ring - 1) ? 0 : n + 1; Elem * elem = mesh->add_elem(new Tri3); elem->set_node(0) = ring_nodes[r + 1][n]; elem->set_node(1) = ring_nodes[r + 1][np1]; elem->set_node(2) = ring_nodes[r][np1]; // Add exterior faces to 'exterior' sideset if we're on the last ring. // Note: this code appears in two places since we could end on either an even or odd ring. if (r == _num_rings - 2) mesh->boundary_info->add_side(elem->id(), /*side=*/0, _exterior_bid); } } else { // odd -> even ring // Inner ring (n, n+1*, n+1) for (std::size_t n = 0; n < _nodes_per_ring; ++n) { // Wrap around unsigned int np1 = (n == _nodes_per_ring - 1) ? 0 : n + 1; Elem * elem = mesh->add_elem(new Tri3); elem->set_node(0) = ring_nodes[r][n]; elem->set_node(1) = ring_nodes[r + 1][np1]; elem->set_node(2) = ring_nodes[r][np1]; } // Outer ring (n*, n+1*, n) for (std::size_t n = 0; n < _nodes_per_ring; ++n) { // Wrap around unsigned int np1 = (n == _nodes_per_ring - 1) ? 0 : n + 1; Elem * elem = mesh->add_elem(new Tri3); elem->set_node(0) = ring_nodes[r + 1][n]; elem->set_node(1) = ring_nodes[r + 1][np1]; elem->set_node(2) = ring_nodes[r][n]; // Add exterior faces to 'exterior' sideset if we're on the last ring. if (r == _num_rings - 2) mesh->boundary_info->add_side(elem->id(), /*side=*/0, _exterior_bid); } } } // Sanity check: make sure all elements have positive area. Note: we // can't use elem->volume() for this, as that always returns a // positive area regardless of the node ordering. // We compute (p1-p0) \cross (p2-p0) and check that the z-component is positive. for (const auto & elem : mesh->element_ptr_range()) { Point cp = (elem->point(1) - elem->point(0)).cross(elem->point(2) - elem->point(0)); if (cp(2) < 0.) mooseError("Invalid elem found with negative area"); } // Create sideset names. mesh->boundary_info->sideset_name(_cylinder_bid) = "cylinder"; mesh->boundary_info->sideset_name(_exterior_bid) = "exterior"; // Find neighbors, etc. mesh->prepare_for_use(); if (_use_tri6) { mesh->all_second_order(/*full_ordered=*/true); std::vector<unsigned int> nos; // Loop over the elements, moving mid-edge nodes onto the // nearest radius as applicable. For each element, exactly one // edge should lie on the same radius, so we move only that // mid-edge node. for (const auto & elem : mesh->element_ptr_range()) { // Make sure we are dealing only with triangles libmesh_assert(elem->n_vertices() == 3); // Compute vertex radii Real radii[3] = {elem->point(0).norm(), elem->point(1).norm(), elem->point(2).norm()}; // Compute absolute differences between radii so we can determine which two are on the same // circular arc. Real dr[3] = {std::abs(radii[0] - radii[1]), std::abs(radii[1] - radii[2]), std::abs(radii[2] - radii[0])}; // Compute index of minimum dr. auto index = std::distance(std::begin(dr), std::min_element(std::begin(dr), std::end(dr))); // Make sure that the minimum found is also (almost) zero. if (dr[index] > TOLERANCE) mooseError("Error: element had no sides with nodes on same radius."); // Get list of all local node ids on this side. The first // two entries in nos correspond to the vertices, the last // entry corresponds to the mid-edge node. nos = elem->nodes_on_side(index); // Compute the angles associated with nodes nos[0] and nos[1]. Real theta0 = std::atan2(elem->point(nos[0])(1), elem->point(nos[0])(0)), theta1 = std::atan2(elem->point(nos[1])(1), elem->point(nos[1])(0)); // atan2 returns values in the range (-pi, pi). If theta0 // and theta1 have the same sign, we can simply average them // to get half of the acute angle between them. On the other // hand, if theta0 and theta1 are of opposite sign _and_ both // are larger than pi/2, we need to add 2*pi when averaging, // otherwise we will get half of the _obtuse_ angle between // them, and the point will flip to the other side of the // circle (see below). Real new_theta = 0.5 * (theta0 + theta1); // It should not be possible for both: // 1.) |theta0| > pi/2, and // 2.) |theta1| < pi/2 // as this would not be a well-formed element. if ((theta0 * theta1 < 0) && (std::abs(theta0) > 0.5 * libMesh::pi) && (std::abs(theta1) > 0.5 * libMesh::pi)) new_theta = 0.5 * (theta0 + theta1 + 2 * libMesh::pi); // The new radius will be the radius of point nos[0] or nos[1] (they are the same!). Real new_r = elem->point(nos[0]).norm(); // Finally, move the point to its new location. elem->point(nos[2]) = Point(new_r * std::cos(new_theta), new_r * std::sin(new_theta), 0.); } } return dynamic_pointer_cast<MeshBase>(mesh); }
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 }
// StoreMaterialSystem/StressSystem/ bool CMaterialInfo::StoreMaterialInfo() { cout<<STRING_WRITE_BEGIN << "store material info" << endl; MeshBase& mesh = d_es->get_mesh(); Mesh::element_iterator it_el = mesh.active_local_elements_begin();//mesh.elements_begin(); const Mesh::element_iterator it_last_el = mesh.active_local_elements_end();//mesh.elements_end(); // part 1: we store the Material Info ExplicitSystem& material_system = d_es->get_system<ExplicitSystem>("MaterialSystem"); const DofMap& material_dof_map = material_system.get_dof_map(); // need to put values from the file vector<double> mat_values; mat_values.resize(d_mat_paras_num); //std::vector< std::vector<unsigned int> > dof_indices_var(system.n_vars()); std::vector<unsigned int> mat_dof_indices_var; string var_pre = "Mat"; for ( ; it_el != it_last_el ; ++it_el) { Elem* elem = *it_el; int domain_id= elem->subdomain_id(); const vector<double> & mat_values = d_material_info[domain_id].mat_paras; for (int it_para = 0; it_para < d_mat_paras_num; it_para ++) { stringstream ss; ss << it_para; string Name_para = var_pre + ss.str();//to_string(it_para); unsigned int mat_vars = material_system.variable_number (Name_para); material_dof_map.dof_indices (elem, mat_dof_indices_var, mat_vars); unsigned int dof_index = mat_dof_indices_var[0]; if( (material_system.solution->first_local_index() <= dof_index) && (dof_index < material_system.solution->last_local_index()) ) { material_system.solution->set(dof_index, mat_values[it_para]); } } } material_system.solution->close(); material_system.update(); Xdr my_mat_io("material.xdr",libMeshEnums::WRITE); material_system.write_serialized_data(my_mat_io,false); // part 2: we store the Fiber info if (d_have_fibers) { if (d_have_fiber_file) { DenseMatrix<Number> Fiber_data; // part 1) have fiber file for store info cout << STRING_CHECK_IMPORTANT << "fiber info is from file: " << endl; if (!ReadFile2Matrix(Fiber_data,d_fiber_file) || Fiber_data.m() < d_Elem_num) { cout << STRING_ERROR << "check fiber file: element num < rows" << d_fiber_file << endl; return false; } else if (Fiber_data.n() < d_fiber_para_num * d_fiber_types) { cout << STRING_ERROR << "check fiber file: fiber total paras < cols" << d_fiber_file << endl; return false; } ExplicitSystem& Fiber_system = d_es->get_system<ExplicitSystem>("FiberSystem"); const DofMap& Fiber_dof_map = Fiber_system.get_dof_map(); it_el = mesh.active_local_elements_begin(); var_pre = "Fiber"; string var_middle = "Para"; vector<string> fiber_vars; fiber_vars.resize(d_fiber_para_num * d_fiber_types); int it_id = -1; for (int it_fiber =0 ; it_fiber < d_fiber_types; it_fiber ++) { for (int it_para = 0; it_para < d_fiber_para_num; it_para ++ ) { // each fiber: a0, a1, a2, C, alpha it_id ++; stringstream ss; ss << it_para; stringstream ss1; ss1 << it_fiber; fiber_vars[ it_id]= var_pre + ss1.str() + var_middle + ss.str(); } } //std::vector< std::vector<unsigned int> > dof_indices_var(system.n_vars()); std::vector<unsigned int> fiber_dof_indices_var; for ( ; it_el != it_last_el ; ++it_el) { Elem* elem = *it_el; int domain_id= elem->subdomain_id(); // mat_values = int global_id =elem->id(); for (int it_para = 0; it_para < d_fiber_para_num * d_fiber_types; it_para ++) { unsigned int vars = Fiber_system.variable_number (fiber_vars[it_para]); Fiber_dof_map.dof_indices (elem, fiber_dof_indices_var, vars); unsigned int dof_index = fiber_dof_indices_var[0]; if( (Fiber_system.solution->first_local_index() <= dof_index) && (dof_index < Fiber_system.solution->last_local_index()) ) { Fiber_system.solution->set(dof_index, Fiber_data(global_id,it_para)); } } } Fiber_system.solution->close(); Fiber_system.update(); } else // part 2) we use parameters: currently, we use tube geometry { cout << STRING_CHECK_IMPORTANT <<"use parameters based on tube geometry only" << "; orientation based on the element center" << endl; d_fiber_types = d_fiberPara_info[0].num_fiber_family; d_fiber_para_num = d_fiberPara_info[0].num_para_per_fiber; ExplicitSystem& Fiber_system = d_es->get_system<ExplicitSystem>("FiberSystem"); const DofMap& Fiber_dof_map = Fiber_system.get_dof_map(); it_el = mesh.active_local_elements_begin(); var_pre = "Fiber"; string var_middle = "Para"; vector<string> fiber_vars; fiber_vars.resize(d_fiber_para_num * d_fiber_types); int it_id = -1; for (int it_fiber =0 ; it_fiber < d_fiber_types; it_fiber ++) { for (int it_para = 0; it_para < d_fiber_para_num; it_para ++ ) { stringstream ss; ss << it_fiber; stringstream ss1; ss1 << it_para; // each fiber: a0, a1, a2, C, alpha it_id ++; fiber_vars[ it_id]= var_pre + ss.str() + var_middle + ss1.str();//::to_string(it_para); } } //std::vector< std::vector<unsigned int> > dof_indices_var(system.n_vars()); std::vector<unsigned int> fiber_dof_indices_var; for ( ; it_el != it_last_el ; ++it_el) { Elem* elem = *it_el; int domain_id= elem->subdomain_id(); Fiber_info a_fiber_info = d_fiberPara_info[domain_id]; FiberPara2Data(a_fiber_info, elem->centroid()); // mat_values = //int global_id =elem->id(); for (int it_para = 0; it_para < d_fiber_para_num * d_fiber_types; it_para ++) { unsigned int vars = Fiber_system.variable_number (fiber_vars[it_para]); Fiber_dof_map.dof_indices (elem, fiber_dof_indices_var, vars); unsigned int dof_index = fiber_dof_indices_var[0]; if( (Fiber_system.solution->first_local_index() <= dof_index) && (dof_index < Fiber_system.solution->last_local_index()) ) { Fiber_system.solution-> set(dof_index,a_fiber_info.fiber_paras[it_para] ); //Fiber_data(global_id)(it_para)); } } } Fiber_system.solution->close(); Fiber_system.update(); Xdr my_io("fiber.xdr",libMeshEnums::WRITE); Fiber_system.write_serialized_data(my_io,false); } } // part 3: we store auxiliary info if (d_have_other) { DenseMatrix<Number> other_data; if (!ReadFile2Matrix(other_data,d_other_file) || other_data.m() < d_Elem_num); { cout << STRING_ERROR << "check other file:" << d_other_file << endl; return false; } d_other_para_num = other_data.n(); ExplicitSystem& other_system = d_es->get_system<ExplicitSystem>("OtherSystem"); const DofMap& other_dof_map = other_system.get_dof_map(); it_el = mesh.active_local_elements_begin(); std::vector<unsigned int> other_dof_indices_var; var_pre = "Other"; for ( ; it_el != it_last_el ; ++it_el) { Elem* elem = *it_el; int domain_id= elem->subdomain_id(); // mat_values = for (int it_para = 0; it_para < d_other_para_num; it_para ++) { stringstream ss; ss << it_para; string Name_para = var_pre + ss.str();//to_string(it_para); unsigned int other_vars = other_system.variable_number (Name_para); other_dof_map.dof_indices (elem, other_dof_indices_var, other_vars); unsigned int dof_index = other_dof_indices_var[0]; if( (other_system.solution->first_local_index() <= dof_index) && (dof_index < other_system.solution->last_local_index()) ) { other_system.solution->set(dof_index, other_data(elem->id(),it_para)); } } } other_system.solution->close(); other_system.update(); } cout<<STRING_WRITE_END << "store material info" << endl; return true; } // StoreMaterialInfo
Elem * Packing<Elem *>::unpack (std::vector<largest_id_type>::const_iterator in, MeshBase * mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = cast_int<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = cast_int<unsigned int>(*in++); // int 2: refinement flag and encoded has_children const int rflag = cast_int<int>(*in++); const int invalid_rflag = cast_int<int>(Elem::INVALID_REFINEMENTSTATE); libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, invalid_rflag*2+1); const bool has_children = (rflag > invalid_rflag); const Elem::RefinementState refinement_flag = has_children ? cast_int<Elem::RefinementState>(rflag - invalid_rflag - 1) : cast_int<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = cast_int<int>(*in++); libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = cast_int<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = cast_int<int>(*in++); libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = cast_int<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = cast_int<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = cast_int<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = cast_int<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = cast_int<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id. // Note: If level==0, then (*in) == invalid_id. In // this case, the equality check in cast_int<unsigned>(*in) will // never succeed. Therefore, we should only attempt the more // rigorous cast verification in cases where level != 0. const dof_id_type parent_id = (level == 0) ? static_cast<dof_id_type>(*in++) : cast_int<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id // Note: If level==0, then which_child_am_i is not valid, so don't // do the more rigorous cast verification. const unsigned int which_child_am_i = (level == 0) ? static_cast<unsigned int>(*in++) : cast_int<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR const dof_id_type interior_parent_id = static_cast<dof_id_type>(*in++); // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem * elem = mesh->query_elem_ptr(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unique id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node_id(i) == cast_int<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->has_children(), has_children); #ifdef DEBUG if (elem->active()) { libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); } #endif libmesh_assert (!level || elem->parent() != libmesh_nullptr); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child_ptr(which_child_am_i) == elem); #endif // Our interior_parent link should be "close to" correct - we // may have to update it, but we can check for some // inconsistencies. { // If the sending processor sees no interior_parent here, we'd // better agree. if (interior_parent_id == DofObject::invalid_id) { if (elem->dim() < LIBMESH_DIM) libmesh_assert (!(elem->interior_parent())); } // If the sending processor has a remote_elem interior_parent, // then all we know is that we'd better have *some* // interior_parent else if (interior_parent_id == remote_elem->id()) { libmesh_assert(elem->interior_parent()); } else { Elem * ip = mesh->query_elem_ptr(interior_parent_id); // The sending processor sees an interior parent here, so // if we don't have that interior element, then we'd // better have a remote_elem signifying that fact. if (!ip) libmesh_assert_equal_to (elem->interior_parent(), remote_elem); else { // The sending processor has an interior_parent here, // and we have that element, but that does *NOT* mean // we're already linking to it. Perhaps we initially // received elem from a processor on which the // interior_parent link was remote? libmesh_assert(elem->interior_parent() == ip || elem->interior_parent() == remote_elem); // If the link was originally remote, update it if (elem->interior_parent() == remote_elem) { elem->set_interior_parent(ip); } } } } // Our neighbor links should be "close to" correct - we may have // to update a remote_elem link, and we can check for possible // inconsistencies along the way. // // For subactive elements, we don't bother keeping neighbor // links in good shape, so there's nothing we need to set or can // safely assert here. if (!elem->subactive()) for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor_ptr(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor_ptr(n)); continue; } Elem * neigh = mesh->query_elem_ptr(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor_ptr(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor_ptr(n) == neigh || elem->neighbor_ptr(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor_ptr(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // Our p level and refinement flags should be "close to" correct // if we're not an active element - we might have a p level // increased or decreased by changes in remote_elem children. // // But if we have remote_elem children, then we shouldn't be // doing a projection on this inactive element on this // processor, so we won't need correct p settings. Couldn't // hurt to update, though. #ifdef LIBMESH_ENABLE_AMR if (elem->processor_id() != mesh->processor_id()) { elem->hack_p_level(p_level); elem->set_p_refinement_flag(p_refinement_flag); } #endif // LIBMESH_ENABLE_AMR // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem * parent = libmesh_nullptr; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem_ptr(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, DofObject::invalid_id); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child_ptr(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element should have children, assign remote_elem to // all of them for now, for consistency. Later unpacked // elements may overwrite that. if (has_children) { const unsigned int nc = elem->n_children(); for (unsigned int c=0; c != nc; ++c) elem->add_child(const_cast<RemoteElem *>(remote_elem), c); } #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (cast_int<dof_id_type>(*in++)); // Set interior_parent if found { // We may be unpacking an element that was a ghost element on the // sender, in which case the element's interior_parent may not be // known by the packed element. We'll have to set such // interior_parents to remote_elem ourselves and wait for a // later packed element to give us better information. if (interior_parent_id == remote_elem->id()) { elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); } else if (interior_parent_id != DofObject::invalid_id) { // If we don't have the interior parent element, then it's // a remote_elem until we get it. Elem * ip = mesh->query_elem_ptr(interior_parent_id); if (!ip ) elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); else elem->set_interior_parent(ip); } } for (auto n : elem->side_index_range()) { const dof_id_type neighbor_id = cast_int<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem * neigh = mesh->query_elem_ptr(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem *>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side or edge boundary condition ids if (level == 0) { for (auto s : elem->side_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_side (elem, s, cast_int<boundary_id_type>(*in++)); } for (auto e : elem->edge_index_range()) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_edge (elem, e, cast_int<boundary_id_type>(*in++)); } for (unsigned short sf=0; sf != 2; ++sf) { const boundary_id_type num_bcs = cast_int<boundary_id_type>(*in++); for (boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++) mesh->get_boundary_info().add_shellface (elem, sf, cast_int<boundary_id_type>(*in++)); } } // Return the new element return elem; }
void ExodusII_IO::read (const std::string& fname) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later // libmesh_assert_equal_to (libMesh::processor_id(), 0); #ifndef LIBMESH_HAVE_EXODUS_API libMesh::err << "ERROR, ExodusII API is not defined.\n" << "Input file " << fname << " cannot be read" << std::endl; libmesh_error(); #else // Get a reference to the mesh we are reading MeshBase& mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data mesh.clear(); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifdef DEBUG this->verbose(true); #endif ExodusII_IO_Helper::ElementMaps em; // Instantiate the ElementMaps interface exio_helper->open(fname.c_str()); // Open the exodus file, if possible exio_helper->read_header(); // Get header information from exodus file exio_helper->print_header(); // Print header information //assertion fails due to inconsistent mesh dimension // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->get_num_dim()), mesh.mesh_dimension()); // Be sure number of dimensions // is equal to the number of // dimensions in the mesh supplied. exio_helper->read_nodes(); // Read nodes from the exodus file mesh.reserve_nodes(exio_helper->get_num_nodes()); // Reserve space for the nodes. // Loop over the nodes, create Nodes with local processor_id 0. for (int i=0; i<exio_helper->get_num_nodes(); i++) mesh.add_point (Point(exio_helper->get_x(i), exio_helper->get_y(i), exio_helper->get_z(i)), i); libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->get_num_nodes()), mesh.n_nodes()); exio_helper->read_block_info(); // Get information about all the blocks mesh.reserve_elem(exio_helper->get_num_elem()); // Reserve space for the elements // Read in the element connectivity for each block. int nelem_last_block = 0; std::map<int, unsigned int> exodus_id_to_mesh_id; // Loop over all the blocks for (int i=0; i<exio_helper->get_num_elem_blk(); i++) { // Read the information for block i exio_helper->read_elem_in_block (i); int subdomain_id = exio_helper->get_block_id(i); // populate the map of names mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = exio_helper->get_block_name(i); // Set any relevant node/edge maps for this element const std::string type_str (exio_helper->get_elem_type()); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); //if (_verbose) //libMesh::out << "Reading a block of " << type_str << " elements." << std::endl; // Loop over all the faces in this block int jmax = nelem_last_block+exio_helper->get_num_elem_this_blk(); for (int j=nelem_last_block; j<jmax; j++) { Elem* elem = Elem::build (conv.get_canonical_type()).release(); libmesh_assert (elem); elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; //elem->set_id(j);// Don't try to second guess the Element ID setting scheme! elems_of_dimension[elem->dim()] = true; elem = mesh.add_elem (elem); // Catch the Elem pointer that the Mesh throws back exodus_id_to_mesh_id[j+1] = elem->id(); // Set all the nodes for this element for (int k=0; k<exio_helper->get_num_nodes_per_elem(); k++) { int gi = (j-nelem_last_block)*exio_helper->get_num_nodes_per_elem() + conv.get_node_map(k); // global index int node_number = exio_helper->get_connect(gi); // Global node number (1-based) elem->set_node(k) = mesh.node_ptr((node_number-1)); // Set node number // Subtract 1 since // exodus is internally 1-based } } // running sum of # of elements per block, // (should equal total number of elements in the end) nelem_last_block += exio_helper->get_num_elem_this_blk(); } libmesh_assert_equal_to (static_cast<unsigned int>(nelem_last_block), mesh.n_elem()); // Set the mesh dimension to the largest encountered for an element for (unsigned int i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); // Read in sideset information -- this is useful for applying boundary conditions { exio_helper->read_sideset_info(); // Get basic information about ALL sidesets int offset=0; for (int i=0; i<exio_helper->get_num_side_sets(); i++) { offset += (i > 0 ? exio_helper->get_num_sides_per_set(i-1) : 0); // Compute new offset exio_helper->read_sideset (i, offset); mesh.boundary_info->sideset_name(exio_helper->get_side_set_id(i)) = exio_helper->get_side_set_name(i); } const std::vector<int>& elem_list = exio_helper->get_elem_list(); const std::vector<int>& side_list = exio_helper->get_side_list(); const std::vector<int>& id_list = exio_helper->get_id_list(); for (unsigned int e=0; e<elem_list.size(); e++) { // Set any relevant node/edge maps for this element Elem * elem = mesh.elem(exodus_id_to_mesh_id[elem_list[e]]); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(elem->type()); mesh.boundary_info->add_side (exodus_id_to_mesh_id[elem_list[e]], conv.get_side_map(side_list[e]-1), id_list[e]); } } // Read nodeset info { exio_helper->read_nodeset_info(); for (int nodeset=0; nodeset<exio_helper->get_num_node_sets(); nodeset++) { int nodeset_id = exio_helper->get_nodeset_id(nodeset); mesh.boundary_info->nodeset_name(nodeset_id) = exio_helper->get_node_set_name(nodeset); exio_helper->read_nodeset(nodeset); const std::vector<int>& node_list = exio_helper->get_node_list(); for(unsigned int node=0; node<node_list.size(); node++) mesh.boundary_info->add_node(node_list[node]-1, nodeset_id); } } #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) { libMesh::err << "Cannot open dimension " << mesh.mesh_dimension() << " mesh file when configured without " << mesh.mesh_dimension() << "D support." << std::endl; libmesh_error(); } #endif #endif }
// The actual implementation of building elements. void InfElemBuilder::build_inf_elem(const Point& origin, const bool x_sym, const bool y_sym, const bool z_sym, const bool be_verbose, std::set< std::pair<dof_id_type, unsigned int> >* inner_faces) { if (be_verbose) { #ifdef DEBUG libMesh::out << " Building Infinite Elements:" << std::endl; libMesh::out << " updating element neighbor tables..." << std::endl; #else libMesh::out << " Verbose mode disabled in non-debug mode." << std::endl; #endif } // update element neighbors this->_mesh.find_neighbors(); START_LOG("build_inf_elem()", "InfElemBuilder"); // A set for storing element number, side number pairs. // pair.first == element number, pair.second == side number std::set< std::pair<dof_id_type,unsigned int> > faces; std::set< std::pair<dof_id_type,unsigned int> > ofaces; // A set for storing node numbers on the outer faces. std::set<dof_id_type> onodes; // The distance to the farthest point in the mesh from the origin Real max_r=0.; // The index of the farthest point in the mesh from the origin int max_r_node = -1; #ifdef DEBUG if (be_verbose) { libMesh::out << " collecting boundary sides"; if (x_sym || y_sym || z_sym) libMesh::out << ", skipping sides in symmetry planes..." << std::endl; else libMesh::out << "..." << std::endl; } #endif // Iterate through all elements and sides, collect indices of all active // boundary sides in the faces set. Skip sides which lie in symmetry planes. // Later, sides of the inner boundary will be sorted out. { MeshBase::element_iterator it = this->_mesh.active_elements_begin(); const MeshBase::element_iterator end = this->_mesh.active_elements_end(); for(; it != end; ++it) { Elem* elem = *it; for (unsigned int s=0; s<elem->n_neighbors(); s++) { // check if elem(e) is on the boundary if (elem->neighbor(s) == NULL) { // note that it is safe to use the Elem::side() method, // which gives a non-full-ordered element AutoPtr<Elem> side(elem->build_side(s)); // bool flags for symmetry detection bool sym_side=false; bool on_x_sym=true; bool on_y_sym=true; bool on_z_sym=true; // Loop over the nodes to check whether they are on the symmetry planes, // and therefore sufficient to use a non-full-ordered side element for(unsigned int n=0; n<side->n_nodes(); n++) { const Point dist_from_origin = this->_mesh.point(side->node(n)) - origin; if(x_sym) if( std::abs(dist_from_origin(0)) > 1.e-3 ) on_x_sym=false; if(y_sym) if( std::abs(dist_from_origin(1)) > 1.e-3 ) on_y_sym=false; if(z_sym) if( std::abs(dist_from_origin(2)) > 1.e-3 ) on_z_sym=false; // if(x_sym) // if( std::abs(dist_from_origin(0)) > 1.e-6 ) // on_x_sym=false; // if(y_sym) // if( std::abs(dist_from_origin(1)) > 1.e-6 ) // on_y_sym=false; // if(z_sym) // if( std::abs(dist_from_origin(2)) > 1.e-6 ) // on_z_sym=false; //find the node most distant from origin Real r = dist_from_origin.size(); if (r > max_r) { max_r = r; max_r_node=side->node(n); } } sym_side = (x_sym && on_x_sym) || (y_sym && on_y_sym) || (z_sym && on_z_sym); if (!sym_side) faces.insert( std::make_pair(elem->id(), s) ); } // neighbor(s) == NULL } // sides } // elems } // If a boundary side has one node on the outer boundary, // all points of this side are on the outer boundary. // Start with the node most distant from origin, which has // to be on the outer boundary, then recursively find all // sides and nodes connected to it. Found sides are moved // from faces to ofaces, nodes are collected in onodes. // Here, the search is done iteratively, because, depending on // the mesh, a very high level of recursion might be necessary. if (max_r_node > 0) onodes.insert(max_r_node); { std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = faces.begin(); unsigned int facesfound=0; while (face_it != faces.end()) { std::pair<dof_id_type, unsigned int> p; p = *face_it; // This has to be a full-ordered side element, // since we need the correct n_nodes, AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second)); bool found=false; for(unsigned int sn=0; sn<side->n_nodes(); sn++) if(onodes.count(side->node(sn))) { found=true; break; } // If a new oface is found, include its nodes in onodes if(found) { for(unsigned int sn=0; sn<side->n_nodes(); sn++) onodes.insert(side->node(sn)); ofaces.insert(p); face_it++; // iteration is done here faces.erase(p); facesfound++; } else face_it++; // iteration is done here // If at least one new oface was found in this cycle, // do another search cycle. if(facesfound>0 && face_it == faces.end()) { facesfound = 0; face_it = faces.begin(); } } } #ifdef DEBUG if (be_verbose) libMesh::out << " found " << faces.size() << " inner and " << ofaces.size() << " outer boundary faces" << std::endl; #endif // When the user provided a non-null pointer to // inner_faces, that implies he wants to have // this std::set. For now, simply copy the data. if (inner_faces != NULL) *inner_faces = faces; // free memory, clear our local variable, no need // for it any more. faces.clear(); // outer_nodes maps onodes to their duplicates std::map<dof_id_type, Node *> outer_nodes; // We may need to pick our own object ids in parallel dof_id_type old_max_node_id = _mesh.max_node_id(); dof_id_type old_max_elem_id = _mesh.max_elem_id(); // for each boundary node, add an outer_node with // double distance from origin. std::set<dof_id_type>::iterator on_it = onodes.begin(); for( ; on_it != onodes.end(); ++on_it) { Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin; if (_mesh.is_serial()) { // Add with a default id in serial outer_nodes[*on_it]=this->_mesh.add_point(p); } else { // Pick a unique id in parallel Node &bnode = _mesh.node(*on_it); dof_id_type new_id = bnode.id() + old_max_node_id; outer_nodes[*on_it] = this->_mesh.add_point(p, new_id, bnode.processor_id()); } } #ifdef DEBUG // for verbose, remember n_elem dof_id_type n_conventional_elem = this->_mesh.n_elem(); #endif // build Elems based on boundary side type std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = ofaces.begin(); for( ; face_it != ofaces.end(); ++face_it) { // Shortcut to the pair being iterated over std::pair<dof_id_type,unsigned int> p = *face_it; // build a full-ordered side element to get the base nodes AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second)); // create cell depending on side type, assign nodes, // use braces to force scope. bool is_higher_order_elem = false; { Elem* el; switch(side->type()) { // 3D infinite elements // TRIs case TRI3: el=new InfPrism6; break; case TRI6: el=new InfPrism12; is_higher_order_elem = true; break; // QUADs case QUAD4: el=new InfHex8; break; case QUAD8: el=new InfHex16; is_higher_order_elem = true; break; case QUAD9: el=new InfHex18; // the method of assigning nodes (which follows below) // omits in the case of QUAD9 the bubble node; therefore // we assign these first by hand here. el->set_node(16) = side->get_node(8); el->set_node(17) = outer_nodes[side->node(8)]; is_higher_order_elem=true; break; // 2D infinite elements case EDGE2: el=new InfQuad4; break; case EDGE3: el=new InfQuad6; el->set_node(4) = side->get_node(2); break; // 1D infinite elements not supported default: libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): " << "invalid face element " << std::endl; continue; } // In parallel, assign unique ids to the new element if (!_mesh.is_serial()) { Elem *belem = _mesh.elem(p.first); el->processor_id() = belem->processor_id(); // We'd better not have elements with more than 6 sides el->set_id (belem->id() * 6 + p.second + old_max_elem_id); } // assign vertices to the new infinite element const unsigned int n_base_vertices = side->n_vertices(); for(unsigned int i=0; i<n_base_vertices; i++) { el->set_node(i ) = side->get_node(i); el->set_node(i+n_base_vertices) = outer_nodes[side->node(i)]; } // when this is a higher order element, // assign also the nodes in between if (is_higher_order_elem) { // n_safe_base_nodes is the number of nodes in \p side // that may be safely assigned using below for loop. // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(), // since for QUAD9, the 9th node was already assigned above const unsigned int n_safe_base_nodes = el->n_vertices(); for(unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++) { el->set_node(i+n_base_vertices) = side->get_node(i); el->set_node(i+n_safe_base_nodes) = outer_nodes[side->node(i)]; } } // add infinite element to mesh this->_mesh.add_elem(el); } // el goes out of scope } // for #ifdef DEBUG _mesh.libmesh_assert_valid_parallel_ids(); if (be_verbose) libMesh::out << " added " << this->_mesh.n_elem() - n_conventional_elem << " infinite elements and " << onodes.size() << " nodes to the mesh" << std::endl << std::endl; #endif STOP_LOG("build_inf_elem()", "InfElemBuilder"); }
void ExodusII_IO::read (const std::string & fname) { // Get a reference to the mesh we are reading MeshBase & mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data mesh.clear(); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifdef DEBUG this->verbose(true); #endif // Instantiate the ElementMaps interface ExodusII_IO_Helper::ElementMaps em(*exio_helper); // Open the exodus file in EX_READ mode exio_helper->open(fname.c_str(), /*read_only=*/true); // Get header information from exodus file exio_helper->read_header(); // Read the QA records exio_helper->read_qa_records(); // Print header information exio_helper->print_header(); // Read nodes from the exodus file exio_helper->read_nodes(); // Reserve space for the nodes. mesh.reserve_nodes(exio_helper->num_nodes); // Read the node number map from the Exodus file. This is // required if we want to preserve the numbering of nodes as it // exists in the Exodus file. If the Exodus file does not contain // a node_num_map, the identity map is returned by this call. exio_helper->read_node_num_map(); // Loop over the nodes, create Nodes with local processor_id 0. for (int i=0; i<exio_helper->num_nodes; i++) { // Use the node_num_map to get the correct ID for Exodus int exodus_id = exio_helper->node_num_map[i]; // Catch the node that was added to the mesh Node * added_node = mesh.add_point (Point(exio_helper->x[i], exio_helper->y[i], exio_helper->z[i]), exodus_id-1); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (added_node->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned node ID " \ << added_node->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); } // This assert is no longer valid if the nodes are not numbered // sequentially starting from 1 in the Exodus file. // libmesh_assert_equal_to (static_cast<unsigned int>(exio_helper->num_nodes), mesh.n_nodes()); // Get information about all the blocks exio_helper->read_block_info(); // Reserve space for the elements mesh.reserve_elem(exio_helper->num_elem); // Read the element number map from the Exodus file. This is // required if we want to preserve the numbering of elements as it // exists in the Exodus file. If the Exodus file does not contain // an elem_num_map, the identity map is returned by this call. exio_helper->read_elem_num_map(); // Read in the element connectivity for each block. int nelem_last_block = 0; // Loop over all the blocks for (int i=0; i<exio_helper->num_elem_blk; i++) { // Read the information for block i exio_helper->read_elem_in_block (i); int subdomain_id = exio_helper->get_block_id(i); // populate the map of names std::string subdomain_name = exio_helper->get_block_name(i); if (!subdomain_name.empty()) mesh.subdomain_name(static_cast<subdomain_id_type>(subdomain_id)) = subdomain_name; // Set any relevant node/edge maps for this element const std::string type_str (exio_helper->get_elem_type()); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str); // Loop over all the faces in this block int jmax = nelem_last_block+exio_helper->num_elem_this_blk; for (int j=nelem_last_block; j<jmax; j++) { Elem * elem = Elem::build (conv.get_canonical_type()).release(); libmesh_assert (elem); elem->subdomain_id() = static_cast<subdomain_id_type>(subdomain_id) ; // Use the elem_num_map to obtain the ID of this element in the Exodus file int exodus_id = exio_helper->elem_num_map[j]; // Assign this element the same ID it had in the Exodus // file, but make it zero-based by subtracting 1. Note: // some day we could use 1-based numbering in libmesh and // thus match the Exodus numbering exactly, but at the // moment libmesh is zero-based. elem->set_id(exodus_id-1); // Record that we have seen an element of dimension elem->dim() elems_of_dimension[elem->dim()] = true; // Catch the Elem pointer that the Mesh throws back elem = mesh.add_elem (elem); // If the Mesh assigned an ID different from what is in the // Exodus file, we should probably error. if (elem->id() != static_cast<unsigned>(exodus_id-1)) libmesh_error_msg("Error! Mesh assigned ID " \ << elem->id() \ << " which is different from the (zero-based) Exodus ID " \ << exodus_id-1 \ << "!"); // Set all the nodes for this element for (int k=0; k<exio_helper->num_nodes_per_elem; k++) { // global index int gi = (j-nelem_last_block)*exio_helper->num_nodes_per_elem + conv.get_node_map(k); // The entries in 'connect' are actually (1-based) // indices into the node_num_map, so to get the right // node ID we: // 1.) Subtract 1 from connect[gi] // 2.) Pass it through node_num_map to get the corresponding Exodus ID // 3.) Subtract 1 from that, since libmesh node numbering is "zero"-based, // even when the Exodus node numbering doesn't start with 1. int libmesh_node_id = exio_helper->node_num_map[exio_helper->connect[gi] - 1] - 1; // Set the node pointer in the Elem elem->set_node(k) = mesh.node_ptr(libmesh_node_id); } } // running sum of # of elements per block, // (should equal total number of elements in the end) nelem_last_block += exio_helper->num_elem_this_blk; } // This assert isn't valid if the Exodus file's numbering doesn't // start with 1! For example, if Exodus's elem_num_map is 21, 22, // 23, 24, 25, 26, 27, 28, 29, 30, ... 84, then by the time you are // done with the loop above, mesh.n_elem() will report 84 and // nelem_last_block will be 64. // libmesh_assert_equal_to (static_cast<unsigned>(nelem_last_block), mesh.n_elem()); // Set the mesh dimension to the largest encountered for an element for (unsigned char i=0; i!=4; ++i) if (elems_of_dimension[i]) mesh.set_mesh_dimension(i); // Read in sideset information -- this is useful for applying boundary conditions { // Get basic information about all sidesets exio_helper->read_sideset_info(); int offset=0; for (int i=0; i<exio_helper->num_side_sets; i++) { // Compute new offset offset += (i > 0 ? exio_helper->num_sides_per_set[i-1] : 0); exio_helper->read_sideset (i, offset); std::string sideset_name = exio_helper->get_side_set_name(i); if (!sideset_name.empty()) mesh.get_boundary_info().sideset_name (cast_int<boundary_id_type>(exio_helper->get_side_set_id(i))) = sideset_name; } for (unsigned int e=0; e<exio_helper->elem_list.size(); e++) { // The numbers in the Exodus file sidesets should be thought // of as (1-based) indices into the elem_num_map array. So, // to get the right element ID we have to: // 1.) Subtract 1 from elem_list[e] (to get a zero-based index) // 2.) Pass it through elem_num_map (to get the corresponding Exodus ID) // 3.) Subtract 1 from that, since libmesh is "zero"-based, // even when the Exodus numbering doesn't start with 1. dof_id_type libmesh_elem_id = cast_int<dof_id_type>(exio_helper->elem_num_map[exio_helper->elem_list[e] - 1] - 1); // Set any relevant node/edge maps for this element Elem * elem = mesh.elem(libmesh_elem_id); const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(elem->type()); // Map the zero-based Exodus side numbering to the libmesh side numbering int mapped_side = conv.get_side_map(exio_helper->side_list[e]-1); // Check for errors if (mapped_side == ExodusII_IO_Helper::Conversion::invalid_id) libmesh_error_msg("Invalid 1-based side id: " \ << exio_helper->side_list[e] \ << " detected for " \ << Utility::enum_to_string(elem->type())); // Add this (elem,side,id) triplet to the BoundaryInfo object. mesh.get_boundary_info().add_side (libmesh_elem_id, cast_int<unsigned short>(mapped_side), cast_int<boundary_id_type>(exio_helper->id_list[e])); } } // Read nodeset info { exio_helper->read_nodeset_info(); for (int nodeset=0; nodeset<exio_helper->num_node_sets; nodeset++) { boundary_id_type nodeset_id = cast_int<boundary_id_type>(exio_helper->nodeset_ids[nodeset]); std::string nodeset_name = exio_helper->get_node_set_name(nodeset); if (!nodeset_name.empty()) mesh.get_boundary_info().nodeset_name(nodeset_id) = nodeset_name; exio_helper->read_nodeset(nodeset); for (unsigned int node=0; node<exio_helper->node_list.size(); node++) { // As before, the entries in 'node_list' are 1-based // indcies into the node_num_map array, so we have to map // them. See comment above. int libmesh_node_id = exio_helper->node_num_map[exio_helper->node_list[node] - 1] - 1; mesh.get_boundary_info().add_node(cast_int<dof_id_type>(libmesh_node_id), nodeset_id); } } } #if LIBMESH_DIM < 3 if (mesh.mesh_dimension() > LIBMESH_DIM) libmesh_error_msg("Cannot open dimension " \ << mesh.mesh_dimension() \ << " mesh file when configured without " \ << mesh.mesh_dimension() \ << "D support."); #endif }
// The main program int main(int argc, char** argv) { //for record-keeping std::cout << "Running: " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; clock_t begin = std::clock(); // Initialize libMesh LibMeshInit init(argc, argv); // Parameters GetPot solverInfile("fem_system_params.in"); const bool transient = solverInfile("transient", false); unsigned int n_timesteps = solverInfile("n_timesteps", 1); const int nx = solverInfile("nx",100); const int ny = solverInfile("ny",100); const int nz = solverInfile("nz",100); GetPot infile("contamTrans.in"); //std::string find_mesh_here = infile("initial_mesh","mesh.exo"); bool doContinuation = infile("do_continuation",false); bool splitSuperAdj = infile("split_super_adjoint",true); //solve as single adjoint or two forwards int maxIter = infile("max_model_refinements",0); //maximum number of model refinements double refStep = infile("refinement_step",0.1); //additional proportion of domain refined per step //this refers to additional basis functions...number of elements will be more... double qoiErrorTol = infile("relative_error_tolerance",0.01); //stopping criterion //bool doDivvyMatlab = infile("do_divvy_in_Matlab",false); //output files to determine next refinement in Matlab bool avoid_sides = infile("avoid_sides",false); //DEBUG, whether to avoid sides while refining if(refStep*maxIter > 1) maxIter = round(ceil(1./refStep)); Mesh mesh(init.comm()); Mesh mesh2(init.comm()); //create mesh unsigned int dim; if(nz == 0){ //to check if oscillations happen in 2D as well... dim = 2; MeshTools::Generation::build_square(mesh, nx, ny, 0., 2300., 0., 1650., QUAD9); MeshTools::Generation::build_square(mesh2, nx, ny, 0., 2300., 0., 1650., QUAD9); }else{ dim = 3; MeshTools::Generation::build_cube(mesh, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27); MeshTools::Generation::build_cube(mesh2, nx, ny, nz, 0., 2300., 0., 1650., 0., 100., HEX27); } mesh.print_info(); //DEBUG // Create an equation systems object. EquationSystems equation_systems (mesh); EquationSystems equation_systems_mix(mesh2); //name system ConvDiff_PrimarySys & system_primary = equation_systems.add_system<ConvDiff_PrimarySys>("ConvDiff_PrimarySys"); //for primary variables ConvDiff_AuxSys & system_aux = equation_systems.add_system<ConvDiff_AuxSys>("ConvDiff_AuxSys"); //for auxiliary variables ConvDiff_MprimeSys & system_mix = equation_systems_mix.add_system<ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); //for superadj ConvDiff_PrimarySadjSys & system_sadj_primary = equation_systems.add_system<ConvDiff_PrimarySadjSys>("ConvDiff_PrimarySadjSys"); //for split superadj ConvDiff_AuxSadjSys & system_sadj_aux = equation_systems.add_system<ConvDiff_AuxSadjSys>("ConvDiff_AuxSadjSys"); //for split superadj //steady-state problem system_primary.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_primary)); system_aux.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_aux)); system_mix.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_mix)); system_sadj_primary.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_sadj_primary)); system_sadj_aux.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system_sadj_aux)); libmesh_assert_equal_to (n_timesteps, 1); // Initialize the system equation_systems.init (); equation_systems_mix.init(); //initial guess for primary state read_initial_parameters(); system_primary.project_solution(initial_value, initial_grad, equation_systems.parameters); finish_initialization(); //nonlinear solver options NewtonSolver *solver_sadj_primary = new NewtonSolver(system_sadj_primary); system_sadj_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_primary); solver_sadj_primary->quiet = solverInfile("solver_quiet", true); solver_sadj_primary->verbose = !solver_sadj_primary->quiet; solver_sadj_primary->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_sadj_primary->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_sadj_primary->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_sadj_primary->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_sadj_aux = new NewtonSolver(system_sadj_aux); system_sadj_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_sadj_aux); solver_sadj_aux->quiet = solverInfile("solver_quiet", true); solver_sadj_aux->verbose = !solver_sadj_aux->quiet; solver_sadj_aux->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_sadj_aux->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_sadj_aux->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_sadj_aux->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_primary = new NewtonSolver(system_primary); system_primary.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_primary); solver_primary->quiet = solverInfile("solver_quiet", true); solver_primary->verbose = !solver_primary->quiet; solver_primary->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_primary->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_primary->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_primary->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); NewtonSolver *solver_aux = new NewtonSolver(system_aux); system_aux.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver_aux); solver_aux->quiet = solverInfile("solver_quiet", true); solver_aux->verbose = !solver_aux->quiet; solver_aux->max_nonlinear_iterations = solverInfile("max_nonlinear_iterations", 15); solver_aux->relative_step_tolerance = solverInfile("relative_step_tolerance", 1.e-3); solver_aux->relative_residual_tolerance = solverInfile("relative_residual_tolerance", 0.0); solver_aux->absolute_residual_tolerance = solverInfile("absolute_residual_tolerance", 0.0); solver_primary->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_sadj_primary->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_aux->require_residual_reduction = solverInfile("require_residual_reduction",true); solver_sadj_aux->require_residual_reduction = solverInfile("require_residual_reduction",true); //linear solver options solver_primary->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_primary->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_primary->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_aux->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_aux->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_aux->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_aux->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_sadj_primary->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_sadj_primary->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_sadj_primary->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_sadj_primary->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); solver_sadj_aux->max_linear_iterations = solverInfile("max_linear_iterations",10000); solver_sadj_aux->initial_linear_tolerance = solverInfile("initial_linear_tolerance",1.e-13); solver_sadj_aux->minimum_linear_tolerance = solverInfile("minimum_linear_tolerance",1.e-13); solver_sadj_aux->linear_tolerance_multiplier = solverInfile("linear_tolerance_multiplier",1.e-3); /*if(doDivvyMatlab){ //DOF maps and such to help visualize std::ofstream output_global_dof("global_dof_map.dat"); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ std::vector< dof_id_type > di; system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di); if(output_global_dof.is_open()){ output_global_dof << i << " "; for(unsigned int j = 0; j < di.size(); j++) output_global_dof << di[j] << " "; output_global_dof << "\n"; } } output_global_dof.close(); std::ofstream output_elem_cent("elem_centroids.dat"); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ Point elem_cent = system_mix.get_mesh().elem(i)->centroid(); if(output_elem_cent.is_open()){ output_elem_cent << elem_cent(0) << " " << elem_cent(1) << "\n"; } } output_elem_cent.close(); }*/ //inverse dof map (elements in support of each node, assuming every 6 dofs belong to same node) std::vector<std::set<dof_id_type> > node_to_elem; node_to_elem.resize(round(system_mix.n_dofs()/6.)); for(unsigned int i = 0 ; i < system_mix.get_mesh().n_elem(); i++){ std::vector< dof_id_type > di; system_mix.get_dof_map().dof_indices(system_mix.get_mesh().elem(i), di); for(unsigned int j = 0; j < di.size(); j++) node_to_elem[round(floor(di[j]/6.))].insert(i); } int refIter = 0; double relError = 2.*qoiErrorTol; while(refIter <= maxIter && relError > qoiErrorTol){ if(!doContinuation){ //clear out previous solutions system_primary.solution->zero(); system_aux.solution->zero(); system_sadj_primary.solution->zero(); system_sadj_aux.solution->zero(); } system_mix.solution->zero(); clock_t begin_inv = std::clock(); system_primary.solve(); system_primary.clearQoI(); clock_t end_inv = std::clock(); clock_t begin_err_est = std::clock(); std::cout << "\n End primary solve, begin auxiliary solve..." << std::endl; system_aux.solve(); std::cout << "\n End auxiliary solve..." << std::endl; clock_t end_aux = std::clock(); system_primary.postprocess(); system_aux.postprocess(); system_sadj_primary.set_c_vals(system_primary.get_c_vals()); system_sadj_aux.set_auxc_vals(system_aux.get_auxc_vals()); equation_systems_mix.reinit(); //combine primary and auxiliary variables into psi DirectSolutionTransfer sol_transfer(init.comm()); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_c")), system_mix.variable(system_mix.variable_number("aux_c"))); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_zc")), system_mix.variable(system_mix.variable_number("aux_zc"))); sol_transfer.transfer(system_aux.variable(system_aux.variable_number("aux_fc")), system_mix.variable(system_mix.variable_number("aux_fc"))); AutoPtr<NumericVector<Number> > just_aux = system_mix.solution->clone(); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("c")), system_mix.variable(system_mix.variable_number("c"))); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("zc")), system_mix.variable(system_mix.variable_number("zc"))); sol_transfer.transfer(system_primary.variable(system_primary.variable_number("fc")), system_mix.variable(system_mix.variable_number("fc"))); if(!splitSuperAdj){ //solve super-adjoint as single adjoint system_mix.assemble_qoi_sides = true; //QoI doesn't involve sides std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve start ~*~*~*~*~*~*~*~*~\n" << std::endl; std::pair<unsigned int, Real> adjsolve = system_mix.adjoint_solve(); std::cout << "number of iterations to solve adjoint: " << adjsolve.first << std::endl; std::cout << "final residual of adjoint solve: " << adjsolve.second << std::endl; std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve end ~*~*~*~*~*~*~*~*~" << std::endl; NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0); //DEBUG system_mix.assemble(); //calculate residual to correspond to solution //std::cout << "\n sadj norm: " << system_mix.calculate_norm(dual_sol, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 0, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 1, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 2, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 3, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 4, L2) << std::endl; //DEBUG //std::cout << system_mix.calculate_norm(dual_sol, 5, L2) << std::endl; //DEBUG }else{ //solve super-adjoint as system_mix.assemble(); //calculate residual to correspond to solution std::cout << "\n Begin primary super-adjoint solve...\n" << std::endl; system_sadj_primary.solve(); std::cout << "\n End primary super-adjoint solve, begin auxiliary super-adjoint solve...\n" << std::endl; system_sadj_aux.solve(); std::cout << "\n End auxiliary super-adjoint solve...\n" << std::endl; const std::string & adjoint_solution0_name = "adjoint_solution0"; system_mix.add_vector(adjoint_solution0_name, false, GHOSTED); system_mix.set_vector_as_adjoint(adjoint_solution0_name,0); NumericVector<Number> &eep = system_mix.add_adjoint_rhs(0); system_mix.set_adjoint_already_solved(true); NumericVector<Number> &dual_sol = system_mix.get_adjoint_solution(0); NumericVector<Number> &primal_sol = *system_mix.solution; dual_sol.swap(primal_sol); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_c")), system_mix.variable(system_mix.variable_number("aux_c"))); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_zc")), system_mix.variable(system_mix.variable_number("aux_zc"))); sol_transfer.transfer(system_sadj_aux.variable(system_sadj_aux.variable_number("sadj_aux_fc")), system_mix.variable(system_mix.variable_number("aux_fc"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_c")), system_mix.variable(system_mix.variable_number("c"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_zc")), system_mix.variable(system_mix.variable_number("zc"))); sol_transfer.transfer(system_sadj_primary.variable(system_sadj_primary.variable_number("sadj_fc")), system_mix.variable(system_mix.variable_number("fc"))); //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG dual_sol.swap(primal_sol); //std::cout << "\n sadj norm: " << system_mix.calculate_norm(primal_sol, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 0, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 1, L2) << std::endl; //DEBUG //std::cout << system_sadj_primary.calculate_norm(*system_sadj_primary.solution, 2, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 0, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 1, L2) << std::endl; //DEBUG //std::cout << system_sadj_aux.calculate_norm(*system_sadj_aux.solution, 2, L2) << std::endl; //DEBUG } NumericVector<Number> &dual_solution = system_mix.get_adjoint_solution(0); /* NumericVector<Number> &primal_solution = *system_mix.solution; //DEBUG primal_solution.swap(dual_solution); //DEBUG ExodusII_IO(mesh).write_timestep("super_adjoint.exo", equation_systems, 1, / his number indicates how many time steps are being written to the file system_mix.time); //DEBUG primal_solution.swap(dual_solution); //DEBUG */ //adjoint-weighted residual AutoPtr<NumericVector<Number> > adjresid = system_mix.solution->zero_clone(); adjresid->pointwise_mult(*system_mix.rhs,dual_solution); adjresid->scale(-0.5); std::cout << "\n -0.5*M'_HF(psiLF)(superadj): " << adjresid->sum() << std::endl; //DEBUG //LprimeHF(psiLF) AutoPtr<NumericVector<Number> > LprimeHF_psiLF = system_mix.solution->zero_clone(); LprimeHF_psiLF->pointwise_mult(*system_mix.rhs,*just_aux); std::cout << " L'_HF(psiLF): " << LprimeHF_psiLF->sum() << std::endl; //DEBUG //QoI and error estimate std::cout << "QoI: " << std::setprecision(17) << system_primary.getQoI() << std::endl; std::cout << "QoI Error estimate: " << std::setprecision(17) << adjresid->sum()+LprimeHF_psiLF->sum() << std::endl; relError = fabs((adjresid->sum()+LprimeHF_psiLF->sum())/system_primary.getQoI()); //print out information std::cout << "Estimated absolute relative qoi error: " << relError << std::endl << std::endl; std::cout << "Estimated HF QoI: " << std::setprecision(17) << system_primary.getQoI()+adjresid->sum()+LprimeHF_psiLF->sum() << std::endl; clock_t end = clock(); std::cout << "Time so far: " << double(end-begin)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << "Time for inverse problem: " << double(end_inv-begin_inv)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << "Time for extra error estimate bits: " << double(end-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << " Time to get auxiliary problems: " << double(end_aux-begin_err_est)/CLOCKS_PER_SEC << " seconds..." << std::endl; std::cout << " Time to get superadjoint: " << double(end-end_aux)/CLOCKS_PER_SEC << " seconds...\n" << std::endl; //proportion of domain refined at this iteration MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); double numMarked = 0.; for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; numMarked += elem->subdomain_id(); } std::cout << "Refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl << std::endl; //output at each iteration std::stringstream ss; ss << refIter; std::string str = ss.str(); std::string write_error_basis_blame = (infile("error_est_output_file_basis_blame", "error_est_breakdown_basis_blame")) + str + ".dat"; std::ofstream output2(write_error_basis_blame); for(unsigned int i = 0 ; i < adjresid->size(); i++){ if(output2.is_open()) output2 << (*adjresid)(i) + (*LprimeHF_psiLF)(i) << "\n"; } output2.close(); if(refIter < maxIter && relError > qoiErrorTol){ //if further refinement needed //collapse error contributions into nodes std::vector<std::pair<Number,dof_id_type> > node_errs(round(system_mix.n_dofs()/6.)); for(unsigned int node_num = 0; node_num < node_errs.size(); node_num++){ node_errs[node_num] = std::pair<Number,dof_id_type> (fabs((*adjresid)(6*node_num) + (*LprimeHF_psiLF)(6*node_num) + (*adjresid)(6*node_num+1) + (*LprimeHF_psiLF)(6*node_num+1) + (*adjresid)(6*node_num+2) + (*LprimeHF_psiLF)(6*node_num+2) + (*adjresid)(6*node_num+3) + (*LprimeHF_psiLF)(6*node_num+3) + (*adjresid)(6*node_num+4) + (*LprimeHF_psiLF)(6*node_num+4) + (*adjresid)(6*node_num+5) + (*LprimeHF_psiLF)(6*node_num+5)), node_num); } //find nodes contributing the most //double refPcnt = std::min((refIter+1)*refStep,1.); double refPcnt = std::min(refStep,1.); //additional refinement (compared to previous iteration) int cutoffLoc = round(node_errs.size()*refPcnt); std::sort(node_errs.begin(), node_errs.end()); std::reverse(node_errs.begin(), node_errs.end()); //find elements in support of worst offenders std::vector<dof_id_type> markMe; markMe.reserve(cutoffLoc*8); for(int i = 0; i < cutoffLoc; i++){ markMe.insert(markMe.end(), node_to_elem[node_errs[i].second].begin(), node_to_elem[node_errs[i].second].end()); } //mark those elements for refinement. for(int i = 0; i < markMe.size(); i++){ if(!avoid_sides || (avoid_sides && !mesh.elem(markMe[i])->on_boundary())) mesh.elem(markMe[i])->subdomain_id() = 1; //assuming HF regions marked with 1 } //to test whether assignment matches matlab's /*std::string stash_assign = "divvy_c_poke.txt"; std::ofstream output_dbg(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; if(output_dbg.is_open()){ output_dbg << elem->id() << " " << elem->subdomain_id() << "\n"; } } output_dbg.close();*/ #ifdef LIBMESH_HAVE_EXODUS_API std::stringstream ss2; ss2 << refIter + 1; std::string str = ss2.str(); std::string write_divvy = "divvy" + str + ".exo"; ExodusII_IO (mesh).write_equation_systems(write_divvy,equation_systems); //DEBUG #endif // #ifdef LIBMESH_HAVE_EXODUS_API } refIter += 1; } std::string stash_assign = "divvy_final.txt"; std::ofstream output_dbg(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); double numMarked = 0.; for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; numMarked += elem->subdomain_id(); if(output_dbg.is_open()){ output_dbg << elem->id() << " " << elem->subdomain_id() << "\n"; } } output_dbg.close(); std::cout << "\nRefinement concluded..." << std::endl; std::cout << "Final refinement fraction: " << numMarked/system_mix.get_mesh().n_elem() << std::endl; std::cout << "Final estimated relative error: " << relError << std::endl; return 0; //done } //end main
// Begin the main program. Note that the first // statement in the program throws an error if // you are in complex number mode, since this // example is only intended to work with real // numbers. int main (int argc, char ** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); #if !defined(LIBMESH_ENABLE_AMR) libmesh_example_requires(false, "--enable-amr"); #else libmesh_example_requires(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc"); // Brief message to the user regarding the program name // and command line arguments. libMesh::out << "Running: " << argv[0]; for (int i=1; i<argc; i++) libMesh::out << " " << argv[i]; libMesh::out << std::endl << std::endl; // Skip this 2D example if libMesh was compiled as 1D-only. libmesh_example_requires(2 <= LIBMESH_DIM, "2D support"); // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); // Create an equation systems object. EquationSystems equation_systems (mesh); MeshTools::Generation::build_square (mesh, 16, 16, -1., 1., -1., 1., QUAD4); LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("System"); // Adds the variable "u" to "System". "u" // will be approximated using first-order approximation. system.add_variable ("u", FIRST); // Also, we need to add two vectors. The tensor matrix v*w^T of // these two vectors will be part of the system matrix. system.add_vector("v", false); system.add_vector("w", false); // We need an additional matrix to be used for preconditioning since // a shell matrix is not suitable for that. system.add_matrix("Preconditioner"); // Give the system a pointer to the matrix assembly function. system.attach_assemble_function (assemble); // Initialize the data structures for the equation system. equation_systems.init (); // Prints information about the system to the screen. equation_systems.print_info(); equation_systems.parameters.set<unsigned int> ("linear solver maximum iterations") = 250; equation_systems.parameters.set<Real> ("linear solver tolerance") = TOLERANCE; // Refine arbitrarily some elements. for (unsigned int i=0; i<2; i++) { MeshRefinement mesh_refinement(mesh); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; if (elem->active()) { if ((elem->id()%20)>8) { elem->set_refinement_flag(Elem::REFINE); } else { elem->set_refinement_flag(Elem::DO_NOTHING); } } else { elem->set_refinement_flag(Elem::INACTIVE); } } mesh_refinement.refine_elements(); equation_systems.reinit(); } // Prints information about the system to the screen. equation_systems.print_info(); // Before the assemblation of the matrix, we have to clear the two // vectors that form the tensor matrix (since this is not performed // automatically). system.get_vector("v").init(system.n_dofs(), system.n_local_dofs()); system.get_vector("w").init(system.n_dofs(), system.n_local_dofs()); // We need a shell matrix to solve. There is currently no way to // store the shell matrix in the system. We just create it locally // here (a shell matrix does not occupy much memory). SumShellMatrix<Number> shellMatrix(system.comm()); TensorShellMatrix<Number> shellMatrix0(system.get_vector("v"), system.get_vector("w")); shellMatrix.matrices.push_back(&shellMatrix0); SparseShellMatrix<Number> shellMatrix1(*system.matrix); shellMatrix.matrices.push_back(&shellMatrix1); // Attach that to the system. system.attach_shell_matrix(&shellMatrix); // Reset the preconditioning matrix to zero (for the system matrix, // the same thing is done automatically). system.get_matrix("Preconditioner").zero(); // Assemble & solve the linear system system.solve(); // Detach the shell matrix from the system since it will go out of // scope. Nobody should solve the system outside this function. system.detach_shell_matrix(); // Print a nice message. libMesh::out << "Solved linear system in " << system.n_linear_iterations() << " iterations, residual norm is " << system.final_linear_residual() << "." << std::endl; #if defined(LIBMESH_HAVE_VTK) && !defined(LIBMESH_ENABLE_PARMESH) // Write result to file. VTKIO(mesh).write_equation_systems ("out.pvtu", equation_systems); #endif // #ifdef LIBMESH_HAVE_VTK #endif // #ifndef LIBMESH_ENABLE_AMR return 0; }
void MultiAppNearestNodeTransfer::execute() { Moose::out << "Beginning NearestNodeTransfer " << _name << std::endl; switch(_direction) { case TO_MULTIAPP: { FEProblem & from_problem = *_multi_app->problem(); MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); MeshBase * from_mesh = NULL; if (_displaced_source_mesh && from_problem.getDisplacedProblem()) { mooseError("Cannot use a NearestNode transfer from a displaced mesh to a MultiApp!"); from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh(); } else from_mesh = &from_problem.mesh().getMesh(); SystemBase & from_system_base = from_var.sys(); System & from_sys = from_system_base.system(); unsigned int from_sys_num = from_sys.number(); // Only works with a serialized mesh to transfer from! mooseAssert(from_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!"); unsigned int from_var_num = from_sys.variable_number(from_var.name()); // EquationSystems & from_es = from_sys.get_equation_systems(); //Create a serialized version of the solution vector NumericVector<Number> * serialized_solution = NumericVector<Number>::build().release(); serialized_solution->init(from_sys.n_dofs(), false, SERIAL); // Need to pull down a full copy of this vector on every processor so we can get values in parallel from_sys.solution->localize(*serialized_solution); for(unsigned int i=0; i<_multi_app->numGlobalApps(); i++) { if (_multi_app->hasLocalApp(i)) { MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); // Loop over the master nodes and set the value of the variable System * to_sys = find_sys(_multi_app->appProblem(i)->es(), _to_var_name); if (!to_sys) mooseError("Cannot find variable "<<_to_var_name<<" for "<<_name<<" Transfer"); 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->appProblem(i)->getDisplacedProblem()) mesh = &_multi_app->appProblem(i)->getDisplacedProblem()->mesh().getMesh(); else mesh = &_multi_app->appProblem(i)->mesh().getMesh(); bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_nodal) { MeshBase::const_node_iterator node_it = mesh->local_nodes_begin(); MeshBase::const_node_iterator node_end = mesh->local_nodes_end(); for(; node_it != node_end; ++node_it) { Node * node = *node_it; Point actual_position = *node+_multi_app->position(i); 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); // Swap back Moose::swapLibMeshComm(swapped); Real distance = 0; // Just to satisfy the last argument MeshBase::const_node_iterator from_nodes_begin = from_mesh->nodes_begin(); MeshBase::const_node_iterator from_nodes_end = from_mesh->nodes_end(); Node * nearest_node = NULL; if (_fixed_meshes) { if (_node_map.find(node->id()) == _node_map.end()) // Haven't cached it yet { nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end); _node_map[node->id()] = nearest_node; _distance_map[node->id()] = distance; } else { nearest_node = _node_map[node->id()]; //distance = _distance_map[node->id()]; } } else nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end); // Assuming LAGRANGE! dof_id_type from_dof = nearest_node->dof_number(from_sys_num, from_var_num, 0); Real from_value = (*serialized_solution)(from_dof); // Swap again swapped = Moose::swapLibMeshComm(_multi_app->comm()); solution.set(dof, from_value); } } } else // Elemental { MeshBase::const_element_iterator elem_it = mesh->local_elements_begin(); MeshBase::const_element_iterator elem_end = mesh->local_elements_end(); for(; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; Point centroid = elem->centroid(); Point actual_position = centroid+_multi_app->position(i); 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); // Swap back Moose::swapLibMeshComm(swapped); Real distance = 0; // Just to satisfy the last argument MeshBase::const_node_iterator from_nodes_begin = from_mesh->nodes_begin(); MeshBase::const_node_iterator from_nodes_end = from_mesh->nodes_end(); Node * nearest_node = NULL; if (_fixed_meshes) { if (_node_map.find(elem->id()) == _node_map.end()) // Haven't cached it yet { nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end); _node_map[elem->id()] = nearest_node; _distance_map[elem->id()] = distance; } else { nearest_node = _node_map[elem->id()]; //distance = _distance_map[elem->id()]; } } else nearest_node = getNearestNode(actual_position, distance, from_nodes_begin, from_nodes_end); // Assuming LAGRANGE! dof_id_type from_dof = nearest_node->dof_number(from_sys_num, from_var_num, 0); Real from_value = (*serialized_solution)(from_dof); // Swap again swapped = Moose::swapLibMeshComm(_multi_app->comm()); solution.set(dof, from_value); } } } solution.close(); to_sys->update(); // Swap back Moose::swapLibMeshComm(swapped); } } delete serialized_solution; break; } case FROM_MULTIAPP: { FEProblem & to_problem = *_multi_app->problem(); MooseVariable & to_var = to_problem.getVariable(0, _to_var_name); SystemBase & to_system_base = to_var.sys(); System & to_sys = to_system_base.system(); NumericVector<Real> & to_solution = *to_sys.solution; unsigned int to_sys_num = to_sys.number(); // Only works with a serialized mesh to transfer to! mooseAssert(to_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!"); unsigned int to_var_num = to_sys.variable_number(to_var.name()); // EquationSystems & to_es = to_sys.get_equation_systems(); 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) == FEType(); dof_id_type n_nodes = to_mesh->n_nodes(); dof_id_type n_elems = to_mesh->n_elem(); ///// All of the following are indexed off to_node->id() or to_elem->id() ///// // Minimum distances from each node in the "to" mesh to a node in std::vector<Real> min_distances; // The node ids in the "from" mesh that this processor has found to be the minimum distances to the "to" nodes std::vector<dof_id_type> min_nodes; // After the call to maxloc() this will tell us which processor actually has the minimum std::vector<unsigned int> min_procs; // The global multiapp ID that this processor found had the minimum distance node in it. std::vector<unsigned int> min_apps; if (is_nodal) { min_distances.resize(n_nodes, std::numeric_limits<Real>::max()); min_nodes.resize(n_nodes); min_procs.resize(n_nodes); min_apps.resize(n_nodes); } else { min_distances.resize(n_elems, std::numeric_limits<Real>::max()); min_nodes.resize(n_elems); min_procs.resize(n_elems); min_apps.resize(n_elems); } for(unsigned int i=0; i<_multi_app->numGlobalApps(); i++) { if (!_multi_app->hasLocalApp(i)) continue; MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); FEProblem & from_problem = *_multi_app->appProblem(i); MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); SystemBase & from_system_base = from_var.sys(); System & from_sys = from_system_base.system(); // Only works with a serialized mesh to transfer from! mooseAssert(from_sys.get_mesh().is_serial(), "MultiAppNearestNodeTransfer only works with SerialMesh!"); // unsigned int from_var_num = from_sys.variable_number(from_var.name()); // EquationSystems & from_es = from_sys.get_equation_systems(); MeshBase * from_mesh = NULL; if (_displaced_source_mesh && from_problem.getDisplacedProblem()) from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh(); else from_mesh = &from_problem.mesh().getMesh(); MeshTools::BoundingBox app_box = MeshTools::processor_bounding_box(*from_mesh, libMesh::processor_id()); Point app_position = _multi_app->position(i); Moose::swapLibMeshComm(swapped); if (is_nodal) { MeshBase::const_node_iterator to_node_it = to_mesh->nodes_begin(); MeshBase::const_node_iterator to_node_end = to_mesh->nodes_end(); for(; to_node_it != to_node_end; ++to_node_it) { Node * to_node = *to_node_it; unsigned int to_node_id = to_node->id(); Real current_distance = 0; MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); MeshBase::const_node_iterator from_nodes_begin = from_mesh->local_nodes_begin(); MeshBase::const_node_iterator from_nodes_end = from_mesh->local_nodes_end(); Node * nearest_node = NULL; if (_fixed_meshes) { if (_node_map.find(to_node->id()) == _node_map.end()) // Haven't cached it yet { nearest_node = getNearestNode(*to_node-app_position, current_distance, from_nodes_begin, from_nodes_end); _node_map[to_node->id()] = nearest_node; _distance_map[to_node->id()] = current_distance; } else { nearest_node = _node_map[to_node->id()]; current_distance = _distance_map[to_node->id()]; } } else nearest_node = getNearestNode(*to_node-app_position, current_distance, from_nodes_begin, from_nodes_end); Moose::swapLibMeshComm(swapped); // TODO: Logic bug when we are using caching. "current_distance" is set by a call to getNearestNode which is // skipped in that case. We shouldn't be relying on it or stuffing it in another data structure if (current_distance < min_distances[to_node->id()]) { min_distances[to_node_id] = current_distance; min_nodes[to_node_id] = nearest_node->id(); min_apps[to_node_id] = i; } } } else // Elemental { MeshBase::const_element_iterator to_elem_it = to_mesh->elements_begin(); MeshBase::const_element_iterator to_elem_end = to_mesh->elements_end(); for(; to_elem_it != to_elem_end; ++to_elem_it) { Elem * to_elem = *to_elem_it; unsigned int to_elem_id = to_elem->id(); Point actual_position = to_elem->centroid()-app_position; Real current_distance = 0; MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); MeshBase::const_node_iterator from_nodes_begin = from_mesh->local_nodes_begin(); MeshBase::const_node_iterator from_nodes_end = from_mesh->local_nodes_end(); Node * nearest_node = NULL; if (_fixed_meshes) { if (_node_map.find(to_elem->id()) == _node_map.end()) // Haven't cached it yet { nearest_node = getNearestNode(actual_position, current_distance, from_nodes_begin, from_nodes_end); _node_map[to_elem->id()] = nearest_node; _distance_map[to_elem->id()] = current_distance; } else { nearest_node = _node_map[to_elem->id()]; current_distance = _distance_map[to_elem->id()]; } } else nearest_node = getNearestNode(actual_position, current_distance, from_nodes_begin, from_nodes_end); Moose::swapLibMeshComm(swapped); // TODO: Logic bug when we are using caching. "current_distance" is set by a call to getNearestNode which is // skipped in that case. We shouldn't be relying on it or stuffing it in another data structure if (current_distance < min_distances[to_elem->id()]) { min_distances[to_elem_id] = current_distance; min_nodes[to_elem_id] = nearest_node->id(); min_apps[to_elem_id] = i; } } } } /* // We're going to need serialized solution vectors for each app // We could try to only do it for the apps that have mins in them... // but it's tough because this is a collective operation... so that would have to be coordinated std::vector<NumericVector<Number> *> serialized_from_solutions(_multi_app->numGlobalApps()); if (_multi_app->hasApp()) { // Swap MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); for(unsigned int i=0; i<_multi_app->numGlobalApps(); i++) { if (!_multi_app->hasLocalApp(i)) continue; FEProblem & from_problem = *_multi_app->appProblem(i); MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); SystemBase & from_system_base = from_var.sys(); System & from_sys = from_system_base.system(); //Create a serialized version of the solution vector serialized_from_solutions[i] = NumericVector<Number>::build().release(); serialized_from_solutions[i]->init(from_sys.n_dofs(), false, SERIAL); // Need to pull down a full copy of this vector on every processor so we can get values in parallel from_sys.solution->localize(*serialized_from_solutions[i]); } // Swap back Moose::swapLibMeshComm(swapped); } */ // We've found the nearest nodes for this processor. We need to see which processor _actually_ found the nearest though Parallel::minloc(min_distances, min_procs); // Now loop through min_procs and see if _this_ processor had the actual minimum for any nodes. // If it did then we're going to go get the value from that nearest node and transfer its value processor_id_type proc_id = libMesh::processor_id(); for(unsigned int j=0; j<min_procs.size(); j++) { if (min_procs[j] == proc_id) // This means that this processor really did find the minumum so we need to transfer the value { // The zero only works for LAGRANGE! dof_id_type to_dof = 0; if (is_nodal) { Node & to_node = to_mesh->node(j); to_dof = to_node.dof_number(to_sys_num, to_var_num, 0); } else { Elem & to_elem = *to_mesh->elem(j); to_dof = to_elem.dof_number(to_sys_num, to_var_num, 0); } // The app that has the nearest node in it unsigned int from_app_num = min_apps[j]; mooseAssert(_multi_app->hasLocalApp(from_app_num), "Something went very wrong!"); // Swap MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); FEProblem & from_problem = *_multi_app->appProblem(from_app_num); MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); SystemBase & from_system_base = from_var.sys(); System & from_sys = from_system_base.system(); unsigned int from_sys_num = from_sys.number(); unsigned int from_var_num = from_sys.variable_number(from_var.name()); // EquationSystems & from_es = from_sys.get_equation_systems(); MeshBase * from_mesh = NULL; if (_displaced_source_mesh && from_problem.getDisplacedProblem()) from_mesh = &from_problem.getDisplacedProblem()->mesh().getMesh(); else from_mesh = &from_problem.mesh().getMesh(); Node & from_node = from_mesh->node(min_nodes[j]); // Assuming LAGRANGE! dof_id_type from_dof = from_node.dof_number(from_sys_num, from_var_num, 0); Real from_value = (*from_sys.solution)(from_dof); // Swap back Moose::swapLibMeshComm(swapped); to_solution.set(to_dof, from_value); } } to_solution.close(); to_sys.update(); break; } } Moose::out << "Finished NearestNodeTransfer " << _name << std::endl; }
void VTKIO::cells_to_vtk() { const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkIdList> pts = vtkSmartPointer<vtkIdList>::New(); std::vector<int> types(mesh.n_active_local_elem()); unsigned active_element_counter = 0; vtkSmartPointer<vtkIntArray> elem_id = vtkSmartPointer<vtkIntArray>::New(); elem_id->SetName("libmesh_elem_id"); elem_id->SetNumberOfComponents(1); vtkSmartPointer<vtkIntArray> subdomain_id = vtkSmartPointer<vtkIntArray>::New(); subdomain_id->SetName("subdomain_id"); subdomain_id->SetNumberOfComponents(1); MeshBase::const_element_iterator it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_local_elements_end(); for (; it != end; ++it, ++active_element_counter) { Elem *elem = *it; pts->SetNumberOfIds(elem->n_nodes()); // get the connectivity for this element std::vector<dof_id_type> conn; elem->connectivity(0, VTK, conn); for (unsigned int i=0; i<conn.size(); ++i) { // If the node ID is not found in the _local_node_map, we'll // add it to the _vtk_grid. NOTE[JWP]: none of the examples // I have actually enters this section of code... if (_local_node_map.find(conn[i]) == _local_node_map.end()) { dof_id_type global_node_id = elem->node(i); const Node* the_node = mesh.node_ptr(global_node_id); // Error checking... if (the_node == NULL) { libMesh::err << "Error getting pointer to node " << global_node_id << "!" << std::endl; libmesh_error(); } // InsertNextPoint accepts either a double or float array of length 3. Real pt[3] = {0., 0., 0.}; for (unsigned int d=0; d<LIBMESH_DIM; ++d) pt[d] = (*the_node)(d); // Insert the point into the _vtk_grid vtkIdType local = _vtk_grid->GetPoints()->InsertNextPoint(pt); // Update the _local_node_map with the ID returned by VTK _local_node_map[global_node_id] = local; } // Otherwise, the node ID was found in the _local_node_map, so // insert it into the vtkIdList. pts->InsertId(i, _local_node_map[conn[i]]); } vtkIdType vtkcellid = cells->InsertNextCell(pts); types[active_element_counter] = this->get_elem_type(elem->type()); elem_id->InsertTuple1(vtkcellid, elem->id()); subdomain_id->InsertTuple1(vtkcellid, elem->subdomain_id()); } // end loop over active elements _vtk_grid->SetCells(&types[0], cells); _vtk_grid->GetCellData()->AddArray(elem_id); _vtk_grid->GetCellData()->AddArray(subdomain_id); }
void ParmetisPartitioner::assign_partitioning (MeshBase & mesh) { // This function must be run on all processors at once libmesh_parallel_only(mesh.comm()); const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; std::vector<std::vector<dof_id_type> > requested_ids(mesh.n_processors()), requests_to_fill(mesh.n_processors()); MeshBase::element_iterator elem_it = mesh.active_elements_begin(); MeshBase::element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; // we need to get the index from the owning processor // (note we cannot assign it now -- we are iterating // over elements again and this will be bad!) libmesh_assert_less (elem->processor_id(), requested_ids.size()); requested_ids[elem->processor_id()].push_back(elem->id()); } // Trade with all processors (including self) to get their indices for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { // Trade my requests with processor procup and procdown const processor_id_type procup = (mesh.processor_id() + pid) % mesh.n_processors(); const processor_id_type procdown = (mesh.n_processors() + mesh.processor_id() - pid) % mesh.n_processors(); mesh.comm().send_receive (procup, requested_ids[procup], procdown, requests_to_fill[procdown]); // we can overwrite these requested ids in-place. for (std::size_t i=0; i<requests_to_fill[procdown].size(); i++) { const dof_id_type requested_elem_index = requests_to_fill[procdown][i]; libmesh_assert(_global_index_by_pid_map.count(requested_elem_index)); const dof_id_type global_index_by_pid = _global_index_by_pid_map[requested_elem_index]; const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, _pmetis->part.size()); libmesh_assert_less (local_index, mesh.n_active_local_elem()); const unsigned int elem_procid = static_cast<unsigned int>(_pmetis->part[local_index]); libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts)); requests_to_fill[procdown][i] = elem_procid; } // Trade back mesh.comm().send_receive (procdown, requests_to_fill[procdown], procup, requested_ids[procup]); } // and finally assign the partitioning. // note we are iterating in exactly the same order // used to build up the request, so we can expect the // required entries to be in the proper sequence. elem_it = mesh.active_elements_begin(); elem_end = mesh.active_elements_end(); for (std::vector<unsigned int> counters(mesh.n_processors(), 0); elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; const processor_id_type current_pid = elem->processor_id(); libmesh_assert_less (counters[current_pid], requested_ids[current_pid].size()); const processor_id_type elem_procid = requested_ids[current_pid][counters[current_pid]++]; libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts)); elem->processor_id() = elem_procid; } }
void MultiAppMeshFunctionTransfer::execute() { Moose::out << "Beginning MeshFunctionTransfer " << name() << std::endl; getAppInfo(); /** * For every combination of global "from" problem and local "to" problem, find * which "from" bounding boxes overlap with which "to" elements. Keep track * of which processors own bounding boxes that overlap with which elements. * Build vectors of node locations/element centroids to send to other * processors for mesh function evaluations. */ // Get the bounding boxes for the "from" domains. std::vector<MeshTools::BoundingBox> bboxes = getFromBoundingBoxes(); // Figure out how many "from" domains each processor owns. std::vector<unsigned int> froms_per_proc = getFromsPerProc(); std::vector<std::vector<Point> > outgoing_points(n_processors()); std::vector<std::map<std::pair<unsigned int, unsigned int>, unsigned int> > point_index_map(n_processors()); // point_index_map[i_to, element_id] = index // outgoing_points[index] is the first quadrature point in element 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) { MeshBase::const_node_iterator node_it = to_mesh->local_nodes_begin(); MeshBase::const_node_iterator node_end = to_mesh->local_nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; // Loop over the "froms" on processor i_proc. If the node is found in // any of the "froms", add that node to the vector that will be sent to // i_proc. unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool point_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && ! point_found; i_from++) { if (bboxes[i_from].contains_point(*node + _to_positions[i_to])) { std::pair<unsigned int, unsigned int> key(i_to, node->id()); point_index_map[i_proc][key] = outgoing_points[i_proc].size(); outgoing_points[i_proc].push_back(*node + _to_positions[i_to]); point_found = true; } } } } } else // Elemental { MeshBase::const_element_iterator elem_it = to_mesh->local_elements_begin(); MeshBase::const_element_iterator elem_end = to_mesh->local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; 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; // Loop over the "froms" on processor i_proc. If the elem is found in // any of the "froms", add that elem to the vector that will be sent to // i_proc. unsigned int from0 = 0; for (processor_id_type i_proc = 0; i_proc < n_processors(); from0 += froms_per_proc[i_proc], i_proc++) { bool point_found = false; for (unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc] && ! point_found; i_from++) { if (bboxes[i_from].contains_point(centroid + _to_positions[i_to])) { std::pair<unsigned int, unsigned int> key(i_to, elem->id()); point_index_map[i_proc][key] = outgoing_points[i_proc].size(); outgoing_points[i_proc].push_back(centroid + _to_positions[i_to]); point_found = true; } } } } } } /** * Request point evaluations from other processors and handle requests sent to * this processor. */ // Get the local bounding boxes. std::vector<MeshTools::BoundingBox> local_bboxes(froms_per_proc[processor_id()]); { // Find the index to the first of this processor's local bounding boxes. unsigned int local_start = 0; for (processor_id_type i_proc = 0; i_proc < n_processors() && i_proc != processor_id(); i_proc++) { local_start += froms_per_proc[i_proc]; } // Extract the local bounding boxes. for (unsigned int i_from = 0; i_from < froms_per_proc[processor_id()]; i_from++) { local_bboxes[i_from] = bboxes[local_start + i_from]; } } // Setup the local mesh functions. std::vector<MooseSharedPointer<MeshFunction> > local_meshfuns; for (unsigned int i_from = 0; i_from < _from_problems.size(); i_from++) { FEProblem & from_problem = *_from_problems[i_from]; MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); System & from_sys = from_var.sys().system(); unsigned int from_var_num = from_sys.variable_number(from_var.name()); MooseSharedPointer<MeshFunction> from_func; //TODO: make MultiAppTransfer give me the right es if (_displaced_source_mesh && from_problem.getDisplacedProblem()) from_func.reset(new MeshFunction(from_problem.getDisplacedProblem()->es(), *from_sys.current_local_solution, from_sys.get_dof_map(), from_var_num)); else from_func.reset(new MeshFunction(from_problem.es(), *from_sys.current_local_solution, from_sys.get_dof_map(), from_var_num)); from_func->init(Trees::ELEMENTS); from_func->enable_out_of_mesh_mode(OutOfMeshValue); local_meshfuns.push_back(from_func); } // Send points to other processors. std::vector<std::vector<Real> > incoming_evals(n_processors()); std::vector<std::vector<unsigned int> > incoming_app_ids(n_processors()); for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { if (i_proc == processor_id()) continue; _communicator.send(i_proc, outgoing_points[i_proc]); } // Recieve points from other processors, evaluate mesh frunctions at those // points, and send the values back. for (processor_id_type i_proc = 0; i_proc < n_processors(); i_proc++) { std::vector<Point> incoming_points; if (i_proc == processor_id()) incoming_points = outgoing_points[i_proc]; else _communicator.receive(i_proc, incoming_points); std::vector<Real> outgoing_evals(incoming_points.size(), OutOfMeshValue); std::vector<unsigned int> outgoing_ids(incoming_points.size(), -1); // -1 = largest unsigned int for (unsigned int i_pt = 0; i_pt < incoming_points.size(); i_pt++) { Point pt = incoming_points[i_pt]; // Loop until we've found the lowest-ranked app that actually contains // the quadrature point. for (unsigned int i_from = 0; i_from < _from_problems.size() && outgoing_evals[i_pt] == OutOfMeshValue; i_from++) { if (local_bboxes[i_from].contains_point(pt)) { outgoing_evals[i_pt] = (* local_meshfuns[i_from])(pt - _from_positions[i_from]); if (_direction == FROM_MULTIAPP) outgoing_ids[i_pt] = _local2global_map[i_from]; } } } if (i_proc == processor_id()) { incoming_evals[i_proc] = outgoing_evals; if (_direction == FROM_MULTIAPP) incoming_app_ids[i_proc] = outgoing_ids; } else { _communicator.send(i_proc, outgoing_evals); if (_direction == FROM_MULTIAPP) _communicator.send(i_proc, outgoing_ids); } } /** * Gather all of the evaluations, pick out the best ones for each point, and * apply them to the solution vector. When we are transferring from * multiapps, there may be multiple overlapping apps for a particular point. * In that case, we'll try to use the value from the app with the lowest id. */ 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]); if (_direction == FROM_MULTIAPP) _communicator.receive(i_proc, incoming_app_ids[i_proc]); } 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); NumericVector<Real> * solution; switch (_direction) { case TO_MULTIAPP: solution = & getTransferVector(i_to, _to_var_name); break; case FROM_MULTIAPP: solution = to_sys->solution.get(); break; } MeshBase * to_mesh = & _to_meshes[i_to]->getMesh(); bool is_nodal = to_sys->variable_type(var_num).family == LAGRANGE; if (is_nodal) { MeshBase::const_node_iterator node_it = to_mesh->local_nodes_begin(); MeshBase::const_node_iterator node_end = to_mesh->local_nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; // Skip this node if the variable has no dofs at it. if (node->n_dofs(sys_num, var_num) < 1) continue; unsigned int lowest_app_rank = libMesh::invalid_uint; Real best_val = 0.; bool point_found = false; for (unsigned int i_proc = 0; i_proc < incoming_evals.size(); i_proc++) { // Skip this proc if the node wasn't in it's bounding boxes. std::pair<unsigned int, unsigned int> key(i_to, node->id()); if (point_index_map[i_proc].find(key) == point_index_map[i_proc].end()) continue; unsigned int i_pt = point_index_map[i_proc][key]; // Ignore this proc if it's app has a higher rank than the // previously found lowest app rank. if (_direction == FROM_MULTIAPP) { if (incoming_app_ids[i_proc][i_pt] >= lowest_app_rank) continue; } // Ignore this proc if the point was actually outside its meshes. if (incoming_evals[i_proc][i_pt] == OutOfMeshValue) continue; best_val = incoming_evals[i_proc][i_pt]; point_found = true; } if (_error_on_miss && ! point_found) mooseError("Point not found! " << *node + _to_positions[i_to]); dof_id_type dof = node->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } else // Elemental { MeshBase::const_element_iterator elem_it = to_mesh->local_elements_begin(); MeshBase::const_element_iterator elem_end = to_mesh->local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; // Skip this element if the variable has no dofs at it. if (elem->n_dofs(sys_num, var_num) < 1) continue; unsigned int lowest_app_rank = libMesh::invalid_uint; Real best_val = 0; bool point_found = false; for (unsigned int i_proc = 0; i_proc < incoming_evals.size(); i_proc++) { // Skip this proc if the elem wasn't in it's bounding boxes. std::pair<unsigned int, unsigned int> key(i_to, elem->id()); if (point_index_map[i_proc].find(key) == point_index_map[i_proc].end()) continue; unsigned int i_pt = point_index_map[i_proc][key]; // Ignore this proc if it's app has a higher rank than the // previously found lowest app rank. if (_direction == FROM_MULTIAPP) { if (incoming_app_ids[i_proc][i_pt] >= lowest_app_rank) continue; } // Ignore this proc if the point was actually outside its meshes. if (incoming_evals[i_proc][i_pt] == OutOfMeshValue) continue; best_val = incoming_evals[i_proc][i_pt]; point_found = true; } if (_error_on_miss && ! point_found) mooseError("Point not found! " << elem->centroid() + _to_positions[i_to]); dof_id_type dof = elem->dof_number(sys_num, var_num, 0); solution->set(dof, best_val); } } solution->close(); to_sys->update(); } _console << "Finished MeshFunctionTransfer " << name() << std::endl; }
void Partitioner::set_parent_processor_ids(MeshBase & mesh) { // Ignore the parameter when !LIBMESH_ENABLE_AMR libmesh_ignore(mesh); LOG_SCOPE("set_parent_processor_ids()", "Partitioner"); #ifdef LIBMESH_ENABLE_AMR // If the mesh is serial we have access to all the elements, // in particular all the active ones. We can therefore set // the parent processor ids indirecly through their children, and // set the subactive processor ids while examining their active // ancestors. // By convention a parent is assigned to the minimum processor // of all its children, and a subactive is assigned to the processor // of its active ancestor. if (mesh.is_serial()) { // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; // First set descendents std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); // Then set ancestors Elem * parent = child->parent(); while (parent) { // invalidate the parent id, otherwise the min below // will not work if the current parent id is less // than all the children! parent->invalidate_processor_id(); for (unsigned int c=0; c<parent->n_children(); c++) { child = parent->child_ptr(c); libmesh_assert(child); libmesh_assert(!child->is_remote()); libmesh_assert_not_equal_to (child->processor_id(), DofObject::invalid_processor_id); parent->processor_id() = std::min(parent->processor_id(), child->processor_id()); } parent = parent->parent(); } } } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. else { // Setting subactive processor ids is easy: we can guarantee // that children have access to all their parents. // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) { Elem * child = *it; std::vector<const Elem *> subactive_family; child->total_family_tree(subactive_family); for (unsigned int i = 0; i != subactive_family.size(); ++i) const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id(); } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. // We will use a brute-force approach here. Each processor finds its parent // elements and sets the parent pid to the minimum of its // semilocal descendants. // A global reduction is then performed to make sure the true minimum is found. // As noted, this is required because we cannot guarantee that a parent has // access to all its children on any single processor. libmesh_parallel_only(mesh.comm()); libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); const dof_id_type max_elem_id = mesh.max_elem_id(); std::vector<processor_id_type> parent_processor_ids (std::min(communication_blocksize, max_elem_id)); for (dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++) { last_elem_id = std::min(static_cast<dof_id_type>((blk+1)*communication_blocksize), max_elem_id); const dof_id_type first_elem_id = blk*communication_blocksize; std::fill (parent_processor_ids.begin(), parent_processor_ids.end(), DofObject::invalid_processor_id); // first build up local contributions to parent_processor_ids MeshBase::element_iterator not_it = mesh.ancestor_elements_begin(); const MeshBase::element_iterator not_end = mesh.ancestor_elements_end(); bool have_parent_in_block = false; for ( ; not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); libmesh_assert_less (parent_idx, max_elem_id); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { have_parent_in_block = true; processor_id_type parent_pid = DofObject::invalid_processor_id; std::vector<const Elem *> active_family; parent->active_family_tree(active_family); for (unsigned int i = 0; i != active_family.size(); ++i) parent_pid = std::min (parent_pid, active_family[i]->processor_id()); const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); parent_processor_ids[packed_idx] = parent_pid; } } // then find the global minimum mesh.comm().min (parent_processor_ids); // and assign the ids, if we have a parent in this block. if (have_parent_in_block) for (not_it = mesh.ancestor_elements_begin(); not_it != not_end; ++not_it) { Elem * parent = *not_it; const dof_id_type parent_idx = parent->id(); if ((parent_idx >= first_elem_id) && (parent_idx < last_elem_id)) { const dof_id_type packed_idx = parent_idx - first_elem_id; libmesh_assert_less (packed_idx, parent_processor_ids.size()); const processor_id_type parent_pid = parent_processor_ids[packed_idx]; libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_processor_id); parent->processor_id() = parent_pid; } } } } #endif // LIBMESH_ENABLE_AMR }
void MultiAppNearestNodeTransfer::execute() { _console << "Beginning NearestNodeTransfer " << name() << std::endl; getAppInfo(); // Get the bounding boxes for the "from" domains. std::vector<MeshTools::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()); MeshBase::const_node_iterator nodes_begin = to_mesh->local_nodes_begin(); MeshBase::const_node_iterator nodes_end = to_mesh->local_nodes_end(); unsigned int i = 0; for (MeshBase::const_node_iterator nodes_it = nodes_begin; nodes_it != nodes_end; ++nodes_it, ++i) target_local_nodes[i] = *nodes_it; } 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 { MeshBase::const_element_iterator elem_it = to_mesh->local_elements_begin(); MeshBase::const_element_iterator elem_end = to_mesh->local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; 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()); 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(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++) { MooseVariable & from_var = _from_problems[i_local_from]->getVariable(0, _from_var_name); 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(_cached_froms[i_proc].size()); for (unsigned int qp = 0; qp < outgoing_evals.size(); qp++) { MooseVariable & from_var = _from_problems[_cached_froms[i_proc][qp]]->getVariable(0, _from_var_name); 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; } 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()); MeshBase::const_node_iterator nodes_begin = to_mesh->local_nodes_begin(); MeshBase::const_node_iterator nodes_end = to_mesh->local_nodes_end(); unsigned int i = 0; for (MeshBase::const_node_iterator nodes_it = nodes_begin; nodes_it != nodes_end; ++nodes_it, ++i) target_local_nodes[i] = *nodes_it; } 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 { MeshBase::const_element_iterator elem_it = to_mesh->local_elements_begin(); MeshBase::const_element_iterator elem_end = to_mesh->local_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; // 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; }
// we need to provide stress data for storing the data; bool CMaterialInfo::StoreStressInfo() { cout<<STRING_WRITE_BEGIN << "store stress info" << endl; MeshBase& mesh = d_es->get_mesh(); Mesh::element_iterator it_el = mesh.active_local_elements_begin();//mesh.elements_begin(); const Mesh::element_iterator it_last_el = mesh.active_local_elements_end();//mesh.elements_end(); int m= mesh.n_elem(); int n=9; DenseMatrix<Number> stress_data(m,n); // this should come from initial case; // ExplicitSystem& stress_system = d_es->get_system<ExplicitSystem>("StressSystem"); const DofMap& stress_dof_map = stress_system.get_dof_map(); unsigned int sigma_vars[3][3]; sigma_vars[0][0] = stress_system.variable_number ("sigma_00"); sigma_vars[0][1] = stress_system.variable_number ("sigma_01"); sigma_vars[0][2] = stress_system.variable_number ("sigma_02"); sigma_vars[1][0] = stress_system.variable_number ("sigma_10"); sigma_vars[1][1] = stress_system.variable_number ("sigma_11"); sigma_vars[1][2] = stress_system.variable_number ("sigma_12"); sigma_vars[2][0] = stress_system.variable_number ("sigma_20"); sigma_vars[2][1] = stress_system.variable_number ("sigma_21"); sigma_vars[2][2] = stress_system.variable_number ("sigma_22"); unsigned int vonMises_var = stress_system.variable_number ("vonMises"); std::vector<unsigned int> stress_dof_indices_var; // need to put values from the file for ( ; it_el != it_last_el ; ++it_el) { Elem* elem = *it_el; int global_id= elem->id(); for (int irow = 0; irow<3; irow++) { for (int icol =0; icol<3; icol++) { stress_dof_map.dof_indices (elem, stress_dof_indices_var, sigma_vars[irow][icol]); unsigned int dof_index = stress_dof_indices_var[0]; if( (stress_system.solution->first_local_index() <= dof_index) && (dof_index < stress_system.solution->last_local_index()) ) { stress_system.solution->set(dof_index, stress_data(global_id,irow*3+icol)); } } } stress_dof_map.dof_indices (elem, stress_dof_indices_var, vonMises_var); unsigned int dof_index = stress_dof_indices_var[0]; if( (stress_system.solution->first_local_index() <= dof_index) && (dof_index < stress_system.solution->last_local_index()) ) { stress_system.solution->set(dof_index, stress_data(global_id,9)); } } stress_system.solution->close(); stress_system.update(); cout<<STRING_WRITE_END << "store stress info" << endl; return true; }
void ParmetisPartitioner::build_graph (const MeshBase & mesh) { // build the graph in distributed CSR format. Note that // the edges in the graph will correspond to // face neighbors const dof_id_type n_active_local_elem = mesh.n_active_local_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 LIBMESH_BEST_UNORDERED_MULTIMAP<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem * 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 Elem set methods // would be nice Elem * neighbor = const_cast<Elem *>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MULTIMAP) || \ defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || \ defined(LIBMESH_HAVE_HASH_MAP) || \ defined(LIBMESH_HAVE_EXT_HASH_MAP) 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 } } } #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem *> neighbors_offspring; #endif std::vector<std::vector<dof_id_type> > graph(n_active_local_elem); dof_id_type graph_size=0; const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem * elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); std::vector<dof_id_type> & graph_row = graph[local_index]; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem * neighbor = elem->neighbor(ms); if (neighbor != libmesh_nullptr) { // If the neighbor is active treat it // as a connection if (neighbor->active()) { libmesh_assert(_global_index_by_pid_map.count(neighbor->id())); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } #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 (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem * child = neighbors_offspring[nc]; // 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(ns) == elem) { libmesh_assert (child->active()); libmesh_assert (_global_index_by_pid_map.count(child->id())); const dof_id_type child_global_index_by_pid = _global_index_by_pid_map[child->id()]; graph_row.push_back(child_global_index_by_pid); graph_size++; } } } #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) { // FIXME - non-const versions of the Elem set methods // would be nice Elem * neighbor = const_cast<Elem *>(*n_it); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_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); for (map_it_type it = bounds.first; it != bounds.second; ++it) { const Elem * neighbor = it->second; const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } } // Reserve space in the adjacency array _pmetis->xadj.clear(); _pmetis->xadj.reserve (n_active_local_elem + 1); _pmetis->adjncy.clear(); _pmetis->adjncy.reserve (graph_size); for (std::size_t r=0; r<graph.size(); r++) { _pmetis->xadj.push_back(_pmetis->adjncy.size()); std::vector<dof_id_type> graph_row; // build this emtpy graph_row.swap(graph[r]); // this will deallocate at the end of scope _pmetis->adjncy.insert(_pmetis->adjncy.end(), graph_row.begin(), graph_row.end()); } // The end of the adjacency array for the last elem _pmetis->xadj.push_back(_pmetis->adjncy.size()); libmesh_assert_equal_to (_pmetis->xadj.size(), n_active_local_elem+1); libmesh_assert_equal_to (_pmetis->adjncy.size(), graph_size); }
void BreakMeshByBlockManual_3Blocks::addInterfaceBoundary() { // construct boundary 100, which will contain the cohesive interface Elem * elem; BoundaryInfo & boundary_info = _mesh_ptr->getMesh().get_boundary_info(); SubdomainID interface_id = 100; if (!_split_interface) { elem = _mesh_ptr->getMesh().elem_ptr(0); boundary_info.add_side(elem->id(), 4, interface_id); elem = _mesh_ptr->getMesh().elem_ptr(1); boundary_info.add_side(elem->id(), 4, interface_id); elem = _mesh_ptr->getMesh().elem_ptr(2); boundary_info.add_side(elem->id(), 4, interface_id); elem = _mesh_ptr->getMesh().elem_ptr(3); boundary_info.add_side(elem->id(), 4, interface_id); elem = _mesh_ptr->getMesh().elem_ptr(4); boundary_info.add_side(elem->id(), 3, interface_id); elem = _mesh_ptr->getMesh().elem_ptr(6); boundary_info.add_side(elem->id(), 0, interface_id); // rename the boundary boundary_info.sideset_name(interface_id) = _interface_name; } else { elem = _mesh_ptr->getMesh().elem_ptr(0); boundary_info.add_side(elem->id(), 4, 0); elem = _mesh_ptr->getMesh().elem_ptr(2); boundary_info.add_side(elem->id(), 4, 0); elem = _mesh_ptr->getMesh().elem_ptr(3); boundary_info.add_side(elem->id(), 4, 0); // rename the boundary boundary_info.sideset_name(0) = "Block1_Block2"; elem = _mesh_ptr->getMesh().elem_ptr(1); boundary_info.add_side(elem->id(), 4, 4); // rename the boundary boundary_info.sideset_name(4) = "Block1_Block3"; elem = _mesh_ptr->getMesh().elem_ptr(4); boundary_info.add_side(elem->id(), 3, 5); elem = _mesh_ptr->getMesh().elem_ptr(6); boundary_info.add_side(elem->id(), 0, 5); // rename the boundary boundary_info.sideset_name(5) = "Block2_Block3"; } }
void LinearElasticityWithContact::move_mesh (MeshBase & input_mesh, const NumericVector<Number> & input_solution) { // Maintain a set of node ids that we've encountered. LIBMESH_BEST_UNORDERED_SET<dof_id_type> encountered_node_ids; // Localize input_solution so that we have the data to move all // elements (not just elements local to this processor). UniquePtr< NumericVector<Number> > localized_input_solution = NumericVector<Number>::build(input_solution.comm()); localized_input_solution->init (input_solution.size(), false, SERIAL); input_solution.localize(*localized_input_solution); MeshBase::const_element_iterator el = input_mesh.active_elements_begin(); const MeshBase::const_element_iterator end_el = input_mesh.active_elements_end(); for ( ; el != end_el; ++el) { Elem * elem = *el; Elem * orig_elem = _sys.get_mesh().elem_ptr(elem->id()); for (unsigned int node_id=0; node_id<elem->n_nodes(); node_id++) { Node & node = elem->node_ref(node_id); if (encountered_node_ids.find(node.id()) != encountered_node_ids.end()) continue; encountered_node_ids.insert(node.id()); std::vector<std::string> uvw_names(3); uvw_names[0] = "u"; uvw_names[1] = "v"; uvw_names[2] = "w"; { const Point master_point = elem->master_point(node_id); Point uvw; for (unsigned int index=0; index<uvw_names.size(); index++) { const unsigned int var = _sys.variable_number(uvw_names[index]); const FEType & fe_type = _sys.get_dof_map().variable_type(var); FEComputeData data (_sys.get_equation_systems(), master_point); FEInterface::compute_data(elem->dim(), fe_type, elem, data); std::vector<dof_id_type> dof_indices_var; _sys.get_dof_map().dof_indices (orig_elem, dof_indices_var, var); for (unsigned int i=0; i<dof_indices_var.size(); i++) { Number value = (*localized_input_solution)(dof_indices_var[i]) * data.shape[i]; #ifdef LIBMESH_USE_COMPLEX_NUMBERS // We explicitly store the real part in uvw uvw(index) += value.real(); #else uvw(index) += value; #endif } } // Update the node's location node += uvw; } } } }
void unpack(std::vector<largest_id_type>::const_iterator in, Elem** out, MeshBase* mesh) { #ifndef NDEBUG const std::vector<largest_id_type>::const_iterator original_in = in; const largest_id_type incoming_header = *in++; libmesh_assert_equal_to (incoming_header, elem_magic_header); #endif // int 0: level const unsigned int level = static_cast<unsigned int>(*in++); #ifdef LIBMESH_ENABLE_AMR // int 1: p level const unsigned int p_level = static_cast<unsigned int>(*in++); // int 2: refinement flag const int rflag = *in++; libmesh_assert_greater_equal (rflag, 0); libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState refinement_flag = static_cast<Elem::RefinementState>(rflag); // int 3: p refinement flag const int pflag = *in++; libmesh_assert_greater_equal (pflag, 0); libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); const Elem::RefinementState p_refinement_flag = static_cast<Elem::RefinementState>(pflag); #else in += 3; #endif // LIBMESH_ENABLE_AMR // int 4: element type const int typeint = *in++; libmesh_assert_greater_equal (typeint, 0); libmesh_assert_less (typeint, INVALID_ELEM); const ElemType type = static_cast<ElemType>(typeint); const unsigned int n_nodes = Elem::type_to_n_nodes_map[type]; // int 5: processor id const processor_id_type processor_id = static_cast<processor_id_type>(*in++); libmesh_assert (processor_id < mesh->n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const subdomain_id_type subdomain_id = static_cast<subdomain_id_type>(*in++); // int 7: dof object id const dof_id_type id = static_cast<dof_id_type>(*in++); libmesh_assert_not_equal_to (id, DofObject::invalid_id); #ifdef LIBMESH_ENABLE_UNIQUE_ID // int 8: dof object unique id const unique_id_type unique_id = static_cast<unique_id_type>(*in++); #endif #ifdef LIBMESH_ENABLE_AMR // int 9: parent dof object id const dof_id_type parent_id = static_cast<dof_id_type>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 10: local child id const unsigned int which_child_am_i = static_cast<unsigned int>(*in++); #else in += 2; #endif // LIBMESH_ENABLE_AMR // Make sure we don't miscount above when adding the "magic" header // plus the real data header libmesh_assert_equal_to (in - original_in, header_size + 1); Elem *elem = mesh->query_elem(id); // if we already have this element, make sure its // properties match, and update any missing neighbor // links, but then go on if (elem) { libmesh_assert_equal_to (elem->level(), level); libmesh_assert_equal_to (elem->id(), id); //#ifdef LIBMESH_ENABLE_UNIQUE_ID // No check for unqiue id sanity //#endif libmesh_assert_equal_to (elem->processor_id(), processor_id); libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); libmesh_assert_equal_to (elem->type(), type); libmesh_assert_equal_to (elem->n_nodes(), n_nodes); #ifndef NDEBUG // All our nodes should be correct for (unsigned int i=0; i != n_nodes; ++i) libmesh_assert(elem->node(i) == static_cast<dof_id_type>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert_equal_to (elem->p_level(), p_level); libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); libmesh_assert (!level || elem->parent() != NULL); libmesh_assert (!level || elem->parent()->id() == parent_id); libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem); #endif // Our neighbor links should be "close to" correct - we may have // to update them, but we can check for some inconsistencies. for (unsigned int n=0; n != elem->n_neighbors(); ++n) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); // If the sending processor sees a domain boundary here, // we'd better agree. if (neighbor_id == DofObject::invalid_id) { libmesh_assert (!(elem->neighbor(n))); continue; } // If the sending processor has a remote_elem neighbor here, // then all we know is that we'd better *not* have a domain // boundary. if (neighbor_id == remote_elem->id()) { libmesh_assert(elem->neighbor(n)); continue; } Elem *neigh = mesh->query_elem(neighbor_id); // The sending processor sees a neighbor here, so if we // don't have that neighboring element, then we'd better // have a remote_elem signifying that fact. if (!neigh) { libmesh_assert_equal_to (elem->neighbor(n), remote_elem); continue; } // The sending processor has a neighbor here, and we have // that element, but that does *NOT* mean we're already // linking to it. Perhaps we initially received both elem // and neigh from processors on which their mutual link was // remote? libmesh_assert(elem->neighbor(n) == neigh || elem->neighbor(n) == remote_elem); // If the link was originally remote, we should update it, // and make sure the appropriate parts of its family link // back to us. if (elem->neighbor(n) == remote_elem) { elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } } // FIXME: We should add some debug mode tests to ensure that the // encoded indexing and boundary conditions are consistent. } else { // We don't already have the element, so we need to create it. // Find the parent if necessary Elem *parent = NULL; #ifdef LIBMESH_ENABLE_AMR // Find a child element's parent if (level > 0) { // Note that we must be very careful to construct the send // connectivity so that parents are encountered before // children. If we get here and can't find the parent that // is a fatal error. parent = mesh->elem(parent_id); } // Or assert that the sending processor sees no parent else libmesh_assert_equal_to (parent_id, static_cast<dof_id_type>(-1)); #else // No non-level-0 elements without AMR libmesh_assert_equal_to (level, 0); #endif elem = Elem::build(type,parent).release(); libmesh_assert (elem); #ifdef LIBMESH_ENABLE_AMR if (level != 0) { // Since this is a newly created element, the parent must // have previously thought of this child as a remote element. libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem); parent->add_child(elem, which_child_am_i); } // Assign the refinement flags and levels elem->set_p_level(p_level); elem->set_refinement_flag(refinement_flag); elem->set_p_refinement_flag(p_refinement_flag); libmesh_assert_equal_to (elem->level(), level); // If this element definitely should have children, assign // remote_elem to all of them for now, for consistency. Later // unpacked elements may overwrite that. if (!elem->active()) for (unsigned int c=0; c != elem->n_children(); ++c) elem->add_child(const_cast<RemoteElem*>(remote_elem), c); #endif // LIBMESH_ENABLE_AMR // Assign the IDs elem->subdomain_id() = subdomain_id; elem->processor_id() = processor_id; elem->set_id() = id; #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif // Assign the connectivity libmesh_assert_equal_to (elem->n_nodes(), n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (static_cast<dof_id_type>(*in++)); for (unsigned int n=0; n<elem->n_neighbors(); n++) { const dof_id_type neighbor_id = static_cast<dof_id_type>(*in++); if (neighbor_id == DofObject::invalid_id) continue; // We may be unpacking an element that was a ghost element on the // sender, in which case the element's neighbors may not all be // known by the packed element. We'll have to set such // neighbors to remote_elem ourselves and wait for a later // packed element to give us better information. if (neighbor_id == remote_elem->id()) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we don't have the neighbor element, then it's a // remote_elem until we get it. Elem *neigh = mesh->query_elem(neighbor_id); if (!neigh) { elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); continue; } // If we have the neighbor element, then link to it, and // make sure the appropriate parts of its family link back // to us. elem->set_neighbor(n, neigh); elem->make_links_to_me_local(n); } elem->unpack_indexing(in); } in += elem->packed_indexing_size(); // If this is a coarse element, // add any element side boundary condition ids if (level == 0) for (unsigned int s = 0; s != elem->n_sides(); ++s) { const int num_bcs = *in++; libmesh_assert_greater_equal (num_bcs, 0); for(int bc_it=0; bc_it < num_bcs; bc_it++) mesh->boundary_info->add_side (elem, s, *in++); } // Return the new element *out = elem; }
int main (int argc, char** argv){ LibMeshInit init (argc, argv); //initialize libmesh library std::cout << "Running " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; Mesh mesh(init.comm()); //T-channel //mesh.read("mesh.e"); //MeshRefinement meshRefinement(mesh); //meshRefinement.uniformly_refine(0); //1D - for debugging //int n = 20; //MeshTools::Generation::build_line(mesh, n, 0.0, 1.0, EDGE2); //n linear elements from 0 to 1 //nice geometry (straight channel) MeshTools::Generation::build_square (mesh, 250, 50, -0.0, 5.0, -0.0, 1.0, QUAD9); //read in subdomain assignments std::vector<double> prev_assign(mesh.n_elem(), 0.); std::string read_assign = "do_divvy.txt"; if(FILE *fp=fopen(read_assign.c_str(),"r")){ int flag = 1; int elemNum, assign; int ind = 0; while(flag != -1){ flag = fscanf(fp, "%d %d",&elemNum,&assign); if(flag != -1){ prev_assign[ind] = assign; ind += 1; } } fclose(fp); } //to stash subdomain assignments std::string stash_assign = "divvy.txt"; std::ofstream output(stash_assign.c_str()); MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it){ Elem* elem = *elem_it; Point c = elem->centroid(); //Point cshift1(c(0)-0.63, c(1)-0.5); elem->subdomain_id() = prev_assign[elem->id()]; //TEST/DEBUG //if(fabs(c(0)-3.0) < 0.35 && fabs(c(1)-0.5) < 0.35) // elem->subdomain_id() = 1; if(output.is_open()){ output << elem->id() << " " << elem->subdomain_id() << "\n"; } } output.close(); EquationSystems equation_systems (mesh); #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems("meep.exo",equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API return 0; } // end main
void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, const bool reset_current_list) { // We might actually want to run this on an empty mesh // (e.g. the boundary mesh for a nonexistant bcid!) // libmesh_assert_not_equal_to (this->n_nodes(), 0); // libmesh_assert_not_equal_to (this->n_elem(), 0); // This function must be run on all processors at once parallel_object_only(); LOG_SCOPE("find_neighbors()", "Mesh"); const element_iterator el_end = this->elements_end(); //TODO:[BSK] This should be removed later?! if (reset_current_list) for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * e = *el; for (unsigned int s=0; s<e->n_neighbors(); s++) if (e->neighbor_ptr(s) != remote_elem || reset_remote_elements) e->set_neighbor(s, libmesh_nullptr); } // Find neighboring elements by first finding elements // with identical side keys and then check to see if they // are neighbors { // data structures -- Use the hash_multimap if available typedef unsigned int key_type; typedef std::pair<Elem *, unsigned char> val_type; typedef std::pair<key_type, val_type> key_val_pair; typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; // A map from side keys to corresponding elements & side numbers map_type side_to_elem_map; for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * element = *el; for (unsigned char ms=0; ms<element->n_neighbors(); ms++) { next_side: // If we haven't yet found a neighbor on this side, try. // Even if we think our neighbor is remote, that // information may be out of date. if (element->neighbor_ptr(ms) == libmesh_nullptr || element->neighbor_ptr(ms) == remote_elem) { // Get the key for the side of this element const unsigned int key = element->key(ms); // Look for elements that have an identical side key std::pair <map_type::iterator, map_type::iterator> bounds = side_to_elem_map.equal_range(key); // May be multiple keys, check all the possible // elements which _might_ be neighbors. if (bounds.first != bounds.second) { // Get the side for this element const UniquePtr<Elem> my_side(element->side_ptr(ms)); // Look at all the entries with an equivalent key while (bounds.first != bounds.second) { // Get the potential element Elem * neighbor = bounds.first->second.first; // Get the side for the neighboring element const unsigned int ns = bounds.first->second.second; const UniquePtr<Elem> their_side(neighbor->side_ptr(ns)); //libmesh_assert(my_side.get()); //libmesh_assert(their_side.get()); // If found a match with my side // // We need special tests here for 1D: // since parents and children have an equal // side (i.e. a node), we need to check // ns != ms, and we also check level() to // avoid setting our neighbor pointer to // any of our neighbor's descendants if( (*my_side == *their_side) && (element->level() == neighbor->level()) && ((element->dim() != 1) || (ns != ms)) ) { // So share a side. Is this a mixed pair // of subactive and active/ancestor // elements? // If not, then we're neighbors. // If so, then the subactive's neighbor is if (element->subactive() == neighbor->subactive()) { // an element is only subactive if it has // been coarsened but not deleted element->set_neighbor (ms,neighbor); neighbor->set_neighbor(ns,element); } else if (element->subactive()) { element->set_neighbor(ms,neighbor); } else if (neighbor->subactive()) { neighbor->set_neighbor(ns,element); } side_to_elem_map.erase (bounds.first); // get out of this nested crap goto next_side; } ++bounds.first; } } // didn't find a match... // Build the map entry for this element key_val_pair kvp; kvp.first = key; kvp.second.first = element; kvp.second.second = ms; // use the lower bound as a hint for // where to put it. #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) side_to_elem_map.insert (kvp); #else side_to_elem_map.insert (bounds.first,kvp); #endif } } } } #ifdef LIBMESH_ENABLE_AMR /** * Here we look at all of the child elements which * don't already have valid neighbors. * * If a child element has a NULL neighbor it is * either because it is on the boundary or because * its neighbor is at a different level. In the * latter case we must get the neighbor from the * parent. * * If a child element has a remote_elem neighbor * on a boundary it shares with its parent, that * info may have become out-dated through coarsening * of the neighbor's parent. In this case, if the * parent's neighbor is active then the child should * share it. * * Furthermore, that neighbor better be active, * otherwise we missed a child somewhere. * * * We also need to look through children ordered by increasing * refinement level in order to add new interior_parent() links in * boundary elements which have just been generated by refinement, * and fix links in boundary elements whose previous * interior_parent() has just been coarsened away. */ const unsigned int n_levels = MeshTools::n_levels(*this); for (unsigned int level = 1; level < n_levels; ++level) { element_iterator end = this->level_elements_end(level); for (element_iterator el = this->level_elements_begin(level); el != end; ++el) { Elem * current_elem = *el; libmesh_assert(current_elem); Elem * parent = current_elem->parent(); libmesh_assert(parent); const unsigned int my_child_num = parent->which_child_am_i(current_elem); for (unsigned int s=0; s < current_elem->n_neighbors(); s++) { if (current_elem->neighbor_ptr(s) == libmesh_nullptr || (current_elem->neighbor_ptr(s) == remote_elem && parent->is_child_on_side(my_child_num, s))) { Elem * neigh = parent->neighbor_ptr(s); // If neigh was refined and had non-subactive children // made remote earlier, then a non-subactive elem should // actually have one of those remote children as a // neighbor if (neigh && (neigh->ancestor()) && (!current_elem->subactive())) { #ifdef DEBUG // Let's make sure that "had children made remote" // situation is actually the case libmesh_assert(neigh->has_children()); bool neigh_has_remote_children = false; for (unsigned int c = 0; c != neigh->n_children(); ++c) { if (neigh->child_ptr(c) == remote_elem) neigh_has_remote_children = true; } libmesh_assert(neigh_has_remote_children); // And let's double-check that we don't have // a remote_elem neighboring a local element libmesh_assert_not_equal_to (current_elem->processor_id(), this->processor_id()); #endif // DEBUG neigh = const_cast<RemoteElem *>(remote_elem); } if (!current_elem->subactive()) current_elem->set_neighbor(s, neigh); #ifdef DEBUG if (neigh != libmesh_nullptr && neigh != remote_elem) // We ignore subactive elements here because // we don't care about neighbors of subactive element. if ((!neigh->active()) && (!current_elem->subactive())) { libMesh::err << "On processor " << this->processor_id() << std::endl; libMesh::err << "Bad element ID = " << current_elem->id() << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl; libMesh::err << "Bad element proc_ID = " << current_elem->processor_id() << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl; libMesh::err << "Bad element size = " << current_elem->hmin() << ", Bad neighbor size = " << neigh->hmin() << std::endl; libMesh::err << "Bad element center = " << current_elem->centroid() << ", Bad neighbor center = " << neigh->centroid() << std::endl; libMesh::err << "ERROR: " << (current_elem->active()?"Active":"Ancestor") << " Element at level " << current_elem->level() << std::endl; libMesh::err << "with " << (parent->active()?"active": (parent->subactive()?"subactive":"ancestor")) << " parent share " << (neigh->subactive()?"subactive":"ancestor") << " neighbor at level " << neigh->level() << std::endl; NameBasedIO(*this).write ("bad_mesh.gmv"); libmesh_error_msg("Problematic mesh written to bad_mesh.gmv."); } #endif // DEBUG } } // We can skip to the next element if we're full-dimension // and therefore don't have any interior parents if (current_elem->dim() >= LIBMESH_DIM) continue; // We have no interior parents unless we can find one later current_elem->set_interior_parent(libmesh_nullptr); Elem * pip = parent->interior_parent(); if (!pip) continue; // If there's no interior_parent children, whether due to a // remote element or a non-conformity, then there's no // children to search. if (pip == remote_elem || pip->active()) { current_elem->set_interior_parent(pip); continue; } // For node comparisons we'll need a sensible tolerance Real node_tolerance = current_elem->hmin() * TOLERANCE; // Otherwise our interior_parent should be a child of our // parent's interior_parent. for (unsigned int c=0; c != pip->n_children(); ++c) { Elem * child = pip->child_ptr(c); // If we have a remote_elem, that might be our // interior_parent. We'll set it provisionally now and // keep trying to find something better. if (child == remote_elem) { current_elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); continue; } bool child_contains_our_nodes = true; for (unsigned int n=0; n != current_elem->n_nodes(); ++n) { bool child_contains_this_node = false; for (unsigned int cn=0; cn != child->n_nodes(); ++cn) if (child->point(cn).absolute_fuzzy_equals (current_elem->point(n), node_tolerance)) { child_contains_this_node = true; break; } if (!child_contains_this_node) { child_contains_our_nodes = false; break; } } if (child_contains_our_nodes) { current_elem->set_interior_parent(child); break; } } // We should have found *some* interior_parent at this // point, whether semilocal or remote. libmesh_assert(current_elem->interior_parent()); } } #endif // AMR #ifdef DEBUG MeshTools::libmesh_assert_valid_neighbors(*this, !reset_remote_elements); MeshTools::libmesh_assert_valid_amr_interior_parents(*this); #endif }