bool Foam::foamyHexMeshChecks::closePoints ( Cell& c, const scalar tol ) { for (label v = 0; v < 4; ++v) { for (label vA = v + 1; vA < 4; ++vA) { if ( mag ( topoint(c->vertex(v)->point()) - topoint(c->vertex(vA)->point()) ) < tol ) { return true; } } } return false; }
void Foam::cellShapeControlMesh::barycentricCoords ( const Foam::point& pt, barycentric& bary, Cell_handle& ch ) const { // Use the previous cell handle as a hint on where to start searching // Giving a hint causes strange errors... ch = locate(toPoint(pt)); if (dimension() > 2 && !is_infinite(ch)) { oldCellHandle_ = ch; tetPointRef tet ( topoint(ch->vertex(0)->point()), topoint(ch->vertex(1)->point()), topoint(ch->vertex(2)->point()), topoint(ch->vertex(3)->point()) ); bary = tet.pointToBarycentric(pt); } }
void Foam::cellShapeControlMesh::writeTriangulation() { OFstream str ( "refinementTriangulation_" + name(Pstream::myProcNo()) + ".obj" ); label count = 0; Info<< "Write refinementTriangulation" << endl; for ( CellSizeDelaunay::Finite_edges_iterator e = finite_edges_begin(); e != finite_edges_end(); ++e ) { Cell_handle c = e->first; Vertex_handle vA = c->vertex(e->second); Vertex_handle vB = c->vertex(e->third); // Don't write far edges if (vA->farPoint() || vB->farPoint()) { continue; } // Don't write unowned edges if (vA->referred() && vB->referred()) { continue; } pointFromPoint p1 = topoint(vA->point()); pointFromPoint p2 = topoint(vB->point()); meshTools::writeOBJ(str, p1, p2, count); } if (is_valid()) { Info<< " Triangulation is valid" << endl; } else { FatalErrorIn ( "Foam::triangulatedMesh::writeRefinementTriangulation()" ) << "Triangulation is not valid" << abort(FatalError); } }
void Foam::DelaunayMeshTools::writeFixedPoints ( const fileName& fName, const Triangulation& t ) { OFstream str(fName); Pout<< nl << "Writing fixed points to " << str.name() << endl; for ( typename Triangulation::Finite_vertices_iterator vit = t.finite_vertices_begin(); vit != t.finite_vertices_end(); ++vit ) { if (vit->fixed()) { meshTools::writeOBJ(str, topoint(vit->point())); } } }
void Foam::DelaunayMeshTools::drawDelaunayCell ( Ostream& os, const CellHandle& c, label offset ) { // Supply offset as tet number offset *= 4; os << "# cell index: " << label(c->cellIndex()) << " INT_MIN = " << INT_MIN << endl; os << "# circumradius " << mag(c->dual() - topoint(c->vertex(0)->point())) << endl; for (int i = 0; i < 4; i++) { os << "# index / type / procIndex: " << label(c->vertex(i)->index()) << " " << label(c->vertex(i)->type()) << " " << label(c->vertex(i)->procIndex()) << ( CGAL::indexedVertexOps::uninitialised(c->vertex(i)) ? " # This vertex is uninitialised!" : "" ) << endl; meshTools::writeOBJ(os, topoint(c->vertex(i)->point())); } os << "f " << 1 + offset << " " << 3 + offset << " " << 2 + offset << nl << "f " << 2 + offset << " " << 3 + offset << " " << 4 + offset << nl << "f " << 1 + offset << " " << 4 + offset << " " << 3 + offset << nl << "f " << 1 + offset << " " << 2 + offset << " " << 4 + offset << endl; // os << "# cicumcentre " << endl; // meshTools::writeOBJ(os, c->dual()); // os << "l " << 1 + offset << " " << 5 + offset << endl; }
Foam::scalar Foam::foamyHexMeshChecks::coplanarTet ( Cell& c, const scalar tol ) { tetPointRef tet ( topoint(c->vertex(0)->point()), topoint(c->vertex(1)->point()), topoint(c->vertex(2)->point()), topoint(c->vertex(3)->point()) ); const scalar quality = tet.quality(); if (quality < tol) { return quality; } return 0; // plane triPlane // ( // topoint(c->vertex(0)->point()), // topoint(c->vertex(1)->point()), // topoint(c->vertex(2)->point()) // ); // // const scalar distance = triPlane.distance(topoint(c->vertex(3)->point())); // // // Check if the four points are roughly coplanar. If they are then we // // cannot calculate the circumcentre. Better test might be the volume // // of the tet. // if (distance < tol) // { // return 0; // } // // return distance; }
Foam::labelList Foam::backgroundMeshDecomposition::processorPosition ( const List<PointType>& pts ) const { DynamicList<label> toCandidateProc; DynamicList<point> testPoints; labelList ptBlockStart(pts.size(), -1); labelList ptBlockSize(pts.size(), -1); label nTotalCandidates = 0; forAll(pts, pI) { const pointFromPoint pt = topoint(pts[pI]); label nCandidates = 0; forAll(allBackgroundMeshBounds_, procI) { if (allBackgroundMeshBounds_[procI].contains(pt)) { toCandidateProc.append(procI); testPoints.append(pt); nCandidates++; } } ptBlockStart[pI] = nTotalCandidates; ptBlockSize[pI] = nCandidates; nTotalCandidates += nCandidates; } // Needed for reverseDistribute label preDistributionToCandidateProcSize = toCandidateProc.size(); autoPtr<mapDistribute> map(buildMap(toCandidateProc)); map().distribute(testPoints); List<bool> pointOnCandidate(testPoints.size(), false); // Test candidate points on candidate processors forAll(testPoints, tPI) { pointOnCandidate[tPI] = positionOnThisProcessor(testPoints[tPI]); }
void Foam::DelaunayMeshTools::writeInternalDelaunayVertices ( const fileName& instance, const Triangulation& t ) { pointField internalDelaunayVertices(t.number_of_vertices()); label vertI = 0; for ( typename Triangulation::Finite_vertices_iterator vit = t.finite_vertices_begin(); vit != t.finite_vertices_end(); ++vit ) { if (vit->internalPoint()) { internalDelaunayVertices[vertI++] = topoint(vit->point()); } } internalDelaunayVertices.setSize(vertI); pointIOField internalDVs ( IOobject ( "internalDelaunayVertices", instance, t.time(), IOobject::NO_READ, IOobject::AUTO_WRITE ), internalDelaunayVertices ); Info<< nl << "Writing " << internalDVs.name() << " to " << internalDVs.instance() << endl; internalDVs.write(); }
void Foam::conformalVoronoiMesh::cellSizeMeshOverlapsBackground() const { const cellShapeControlMesh& cellSizeMesh = cellShapeControl_.shapeControlMesh(); DynamicList<Foam::point> pts(number_of_vertices()); for ( Delaunay::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (vit->internalOrBoundaryPoint() && !vit->referred()) { pts.append(topoint(vit->point())); } } boundBox bb(pts); boundBox cellSizeMeshBb = cellSizeMesh.bounds(); bool fullyContained = true; if (!cellSizeMeshBb.contains(bb)) { Pout<< "Triangulation not fully contained in cell size mesh." << endl; Pout<< "Cell Size Mesh Bounds = " << cellSizeMesh.bounds() << endl; Pout<< "foamyHexMesh Bounds = " << bb << endl; fullyContained = false; } reduce(fullyContained, andOp<unsigned int>()); Info<< "Triangulation is " << (fullyContained ? "fully" : "not fully") << " contained in the cell size mesh" << endl; }
void Foam::DelaunayMeshTools::writeOBJ ( const fileName& fName, const Triangulation& t, const indexedVertexEnum::vertexType startPointType, const indexedVertexEnum::vertexType endPointType ) { OFstream str(fName); Pout<< nl << "Writing points of types:" << nl; forAllConstIter ( HashTable<int>, indexedVertexEnum::vertexTypeNames_, iter ) { if (iter() >= startPointType && iter() <= endPointType) { Pout<< " " << iter.key() << nl; } } Pout<< "to " << str.name() << endl; for ( typename Triangulation::Finite_vertices_iterator vit = t.finite_vertices_begin(); vit != t.finite_vertices_end(); ++vit ) { if (vit->type() >= startPointType && vit->type() <= endPointType) { meshTools::writeOBJ(str, topoint(vit->point())); } } }
Foam::boundBox Foam::cellShapeControlMesh::bounds() const { DynamicList<Foam::point> pts(number_of_vertices()); for ( Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (vit->real()) { pts.append(topoint(vit->point())); } } boundBox bb(pts); return bb; }
Foam::tmp<Foam::pointField> Foam::cellShapeControlMesh::cellCentres() const { tmp<pointField> tcellCentres(new pointField(number_of_finite_cells())); pointField& cellCentres = tcellCentres.ref(); label count = 0; for ( CellSizeDelaunay::Finite_cells_iterator c = finite_cells_begin(); c != finite_cells_end(); ++c ) { if (c->hasFarPoint()) { continue; } scalarList bary; cellShapeControlMesh::Cell_handle ch; const Foam::point centre = topoint ( CGAL::centroid<baseK> ( c->vertex(0)->point(), c->vertex(1)->point(), c->vertex(2)->point(), c->vertex(3)->point() ) ); cellCentres[count++] = centre; } cellCentres.resize(count); return tcellCentres; }
void Foam::conformalVoronoiMesh::insertInternalPoints ( List<Point>& points, bool distribute ) { label nPoints = points.size(); if (Pstream::parRun()) { reduce(nPoints, sumOp<label>()); } Info<< " " << nPoints << " points to insert..." << endl; if (Pstream::parRun() && distribute) { List<Foam::point> transferPoints(points.size()); forAll(points, pI) { transferPoints[pI] = topoint(points[pI]); }
Foam::tmp<Foam::pointField> Foam::DelaunayMeshTools::allPoints ( const Triangulation& t ) { tmp<pointField> tpts(new pointField(t.vertexCount(), point::max)); pointField& pts = tpts.ref(); for ( typename Triangulation::Finite_vertices_iterator vit = t.finite_vertices_begin(); vit != t.finite_vertices_end(); ++vit ) { if (vit->internalOrBoundaryPoint() && !vit->referred()) { pts[vit->index()] = topoint(vit->point()); } } return tpts; }
forAll(pts, pI) { // Extract the sub list of results for this point SubList<bool> ptProcResults ( pointOnCandidate, ptBlockSize[pI], ptBlockStart[pI] ); forAll(ptProcResults, pPRI) { if (ptProcResults[pPRI]) { ptProc[pI] = toCandidateProc[ptBlockStart[pI] + pPRI]; break; } } if (ptProc[pI] < 0) { const pointFromPoint pt = topoint(pts[pI]); if (!globalBackgroundBounds_.contains(pt)) { FatalErrorIn ( "Foam::labelList" "Foam::backgroundMeshDecomposition::processorPosition" "(" "const List<point>&" ") const" ) << "The position " << pt << " is not in any part of the background mesh " << globalBackgroundBounds_ << endl << "A background mesh with a wider margin around " << "the geometry may help." << exit(FatalError); } if (debug) { WarningIn ( "Foam::labelList" "Foam::backgroundMeshDecomposition::processorPosition" "(" "const List<point>&" ") const" ) << "The position " << pt << " was not found in the background mesh " << globalBackgroundBounds_ << ", finding nearest." << endl; } failedPointIndices.append(pI); failedPoints.append(pt); } }
void Foam::cellShapeControlMesh::distribute ( const backgroundMeshDecomposition& decomposition ) { DynamicList<Foam::point> points(number_of_vertices()); DynamicList<scalar> sizes(number_of_vertices()); DynamicList<tensor> alignments(number_of_vertices()); DynamicList<Vb> farPts(8); for ( Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (vit->real()) { points.append(topoint(vit->point())); sizes.append(vit->targetCellSize()); alignments.append(vit->alignment()); } else if (vit->farPoint()) { farPts.append ( Vb ( vit->point(), -1, Vb::vtFar, Pstream::myProcNo() ) ); farPts.last().targetCellSize() = vit->targetCellSize(); farPts.last().alignment() = vit->alignment(); } } autoPtr<mapDistribute> mapDist = DistributedDelaunayMesh<CellSizeDelaunay>::distribute ( decomposition, points ); mapDist().distribute(sizes); mapDist().distribute(alignments); // Reset the entire tessellation DelaunayMesh<CellSizeDelaunay>::reset(); // Internal points have to be inserted first DynamicList<Vb> verticesToInsert(points.size()); forAll(farPts, ptI) { verticesToInsert.append(farPts[ptI]); }
void Foam::controlMeshRefinement::initialMeshPopulation ( const autoPtr<backgroundMeshDecomposition>& decomposition ) { if (shapeController_.shapeControlMesh().vertexCount() > 0) { // Mesh already populated. Info<< "Cell size and alignment mesh already populated." << endl; return; } autoPtr<boundBox> overallBoundBox; // Need to pass in the background mesh decomposition so that can test if // a point to insert is on the processor. if (Pstream::parRun()) { // overallBoundBox.set(new boundBox(decomposition().procBounds())); } else { // overallBoundBox.set // ( // new boundBox(geometryToConformTo_.geometry().bounds()) // ); // // mesh_.insertBoundingPoints // ( // overallBoundBox(), // sizeControls_ // ); } Map<label> priorityMap; const PtrList<cellSizeAndAlignmentControl>& controlFunctions = sizeControls_.controlFunctions(); forAll(controlFunctions, fI) { const cellSizeAndAlignmentControl& controlFunction = controlFunctions[fI]; const Switch& forceInsertion = controlFunction.forceInitialPointInsertion(); Info<< "Inserting points from " << controlFunction.name() << " (" << controlFunction.type() << ")" << endl; Info<< " Force insertion is " << forceInsertion.asText() << endl; pointField pts; scalarField sizes; triadField alignments; controlFunction.initialVertices(pts, sizes, alignments); Info<< " Got initial vertices list of size " << pts.size() << endl; List<Vb> vertices(pts.size()); // Clip the minimum size for (label vI = 0; vI < pts.size(); ++vI) { vertices[vI] = Vb(pts[vI], Vb::vtInternalNearBoundary); label maxPriority = -1; scalar size = sizeControls_.cellSize(pts[vI], maxPriority); if (maxPriority > controlFunction.maxPriority()) { vertices[vI].targetCellSize() = max ( size, shapeController_.minimumCellSize() ); } // else if (maxPriority == controlFunction.maxPriority()) // { // vertices[vI].targetCellSize() = max // ( // min(sizes[vI], size), // shapeController_.minimumCellSize() // ); // } else { vertices[vI].targetCellSize() = max ( sizes[vI], shapeController_.minimumCellSize() ); } vertices[vI].alignment() = alignments[vI]; } Info<< " Clipped minimum size" << endl; pts.clear(); sizes.clear(); alignments.clear(); PackedBoolList keepVertex(vertices.size(), true); forAll(vertices, vI) { bool keep = true; pointFromPoint pt = topoint(vertices[vI].point()); if (Pstream::parRun()) { keep = decomposition().positionOnThisProcessor(pt); } if (keep && geometryToConformTo_.wellOutside(pt, SMALL)) { keep = false; } if (!keep) { keepVertex[vI] = false; } } inplaceSubset(keepVertex, vertices); const label preInsertedSize = mesh_.number_of_vertices(); Info<< " Check sizes" << endl; forAll(vertices, vI) { bool insertPoint = false; pointFromPoint pt(topoint(vertices[vI].point())); if ( mesh_.dimension() < 3 || mesh_.is_infinite ( mesh_.locate(vertices[vI].point()) ) ) { insertPoint = true; } const scalar interpolatedCellSize = shapeController_.cellSize(pt); const triad interpolatedAlignment = shapeController_.cellAlignment(pt); const scalar calculatedCellSize = vertices[vI].targetCellSize(); const triad calculatedAlignment = vertices[vI].alignment(); if (debug) { Info<< "Point = " << pt << nl << " Size(interp) = " << interpolatedCellSize << nl << " Size(calc) = " << calculatedCellSize << nl << " Align(interp) = " << interpolatedAlignment << nl << " Align(calc) = " << calculatedAlignment << nl << endl; } const scalar sizeDiff = mag(interpolatedCellSize - calculatedCellSize); const scalar alignmentDiff = diff(interpolatedAlignment, calculatedAlignment); if (debug) { Info<< " size difference = " << sizeDiff << nl << ", alignment difference = " << alignmentDiff << endl; } // @todo Also need to base it on the alignments if ( sizeDiff/interpolatedCellSize > 0.1 || alignmentDiff > 0.15 ) { insertPoint = true; } if (forceInsertion || insertPoint) { const label oldSize = mesh_.vertexCount(); cellShapeControlMesh::Vertex_handle insertedVert = mesh_.insert ( pt, calculatedCellSize, vertices[vI].alignment(), Vb::vtInternalNearBoundary ); if (oldSize == mesh_.vertexCount() - 1) { priorityMap.insert ( insertedVert->index(), controlFunction.maxPriority() ); } } }
bool Foam::conformalVoronoiMesh::distributeBackground(const Triangulation& mesh) { if (!Pstream::parRun()) { return false; } Info<< nl << "Redistributing points" << endl; timeCheck("Before distribute"); label iteration = 0; scalar previousLoadUnbalance = 0; while (true) { scalar maxLoadUnbalance = mesh.calculateLoadUnbalance(); if ( maxLoadUnbalance <= foamyHexMeshControls().maxLoadUnbalance() || maxLoadUnbalance <= previousLoadUnbalance ) { // If this is the first iteration, return false, if it was a // subsequent one, return true; return iteration != 0; } previousLoadUnbalance = maxLoadUnbalance; Info<< " Total number of vertices before redistribution " << returnReduce(label(mesh.number_of_vertices()), sumOp<label>()) << endl; const fvMesh& bMesh = decomposition_().mesh(); volScalarField cellWeights ( IOobject ( "cellWeights", bMesh.time().timeName(), bMesh, IOobject::NO_READ, IOobject::NO_WRITE ), bMesh, dimensionedScalar("weight", dimless, 1e-2), zeroGradientFvPatchScalarField::typeName ); meshSearch cellSearch(bMesh, polyMesh::FACE_PLANES); labelList cellVertices(bMesh.nCells(), label(0)); for ( typename Triangulation::Finite_vertices_iterator vit = mesh.finite_vertices_begin(); vit != mesh.finite_vertices_end(); ++vit ) { // Only store real vertices that are not feature vertices if (vit->real() && !vit->featurePoint()) { pointFromPoint v = topoint(vit->point()); label cellI = cellSearch.findCell(v); if (cellI == -1) { // Pout<< "findCell conformalVoronoiMesh::distribute " // << "findCell " // << vit->type() << " " // << vit->index() << " " // << v << " " // << cellI // << " find nearest cellI "; cellI = cellSearch.findNearestCell(v); } cellVertices[cellI]++; } } forAll(cellVertices, cI) { // Give a small but finite weight for empty cells. Some // decomposition methods have difficulty with integer overflows in // the sum of the normalised weight field. cellWeights.internalField()[cI] = max ( cellVertices[cI], 1e-2 ); } autoPtr<mapDistributePolyMesh> mapDist = decomposition_().distribute ( cellWeights ); cellShapeControl_.shapeControlMesh().distribute(decomposition_); distribute(); timeCheck("After distribute"); iteration++; }