void VTKIO::read (const std::string& name) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); // Keep track of what kinds of elements this file contains elems_of_dimension.clear(); elems_of_dimension.resize(4, false); #ifndef LIBMESH_HAVE_VTK libMesh::err << "Cannot read VTK file: " << name << "\nYou must have VTK installed and correctly configured to read VTK meshes." << std::endl; libmesh_error(); #else // Use a typedef, because these names are just crazy typedef vtkSmartPointer<vtkXMLUnstructuredGridReader> MyReader; MyReader reader = MyReader::New(); // Pass the filename along to the reader reader->SetFileName( name.c_str() ); // Force reading reader->Update(); // read in the grid _vtk_grid = reader->GetOutput(); // _vtk_grid->Update(); // FIXME: Necessary? // Get a reference to the mesh MeshBase& mesh = MeshInput<MeshBase>::mesh(); // Clear out any pre-existing data from the Mesh mesh.clear(); // Get the number of points from the _vtk_grid object const unsigned int vtk_num_points = static_cast<unsigned int>(_vtk_grid->GetNumberOfPoints()); // always numbered nicely??, so we can loop like this // I'm pretty sure it is numbered nicely for (unsigned int i=0; i<vtk_num_points; ++i) { // add to the id map // and add the actual point double * pnt = _vtk_grid->GetPoint(static_cast<vtkIdType>(i)); Point xyz(pnt[0], pnt[1], pnt[2]); Node* newnode = mesh.add_point(xyz, i); // Add node to the nodes vector & // tell the MeshData object the foreign node id. if (this->_mesh_data != NULL) this->_mesh_data->add_foreign_node_id (newnode, i); } // Get the number of cells from the _vtk_grid object const unsigned int vtk_num_cells = static_cast<unsigned int>(_vtk_grid->GetNumberOfCells()); for (unsigned int i=0; i<vtk_num_cells; ++i) { vtkCell* cell = _vtk_grid->GetCell(i); Elem* elem = NULL; switch (cell->GetCellType()) { case VTK_LINE: elem = new Edge2; break; case VTK_QUADRATIC_EDGE: elem = new Edge3; break; case VTK_TRIANGLE: elem = new Tri3(); break; case VTK_QUADRATIC_TRIANGLE: elem = new Tri6(); break; case VTK_QUAD: elem = new Quad4(); break; case VTK_QUADRATIC_QUAD: elem = new Quad8(); break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUAD: elem = new Quad9(); break; #endif case VTK_TETRA: elem = new Tet4(); break; case VTK_QUADRATIC_TETRA: elem = new Tet10(); break; case VTK_WEDGE: elem = new Prism6(); break; case VTK_QUADRATIC_WEDGE: elem = new Prism15(); break; case VTK_BIQUADRATIC_QUADRATIC_WEDGE: elem = new Prism18(); break; case VTK_HEXAHEDRON: elem = new Hex8(); break; case VTK_QUADRATIC_HEXAHEDRON: elem = new Hex20(); break; case VTK_TRIQUADRATIC_HEXAHEDRON: elem = new Hex27(); break; case VTK_PYRAMID: elem = new Pyramid5(); break; default: libMesh::err << "element type not implemented in vtkinterface " << cell->GetCellType() << std::endl; libmesh_error(); break; } // get the straightforward numbering from the VTK cells for (unsigned int j=0; j<elem->n_nodes(); ++j) elem->set_node(j) = mesh.node_ptr(cell->GetPointId(j)); // then get the connectivity std::vector<dof_id_type> conn; elem->connectivity(0, VTK, conn); // then reshuffle the nodes according to the connectivity, this // two-time-assign would evade the definition of the vtk_mapping for (unsigned int j=0; j<conn.size(); ++j) elem->set_node(j) = mesh.node_ptr(conn[j]); elem->set_id(i); elems_of_dimension[elem->dim()] = true; mesh.add_elem(elem); } // end loop over VTK cells // 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); #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 // LIBMESH_HAVE_VTK }
void CombinedCreepPlasticity::computeStress( const Elem & current_elem, unsigned qp, const SymmElasticityTensor & elasticityTensor, const SymmTensor & stress_old, SymmTensor & strain_increment, SymmTensor & stress_new ) { // Given the stretching, compute the stress increment and add it to the old stress. Also update the creep strain // stress = stressOld + stressIncrement // creep_strain = creep_strainOld + creep_strainIncrement if(_t_step == 0) return; if (_output_iteration_info == true) { Moose::out << std::endl << "iteration output for CombinedCreepPlasticity solve:" << " time=" <<_t << " temperature=" << _temperature[qp] << " int_pt=" << qp << std::endl; } // compute trial stress stress_new = elasticityTensor * strain_increment; stress_new += stress_old; const SubdomainID current_block = current_elem.subdomain_id(); const std::vector<ReturnMappingModel*> & rmm( _submodels[current_block] ); const unsigned num_submodels = rmm.size(); SymmTensor inelastic_strain_increment; SymmTensor elastic_strain_increment; SymmTensor stress_new_last( stress_new ); Real delS(_absolute_tolerance+1); Real first_delS(delS); unsigned int counter(0); while(counter < _max_its && delS > _absolute_tolerance && (delS/first_delS) > _relative_tolerance && (num_submodels != 1 || counter < 1)) { elastic_strain_increment = strain_increment; stress_new = elasticityTensor * (elastic_strain_increment - inelastic_strain_increment); stress_new += stress_old; for (unsigned i_rmm(0); i_rmm < num_submodels; ++i_rmm) { rmm[i_rmm]->computeStress( current_elem, qp, elasticityTensor, stress_old, elastic_strain_increment, stress_new, inelastic_strain_increment ); } // now check convergence SymmTensor deltaS(stress_new_last - stress_new); delS = std::sqrt(deltaS.doubleContraction(deltaS)); if (counter == 0) { first_delS = delS; } stress_new_last = stress_new; if (_output_iteration_info == true) { Moose::out << "stress_it=" << counter << " rel_delS=" << (0 == first_delS ? 0 : delS/first_delS) << " rel_tol=" << _relative_tolerance << " abs_delS=" << delS << " abs_tol=" << _absolute_tolerance << std::endl; } ++counter; } if(counter == _max_its && delS > _absolute_tolerance && (delS/first_delS) > _relative_tolerance) { mooseError("Max stress iteration hit during CombinedCreepPlasticity solve!"); } strain_increment = elastic_strain_increment; }
bool MeshRefinement::eliminate_unrefined_patches () { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; 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; // First assume that we'll have to flag this element for both h // and p refinement, then change our minds if we see any // neighbors that are as coarse or coarser than us. bool h_flag_me = true, p_flag_me = true; // Skip the element if it is already fully flagged for refinement if (elem->p_refinement_flag() == Elem::REFINE) p_flag_me = false; if (elem->refinement_flag() == Elem::REFINE) { h_flag_me = false; if (!p_flag_me) continue; } // Test the parent if that is already flagged for coarsening else if (elem->refinement_flag() == Elem::COARSEN) { libmesh_assert(elem->parent()); elem = elem->parent(); // FIXME - this doesn't seem right - RHS if (elem->refinement_flag() != Elem::COARSEN_INACTIVE) continue; p_flag_me = false; } const unsigned int my_level = elem->level(); int my_p_adjustment = 0; if (elem->p_refinement_flag() == Elem::REFINE) my_p_adjustment = 1; else if (elem->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (elem->p_level(), 0); my_p_adjustment = -1; } const unsigned int my_new_p_level = elem->p_level() + my_p_adjustment; // Check all the element neighbors for (unsigned int n=0; n<elem->n_neighbors(); n++) { const Elem *neighbor = elem->neighbor(n); // Quit if the element is on a local boundary if (neighbor == NULL || neighbor == remote_elem) { h_flag_me = false; p_flag_me = false; break; } // if the neighbor will be equally or less refined than // we are, then we will not become an unrefined island. // So if we are still considering h refinement: if (h_flag_me && // If our neighbor is already at a lower level, // it can't end up at a higher level even if it // is flagged for refinement once ((neighbor->level() < my_level) || // If our neighbor is at the same level but isn't // flagged for refinement, it won't end up at a // higher level ((neighbor->active()) && (neighbor->refinement_flag() != Elem::REFINE)) || // If our neighbor is currently more refined but is // a parent flagged for coarsening, it will end up // at the same level. (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE))) { // We've proven we won't become an unrefined island, // so don't h refine to avoid that. h_flag_me = false; // If we've also proven we don't need to p refine, // we don't need to check more neighbors if (!p_flag_me) break; } if (p_flag_me) { // if active neighbors will have a p level // equal to or lower than ours, then we do not need to p // refine ourselves. if (neighbor->active()) { int p_adjustment = 0; if (neighbor->p_refinement_flag() == Elem::REFINE) p_adjustment = 1; else if (neighbor->p_refinement_flag() == Elem::COARSEN) { libmesh_assert_greater (neighbor->p_level(), 0); p_adjustment = -1; } if (my_new_p_level >= neighbor->p_level() + p_adjustment) { p_flag_me = false; if (!h_flag_me) break; } } // If we have inactive neighbors, we need to // test all their active descendants which neighbor us else if (neighbor->ancestor()) { if (neighbor->min_new_p_level_by_neighbor(elem, my_new_p_level + 2) <= my_new_p_level) { p_flag_me = false; if (!h_flag_me) break; } } } } if (h_flag_me) { // Parents that would create islands should no longer // coarsen if (elem->refinement_flag() == Elem::COARSEN_INACTIVE) { for (unsigned int c=0; c<elem->n_children(); c++) { libmesh_assert_equal_to (elem->child(c)->refinement_flag(), Elem::COARSEN); elem->child(c)->set_refinement_flag(Elem::DO_NOTHING); } elem->set_refinement_flag(Elem::INACTIVE); } else elem->set_refinement_flag(Elem::REFINE); flags_changed = true; } if (p_flag_me) { if (elem->p_refinement_flag() == Elem::COARSEN) elem->set_p_refinement_flag(Elem::DO_NOTHING); else elem->set_p_refinement_flag(Elem::REFINE); flags_changed = true; } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
void MeshBase::detect_interior_parents() { // This requires an inspection on every processor parallel_object_only(); // Check if the mesh contains mixed dimensions. If so, then set interior parents, otherwise return. if (this->elem_dimensions().size() == 1) return; //This map will be used to set interior parents LIBMESH_BEST_UNORDERED_MAP<dof_id_type, std::vector<dof_id_type> > node_to_elem; const_element_iterator el = this->active_elements_begin(); const_element_iterator end = this->active_elements_end(); for (; el!=end; ++el) { const Elem * elem = *el; // Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map for (unsigned int n=0; n<elem->n_vertices(); n++) { libmesh_assert_less (elem->id(), this->max_elem_id()); node_to_elem[elem->node(n)].push_back(elem->id()); } } // Automatically set interior parents el = this->elements_begin(); for (; el!=end; ++el) { Elem * element = *el; // Ignore an 3D element or an element that already has an interior parent if (element->dim()>=LIBMESH_DIM || element->interior_parent()) continue; // Start by generating a SET of elements that are dim+1 to the current // element at each vertex of the current element, thus ignoring interior nodes. // If one of the SET of elements is empty, then we will not have an interior parent // since an interior parent must be connected to all vertices of the current element std::vector< std::set<dof_id_type> > neighbors( element->n_vertices() ); bool found_interior_parents = false; for (dof_id_type n=0; n < element->n_vertices(); n++) { std::vector<dof_id_type> & element_ids = node_to_elem[element->node(n)]; for (std::vector<dof_id_type>::iterator e_it = element_ids.begin(); e_it != element_ids.end(); e_it++) { dof_id_type eid = *e_it; if (this->elem(eid)->dim() == element->dim()+1) neighbors[n].insert(eid); } if (neighbors[n].size()>0) { found_interior_parents = true; } else { // We have found an empty set, no reason to continue // Ensure we set this flag to false before the break since it could have // been set to true for previous vertex found_interior_parents = false; break; } } // If we have successfully generated a set of elements for each vertex, we will compare // the set for vertex 0 will the sets for the vertices until we find a id that exists in // all sets. If found, this is our an interior parent id. The interior parent id found // will be the lowest element id if there is potential for multiple interior parents. if (found_interior_parents) { std::set<dof_id_type> & neighbors_0 = neighbors[0]; for (std::set<dof_id_type>::iterator e_it = neighbors_0.begin(); e_it != neighbors_0.end(); e_it++) { found_interior_parents=false; dof_id_type interior_parent_id = *e_it; for (dof_id_type n=1; n < element->n_vertices(); n++) { if (neighbors[n].find(interior_parent_id)!=neighbors[n].end()) { found_interior_parents=true; } else { found_interior_parents=false; break; } } if (found_interior_parents) { element->set_interior_parent(this->elem(interior_parent_id)); break; } } } } }
void Elem::coarsen() { libmesh_assert_equal_to (this->refinement_flag(), Elem::COARSEN_INACTIVE); libmesh_assert (!this->active()); // We no longer delete children until MeshRefinement::contract() // delete [] _children; // _children = NULL; unsigned int parent_p_level = 0; // re-compute hanging node nodal locations for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; for (unsigned int nc=0; nc<mychild->n_nodes(); nc++) { Point new_pos; bool calculated_new_pos = false; for (unsigned int n=0; n<this->n_nodes(); n++) { // The value from the embedding matrix const float em_val = this->embedding_matrix(c,nc,n); // The node location is somewhere between existing vertices if ((em_val != 0.) && (em_val != 1.)) { new_pos.add_scaled (this->point(n), em_val); calculated_new_pos = true; } } if(calculated_new_pos) { //Move the existing node back into it's original location for(unsigned int i=0; i<LIBMESH_DIM; i++) { Point & child_node = *(mychild->get_node(nc)); child_node(i)=new_pos(i); } } } } for (unsigned int c=0; c<this->n_children(); c++) { Elem *mychild = this->child(c); if (mychild == remote_elem) continue; libmesh_assert_equal_to (mychild->refinement_flag(), Elem::COARSEN); mychild->set_refinement_flag(Elem::INACTIVE); if (mychild->p_level() > parent_p_level) parent_p_level = mychild->p_level(); } this->set_refinement_flag(Elem::JUST_COARSENED); this->set_p_level(parent_p_level); libmesh_assert (this->active()); }
// ------------------------------------------------------------ // MetisPartitioner implementation void MetisPartitioner::_do_partition (MeshBase& mesh, const unsigned int n_pieces) { libmesh_assert_greater (n_pieces, 0); libmesh_assert (mesh.is_serial()); // Check for an easy return if (n_pieces == 1) { this->single_partition (mesh); 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 (mesh, n_pieces); // What to do if the Metis library IS present #else START_LOG("partition()", "MetisPartitioner"); const dof_id_type n_active_elem = mesh.n_active_elem(); // build the graph // std::vector<int> options(5); std::vector<int> vwgt(n_active_elem); std::vector<int> part(n_active_elem); int n = static_cast<int>(n_active_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<int>(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 // Metis will only consider the active elements. // We need to map the active element ids into a // contiguous range. Further, we want the unique range indexing to be // independednt of the element ordering, otherwise a circular dependency // can result in which the partitioning depends on the ordering which // depends on the partitioning... std::map<const Elem*, dof_id_type> global_index_map; { std::vector<dof_id_type> global_index; MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); MeshCommunication().find_global_indices (MeshTools::bounding_box(mesh), it, end, global_index); libmesh_assert_equal_to (global_index.size(), n_active_elem); for (std::size_t cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!global_index_map.count(elem)); global_index_map[elem] = global_index[cnt++]; } libmesh_assert_equal_to (global_index_map.size(), n_active_elem); } // build the graph in CSR format. Note that // the edges in the graph will correspond to // face neighbors std::vector<int> xadj, adjncy; { std::vector<const Elem*> neighbors_offspring; MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); // This will be exact when there is no refinement and all the // elements are of the same type. std::size_t graph_size=0; std::vector<std::vector<dof_id_type> > graph(n_active_elem); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; libmesh_assert (global_index_map.count(elem)); const dof_id_type elem_global_index = global_index_map[elem]; libmesh_assert_less (elem_global_index, vwgt.size()); libmesh_assert_less (elem_global_index, graph.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<int>((*_weights)[elem->id()]); // 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 != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) { libmesh_assert (global_index_map.count(neighbor)); const dof_id_type neighbor_global_index = global_index_map[neighbor]; graph[elem_global_index].push_back(neighbor_global_index); 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. 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_map.count(child)); const dof_id_type child_global_index = global_index_map[child]; graph[elem_global_index].push_back(child_global_index); graph_size++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } } // Convert the graph into the format Metis wants xadj.reserve(n_active_elem+1); adjncy.reserve(graph_size); for (std::size_t r=0; r<graph.size(); r++) { xadj.push_back(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 adjncy.insert(adjncy.end(), graph_row.begin(), graph_row.end()); } // The end of the adjacency array for the last elem xadj.push_back(adjncy.size()); libmesh_assert_equal_to (adjncy.size(), graph_size); libmesh_assert_equal_to (xadj.size(), n_active_elem+1); } // done building the graph if (adjncy.empty()) adjncy.push_back(0); int 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, &xadj[0], &adjncy[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); // Otherwise use kway else Metis::METIS_PartGraphKway(&n, &ncon, &xadj[0], &adjncy[0], &vwgt[0], NULL, NULL, &nparts, NULL, NULL, NULL, &edgecut, &part[0]); // 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 = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for (; it!=end; ++it) { Elem* elem = *it; libmesh_assert (global_index_map.count(elem)); const dof_id_type elem_global_index = global_index_map[elem]; 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; } } STOP_LOG("partition()", "MetisPartitioner"); #endif }
void MultiAppUserObjectTransfer::execute() { _console << "Beginning MultiAppUserObjectTransfer " << name() << std::endl; switch (_direction) { case TO_MULTIAPP: { for (unsigned int i=0; i<_multi_app->numGlobalApps(); i++) { if (_multi_app->hasLocalApp(i)) { 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); 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; const UserObject & user_object = _multi_app->problem()->getUserObjectBase(_user_object_name); 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; 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 from_value = user_object.spatialValue(*node+_multi_app->position(i)); // 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(); 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 from_value = user_object.spatialValue(centroid+_multi_app->position(i)); // Swap again swapped = Moose::swapLibMeshComm(_multi_app->comm()); solution.set(dof, from_value); } } } solution.close(); to_sys->update(); // Swap back Moose::swapLibMeshComm(swapped); } } 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(); unsigned int to_sys_num = to_sys.number(); // Only works with a serialized mesh to transfer to! mooseAssert(to_sys.get_mesh().is_serial(), "MultiAppUserObjectTransfer only works with SerialMesh!"); unsigned int to_var_num = to_sys.variable_number(to_var.name()); _console << "Transferring to: " << to_var.name() << std::endl; // EquationSystems & to_es = to_sys.get_equation_systems(); //Create a serialized version of the solution vector NumericVector<Number> * to_solution = to_sys.solution.get(); MeshBase * to_mesh = NULL; if (_displaced_target_mesh && to_problem.getDisplacedProblem()) to_mesh = &to_problem.getDisplacedProblem()->mesh().getMesh(); else to_mesh = &to_problem.mesh().getMesh(); bool is_nodal = to_sys.variable_type(to_var_num).family == LAGRANGE; for (unsigned int i=0; i<_multi_app->numGlobalApps(); i++) { if (!_multi_app->hasLocalApp(i)) continue; Point app_position = _multi_app->position(i); MeshTools::BoundingBox app_box = _multi_app->getBoundingBox(i); const UserObject & user_object = _multi_app->appUserObjectBase(i, _user_object_name); if (is_nodal) { MeshBase::const_node_iterator node_it = to_mesh->nodes_begin(); MeshBase::const_node_iterator node_end = to_mesh->nodes_end(); for (; node_it != node_end; ++node_it) { Node * node = *node_it; if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node { // See if this node falls in this bounding box if (app_box.contains_point(*node)) { dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0); MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); Real from_value = user_object.spatialValue(*node-app_position); Moose::swapLibMeshComm(swapped); to_solution->set(dof, from_value); } } } } else // Elemental { MeshBase::const_element_iterator elem_it = to_mesh->elements_begin(); MeshBase::const_element_iterator elem_end = to_mesh->elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; if (elem->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this elem { Point centroid = elem->centroid(); // See if this elem falls in this bounding box if (app_box.contains_point(centroid)) { dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, 0); MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); Real from_value = user_object.spatialValue(centroid-app_position); Moose::swapLibMeshComm(swapped); to_solution->set(dof, from_value); } } } } } to_solution->close(); to_sys.update(); break; } } _console << "Finished MultiAppUserObjectTransfer " << name() << std::endl; }
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_object_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 dof_id_type n_active_elem = _mesh.n_elem(); // The number of elements to flag for coarsening const dof_id_type n_elem_coarsen = static_cast<dof_id_type>(_coarsen_fraction * n_active_elem); // The number of elements to flag for refinement const dof_id_type n_elem_refine = static_cast<dof_id_type>(_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<ErrorVectorReal> 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()]); this->comm().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()); } ErrorVectorReal 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; dof_id_type 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 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 dof_id_type id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const ErrorVectorReal 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); } }
bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector& error_per_cell) { parallel_object_only(); // 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); // This function is currently only coded to work when coarsening by // parents - it's too hard to guess how many coarsenings will be // performed otherwise. libmesh_assert (_coarsen_by_parents); // The number of active elements in the mesh - hopefully less than // 2 billion on 32 bit machines const dof_id_type n_active_elem = _mesh.n_active_elem(); // The maximum number of active elements to flag for coarsening const dof_id_type max_elem_coarsen = static_cast<dof_id_type>(_coarsen_fraction * n_active_elem) + 1; // The maximum number of elements to flag for refinement const dof_id_type max_elem_refine = static_cast<dof_id_type>(_refine_fraction * n_active_elem) + 1; // Clean up the refinement flags. These could be left // over from previous refinement steps. this->clean_refinement_flags(); // The target number of elements to add or remove const std::ptrdiff_t n_elem_new = _nelem_target - n_active_elem; // Create an vector with active element errors and ids, // sorted by highest errors first const dof_id_type max_elem_id = _mesh.max_elem_id(); std::vector<std::pair<ErrorVectorReal, dof_id_type> > sorted_error; sorted_error.reserve (n_active_elem); // On a ParallelMesh, we need to communicate to know which remote ids // correspond to active elements. { std::vector<bool> is_active(max_elem_id, false); 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) { const dof_id_type eid = (*elem_it)->id(); is_active[eid] = true; libmesh_assert_less (eid, error_per_cell.size()); sorted_error.push_back (std::make_pair(error_per_cell[eid], eid)); } this->comm().max(is_active); this->comm().allgather(sorted_error); } // Default sort works since pairs are sorted lexicographically std::sort (sorted_error.begin(), sorted_error.end()); std::reverse (sorted_error.begin(), sorted_error.end()); // Create a sorted error vector with coarsenable parent elements // only, sorted by lowest errors first ErrorVector error_per_parent; std::vector<std::pair<ErrorVectorReal, dof_id_type> > sorted_parent_error; Real parent_error_min, parent_error_max; create_parent_error_vector(error_per_cell, error_per_parent, parent_error_min, parent_error_max); // create_parent_error_vector sets values for non-parents and // non-coarsenable parents to -1. Get rid of them. for (dof_id_type i=0; i != error_per_parent.size(); ++i) if (error_per_parent[i] != -1) sorted_parent_error.push_back(std::make_pair(error_per_parent[i], i)); std::sort (sorted_parent_error.begin(), sorted_parent_error.end()); // Keep track of how many elements we plan to coarsen & refine dof_id_type coarsen_count = 0; dof_id_type refine_count = 0; const unsigned int dim = _mesh.mesh_dimension(); unsigned int twotodim = 1; for (unsigned int i=0; i!=dim; ++i) twotodim *= 2; // First, let's try to get our element count to target_nelem if (n_elem_new >= 0) { // Every element refinement creates at least // 2^dim-1 new elements refine_count = std::min(libmesh_cast_int<dof_id_type>(n_elem_new / (twotodim-1)), max_elem_refine); } else { // Every successful element coarsening is likely to destroy // 2^dim-1 net elements. coarsen_count = std::min(libmesh_cast_int<dof_id_type>(-n_elem_new / (twotodim-1)), max_elem_coarsen); } // Next, let's see if we can trade any refinement for coarsening while (coarsen_count < max_elem_coarsen && refine_count < max_elem_refine && coarsen_count < sorted_parent_error.size() && refine_count < sorted_error.size() && sorted_error[refine_count].first > sorted_parent_error[coarsen_count].first * _coarsen_threshold) { coarsen_count++; refine_count++; } // On a ParallelMesh, we need to communicate to know which remote ids // correspond to refinable elements dof_id_type successful_refine_count = 0; { std::vector<bool> is_refinable(max_elem_id, false); for (dof_id_type i=0; i != sorted_error.size(); ++i) { dof_id_type eid = sorted_error[i].second; Elem *elem = _mesh.query_elem(eid); if (elem && elem->level() < _max_h_level) is_refinable[eid] = true; } this->comm().max(is_refinable); if (refine_count > max_elem_refine) refine_count = max_elem_refine; for (dof_id_type i=0; i != sorted_error.size(); ++i) { if (successful_refine_count >= refine_count) break; dof_id_type eid = sorted_error[i].second; Elem *elem = _mesh.query_elem(eid); if (is_refinable[eid]) { if (elem) elem->set_refinement_flag(Elem::REFINE); successful_refine_count++; } } } // If we couldn't refine enough elements, don't coarsen too many // either if (coarsen_count < (refine_count - successful_refine_count)) coarsen_count = 0; else coarsen_count -= (refine_count - successful_refine_count); if (coarsen_count > max_elem_coarsen) coarsen_count = max_elem_coarsen; dof_id_type successful_coarsen_count = 0; if (coarsen_count) { for (dof_id_type i=0; i != sorted_parent_error.size(); ++i) { if (successful_coarsen_count >= coarsen_count * twotodim) break; dof_id_type parent_id = sorted_parent_error[i].second; Elem *parent = _mesh.query_elem(parent_id); // On a ParallelMesh we skip remote elements if (!parent) continue; libmesh_assert(parent->has_children()); for (unsigned int c=0; c != parent->n_children(); ++c) { Elem *elem = parent->child(c); if (elem && elem != remote_elem) { libmesh_assert(elem->active()); elem->set_refinement_flag(Elem::COARSEN); successful_coarsen_count++; } } } } // Return true if we've done all the AMR/C we can if (!successful_coarsen_count && !successful_refine_count) return true; // And false if there may still be more to do. return false; }
//----------------------------------------------------------------- // 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_object_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 dof_id_type 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]); } this->comm().max(error_max); this->comm().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 dof_id_type id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const ErrorVectorReal elem_error = error_per_cell[id]; if (_coarsen_by_parents) { Elem* parent = elem->parent(); if (parent) { const dof_id_type 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_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); } 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; 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); } } } }
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 }
// ------------------------------------------------------------ // SFCPartitioner implementation void SFCPartitioner::_do_partition (MeshBase& mesh, const unsigned int n) { libmesh_assert_greater (n, 0); // Check for an easy return if (n == 1) { this->single_partition (mesh); return; } // What to do if the sfcurves library IS NOT present #ifndef LIBMESH_HAVE_SFCURVES libmesh_here(); libMesh::err << "ERROR: The library has been built without" << std::endl << "Space Filling Curve support. Using a linear" << std::endl << "partitioner instead!" << std::endl; LinearPartitioner lp; lp.partition (mesh, n); // What to do if the sfcurves library IS present #else START_LOG("sfc_partition()", "SFCPartitioner"); const unsigned int n_active_elem = mesh.n_active_elem(); const unsigned int n_elem = mesh.n_elem(); // the forward_map maps the active element id // into a contiguous block of indices std::vector<unsigned int> forward_map (n_elem, libMesh::invalid_uint); // the reverse_map maps the contiguous ids back // to active elements std::vector<Elem*> reverse_map (n_active_elem, NULL); int size = static_cast<int>(n_active_elem); std::vector<double> x (size); std::vector<double> y (size); std::vector<double> z (size); std::vector<int> table (size); // We need to map the active element ids into a // contiguous range. { // active_elem_iterator elem_it (mesh.elements_begin()); // const active_elem_iterator elem_end(mesh.elements_end()); MeshBase::element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::element_iterator elem_end = mesh.active_elements_end(); unsigned int el_num = 0; for (; elem_it != elem_end; ++elem_it) { libmesh_assert_less ((*elem_it)->id(), forward_map.size()); libmesh_assert_less (el_num, reverse_map.size()); forward_map[(*elem_it)->id()] = el_num; reverse_map[el_num] = *elem_it; el_num++; } libmesh_assert_equal_to (el_num, n_active_elem); } // Get the centroid for each active element { // const_active_elem_iterator elem_it (mesh.const_elements_begin()); // const const_active_elem_iterator elem_end(mesh.const_elements_end()); 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) { const Elem* elem = *elem_it; libmesh_assert_less (elem->id(), forward_map.size()); const Point p = elem->centroid(); x[forward_map[elem->id()]] = p(0); y[forward_map[elem->id()]] = p(1); z[forward_map[elem->id()]] = p(2); } } // build the space-filling curve if (_sfc_type == "Hilbert") Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]); else if (_sfc_type == "Morton") Sfc::morton (&x[0], &y[0], &z[0], &size, &table[0]); else { libmesh_here(); libMesh::err << "ERROR: Unknown type: " << _sfc_type << std::endl << " Valid types are" << std::endl << " \"Hilbert\"" << std::endl << " \"Morton\"" << std::endl << " " << std::endl << "Proceeding with a Hilbert curve." << std::endl; Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]); } // Assign the partitioning to the active elements { // { // std::ofstream out ("sfc.dat"); // out << "variables=x,y,z" << std::endl; // out << "zone f=point" << std::endl; // for (unsigned int i=0; i<n_active_elem; i++) // out << x[i] << " " // << y[i] << " " // << z[i] << std::endl; // } const unsigned int blksize = (n_active_elem+n-1)/n; for (unsigned int i=0; i<n_active_elem; i++) { libmesh_assert_less (static_cast<unsigned int>(table[i]-1), reverse_map.size()); Elem* elem = reverse_map[table[i]-1]; elem->processor_id() = i/blksize; } } STOP_LOG("sfc_partition()", "SFCPartitioner"); #endif }
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 = _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, _part.size()); libmesh_assert_less (local_index, mesh.n_active_local_elem()); const unsigned int elem_procid = static_cast<unsigned int>(_part[local_index]); libmesh_assert_less (elem_procid, static_cast<unsigned int>(_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>(_nparts)); elem->processor_id() = elem_procid; } }
// Begin the main program. int main (int argc, char ** argv) { // Initialize libMesh and any dependent libaries, like in example 2. LibMeshInit init (argc, argv); // Declare a performance log for the main program // PerfLog perf_main("Main Program"); // Create a GetPot object to parse the command line GetPot command_line (argc, argv); // Check for proper calling arguments. if (argc < 3) { // This handy function will print the file name, line number, // specified message, and then throw an exception. libmesh_error_msg("Usage:\n" << "\t " << argv[0] << " -d 2(3)" << " -n 15"); } // Brief message to the user regarding the program name // and command line arguments. else { libMesh::out << "Running " << argv[0]; for (int i=1; i<argc; i++) libMesh::out << " " << argv[i]; libMesh::out << std::endl << std::endl; } // Read problem dimension from command line. Use int // instead of unsigned since the GetPot overload is ambiguous // otherwise. int dim = 2; if (command_line.search(1, "-d")) dim = command_line.next(dim); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support"); // Create a mesh with user-defined dimension on the default MPI // communicator. Mesh mesh (init.comm(), dim); // Read number of elements from command line int ps = 15; if (command_line.search(1, "-n")) ps = command_line.next(ps); // Read FE order from command line std::string order = "SECOND"; if (command_line.search(2, "-Order", "-o")) order = command_line.next(order); // Read FE Family from command line std::string family = "LAGRANGE"; if (command_line.search(2, "-FEFamily", "-f")) family = command_line.next(family); // Cannot use discontinuous basis. if ((family == "MONOMIAL") || (family == "XYZ")) { if (mesh.processor_id() == 0) libmesh_error_msg("This example requires a C^0 (or higher) FE basis."); } // Use the MeshTools::Generation mesh generator to create a uniform // grid on the square [-1,1]^D. We instruct the mesh generator // to build a mesh of 8x8 Quad9 elements in 2D, or Hex27 // elements in 3D. Building these higher-order elements allows // us to use higher-order approximation, as in example 3. Real halfwidth = dim > 1 ? 1. : 0.; Real halfheight = dim > 2 ? 1. : 0.; if ((family == "LAGRANGE") && (order == "FIRST")) { // No reason to use high-order geometric elements if we are // solving with low-order finite elements. MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE2 : ((dim == 2) ? QUAD4 : HEX8)); } else { MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE3 : ((dim == 2) ? QUAD9 : HEX27)); } { MeshBase::element_iterator el = mesh.elements_begin(); const MeshBase::element_iterator end_el = mesh.elements_end(); for ( ; el != end_el; ++el) { Elem * elem = *el; const Point cent = elem->centroid(); if (dim > 1) { if ((cent(0) > 0) == (cent(1) > 0)) elem->subdomain_id() = 1; } else { if (cent(0) > 0) elem->subdomain_id() = 1; } } } // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Poisson" LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Poisson"); std::set<subdomain_id_type> active_subdomains; // Add the variable "u" to "Poisson". "u" // will be approximated using second-order approximation. active_subdomains.clear(); active_subdomains.insert(0); system.add_variable("u", Utility::string_to_enum<Order> (order), Utility::string_to_enum<FEFamily>(family), &active_subdomains); // Add the variable "v" to "Poisson". "v" // will be approximated using second-order approximation. active_subdomains.clear(); active_subdomains.insert(1); system.add_variable("v", Utility::string_to_enum<Order> (order), Utility::string_to_enum<FEFamily>(family), &active_subdomains); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_poisson); // Initialize the data structures for the equation system. equation_systems.init(); // Print information about the system to the screen. equation_systems.print_info(); mesh.print_info(); // Solve the system "Poisson", just like example 2. equation_systems.get_system("Poisson").solve(); // After solving the system write the solution // to a GMV-formatted plot file. if (dim == 1) { GnuPlotIO plot(mesh, "Subdomains Example 2, 1D", GnuPlotIO::GRID_ON); plot.write_equation_systems("gnuplot_script", equation_systems); } else { #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems ((dim == 3) ? "out_3.e" : "out_2.e", equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; }
void FeatureFloodCount::FeatureData::updateBBoxExtremes(MeshTools::BoundingBox & bbox, const Elem & elem) { for (auto node_n = decltype(elem.n_nodes())(0); node_n < elem.n_nodes(); ++node_n) updateBBoxExtremes(bbox, *(elem.get_node(node_n))); }
int main(int argc, char** argv) { LibMeshInit init(argc, argv); GetPot cl(argc, argv); int dim = -1; if (!cl.search("--dim")) { std::cerr << "No --dim argument found!" << std::endl; usage_error(argv[0]); } dim = cl.next(dim); Mesh mesh(dim); if(!cl.search("--input")) { std::cerr << "No --input argument found!" << std::endl; usage_error(argv[0]); } const char* meshname = cl.next("mesh.xda"); mesh.read(meshname); std::cout << "Loaded mesh " << meshname << std::endl; if(!cl.search("--newbcid")) { std::cerr << "No --bcid argument found!" << std::endl; usage_error(argv[0]); } boundary_id_type bcid = 0; bcid = cl.next(bcid); Point minnormal(-std::numeric_limits<Real>::max(), -std::numeric_limits<Real>::max(), -std::numeric_limits<Real>::max()); Point maxnormal(std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max()); Point minpoint(-std::numeric_limits<Real>::max(), -std::numeric_limits<Real>::max(), -std::numeric_limits<Real>::max()); Point maxpoint(std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max(), std::numeric_limits<Real>::max()); if (cl.search("--minnormalx")) minnormal(0) = cl.next(minnormal(0)); if (cl.search("--minnormalx")) minnormal(0) = cl.next(minnormal(0)); if (cl.search("--maxnormalx")) maxnormal(0) = cl.next(maxnormal(0)); if (cl.search("--minnormaly")) minnormal(1) = cl.next(minnormal(1)); if (cl.search("--maxnormaly")) maxnormal(1) = cl.next(maxnormal(1)); if (cl.search("--minnormalz")) minnormal(2) = cl.next(minnormal(2)); if (cl.search("--maxnormalz")) maxnormal(2) = cl.next(maxnormal(2)); if (cl.search("--minpointx")) minpoint(0) = cl.next(minpoint(0)); if (cl.search("--maxpointx")) maxpoint(0) = cl.next(maxpoint(0)); if (cl.search("--minpointy")) minpoint(1) = cl.next(minpoint(1)); if (cl.search("--maxpointy")) maxpoint(1) = cl.next(maxpoint(1)); if (cl.search("--minpointz")) minpoint(2) = cl.next(minpoint(2)); if (cl.search("--maxpointz")) maxpoint(2) = cl.next(maxpoint(2)); std::cout << "min point = " << minpoint << std::endl; std::cout << "max point = " << maxpoint << std::endl; std::cout << "min normal = " << minnormal << std::endl; std::cout << "max normal = " << maxnormal << std::endl; bool matcholdbcid = false; boundary_id_type oldbcid = 0; if (cl.search("--oldbcid")) { matcholdbcid = true; oldbcid = cl.next(oldbcid); if (oldbcid < 0) oldbcid = BoundaryInfo::invalid_id; } AutoPtr<FEBase> fe = FEBase::build(dim, FEType(FIRST,LAGRANGE)); QGauss qface(dim-1, CONSTANT); fe->attach_quadrature_rule(&qface); const std::vector<Point> &face_points = fe->get_xyz(); const std::vector<Point> &face_normals = fe->get_normals(); MeshBase::element_iterator el = mesh.elements_begin(); const MeshBase::element_iterator end_el = mesh.elements_end(); for (; el != end_el; ++el) { Elem *elem = *el; unsigned int n_sides = elem->n_sides(); for (unsigned int s=0; s != n_sides; ++s) { if (elem->neighbor(s)) continue; fe->reinit(elem,s); const Point &p = face_points[0]; const Point &n = face_normals[0]; //std::cout << "elem = " << elem->id() << std::endl; //std::cout << "centroid = " << elem->centroid() << std::endl; //std::cout << "p = " << p << std::endl; //std::cout << "n = " << n << std::endl; if (p(0) > minpoint(0) && p(0) < maxpoint(0) && p(1) > minpoint(1) && p(1) < maxpoint(1) && p(2) > minpoint(2) && p(2) < maxpoint(2) && n(0) > minnormal(0) && n(0) < maxnormal(0) && n(1) > minnormal(1) && n(1) < maxnormal(1) && n(2) > minnormal(2) && n(2) < maxnormal(2)) { if (matcholdbcid && mesh.boundary_info->boundary_id(elem, s) != oldbcid) continue; mesh.boundary_info->remove_side(elem, s); mesh.boundary_info->add_side(elem, s, bcid); //std::cout << "Set element " << elem->id() << " side " << s << // " to boundary " << bcid << std::endl; } } } std::string outputname; if(cl.search("--output")) { outputname = cl.next("mesh.xda"); } else { outputname = "new."; outputname += meshname; } mesh.write(outputname.c_str()); std::cout << "Wrote mesh " << outputname << std::endl; return 0; }
void MaterialPropertyStorage::prolongStatefulProps( const std::vector<std::vector<QpMap>> & refinement_map, QBase & qrule, QBase & qrule_face, MaterialPropertyStorage & parent_material_props, MaterialData & child_material_data, const Elem & elem, const int input_parent_side, const int input_child, const int input_child_side) { mooseAssert(input_child != -1 || input_parent_side == input_child_side, "Invalid inputs!"); unsigned int n_qpoints = 0; // If we passed in -1 for these then we really need to store properties at 0 unsigned int parent_side = input_parent_side == -1 ? 0 : input_parent_side; unsigned int child_side = input_child_side == -1 ? 0 : input_child_side; if (input_child_side == -1) // Not doing side projection (ie, doing volume projection) n_qpoints = qrule.n_points(); else n_qpoints = qrule_face.n_points(); child_material_data.resize(n_qpoints); unsigned int n_children = elem.n_children(); std::vector<unsigned int> children; if (input_child != -1) // Passed in a child explicitly children.push_back(input_child); else { children.resize(n_children); for (unsigned int child = 0; child < n_children; child++) children[child] = child; } for (const auto & child : children) { // If we're not projecting an internal child side, but we are projecting sides, see if this // child is on that side if (input_child == -1 && input_child_side != -1 && !elem.is_child_on_side(child, parent_side)) continue; const Elem * child_elem = elem.child_ptr(child); mooseAssert(child < refinement_map.size(), "Refinement_map vector not initialized"); const std::vector<QpMap> & child_map = refinement_map[child]; initProps(child_material_data, *child_elem, child_side, n_qpoints); for (unsigned int i = 0; i < _stateful_prop_id_to_prop_id.size(); ++i) { // Copy from the parent stateful properties for (unsigned int qp = 0; qp < refinement_map[child].size(); qp++) { PropertyValue * child_property = props(child_elem, child_side)[i]; mooseAssert(props().contains(&elem), "Parent pointer is not in the MaterialProps data structure"); PropertyValue * parent_property = parent_material_props.props(&elem, parent_side)[i]; child_property->qpCopy(qp, parent_property, child_map[qp]._to); propsOld(child_elem, child_side)[i]->qpCopy( qp, parent_material_props.propsOld(&elem, parent_side)[i], child_map[qp]._to); if (hasOlderProperties()) propsOlder(child_elem, child_side)[i]->qpCopy( qp, parent_material_props.propsOlder(&elem, parent_side)[i], child_map[qp]._to); } } } }
int main (int argc, char** argv) { LibMeshInit init(argc, argv); PerfMon perfmon(argv[0]); unsigned int n_subdomains = 1; unsigned int n_rsteps = 0; unsigned char dim = static_cast<unsigned char>(-1); // invalid dimension double dist_fact = 0.; bool verbose = false; BoundaryMeshWriteMode write_bndry = BM_DISABLED; unsigned int convert_second_order = 0; bool addinfelems = false; bool triangulate = false; bool do_quality = false; ElemQuality quality_type = DIAGONAL; #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS InfElemBuilder::InfElemOriginValue origin_x(false, 0.); InfElemBuilder::InfElemOriginValue origin_y(false, 0.); InfElemBuilder::InfElemOriginValue origin_z(false, 0.); #endif bool x_sym=false; bool y_sym=false; bool z_sym=false; std::vector<std::string> names; std::vector<std::string> var_names; std::vector<Number> soln; process_cmd_line(argc, argv, names, n_subdomains, n_rsteps, dim, dist_fact, verbose, write_bndry, convert_second_order, triangulate, do_quality, quality_type, addinfelems, #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS origin_x, origin_y, origin_z, #endif x_sym, y_sym, z_sym); UniquePtr<Mesh> mesh_ptr; if (dim == static_cast<unsigned char>(-1)) { mesh_ptr.reset(new Mesh(init.comm())); } else { mesh_ptr.reset(new Mesh(init.comm(),dim)); } Mesh& mesh = *mesh_ptr; MeshData mesh_data(mesh); /** * Read the input mesh */ if (!names.empty()) { /* * activate the MeshData of the dim mesh, * so that it can be copied to the boundary */ if (write_bndry == BM_WITH_MESHDATA) { mesh_data.activate(); if (verbose) mesh_data.print_info(); } mesh.read(names[0]); if (verbose) { mesh.print_info(); mesh.get_boundary_info().print_summary(); } } else { libMesh::out << "No input specified." << std::endl; return 1; } #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS if(addinfelems) { if (names.size() == 3) { libMesh::out << "ERROR: Invalid combination: Building infinite elements " << std::endl << "not compatible with solution import." << std::endl; exit(1); } if (write_bndry != BM_DISABLED) { libMesh::out << "ERROR: Invalid combination: Building infinite elements " << std::endl << "not compatible with writing boundary conditions." << std::endl; exit(1); } /* * Sanity checks: -X/Y/Z can only be used, when the * corresponding coordinate is also given (using -x/y/z) */ if ((x_sym && !origin_x.first) || // claim x-symmetry, but x-coordinate of origin not given! (y_sym && !origin_y.first) || // the same for y (z_sym && !origin_z.first)) // the same for z { libMesh::out << "ERROR: When x-symmetry is requested using -X, then" << std::endl << "the option -x <coord> also has to be given." << std::endl << "This holds obviously for y and z, too." << std::endl; exit(1); } // build infinite elements InfElemBuilder(mesh).build_inf_elem(origin_x, origin_y, origin_z, x_sym, y_sym, z_sym, verbose); if (verbose) { mesh.print_info(); mesh.get_boundary_info().print_summary(); } } // sanity check else if((origin_x.first || origin_y.first || origin_z.first) || (x_sym || y_sym || z_sym)) { libMesh::out << "ERROR: -x/-y/-z/-X/-Y/-Z is only to be used when" << std::endl << "the option -a is also specified!" << std::endl; exit(1); } #endif /** * Possibly read the solution */ if (names.size() == 3) LegacyXdrIO(mesh,true).read_mgf_soln(names[2], soln, var_names); /** * Maybe Triangulate */ // if (dim == 2 && triangulate) if (triangulate) { if (verbose) libMesh::out << "...Converting to all simplices...\n"; MeshTools::Modification::all_tri(mesh); } /** * Compute Shape quality metrics */ if (do_quality) { StatisticsVector<Real> sv; sv.reserve(mesh.n_elem()); libMesh::out << "Quality type is: " << Quality::name(quality_type) << std::endl; // What are the quality bounds for this element? std::pair<Real, Real> bounds = mesh.elem(0)->qual_bounds(quality_type); libMesh::out << "Quality bounds for this element type are: (" << bounds.first << ", " << bounds.second << ") " << std::endl; MeshBase::const_element_iterator it = mesh.active_elements_begin(), end = mesh.active_elements_end(); for (; it != end; ++it) { Elem *e = *it; sv.push_back(e->quality(quality_type)); } const unsigned int n_bins = 10; libMesh::out << "Avg. shape quality: " << sv.mean() << std::endl; // Find element indices below the specified cutoff. // These might be considered "bad" elements which need refinement. std::vector<dof_id_type> bad_elts = sv.cut_below(0.8); libMesh::out << "Found " << bad_elts.size() << " of " << mesh.n_elem() << " elements below the cutoff." << std::endl; /* for (unsigned int i=0; i<bad_elts.size(); i++) libMesh::out << bad_elts[i] << " "; libMesh::out << std::endl; */ // Compute the histogram for this distribution std::vector<dof_id_type> histogram; sv.histogram(histogram, n_bins); /* for (unsigned int i=0; i<n_bins; i++) histogram[i] = histogram[i] / mesh.n_elem(); */ const bool do_matlab = true; if (do_matlab) { std::ofstream out ("histo.m"); out << "% This is a sample histogram plot for Matlab." << std::endl; out << "bin_members = [" << std::endl; for (unsigned int i=0; i<n_bins; i++) out << static_cast<Real>(histogram[i]) / static_cast<Real>(mesh.n_elem()) << std::endl; out << "];" << std::endl; std::vector<Real> bin_coords(n_bins); const Real max = *(std::max_element(sv.begin(), sv.end())); const Real min = *(std::min_element(sv.begin(), sv.end())); const Real delta = (max - min) / static_cast<Real>(n_bins); for (unsigned int i=0; i<n_bins; i++) bin_coords[i] = min + (i * delta) + delta / 2.0 ; out << "bin_coords = [" << std::endl; for (unsigned int i=0; i<n_bins; i++) out << bin_coords[i] << std::endl; out << "];" << std::endl; out << "bar(bin_coords, bin_members, 1);" << std::endl; out << "hold on" << std::endl; out << "plot (bin_coords, 0, 'kx');" << std::endl; out << "xlabel('Quality (0=Worst, 1=Best)');" << std::endl; out << "ylabel('Percentage of elements in each bin');" << std::endl; out << "axis([" << min << "," << max << ",0, max(bin_members)]);" << std::endl; out << "title('" << Quality::name(quality_type) << "');" << std::endl; } } /** * Possibly convert all linear * elements to second-order counterparts */ if (convert_second_order > 0) { bool second_order_mode = true; std:: string message = "Converting elements to second order counterparts"; if (convert_second_order == 2) { second_order_mode = false; message += ", lower version: Quad4 -> Quad8, not Quad9"; } else if (convert_second_order == 22) { second_order_mode = true; message += ", highest version: Quad4 -> Quad9"; } else libmesh_error_msg("Invalid value, convert_second_order = " << convert_second_order); if (verbose) libMesh::out << message << std::endl; mesh.all_second_order(second_order_mode); if (verbose) { mesh.print_info(); mesh.get_boundary_info().print_summary(); } } #ifdef LIBMESH_ENABLE_AMR /** * Possibly refine the mesh */ if (n_rsteps > 0) { if (verbose) libMesh::out << "Refining the mesh " << n_rsteps << " times" << std::endl; MeshRefinement mesh_refinement (mesh); mesh_refinement.uniformly_refine(n_rsteps); if (verbose) { mesh.print_info(); mesh.get_boundary_info().print_summary(); } } /** * Possibly distort the mesh */ if (dist_fact > 0.) { libMesh::out << "Distoring the mesh by a factor of " << dist_fact << std::endl; MeshTools::Modification::distort(mesh,dist_fact); }; /* char filechar[81]; sprintf(filechar,"%s-%04d.plt", "out", 0); std::string oname(filechar); mesh.write(oname); for (unsigned int step=0; step<100; step++) { // const Real x = .5 + .25*cos((((Real) step)/100.)*3.1415927); // const Real y = .5 + .25*sin((((Real) step)/100.)*3.1415927); const Real x = 2.5*cos((((Real) step)/100.)*3.1415927); const Real y = 2.5*sin((((Real) step)/100.)*3.1415927); const Point p(x,y); for (unsigned int e=0; e<mesh.n_elem(); e++) if (mesh.elem(e)->active()) mesh.elem(e)->set_refinement_flag() = -1; for (unsigned int e=0; e<mesh.n_elem(); e++) if (mesh.elem(e)->active()) { const Point diff = mesh.elem(e)->centroid(mesh) - p; if (diff.size() < .5) { if (mesh.elem(e)->level() < 4) mesh.elem(e)->set_refinement_flag() = 1; else if (mesh.elem(e)->level() == 4) mesh.elem(e)->set_refinement_flag() = 0; } } mesh.mesh_refinement.refine_and_coarsen_elements(); char filechar[81]; sprintf(filechar,"%s-%04d.plt", "out", step+1); std::string oname(filechar); mesh.write(oname); } */ #endif // /** // * Possibly partition the mesh // */ if (n_subdomains > 1) mesh.partition(n_subdomains); /** * Possibly write the mesh */ { if (names.size() >= 2) { /* * When the mesh got refined, it is likely that * the user does _not_ want to write also * the coarse elements, but only the active ones. * Use Mesh::create_submesh() to create a mesh * of only active elements, and then write _this_ * new mesh. */ if (n_rsteps > 0) { if (verbose) libMesh::out << " Mesh got refined, will write only _active_ elements." << std::endl; Mesh new_mesh (init.comm(), mesh.mesh_dimension()); construct_mesh_of_active_elements(new_mesh, mesh); // now write the new_mesh if (names.size() == 2) new_mesh.write(names[1]); else if (names.size() == 3) new_mesh.write(names[1], soln, var_names); else libmesh_error_msg("Invalid names.size() = " << names.size()); } else { if (names.size() == 2) mesh.write(names[1]); else if (names.size() == 3) mesh.write(names[1], soln, var_names); else libmesh_error_msg("Invalid names.size() = " << names.size()); } /** * Possibly write the BCs */ if (write_bndry != BM_DISABLED) { BoundaryMesh boundary_mesh (mesh.comm(), cast_int<unsigned char>(mesh.mesh_dimension()-1)); MeshData boundary_mesh_data (boundary_mesh); std::string boundary_name = "bndry_"; boundary_name += names[1]; if (write_bndry == BM_MESH_ONLY) mesh.get_boundary_info().sync(boundary_mesh); else if (write_bndry == BM_WITH_MESHDATA) mesh.get_boundary_info().sync(boundary_mesh, &boundary_mesh_data, &mesh_data); else libmesh_error_msg("Invalid value write_bndry = " << write_bndry); if (names.size() == 2) boundary_mesh.write(boundary_name); else if (names.size() == 3) boundary_mesh.write(boundary_name, soln, var_names); } } }; /* libMesh::out << "Infinite loop, look at memory footprint" << std::endl; for (;;) ; */ return 0; }
// Begin the main program. int main (int argc, char ** argv) { // Initialize libMesh, like in example 2. LibMeshInit init (argc, argv); // This example requires Infinite Elements #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS libmesh_example_requires(false, "--enable-ifem"); #else // Skip this 3D example if libMesh was compiled as 1D/2D-only. libmesh_example_requires(3 <= LIBMESH_DIM, "3D support"); // Tell the user what we are doing. libMesh::out << "Running ex6 with dim = 3" << std::endl << std::endl; // Create a serialized mesh, distributed across the default MPI // communicator. // InfElemBuilder still requires some updates to be DistributedMesh // compatible ReplicatedMesh mesh(init.comm()); // Use the internal mesh generator to create elements // on the square [-1,1]^3, of type Hex8. MeshTools::Generation::build_cube (mesh, 4, 4, 4, -1., 1., -1., 1., -1., 1., HEX8); // Print information about the mesh to the screen. mesh.print_info(); // Write the mesh before the infinite elements are added #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write ("orig_mesh.e"); #endif // Normally, when a mesh is imported or created in // libMesh, only conventional elements exist. The infinite // elements used here, however, require prescribed // nodal locations (with specified distances from an imaginary // origin) and configurations that a conventional mesh creator // in general does not offer. Therefore, an efficient method // for building infinite elements is offered. It can account // for symmetry planes and creates infinite elements in a fully // automatic way. // // Right now, the simplified interface is used, automatically // determining the origin. Check MeshBase for a generalized // method that can even return the element faces of interior // vibrating surfaces. The bool determines whether to be // verbose. InfElemBuilder builder(mesh); builder.build_inf_elem(true); // Reassign subdomain_id() of all infinite elements. // Otherwise, the exodus-api will fail on the 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->infinite()) { elem->subdomain_id() = 1; } } // Print information about the mesh to the screen. mesh.print_info(); // Write the mesh with the infinite elements added. // Compare this to the original mesh. #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write ("ifems_added.e"); #endif // After building infinite elements, we have to let // the elements find their neighbors again. mesh.find_neighbors(); // Create an equation systems object, where ThinSystem // offers only the crucial functionality for solving a // system. Use ThinSystem when you want the sleekest // system possible. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Wave". This can // be a simple, steady system equation_systems.add_system<LinearImplicitSystem> ("Wave"); // Create an FEType describing the approximation // characteristics of the InfFE object. Note that // the constructor automatically defaults to some // sensible values. But use FIRST order // approximation. FEType fe_type(FIRST); // Add the variable "p" to "Wave". Note that there exist // various approaches in adding variables. In example 3, // add_variable took the order of approximation and used // default values for the FEFamily, while here the FEType // is used. equation_systems.get_system("Wave").add_variable("p", fe_type); // Give the system a pointer to the matrix assembly // function. equation_systems.get_system("Wave").attach_assemble_function (assemble_wave); // Set the speed of sound and fluid density // as EquationSystems parameter, // so that assemble_wave() can access it. equation_systems.parameters.set<Real>("speed") = 1.; equation_systems.parameters.set<Real>("fluid density") = 1.; // Initialize the data structures for the equation system. equation_systems.init(); // Prints information about the system to the screen. equation_systems.print_info(); // Solve the system "Wave". equation_systems.get_system("Wave").solve(); // Write the whole EquationSystems object to file. // For infinite elements, the concept of nodal_soln() // is not applicable. Therefore, writing the mesh in // some format @e always gives all-zero results at // the nodes of the infinite elements. Instead, // use the FEInterface::compute_data() methods to // determine physically correct results within an // infinite element. equation_systems.write ("eqn_sys.dat", WRITE); // All done. return 0; #endif // else part of ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS }
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 setUp() { #if LIBMESH_DIM > 2 mesh.reset(new Mesh(*TestCommWorld)); MeshTools::Generation::build_cube(*mesh, 1, 1, 1); es.reset(new EquationSystems(*mesh)); sys = &(es->add_system<System> ("SimpleSystem")); sys->add_variable("x2"); sys->add_variable("x3"); sys->add_variable("c05"); sys->add_variable("y4"); sys->add_variable("xy"); sys->add_variable("yz"); sys->add_variable("xyz"); es->init(); NumericVector<Number> & sol = *sys->solution; Elem *elem = mesh->query_elem_ptr(0); if (elem && elem->processor_id() == TestCommWorld->rank()) { // Set x2 = 2*x sol.set(elem->node_ref(1).dof_number(0,0,0), 2); sol.set(elem->node_ref(2).dof_number(0,0,0), 2); sol.set(elem->node_ref(5).dof_number(0,0,0), 2); sol.set(elem->node_ref(6).dof_number(0,0,0), 2); // Set x3 = 3*x sol.set(elem->node_ref(1).dof_number(0,1,0), 3); sol.set(elem->node_ref(2).dof_number(0,1,0), 3); sol.set(elem->node_ref(5).dof_number(0,1,0), 3); sol.set(elem->node_ref(6).dof_number(0,1,0), 3); // Set c05 = 0.5 sol.set(elem->node_ref(0).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(1).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(2).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(3).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(4).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(5).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(6).dof_number(0,2,0), 0.5); sol.set(elem->node_ref(7).dof_number(0,2,0), 0.5); // Set y4 = 4*y sol.set(elem->node_ref(2).dof_number(0,3,0), 4); sol.set(elem->node_ref(3).dof_number(0,3,0), 4); sol.set(elem->node_ref(6).dof_number(0,3,0), 4); sol.set(elem->node_ref(7).dof_number(0,3,0), 4); // Set xy = x*y sol.set(elem->node_ref(2).dof_number(0,4,0), 1); sol.set(elem->node_ref(6).dof_number(0,4,0), 1); // Set yz = y*z sol.set(elem->node_ref(6).dof_number(0,5,0), 1); sol.set(elem->node_ref(7).dof_number(0,5,0), 1); // Set xyz = x*y*z sol.set(elem->node_ref(6).dof_number(0,6,0), 1); } sol.close(); sys->update(); c.reset(new FEMContext(*sys)); s.reset(new FEMContext(*sys)); if (elem && elem->processor_id() == TestCommWorld->rank()) { c->pre_fe_reinit(*sys, elem); c->elem_fe_reinit(); s->pre_fe_reinit(*sys, elem); s->side = 3; s->side_fe_reinit(); } #endif }
void unpack(std::vector<int>::const_iterator in, Elem** out, MeshBase* mesh) { #ifndef NDEBUG const std::vector<int>::const_iterator original_in = in; const int incoming_header = *in++; libmesh_assert (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(rflag >= 0); libmesh_assert(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(pflag >= 0); libmesh_assert(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(typeint >= 0); libmesh_assert(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 unsigned int processor_id = static_cast<unsigned int>(*in++); libmesh_assert (processor_id < libMesh::n_processors() || processor_id == DofObject::invalid_processor_id); // int 6: subdomain id const unsigned int subdomain_id = static_cast<unsigned int>(*in++); // int 7: dof object id const unsigned int id = static_cast<unsigned int>(*in++); libmesh_assert (id != DofObject::invalid_id); #ifdef LIBMESH_ENABLE_AMR // int 8: parent dof object id const unsigned int parent_id = static_cast<unsigned int>(*in++); libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); // int 9: 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(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 (elem->level() == level); libmesh_assert (elem->id() == id); libmesh_assert (elem->processor_id() == processor_id); libmesh_assert (elem->subdomain_id() == subdomain_id); libmesh_assert (elem->type() == type); libmesh_assert (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<unsigned int>(*in++)); #else in += n_nodes; #endif #ifdef LIBMESH_ENABLE_AMR libmesh_assert (elem->p_level() == p_level); libmesh_assert (elem->refinement_flag() == refinement_flag); libmesh_assert (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 unsigned int neighbor_id = static_cast<unsigned int>(*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) == NULL); 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) != NULL); 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(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 (parent_id == static_cast<unsigned int>(-1)); #else // No non-level-0 elements without AMR libmesh_assert (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 (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 (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; // Assign the connectivity libmesh_assert (elem->n_nodes() == n_nodes); for (unsigned int n=0; n != n_nodes; n++) elem->set_node(n) = mesh->node_ptr (static_cast<unsigned int>(*in++)); for (unsigned int n=0; n<elem->n_neighbors(); n++) { const unsigned int neighbor_id = static_cast<unsigned int>(*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 (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; }
UniquePtr<Elem> InfHex8::build_side (const unsigned int i, bool proxy) const { libmesh_assert_less (i, this->n_sides()); if (proxy) { switch (i) { // base case 0: return UniquePtr<Elem>(new Side<Quad4,InfHex8>(this,i)); // ifem sides case 1: case 2: case 3: case 4: return UniquePtr<Elem>(new Side<InfQuad4,InfHex8>(this,i)); default: libmesh_error_msg("Invalid side i = " << i); } } else { // Create NULL pointer to be initialized, returned later. Elem * face = libmesh_nullptr; // Think of a unit cube: (-1,1) x (-1,1) x (1,1) switch (i) { case 0: // the base face { face = new Quad4; break; } // connecting to another infinite element case 1: case 2: case 3: case 4: { face = new InfQuad4; break; } default: libmesh_error_msg("Invalid side i = " << i); } face->subdomain_id() = this->subdomain_id(); // Set the nodes for (unsigned n=0; n<face->n_nodes(); ++n) face->set_node(n) = this->get_node(InfHex8::side_nodes_map[i][n]); return UniquePtr<Elem>(face); } libmesh_error_msg("We'll never get here!"); return UniquePtr<Elem>(); }
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; }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_edge (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; // Maps holding the maximum element level that touches an edge std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_level_at_edge; std::map<std::pair<unsigned int, unsigned int>, unsigned char> max_p_level_at_edge; // Loop over all the active elements & fill the maps { 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) { const Elem* elem = *elem_it; const unsigned char elem_level = elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0); const unsigned char elem_p_level = elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0); // Set the max_level at each edge for (unsigned int n=0; n<elem->n_edges(); n++) { AutoPtr<Elem> edge = elem->build_edge(n); unsigned int childnode0 = edge->node(0); unsigned int childnode1 = edge->node(1); if (childnode1 < childnode0) std::swap(childnode0, childnode1); for (const Elem *p = elem; p != NULL; p = p->parent()) { AutoPtr<Elem> pedge = p->build_edge(n); unsigned int node0 = pedge->node(0); unsigned int node1 = pedge->node(1); if (node1 < node0) std::swap(node0, node1); // If elem does not share this edge with its ancestor // p, refinement levels of elements sharing p's edge // are not restricted by refinement levels of elem. // Furthermore, elem will not share this edge with any // of p's ancestors, so we can safely break out of the // for loop early. if (node0 != childnode0 && node1 != childnode1) break; childnode0 = node0; childnode1 = node1; std::pair<unsigned int, unsigned int> edge_key = std::make_pair(node0, node1); if (max_level_at_edge.find(edge_key) == max_level_at_edge.end()) { max_level_at_edge[edge_key] = elem_level; max_p_level_at_edge[edge_key] = elem_p_level; } else { max_level_at_edge[edge_key] = std::max (max_level_at_edge[edge_key], elem_level); max_p_level_at_edge[edge_key] = std::max (max_p_level_at_edge[edge_key], elem_p_level); } } } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch { 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 elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_edges(); n++) { AutoPtr<Elem> edge = elem->build_edge(n); unsigned int node0 = edge->node(0); unsigned int node1 = edge->node(1); if (node1 < node0) std::swap(node0, node1); std::pair<unsigned int, unsigned int> edge_key = std::make_pair(node0, node1); // Flag the element for refinement if it violates // the requested level mismatch if ( (elem_level + max_mismatch) < max_level_at_edge[edge_key] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ( (elem_p_level + max_mismatch) < max_p_level_at_edge[edge_key] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } } } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit) { #ifdef LIBMESH_HAVE_TETGEN SerialMesh cube_mesh(3); unsigned n_elem = 1; MeshTools::Generation::build_cube(cube_mesh, n_elem,n_elem,n_elem, // n. elements in each direction lower_limit(0), upper_limit(0), lower_limit(1), upper_limit(1), lower_limit(2), upper_limit(2), HEX8); // The pointset_convexhull() algorithm will ignore the Hex8s // in the Mesh, and just construct the triangulation // of the convex hull. TetGenMeshInterface t(cube_mesh); t.pointset_convexhull(); // Now add all nodes from the boundary of the cube_mesh to the input mesh. // Map from "node id in cube_mesh" -> "node id in mesh". Initially inserted // with a dummy value, later to be assigned a value by the input mesh. std::map<unsigned,unsigned> node_id_map; typedef std::map<unsigned,unsigned>::iterator iterator; { MeshBase::element_iterator it = cube_mesh.elements_begin(); const MeshBase::element_iterator end = cube_mesh.elements_end(); for ( ; it != end; ++it) { Elem* elem = *it; for (unsigned s=0; s<elem->n_sides(); ++s) if (elem->neighbor(s) == NULL) { // Add the node IDs of this side to the set AutoPtr<Elem> side = elem->side(s); for (unsigned n=0; n<side->n_nodes(); ++n) node_id_map.insert( std::make_pair(side->node(n), /*dummy_value=*/0) ); } } } // For each node in the map, insert it into the input mesh and keep // track of the ID assigned. for (iterator it=node_id_map.begin(); it != node_id_map.end(); ++it) { // Id of the node in the cube mesh unsigned id = (*it).first; // Pointer to node in the cube mesh Node* old_node = cube_mesh.node_ptr(id); // Add geometric point to input mesh Node* new_node = mesh.add_point ( *old_node ); // Track ID value of new_node in map (*it).second = new_node->id(); } // With the points added and the map data structure in place, we are // ready to add each TRI3 element of the cube_mesh to the input Mesh // with proper node assignments { MeshBase::element_iterator el = cube_mesh.elements_begin(); const MeshBase::element_iterator end_el = cube_mesh.elements_end(); for (; el != end_el; ++el) { Elem* old_elem = *el; if (old_elem->type() == TRI3) { Elem* new_elem = mesh.add_elem(new Tri3); // Assign nodes in new elements. Since this is an example, // we'll do it in several steps. for (unsigned i=0; i<old_elem->n_nodes(); ++i) { // Locate old node ID in the map iterator it = node_id_map.find(old_elem->node(i)); // Check for not found if (it == node_id_map.end()) { libMesh::err << "Node id " << old_elem->node(i) << " not found in map!" << std::endl; libmesh_error(); } // Mapping to node ID in input mesh unsigned new_node_id = (*it).second; // Node pointer assigned from input mesh new_elem->set_node(i) = mesh.node_ptr(new_node_id); } } } } #endif // LIBMESH_HAVE_TETGEN }
//----------------------------------------------------------------- // Mesh refinement methods bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch) { // This function must be run on all processors at once parallel_only(); bool flags_changed = false; // Vector holding the maximum element level that touches a node. std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0); std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0); // Loop over all the active elements & fill the vector { 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) { const Elem* elem = *elem_it; const unsigned char elem_level = elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0); const unsigned char elem_p_level = elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0); // Set the max_level at each node for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); libmesh_assert_less (node_number, max_level_at_node.size()); max_level_at_node[node_number] = std::max (max_level_at_node[node_number], elem_level); max_p_level_at_node[node_number] = std::max (max_p_level_at_node[node_number], elem_p_level); } } } // Now loop over the active elements and flag the elements // who violate the requested level mismatch { 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 elem_level = elem->level(); const unsigned int elem_p_level = elem->p_level(); // Skip the element if it is already fully flagged if (elem->refinement_flag() == Elem::REFINE && elem->p_refinement_flag() == Elem::REFINE) continue; // Loop over the nodes, check for possible mismatch for (unsigned int n=0; n<elem->n_nodes(); n++) { const unsigned int node_number = elem->node(n); // Flag the element for refinement if it violates // the requested level mismatch if ( (elem_level + max_mismatch) < max_level_at_node[node_number] && elem->refinement_flag() != Elem::REFINE) { elem->set_refinement_flag (Elem::REFINE); flags_changed = true; } if ( (elem_p_level + max_mismatch) < max_p_level_at_node[node_number] && elem->p_refinement_flag() != Elem::REFINE) { elem->set_p_refinement_flag (Elem::REFINE); flags_changed = true; } } } } // If flags changed on any processor then they changed globally CommWorld.max(flags_changed); return flags_changed; }
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); }