MeshLib::Mesh* MshEditor::getMeshSurface(const MeshLib::Mesh &mesh, const double* dir) { INFO ("Extracting mesh surface..."); const std::vector<MeshLib::Element*> all_elements (mesh.getElements()); const std::vector<MeshLib::Node*> all_nodes (mesh.getNodes()); std::vector<MeshLib::Element*> sfc_elements; get2DSurfaceElements(all_elements, sfc_elements, dir, mesh.getDimension()); std::vector<MeshLib::Node*> sfc_nodes; std::vector<unsigned> node_id_map(mesh.getNNodes()); get2DSurfaceNodes(all_nodes, sfc_nodes, sfc_elements, node_id_map); // create new elements vector with newly created nodes const size_t nNewElements (sfc_elements.size()); std::vector<MeshLib::Element*> new_elements(sfc_elements.size()); for (unsigned i=0; i<nNewElements; ++i) { MeshLib::Element* elem (sfc_elements[i]); if (elem->getType() == MshElemType::TRIANGLE) { MeshLib::Node** tri_nodes = new MeshLib::Node*[3]; for (unsigned k(0); k<3; k++) tri_nodes[k] = sfc_nodes[node_id_map[elem->getNode(k)->getID()]]; new_elements[i] = new MeshLib::Tri(tri_nodes); } else { MeshLib::Node** quad_nodes = new MeshLib::Node*[4]; for (unsigned k(0); k<3; k++) quad_nodes[k] = sfc_nodes[node_id_map[elem->getNode(k)->getID()]]; new_elements[i] = new MeshLib::Quad(quad_nodes); } delete sfc_elements[i]; } return new Mesh("SurfaceMesh", sfc_nodes, new_elements); }
static void checkJacobianDeterminant(const double detJ, MeshLib::Element const& element) { if (detJ > 0) // The usual case return; if (detJ < 0) { ERR("det J = %g is negative for element %d.", detJ, element.getID()); #ifndef NDEBUG std::cerr << element << "\n"; #endif // NDEBUG OGS_FATAL("Please check the node numbering of the element."); } if (detJ == 0) { ERR("det J is zero for element %d.", element.getID()); #ifndef NDEBUG std::cerr << element << "\n"; #endif // NDEBUG OGS_FATAL( "Please check whether:\n" "\t the element nodes may have the same coordinates,\n" "\t or the coordinates of all nodes are not given on the x-axis " "for a 1D problem or in the xy-plane in the 2D case."); } }
bool BoundaryElementsAlongPolyline::includesAllEdgeNodeIDs(const std::vector<std::size_t> &vec_node_ids, const MeshLib::Element &edge, std::vector<std::size_t> &edge_node_distances) const { unsigned j=0; for (; j<edge.getNumberOfBaseNodes(); j++) { auto itr = std::find(vec_node_ids.begin(), vec_node_ids.end(), edge.getNodeIndex(j)); if (itr != vec_node_ids.end()) edge_node_distances.push_back(std::distance(vec_node_ids.begin(), itr)); else break; } return (j==edge.getNumberOfBaseNodes()); }
bool convertMeshToGeo(const MeshLib::Mesh &mesh, GeoLib::GEOObjects &geo_objects, double eps) { if (mesh.getDimension() != 2) { ERR ("Mesh to geometry conversion is only working for 2D meshes."); return false; } // nodes to points conversion std::string mesh_name(mesh.getName()); { auto points = std::make_unique<std::vector<GeoLib::Point*>>(); points->reserve(mesh.getNumberOfNodes()); for (auto node_ptr : mesh.getNodes()) points->push_back(new GeoLib::Point(*node_ptr, node_ptr->getID())); geo_objects.addPointVec(std::move(points), mesh_name, nullptr, eps); } const std::vector<std::size_t> id_map (geo_objects.getPointVecObj(mesh_name)->getIDMap()); // elements to surface triangles conversion std::string const mat_name ("MaterialIDs"); auto bounds (MeshInformation::getValueBounds<int>(mesh, mat_name)); const unsigned nMatGroups(bounds.second-bounds.first+1); auto sfcs = std::make_unique<std::vector<GeoLib::Surface*>>(); sfcs->reserve(nMatGroups); auto const& points = *geo_objects.getPointVec(mesh_name); for (unsigned i=0; i<nMatGroups; ++i) sfcs->push_back(new GeoLib::Surface(points)); const std::vector<MeshLib::Element*> &elements = mesh.getElements(); const std::size_t nElems (mesh.getNumberOfElements()); MeshLib::PropertyVector<int> const*const materialIds = mesh.getProperties().existsPropertyVector<int>("MaterialIDs") ? mesh.getProperties().getPropertyVector<int>("MaterialIDs") : nullptr; for (unsigned i=0; i<nElems; ++i) { auto surfaceId = !materialIds ? 0 : ((*materialIds)[i] - bounds.first); MeshLib::Element* e (elements[i]); if (e->getGeomType() == MeshElemType::TRIANGLE) (*sfcs)[surfaceId]->addTriangle(id_map[e->getNodeIndex(0)], id_map[e->getNodeIndex(1)], id_map[e->getNodeIndex(2)]); if (e->getGeomType() == MeshElemType::QUAD) { (*sfcs)[surfaceId]->addTriangle(id_map[e->getNodeIndex(0)], id_map[e->getNodeIndex(1)], id_map[e->getNodeIndex(2)]); (*sfcs)[surfaceId]->addTriangle(id_map[e->getNodeIndex(0)], id_map[e->getNodeIndex(2)], id_map[e->getNodeIndex(3)]); } // all other element types are ignored (i.e. lines) } std::for_each(sfcs->begin(), sfcs->end(), [](GeoLib::Surface* sfc){ if (sfc->getNumberOfTriangles()==0) delete sfc; sfc = nullptr;}); auto sfcs_end = std::remove(sfcs->begin(), sfcs->end(), nullptr); sfcs->erase(sfcs_end, sfcs->end()); geo_objects.addSurfaceVec(std::move(sfcs), mesh_name); return true; }
MeshLib::Mesh* MeshSurfaceExtraction::getMeshBoundary(const MeshLib::Mesh &mesh) { if (mesh.getDimension()==1) return nullptr; // For 3D meshes return the 2D surface if (mesh.getDimension()==3) { MathLib::Vector3 dir(0,0,0); return getMeshSurface(mesh, dir, 90); } // For 2D meshes return the boundary lines std::vector<MeshLib::Node*> nodes = MeshLib::copyNodeVector(mesh.getNodes()); std::vector<MeshLib::Element*> boundary_elements; std::vector<MeshLib::Element*> const& org_elems (mesh.getElements()); for (auto it=org_elems.begin(); it!=org_elems.end(); ++it) { MeshLib::Element* elem (*it); std::size_t const n_edges (elem->getNEdges()); for (std::size_t i=0; i<n_edges; ++i) if (elem->getNeighbor(i) == nullptr) { MeshLib::Element const*const edge (elem->getEdge(i)); boundary_elements.push_back(MeshLib::copyElement(edge, nodes)); delete edge; } } MeshLib::Mesh* result = new MeshLib::Mesh("Boundary Mesh", nodes, boundary_elements); MeshLib::NodeSearch ns(*result); if (ns.searchUnused() == 0) { return result; } else { auto removed = MeshLib::removeNodes(*result, ns.getSearchedNodeIDs(), result->getName()); delete result; return removed; } }
void Mesh::setElementsConnectedToNodes() { const size_t nElements (_elements.size()); for (unsigned i=0; i<nElements; ++i) { MeshLib::Element* element = _elements[i]; const unsigned nNodes (element->getNNodes()); for (unsigned j=0; j<nNodes; ++j) element->_nodes[j]->addElement(element); } #ifndef NDEBUG // search for nodes that are not part of any element unsigned count(0); const size_t nNodes (_nodes.size()); for (unsigned i=0; i<nNodes; ++i) if (_nodes[i]->getNElements() == 0) { WARN ("Node %d is not part of any element.", i); ++count; } if (count) WARN ("%d unused mesh nodes found.", count); #endif }
PostProcessTool::PostProcessTool( MeshLib::Mesh const& org_mesh, std::vector<MeshLib::Node*> const& vec_fracture_nodes, std::vector<MeshLib::Element*> const& vec_fracutre_matrix_elements) :_org_mesh(org_mesh) { if (!org_mesh.getProperties().hasPropertyVector("displacement") || !org_mesh.getProperties().hasPropertyVector("displacement_jump1") || !org_mesh.getProperties().hasPropertyVector("levelset1") ) { OGS_FATAL("The given mesh does not have relevant properties"); } // clone nodes and elements std::vector<MeshLib::Node*> new_nodes(MeshLib::copyNodeVector(org_mesh.getNodes())); std::vector<MeshLib::Element*> new_eles( MeshLib::copyElementVector(org_mesh.getElements(), new_nodes)); // duplicate fracture nodes for (auto const* org_node : vec_fracture_nodes) { auto duplicated_node = new MeshLib::Node(org_node->getCoords(), new_nodes.size()); new_nodes.push_back(duplicated_node); _map_dup_newNodeIDs[org_node->getID()] = duplicated_node->getID(); } // split elements using the new duplicated nodes auto prop_levelset = org_mesh.getProperties().getPropertyVector<double>("levelset1"); for (auto const* org_e : vec_fracutre_matrix_elements) { // only matrix elements if (org_e->getDimension() != org_mesh.getDimension()) continue; auto const eid = org_e->getID(); // keep original if the element has levelset=0 if ((*prop_levelset)[eid] == 0) continue; // replace fracture nodes with duplicated ones MeshLib::Element* e = new_eles[eid]; for (unsigned i=0; i<e->getNumberOfNodes(); i++) { // only fracture nodes auto itr = _map_dup_newNodeIDs.find(e->getNodeIndex(i)); if (itr == _map_dup_newNodeIDs.end()) continue; // check if a node belongs to the particular fracture group auto itr2 = std::find_if(vec_fracture_nodes.begin(), vec_fracture_nodes.end(), [&](MeshLib::Node const*node) { return node->getID()==e->getNodeIndex(i);}); if (itr2 == vec_fracture_nodes.end()) continue; e->setNode(i, new_nodes[itr->second]); } } // new mesh _output_mesh.reset(new MeshLib::Mesh(org_mesh.getName(), new_nodes, new_eles)); createProperties<int>(); createProperties<double>(); copyProperties<int>(); copyProperties<double>(); calculateTotalDisplacement(); }
bool test(MeshLib::Element const& element) { using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, GlobalDim>; using FemType = NumLib::TemplateIsoparametric<ShapeFunction, ShapeMatricesType>; // Test if the cast is possible. bool const dynamic_cast_failed = dynamic_cast<typename ShapeFunction::MeshElement const*>(&element) == nullptr; EXPECT_FALSE(dynamic_cast_failed); if (dynamic_cast_failed) { return false; } FemType fe{ static_cast<typename ShapeFunction::MeshElement const&>(element)}; bool result = true; // For each node evaluate the shape functions at natural coordinates and // test if only the corresponding shape function has value 1 and all others // must return 0. int const number_nodes = element.getNumberOfNodes(); for (int n = 0; n < number_nodes; ++n) { // Evaluate shape matrices at natural coordinates. typename ShapeMatricesType::ShapeMatrices shape_matrices{ ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS}; // Compute only N, because for pyramid the detJ becomes zero at the // apex, and we only use N in the following test anyway. fe.template computeShapeFunctions<NumLib::ShapeMatrixType::N>( NumLib::NaturalCoordinates< typename ShapeFunction::MeshElement>::coordinates[n] .data(), shape_matrices, GlobalDim, false /* axial symmetry */); auto const& N = shape_matrices.N; for (int p = 0; p < static_cast<int>(ShapeFunction::NPOINTS); ++p) { if (p == n) { if (N[p] != 1) { EXPECT_EQ(1, N[p]) << "for n = " << n << ", p = " << p << " and dimension " << GlobalDim; result = false; } } else { if (N[p] != 0) { EXPECT_EQ(0, N[p]) << "for n = " << n << ", p = " << p << " and dimension " << GlobalDim; result = false; } } } } return result; }
void MeshLayerMapper::addLayerToMesh(const MeshLib::Mesh &dem_mesh, unsigned layer_id, GeoLib::Raster const& raster) { const unsigned pyramid_base[3][4] = { {1, 3, 4, 2}, // Point 4 missing {2, 4, 3, 0}, // Point 5 missing {0, 3, 4, 1}, // Point 6 missing }; std::size_t const nNodes = dem_mesh.getNumberOfNodes(); std::vector<MeshLib::Node*> const& nodes = dem_mesh.getNodes(); int const last_layer_node_offset = layer_id * nNodes; // add nodes for new layer for (std::size_t i=0; i<nNodes; ++i) _nodes.push_back(getNewLayerNode(*nodes[i], *_nodes[last_layer_node_offset + i], raster, _nodes.size())); std::vector<MeshLib::Element*> const& elems = dem_mesh.getElements(); std::size_t const nElems (dem_mesh.getNumberOfElements()); for (std::size_t i=0; i<nElems; ++i) { MeshLib::Element* elem (elems[i]); if (elem->getGeomType() != MeshLib::MeshElemType::TRIANGLE) continue; unsigned node_counter(3), missing_idx(0); std::array<MeshLib::Node*, 6> new_elem_nodes; for (unsigned j=0; j<3; ++j) { new_elem_nodes[j] = _nodes[_nodes[last_layer_node_offset + elem->getNodeIndex(j)]->getID()]; new_elem_nodes[node_counter] = (_nodes[last_layer_node_offset + elem->getNodeIndex(j) + nNodes]); if (new_elem_nodes[j]->getID() != new_elem_nodes[node_counter]->getID()) node_counter++; else missing_idx = j; } switch (node_counter) { case 6: _elements.push_back(new MeshLib::Prism(new_elem_nodes)); _materials.push_back(layer_id); break; case 5: std::array<MeshLib::Node*, 5> pyramid_nodes; pyramid_nodes[0] = new_elem_nodes[pyramid_base[missing_idx][0]]; pyramid_nodes[1] = new_elem_nodes[pyramid_base[missing_idx][1]]; pyramid_nodes[2] = new_elem_nodes[pyramid_base[missing_idx][2]]; pyramid_nodes[3] = new_elem_nodes[pyramid_base[missing_idx][3]]; pyramid_nodes[4] = new_elem_nodes[missing_idx]; _elements.push_back(new MeshLib::Pyramid(pyramid_nodes)); _materials.push_back(layer_id); break; case 4: std::array<MeshLib::Node*, 4> tet_nodes; std::copy(new_elem_nodes.begin(), new_elem_nodes.begin() + node_counter, tet_nodes.begin()); _elements.push_back(new MeshLib::Tet(tet_nodes)); _materials.push_back(layer_id); break; default: continue; } } }