TEST(Mesh, HigherOrderLine1) { UnstructuredMesh* msh = createLineElement(GeoLib::Point(0,0,0), GeoLib::Point(1,0,0), CoordinateSystemType::X); std::vector<IElement*> vec_edge; createEdgeElements(msh); ASSERT_EQ(1u, msh->getNumberOfEdges()); MeshGenerator::generateHigherOrderUnstrucuredMesh(*msh, 2); IElement* e = 0; ASSERT_EQ(2u, msh->getNumberOfNodes(1)); ASSERT_EQ(3u, msh->getNumberOfNodes(2)); msh->setCurrentOrder(1); e = msh->getElement(0); ASSERT_EQ(2u, msh->getNumberOfNodes(1)); ASSERT_EQ(2u, e->getNumberOfNodes()); msh->setCurrentOrder(2); e = msh->getElement(0); ASSERT_EQ(3u, msh->getNumberOfNodes(2)); ASSERT_EQ(3u, e->getNumberOfNodes()); e->setCurrentOrder(1); ASSERT_EQ(2u, e->getNumberOfNodes()); e->setCurrentOrder(2); ASSERT_EQ(3u, e->getNumberOfNodes()); const GeoLib::Point* p = msh->getNodeCoordinatesRef(2); ASSERT_DOUBLE_EQ(0.5, (*p)[0]); ASSERT_DOUBLE_EQ(0., (*p)[1]); ASSERT_DOUBLE_EQ(0., (*p)[2]); }
TEST(Mesh, MappingLineXZ2) { UnstructuredMesh* msh = createLineElement(GeoLib::Point(1,0,1), GeoLib::Point(2,0,2), CoordinateSystemType::XZ); ElementCoordinatesMappingLocal emap(msh, *msh->getElement(0), msh->getGeometricProperty()->getCoordinateSystem()); GeoLib::Point* p1 = emap.getNodePoint(0); GeoLib::Point* p2 = emap.getNodePoint(1); ASSERT_EQ(GeoLib::Point(0,0,0), *p1); ASSERT_EQ(GeoLib::Point(sqrt(2.),0,0), *p2); }
UnstructuredMesh * createLineElement(GeoLib::Point pt1, GeoLib::Point pt2, CoordinateSystemType::type coord_type) { UnstructuredMesh *msh = new UnstructuredMesh(coord_type); msh->addNode(pt1); msh->addNode(pt2); Line *e = new Line(); e->setNodeID(0,0); e->setNodeID(1,1); msh->addElement(e); return msh; }
TEST(Mesh, MappingTriYZ1) { UnstructuredMesh* msh = createTriangleElement(GeoLib::Point(0,1,1), GeoLib::Point(0,3,1), GeoLib::Point(0,1,3), CoordinateSystemType::YZ); ElementCoordinatesMappingLocal emap(msh, *msh->getElement(0), msh->getGeometricProperty()->getCoordinateSystem()); GeoLib::Point* p1 = emap.getNodePoint(0); GeoLib::Point* p2 = emap.getNodePoint(1); GeoLib::Point* p3 = emap.getNodePoint(2); // ASSERT_EQ(GeoLib::Point(0,0,0), *p1); // ASSERT_EQ(GeoLib::Point(2,0,0), *p2); // ASSERT_EQ(GeoLib::Point(0,2,0), *p3); ASSERT_EQ(GeoLib::Point(1,1,0), *p1); ASSERT_EQ(GeoLib::Point(3,1,0), *p2); ASSERT_EQ(GeoLib::Point(1,3,0), *p3); }
double calculateMeshMinimumEdgeLength(UnstructuredMesh &msh) { std::vector<size_t> vec_edge_nodes; double min_edge_len = std::numeric_limits<double>::max(); const size_t n_ele = msh.getNumberOfElements(); for (size_t i=0; i<n_ele; i++) { MeshLib::IElement* e = msh.getElement(i); for (size_t j=0; j<e->getNumberOfEdges(); j++) { e->getNodeIDsOfEdges(j, vec_edge_nodes); assert (vec_edge_nodes.size() == 2); double edge_len = std::sqrt(GeoLib::sqrDist(msh.getNodeCoordinatesRef(vec_edge_nodes[0]), msh.getNodeCoordinatesRef(vec_edge_nodes[1]))); min_edge_len = std::min(min_edge_len, edge_len); } } return min_edge_len; }
void calculateMeshGeometricProperties(UnstructuredMesh &msh) { MeshGeometricProperty* geo_prop = msh.getGeometricProperty(); //double tol = std::numeric_limits<double>::epsilon(); // coordinate systems geo_prop->setCoordinateSystem(getCoordinateSystemFromBoundingBox(geo_prop->getBoundingBox())); // // GeoLib::Point pt_diff = geo_prop->getBoundingBox().getMaxPoint() - geo_prop->getBoundingBox().getMinPoint(); // double max_len = std::max(pt_diff[0], pt_diff[1]); // max_len = std::max(max_len, pt_diff[2]); // double min_edge_len = max_len / msh.getNumberOfNodes(); double min_edge_len = calculateMeshMinimumEdgeLength(msh); geo_prop->setMinEdgeLength(min_edge_len); INFO("-> calculate mesh geometric properties"); INFO("* min. edge length = %f", min_edge_len); }
void TriangleWrapper::copy_tri_to_mesh(const triangulateio& triangle_data_input, UnstructuredMesh& mesh_output, const ElemType type) { // Transfer the information into the LibMesh mesh. mesh_output.clear(); // Make sure the new Mesh will be 2D mesh_output.set_mesh_dimension(2); // Node information for (int i=0, c=0; c<triangle_data_input.numberofpoints; i+=2, ++c) { // Specify ID when adding point, otherwise, if this is ParallelMesh, // it might add points with a non-sequential numbering... mesh_output.add_point( Point(triangle_data_input.pointlist[i], triangle_data_input.pointlist[i+1]), /*id=*/c); } // Element information for (int i=0; i<triangle_data_input.numberoftriangles; ++i) { switch (type) { case TRI3: { Elem* elem = mesh_output.add_elem (new Tri3); for (unsigned int n=0; n<3; ++n) elem->set_node(n) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*3 + n]); break; } case TRI6: { Elem* elem = mesh_output.add_elem (new Tri6); // Triangle number TRI6 nodes in a different way to libMesh elem->set_node(0) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 0]); elem->set_node(1) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 1]); elem->set_node(2) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 2]); elem->set_node(3) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 5]); elem->set_node(4) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 3]); elem->set_node(5) = mesh_output.node_ptr(triangle_data_input.trianglelist[i*6 + 4]); break; } default: { libMesh::err << "ERROR: Unrecognized triangular element type." << std::endl; libmesh_error(); } } } // Note: If the input mesh was a parallel one, calling // prepare_for_use() now will re-parallelize it by a call to // delete_remote_elements()... We do not actually want to // reparallelize it here though: the triangulate() function may // still do some Mesh smoothing. The main thing needed (for // smoothing) is the neighbor information, so let's just find // neighbors... //mesh_output.prepare_for_use(/*skip_renumber =*/false); mesh_output.find_neighbors(); }
void UnstructuredMesh::copy_nodes_and_elements(const UnstructuredMesh & other_mesh, const bool skip_find_neighbors) { // We're assuming our subclass data needs no copy libmesh_assert_equal_to (_n_parts, other_mesh._n_parts); libmesh_assert (std::equal(_elem_dims.begin(), _elem_dims.end(), other_mesh._elem_dims.begin())); libmesh_assert_equal_to (_is_prepared, other_mesh._is_prepared); // We're assuming the other mesh has proper element number ordering, // so that we add parents before their children. #ifdef DEBUG MeshTools::libmesh_assert_valid_amr_elem_ids(other_mesh); #endif //Copy in Nodes { //Preallocate Memory if necessary this->reserve_nodes(other_mesh.n_nodes()); const_node_iterator it = other_mesh.nodes_begin(); const_node_iterator end = other_mesh.nodes_end(); for (; it != end; ++it) { const Node * oldn = *it; // Add new nodes in old node Point locations #ifdef LIBMESH_ENABLE_UNIQUE_ID Node *newn = #endif this->add_point(*oldn, oldn->id(), oldn->processor_id()); #ifdef LIBMESH_ENABLE_UNIQUE_ID newn->set_unique_id() = oldn->unique_id(); #endif } } //Copy in Elements { //Preallocate Memory if necessary this->reserve_elem(other_mesh.n_elem()); // Declare a map linking old and new elements, needed to copy the neighbor lists std::map<const Elem *, Elem *> old_elems_to_new_elems; // Loop over the elements MeshBase::const_element_iterator it = other_mesh.elements_begin(); const MeshBase::const_element_iterator end = other_mesh.elements_end(); // FIXME: Where do we set element IDs?? for (; it != end; ++it) { //Look at the old element const Elem * old = *it; //Build a new element Elem * newparent = old->parent() ? this->elem_ptr(old->parent()->id()) : libmesh_nullptr; UniquePtr<Elem> ap = Elem::build(old->type(), newparent); Elem * el = ap.release(); el->subdomain_id() = old->subdomain_id(); for (unsigned int s=0; s != old->n_sides(); ++s) if (old->neighbor_ptr(s) == remote_elem) el->set_neighbor(s, const_cast<RemoteElem *>(remote_elem)); #ifdef LIBMESH_ENABLE_AMR if (old->has_children()) for (unsigned int c=0; c != old->n_children(); ++c) if (old->child_ptr(c) == remote_elem) el->add_child(const_cast<RemoteElem *>(remote_elem), c); //Create the parent's child pointers if necessary if (newparent) { unsigned int oldc = old->parent()->which_child_am_i(old); newparent->add_child(el, oldc); } // Copy the refinement flags el->set_refinement_flag(old->refinement_flag()); // Use hack_p_level since we may not have sibling elements // added yet el->hack_p_level(old->p_level()); el->set_p_refinement_flag(old->p_refinement_flag()); #endif // #ifdef LIBMESH_ENABLE_AMR //Assign all the nodes for(unsigned int i=0;i<el->n_nodes();i++) el->set_node(i) = this->node_ptr(old->node_id(i)); // And start it off in the same subdomain el->processor_id() = old->processor_id(); // Give it the same ids el->set_id(old->id()); #ifdef LIBMESH_ENABLE_UNIQUE_ID el->set_unique_id() = old->unique_id(); #endif //Hold onto it if(!skip_find_neighbors) { this->add_elem(el); } else { Elem * new_el = this->add_elem(el); old_elems_to_new_elems[old] = new_el; } // Add the link between the original element and this copy to the map if(skip_find_neighbors) old_elems_to_new_elems[old] = el; } // Loop (again) over the elements to fill in the neighbors if(skip_find_neighbors) { it = other_mesh.elements_begin(); for (; it != end; ++it) { Elem * old_elem = *it; Elem * new_elem = old_elems_to_new_elems[old_elem]; for (unsigned int s=0; s != old_elem->n_neighbors(); ++s) { const Elem * old_neighbor = old_elem->neighbor_ptr(s); Elem * new_neighbor = old_elems_to_new_elems[old_neighbor]; new_elem->set_neighbor(s, new_neighbor); } } } } //Finally prepare the new Mesh for use. Keep the same numbering and //partitioning but also the same renumbering and partitioning //policies as our source mesh. this->allow_renumbering(false); this->skip_partitioning(true); this->prepare_for_use(false, skip_find_neighbors); this->allow_renumbering(other_mesh.allow_renumbering()); this->skip_partitioning(other_mesh.skip_partitioning()); }
void UnstructuredMesh::create_submesh (UnstructuredMesh & new_mesh, const_element_iterator & it, const const_element_iterator & it_end) const { // Just in case the subdomain_mesh already has some information // in it, get rid of it. new_mesh.clear(); // If we're not serial, our submesh isn't either. // There are no remote elements to delete on an empty mesh, but // calling the method to do so marks the mesh as parallel. if (!this->is_serial()) new_mesh.delete_remote_elements(); // Fail if (*this == new_mesh), we cannot create a submesh inside ourself! // This may happen if the user accidently passes the original mesh into // this function! We will check this by making sure we did not just // clear ourself. libmesh_assert_not_equal_to (this->n_nodes(), 0); libmesh_assert_not_equal_to (this->n_elem(), 0); // Container to catch boundary IDs handed back by BoundaryInfo std::vector<boundary_id_type> bc_ids; for (; it != it_end; ++it) { const Elem * old_elem = *it; // Add an equivalent element type to the new_mesh. // Copy ids for this element. Elem * new_elem = Elem::build(old_elem->type()).release(); new_elem->set_id() = old_elem->id(); #ifdef LIBMESH_ENABLE_UNIQUE_ID new_elem->set_unique_id() = old_elem->unique_id(); #endif new_elem->subdomain_id() = old_elem->subdomain_id(); new_elem->processor_id() = old_elem->processor_id(); new_mesh.add_elem (new_elem); libmesh_assert(new_elem); // Loop over the nodes on this element. for (unsigned int n=0; n<old_elem->n_nodes(); n++) { const dof_id_type this_node_id = old_elem->node_id(n); // Add this node to the new mesh if it's not there already if (!new_mesh.query_node_ptr(this_node_id)) { #ifdef LIBMESH_ENABLE_UNIQUE_ID Node *newn = #endif new_mesh.add_point (old_elem->point(n), this_node_id, old_elem->node_ptr(n)->processor_id()); #ifdef LIBMESH_ENABLE_UNIQUE_ID newn->set_unique_id() = old_elem->node_ptr(n)->unique_id(); #endif } // Define this element's connectivity on the new mesh new_elem->set_node(n) = new_mesh.node_ptr(this_node_id); } // Maybe add boundary conditions for this element for (unsigned short s=0; s<old_elem->n_sides(); s++) { this->get_boundary_info().boundary_ids(old_elem, s, bc_ids); new_mesh.get_boundary_info().add_side (new_elem, s, bc_ids); } } // end loop over elements // Prepare the new_mesh for use new_mesh.prepare_for_use(/*skip_renumber =*/false); }