bool MeshTestUtility::neighborBasesAgreeOnSides(Teuchos::RCP<Mesh> mesh, Epetra_MultiVector &globalSolutionCoefficients) { bool success = true; MeshTopologyViewPtr meshTopo = mesh->getTopology(); int spaceDim = meshTopo->getDimension(); set<IndexType> activeCellIndices = meshTopo->getActiveCellIndices(); for (set<IndexType>::iterator cellIt=activeCellIndices.begin(); cellIt != activeCellIndices.end(); cellIt++) { IndexType cellIndex = *cellIt; CellPtr cell = meshTopo->getCell(cellIndex); BasisCachePtr fineCellBasisCache = BasisCache::basisCacheForCell(mesh, cellIndex); ElementTypePtr fineElemType = mesh->getElementType(cellIndex); DofOrderingPtr fineElemTrialOrder = fineElemType->trialOrderPtr; FieldContainer<double> fineSolutionCoefficients(fineElemTrialOrder->totalDofs()); mesh->globalDofAssignment()->interpretGlobalCoefficients(cellIndex, fineSolutionCoefficients, globalSolutionCoefficients); // if ((cellIndex==0) || (cellIndex==2)) { // cout << "MeshTestUtility: local coefficients for cell " << cellIndex << ":\n" << fineSolutionCoefficients; // } unsigned sideCount = cell->getSideCount(); for (unsigned sideOrdinal=0; sideOrdinal<sideCount; sideOrdinal++) { FieldContainer<double> fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints; bool hasCoarserNeighbor = determineRefTestPointsForNeighbors(meshTopo, cell, sideOrdinal, fineSideRefPoints, fineCellRefPoints, coarseSideRefPoints, coarseCellRefPoints); if (!hasCoarserNeighbor) continue; pair<GlobalIndexType, unsigned> neighborInfo = cell->getNeighborInfo(sideOrdinal, meshTopo); CellPtr neighborCell = meshTopo->getCell(neighborInfo.first); unsigned numTestPoints = coarseCellRefPoints.dimension(0); // cout << "testing neighbor agreement between cell " << cellIndex << " and " << neighborCell->cellIndex() << endl; // if we get here, the cell has a neighbor on this side, and is at least as fine as that neighbor. BasisCachePtr fineSideBasisCache = fineCellBasisCache->getSideBasisCache(sideOrdinal); fineCellBasisCache->setRefCellPoints(fineCellRefPoints); BasisCachePtr coarseCellBasisCache = BasisCache::basisCacheForCell(mesh, neighborInfo.first); BasisCachePtr coarseSideBasisCache = coarseCellBasisCache->getSideBasisCache(neighborInfo.second); coarseCellBasisCache->setRefCellPoints(coarseCellRefPoints); bool hasSidePoints = (fineSideRefPoints.size() > 0); if (hasSidePoints) { fineSideBasisCache->setRefCellPoints(fineSideRefPoints); coarseSideBasisCache->setRefCellPoints(coarseSideRefPoints); } // sanity check: do physical points match? FieldContainer<double> fineCellPhysicalCubaturePoints = fineCellBasisCache->getPhysicalCubaturePoints(); FieldContainer<double> coarseCellPhysicalCubaturePoints = coarseCellBasisCache->getPhysicalCubaturePoints(); double tol = 1e-14; double maxDiff = 0; if (! fcsAgree(coarseCellPhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse cell cubature points do not agree.\n"; success = false; continue; } if (hasSidePoints) { FieldContainer<double> fineSidePhysicalCubaturePoints = fineSideBasisCache->getPhysicalCubaturePoints(); FieldContainer<double> coarseSidePhysicalCubaturePoints = coarseSideBasisCache->getPhysicalCubaturePoints(); double tol = 1e-14; double maxDiff = 0; if (! fcsAgree(fineSidePhysicalCubaturePoints, fineCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine side and cell cubature points do not agree.\n"; success = false; continue; } if (! fcsAgree(coarseSidePhysicalCubaturePoints, coarseCellPhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: coarse side and cell cubature points do not agree.\n"; success = false; continue; } if (! fcsAgree(coarseSidePhysicalCubaturePoints, fineSidePhysicalCubaturePoints, tol, maxDiff) ) { cout << "ERROR: MeshTestUtility::neighborBasesAgreeOnSides internal error: fine and coarse side cubature points do not agree.\n"; success = false; continue; } } ElementTypePtr coarseElementType = mesh->getElementType(neighborInfo.first); DofOrderingPtr coarseElemTrialOrder = coarseElementType->trialOrderPtr; FieldContainer<double> coarseSolutionCoefficients(coarseElemTrialOrder->totalDofs()); mesh->globalDofAssignment()->interpretGlobalCoefficients(neighborInfo.first, coarseSolutionCoefficients, globalSolutionCoefficients); set<int> varIDs = fineElemTrialOrder->getVarIDs(); for (set<int>::iterator varIt = varIDs.begin(); varIt != varIDs.end(); varIt++) { int varID = *varIt; // cout << "MeshTestUtility: varID " << varID << ":\n"; bool isTraceVar = mesh->bilinearForm()->isFluxOrTrace(varID); BasisPtr fineBasis, coarseBasis; BasisCachePtr fineCache, coarseCache; if (isTraceVar) { if (! hasSidePoints) continue; // then nothing to do for traces fineBasis = fineElemTrialOrder->getBasis(varID, sideOrdinal); coarseBasis = coarseElemTrialOrder->getBasis(varID, neighborInfo.second); fineCache = fineSideBasisCache; coarseCache = coarseSideBasisCache; } else { fineBasis = fineElemTrialOrder->getBasis(varID); coarseBasis = coarseElemTrialOrder->getBasis(varID); fineCache = fineCellBasisCache; coarseCache = coarseCellBasisCache; Camellia::EFunctionSpace fs = fineBasis->functionSpace(); if ((fs == Camellia::FUNCTION_SPACE_HVOL) || (fs == Camellia::FUNCTION_SPACE_VECTOR_HVOL) || (fs == Camellia::FUNCTION_SPACE_TENSOR_HVOL)) { // volume L^2 basis: no continuities expected... continue; } } FieldContainer<double> localValuesFine = *fineCache->getTransformedValues(fineBasis, OP_VALUE); FieldContainer<double> localValuesCoarse = *coarseCache->getTransformedValues(coarseBasis, OP_VALUE); bool scalarValued = (localValuesFine.rank() == 3); // the following used if vector or tensor-valued: Teuchos::Array<int> valueDim; unsigned componentsPerValue = 1; FieldContainer<double> valueContainer; // just used for enumeration computation... if (!scalarValued) { localValuesFine.dimensions(valueDim); // clear first three: valueDim.erase(valueDim.begin()); valueDim.erase(valueDim.begin()); valueDim.erase(valueDim.begin()); valueContainer.resize(valueDim); componentsPerValue = valueContainer.size(); } // if (localValuesFine.rank() != 3) { // cout << "WARNING: MeshTestUtility::neighborBasesAgreeOnSides() only supports scalar-valued bases right now. Skipping check for varID " << varID << endl; // continue; // } FieldContainer<double> localPointValuesFine(fineElemTrialOrder->totalDofs()); FieldContainer<double> localPointValuesCoarse(coarseElemTrialOrder->totalDofs()); for (int valueComponentOrdinal=0; valueComponentOrdinal<componentsPerValue; valueComponentOrdinal++) { Teuchos::Array<int> valueMultiIndex(valueContainer.rank()); if (!scalarValued) valueContainer.getMultiIndex(valueMultiIndex, valueComponentOrdinal); Teuchos::Array<int> localValuesMultiIndex(localValuesFine.rank()); for (int r=0; r<valueMultiIndex.size(); r++) { localValuesMultiIndex[r+3] = valueMultiIndex[r]; } for (int ptOrdinal=0; ptOrdinal<numTestPoints; ptOrdinal++) { localPointValuesCoarse.initialize(0); localPointValuesFine.initialize(0); localValuesMultiIndex[2] = ptOrdinal; double fineSolutionValue = 0, coarseSolutionValue = 0; for (int basisOrdinal=0; basisOrdinal < fineBasis->getCardinality(); basisOrdinal++) { int fineDofIndex; if (isTraceVar) fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal, sideOrdinal); else fineDofIndex = fineElemTrialOrder->getDofIndex(varID, basisOrdinal); if (scalarValued) { localPointValuesFine(fineDofIndex) = localValuesFine(0,basisOrdinal,ptOrdinal); } else { localValuesMultiIndex[1] = basisOrdinal; localPointValuesFine(fineDofIndex) = localValuesFine.getValue(localValuesMultiIndex); } fineSolutionValue += fineSolutionCoefficients(fineDofIndex) * localPointValuesFine(fineDofIndex); } for (int basisOrdinal=0; basisOrdinal < coarseBasis->getCardinality(); basisOrdinal++) { int coarseDofIndex; if (isTraceVar) coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal, neighborInfo.second); else coarseDofIndex = coarseElemTrialOrder->getDofIndex(varID, basisOrdinal); if (scalarValued) { localPointValuesCoarse(coarseDofIndex) = localValuesCoarse(0,basisOrdinal,ptOrdinal); } else { localValuesMultiIndex[1] = basisOrdinal; localPointValuesCoarse(coarseDofIndex) = localValuesCoarse.getValue(localValuesMultiIndex); } coarseSolutionValue += coarseSolutionCoefficients(coarseDofIndex) * localPointValuesCoarse(coarseDofIndex); } if (abs(coarseSolutionValue - fineSolutionValue) > 1e-13) { success = false; cout << "coarseSolutionValue (" << coarseSolutionValue << ") and fineSolutionValue (" << fineSolutionValue << ") differ by " << abs(coarseSolutionValue - fineSolutionValue); cout << " at point " << ptOrdinal << " for varID " << varID << ". "; cout << "This may be an indication that something is amiss with the global-to-local map.\n"; } else { // // DEBUGGING: // cout << "solution value at point ("; // for (int d=0; d<spaceDim-1; d++) { // cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,d) << ", "; // } // cout << fineSidePhysicalCubaturePoints(0,ptOrdinal,spaceDim-1) << "): "; // cout << coarseSolutionValue << endl; } FieldContainer<double> globalValuesFromFine, globalValuesFromCoarse; FieldContainer<GlobalIndexType> globalDofIndicesFromFine, globalDofIndicesFromCoarse; mesh->globalDofAssignment()->interpretLocalData(cellIndex, localPointValuesFine, globalValuesFromFine, globalDofIndicesFromFine); mesh->globalDofAssignment()->interpretLocalData(neighborInfo.first, localPointValuesCoarse, globalValuesFromCoarse, globalDofIndicesFromCoarse); std::map<GlobalIndexType, double> fineValuesMap; std::map<GlobalIndexType, double> coarseValuesMap; for (int i=0; i<globalDofIndicesFromCoarse.size(); i++) { GlobalIndexType globalDofIndex = globalDofIndicesFromCoarse[i]; coarseValuesMap[globalDofIndex] = globalValuesFromCoarse[i]; } double maxDiff = 0; for (int i=0; i<globalDofIndicesFromFine.size(); i++) { GlobalIndexType globalDofIndex = globalDofIndicesFromFine[i]; fineValuesMap[globalDofIndex] = globalValuesFromFine[i]; double diff = abs( fineValuesMap[globalDofIndex] - coarseValuesMap[globalDofIndex]); maxDiff = std::max(diff, maxDiff); if (diff > tol) { success = false; cout << "interpreted fine and coarse disagree at point ("; for (int d=0; d<spaceDim; d++) { cout << fineCellPhysicalCubaturePoints(0,ptOrdinal,d); if (d==spaceDim-1) cout << ").\n"; else cout << ", "; } } } if (maxDiff > tol) { cout << "maxDiff: " << maxDiff << endl; cout << "globalValuesFromFine:\n" << globalValuesFromFine; cout << "globalValuesFromCoarse:\n" << globalValuesFromCoarse; cout << "globalDofIndicesFromFine:\n" << globalDofIndicesFromFine; cout << "globalDofIndicesFromCoarse:\n" << globalDofIndicesFromCoarse; continue; // only worth testing further if we passed the above } } } } } } // cout << "Completed neighborBasesAgreeOnSides.\n"; return success; }
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; }