Eigen::ArrayXXi distmesh::utils::findUniqueEdges(Eigen::Ref<Eigen::ArrayXXi const> const triangulation) { // find all unique combinations auto const combinations = nOverK(triangulation.cols(), 2); // find unique edges for all combinations // guarantee direction of edges with lower node index to higher index std::set<std::array<int, 2>> uniqueEdges; std::array<int, 2> edge = {{0, 0}}; for (int combination = 0; combination < combinations.rows(); ++combination) for (int triangle = 0; triangle < triangulation.rows(); ++triangle) { edge[0] = triangulation(triangle, combinations(combination, 0)); edge[1] = triangulation(triangle, combinations(combination, 1)); edge = edge[1] < edge[0] ? std::array<int, 2>{edge[1], edge[0]} : edge; uniqueEdges.insert(edge); } // copy set to eigen array Eigen::ArrayXXi edgeIndices(uniqueEdges.size(), 2); int index = 0; for (auto const& edge : uniqueEdges) { edgeIndices(index, 0) = edge[0]; edgeIndices(index, 1) = edge[1]; index++; } return edgeIndices; }
Eigen::ArrayXXi distmesh::utils::getTriangulationEdgeIndices( Eigen::Ref<Eigen::ArrayXXi const> const triangulation, Eigen::Ref<Eigen::ArrayXXi const> const edges) { // find indices for each edge of triangulation in edge index array Eigen::ArrayXXi edgeIndices(triangulation.rows(), triangulation.cols()); for (int element = 0; element < triangulation.rows(); ++element) for (int node = 0; node < triangulation.cols(); ++node) { // create edge with direction from node with lower index // to node with higher index auto const edge = (Eigen::ArrayXi(2) << triangulation(element, node), triangulation(element, (node + 1) % triangulation.cols())).finished(); // check if edge is in edges list, and get index int edgeIndex = 0; if (((edges.rowwise() - edge.transpose()).square().rowwise().sum().minCoeff(&edgeIndex) == 0) || ((edges.rowwise() - edge.transpose().reverse()).square().rowwise().sum().minCoeff(&edgeIndex) == 0)) { edgeIndices(element, node) = edgeIndex; } } return edgeIndices; }
void Expand(const TriMeshWithTopology& in,Real distance,int divs,TriMesh& m) { Assert(in.tris.size()==in.triNeighbors.size()); Assert(in.verts.size()==in.incidentTris.size()); if(divs > 1) { FatalError("Only support 1 division yet"); } Assert(divs <= 1); vector<TriMeshEdge> edges; vector<IntTriple> edgeIndices(in.tris.size()); GetPairedEdges(in,edges); for(size_t i=0;i<edges.size();i++) { edgeIndices[edges[i].t1][edges[i].e1] = i; edgeIndices[edges[i].t2][edges[i].e2] = i; } vector<Vector3> tripts(in.tris.size()*3); vector<Vector3> vertpts(in.verts.size()); vector<Vector3> edgepts(edges.size()*2); for(size_t i=0;i<in.tris.size();i++) { Vector3 n=in.TriangleNormal(i)*distance; tripts[i*3] = in.TriangleVertex(i,0) + n; tripts[i*3+1] = in.TriangleVertex(i,1) + n; tripts[i*3+2] = in.TriangleVertex(i,2) + n; } for(size_t i=0;i<in.verts.size();i++) { Vector3 n(Zero); for(size_t j=0;j<in.incidentTris[i].size();j++) n+=in.TriangleNormal(in.incidentTris[i][j]); n.inplaceNormalize(); vertpts[i] = in.verts[i] + n * distance; } if(divs >= 1) { for(size_t i=0;i<edges.size();i++) { Vector3 n=in.TriangleNormal(edges[i].t1)+in.TriangleNormal(edges[i].t2); n.inplaceNormalize(); edgepts[i*2] = in.verts[edges[i].v1] + n * distance; edgepts[i*2+1] = in.verts[edges[i].v2] + n * distance; } } m.verts = tripts; ArrayUtils::concat(m.verts,vertpts); ArrayUtils::concat(m.verts,edgepts); m.tris.resize(0); m.tris.reserve(in.tris.size() + 2*(1+divs)*edges.size() + in.verts.size()); //triangle faces for(size_t i=0;i<in.tris.size();i++) m.tris.push_back(IntTriple(i*3,i*3+1,i*3+2)); //vertex faces int k1=(int)tripts.size(); int k2=(int)tripts.size()+(int)vertpts.size(); for(size_t i=0;i<in.verts.size();i++) { if(divs==1) { for(size_t j=0;j<in.incidentTris[i].size();j++) { int t=in.incidentTris[i][j]; int vi=in.tris[t].getIndex(i); Assert(vi >= 0); int e1,e2; edgeIndices[in.incidentTris[i][j]].getCompliment(vi,e1,e2); int flip1 = (edges[e1].v1 == (int)i? 0 : 1); int flip2 = (edges[e2].v1 == (int)i? 0 : 1); m.tris.push_back(IntTriple(k1+i,t*3+vi,k2+e1*2+flip1)); m.tris.push_back(IntTriple(k1+i,k2+e2*2+flip2,t*3+vi)); } } else { vector<int> ring; ring.reserve(in.incidentTris[i].size()); int t0=in.incidentTris[i][0]; while(ring.size() < in.incidentTris[i].size()) { ring.push_back(t0); int vi=in.tris[t0].getIndex(i); t0=in.triNeighbors[t0][(vi+1)%3]; if(ring.size() >= 2) Assert(t0 != ring[ring.size()-2]); } vector<int> v(ring.size()); for(size_t j=0;j<ring.size();j++) { int t=ring[j]; int vi=in.tris[t].getIndex(i); Assert(vi >= 0); v[j] = t*3+vi; } for(size_t j=0;j<ring.size();j++) { int vi=v[j]; int vn=v[(j+1)%ring.size()]; m.tris.push_back(IntTriple(k1+i,vi,vn)); } } } //edge faces for(size_t i=0;i<edges.size();i++) { int v11=(edges[i].e1+1)%3,v12=(edges[i].e1+2)%3; int v21=(edges[i].e2+1)%3,v22=(edges[i].e2+2)%3; int t1=edges[i].t1; int t2=edges[i].t2; int a=t1*3+v11,b=t1*3+v12,c=t2*3+v21,d=t2*3+v22; if(divs==0) { m.tris.push_back(IntTriple(a,c,b)); m.tris.push_back(IntTriple(a,d,c)); } else { int e=k2+i*2; int f=k2+i*2+1; m.tris.push_back(IntTriple(a,f,b)); m.tris.push_back(IntTriple(a,e,f)); m.tris.push_back(IntTriple(e,c,f)); m.tris.push_back(IntTriple(e,d,c)); } } }
bool MeshTopologyTests::testEntityConstraints() { bool success = true; // make two simple meshes MeshTopologyPtr mesh2D = makeRectMesh(0.0, 0.0, 2.0, 1.0, 2, 1); MeshTopologyPtr mesh3D = makeHexMesh(0.0, 0.0, 0.0, 2.0, 4.0, 3.0, 2, 2, 1); unsigned vertexDim = 0; unsigned edgeDim = 1; unsigned faceDim = 2; // first, check that unconstrained edges and faces are unconstrained set< unsigned > boundaryEdges; set< unsigned > internalEdges; for (unsigned cellIndex=0; cellIndex<mesh2D->cellCount(); cellIndex++) { CellPtr cell = mesh2D->getCell(cellIndex); unsigned sideCount = cell->getSideCount(); for (unsigned sideOrdinal=0; sideOrdinal<sideCount; sideOrdinal++) { unsigned edgeIndex = cell->entityIndex(edgeDim, sideOrdinal); unsigned numCells = mesh2D->getActiveCellCount(edgeDim,edgeIndex); if (numCells == 1) // boundary edge { boundaryEdges.insert(edgeIndex); } else if (numCells == 2) { internalEdges.insert(edgeIndex); } else { success = false; cout << "testEntityConstraints: In initial 2D mesh, edge " << edgeIndex << " has active cell count of " << numCells << ".\n"; } } } if (internalEdges.size() != 1) { success = false; cout << "testEntityConstraints: In initial 2D mesh, there are " << internalEdges.size() << " internal edges (expected 1).\n"; } for (set<unsigned>::iterator edgeIt=internalEdges.begin(); edgeIt != internalEdges.end(); edgeIt++) { unsigned edgeIndex = *edgeIt; unsigned constrainingEntityIndex = mesh2D->getConstrainingEntity(edgeDim,edgeIndex).first; if (constrainingEntityIndex != edgeIndex) { success = false; cout << "testEntityConstraints: In initial 2D mesh, internal edge is constrained by a different edge.\n"; } } set<unsigned> boundaryFaces; set<unsigned> internalFaces; map<unsigned, vector<unsigned> > faceToEdges; for (unsigned cellIndex=0; cellIndex<mesh3D->cellCount(); cellIndex++) { CellPtr cell = mesh3D->getCell(cellIndex); unsigned sideCount = cell->getSideCount(); for (unsigned sideOrdinal=0; sideOrdinal<sideCount; sideOrdinal++) { unsigned faceIndex = cell->entityIndex(faceDim, sideOrdinal); unsigned numCells = mesh3D->getActiveCellCount(faceDim,faceIndex); if (numCells == 1) // boundary face { boundaryFaces.insert(faceIndex); } else if (numCells == 2) { internalFaces.insert(faceIndex); } else { success = false; cout << "testEntityConstraints: In initial 3D mesh, face " << faceIndex << " has active cell count of " << numCells << ".\n"; } if (faceToEdges.find(faceIndex) == faceToEdges.end()) { CellTopoPtr faceTopo = cell->topology()->getSubcell(faceDim, sideOrdinal); unsigned numEdges = faceTopo->getSubcellCount(edgeDim); vector<unsigned> edgeIndices(numEdges); for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { edgeIndices[edgeOrdinal] = mesh3D->getFaceEdgeIndex(faceIndex, edgeOrdinal); } } } } if (internalFaces.size() != 4) { success = false; cout << "testEntityConstraints: In initial 3D mesh, there are " << internalFaces.size() << " internal faces (expected 4).\n"; } for (set<unsigned>::iterator faceIt=internalFaces.begin(); faceIt != internalFaces.end(); faceIt++) { unsigned faceIndex = *faceIt; unsigned constrainingEntityIndex = mesh3D->getConstrainingEntity(faceDim,faceIndex).first; if (constrainingEntityIndex != faceIndex) { success = false; cout << "testEntityConstraints: In initial 3D mesh, internal face is constrained by a different face.\n"; } } // now, make a single refinement in each mesh: unsigned cellToRefine2D = 0, cellToRefine3D = 3; mesh2D->refineCell(cellToRefine2D, RefinementPattern::regularRefinementPatternQuad(), mesh2D->cellCount()); mesh3D->refineCell(cellToRefine3D, RefinementPattern::regularRefinementPatternHexahedron(), mesh3D->cellCount()); // printMeshInfo(mesh2D); // figure out which faces/edges were refined and add the corresponding map<unsigned,pair<IndexType,unsigned> > expectedEdgeConstraints2D; set<unsigned> refinedEdges; for (set<unsigned>::iterator edgeIt=boundaryEdges.begin(); edgeIt != boundaryEdges.end(); edgeIt++) { set<unsigned> children = mesh2D->getChildEntitiesSet(edgeDim, *edgeIt); if (children.size() > 0) { refinedEdges.insert(*edgeIt); boundaryEdges.insert(children.begin(), children.end()); } } for (set<unsigned>::iterator edgeIt=internalEdges.begin(); edgeIt != internalEdges.end(); edgeIt++) { set<unsigned> children = mesh2D->getChildEntitiesSet(edgeDim, *edgeIt); if (children.size() > 0) { refinedEdges.insert(*edgeIt); internalEdges.insert(children.begin(), children.end()); for (set<unsigned>::iterator childIt = children.begin(); childIt != children.end(); childIt++) { unsigned childIndex = *childIt; expectedEdgeConstraints2D[childIndex] = make_pair(*edgeIt, edgeDim); } } } // 1 quad refined: expect 4 refined edges if (refinedEdges.size() != 4) { success = false; cout << "After initial refinement, 2D mesh has " << refinedEdges.size() << " refined edges (expected 4).\n"; } checkConstraints(mesh2D, edgeDim, expectedEdgeConstraints2D); set<unsigned> refinedFaces; map<unsigned,pair<IndexType,unsigned> > expectedFaceConstraints3D; map<unsigned,pair<IndexType,unsigned> > expectedEdgeConstraints3D; for (set<unsigned>::iterator faceIt=boundaryFaces.begin(); faceIt != boundaryFaces.end(); faceIt++) { set<unsigned> children = mesh3D->getChildEntitiesSet(faceDim, *faceIt); if (children.size() > 0) { refinedFaces.insert(*faceIt); boundaryFaces.insert(children.begin(), children.end()); } } for (set<unsigned>::iterator faceIt=internalFaces.begin(); faceIt != internalFaces.end(); faceIt++) { vector<unsigned> children = mesh3D->getChildEntities(faceDim, *faceIt); if (children.size() > 0) { refinedFaces.insert(*faceIt); internalFaces.insert(children.begin(), children.end()); for (unsigned childOrdinal = 0; childOrdinal < children.size(); childOrdinal++) { unsigned childIndex = children[childOrdinal]; expectedFaceConstraints3D[childIndex] = make_pair(*faceIt, faceDim); unsigned numEdges = 4; unsigned internalEdgeCount = 0; // for each child of a quad, we expect to have 2 internal edges for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned edgeIndex = mesh3D->getFaceEdgeIndex(childIndex, edgeOrdinal); unsigned activeCellCount = mesh3D->getActiveCellCount(edgeDim, edgeIndex); if (activeCellCount==2) { internalEdgeCount++; expectedEdgeConstraints3D[edgeIndex] = make_pair(*faceIt, faceDim); } else if (activeCellCount==1) // hanging edge { if (! mesh3D->entityHasParent(edgeDim, edgeIndex)) { cout << "Hanging edge with edgeIndex " << edgeIndex << " (in face " << childIndex << ") does not have a parent edge.\n"; cout << "Edge vertices:\n"; mesh3D->printEntityVertices(edgeDim, edgeIndex); cout << "Face vertices:\n"; mesh3D->printEntityVertices(faceDim, childIndex); success = false; } else { unsigned edgeParentIndex = mesh3D->getEntityParent(edgeDim, edgeIndex); expectedEdgeConstraints3D[edgeIndex] = make_pair(edgeParentIndex, edgeDim); } } else { cout << "Unexpected number of active cells: " << activeCellCount << endl; } } if (internalEdgeCount != 2) { cout << "Expected internalEdgeCount to be 2; was " << internalEdgeCount << endl; success = false; } } } } // 1 hex refined: expect 6 refined faces if (refinedFaces.size() != 6) { success = false; cout << "After initial refinement, 3D mesh has " << refinedFaces.size() << " refined faces (expected 6).\n"; } if (! checkConstraints(mesh3D, faceDim, expectedFaceConstraints3D, "refined 3D mesh") ) { cout << "Failed face constraint check for refined 3D mesh." << endl; success = false; } if (! checkConstraints(mesh3D, edgeDim, expectedEdgeConstraints3D, "refined 3D mesh") ) { cout << "Failed edge constraint check for refined 3D mesh." << endl; success = false; } // now, we refine one of the children of the refined cells in each mesh, to produce a 2-level constraint set<unsigned> edgeChildren2D; set<unsigned> cellsForEdgeChildren2D; for (map<unsigned,pair<IndexType,unsigned> >::iterator edgeConstraint=expectedEdgeConstraints2D.begin(); edgeConstraint != expectedEdgeConstraints2D.end(); edgeConstraint++) { edgeChildren2D.insert(edgeConstraint->first); unsigned cellIndex = mesh2D->getActiveCellIndices(edgeDim, edgeConstraint->first).begin()->first; cellsForEdgeChildren2D.insert(cellIndex); // cout << "cellsForEdgeChildren2D: " << cellIndex << endl; } // one of these has (1,0) as one of its vertices. Let's figure out which one: unsigned vertexIndex; if (! mesh2D->getVertexIndex(makeVertex(1, 0), vertexIndex) ) { cout << "Error: vertex not found.\n"; success = false; } vector< pair<unsigned,unsigned> > cellsForVertex = mesh2D->getActiveCellIndices(vertexDim, vertexIndex); if (cellsForVertex.size() != 2) { cout << "cellsForVertex should have 2 entries; has " << cellsForVertex.size() << endl; success = false; } unsigned childCellForVertex, childCellConstrainedEdge; set<unsigned> childNewlyConstrainingEdges; // the two interior edges that we break for (vector< pair<unsigned,unsigned> >::iterator cellIt=cellsForVertex.begin(); cellIt != cellsForVertex.end(); cellIt++) { // cout << "cellsForVertex: " << cellIt->first << endl; if ( cellsForEdgeChildren2D.find( cellIt->first ) != cellsForEdgeChildren2D.end() ) { // found match childCellForVertex = cellIt->first; // now, figure out which of the "edgeChildren2D" is shared by this cell: CellPtr cell = mesh2D->getCell(childCellForVertex); unsigned numEdges = cell->getSideCount(); for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned edgeIndex = cell->entityIndex(edgeDim, edgeOrdinal); if (edgeChildren2D.find(edgeIndex) != edgeChildren2D.end()) { childCellConstrainedEdge = edgeIndex; } else if ( mesh2D->getActiveCellCount(edgeDim, edgeIndex) == 2 ) { childNewlyConstrainingEdges.insert(edgeIndex); } } } } if (childNewlyConstrainingEdges.size() != 2) { cout << "Expected 2 newly constraining edges after 2nd refinement of 2D mesh, but found " << childNewlyConstrainingEdges.size() << endl; success = false; } // refine the cell that matches (1,0): mesh2D->refineCell(childCellForVertex, RefinementPattern::regularRefinementPatternQuad(), mesh2D->cellCount()); // now, fix the expected edge constraints, then check them... set<unsigned> childEdges = mesh2D->getChildEntitiesSet(edgeDim, childCellConstrainedEdge); if (childEdges.size() != 2) { cout << "Expected 2 child edges, but found " << childEdges.size() << ".\n"; success = false; } for (set<unsigned>::iterator edgeIt = childEdges.begin(); edgeIt != childEdges.end(); edgeIt++) { expectedEdgeConstraints2D[*edgeIt] = expectedEdgeConstraints2D[childCellConstrainedEdge]; } expectedEdgeConstraints2D.erase(childCellConstrainedEdge); for (set<unsigned>::iterator edgeIt = childNewlyConstrainingEdges.begin(); edgeIt != childNewlyConstrainingEdges.end(); edgeIt++) { set<unsigned> newChildEdges = mesh2D->getChildEntitiesSet(edgeDim, *edgeIt); for (set<unsigned>::iterator newEdgeIt = newChildEdges.begin(); newEdgeIt != newChildEdges.end(); newEdgeIt++) { expectedEdgeConstraints2D[*newEdgeIt] = make_pair(*edgeIt,edgeDim); } } if (! checkConstraints(mesh2D, edgeDim, expectedEdgeConstraints2D, "twice-refined 2D mesh") ) { cout << "Failed constraint check for twice-refined 2D mesh." << endl; success = false; } // now, do a second level of refinement for 3D mesh // one of these has (1,2,0) as one of its vertices. Let's figure out which one: if (! mesh3D->getVertexIndex(makeVertex(1, 2, 0), vertexIndex) ) { cout << "Error: vertex not found.\n"; success = false; } cellsForVertex = mesh3D->getActiveCellIndices(vertexDim, vertexIndex); if (cellsForVertex.size() != 4) { cout << "cellsForVertex should have 4 entries; has " << cellsForVertex.size() << endl; success = false; } vector<unsigned> justCellsForVertex; for (vector< pair<unsigned,unsigned> >::iterator entryIt = cellsForVertex.begin(); entryIt != cellsForVertex.end(); entryIt++) { justCellsForVertex.push_back(entryIt->first); } vector<unsigned> childCellIndices = mesh3D->getCell(cellToRefine3D)->getChildIndices(mesh3D); std::sort(childCellIndices.begin(), childCellIndices.end()); vector<unsigned> matches(childCellIndices.size() + cellsForVertex.size()); vector<unsigned>::iterator matchEnd = std::set_intersection(justCellsForVertex.begin(), justCellsForVertex.end(), childCellIndices.begin(), childCellIndices.end(), matches.begin()); matches.resize(matchEnd-matches.begin()); if (matches.size() != 1) { cout << "matches should have exactly one entry, but has " << matches.size(); success = false; } unsigned childCellIndex = matches[0]; CellPtr childCell = mesh3D->getCell(childCellIndex); set<unsigned> childInteriorUnconstrainedFaces; set<unsigned> childInteriorConstrainedFaces; unsigned faceCount = childCell->getSideCount(); for (unsigned faceOrdinal=0; faceOrdinal<faceCount; faceOrdinal++) { unsigned faceIndex = childCell->entityIndex(faceDim, faceOrdinal); if (mesh3D->getActiveCellCount(faceDim, faceIndex) == 1) { // that's an interior constrained face, or a boundary face if (expectedFaceConstraints3D.find(faceIndex) != expectedFaceConstraints3D.end()) { // constrained face childInteriorConstrainedFaces.insert(faceIndex); } } else if (mesh3D->getActiveCellCount(faceDim, faceIndex) == 2) { // an interior unconstrained face childInteriorUnconstrainedFaces.insert(faceIndex); } else { cout << "Error: unexpected active cell count. Expected 1 or 2, but was " << mesh3D->getActiveCellCount(faceDim, faceIndex) << endl; success = false; } } // Camellia::print("childInteriorUnconstrainedFaces", childInteriorUnconstrainedFaces); // Camellia::print("childInteriorConstrainedFaces", childInteriorConstrainedFaces); mesh3D->refineCell(childCellIndex, RefinementPattern::regularRefinementPatternHexahedron(), mesh3D->cellCount()); // update expected face and edge constraints // set<unsigned> edgeConstraintsToDrop; for (set<unsigned>::iterator faceIt=childInteriorConstrainedFaces.begin(); faceIt != childInteriorConstrainedFaces.end(); faceIt++) { unsigned faceIndex = *faceIt; set<unsigned> newChildFaces = mesh3D->getChildEntitiesSet(faceDim, faceIndex); for (set<unsigned>::iterator newChildIt=newChildFaces.begin(); newChildIt != newChildFaces.end(); newChildIt++) { unsigned newChildIndex = *newChildIt; expectedFaceConstraints3D[newChildIndex] = expectedFaceConstraints3D[faceIndex]; // cout << "Expecting two-level face constraint: face " << newChildIndex << " constrained by face " << expectedFaceConstraints3D[newChildIndex].first << endl; } unsigned numEdges = mesh3D->getSubEntityCount(faceDim, faceIndex, edgeDim); set<IndexType> childEdgesOnParentBoundary; for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned edgeIndex = mesh3D->getSubEntityIndex(faceDim, faceIndex, edgeDim, edgeOrdinal); set<unsigned> newChildEdges = mesh3D->getChildEntitiesSet(edgeDim, edgeIndex); for (set<unsigned>::iterator newChildIt=newChildEdges.begin(); newChildIt != newChildEdges.end(); newChildIt++) { unsigned newChildIndex = *newChildIt; expectedEdgeConstraints3D[newChildIndex] = expectedEdgeConstraints3D[edgeIndex]; // cout << "Expecting two-level edge constraint: edge " << newChildIndex << " constrained by "; // cout << typeString(expectedEdgeConstraints3D[newChildIndex].second) << " " << expectedEdgeConstraints3D[newChildIndex].first << endl; childEdgesOnParentBoundary.insert(newChildIndex); // edgeConstraintsToDrop.insert(edgeIndex); } } for (set<unsigned>::iterator newChildIt=newChildFaces.begin(); newChildIt != newChildFaces.end(); newChildIt++) { unsigned newChildFaceIndex = *newChildIt; int numEdges = mesh3D->getSubEntityCount(faceDim, newChildFaceIndex, edgeDim); for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned newChildEdgeIndex = mesh3D->getSubEntityIndex(faceDim, newChildFaceIndex, edgeDim, edgeOrdinal); if (childEdgesOnParentBoundary.find(newChildEdgeIndex) == childEdgesOnParentBoundary.end()) { expectedEdgeConstraints3D[newChildEdgeIndex] = expectedFaceConstraints3D[faceIndex]; } } } expectedFaceConstraints3D.erase(faceIndex); } // for (set<unsigned>::iterator edgeToDropIt=edgeConstraintsToDrop.begin(); edgeToDropIt != edgeConstraintsToDrop.end(); edgeToDropIt++) { // expectedEdgeConstraints3D.erase(*edgeToDropIt); // } for (set<unsigned>::iterator faceIt=childInteriorUnconstrainedFaces.begin(); faceIt != childInteriorUnconstrainedFaces.end(); faceIt++) { unsigned faceIndex = *faceIt; set<unsigned> newChildFaces = mesh3D->getChildEntitiesSet(faceDim, faceIndex); for (set<unsigned>::iterator newChildIt=newChildFaces.begin(); newChildIt != newChildFaces.end(); newChildIt++) { unsigned newChildIndex = *newChildIt; expectedFaceConstraints3D[newChildIndex] = make_pair(faceIndex, faceDim); } expectedFaceConstraints3D.erase(faceIndex); unsigned numEdges = mesh3D->getSubEntityCount(faceDim, faceIndex, edgeDim); set<IndexType> childEdgesOnParentBoundary; for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned edgeIndex = mesh3D->getSubEntityIndex(faceDim, faceIndex, edgeDim, edgeOrdinal); set<unsigned> newChildEdges = mesh3D->getChildEntitiesSet(edgeDim, edgeIndex); for (set<unsigned>::iterator newChildIt=newChildEdges.begin(); newChildIt != newChildEdges.end(); newChildIt++) { unsigned newChildIndex = *newChildIt; if (expectedEdgeConstraints3D.find(newChildIndex) == expectedEdgeConstraints3D.end()) // only impose edge constraint if there is not one already present { expectedEdgeConstraints3D[newChildIndex] = make_pair(edgeIndex,edgeDim); } childEdgesOnParentBoundary.insert(newChildIndex); } } for (set<unsigned>::iterator newChildIt=newChildFaces.begin(); newChildIt != newChildFaces.end(); newChildIt++) { unsigned newChildFaceIndex = *newChildIt; int numEdges = mesh3D->getSubEntityCount(faceDim, newChildFaceIndex, edgeDim); for (unsigned edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++) { unsigned newChildEdgeIndex = mesh3D->getSubEntityIndex(faceDim, newChildFaceIndex, edgeDim, edgeOrdinal); if (childEdgesOnParentBoundary.find(newChildEdgeIndex) == childEdgesOnParentBoundary.end()) { if (expectedEdgeConstraints3D.find(newChildEdgeIndex) == expectedEdgeConstraints3D.end()) // only impose edge constraint if there is not one already present { expectedEdgeConstraints3D[newChildEdgeIndex] = make_pair(faceIndex, faceDim); } } } } } if (! checkConstraints(mesh3D, edgeDim, expectedEdgeConstraints3D, "twice-refined 3D mesh") ) { cout << "Failed edge constraint check for twice-refined 3D mesh." << endl; success = false; } if (! checkConstraints(mesh3D, faceDim, expectedFaceConstraints3D, "twice-refined 3D mesh") ) { cout << "Failed face constraint check for twice-refined 3D mesh." << endl; success = false; } return success; }