// Write set to VTK readable files void writeVTK ( const polyMesh& mesh, const topoSet& currentSet, const fileName& vtkName ) { if (isA<faceSet>(currentSet)) { // Faces of set with OpenFOAM faceID as value faceList setFaces(currentSet.size()); labelList faceValues(currentSet.size()); label setFaceI = 0; forAllConstIter(topoSet, currentSet, iter) { setFaces[setFaceI] = mesh.faces()[iter.key()]; faceValues[setFaceI] = iter.key(); setFaceI++; } primitiveFacePatch fp(setFaces, mesh.points()); writePatch ( true, currentSet.name(), fp, "faceID", faceValues, mesh.time().path()/vtkName ); }
Foam::labelList Foam::meshToMesh::maskCells ( const polyMesh& src, const polyMesh& tgt ) const { boundBox intersectBb ( max(src.bounds().min(), tgt.bounds().min()), min(src.bounds().max(), tgt.bounds().max()) ); intersectBb.inflate(0.01); const cellList& srcCells = src.cells(); const faceList& srcFaces = src.faces(); const pointField& srcPts = src.points(); DynamicList<label> cells(src.size()); forAll(srcCells, srcI) { boundBox cellBb(srcCells[srcI].points(srcFaces, srcPts), false); if (intersectBb.overlaps(cellBb)) { cells.append(srcI); } }
bool Foam::meshStructure::isStructuredCell ( const polyMesh& mesh, const label layerI, const label cellI ) const { const cell& cFaces = mesh.cells()[cellI]; // Count number of side faces label nSide = 0; forAll(cFaces, i) { if (faceToPatchEdgeAddressing_[cFaces[i]] != -1) { nSide++; } } if (nSide != cFaces.size()-2) { return false; } // Check that side faces have correct point layers forAll(cFaces, i) { if (faceToPatchEdgeAddressing_[cFaces[i]] != -1) { const face& f = mesh.faces()[cFaces[i]]; label nLayer = 0; label nLayerPlus1 = 0; forAll(f, fp) { label pointI = f[fp]; if (pointLayer_[pointI] == layerI) { nLayer++; } else if (pointLayer_[pointI] == layerI+1) { nLayerPlus1++; } } if (f.size() != 4 || (nLayer+nLayerPlus1 != 4)) { return false; } } }
Foam::Cloud<ParticleType>::Cloud ( const polyMesh& pMesh, const IDLList<ParticleType>& particles ) : cloud(pMesh), IDLList<ParticleType>(particles), polyMesh_(pMesh), allFaces_(pMesh.faces()), points_(pMesh.points()), cellFaces_(pMesh.cells()), allFaceCentres_(pMesh.faceCentres()), owner_(pMesh.faceOwner()), neighbour_(pMesh.faceNeighbour()), meshInfo_(polyMesh_) {}
// Determines face blocking void Foam::channelIndex::walkOppositeFaces ( const polyMesh& mesh, const labelList& startFaces, boolList& blockedFace ) { const cellList& cells = mesh.cells(); const faceList& faces = mesh.faces(); label nBnd = mesh.nFaces() - mesh.nInternalFaces(); DynamicList<label> frontFaces(startFaces); forAll(frontFaces, i) { label facei = frontFaces[i]; blockedFace[facei] = true; }
Foam::Cloud<ParticleType>::Cloud ( const polyMesh& pMesh, const bool checkClass ) : cloud(pMesh), polyMesh_(pMesh), allFaces_(pMesh.faces()), points_(pMesh.points()), cellFaces_(pMesh.cells()), allFaceCentres_(pMesh.faceCentres()), owner_(pMesh.faceOwner()), neighbour_(pMesh.faceNeighbour()), meshInfo_(polyMesh_) { initCloud(checkClass); }
void Foam::meshToMeshNew::writeConnectivity ( const polyMesh& src, const polyMesh& tgt, const labelListList& srcToTargetAddr ) const { Pout<< "Source size = " << src.nCells() << endl; Pout<< "Target size = " << tgt.nCells() << endl; word fName("addressing_" + src.name() + "_to_" + tgt.name()); if (Pstream::parRun()) { fName = fName + "_proc" + Foam::name(Pstream::myProcNo()); } OFstream os(src.time().path()/fName + ".obj"); label vertI = 0; forAll(srcToTargetAddr, i) { const labelList& tgtAddress = srcToTargetAddr[i]; forAll(tgtAddress, j) { label tgtI = tgtAddress[j]; const vector& c0 = src.cellCentres()[i]; const cell& c = tgt.cells()[tgtI]; const pointField pts(c.points(tgt.faces(), tgt.points())); forAll(pts, j) { const point& p = pts[j]; os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl; vertI++; os << "v " << c0.x() << ' ' << c0.y() << ' ' << c0.z() << nl; vertI++; os << "l " << vertI - 1 << ' ' << vertI << nl; } } }
// Split hex (and hex only) along edgeI creating two prisms bool splitHex ( const polyMesh& mesh, const label celli, const label edgeI, DynamicList<label>& cutCells, DynamicList<labelList>& cellLoops, DynamicList<scalarField>& cellEdgeWeights ) { // cut handling functions edgeVertex ev(mesh); const edgeList& edges = mesh.edges(); const faceList& faces = mesh.faces(); const edge& e = edges[edgeI]; // Get faces on the side, i.e. faces not using edge but still using one of // the edge endpoints. label leftI = -1; label rightI = -1; label leftFp = -1; label rightFp = -1; const cell& cFaces = mesh.cells()[celli]; forAll(cFaces, i) { label facei = cFaces[i]; const face& f = faces[facei]; label fp0 = findIndex(f, e[0]); label fp1 = findIndex(f, e[1]); if (fp0 == -1) { if (fp1 != -1) { // Face uses e[1] but not e[0] rightI = facei; rightFp = fp1; if (leftI != -1) { // Have both faces so exit break; } } } else { if (fp1 != -1) { // Face uses both e[1] and e[0] } else { leftI = facei; leftFp = fp0; if (rightI != -1) { break; } } } }
Foam::label Foam::polyMeshTetDecomposition::findSharedBasePoint ( const polyMesh& mesh, label fI, const point& nCc, scalar tol, bool report ) { const faceList& pFaces = mesh.faces(); const pointField& pPts = mesh.points(); const vectorField& pC = mesh.cellCentres(); const labelList& pOwner = mesh.faceOwner(); const face& f = pFaces[fI]; label oCI = pOwner[fI]; const point& oCc = pC[oCI]; List<scalar> tetQualities(2, 0.0); forAll(f, faceBasePtI) { scalar thisBaseMinTetQuality = VGREAT; const point& tetBasePt = pPts[f[faceBasePtI]]; for (label tetPtI = 1; tetPtI < f.size() - 1; tetPtI++) { label facePtI = (tetPtI + faceBasePtI) % f.size(); label otherFacePtI = f.fcIndex(facePtI); { // owner cell tet label ptAI = f[facePtI]; label ptBI = f[otherFacePtI]; const point& pA = pPts[ptAI]; const point& pB = pPts[ptBI]; tetPointRef tet(oCc, tetBasePt, pA, pB); tetQualities[0] = tet.quality(); } { // neighbour cell tet label ptAI = f[otherFacePtI]; label ptBI = f[facePtI]; const point& pA = pPts[ptAI]; const point& pB = pPts[ptBI]; tetPointRef tet(nCc, tetBasePt, pA, pB); tetQualities[1] = tet.quality(); } if (min(tetQualities) < thisBaseMinTetQuality) { thisBaseMinTetQuality = min(tetQualities); } } if (thisBaseMinTetQuality > tol) { return faceBasePtI; } }
void Foam::cellPointWeight::findTriangle ( const polyMesh& mesh, const vector& position, const label faceIndex ) { if (debug) { Pout<< "\nbool Foam::cellPointWeight::findTriangle" << nl << "position = " << position << nl << "faceIndex = " << faceIndex << endl; } // Initialise closest triangle variables scalar minUVClose = VGREAT; label pointIClose = 0; // Decompose each face into triangles, making a tet when // augmented by the cell centre const labelList& facePoints = mesh.faces()[faceIndex]; const scalar faceArea2 = magSqr(mesh.faceAreas()[faceIndex]); label pointI = 1; while ((pointI + 1) < facePoints.size()) { // Cartesian co-ordinates of the triangle vertices const vector& P1 = mesh.points()[facePoints[0]]; const vector& P2 = mesh.points()[facePoints[pointI]]; const vector& P3 = mesh.points()[facePoints[pointI + 1]]; // Direction vectors vector v1 = position - P1; const vector v2 = P2 - P1; const vector v3 = P3 - P1; // Plane normal vector n = v2 ^ v3; n /= mag(n); // Remove any offset to plane v1 -= (n & v1)*v1; // Helper variables const scalar d12 = v1 & v2; const scalar d13 = v1 & v3; const scalar d22 = v2 & v2; const scalar d23 = v2 & v3; const scalar d33 = v3 & v3; // Determinant of coefficients matrix // Note: if det(A) = 0 the triangle is degenerate const scalar detA = d22*d33 - d23*d23; if (0.25*detA/faceArea2 > tol) { // Solve using Cramers' rule const scalar u = (d12*d33 - d23*d13)/detA; const scalar v = (d22*d13 - d12*d23)/detA; // Check if point is in triangle if ((u + tol > 0) && (v + tol > 0) && (u + v < 1 + tol)) { // Indices of the cell vertices making up the triangle faceVertices_[0] = facePoints[0]; faceVertices_[1] = facePoints[pointI]; faceVertices_[2] = facePoints[pointI + 1]; weights_[0] = u; weights_[1] = v; weights_[2] = 1.0 - (u + v); weights_[3] = 0.0; return; } else { scalar minU = mag(u); scalar minV = mag(v); if (minU > 1.0) { minU -= 1.0; } if (minV > 1.0) { minV -= 1.0; } const scalar minUV = mag(minU + minV); if (minUV < minUVClose) { minUVClose = minUV; pointIClose = pointI; } } } pointI++; } if (debug) { Pout<< "Foam::cellPointWeight::findTriangle" << "Triangle search failed; using closest triangle to point" << nl << " cell face: " << faceIndex << nl << endl; } // Indices of the cell vertices making up the triangle faceVertices_[0] = facePoints[0]; faceVertices_[1] = facePoints[pointIClose]; faceVertices_[2] = facePoints[pointIClose + 1]; weights_[0] = 1.0/3.0; weights_[1] = 1.0/3.0; weights_[2] = 1.0/3.0; weights_[3] = 0.0; }
void insertDuplicateMerge ( const polyMesh& mesh, const labelList& duplicates, polyTopoChange& meshMod ) { const faceList& faces = mesh.faces(); const labelList& faceOwner = mesh.faceOwner(); const faceZoneMesh& faceZones = mesh.faceZones(); forAll(duplicates, bFacei) { label otherFacei = duplicates[bFacei]; if (otherFacei != -1 && otherFacei > bFacei) { // Two duplicate faces. Merge. label face0 = mesh.nInternalFaces() + bFacei; label face1 = mesh.nInternalFaces() + otherFacei; label own0 = faceOwner[face0]; label own1 = faceOwner[face1]; if (own0 < own1) { // Use face0 as the new internal face. label zoneID = faceZones.whichZone(face0); bool zoneFlip = false; if (zoneID >= 0) { const faceZone& fZone = faceZones[zoneID]; zoneFlip = fZone.flipMap()[fZone.whichFace(face0)]; } meshMod.setAction(polyRemoveFace(face1)); meshMod.setAction ( polyModifyFace ( faces[face0], // modified face face0, // label of face being modified own0, // owner own1, // neighbour false, // face flip -1, // patch for face false, // remove from zone zoneID, // zone for face zoneFlip // face flip in zone ) ); } else { // Use face1 as the new internal face. label zoneID = faceZones.whichZone(face1); bool zoneFlip = false; if (zoneID >= 0) { const faceZone& fZone = faceZones[zoneID]; zoneFlip = fZone.flipMap()[fZone.whichFace(face1)]; } meshMod.setAction(polyRemoveFace(face0)); meshMod.setAction ( polyModifyFace ( faces[face1], // modified face face1, // label of face being modified own1, // owner own0, // neighbour false, // face flip -1, // patch for face false, // remove from zone zoneID, // zone for face zoneFlip // face flip in zone ) ); } } }
void Foam::cellPointWeight::findTetrahedron ( const polyMesh& mesh, const vector& position, const label cellI ) { if (debug) { Pout<< nl << "Foam::cellPointWeight::findTetrahedron" << nl << "position = " << position << nl << "cellI = " << cellI << endl; } List<tetIndices> cellTets = polyMeshTetDecomposition::cellTetIndices ( mesh, cellI ); const faceList& pFaces = mesh.faces(); const scalar cellVolume = mesh.cellVolumes()[cellI]; forAll(cellTets, tetI) { const tetIndices& tetIs = cellTets[tetI]; const face& f = pFaces[tetIs.face()]; // Barycentric coordinates of the position scalar det = tetIs.tet(mesh).barycentric(position, weights_); if (mag(det/cellVolume) > tol) { const scalar& u = weights_[0]; const scalar& v = weights_[1]; const scalar& w = weights_[2]; if ( (u + tol > 0) && (v + tol > 0) && (w + tol > 0) && (u + v + w < 1 + tol) ) { faceVertices_[0] = f[tetIs.faceBasePt()]; faceVertices_[1] = f[tetIs.facePtA()];; faceVertices_[2] = f[tetIs.facePtB()];; return; } } } // A suitable point in a tetrahedron was not found, find the // nearest. scalar minNearDist = VGREAT; label nearestTetI = -1; forAll(cellTets, tetI) { const tetIndices& tetIs = cellTets[tetI]; scalar nearDist = tetIs.tet(mesh).nearestPoint(position).distance(); if (nearDist < minNearDist) { minNearDist = nearDist; nearestTetI = tetI; } } if (debug) { Pout<< "cellPointWeight::findTetrahedron" << nl << " Tetrahedron search failed; using closest tet to point " << position << nl << " cell: " << cellI << nl << endl; } const tetIndices& tetIs = cellTets[nearestTetI]; const face& f = pFaces[tetIs.face()]; // Barycentric coordinates of the position, ignoring if the // determinant is suitable. If not, the return from barycentric // to weights_ is safe. tetIs.tet(mesh).barycentric(position, weights_); faceVertices_[0] = f[tetIs.faceBasePt()]; faceVertices_[1] = f[tetIs.facePtA()]; faceVertices_[2] = f[tetIs.facePtB()]; }
void Foam::cellPointWeight::findTriangle ( const polyMesh& mesh, const vector& position, const label faceI ) { if (debug) { Pout<< "\nbool Foam::cellPointWeight::findTriangle" << nl << "position = " << position << nl << "faceI = " << faceI << endl; } List<tetIndices> faceTets = polyMeshTetDecomposition::faceTetIndices ( mesh, faceI, mesh.faceOwner()[faceI] ); const scalar faceAreaSqr = magSqr(mesh.faceAreas()[faceI]); const face& f = mesh.faces()[faceI]; forAll(faceTets, tetI) { const tetIndices& tetIs = faceTets[tetI]; List<scalar> triWeights(3); // Barycentric coordinates of the position scalar det = tetIs.faceTri(mesh).barycentric(position, triWeights); if (0.25*mag(det)/faceAreaSqr > tol) { const scalar& u = triWeights[0]; const scalar& v = triWeights[1]; if ( (u + tol > 0) && (v + tol > 0) && (u + v < 1 + tol) ) { // Weight[0] is for the cell centre. weights_[0] = 0; weights_[1] = triWeights[0]; weights_[2] = triWeights[1]; weights_[3] = triWeights[2]; faceVertices_[0] = f[tetIs.faceBasePt()]; faceVertices_[1] = f[tetIs.facePtA()];; faceVertices_[2] = f[tetIs.facePtB()];; return; } } } // A suitable point in a triangle was not found, find the nearest. scalar minNearDist = VGREAT; label nearestTetI = -1; forAll(faceTets, tetI) { const tetIndices& tetIs = faceTets[tetI]; scalar nearDist = tetIs.faceTri(mesh).nearestPoint(position).distance(); if (nearDist < minNearDist) { minNearDist = nearDist; nearestTetI = tetI; } } if (debug) { Pout<< "cellPointWeight::findTriangle" << nl << " Triangle search failed; using closest tri to point " << position << nl << " face: " << faceI << nl << endl; } const tetIndices& tetIs = faceTets[nearestTetI]; // Barycentric coordinates of the position, ignoring if the // determinant is suitable. If not, the return from barycentric // to triWeights is safe. List<scalar> triWeights(3); tetIs.faceTri(mesh).barycentric(position, triWeights); // Weight[0] is for the cell centre. weights_[0] = 0; weights_[1] = triWeights[0]; weights_[2] = triWeights[1]; weights_[3] = triWeights[2]; faceVertices_[0] = f[tetIs.faceBasePt()]; faceVertices_[1] = f[tetIs.facePtA()]; faceVertices_[2] = f[tetIs.facePtB()]; }
Foam::ensightPartFaces::ensightPartFaces ( label partNumber, const polyMesh& pMesh, const polyPatch& pPatch ) : ensightPart(partNumber, pPatch.name(), pMesh) { isCellData_ = false; offset_ = pPatch.start(); size_ = pPatch.size(); // count the shapes label nTri = 0; label nQuad = 0; label nPoly = 0; forAll (pPatch, patchfaceI) { const face& f = pMesh.faces()[patchfaceI + offset_]; if (f.size() == 3) { nTri++; } else if (f.size() == 4) { nQuad++; } else { nPoly++; } } // we can avoid double looping, but at the cost of allocation labelList triCells(nTri); labelList quadCells(nQuad); labelList polygonCells(nPoly); nTri = 0; nQuad = 0; nPoly = 0; // classify the shapes forAll(pPatch, patchfaceI) { const face& f = pMesh.faces()[patchfaceI + offset_]; if (f.size() == 3) { triCells[nTri++] = patchfaceI; } else if (f.size() == 4) { quadCells[nQuad++] = patchfaceI; } else { polygonCells[nPoly++] = patchfaceI; } } // MUST match with elementTypes elemLists_.setSize(elementTypes().size()); elemLists_[tria3Elements].transfer( triCells ); elemLists_[quad4Elements].transfer( quadCells ); elemLists_[nsidedElements].transfer( polygonCells ); }
bool Foam::polyMeshZipUpCells(polyMesh& mesh) { if (polyMesh::debug) { Info<< "bool polyMeshZipUpCells(polyMesh& mesh) const: " << "zipping up topologically open cells" << endl; } // Algorithm: // Take the original mesh and visit all cells. For every cell // calculate the edges of all faces on the cells. A cell is // correctly topologically closed when all the edges are referenced // by exactly two faces. If the edges are referenced only by a // single face, additional vertices need to be inserted into some // of the faces (topological closedness). If an edge is // referenced by more that two faces, there is an error in // topological closedness. // Point insertion into the faces is done by attempting to create // closed loops and inserting the intermediate points into the // defining edge // Note: // The algorithm is recursive and changes the mesh faces in each // pass. It is therefore essential to discard the addressing // after every pass. The algorithm is completed when the mesh // stops changing. label nChangedFacesInMesh = 0; label nCycles = 0; labelHashSet problemCells; do { nChangedFacesInMesh = 0; const cellList& Cells = mesh.cells(); const pointField& Points = mesh.points(); faceList newFaces = mesh.faces(); const faceList& oldFaces = mesh.faces(); const labelListList& pFaces = mesh.pointFaces(); forAll(Cells, cellI) { const labelList& curFaces = Cells[cellI]; const edgeList cellEdges = Cells[cellI].edges(oldFaces); const labelList cellPoints = Cells[cellI].labels(oldFaces); // Find the edges used only once in the cell labelList edgeUsage(cellEdges.size(), 0); forAll(curFaces, faceI) { edgeList curFaceEdges = oldFaces[curFaces[faceI]].edges(); forAll(curFaceEdges, faceEdgeI) { const edge& curEdge = curFaceEdges[faceEdgeI]; forAll(cellEdges, cellEdgeI) { if (cellEdges[cellEdgeI] == curEdge) { edgeUsage[cellEdgeI]++; break; } } } } edgeList singleEdges(cellEdges.size()); label nSingleEdges = 0; forAll(edgeUsage, edgeI) { if (edgeUsage[edgeI] == 1) { singleEdges[nSingleEdges] = cellEdges[edgeI]; nSingleEdges++; } else if (edgeUsage[edgeI] != 2) { WarningIn("void polyMeshZipUpCells(polyMesh& mesh)") << "edge " << cellEdges[edgeI] << " in cell " << cellI << " used " << edgeUsage[edgeI] << " times. " << nl << "Should be 1 or 2 - serious error " << "in mesh structure. " << endl; # ifdef DEBUG_ZIPUP forAll(curFaces, faceI) { Info<< "face: " << oldFaces[curFaces[faceI]] << endl; } Info<< "Cell edges: " << cellEdges << nl << "Edge usage: " << edgeUsage << nl << "Cell points: " << cellPoints << endl; forAll(cellPoints, cpI) { Info<< "vertex create \"" << cellPoints[cpI] << "\" coordinates " << Points[cellPoints[cpI]] << endl; } # endif // Gather the problem cell problemCells.insert(cellI); } } // Check if the cell is already zipped up if (nSingleEdges == 0) continue; singleEdges.setSize(nSingleEdges); # ifdef DEBUG_ZIPUP Info<< "Cell " << cellI << endl; forAll(curFaces, faceI) { Info<< "face: " << oldFaces[curFaces[faceI]] << endl; } Info<< "Cell edges: " << cellEdges << nl << "Edge usage: " << edgeUsage << nl << "Single edges: " << singleEdges << nl << "Cell points: " << cellPoints << endl; forAll(cellPoints, cpI) { Info<< "vertex create \"" << cellPoints[cpI] << "\" coordinates " << points()[cellPoints[cpI]] << endl; } # endif // Loop through all single edges and mark the points they use // points marked twice are internal to edge; those marked more than // twice are corners labelList pointUsage(cellPoints.size(), 0); forAll(singleEdges, edgeI) { const edge& curEdge = singleEdges[edgeI]; forAll(cellPoints, pointI) { if ( cellPoints[pointI] == curEdge.start() || cellPoints[pointI] == curEdge.end() ) { pointUsage[pointI]++; } } } boolList singleEdgeUsage(singleEdges.size(), false); // loop through all edges and eliminate the ones that are // blocked out forAll(singleEdges, edgeI) { bool blockedHead = false; bool blockedTail = false; label newEdgeStart = singleEdges[edgeI].start(); label newEdgeEnd = singleEdges[edgeI].end(); // check that the edge has not got all ends blocked forAll(cellPoints, pointI) { if (cellPoints[pointI] == newEdgeStart) { if (pointUsage[pointI] > 2) { blockedHead = true; } } else if (cellPoints[pointI] == newEdgeEnd) { if (pointUsage[pointI] > 2) { blockedTail = true; } } } if (blockedHead && blockedTail) { // Eliminating edge singleEdges[edgeI] as blocked singleEdgeUsage[edgeI] = true; } }
// Check the blockMesh topology void Foam::blockMesh::checkBlockMesh(const polyMesh& bm) const { if (verboseOutput) { Info<< nl << "Check topology" << endl; } bool ok = true; const pointField& points = bm.points(); const faceList& faces = bm.faces(); const cellList& cells = bm.cells(); const polyPatchList& patches = bm.boundaryMesh(); label nBoundaryFaces = 0; forAll(cells, celli) { nBoundaryFaces += cells[celli].nFaces(); } nBoundaryFaces -= 2*bm.nInternalFaces(); label nDefinedBoundaryFaces = 0; forAll(patches, patchi) { nDefinedBoundaryFaces += patches[patchi].size(); } if (verboseOutput) { Info<< nl << tab << "Basic statistics" << nl << tab << tab << "Number of internal faces : " << bm.nInternalFaces() << nl << tab << tab << "Number of boundary faces : " << nBoundaryFaces << nl << tab << tab << "Number of defined boundary faces : " << nDefinedBoundaryFaces << nl << tab << tab << "Number of undefined boundary faces : " << nBoundaryFaces - nDefinedBoundaryFaces << nl; if ((nBoundaryFaces - nDefinedBoundaryFaces) > 0) { Info<< tab << tab << tab << "(Warning : only leave undefined the front and back planes " << "of 2D planar geometries!)" << endl; } Info<< tab << "Checking patch -> block consistency" << endl; } forAll(patches, patchi) { const faceList& Patch = patches[patchi]; forAll(Patch, patchFacei) { const face& patchFace = Patch[patchFacei]; bool patchFaceOK = false; forAll(cells, celli) { const labelList& cellFaces = cells[celli]; forAll(cellFaces, cellFacei) { if (patchFace == faces[cellFaces[cellFacei]]) { patchFaceOK = true; if ( ( patchFace.normal(points) & faces[cellFaces[cellFacei]].normal(points) ) < 0.0 ) { Info<< tab << tab << "Face " << patchFacei << " of patch " << patchi << " (" << patches[patchi].name() << ")" << " points inwards" << endl; ok = false; } } } } if (!patchFaceOK) { Info<< tab << tab << "Face " << patchFacei << " of patch " << patchi << " (" << patches[patchi].name() << ")" << " does not match any block faces" << endl; ok = false; } } } if (verboseOutput) { Info<< endl; } if (!ok) { FatalErrorIn("blockMesh::checkBlockMesh(const polyMesh& bm)") << "Block mesh topology incorrect, stopping mesh generation!" << exit(FatalError); } }
// Naive feature detection. All boundary edges with angle > featureAngle become // feature edges. All points on feature edges become feature points. All // boundary faces become feature faces. void simpleMarkFeatures ( const polyMesh& mesh, const PackedBoolList& isBoundaryEdge, const scalar featureAngle, const bool concaveMultiCells, const bool doNotPreserveFaceZones, labelList& featureFaces, labelList& featureEdges, labelList& singleCellFeaturePoints, labelList& multiCellFeaturePoints ) { scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0); const polyBoundaryMesh& patches = mesh.boundaryMesh(); // Working sets labelHashSet featureEdgeSet; labelHashSet singleCellFeaturePointSet; labelHashSet multiCellFeaturePointSet; // 1. Mark all edges between patches // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ forAll(patches, patchI) { const polyPatch& pp = patches[patchI]; const labelList& meshEdges = pp.meshEdges(); // All patch corner edges. These need to be feature points & edges! for (label edgeI = pp.nInternalEdges(); edgeI < pp.nEdges(); edgeI++) { label meshEdgeI = meshEdges[edgeI]; featureEdgeSet.insert(meshEdgeI); singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][0]); singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][1]); } } // 2. Mark all geometric feature edges // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make distinction between convex features where the boundary point becomes // a single cell and concave features where the boundary point becomes // multiple 'half' cells. // Addressing for all outside faces primitivePatch allBoundary ( SubList<face> ( mesh.faces(), mesh.nFaces()-mesh.nInternalFaces(), mesh.nInternalFaces() ), mesh.points() ); // Check for non-manifold points (surface pinched at point) allBoundary.checkPointManifold(false, &singleCellFeaturePointSet); // Check for non-manifold edges (surface pinched at edge) const labelListList& edgeFaces = allBoundary.edgeFaces(); const labelList& meshPoints = allBoundary.meshPoints(); forAll(edgeFaces, edgeI) { const labelList& eFaces = edgeFaces[edgeI]; if (eFaces.size() > 2) { const edge& e = allBoundary.edges()[edgeI]; //Info<< "Detected non-manifold boundary edge:" << edgeI // << " coords:" // << allBoundary.points()[meshPoints[e[0]]] // << allBoundary.points()[meshPoints[e[1]]] << endl; singleCellFeaturePointSet.insert(meshPoints[e[0]]); singleCellFeaturePointSet.insert(meshPoints[e[1]]); } } // Check for features. forAll(edgeFaces, edgeI) { const labelList& eFaces = edgeFaces[edgeI]; if (eFaces.size() == 2) { label f0 = eFaces[0]; label f1 = eFaces[1]; // check angle const vector& n0 = allBoundary.faceNormals()[f0]; const vector& n1 = allBoundary.faceNormals()[f1]; if ((n0 & n1) < minCos) { const edge& e = allBoundary.edges()[edgeI]; label v0 = meshPoints[e[0]]; label v1 = meshPoints[e[1]]; label meshEdgeI = meshTools::findEdge(mesh, v0, v1); featureEdgeSet.insert(meshEdgeI); // Check if convex or concave by looking at angle // between face centres and normal vector c1c0 ( allBoundary[f1].centre(allBoundary.points()) - allBoundary[f0].centre(allBoundary.points()) ); if (concaveMultiCells && (c1c0 & n0) > SMALL) { // Found concave edge. Make into multiCell features Info<< "Detected concave feature edge:" << edgeI << " cos:" << (c1c0 & n0) << " coords:" << allBoundary.points()[v0] << allBoundary.points()[v1] << endl; singleCellFeaturePointSet.erase(v0); multiCellFeaturePointSet.insert(v0); singleCellFeaturePointSet.erase(v1); multiCellFeaturePointSet.insert(v1); } else { // Convex. singleCell feature. if (!multiCellFeaturePointSet.found(v0)) { singleCellFeaturePointSet.insert(v0); } if (!multiCellFeaturePointSet.found(v1)) { singleCellFeaturePointSet.insert(v1); } } } } } // 3. Mark all feature faces // ~~~~~~~~~~~~~~~~~~~~~~~~~ // Face centres that need inclusion in the dual mesh labelHashSet featureFaceSet(mesh.nFaces()-mesh.nInternalFaces()); // A. boundary faces. for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++) { featureFaceSet.insert(faceI); } // B. face zones. const faceZoneMesh& faceZones = mesh.faceZones(); if (doNotPreserveFaceZones) { if (faceZones.size() > 0) { WarningIn("simpleMarkFeatures(..)") << "Detected " << faceZones.size() << " faceZones. These will not be preserved." << endl; } } else { if (faceZones.size() > 0) { Info<< "Detected " << faceZones.size() << " faceZones. Preserving these by marking their" << " points, edges and faces as features." << endl; } forAll(faceZones, zoneI) { const faceZone& fz = faceZones[zoneI]; Info<< "Inserting all faces in faceZone " << fz.name() << " as features." << endl; forAll(fz, i) { label faceI = fz[i]; const face& f = mesh.faces()[faceI]; const labelList& fEdges = mesh.faceEdges()[faceI]; featureFaceSet.insert(faceI); forAll(f, fp) { // Mark point as multi cell point (since both sides of // face should have different cells) singleCellFeaturePointSet.erase(f[fp]); multiCellFeaturePointSet.insert(f[fp]); // Make sure there are points on the edges. featureEdgeSet.insert(fEdges[fp]); } } }
Foam::autoPtr<Foam::mapDistribute> Foam::meshToMeshNew::calcProcMap ( const polyMesh& src, const polyMesh& tgt ) const { // get decomposition of cells on src mesh List<boundBox> procBb(Pstream::nProcs()); if (src.nCells() > 0) { // bounding box for my mesh - do not parallel reduce procBb[Pstream::myProcNo()] = boundBox(src.points(), false); // slightly increase size of bounding boxes to allow for cases where // bounding boxes are perfectly alligned procBb[Pstream::myProcNo()].inflate(0.01); } else { procBb[Pstream::myProcNo()] = boundBox(); } Pstream::gatherList(procBb); Pstream::scatterList(procBb); if (debug) { Info<< "Determining extent of src mesh per processor:" << nl << "\tproc\tbb" << endl; forAll(procBb, procI) { Info<< '\t' << procI << '\t' << procBb[procI] << endl; } } // determine which cells of tgt mesh overlaps src mesh per proc const cellList& cells = tgt.cells(); const faceList& faces = tgt.faces(); const pointField& points = tgt.points(); labelListList sendMap; { // per processor indices into all segments to send List<DynamicList<label> > dynSendMap(Pstream::nProcs()); label iniSize = floor(tgt.nCells()/Pstream::nProcs()); forAll(dynSendMap, procI) { dynSendMap[procI].setCapacity(iniSize); } // work array - whether src processor bb overlaps the tgt cell bounds boolList procBbOverlaps(Pstream::nProcs()); forAll(cells, cellI) { const cell& c = cells[cellI]; // determine bounding box of tgt cell boundBox cellBb(point::max, point::min); forAll(c, faceI) { const face& f = faces[c[faceI]]; forAll(f, fp) { cellBb.min() = min(cellBb.min(), points[f[fp]]); cellBb.max() = max(cellBb.max(), points[f[fp]]); } } // find the overlapping tgt cells on each src processor (void)calcOverlappingProcs(procBb, cellBb, procBbOverlaps); forAll(procBbOverlaps, procI) { if (procBbOverlaps[procI]) { dynSendMap[procI].append(cellI); } } }
void Foam::cellPointWeight::findTetrahedron ( const polyMesh& mesh, const vector& position, const label cellIndex ) { if (debug) { Pout<< "\nFoam::cellPointWeight::findTetrahedron" << nl << "position = " << position << nl << "cellIndex = " << cellIndex << endl; } // Initialise closest triangle variables scalar minUVWClose = VGREAT; label pointIClose = 0; label faceClose = 0; const vector& P0 = mesh.cellCentres()[cellIndex]; const labelList& cellFaces = mesh.cells()[cellIndex]; const scalar cellVolume = mesh.cellVolumes()[cellIndex]; // Find the tet that the point occupies forAll(cellFaces, faceI) { // Decompose each face into triangles, making a tet when // augmented by the cell centre const labelList& facePoints = mesh.faces()[cellFaces[faceI]]; label pointI = 1; while ((pointI + 1) < facePoints.size()) { // Cartesian co-ordinates of the triangle vertices const vector& P1 = mesh.points()[facePoints[0]]; const vector& P2 = mesh.points()[facePoints[pointI]]; const vector& P3 = mesh.points()[facePoints[pointI + 1]]; // Edge vectors const vector e1 = P1 - P0; const vector e2 = P2 - P0; const vector e3 = P3 - P0; // Solve for interpolation weighting factors // Source term const vector rhs = position - P0; // Determinant of coefficients matrix // Note: if det(A) = 0 the tet is degenerate const scalar detA = e1.x()*e2.y()*e3.z() + e2.x()*e3.y()*e1.z() + e3.x()*e1.y()*e2.z() - e1.x()*e3.y()*e2.z() - e2.x()*e1.y()*e3.z() - e3.x()*e2.y()*e1.z(); if (mag(detA/cellVolume) > tol) { // Solve using Cramers' rule const scalar u = ( rhs.x()*e2.y()*e3.z() + e2.x()*e3.y()*rhs.z() + e3.x()*rhs.y()*e2.z() - rhs.x()*e3.y()*e2.z() - e2.x()*rhs.y()*e3.z() - e3.x()*e2.y()*rhs.z() )/detA; const scalar v = ( e1.x()*rhs.y()*e3.z() + rhs.x()*e3.y()*e1.z() + e3.x()*e1.y()*rhs.z() - e1.x()*e3.y()*rhs.z() - rhs.x()*e1.y()*e3.z() - e3.x()*rhs.y()*e1.z() )/detA; const scalar w = ( e1.x()*e2.y()*rhs.z() + e2.x()*rhs.y()*e1.z() + rhs.x()*e1.y()*e2.z() - e1.x()*rhs.y()*e2.z() - e2.x()*e1.y()*rhs.z() - rhs.x()*e2.y()*e1.z() )/detA; // Check if point is in tet // value = 0 indicates position lies on a tet face if ( (u + tol > 0) && (v + tol > 0) && (w + tol > 0) && (u + v + w < 1 + tol) ) { faceVertices_[0] = facePoints[0]; faceVertices_[1] = facePoints[pointI]; faceVertices_[2] = facePoints[pointI + 1]; weights_[0] = u; weights_[1] = v; weights_[2] = w; weights_[3] = 1.0 - (u + v + w); return; } else { scalar minU = mag(u); scalar minV = mag(v); scalar minW = mag(w); if (minU > 1.0) { minU -= 1.0; } if (minV > 1.0) { minV -= 1.0; } if (minW > 1.0) { minW -= 1.0; } const scalar minUVW = mag(minU + minV + minW); if (minUVW < minUVWClose) { minUVWClose = minUVW; pointIClose = pointI; faceClose = faceI; } } } pointI++; } } if (debug) { Pout<< "cellPointWeight::findTetrahedron" << nl << " Tetrahedron search failed; using closest tet values to " << "point " << nl << " cell: " << cellIndex << nl << endl; } const labelList& facePointsClose = mesh.faces()[cellFaces[faceClose]]; faceVertices_[0] = facePointsClose[0]; faceVertices_[1] = facePointsClose[pointIClose]; faceVertices_[2] = facePointsClose[pointIClose + 1]; weights_[0] = 0.25; weights_[1] = 0.25; weights_[2] = 0.25; weights_[3] = 0.25; }
void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology) { Info<< "Mesh stats" << nl << " points: " << returnReduce(mesh.points().size(), sumOp<label>()) << nl; label nInternalPoints = returnReduce ( mesh.nInternalPoints(), sumOp<label>() ); if (nInternalPoints != -Pstream::nProcs()) { Info<< " internal points: " << nInternalPoints << nl; if (returnReduce(mesh.nInternalPoints(), minOp<label>()) == -1) { WarningIn("Foam::printMeshStats(const polyMesh&, const bool)") << "Some processors have their points sorted into internal" << " and external and some do not." << endl << "This can cause problems later on." << endl; } } if (allTopology && nInternalPoints != -Pstream::nProcs()) { label nEdges = returnReduce(mesh.nEdges(), sumOp<label>()); label nInternalEdges = returnReduce ( mesh.nInternalEdges(), sumOp<label>() ); label nInternal1Edges = returnReduce ( mesh.nInternal1Edges(), sumOp<label>() ); label nInternal0Edges = returnReduce ( mesh.nInternal0Edges(), sumOp<label>() ); Info<< " edges: " << nEdges << nl << " internal edges: " << nInternalEdges << nl << " internal edges using one boundary point: " << nInternal1Edges-nInternal0Edges << nl << " internal edges using two boundary points: " << nInternalEdges-nInternal1Edges << nl; } label nFaces = returnReduce(mesh.faces().size(), sumOp<label>()); label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>()); label nCells = returnReduce(mesh.cells().size(), sumOp<label>()); Info<< " faces: " << nFaces << nl << " internal faces: " << nIntFaces << nl << " cells: " << nCells << nl << " faces per cell: " << scalar(nFaces + nIntFaces)/max(1, nCells) << nl << " boundary patches: " << mesh.boundaryMesh().size() << nl << " point zones: " << mesh.pointZones().size() << nl << " face zones: " << mesh.faceZones().size() << nl << " cell zones: " << mesh.cellZones().size() << nl << endl; // Construct shape recognizers hexMatcher hex; prismMatcher prism; wedgeMatcher wedge; pyrMatcher pyr; tetWedgeMatcher tetWedge; tetMatcher tet; // Counters for different cell types label nHex = 0; label nWedge = 0; label nPrism = 0; label nPyr = 0; label nTet = 0; label nTetWedge = 0; label nUnknown = 0; Map<label> polyhedralFaces; for (label cellI = 0; cellI < mesh.nCells(); cellI++) { if (hex.isA(mesh, cellI)) { nHex++; } else if (tet.isA(mesh, cellI)) { nTet++; } else if (pyr.isA(mesh, cellI)) { nPyr++; } else if (prism.isA(mesh, cellI)) { nPrism++; } else if (wedge.isA(mesh, cellI)) { nWedge++; } else if (tetWedge.isA(mesh, cellI)) { nTetWedge++; } else { nUnknown++; polyhedralFaces(mesh.cells()[cellI].size())++; } } reduce(nHex,sumOp<label>()); reduce(nPrism,sumOp<label>()); reduce(nWedge,sumOp<label>()); reduce(nPyr,sumOp<label>()); reduce(nTetWedge,sumOp<label>()); reduce(nTet,sumOp<label>()); reduce(nUnknown,sumOp<label>()); Info<< "Overall number of cells of each type:" << nl << " hexahedra: " << nHex << nl << " prisms: " << nPrism << nl << " wedges: " << nWedge << nl << " pyramids: " << nPyr << nl << " tet wedges: " << nTetWedge << nl << " tetrahedra: " << nTet << nl << " polyhedra: " << nUnknown << endl; if (nUnknown > 0) { Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>()); Info<< " Breakdown of polyhedra by number of faces:" << nl << " faces" << " number of cells" << endl; const labelList sortedKeys = polyhedralFaces.sortedToc(); forAll(sortedKeys, keyI) { const label nFaces = sortedKeys[keyI]; Info<< setf(std::ios::right) << setw(13) << nFaces << " " << polyhedralFaces[nFaces] << nl; } }