diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C index ca0c0cbddc8c7704d675e3e77af2f2fd3966da43..57a4cb5b64702f20e4ad2b4de0aee4788fd9af10 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.C @@ -25,6 +25,7 @@ License \*----------------------------------------------------------------------------*/ #include "autoRefineDriver.H" +#include "meshRefinement.H" #include "fvMesh.H" #include "Time.H" #include "boundBox.H" diff --git a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H index f1747a29be73c02ef6754edb2638eb7d6b0d256d..ce788e4b1eef35618709db716b735ca25dd3057c 100644 --- a/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H +++ b/src/autoMesh/autoHexMesh/autoHexMeshDriver/autoRefineDriver.H @@ -35,7 +35,7 @@ SourceFiles #ifndef autoRefineDriver_H #define autoRefineDriver_H -#include "meshRefinement.H" +#include "treeBoundBox.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -45,6 +45,9 @@ namespace Foam // Forward declaration of classes class featureEdgeMesh; class refinementParameters; +class meshRefinement; +class decompositionMethod; +class fvMeshDistribute; /*---------------------------------------------------------------------------*\ Class autoRefineDriver Declaration diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C index 7f5bc29a796e40d24048ae89155c0edfec971f24..626fb2fe25634720dfd1c10a431142171ea0ba9f 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinement.C @@ -51,6 +51,9 @@ License #include "meshTools.H" #include "OFstream.H" #include "geomDecomp.H" +#include "Random.H" +#include "searchableSurfaces.H" +#include "treeBoundBox.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -122,13 +125,36 @@ void Foam::meshRefinement::updateIntersections(const labelList& changedFaces) { const pointField& cellCentres = mesh_.cellCentres(); - label nTotEdges = returnReduce(surfaceIndex_.size(), sumOp<label>()); - label nChangedFaces = returnReduce(changedFaces.size(), sumOp<label>()); + // Stats on edges to test. Count proc faces only once. + PackedList<1> isMasterFace(syncTools::getMasterFaces(mesh_)); + + { + label nMasterFaces = 0; + forAll(isMasterFace, faceI) + { + if (isMasterFace.get(faceI) == 1) + { + nMasterFaces++; + } + } + reduce(nMasterFaces, sumOp<label>()); + + label nChangedFaces = 0; + forAll(changedFaces, i) + { + if (isMasterFace.get(changedFaces[i]) == 1) + { + nChangedFaces++; + } + } + reduce(nChangedFaces, sumOp<label>()); + + Info<< "Edge intersection testing:" << nl + << " Number of edges : " << nMasterFaces << nl + << " Number of edges to retest : " << nChangedFaces + << endl; + } - Info<< "Edge intersection testing:" << nl - << " Number of edges : " << nTotEdges << nl - << " Number of edges to retest : " << nChangedFaces - << endl; // Get boundary face centre and level. Coupled aware. labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces()); @@ -838,11 +864,14 @@ Foam::meshRefinement::meshRefinement Foam::label Foam::meshRefinement::countHits() const { + // Stats on edges to test. Count proc faces only once. + PackedList<1> isMasterFace(syncTools::getMasterFaces(mesh_)); + label nHits = 0; forAll(surfaceIndex_, faceI) { - if (surfaceIndex_[faceI] >= 0) + if (surfaceIndex_[faceI] >= 0 && isMasterFace.get(faceI) == 1) { nHits++; } @@ -996,11 +1025,6 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance if (Pstream::parRun()) { - //Info<< nl - // << "Doing final balancing" << nl - // << "---------------------" << nl - // << endl; - // //if (debug_) //{ // const_cast<Time&>(mesh_.time())++; @@ -1014,17 +1038,12 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance // Faces where owner and neighbour are not 'connected' so can // go to different processors. boolList blockedFace(mesh_.nFaces(), true); + label nUnblocked = 0; // Pairs of baffles List<labelPair> couples; if (keepZoneFaces) { - label nNamed = surfaces().getNamedSurfaces().size(); - - Info<< "Found " << nNamed << " surfaces with faceZones." - << " Applying special decomposition to keep those together." - << endl; - // Determine decomposition to keep/move surface zones // on one processor. The reason is that snapping will make these // into baffles, move and convert them back so if they were @@ -1039,8 +1058,6 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance // Get faces whose owner and neighbour should stay together, // i.e. they are not 'blocked'. - label nZoned = 0; - forAll(fzNames, surfI) { if (fzNames[surfI].size() > 0) @@ -1055,14 +1072,18 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance if (blockedFace[fZone[i]]) { blockedFace[fZone[i]] = false; - nZoned++; + nUnblocked++; } } } } - Info<< "Found " << returnReduce(nZoned, sumOp<label>()) - << " zoned faces to keep together." - << endl; + } + reduce(nUnblocked, sumOp<label>()); + + if (keepZoneFaces) + { + Info<< "Found " << nUnblocked + << " zoned faces to keep together." << endl; } if (keepBaffles) @@ -1073,29 +1094,43 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance identity(mesh_.nFaces()-mesh_.nInternalFaces()) +mesh_.nInternalFaces() ); + } + label nCouples = returnReduce(couples.size(), sumOp<label>()); - Info<< "Found " << returnReduce(couples.size(), sumOp<label>()) - << " baffles to keep together." + if (keepBaffles) + { + Info<< "Found " << nCouples << " baffles to keep together." << endl; } - distribution = decomposeCombineRegions - ( - blockedFace, - couples, - decomposer - ); + if (nUnblocked > 0 || nCouples > 0) + { + Info<< "Applying special decomposition to keep baffles" + << " and zoned faces together." << endl; - labelList nProcCells(distributor.countCells(distribution)); - Pstream::listCombineGather(nProcCells, plusEqOp<label>()); - Pstream::listCombineScatter(nProcCells); + distribution = decomposeCombineRegions + ( + blockedFace, + couples, + decomposer + ); - Info<< "Calculated decomposition:" << endl; - forAll(nProcCells, procI) + labelList nProcCells(distributor.countCells(distribution)); + Pstream::listCombineGather(nProcCells, plusEqOp<label>()); + Pstream::listCombineScatter(nProcCells); + + Info<< "Calculated decomposition:" << endl; + forAll(nProcCells, procI) + { + Info<< " " << procI << '\t' << nProcCells[procI] << endl; + } + Info<< endl; + } + else { - Info<< " " << procI << '\t' << nProcCells[procI] << endl; + // Normal decomposition + distribution = decomposer.decompose(mesh_.cellCentres()); } - Info<< endl; } else { @@ -1715,6 +1750,36 @@ void Foam::meshRefinement::distribute(const mapDistributePolyMesh& map) { map.distributeFaceData(userFaceData_[i].second()); } + + // Redistribute surface and any fields on it. + { + Random rndGen(653213); + + // Get local mesh bounding box. Single box for now. + List<treeBoundBox> meshBb(1); + treeBoundBox& bb = meshBb[0]; + bb = boundBox(mesh_.points(), false); + bb = bb.extend(rndGen, 1E-4); + + // Distribute all geometry (so refinementSurfaces and shellSurfaces) + searchableSurfaces& geometry = + const_cast<searchableSurfaces&>(surfaces_.geometry()); + + forAll(geometry, i) + { + autoPtr<mapDistribute> faceMap; + autoPtr<mapDistribute> pointMap; + geometry[i].distribute + ( + meshBb, + false, // do not keep outside triangles + faceMap, + pointMap + ); + faceMap.clear(); + pointMap.clear(); + } + } } diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C index e6bd37f6709484919c1c94cc99257168ad12de9f..58c74d3fb4eb36f44e8f043c265751b1172d5a01 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementBaffles.C @@ -386,7 +386,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles FatalErrorIn ( "meshRefinement::createBaffles" - "(const label, const labelList&, const labelList&)" + "(const labelList&, const labelList&)" ) << "Illegal size :" << " ownPatch:" << ownPatch.size() << " neiPatch:" << neiPatch.size() @@ -412,7 +412,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles FatalErrorIn ( "meshRefinement::createBaffles" - "(const label, const labelList&, const labelList&)" + "(const labelList&, const labelList&)" ) << "Non synchronised at face:" << faceI << " on patch:" << mesh_.boundaryMesh().whichPatch(faceI) << " fc:" << mesh_.faceCentres()[faceI] << endl @@ -461,7 +461,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles //- Redo the intersections on the newly create baffle faces. Note that // this changes also the cell centre positions. - labelHashSet baffledFacesSet(2*nBaffles); + faceSet baffledFacesSet(mesh_, "baffledFacesSet", 2*nBaffles); const labelList& reverseFaceMap = map().reverseFaceMap(); const labelList& faceMap = map().faceMap(); @@ -496,6 +496,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createBaffles } } } + baffledFacesSet.sync(mesh_); updateMesh(map, baffledFacesSet.toc()); @@ -1886,15 +1887,15 @@ void Foam::meshRefinement::baffleAndSplitMesh labelList facePatch ( - //markFacesOnProblemCells - //( - // globalToPatch - //) - markFacesOnProblemCellsGeometric + markFacesOnProblemCells ( - motionDict, globalToPatch ) + //markFacesOnProblemCellsGeometric + //( + // motionDict, + // globalToPatch + //) ); Info<< "Analyzed problem cells in = " << runTime.cpuTimeIncrement() << " s\n" << nl << endl; diff --git a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C index e9eb2cb44594008297c317e9994e6b52cbea1d28..b457f0f5c7f5f919e9cbf0807b07fa46155a6af5 100644 --- a/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C +++ b/src/autoMesh/autoHexMesh/meshRefinement/meshRefinementRefine.C @@ -1091,8 +1091,8 @@ Foam::labelList Foam::meshRefinement::refineCandidates // << " local allowable refinement:" << nAllowRefine << nl // << endl; - //- Disable refinement shortcut - label nAllowRefine = labelMax; + //- Disable refinement shortcut. nAllowRefine is per processor limit. + label nAllowRefine = labelMax / Pstream::nProcs(); // Marked for refinement (>= 0) or not (-1). Actual value is the // index of the surface it intersects. diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C index 1654e3cd7fcae7de1e9a73d4186d304952d3598e..9629b53bdc133c7d8f364f5e82af274b3e46771a 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.C @@ -25,19 +25,13 @@ License \*----------------------------------------------------------------------------*/ #include "refinementSurfaces.H" -#include "orientedSurface.H" #include "Time.H" #include "searchableSurfaces.H" #include "shellSurfaces.H" #include "triSurfaceMesh.H" #include "labelPair.H" #include "searchableSurfacesQueries.H" - - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +#include "UPtrList.H" // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // @@ -438,31 +432,6 @@ Foam::labelList Foam::refinementSurfaces::getClosedNamedSurfaces() const } -// Orient surface (if they're closed) before any searching is done. -void Foam::refinementSurfaces::orientSurface -( - const point& keepPoint, - triSurfaceMesh& s -) -{ - // Flip surface so keepPoint is outside. - bool anyFlipped = orientedSurface::orient(s, keepPoint, true); - - if (anyFlipped) - { - // orientedSurface will have done a clearOut of the surface. - // we could do a clearout of the triSurfaceMeshes::trees() - // but these aren't affected by orientation (except for cached - // sideness which should not be set at this point. !!Should - // check!) - - Info<< "orientSurfaces : Flipped orientation of surface " - << s.searchableSurface::name() - << " so point " << keepPoint << " is outside." << endl; - } -} - - // Count number of triangles per surface region Foam::labelList Foam::refinementSurfaces::countRegions(const triSurface& s) { @@ -485,7 +454,7 @@ void Foam::refinementSurfaces::setMinLevelFields const shellSurfaces& shells ) { - minLevelFields_.setSize(surfaces_.size()); + //minLevelFields_.setSize(surfaces_.size()); forAll(surfaces_, surfI) { @@ -495,26 +464,24 @@ void Foam::refinementSurfaces::setMinLevelFields { const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom); - minLevelFields_.set + autoPtr<triSurfaceLabelField> minLevelFieldPtr ( - surfI, new triSurfaceLabelField ( IOobject ( - triMesh.searchableSurface::name(), + "minLevel", triMesh.objectRegistry::time().constant(),// directory "triSurface", // instance triMesh, IOobject::NO_READ, - IOobject::AUTO_WRITE, - false + IOobject::AUTO_WRITE ), triMesh, dimless ) ); - triSurfaceLabelField& minLevelField = minLevelFields_[surfI]; + triSurfaceLabelField& minLevelField = minLevelFieldPtr(); const triSurface& s = static_cast<const triSurface&>(triMesh); @@ -542,6 +509,9 @@ void Foam::refinementSurfaces::setMinLevelFields shellLevel[triI] ); } + + // Store field on triMesh + minLevelFieldPtr.ptr()->store(); } } } @@ -569,17 +539,38 @@ void Foam::refinementSurfaces::findHigherIntersection return; } + + // Precalculate per surface whether it has a minlevelfield + UPtrList<triSurfaceLabelField> minLevelFields(surfaces_.size()); + forAll(surfaces_, surfI) + { + const searchableSurface& geom = allGeometry_[surfaces_[surfI]]; + + if (isA<triSurfaceMesh>(geom)) + { + const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom); + minLevelFields.set + ( + surfI, + &const_cast<triSurfaceLabelField&> + ( + triMesh.lookupObject<triSurfaceLabelField>("minLevel") + ) + ); + } + } + // Work arrays labelList hitMap(identity(start.size())); pointField p0(start); pointField p1(end); List<pointIndexHit> hitInfo(start.size()); - forAll(surfaces_, surfI) { allGeometry_[surfaces_[surfI]].findLineAny(p0, p1, hitInfo); + // Copy all hits into arguments, continue with misses label newI = 0; forAll(hitInfo, hitI) @@ -592,12 +583,12 @@ void Foam::refinementSurfaces::findHigherIntersection // Check if minLevelField for this surface. if ( - minLevelFields_.set(surfI) - && minLevelFields_[surfI].size() > 0 + minLevelFields.set(surfI) + && minLevelFields[surfI].size() > 0 ) { minLocalLevel = - minLevelFields_[surfI][hitInfo[hitI].index()]; + minLevelFields[surfI][hitInfo[hitI].index()]; } else { @@ -668,30 +659,57 @@ void Foam::refinementSurfaces::findAllHigherIntersections { allGeometry_[surfaces_[surfI]].findLineAll(start, end, hitInfo); + // Repack hits for surface into flat list + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // To avoid overhead of calling getRegion for every point + + label n = 0; forAll(hitInfo, pointI) { - const List<pointIndexHit>& pHits = hitInfo[pointI]; - allGeometry_[surfaces_[surfI]].getRegion(pHits, pRegions); - allGeometry_[surfaces_[surfI]].getNormal(pHits, pNormals); + n += hitInfo[pointI].size(); + } - // Extract those hits that are on higher levelled surfaces. - // Note: should move extraction of region, normal outside of loop - // below for if getRegion/getNormal have high overhead. + List<pointIndexHit> surfInfo(n); + labelList pointMap(n); + n = 0; - forAll(pHits, pHitI) + forAll(hitInfo, pointI) + { + const List<pointIndexHit>& pHits = hitInfo[pointI]; + + forAll(pHits, i) { - label region = globalRegion(surfI, pRegions[pHitI]); + surfInfo[n] = pHits[i]; + pointMap[n] = pointI; + n++; + } + } - if (maxLevel_[region] > currentLevel[pointI]) - { - // Append to pointI info - label sz = surfaceNormal[pointI].size(); - surfaceNormal[pointI].setSize(sz+1); - surfaceNormal[pointI][sz] = pNormals[pHitI]; + labelList surfRegion(n); + vectorField surfNormal(n); + allGeometry_[surfaces_[surfI]].getRegion(surfInfo, surfRegion); + allGeometry_[surfaces_[surfI]].getNormal(surfInfo, surfNormal); - surfaceLevel[pointI].setSize(sz+1); - surfaceLevel[pointI][sz] = maxLevel_[region]; - } + surfInfo.clear(); + + + // Extract back into pointwise + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + forAll(surfRegion, i) + { + label region = globalRegion(surfI, surfRegion[i]); + label pointI = pointMap[i]; + + if (maxLevel_[region] > currentLevel[pointI]) + { + // Append to pointI info + label sz = surfaceNormal[pointI].size(); + surfaceNormal[pointI].setSize(sz+1); + surfaceNormal[pointI][sz] = surfNormal[i]; + + surfaceLevel[pointI].setSize(sz+1); + surfaceLevel[pointI][sz] = maxLevel_[region]; } } } diff --git a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H index ee5dd219a540cc5139e1d0ec0df11bc6dbf113ae..a20df19f29f76e5d57b0a90725dc2ff8ddb6e9b2 100644 --- a/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H +++ b/src/autoMesh/autoHexMesh/refinementSurfaces/refinementSurfaces.H @@ -90,9 +90,6 @@ class refinementSurfaces //- From global region number to refinement level labelList maxLevel_; - //- Per surface refinement level adapted for shells. - PtrList<triSurfaceLabelField> minLevelFields_; - // Private Member Functions @@ -213,13 +210,6 @@ public: const shellSurfaces& shells ); - //- Helper: orient (closed only) surfaces so keepPoint is outside. - static void orientSurface - ( - const point& keepPoint, - triSurfaceMesh& surface - ); - //- Helper: count number of triangles per region static labelList countRegions(const triSurface&); diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C new file mode 100644 index 0000000000000000000000000000000000000000..b0ac2357974615fa07e8577a999a7ae3ebf07788 --- /dev/null +++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.C @@ -0,0 +1,2217 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "distributedTriSurfaceMesh.H" +#include "mapDistribute.H" +#include "Random.H" +#include "addToRunTimeSelectionTable.H" +#include "triangleFuncs.H" +#include "matchPoints.H" +#include "globalIndex.H" +#include "Time.H" + + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + +defineTypeNameAndDebug(distributedTriSurfaceMesh, 0); +addToRunTimeSelectionTable(searchableSurface, distributedTriSurfaceMesh, dict); + +scalar distributedTriSurfaceMesh::mergeDist_ = SMALL; + +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +// Read my additional data from the dictionary +bool Foam::distributedTriSurfaceMesh::read() +{ + // Get bb of all domains + procBb_.setSize(Pstream::nProcs()); + + procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds")); + Pstream::gatherList(procBb_); + Pstream::scatterList(procBb_); + + return true; +} + + +// Is segment fully local? +bool Foam::distributedTriSurfaceMesh::isLocal +( + const List<treeBoundBox>& myBbs, + const point& start, + const point& end +) +{ + forAll(myBbs, bbI) + { + if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end)) + { + return true; + } + } + return false; +} + + +void Foam::distributedTriSurfaceMesh::splitSegment +( + const label segmentI, + const point& start, + const point& end, + + DynamicList<Pair<point> >& allSegments, + DynamicList<label>& allSegmentMap, + List<DynamicList<label> >& sendMap +) const +{ + // Work points + point clipPt0, clipPt1; + + + // 1. Fully local already handled outside + + + // 2. Check if fully inside other processor. Rare occurrence + // but cheap to test. + + forAll(procBb_, procI) + { + if (procI != Pstream::myProcNo()) + { + const List<treeBoundBox>& bbs = procBb_[procI]; + + forAll(bbs, bbI) + { + if (bbs[bbI].contains(start) && bbs[bbI].contains(end)) + { + //Pout<< " Completely remote segment:" + // << start << end << " on proc:" << procI << endl; + sendMap[procI].append(allSegments.size()); + allSegmentMap.append(segmentI); + allSegments.append(Pair<point>(start, end)); + return; + } + } + } + } + + + // 3. Not contained in single processor. Clip against proc bbs. + forAll(procBb_, procI) + { + const List<treeBoundBox>& bbs = procBb_[procI]; + + forAll(bbs, bbI) + { + const treeBoundBox& bb = bbs[bbI]; + + if (bb.contains(start)) + { + // start within, trim end to bb + bool clipped = bb.intersects(end, start, clipPt0); + + if (clipped) + { + //Pout<< " Start of segment:" + // << start << end << " clips proc:" << procI + // << " at " << clipPt0 << endl; + // segment from start to clippedStart passes + // through proc. + sendMap[procI].append(allSegments.size()); + allSegmentMap.append(segmentI); + allSegments.append(Pair<point>(start, clipPt0)); + } + } + else if (bb.contains(end)) + { + // end within, trim start to bb + bool clipped = bb.intersects(start, end, clipPt0); + + if (clipped) + { + //Pout<< " End of segment:" + // << start << end << " clips proc:" << procI + // << " at " << clipPt0 << endl; + sendMap[procI].append(allSegments.size()); + allSegmentMap.append(segmentI); + allSegments.append(Pair<point>(clipPt0, end)); + } + } + else + { + // trim both + bool clippedStart = bb.intersects(start, end, clipPt0); + + if (clippedStart) + { + bool clippedEnd = bb.intersects(end, clipPt0, clipPt1); + + if (clippedEnd) + { + //Pout<< " Middle of segment:" + // << start << end << " clips proc:" << procI + // << " at " << clipPt0 << clipPt1 << endl; + // middle part of segment passes through + // proc. + sendMap[procI].append(allSegments.size()); + allSegmentMap.append(segmentI); + allSegments.append(Pair<point>(clipPt0, clipPt1)); + } + } + } + } + } +} + + +Foam::autoPtr<Foam::mapDistribute> +Foam::distributedTriSurfaceMesh::constructSegments +( + const pointField& start, + const pointField& end, + + List<Pair<point> >& allSegments, + labelList& allSegmentMap +) const +{ + // Determine send map + // ~~~~~~~~~~~~~~~~~~ + + labelListList sendMap(Pstream::nProcs()); + + { + // Since intersection test is quite expensive compared to memory + // allocation we use DynamicList to immediately store the segment + // in the correct bin. + + // Segments to test + DynamicList<Pair<point> > dynAllSegments(start.size()); + // Original index of segment + DynamicList<label> dynAllSegmentMap(start.size()); + // Per processor indices into allSegments to send + List<DynamicList<label> > dynSendMap(Pstream::nProcs()); + + forAll(start, segmentI) + { + splitSegment + ( + segmentI, + start[segmentI], + end[segmentI], + + dynAllSegments, + dynAllSegmentMap, + dynSendMap + ); + } + + // Convert dynamicList to labelList + sendMap.setSize(Pstream::nProcs()); + forAll(sendMap, procI) + { + dynSendMap[procI].shrink(); + sendMap[procI].transfer(dynSendMap[procI]); + dynSendMap[procI].clear(); + } + + allSegments.transfer(dynAllSegments.shrink()); + dynAllSegments.clear(); + allSegmentMap.transfer(dynAllSegmentMap.shrink()); + dynAllSegmentMap.clear(); + } + + + // Send over how many I need to receive. + labelListList sendSizes(Pstream::nProcs()); + sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs()); + forAll(sendMap, procI) + { + sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size(); + } + Pstream::gatherList(sendSizes); + Pstream::scatterList(sendSizes); + + + // Determine order of receiving + labelListList constructMap(Pstream::nProcs()); + + // My local segments first + constructMap[Pstream::myProcNo()] = identity + ( + sendMap[Pstream::myProcNo()].size() + ); + + label segmentI = constructMap[Pstream::myProcNo()].size(); + forAll(constructMap, procI) + { + if (procI != Pstream::myProcNo()) + { + // What I need to receive is what other processor is sending to me. + label nRecv = sendSizes[procI][Pstream::myProcNo()]; + constructMap[procI].setSize(nRecv); + + for (label i = 0; i < nRecv; i++) + { + constructMap[procI][i] = segmentI++; + } + } + } + + return autoPtr<mapDistribute> + ( + new mapDistribute + ( + segmentI, // size after construction + sendMap, + constructMap, + true // reuse storage + ) + ); +} + + +void Foam::distributedTriSurfaceMesh::findLine +( + const bool nearestIntersection, + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + // Important:force synchronised construction of indexing + const globalIndex& triIndexer = globalTris(); + + // Initialise + info.setSize(start.size()); + forAll(info, i) + { + info[i].setMiss(); + } + + + // Do any local queries + // ~~~~~~~~~~~~~~~~~~~~ + + label nLocal = 0; + + forAll(start, i) + { + if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i])) + { + if (nearestIntersection) + { + info[i] = octree.findLine(start[i], end[i]); + } + else + { + info[i] = octree.findLineAny(start[i], end[i]); + } + + if (info[i].hit()) + { + info[i].setIndex(triIndexer.toGlobal(info[i].index())); + } + nLocal++; + } + } + + + if + ( + Pstream::parRun() + && ( + returnReduce(nLocal, sumOp<label>()) + < returnReduce(start.size(), sumOp<label>()) + ) + ) + { + // Not all can be resolved locally. Build segments and map, send over + // segments, do intersections, send back and merge. + + + // Construct queries (segments) + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + // Segments to test + List<Pair<point> > allSegments(start.size()); + // Original index of segment + labelList allSegmentMap(start.size()); + + const autoPtr<mapDistribute> mapPtr + ( + constructSegments + ( + start, + end, + allSegments, + allSegmentMap + ) + ); + const mapDistribute& map = mapPtr(); + + label nOldAllSegments = allSegments.size(); + + + // Exchange the segments + // ~~~~~~~~~~~~~~~~~~~~~ + + map.distribute + ( + Pstream::nonBlocking, //Pstream::scheduled, + List<labelPair>(0), //map.schedule(), + map.constructSize(), + map.subMap(), // what to send + map.constructMap(), // what to receive + allSegments + ); + + + // Do tests I need to do + // ~~~~~~~~~~~~~~~~~~~~~ + + // Intersections + List<pointIndexHit> intersections(allSegments.size()); + + forAll(allSegments, i) + { + if (nearestIntersection) + { + intersections[i] = octree.findLine + ( + allSegments[i].first(), + allSegments[i].second() + ); + } + else + { + intersections[i] = octree.findLineAny + ( + allSegments[i].first(), + allSegments[i].second() + ); + } + + // Convert triangle index to global numbering + if (intersections[i].hit()) + { + intersections[i].setIndex + ( + triIndexer.toGlobal(intersections[i].index()) + ); + } + } + + + // Exchange the intersections (opposite to segments) + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule // Note reverse schedule + //( + // map.constructMap(), + // map.subMap() + //), + Pstream::nonBlocking, + List<labelPair>(0), + nOldAllSegments, + map.constructMap(), // what to send + map.subMap(), // what to receive + intersections + ); + + + // Extract the hits + // ~~~~~~~~~~~~~~~~ + + forAll(intersections, i) + { + const pointIndexHit& allInfo = intersections[i]; + label segmentI = allSegmentMap[i]; + pointIndexHit& hitInfo = info[segmentI]; + + if (allInfo.hit()) + { + if (!hitInfo.hit()) + { + // No intersection yet so take this one + hitInfo = allInfo; + } + else if (nearestIntersection) + { + // Nearest intersection + if + ( + magSqr(allInfo.hitPoint()-start[segmentI]) + < magSqr(hitInfo.hitPoint()-start[segmentI]) + ) + { + hitInfo = allInfo; + } + } + } + } + } +} + + +// Exchanges indices to the processor they come from. +// - calculates exchange map +// - uses map to calculate local triangle index +Foam::autoPtr<Foam::mapDistribute> +Foam::distributedTriSurfaceMesh::calcLocalQueries +( + const List<pointIndexHit>& info, + labelList& triangleIndex +) const +{ + triangleIndex.setSize(info.size()); + + const globalIndex& triIndexer = globalTris(); + + + // Determine send map + // ~~~~~~~~~~~~~~~~~~ + + // Since determining which processor the query should go to is + // cheap we do a multi-pass algorithm to save some memory temporarily. + + // 1. Count + labelList nSend(Pstream::nProcs(), 0); + + forAll(info, i) + { + if (info[i].hit()) + { + label procI = triIndexer.whichProcID(info[i].index()); + nSend[procI]++; + } + } + + // 2. Size sendMap + labelListList sendMap(Pstream::nProcs()); + forAll(nSend, procI) + { + sendMap[procI].setSize(nSend[procI]); + nSend[procI] = 0; + } + + // 3. Fill sendMap + forAll(info, i) + { + if (info[i].hit()) + { + label procI = triIndexer.whichProcID(info[i].index()); + triangleIndex[i] = triIndexer.toLocal(procI, info[i].index()); + sendMap[procI][nSend[procI]++] = i; + } + else + { + triangleIndex[i] = -1; + } + } + + + // Send over how many I need to receive + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelListList sendSizes(Pstream::nProcs()); + sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs()); + forAll(sendMap, procI) + { + sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size(); + } + Pstream::gatherList(sendSizes); + Pstream::scatterList(sendSizes); + + + // Determine receive map + // ~~~~~~~~~~~~~~~~~~~~~ + + labelListList constructMap(Pstream::nProcs()); + + // My local segments first + constructMap[Pstream::myProcNo()] = identity + ( + sendMap[Pstream::myProcNo()].size() + ); + + label segmentI = constructMap[Pstream::myProcNo()].size(); + forAll(constructMap, procI) + { + if (procI != Pstream::myProcNo()) + { + // What I need to receive is what other processor is sending to me. + label nRecv = sendSizes[procI][Pstream::myProcNo()]; + constructMap[procI].setSize(nRecv); + + for (label i = 0; i < nRecv; i++) + { + constructMap[procI][i] = segmentI++; + } + } + } + + + // Pack into distribution map + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + autoPtr<mapDistribute> mapPtr + ( + new mapDistribute + ( + segmentI, // size after construction + sendMap, + constructMap, + true // reuse storage + ) + ); + const mapDistribute& map = mapPtr(); + + + // Send over queries + // ~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule(), + Pstream::nonBlocking, + List<labelPair>(0), + map.constructSize(), + map.subMap(), // what to send + map.constructMap(), // what to receive + triangleIndex + ); + + + return mapPtr; +} + + +Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs +( + const point& centre, + const scalar radiusSqr, + boolList& overlaps +) const +{ + overlaps = false; + label nOverlaps = 0; + + forAll(procBb_, procI) + { + const List<treeBoundBox>& bbs = procBb_[procI]; + + forAll(bbs, bbI) + { + if (bbs[bbI].overlaps(centre, radiusSqr)) + { + overlaps[procI] = true; + nOverlaps++; + break; + } + } + } + return nOverlaps; +} + + +// Generate queries for parallel distance calculation +// - calculates exchange map +// - uses map to exchange points and radius +Foam::autoPtr<Foam::mapDistribute> +Foam::distributedTriSurfaceMesh::calcLocalQueries +( + const pointField& centres, + const scalarField& radiusSqr, + + pointField& allCentres, + scalarField& allRadiusSqr, + labelList& allSegmentMap +) const +{ + // Determine queries + // ~~~~~~~~~~~~~~~~~ + + labelListList sendMap(Pstream::nProcs()); + + { + // Queries + DynamicList<point> dynAllCentres(centres.size()); + DynamicList<scalar> dynAllRadiusSqr(centres.size()); + // Original index of segment + DynamicList<label> dynAllSegmentMap(centres.size()); + // Per processor indices into allSegments to send + List<DynamicList<label> > dynSendMap(Pstream::nProcs()); + + // Work array - whether processor bb overlaps the bounding sphere. + boolList procBbOverlaps(Pstream::nProcs()); + + forAll(centres, centreI) + { + // Find the processor this sample+radius overlaps. + calcOverlappingProcs + ( + centres[centreI], + radiusSqr[centreI], + procBbOverlaps + ); + + forAll(procBbOverlaps, procI) + { + if (procI != Pstream::myProcNo() && procBbOverlaps[procI]) + { + dynSendMap[procI].append(dynAllCentres.size()); + dynAllSegmentMap.append(centreI); + dynAllCentres.append(centres[centreI]); + dynAllRadiusSqr.append(radiusSqr[centreI]); + } + } + } + + // Convert dynamicList to labelList + sendMap.setSize(Pstream::nProcs()); + forAll(sendMap, procI) + { + dynSendMap[procI].shrink(); + sendMap[procI].transfer(dynSendMap[procI]); + dynSendMap[procI].clear(); + } + + allCentres.transfer(dynAllCentres.shrink()); + dynAllCentres.clear(); + allRadiusSqr.transfer(dynAllRadiusSqr.shrink()); + dynAllRadiusSqr.clear(); + allSegmentMap.transfer(dynAllSegmentMap.shrink()); + dynAllSegmentMap.clear(); + } + + + // Send over how many I need to receive. + labelListList sendSizes(Pstream::nProcs()); + sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs()); + forAll(sendMap, procI) + { + sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size(); + } + Pstream::gatherList(sendSizes); + Pstream::scatterList(sendSizes); + + + // Determine order of receiving + labelListList constructMap(Pstream::nProcs()); + + // My local segments first + constructMap[Pstream::myProcNo()] = identity + ( + sendMap[Pstream::myProcNo()].size() + ); + + label segmentI = constructMap[Pstream::myProcNo()].size(); + forAll(constructMap, procI) + { + if (procI != Pstream::myProcNo()) + { + // What I need to receive is what other processor is sending to me. + label nRecv = sendSizes[procI][Pstream::myProcNo()]; + constructMap[procI].setSize(nRecv); + + for (label i = 0; i < nRecv; i++) + { + constructMap[procI][i] = segmentI++; + } + } + } + + autoPtr<mapDistribute> mapPtr + ( + new mapDistribute + ( + segmentI, // size after construction + sendMap, + constructMap, + true // reuse storage + ) + ); + return mapPtr; +} + + +void Foam::distributedTriSurfaceMesh::calcBounds +( + boundBox& bb, + label& nPoints +) const +{ + // Unfortunately nPoints constructs meshPoints() so do compact version + // ourselves + + PackedList<1> pointIsUsed(points().size()); + pointIsUsed = 0U; + + nPoints = 0; + bb.min() = point(VGREAT, VGREAT, VGREAT); + bb.max() = point(-VGREAT, -VGREAT, -VGREAT); + + const triSurface& s = static_cast<const triSurface&>(*this); + + forAll(s, triI) + { + const labelledTri& f = s[triI]; + + forAll(f, fp) + { + label pointI = f[fp]; + if (pointIsUsed.set(pointI, 1)) + { + bb.min() = ::Foam::min(bb.min(), points()[pointI]); + bb.max() = ::Foam::max(bb.max(), points()[pointI]); + nPoints++; + } + } + } +} + + +// Does any part of triangle overlap bb. +bool Foam::distributedTriSurfaceMesh::overlaps +( + const List<treeBoundBox>& bbs, + const point& p0, + const point& p1, + const point& p2 +) +{ + forAll(bbs, bbI) + { + const treeBoundBox& bb = bbs[bbI]; + + boundBox triBb(p0, p0); + triBb.min() = min(triBb.min(), p1); + triBb.min() = min(triBb.min(), p2); + + triBb.max() = max(triBb.max(), p1); + triBb.max() = max(triBb.max(), p2); + + //- Exact test of triangle intersecting bb + + // Quick rejection. If whole bounding box of tri is outside cubeBb then + // there will be no intersection. + if (bb.overlaps(triBb)) + { + // Check if one or more triangle point inside + if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2)) + { + // One or more points inside + return true; + } + + // Now we have the difficult case: all points are outside but + // connecting edges might go through cube. Use fast intersection + // of bounding box. + bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb); + + if (intersect) + { + return true; + } + } + } + return false; +} + + +void Foam::distributedTriSurfaceMesh::subsetMeshMap +( + const triSurface& s, + const boolList& include, + const label nIncluded, + labelList& newToOldPoints, + labelList& oldToNewPoints, + labelList& newToOldFaces +) +{ + newToOldFaces.setSize(nIncluded); + newToOldPoints.setSize(s.points().size()); + oldToNewPoints.setSize(s.points().size()); + oldToNewPoints = -1; + { + label faceI = 0; + label pointI = 0; + + forAll(include, oldFacei) + { + if (include[oldFacei]) + { + // Store new faces compact + newToOldFaces[faceI++] = oldFacei; + + // Renumber labels for triangle + const labelledTri& tri = s[oldFacei]; + + forAll(tri, fp) + { + label oldPointI = tri[fp]; + + if (oldToNewPoints[oldPointI] == -1) + { + oldToNewPoints[oldPointI] = pointI; + newToOldPoints[pointI++] = oldPointI; + } + } + } + } + newToOldPoints.setSize(pointI); + } +} + + +Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh +( + const triSurface& s, + const labelList& newToOldPoints, + const labelList& oldToNewPoints, + const labelList& newToOldFaces +) +{ + // Extract points + pointField newPoints(newToOldPoints.size()); + forAll(newToOldPoints, i) + { + newPoints[i] = s.points()[newToOldPoints[i]]; + } + // Extract faces + List<labelledTri> newTriangles(newToOldFaces.size()); + + forAll(newToOldFaces, i) + { + // Get old vertex labels + const labelledTri& tri = s[newToOldFaces[i]]; + + newTriangles[i][0] = oldToNewPoints[tri[0]]; + newTriangles[i][1] = oldToNewPoints[tri[1]]; + newTriangles[i][2] = oldToNewPoints[tri[2]]; + newTriangles[i].region() = tri.region(); + } + + // Reuse storage. + return triSurface(newTriangles, s.patches(), newPoints, true); +} + + +Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh +( + const triSurface& s, + const boolList& include, + labelList& newToOldPoints, + labelList& newToOldFaces +) +{ + label n = 0; + + forAll(include, i) + { + if (include[i]) + { + n++; + } + } + + labelList oldToNewPoints; + subsetMeshMap + ( + s, + include, + n, + newToOldPoints, + oldToNewPoints, + newToOldFaces + ); + + return subsetMesh + ( + s, + newToOldPoints, + oldToNewPoints, + newToOldFaces + ); +} + + +Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh +( + const triSurface& s, + const labelList& newToOldFaces, + labelList& newToOldPoints +) +{ + const boolList include + ( + createWithValues<boolList> + ( + s.size(), + false, + newToOldFaces, + true + ) + ); + + newToOldPoints.setSize(s.points().size()); + labelList oldToNewPoints(s.points().size(), -1); + { + label pointI = 0; + + forAll(include, oldFacei) + { + if (include[oldFacei]) + { + // Renumber labels for triangle + const labelledTri& tri = s[oldFacei]; + + forAll(tri, fp) + { + label oldPointI = tri[fp]; + + if (oldToNewPoints[oldPointI] == -1) + { + oldToNewPoints[oldPointI] = pointI; + newToOldPoints[pointI++] = oldPointI; + } + } + } + } + newToOldPoints.setSize(pointI); + } + + return subsetMesh + ( + s, + newToOldPoints, + oldToNewPoints, + newToOldFaces + ); +} + + +Foam::label Foam::distributedTriSurfaceMesh::findTriangle +( + const List<labelledTri>& allFaces, + const labelListList& allPointFaces, + const labelledTri& otherF +) +{ + // allFaces connected to otherF[0] + const labelList& pFaces = allPointFaces[otherF[0]]; + + forAll(pFaces, i) + { + const labelledTri& f = allFaces[pFaces[i]]; + + if (f.region() == otherF.region()) + { + // Find index of otherF[0] + label fp0 = findIndex(f, otherF[0]); + // Check rest of triangle in same order + label fp1 = f.fcIndex(fp0); + label fp2 = f.fcIndex(fp1); + + if (f[fp1] == otherF[1] && f[fp2] == otherF[2]) + { + return pFaces[i]; + } + } + } + return -1; +} + + +// Merge into allSurf. +void Foam::distributedTriSurfaceMesh::merge +( + const scalar mergeDist, + const List<labelledTri>& subTris, + const pointField& subPoints, + + List<labelledTri>& allTris, + pointField& allPoints, + + labelList& faceConstructMap, + labelList& pointConstructMap +) +{ + labelList subToAll; + matchPoints + ( + subPoints, + allPoints, + scalarField(subPoints.size(), mergeDist), // match distance + false, // verbose + pointConstructMap + ); + + label nOldAllPoints = allPoints.size(); + + + // Add all unmatched points + // ~~~~~~~~~~~~~~~~~~~~~~~~ + + label allPointI = nOldAllPoints; + forAll(pointConstructMap, pointI) + { + if (pointConstructMap[pointI] == -1) + { + pointConstructMap[pointI] = allPointI++; + } + } + + if (allPointI > nOldAllPoints) + { + allPoints.setSize(allPointI); + + forAll(pointConstructMap, pointI) + { + if (pointConstructMap[pointI] >= nOldAllPoints) + { + allPoints[pointConstructMap[pointI]] = subPoints[pointI]; + } + } + } + + + // To check whether triangles are same we use pointFaces. + labelListList allPointFaces; + invertManyToMany(nOldAllPoints, allTris, allPointFaces); + + + // Add all unmatched triangles + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + label allTriI = allTris.size(); + allTris.setSize(allTriI + subTris.size()); + + faceConstructMap.setSize(subTris.size()); + + forAll(subTris, triI) + { + const labelledTri& subTri = subTris[triI]; + + // Get triangle in new numbering + labelledTri mappedTri + ( + pointConstructMap[subTri[0]], + pointConstructMap[subTri[1]], + pointConstructMap[subTri[2]], + subTri.region() + ); + + + // Check if all points were already in surface + bool fullMatch = true; + + forAll(mappedTri, fp) + { + if (mappedTri[fp] >= nOldAllPoints) + { + fullMatch = false; + break; + } + } + + if (fullMatch) + { + // All three points are mapped to old points. See if same + // triangle. + label i = findTriangle + ( + allTris, + allPointFaces, + mappedTri + ); + + if (i == -1) + { + // Add + faceConstructMap[triI] = allTriI; + allTris[allTriI] = mappedTri; + allTriI++; + } + else + { + faceConstructMap[triI] = i; + } + } + else + { + // Add + faceConstructMap[triI] = allTriI; + allTris[allTriI] = mappedTri; + allTriI++; + } + } + allTris.setSize(allTriI); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh +( + const IOobject& io, + const triSurface& s, + const dictionary& dict +) +: + triSurfaceMesh(io, s), + dict_(io, dict) +{ + read(); +} + + +Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io) +: + triSurfaceMesh(io), + dict_ + ( + IOobject + ( + io.name() + "Dict", + io.instance(), + io.local(), + io.db(), + io.readOpt(), + io.writeOpt(), + io.registerObject() + ) + ) +{ + read(); +} + + +Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh +( + const IOobject& io, + const dictionary& dict +) +: + triSurfaceMesh(io, dict), + dict_ + ( + IOobject + ( + io.name() + "Dict", + io.instance(), + io.local(), + io.db(), + io.readOpt(), + io.writeOpt(), + io.registerObject() + ) + ) +{ + read(); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh() +{ + clearOut(); +} + + +void Foam::distributedTriSurfaceMesh::clearOut() +{ + globalTris_.clear(); + triSurfaceMesh::clearOut(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const +{ + if (!globalTris_.valid()) + { + globalTris_.reset(new globalIndex(triSurface::size())); + } + return globalTris_; +} + + +void Foam::distributedTriSurfaceMesh::findNearest +( + const pointField& samples, + const scalarField& nearestDistSqr, + List<pointIndexHit>& info +) const +{ + const indexedOctree<treeDataTriSurface>& octree = tree(); + + // Important:force synchronised construction of indexing + const globalIndex& triIndexer = globalTris(); + + + // Initialise + // ~~~~~~~~~~ + + info.setSize(samples.size()); + forAll(info, i) + { + info[i].setMiss(); + } + + + + // Do any local queries + // ~~~~~~~~~~~~~~~~~~~~ + + label nLocal = 0; + + { + // Work array - whether processor bb overlaps the bounding sphere. + boolList procBbOverlaps(Pstream::nProcs()); + + forAll(samples, i) + { + // Find the processor this sample+radius overlaps. + label nProcs = calcOverlappingProcs + ( + samples[i], + nearestDistSqr[i], + procBbOverlaps + ); + + // Overlaps local processor? + if (procBbOverlaps[Pstream::myProcNo()]) + { + info[i] = octree.findNearest(samples[i], nearestDistSqr[i]); + if (info[i].hit()) + { + info[i].setIndex(triIndexer.toGlobal(info[i].index())); + } + if (nProcs == 1) + { + // Fully local + nLocal++; + } + } + } + } + + + if + ( + Pstream::parRun() + && ( + returnReduce(nLocal, sumOp<label>()) + < returnReduce(samples.size(), sumOp<label>()) + ) + ) + { + // Not all can be resolved locally. Build queries and map, send over + // queries, do intersections, send back and merge. + + // Calculate queries and exchange map + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + pointField allCentres; + scalarField allRadiusSqr; + labelList allSegmentMap; + autoPtr<mapDistribute> mapPtr + ( + calcLocalQueries + ( + samples, + nearestDistSqr, + + allCentres, + allRadiusSqr, + allSegmentMap + ) + ); + const mapDistribute& map = mapPtr(); + + + // swap samples to local processor + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule(), + Pstream::nonBlocking, + List<labelPair>(0), + map.constructSize(), + map.subMap(), // what to send + map.constructMap(), // what to receive + allCentres + ); + map.distribute + ( + //Pstream::scheduled, + //map.schedule(), + Pstream::nonBlocking, + List<labelPair>(0), + map.constructSize(), + map.subMap(), // what to send + map.constructMap(), // what to receive + allRadiusSqr + ); + + + // Do my tests + // ~~~~~~~~~~~ + + List<pointIndexHit> allInfo(allCentres.size()); + forAll(allInfo, i) + { + allInfo[i] = octree.findNearest + ( + allCentres[i], + allRadiusSqr[i] + ); + if (allInfo[i].hit()) + { + allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index())); + } + } + + + // Send back results + // ~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule // note reverse schedule + //( + // map.constructMap(), + // map.subMap() + //), + Pstream::nonBlocking, + List<labelPair>(0), + allSegmentMap.size(), + map.constructMap(), // what to send + map.subMap(), // what to receive + allInfo + ); + + + // Extract information + // ~~~~~~~~~~~~~~~~~~~ + + forAll(allInfo, i) + { + if (allInfo[i].hit()) + { + label pointI = allSegmentMap[i]; + + if (!info[pointI].hit()) + { + // No intersection yet so take this one + info[pointI] = allInfo[i]; + } + else + { + // Nearest intersection + if + ( + magSqr(allInfo[i].hitPoint()-samples[pointI]) + < magSqr(info[pointI].hitPoint()-samples[pointI]) + ) + { + info[pointI] = allInfo[i]; + } + } + } + } + } +} + + +void Foam::distributedTriSurfaceMesh::findLine +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + findLine + ( + true, // nearestIntersection + start, + end, + info + ); +} + + +void Foam::distributedTriSurfaceMesh::findLineAny +( + const pointField& start, + const pointField& end, + List<pointIndexHit>& info +) const +{ + findLine + ( + true, // nearestIntersection + start, + end, + info + ); +} + + +void Foam::distributedTriSurfaceMesh::findLineAll +( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& info +) const +{ + // Reuse fineLine. We could modify all of findLine to do multiple + // intersections but this would mean a lot of data transferred so + // for now we just find nearest intersection and retest from that + // intersection onwards. + + // Work array. + List<pointIndexHit> hitInfo(start.size()); + + findLine + ( + true, // nearestIntersection + start, + end, + hitInfo + ); + + // Tolerances: + // To find all intersections we add a small vector to the last intersection + // This is chosen such that + // - it is significant (SMALL is smallest representative relative tolerance; + // we need something bigger since we're doing calculations) + // - if the start-end vector is zero we still progress + const vectorField dirVec(end-start); + const scalarField magSqrDirVec(magSqr(dirVec)); + const vectorField smallVec + ( + Foam::sqrt(SMALL)*dirVec + + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL) + ); + + // Copy to input and compact any hits + labelList pointMap(start.size()); + pointField e0(start.size()); + pointField e1(start.size()); + label compactI = 0; + + info.setSize(hitInfo.size()); + forAll(hitInfo, pointI) + { + if (hitInfo[pointI].hit()) + { + info[pointI].setSize(1); + info[pointI][0] = hitInfo[pointI]; + + point pt = hitInfo[pointI].hitPoint() + smallVec[pointI]; + + if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI]) + { + e0[compactI] = pt; + e1[compactI] = end[pointI]; + pointMap[compactI] = pointI; + compactI++; + } + } + else + { + info[pointI].clear(); + } + } + + e0.setSize(compactI); + e1.setSize(compactI); + pointMap.setSize(compactI); + + while (returnReduce(e0.size(), sumOp<label>()) > 0) + { + findLine + ( + true, // nearestIntersection + e0, + e1, + hitInfo + ); + + + // Extract + label compactI = 0; + forAll(hitInfo, i) + { + if (hitInfo[i].hit()) + { + label pointI = pointMap[i]; + + label sz = info[pointI].size(); + info[pointI].setSize(sz+1); + info[pointI][sz] = hitInfo[i]; + + point pt = hitInfo[i].hitPoint() + smallVec[pointI]; + + if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI]) + { + e0[compactI] = pt; + e1[compactI] = end[pointI]; + pointMap[compactI] = pointI; + compactI++; + } + } + } + + // Trim + e0.setSize(compactI); + e1.setSize(compactI); + pointMap.setSize(compactI); + } +} + + +void Foam::distributedTriSurfaceMesh::getRegion +( + const List<pointIndexHit>& info, + labelList& region +) const +{ + if (!Pstream::parRun()) + { + region.setSize(info.size()); + forAll(info, i) + { + if (info[i].hit()) + { + region[i] = triSurface::operator[](info[i].index()).region(); + } + else + { + region[i] = -1; + } + } + return; + } + + + // Get query data (= local index of triangle) + // ~~~~~~~~~~~~~~ + + labelList triangleIndex(info.size()); + autoPtr<mapDistribute> mapPtr + ( + calcLocalQueries + ( + info, + triangleIndex + ) + ); + const mapDistribute& map = mapPtr(); + + + // Do my tests + // ~~~~~~~~~~~ + + const triSurface& s = static_cast<const triSurface&>(*this); + + region.setSize(triangleIndex.size()); + + forAll(triangleIndex, i) + { + label triI = triangleIndex[i]; + region[i] = s[triI].region(); + } + + + // Send back results + // ~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule // note reverse schedule + //( + // map.constructMap(), + // map.subMap() + //), + Pstream::nonBlocking, + List<labelPair>(0), + info.size(), + map.constructMap(), // what to send + map.subMap(), // what to receive + region + ); +} + + +void Foam::distributedTriSurfaceMesh::getNormal +( + const List<pointIndexHit>& info, + vectorField& normal +) const +{ + if (!Pstream::parRun()) + { + normal.setSize(info.size()); + + forAll(info, i) + { + if (info[i].hit()) + { + normal[i] = faceNormals()[info[i].index()]; + } + else + { + // Set to what? + normal[i] = vector::zero; + } + } + return; + } + + + // Get query data (= local index of triangle) + // ~~~~~~~~~~~~~~ + + labelList triangleIndex(info.size()); + autoPtr<mapDistribute> mapPtr + ( + calcLocalQueries + ( + info, + triangleIndex + ) + ); + const mapDistribute& map = mapPtr(); + + + // Do my tests + // ~~~~~~~~~~~ + + const triSurface& s = static_cast<const triSurface&>(*this); + + normal.setSize(triangleIndex.size()); + + forAll(triangleIndex, i) + { + label triI = triangleIndex[i]; + normal[i] = s[triI].normal(s.points()); + normal[i] /= mag(normal[i]) + VSMALL; + } + + + // Send back results + // ~~~~~~~~~~~~~~~~~ + + map.distribute + ( + //Pstream::scheduled, + //map.schedule // note reverse schedule + //( + // map.constructMap(), + // map.subMap() + //), + Pstream::nonBlocking, + List<labelPair>(0), + info.size(), + map.constructMap(), // what to send + map.subMap(), // what to receive + normal + ); +} + + +void Foam::distributedTriSurfaceMesh::getField +( + const word& fieldName, + const List<pointIndexHit>& info, + labelList& values +) const +{ + const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField> + ( + fieldName + ); + + + if (!Pstream::parRun()) + { + values.setSize(info.size()); + forAll(info, i) + { + if (info[i].hit()) + { + values[i] = fld[info[i].index()]; + } + } + return; + } + + + // Get query data (= local index of triangle) + // ~~~~~~~~~~~~~~ + + labelList triangleIndex(info.size()); + autoPtr<mapDistribute> mapPtr + ( + calcLocalQueries + ( + info, + triangleIndex + ) + ); + const mapDistribute& map = mapPtr(); + + + // Do my tests + // ~~~~~~~~~~~ + + values.setSize(triangleIndex.size()); + + forAll(triangleIndex, i) + { + label triI = triangleIndex[i]; + values[i] = fld[triI]; + } + + + // Send back results + // ~~~~~~~~~~~~~~~~~ + + map.distribute + ( + Pstream::nonBlocking, + List<labelPair>(0), + info.size(), + map.constructMap(), // what to send + map.subMap(), // what to receive + values + ); +} + + +void Foam::distributedTriSurfaceMesh::getVolumeType +( + const pointField& points, + List<volumeType>& volType +) const +{ + FatalErrorIn + ( + "distributedTriSurfaceMesh::getVolumeType" + "(const pointField&, List<volumeType>&) const" + ) << "Volume type not supported for distributed surfaces." + << exit(FatalError); +} + + +// Subset the part of surface that is overlapping bb. +Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface +( + const triSurface& s, + const List<treeBoundBox>& bbs, + + labelList& subPointMap, + labelList& subFaceMap +) +{ + // Determine what triangles to keep. + boolList includedFace(s.size(), false); + + forAll(s, triI) + { + const labelledTri& f = s[triI]; + const point& p0 = s.points()[f[0]]; + const point& p1 = s.points()[f[1]]; + const point& p2 = s.points()[f[2]]; + + if (overlaps(bbs, p0, p1, p2)) + { + includedFace[triI] = true; + } + } + + return subsetMesh(s, includedFace, subPointMap, subFaceMap); +} + + +void Foam::distributedTriSurfaceMesh::distribute +( + const List<treeBoundBox>& bbs, + const bool keepNonLocal, + autoPtr<mapDistribute>& faceMap, + autoPtr<mapDistribute>& pointMap +) +{ + // Get bb of all domains + { + List<List<treeBoundBox> > newProcBb(Pstream::nProcs()); + newProcBb[Pstream::myProcNo()].setSize(bbs.size()); + forAll(bbs, i) + { + newProcBb[Pstream::myProcNo()][i] = bbs[i]; + } + Pstream::gatherList(newProcBb); + Pstream::scatterList(newProcBb); + + + //if (debug) + //{ + // Info<< "old bb:" << procBb_ << endl << endl; + // Info<< "new bb:" << newProcBb << endl << endl; + // Info<< "Same:" << (newProcBb == procBb_) << endl; + //} + + if (newProcBb == procBb_) + { + return; + } + else + { + procBb_.transfer(newProcBb); + } + } + + + // Debug information + if (debug) + { + labelList nTris(Pstream::nProcs()); + nTris[Pstream::myProcNo()] = triSurface::size(); + Pstream::gatherList(nTris); + Pstream::scatterList(nTris); + + Info<< "distributedTriSurfaceMesh::distribute : before distribution:" + << endl + << "\tproc\ttris" << endl; + + forAll(nTris, procI) + { + Info<< '\t' << procI << '\t' << nTris[procI] << endl; + } + Info<< endl; + } + + + labelListList faceSendMap(Pstream::nProcs()); + labelListList pointSendMap(Pstream::nProcs()); + + forAll(procBb_, procI) + { + overlappingSurface + ( + *this, + procBb_[procI], + pointSendMap[procI], + faceSendMap[procI] + ); + + if (debug) + { + //Pout<< "Overlapping with proc " << procI + // << " faces:" << faceSendMap[procI].size() + // << " points:" << pointSendMap[procI].size() << endl << endl; + } + } + + if (keepNonLocal) + { + // Include in faceSendMap/pointSendMap the triangles that are + // not mapped to any processor so they stay local. + + const triSurface& s = static_cast<const triSurface&>(*this); + + boolList includedFace(s.size(), true); + + forAll(faceSendMap, procI) + { + if (procI != Pstream::myProcNo()) + { + forAll(faceSendMap[procI], i) + { + includedFace[faceSendMap[procI][i]] = false; + } + } + } + + // Combine includedFace (all triangles that are not on any neighbour) + // with overlap. + + forAll(faceSendMap[Pstream::myProcNo()], i) + { + includedFace[faceSendMap[Pstream::myProcNo()][i]] = true; + } + + subsetMesh + ( + s, + includedFace, + pointSendMap[Pstream::myProcNo()], + faceSendMap[Pstream::myProcNo()] + ); + } + + + // Send over how many faces/points I need to receive + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + labelListList faceSendSizes(Pstream::nProcs()); + faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs()); + forAll(faceSendMap, procI) + { + faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size(); + } + Pstream::gatherList(faceSendSizes); + Pstream::scatterList(faceSendSizes); + + + + // Exchange surfaces + // ~~~~~~~~~~~~~~~~~ + + // Storage for resulting surface + List<labelledTri> allTris; + pointField allPoints; + + labelListList faceConstructMap(Pstream::nProcs()); + labelListList pointConstructMap(Pstream::nProcs()); + + + // My own surface first + // ~~~~~~~~~~~~~~~~~~~~ + + { + labelList pointMap; + triSurface subSurface + ( + subsetMesh + ( + *this, + faceSendMap[Pstream::myProcNo()], + pointMap + ) + ); + + allTris = subSurface; + allPoints = subSurface.points(); + + faceConstructMap[Pstream::myProcNo()] = identity + ( + faceSendMap[Pstream::myProcNo()].size() + ); + pointConstructMap[Pstream::myProcNo()] = identity + ( + pointSendMap[Pstream::myProcNo()].size() + ); + } + + + + // Send all + // ~~~~~~~~ + + forAll(faceSendSizes, procI) + { + if (procI != Pstream::myProcNo()) + { + if (faceSendSizes[Pstream::myProcNo()][procI] > 0) + { + OPstream str(Pstream::blocking, procI); + + labelList pointMap; + triSurface subSurface + ( + subsetMesh + ( + *this, + faceSendMap[procI], + pointMap + ) + ); + + //if (debug) + //{ + // Pout<< "Sending to " << procI + // << " faces:" << faceSendMap[procI].size() + // << " points:" << subSurface.points().size() << endl + // << endl; + //} + + str << subSurface; + } + } + } + + + // Receive and merge all + // ~~~~~~~~~~~~~~~~~~~~~ + + forAll(faceSendSizes, procI) + { + if (procI != Pstream::myProcNo()) + { + if (faceSendSizes[procI][Pstream::myProcNo()] > 0) + { + IPstream str(Pstream::blocking, procI); + + // Receive + triSurface subSurface(str); + + //if (debug) + //{ + // Pout<< "Received from " << procI + // << " faces:" << subSurface.size() + // << " points:" << subSurface.points().size() << endl + // << endl; + //} + + // Merge into allSurf + merge + ( + mergeDist_, + subSurface, + subSurface.points(), + + allTris, + allPoints, + faceConstructMap[procI], + pointConstructMap[procI] + ); + + //if (debug) + //{ + // Pout<< "Current merged surface : faces:" << allTris.size() + // << " points:" << allPoints.size() << endl << endl; + //} + } + } + } + + + faceMap.reset + ( + new mapDistribute + ( + allTris.size(), + faceSendMap, + faceConstructMap, + true + ) + ); + pointMap.reset + ( + new mapDistribute + ( + allPoints.size(), + pointSendMap, + pointConstructMap, + true + ) + ); + + // Construct triSurface. Reuse storage. + triSurface::operator=(triSurface(allTris, patches(), allPoints, true)); + + clearOut(); + + // Regions stays same + // Volume type stays same. + + distributeFields<label>(faceMap()); + distributeFields<scalar>(faceMap()); + distributeFields<vector>(faceMap()); + distributeFields<sphericalTensor>(faceMap()); + distributeFields<symmTensor>(faceMap()); + distributeFields<tensor>(faceMap()); + + if (debug) + { + labelList nTris(Pstream::nProcs()); + nTris[Pstream::myProcNo()] = triSurface::size(); + Pstream::gatherList(nTris); + Pstream::scatterList(nTris); + + Info<< "distributedTriSurfaceMesh::distribute : after distribution:" + << endl + << "\tproc\ttris" << endl; + + forAll(nTris, procI) + { + Info<< '\t' << procI << '\t' << nTris[procI] << endl; + } + Info<< endl; + } +} + + +//- Write using given format, version and compression +bool Foam::distributedTriSurfaceMesh::writeObject +( + IOstream::streamFormat fmt, + IOstream::versionNumber ver, + IOstream::compressionType cmp +) const +{ + return + triSurfaceMesh::writeObject(fmt, ver, cmp) + && dict_.writeObject(fmt, ver, cmp); +} + + +void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const +{ + boundBox bb; + label nPoints; + calcBounds(bb, nPoints); + + os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>()) + << endl + << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl + << "Bounding Box : " << bb << endl; +} + + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H new file mode 100644 index 0000000000000000000000000000000000000000..3e7dd3b57cdb2e7fe34e56c7ad6b9eae98984b57 --- /dev/null +++ b/src/meshTools/searchableSurface/distributedTriSurfaceMesh.H @@ -0,0 +1,453 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Class + Foam::distributedTriSurfaceMesh + +Description + IOoject and searching on triSurface + +SourceFiles + distributedTriSurfaceMesh.C + +\*---------------------------------------------------------------------------*/ + +#ifndef distributedTriSurfaceMesh_H +#define distributedTriSurfaceMesh_H + +#include "triSurfaceMesh.H" +#include "IOdictionary.H" +#include "Pair.H" +#include "globalIndex.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class mapDistribute; + +/*---------------------------------------------------------------------------*\ + Class distributedTriSurfaceMesh Declaration +\*---------------------------------------------------------------------------*/ + +class distributedTriSurfaceMesh +: + public triSurfaceMesh +{ +private: + + // Static data + + //- Merging distance + static scalar mergeDist_; + + + // Private member data + + //- Bounding box settings + IOdictionary dict_; + + //- bounding boxes of all processors + List<List<treeBoundBox> > procBb_; + + //- Global triangle numbering + mutable autoPtr<globalIndex> globalTris_; + + + // Private Member Functions + + // Read + + //- Read my additional data + bool read(); + + + // Line intersection + + static bool isLocal + ( + const List<treeBoundBox>& myBbs, + const point& start, + const point& end + ); + + //- Split segment into subsegments overlapping the processor + // bounding boxes. Sort per processor. + void splitSegment + ( + const label, + const point& start, + const point& end, + + DynamicList<Pair<point> >&, + DynamicList<label>&, + List<DynamicList<label> >& + ) const; + + //- Divide edges into local and remote segments. Construct map to + // distribute and collect data. + autoPtr<mapDistribute> constructSegments + ( + const pointField& start, + const pointField& end, + + List<Pair<point> >& allSegments, + List<label>& allSegmentMap + ) const; + + //- Split edges, distribute, test and collect. + void findLine + ( + const bool nearestIntersection, + const pointField& start, + const pointField& end, + List<pointIndexHit>& info + ) const; + + + // Triangle index + + //- Obtains global indices from pointIndexHit and swaps them back + // to their original processor. Used to calculate local region + // and normal. + autoPtr<mapDistribute> calcLocalQueries + ( + const List<pointIndexHit>&, + labelList& triangleIndex + ) const; + + + // Nearest + + label calcOverlappingProcs + ( + const point& centre, + const scalar radiusSqr, + boolList& overlaps + ) const; + + autoPtr<mapDistribute> calcLocalQueries + ( + const pointField& centres, + const scalarField& radiusSqr, + + pointField& allCentres, + scalarField& allRadiusSqr, + labelList& allSegmentMap + ) const; + + + // Surface redistribution + + //- Calculate surface bounding box + void calcBounds(boundBox& bb, label& nPoints) const; + + //- Does any part of triangle overlap bb. + static bool overlaps + ( + const List<treeBoundBox>& bb, + const point& p0, + const point& p1, + const point& p2 + ); + + //- Find points used in subset + static void subsetMeshMap + ( + const triSurface& s, + const boolList& include, + const label nIncluded, + labelList& newToOldPoints, + labelList& oldToNewPoints, + labelList& newToOldFaces + ); + + //- Construct subsetted surface + static triSurface subsetMesh + ( + const triSurface& s, + const labelList& newToOldPoints, + const labelList& oldToNewPoints, + const labelList& newToOldFaces + ); + + //- Subset given marked faces + static triSurface subsetMesh + ( + const triSurface& s, + const boolList& include, + labelList& newToOldPoints, + labelList& newToOldFaces + ); + + //- Subset given marked faces + static triSurface subsetMesh + ( + const triSurface& s, + const labelList& newToOldFaces, + labelList& newToOldPoints + ); + + //- Find triangle otherF in allFaces. + static label findTriangle + ( + const List<labelledTri>& allFaces, + const labelListList& allPointFaces, + const labelledTri& otherF + ); + + //- Merge triSurface (subTris, subPoints) into allTris, allPoints. + static void merge + ( + const scalar mergeDist, + const List<labelledTri>& subTris, + const pointField& subPoints, + + List<labelledTri>& allTris, + pointField& allPoints, + + labelList& faceConstructMap, + labelList& pointConstructMap + ); + + //- Distribute stored fields + template<class Type> + void distributeFields(const mapDistribute& map); + + + //- Disallow default bitwise copy construct + distributedTriSurfaceMesh(const distributedTriSurfaceMesh&); + + //- Disallow default bitwise assignment + void operator=(const distributedTriSurfaceMesh&); + + +public: + + //- Runtime type information + TypeName("distributedTriSurfaceMesh"); + + + // Constructors + + //- Construct from triSurface + distributedTriSurfaceMesh + ( + const IOobject&, + const triSurface&, + const dictionary& dict + ); + + //- Construct read + distributedTriSurfaceMesh(const IOobject& io); + + //- Construct from dictionary (used by searchableSurface) + distributedTriSurfaceMesh + ( + const IOobject& io, + const dictionary& dict + ); + + + // Destructor + + virtual ~distributedTriSurfaceMesh(); + + //- Clear storage + void clearOut(); + + + // Member Functions + + //- Return merge distance + static scalar mergeDist() + { + return mergeDist_; + } + + //- Set the merge distance, returning the previous value + static scalar setMergeDist(const scalar t) + { + if (t < -VSMALL) + { + FatalErrorIn + ( + "scalar distributedTriSurfaceMesh::setMergeDist" + "(const scalar t)" + ) << "Negative merge distance tolerance. This is not allowed." + << abort(FatalError); + } + + scalar oldTol = mergeDist_; + mergeDist_ = t; + + return oldTol; + } + + + //- Triangle indexing (demand driven) + const globalIndex& globalTris() const; + + + // searchableSurface implementation + + //- Whether supports volume type below. I.e. whether is closed. + // Not supported. + virtual bool hasVolumeType() const + { + return false; + } + + //- Range of global indices that can be returned. + virtual label globalSize() const + { + const labelList& offsets = globalTris().offsets(); + return offsets[offsets.size()-1]; + } + + virtual void findNearest + ( + const pointField& sample, + const scalarField& nearestDistSqr, + List<pointIndexHit>& + ) const; + + virtual void findLine + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + virtual void findLineAny + ( + const pointField& start, + const pointField& end, + List<pointIndexHit>& + ) const; + + //- Get all intersections in order from start to end. + virtual void findLineAll + ( + const pointField& start, + const pointField& end, + List<List<pointIndexHit> >& + ) const; + + //- From a set of points and indices get the region + virtual void getRegion + ( + const List<pointIndexHit>&, + labelList& region + ) const; + + //- From a set of points and indices get the normal + virtual void getNormal + ( + const List<pointIndexHit>&, + vectorField& normal + ) const; + + //- Determine type (inside/outside/mixed) for point. unknown if + // cannot be determined (e.g. non-manifold surface) + virtual void getVolumeType + ( + const pointField&, + List<volumeType>& + ) const; + + //- Set bounds of surface. Bounds currently set as list of + // bounding boxes. Will do redistribution of surface to locally + // have all triangles overlapping bounds. + // Larger bounds: more triangles (memory), more fully local tests + // (quick). + // keepNonLocal = true : keep triangles that do not overlap + // any processor bounds. + // Should really be split into a routine to determine decomposition + // and one that does actual distribution but determining + // decomposition with duplicate triangle merging requires + // same amoun as work as actual distribution. + virtual void distribute + ( + const List<treeBoundBox>&, + const bool keepNonLocal, + autoPtr<mapDistribute>& faceMap, + autoPtr<mapDistribute>& pointMap + ); + + + // Other + + //- Specific to triSurfaceMesh: from a set of hits (points and + // indices) get the specified field. Misses do not get set. + virtual void getField + ( + const word& fieldName, + const List<pointIndexHit>&, + labelList& values + ) const; + + //- Subset the part of surface that is overlapping bounds. + static triSurface overlappingSurface + ( + const triSurface&, + const List<treeBoundBox>&, + labelList& subPointMap, + labelList& subFaceMap + ); + + //- Print some stats. Parallel aware version of + // triSurface::writeStats. + void writeStats(Ostream& os) const; + + + // regIOobject implementation + + //- Write using given format, version and compression + virtual bool writeObject + ( + IOstream::streamFormat fmt, + IOstream::versionNumber ver, + IOstream::compressionType cmp + ) const; + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository +# include "distributedTriSurfaceMeshTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/searchableSurface/distributedTriSurfaceMeshTemplates.C b/src/meshTools/searchableSurface/distributedTriSurfaceMeshTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..689e1a3f22fd66e6abe37206b6f07f69f7644fd1 --- /dev/null +++ b/src/meshTools/searchableSurface/distributedTriSurfaceMeshTemplates.C @@ -0,0 +1,139 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM; if not, write to the Free Software Foundation, + Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +\*---------------------------------------------------------------------------*/ + +#include "distributedTriSurfaceMesh.H" +#include "triSurfaceFields.H" +#include "mapDistribute.H" + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +//template<class Type> +//void Foam::distributedTriSurfaceMesh::getField +//( +// const word& fieldName, +// const List<pointIndexHit>& info, +// List<Type>& values +//) const +//{ +// typedef DimensionedField<Type, triSurfaceGeoMesh> DimensionedSurfField; +// +// +// // Get query data (= local index of triangle) +// // ~~~~~~~~~~~~~~ +// +// labelList triangleIndex(info.size()); +// autoPtr<mapDistribute> mapPtr +// ( +// calcLocalQueries +// ( +// info, +// triangleIndex +// ) +// ); +// const mapDistribute& map = mapPtr(); +// +// +// // Do my tests +// // ~~~~~~~~~~~ +// +// const DimensionedSurfField& fld = lookupObject<DimensionedSurfField> +// ( +// fieldName +// ); +// const triSurface& s = static_cast<const triSurface&>(*this); +// +// values.setSize(triangleIndex.size()); +// +// forAll(triangleIndex, i) +// { +// label triI = triangleIndex[i]; +// values[i] = fld[triI]; +// } +// +// +// // Send back results +// // ~~~~~~~~~~~~~~~~~ +// +// map.distribute +// ( +// Pstream::nonBlocking, +// List<labelPair>(0), +// info.size(), +// map.constructMap(), // what to send +// map.subMap(), // what to receive +// values +// ); +//} + + +template<class Type> +void Foam::distributedTriSurfaceMesh::distributeFields +( + const mapDistribute& map +) +{ + typedef DimensionedField<Type, triSurfaceGeoMesh> DimensionedSurfField; + + HashTable<const DimensionedSurfField*> fields + ( + objectRegistry::lookupClass + <DimensionedSurfField >() + ); + + for + ( + typename HashTable<const DimensionedSurfField*>::iterator fieldIter = + fields.begin(); + fieldIter != fields.end(); + ++fieldIter + ) + { + DimensionedSurfField& field = + const_cast<DimensionedSurfField&>(*fieldIter()); + + label oldSize = field.size(); + + map.distribute + ( + Pstream::nonBlocking, + List<labelPair>(0), + map.constructSize(), + map.subMap(), + map.constructMap(), + field + ); + + if (debug) + { + Info<< "Mapped " << field.typeName << ' ' << field.name() + << " from size " << oldSize << " to size " << field.size() + << endl; + } + } +} + + +// ************************************************************************* //