1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "distributedTriSurfaceMesh.H"
28 #include "mapDistribute.H"
30 #include "addToRunTimeSelectionTable.H"
31 #include "triangleFuncs.H"
32 #include "matchPoints.H"
33 #include "globalIndex.H"
37 #include "decompositionMethod.H"
38 #include "vectorList.H"
39 #include "PackedBoolList.H"
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
46 addToRunTimeSelectionTable
49 distributedTriSurfaceMesh,
57 Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>::names[] =
64 const Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>
65 Foam::distributedTriSurfaceMesh::distributionTypeNames_;
68 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
70 // Read my additional data from the dictionary
71 bool Foam::distributedTriSurfaceMesh::read()
73 // Get bb of all domains.
74 procBb_.setSize(Pstream::nProcs());
76 procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
77 Pstream::gatherList(procBb_);
78 Pstream::scatterList(procBb_);
81 distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
84 mergeDist_ = readScalar(dict_.lookup("mergeDistance"));
90 // Is segment fully local?
91 bool Foam::distributedTriSurfaceMesh::isLocal
93 const List<treeBoundBox>& myBbs,
100 if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
109 //void Foam::distributedTriSurfaceMesh::splitSegment
111 // const label segmentI,
112 // const point& start,
114 // const treeBoundBox& bb,
116 // DynamicList<segment>& allSegments,
117 // DynamicList<label>& allSegmentMap,
118 // DynamicList<label> sendMap
122 // point clipPt0, clipPt1;
124 // if (bb.contains(start))
126 // // start within, trim end to bb
127 // bool clipped = bb.intersects(end, start, clipPt0);
131 // // segment from start to clippedStart passes
133 // sendMap[procI].append(allSegments.size());
134 // allSegmentMap.append(segmentI);
135 // allSegments.append(segment(start, clipPt0));
138 // else if (bb.contains(end))
140 // // end within, trim start to bb
141 // bool clipped = bb.intersects(start, end, clipPt0);
145 // sendMap[procI].append(allSegments.size());
146 // allSegmentMap.append(segmentI);
147 // allSegments.append(segment(clipPt0, end));
153 // bool clippedStart = bb.intersects(start, end, clipPt0);
157 // bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
161 // // middle part of segment passes through proc.
162 // sendMap[procI].append(allSegments.size());
163 // allSegmentMap.append(segmentI);
164 // allSegments.append(segment(clipPt0, clipPt1));
171 void Foam::distributedTriSurfaceMesh::distributeSegment
173 const label segmentI,
177 DynamicList<segment>& allSegments,
178 DynamicList<label>& allSegmentMap,
179 List<DynamicList<label> >& sendMap
186 // 1. Fully local already handled outside. Note: retest is cheap.
187 if (isLocal(procBb_[Pstream::myProcNo()], start, end))
193 // 2. If fully inside one other processor, then only need to send
194 // to that one processor even if it intersects another. Rare occurrence
195 // but cheap to test.
196 forAll(procBb_, procI)
198 if (procI != Pstream::myProcNo())
200 const List<treeBoundBox>& bbs = procBb_[procI];
202 if (isLocal(bbs, start, end))
204 sendMap[procI].append(allSegments.size());
205 allSegmentMap.append(segmentI);
206 allSegments.append(segment(start, end));
213 // 3. If not contained in single processor send to all intersecting
215 forAll(procBb_, procI)
217 const List<treeBoundBox>& bbs = procBb_[procI];
221 const treeBoundBox& bb = bbs[bbI];
223 // Scheme a: any processor that intersects the segment gets
226 if (bb.intersects(start, end, clipPt))
228 sendMap[procI].append(allSegments.size());
229 allSegmentMap.append(segmentI);
230 allSegments.append(segment(start, end));
233 // Alternative: any processor only gets clipped bit of
234 // segment. This gives small problems with additional
235 // truncation errors.
252 Foam::autoPtr<Foam::mapDistribute>
253 Foam::distributedTriSurfaceMesh::distributeSegments
255 const pointField& start,
256 const pointField& end,
258 List<segment>& allSegments,
259 labelList& allSegmentMap
262 // Determine send map
263 // ~~~~~~~~~~~~~~~~~~
265 labelListList sendMap(Pstream::nProcs());
268 // Since intersection test is quite expensive compared to memory
269 // allocation we use DynamicList to immediately store the segment
270 // in the correct bin.
273 DynamicList<segment> dynAllSegments(start.size());
274 // Original index of segment
275 DynamicList<label> dynAllSegmentMap(start.size());
276 // Per processor indices into allSegments to send
277 List<DynamicList<label> > dynSendMap(Pstream::nProcs());
279 forAll(start, segmentI)
293 // Convert dynamicList to labelList
294 sendMap.setSize(Pstream::nProcs());
295 forAll(sendMap, procI)
297 dynSendMap[procI].shrink();
298 sendMap[procI].transfer(dynSendMap[procI]);
301 allSegments.transfer(dynAllSegments.shrink());
302 allSegmentMap.transfer(dynAllSegmentMap.shrink());
306 // Send over how many I need to receive.
307 labelListList sendSizes(Pstream::nProcs());
308 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
309 forAll(sendMap, procI)
311 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
313 Pstream::gatherList(sendSizes);
314 Pstream::scatterList(sendSizes);
317 // Determine order of receiving
318 labelListList constructMap(Pstream::nProcs());
320 // My local segments first
321 constructMap[Pstream::myProcNo()] = identity
323 sendMap[Pstream::myProcNo()].size()
326 label segmentI = constructMap[Pstream::myProcNo()].size();
327 forAll(constructMap, procI)
329 if (procI != Pstream::myProcNo())
331 // What I need to receive is what other processor is sending to me.
332 label nRecv = sendSizes[procI][Pstream::myProcNo()];
333 constructMap[procI].setSize(nRecv);
335 for (label i = 0; i < nRecv; i++)
337 constructMap[procI][i] = segmentI++;
342 return autoPtr<mapDistribute>
346 segmentI, // size after construction
349 true // reuse storage
355 void Foam::distributedTriSurfaceMesh::findLine
357 const bool nearestIntersection,
358 const pointField& start,
359 const pointField& end,
360 List<pointIndexHit>& info
363 const indexedOctree<treeDataTriSurface>& octree = tree();
365 // Important:force synchronised construction of indexing
366 const globalIndex& triIndexer = globalTris();
369 info.setSize(start.size());
376 // Do any local queries
377 // ~~~~~~~~~~~~~~~~~~~~
383 if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
385 if (nearestIntersection)
387 info[i] = octree.findLine(start[i], end[i]);
391 info[i] = octree.findLineAny(start[i], end[i]);
396 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
407 returnReduce(nLocal, sumOp<label>())
408 < returnReduce(start.size(), sumOp<label>())
412 // Not all can be resolved locally. Build segments and map, send over
413 // segments, do intersections, send back and merge.
416 // Construct queries (segments)
417 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
420 List<segment> allSegments(start.size());
421 // Original index of segment
422 labelList allSegmentMap(start.size());
424 const autoPtr<mapDistribute> mapPtr
434 const mapDistribute& map = mapPtr();
436 label nOldAllSegments = allSegments.size();
439 // Exchange the segments
440 // ~~~~~~~~~~~~~~~~~~~~~
444 Pstream::nonBlocking, //Pstream::scheduled,
445 List<labelPair>(0), //map.schedule(),
447 map.subMap(), // what to send
448 map.constructMap(), // what to receive
453 // Do tests I need to do
454 // ~~~~~~~~~~~~~~~~~~~~~
457 List<pointIndexHit> intersections(allSegments.size());
459 forAll(allSegments, i)
461 if (nearestIntersection)
463 intersections[i] = octree.findLine
465 allSegments[i].first(),
466 allSegments[i].second()
471 intersections[i] = octree.findLineAny
473 allSegments[i].first(),
474 allSegments[i].second()
478 // Convert triangle index to global numbering
479 if (intersections[i].hit())
481 intersections[i].setIndex
483 triIndexer.toGlobal(intersections[i].index())
489 // Exchange the intersections (opposite to segments)
490 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
494 //Pstream::scheduled,
495 //map.schedule // Note reverse schedule
497 // map.constructMap(),
500 Pstream::nonBlocking,
503 map.constructMap(), // what to send
504 map.subMap(), // what to receive
512 forAll(intersections, i)
514 const pointIndexHit& allInfo = intersections[i];
515 label segmentI = allSegmentMap[i];
516 pointIndexHit& hitInfo = info[segmentI];
522 // No intersection yet so take this one
525 else if (nearestIntersection)
527 // Nearest intersection
530 magSqr(allInfo.hitPoint()-start[segmentI])
531 < magSqr(hitInfo.hitPoint()-start[segmentI])
543 // Exchanges indices to the processor they come from.
544 // - calculates exchange map
545 // - uses map to calculate local triangle index
546 Foam::autoPtr<Foam::mapDistribute>
547 Foam::distributedTriSurfaceMesh::calcLocalQueries
549 const List<pointIndexHit>& info,
550 labelList& triangleIndex
553 triangleIndex.setSize(info.size());
555 const globalIndex& triIndexer = globalTris();
558 // Determine send map
559 // ~~~~~~~~~~~~~~~~~~
561 // Since determining which processor the query should go to is
562 // cheap we do a multi-pass algorithm to save some memory temporarily.
565 labelList nSend(Pstream::nProcs(), 0);
571 label procI = triIndexer.whichProcID(info[i].index());
577 labelListList sendMap(Pstream::nProcs());
580 sendMap[procI].setSize(nSend[procI]);
589 label procI = triIndexer.whichProcID(info[i].index());
590 triangleIndex[i] = triIndexer.toLocal(procI, info[i].index());
591 sendMap[procI][nSend[procI]++] = i;
595 triangleIndex[i] = -1;
600 // Send over how many I need to receive
601 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
603 labelListList sendSizes(Pstream::nProcs());
604 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
605 forAll(sendMap, procI)
607 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
609 Pstream::gatherList(sendSizes);
610 Pstream::scatterList(sendSizes);
613 // Determine receive map
614 // ~~~~~~~~~~~~~~~~~~~~~
616 labelListList constructMap(Pstream::nProcs());
618 // My local segments first
619 constructMap[Pstream::myProcNo()] = identity
621 sendMap[Pstream::myProcNo()].size()
624 label segmentI = constructMap[Pstream::myProcNo()].size();
625 forAll(constructMap, procI)
627 if (procI != Pstream::myProcNo())
629 // What I need to receive is what other processor is sending to me.
630 label nRecv = sendSizes[procI][Pstream::myProcNo()];
631 constructMap[procI].setSize(nRecv);
633 for (label i = 0; i < nRecv; i++)
635 constructMap[procI][i] = segmentI++;
641 // Pack into distribution map
642 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
644 autoPtr<mapDistribute> mapPtr
648 segmentI, // size after construction
651 true // reuse storage
654 const mapDistribute& map = mapPtr();
662 //Pstream::scheduled,
664 Pstream::nonBlocking,
667 map.subMap(), // what to send
668 map.constructMap(), // what to receive
677 Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs
680 const scalar radiusSqr,
687 forAll(procBb_, procI)
689 const List<treeBoundBox>& bbs = procBb_[procI];
693 if (bbs[bbI].overlaps(centre, radiusSqr))
695 overlaps[procI] = true;
705 // Generate queries for parallel distance calculation
706 // - calculates exchange map
707 // - uses map to exchange points and radius
708 Foam::autoPtr<Foam::mapDistribute>
709 Foam::distributedTriSurfaceMesh::calcLocalQueries
711 const pointField& centres,
712 const scalarField& radiusSqr,
714 pointField& allCentres,
715 scalarField& allRadiusSqr,
716 labelList& allSegmentMap
722 labelListList sendMap(Pstream::nProcs());
726 DynamicList<point> dynAllCentres(centres.size());
727 DynamicList<scalar> dynAllRadiusSqr(centres.size());
728 // Original index of segment
729 DynamicList<label> dynAllSegmentMap(centres.size());
730 // Per processor indices into allSegments to send
731 List<DynamicList<label> > dynSendMap(Pstream::nProcs());
733 // Work array - whether processor bb overlaps the bounding sphere.
734 boolList procBbOverlaps(Pstream::nProcs());
736 forAll(centres, centreI)
738 // Find the processor this sample+radius overlaps.
746 forAll(procBbOverlaps, procI)
748 if (procI != Pstream::myProcNo() && procBbOverlaps[procI])
750 dynSendMap[procI].append(dynAllCentres.size());
751 dynAllSegmentMap.append(centreI);
752 dynAllCentres.append(centres[centreI]);
753 dynAllRadiusSqr.append(radiusSqr[centreI]);
758 // Convert dynamicList to labelList
759 sendMap.setSize(Pstream::nProcs());
760 forAll(sendMap, procI)
762 dynSendMap[procI].shrink();
763 sendMap[procI].transfer(dynSendMap[procI]);
766 allCentres.transfer(dynAllCentres.shrink());
767 allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
768 allSegmentMap.transfer(dynAllSegmentMap.shrink());
772 // Send over how many I need to receive.
773 labelListList sendSizes(Pstream::nProcs());
774 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
775 forAll(sendMap, procI)
777 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
779 Pstream::gatherList(sendSizes);
780 Pstream::scatterList(sendSizes);
783 // Determine order of receiving
784 labelListList constructMap(Pstream::nProcs());
786 // My local segments first
787 constructMap[Pstream::myProcNo()] = identity
789 sendMap[Pstream::myProcNo()].size()
792 label segmentI = constructMap[Pstream::myProcNo()].size();
793 forAll(constructMap, procI)
795 if (procI != Pstream::myProcNo())
797 // What I need to receive is what other processor is sending to me.
798 label nRecv = sendSizes[procI][Pstream::myProcNo()];
799 constructMap[procI].setSize(nRecv);
801 for (label i = 0; i < nRecv; i++)
803 constructMap[procI][i] = segmentI++;
808 autoPtr<mapDistribute> mapPtr
812 segmentI, // size after construction
815 true // reuse storage
822 // Find bounding boxes that guarantee a more or less uniform distribution
823 // of triangles. Decomposition in here is only used to get the bounding
824 // boxes, actual decomposition is done later on.
825 // Returns a per processor a list of bounding boxes that most accurately
826 // describe the shape. For now just a single bounding box per processor but
827 // optimisation might be to determine a better fitting shape.
828 Foam::List<Foam::List<Foam::treeBoundBox> >
829 Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
834 if (!decomposer_.valid())
836 // Use current decomposer.
837 // Note: or always use hierarchical?
838 IOdictionary decomposeDict
843 searchableSurface::time().system(),
844 searchableSurface::time(),
850 decomposer_ = decompositionMethod::New(decomposeDict);
852 if (!decomposer_().parallelAware())
856 "distributedTriSurfaceMesh::independentlyDistributedBbs"
857 "(const triSurface&)"
858 ) << "The decomposition method " << decomposer_().typeName
859 << " does not decompose in parallel."
860 << " Please choose one that does." << exit(FatalError);
864 // Do decomposition according to triangle centre
865 pointField triCentres(s.size());
868 triCentres[triI] = s[triI].centre(s.points());
871 // Do the actual decomposition
872 labelList distribution(decomposer_->decompose(triCentres));
874 // Find bounding box for all triangles on new distribution.
876 // Initialise to inverted box (VGREAT, -VGREAT)
877 List<List<treeBoundBox> > bbs(Pstream::nProcs());
880 bbs[procI].setSize(1);
881 //bbs[procI][0] = boundBox::invertedBox;
882 bbs[procI][0].min() = point( VGREAT, VGREAT, VGREAT);
883 bbs[procI][0].max() = point(-VGREAT, -VGREAT, -VGREAT);
888 point& bbMin = bbs[distribution[triI]][0].min();
889 point& bbMax = bbs[distribution[triI]][0].max();
891 const labelledTri& f = s[triI];
892 const point& p0 = s.points()[f[0]];
893 const point& p1 = s.points()[f[1]];
894 const point& p2 = s.points()[f[2]];
896 bbMin = min(bbMin, p0);
897 bbMin = min(bbMin, p1);
898 bbMin = min(bbMin, p2);
900 bbMax = max(bbMax, p0);
901 bbMax = max(bbMax, p1);
902 bbMax = max(bbMax, p2);
905 // Now combine for all processors and convert to correct format.
908 forAll(bbs[procI], i)
910 reduce(bbs[procI][i].min(), minOp<point>());
911 reduce(bbs[procI][i].max(), maxOp<point>());
918 // Does any part of triangle overlap bb.
919 bool Foam::distributedTriSurfaceMesh::overlaps
921 const List<treeBoundBox>& bbs,
929 const treeBoundBox& bb = bbs[bbI];
931 treeBoundBox triBb(p0, p0);
932 triBb.min() = min(triBb.min(), p1);
933 triBb.min() = min(triBb.min(), p2);
935 triBb.max() = max(triBb.max(), p1);
936 triBb.max() = max(triBb.max(), p2);
938 //- Exact test of triangle intersecting bb
940 // Quick rejection. If whole bounding box of tri is outside cubeBb then
941 // there will be no intersection.
942 if (bb.overlaps(triBb))
944 // Check if one or more triangle point inside
945 if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
947 // One or more points inside
951 // Now we have the difficult case: all points are outside but
952 // connecting edges might go through cube. Use fast intersection
954 bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
966 void Foam::distributedTriSurfaceMesh::subsetMeshMap
969 const boolList& include,
970 const label nIncluded,
971 labelList& newToOldPoints,
972 labelList& oldToNewPoints,
973 labelList& newToOldFaces
976 newToOldFaces.setSize(nIncluded);
977 newToOldPoints.setSize(s.points().size());
978 oldToNewPoints.setSize(s.points().size());
984 forAll(include, oldFacei)
986 if (include[oldFacei])
988 // Store new faces compact
989 newToOldFaces[faceI++] = oldFacei;
991 // Renumber labels for triangle
992 const labelledTri& tri = s[oldFacei];
996 label oldPointI = tri[fp];
998 if (oldToNewPoints[oldPointI] == -1)
1000 oldToNewPoints[oldPointI] = pointI;
1001 newToOldPoints[pointI++] = oldPointI;
1006 newToOldPoints.setSize(pointI);
1011 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1013 const triSurface& s,
1014 const labelList& newToOldPoints,
1015 const labelList& oldToNewPoints,
1016 const labelList& newToOldFaces
1020 pointField newPoints(newToOldPoints.size());
1021 forAll(newToOldPoints, i)
1023 newPoints[i] = s.points()[newToOldPoints[i]];
1026 List<labelledTri> newTriangles(newToOldFaces.size());
1028 forAll(newToOldFaces, i)
1030 // Get old vertex labels
1031 const labelledTri& tri = s[newToOldFaces[i]];
1033 newTriangles[i][0] = oldToNewPoints[tri[0]];
1034 newTriangles[i][1] = oldToNewPoints[tri[1]];
1035 newTriangles[i][2] = oldToNewPoints[tri[2]];
1036 newTriangles[i].region() = tri.region();
1040 return triSurface(newTriangles, s.patches(), newPoints, true);
1044 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1046 const triSurface& s,
1047 const boolList& include,
1048 labelList& newToOldPoints,
1049 labelList& newToOldFaces
1062 labelList oldToNewPoints;
1083 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1085 const triSurface& s,
1086 const labelList& newToOldFaces,
1087 labelList& newToOldPoints
1090 const boolList include
1092 createWithValues<boolList>
1101 newToOldPoints.setSize(s.points().size());
1102 labelList oldToNewPoints(s.points().size(), -1);
1106 forAll(include, oldFacei)
1108 if (include[oldFacei])
1110 // Renumber labels for triangle
1111 const labelledTri& tri = s[oldFacei];
1115 label oldPointI = tri[fp];
1117 if (oldToNewPoints[oldPointI] == -1)
1119 oldToNewPoints[oldPointI] = pointI;
1120 newToOldPoints[pointI++] = oldPointI;
1125 newToOldPoints.setSize(pointI);
1138 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
1140 const List<labelledTri>& allFaces,
1141 const labelListList& allPointFaces,
1142 const labelledTri& otherF
1145 // allFaces connected to otherF[0]
1146 const labelList& pFaces = allPointFaces[otherF[0]];
1150 const labelledTri& f = allFaces[pFaces[i]];
1152 if (f.region() == otherF.region())
1154 // Find index of otherF[0]
1155 label fp0 = findIndex(f, otherF[0]);
1156 // Check rest of triangle in same order
1157 label fp1 = f.fcIndex(fp0);
1158 label fp2 = f.fcIndex(fp1);
1160 if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1170 // Merge into allSurf.
1171 void Foam::distributedTriSurfaceMesh::merge
1173 const scalar mergeDist,
1174 const List<labelledTri>& subTris,
1175 const pointField& subPoints,
1177 List<labelledTri>& allTris,
1178 pointField& allPoints,
1180 labelList& faceConstructMap,
1181 labelList& pointConstructMap
1189 scalarField(subPoints.size(), mergeDist), // match distance
1194 label nOldAllPoints = allPoints.size();
1197 // Add all unmatched points
1198 // ~~~~~~~~~~~~~~~~~~~~~~~~
1200 label allPointI = nOldAllPoints;
1201 forAll(pointConstructMap, pointI)
1203 if (pointConstructMap[pointI] == -1)
1205 pointConstructMap[pointI] = allPointI++;
1209 if (allPointI > nOldAllPoints)
1211 allPoints.setSize(allPointI);
1213 forAll(pointConstructMap, pointI)
1215 if (pointConstructMap[pointI] >= nOldAllPoints)
1217 allPoints[pointConstructMap[pointI]] = subPoints[pointI];
1223 // To check whether triangles are same we use pointFaces.
1224 labelListList allPointFaces;
1225 invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1228 // Add all unmatched triangles
1229 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1231 label allTriI = allTris.size();
1232 allTris.setSize(allTriI + subTris.size());
1234 faceConstructMap.setSize(subTris.size());
1236 forAll(subTris, triI)
1238 const labelledTri& subTri = subTris[triI];
1240 // Get triangle in new numbering
1241 labelledTri mappedTri
1243 pointConstructMap[subTri[0]],
1244 pointConstructMap[subTri[1]],
1245 pointConstructMap[subTri[2]],
1250 // Check if all points were already in surface
1251 bool fullMatch = true;
1253 forAll(mappedTri, fp)
1255 if (mappedTri[fp] >= nOldAllPoints)
1264 // All three points are mapped to old points. See if same
1266 label i = findTriangle
1276 faceConstructMap[triI] = allTriI;
1277 allTris[allTriI] = mappedTri;
1282 faceConstructMap[triI] = i;
1288 faceConstructMap[triI] = allTriI;
1289 allTris[allTriI] = mappedTri;
1293 allTris.setSize(allTriI);
1297 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1299 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1302 const triSurface& s,
1303 const dictionary& dict
1306 triSurfaceMesh(io, s),
1311 searchableSurface::name() + "Dict",
1312 searchableSurface::instance(),
1313 searchableSurface::local(),
1314 searchableSurface::db(),
1315 searchableSurface::NO_READ,
1316 searchableSurface::writeOpt(),
1317 searchableSurface::registerObject()
1326 Info<< "Constructed from triSurface:" << endl;
1329 labelList nTris(Pstream::nProcs());
1330 nTris[Pstream::myProcNo()] = triSurface::size();
1331 Pstream::gatherList(nTris);
1332 Pstream::scatterList(nTris);
1334 Info<< endl<< "\tproc\ttris\tbb" << endl;
1335 forAll(nTris, procI)
1337 Info<< '\t' << procI << '\t' << nTris[procI]
1338 << '\t' << procBb_[procI] << endl;
1345 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
1347 //triSurfaceMesh(io),
1353 io.time().findInstance(io.local(), word::null),
1365 searchableSurface::name() + "Dict",
1366 searchableSurface::instance(),
1367 searchableSurface::local(),
1368 searchableSurface::db(),
1369 searchableSurface::readOpt(),
1370 searchableSurface::writeOpt(),
1371 searchableSurface::registerObject()
1379 Info<< "Read distributedTriSurface from " << io.objectPath()
1383 labelList nTris(Pstream::nProcs());
1384 nTris[Pstream::myProcNo()] = triSurface::size();
1385 Pstream::gatherList(nTris);
1386 Pstream::scatterList(nTris);
1388 Info<< endl<< "\tproc\ttris\tbb" << endl;
1389 forAll(nTris, procI)
1391 Info<< '\t' << procI << '\t' << nTris[procI]
1392 << '\t' << procBb_[procI] << endl;
1399 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1402 const dictionary& dict
1405 //triSurfaceMesh(io, dict),
1411 io.time().findInstance(io.local(), word::null),
1424 searchableSurface::name() + "Dict",
1425 searchableSurface::instance(),
1426 searchableSurface::local(),
1427 searchableSurface::db(),
1428 searchableSurface::readOpt(),
1429 searchableSurface::writeOpt(),
1430 searchableSurface::registerObject()
1438 Info<< "Read distributedTriSurface from " << io.objectPath()
1439 << " and dictionary:" << endl;
1442 labelList nTris(Pstream::nProcs());
1443 nTris[Pstream::myProcNo()] = triSurface::size();
1444 Pstream::gatherList(nTris);
1445 Pstream::scatterList(nTris);
1447 Info<< endl<< "\tproc\ttris\tbb" << endl;
1448 forAll(nTris, procI)
1450 Info<< '\t' << procI << '\t' << nTris[procI]
1451 << '\t' << procBb_[procI] << endl;
1458 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1460 Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh()
1466 void Foam::distributedTriSurfaceMesh::clearOut()
1468 globalTris_.clear();
1469 triSurfaceMesh::clearOut();
1473 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1475 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
1477 if (!globalTris_.valid())
1479 globalTris_.reset(new globalIndex(triSurface::size()));
1485 void Foam::distributedTriSurfaceMesh::findNearest
1487 const pointField& samples,
1488 const scalarField& nearestDistSqr,
1489 List<pointIndexHit>& info
1492 const indexedOctree<treeDataTriSurface>& octree = tree();
1494 // Important:force synchronised construction of indexing
1495 const globalIndex& triIndexer = globalTris();
1501 info.setSize(samples.size());
1509 // Do any local queries
1510 // ~~~~~~~~~~~~~~~~~~~~
1515 // Work array - whether processor bb overlaps the bounding sphere.
1516 boolList procBbOverlaps(Pstream::nProcs());
1520 // Find the processor this sample+radius overlaps.
1521 label nProcs = calcOverlappingProcs
1528 // Overlaps local processor?
1529 if (procBbOverlaps[Pstream::myProcNo()])
1531 info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1534 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1550 returnReduce(nLocal, sumOp<label>())
1551 < returnReduce(samples.size(), sumOp<label>())
1555 // Not all can be resolved locally. Build queries and map, send over
1556 // queries, do intersections, send back and merge.
1558 // Calculate queries and exchange map
1559 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1561 pointField allCentres;
1562 scalarField allRadiusSqr;
1563 labelList allSegmentMap;
1564 autoPtr<mapDistribute> mapPtr
1576 const mapDistribute& map = mapPtr();
1579 // swap samples to local processor
1580 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1584 //Pstream::scheduled,
1586 Pstream::nonBlocking,
1588 map.constructSize(),
1589 map.subMap(), // what to send
1590 map.constructMap(), // what to receive
1595 //Pstream::scheduled,
1597 Pstream::nonBlocking,
1599 map.constructSize(),
1600 map.subMap(), // what to send
1601 map.constructMap(), // what to receive
1609 List<pointIndexHit> allInfo(allCentres.size());
1612 allInfo[i] = octree.findNearest
1617 if (allInfo[i].hit())
1619 allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1624 // Send back results
1625 // ~~~~~~~~~~~~~~~~~
1629 //Pstream::scheduled,
1630 //map.schedule // note reverse schedule
1632 // map.constructMap(),
1635 Pstream::nonBlocking,
1637 allSegmentMap.size(),
1638 map.constructMap(), // what to send
1639 map.subMap(), // what to receive
1644 // Extract information
1645 // ~~~~~~~~~~~~~~~~~~~
1649 if (allInfo[i].hit())
1651 label pointI = allSegmentMap[i];
1653 if (!info[pointI].hit())
1655 // No intersection yet so take this one
1656 info[pointI] = allInfo[i];
1660 // Nearest intersection
1663 magSqr(allInfo[i].hitPoint()-samples[pointI])
1664 < magSqr(info[pointI].hitPoint()-samples[pointI])
1667 info[pointI] = allInfo[i];
1676 void Foam::distributedTriSurfaceMesh::findLine
1678 const pointField& start,
1679 const pointField& end,
1680 List<pointIndexHit>& info
1685 true, // nearestIntersection
1693 void Foam::distributedTriSurfaceMesh::findLineAny
1695 const pointField& start,
1696 const pointField& end,
1697 List<pointIndexHit>& info
1702 true, // nearestIntersection
1710 void Foam::distributedTriSurfaceMesh::findLineAll
1712 const pointField& start,
1713 const pointField& end,
1714 List<List<pointIndexHit> >& info
1717 // Reuse fineLine. We could modify all of findLine to do multiple
1718 // intersections but this would mean a lot of data transferred so
1719 // for now we just find nearest intersection and retest from that
1720 // intersection onwards.
1723 List<pointIndexHit> hitInfo(start.size());
1727 true, // nearestIntersection
1734 // To find all intersections we add a small vector to the last intersection
1735 // This is chosen such that
1736 // - it is significant (SMALL is smallest representative relative tolerance;
1737 // we need something bigger since we're doing calculations)
1738 // - if the start-end vector is zero we still progress
1739 const vectorField dirVec(end-start);
1740 const scalarField magSqrDirVec(magSqr(dirVec));
1741 const vectorField smallVec
1743 Foam::sqrt(SMALL)*dirVec
1744 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
1747 // Copy to input and compact any hits
1748 labelList pointMap(start.size());
1749 pointField e0(start.size());
1750 pointField e1(start.size());
1753 info.setSize(hitInfo.size());
1754 forAll(hitInfo, pointI)
1756 if (hitInfo[pointI].hit())
1758 info[pointI].setSize(1);
1759 info[pointI][0] = hitInfo[pointI];
1761 point pt = hitInfo[pointI].hitPoint() + smallVec[pointI];
1763 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1766 e1[compactI] = end[pointI];
1767 pointMap[compactI] = pointI;
1773 info[pointI].clear();
1777 e0.setSize(compactI);
1778 e1.setSize(compactI);
1779 pointMap.setSize(compactI);
1781 while (returnReduce(e0.size(), sumOp<label>()) > 0)
1785 true, // nearestIntersection
1796 if (hitInfo[i].hit())
1798 label pointI = pointMap[i];
1800 label sz = info[pointI].size();
1801 info[pointI].setSize(sz+1);
1802 info[pointI][sz] = hitInfo[i];
1804 point pt = hitInfo[i].hitPoint() + smallVec[pointI];
1806 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1809 e1[compactI] = end[pointI];
1810 pointMap[compactI] = pointI;
1817 e0.setSize(compactI);
1818 e1.setSize(compactI);
1819 pointMap.setSize(compactI);
1824 void Foam::distributedTriSurfaceMesh::getRegion
1826 const List<pointIndexHit>& info,
1830 if (!Pstream::parRun())
1832 region.setSize(info.size());
1837 region[i] = triSurface::operator[](info[i].index()).region();
1848 // Get query data (= local index of triangle)
1851 labelList triangleIndex(info.size());
1852 autoPtr<mapDistribute> mapPtr
1860 const mapDistribute& map = mapPtr();
1866 const triSurface& s = static_cast<const triSurface&>(*this);
1868 region.setSize(triangleIndex.size());
1870 forAll(triangleIndex, i)
1872 label triI = triangleIndex[i];
1873 region[i] = s[triI].region();
1877 // Send back results
1878 // ~~~~~~~~~~~~~~~~~
1882 //Pstream::scheduled,
1883 //map.schedule // note reverse schedule
1885 // map.constructMap(),
1888 Pstream::nonBlocking,
1891 map.constructMap(), // what to send
1892 map.subMap(), // what to receive
1898 void Foam::distributedTriSurfaceMesh::getNormal
1900 const List<pointIndexHit>& info,
1904 if (!Pstream::parRun())
1906 triSurfaceMesh::getNormal(info, normal);
1911 // Get query data (= local index of triangle)
1914 labelList triangleIndex(info.size());
1915 autoPtr<mapDistribute> mapPtr
1923 const mapDistribute& map = mapPtr();
1929 const triSurface& s = static_cast<const triSurface&>(*this);
1931 normal.setSize(triangleIndex.size());
1933 forAll(triangleIndex, i)
1935 label triI = triangleIndex[i];
1936 normal[i] = s[triI].normal(s.points());
1937 normal[i] /= mag(normal[i]) + VSMALL;
1941 // Send back results
1942 // ~~~~~~~~~~~~~~~~~
1946 //Pstream::scheduled,
1947 //map.schedule // note reverse schedule
1949 // map.constructMap(),
1952 Pstream::nonBlocking,
1955 map.constructMap(), // what to send
1956 map.subMap(), // what to receive
1962 void Foam::distributedTriSurfaceMesh::getField
1964 const List<pointIndexHit>& info,
1968 if (!Pstream::parRun())
1970 triSurfaceMesh::getField(info, values);
1974 if (foundObject<triSurfaceLabelField>("values"))
1976 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
1982 // Get query data (= local index of triangle)
1985 labelList triangleIndex(info.size());
1986 autoPtr<mapDistribute> mapPtr
1994 const mapDistribute& map = mapPtr();
2000 values.setSize(triangleIndex.size());
2002 forAll(triangleIndex, i)
2004 label triI = triangleIndex[i];
2005 values[i] = fld[triI];
2009 // Send back results
2010 // ~~~~~~~~~~~~~~~~~
2014 Pstream::nonBlocking,
2017 map.constructMap(), // what to send
2018 map.subMap(), // what to receive
2025 void Foam::distributedTriSurfaceMesh::getVolumeType
2027 const pointField& points,
2028 List<volumeType>& volType
2033 "distributedTriSurfaceMesh::getVolumeType"
2034 "(const pointField&, List<volumeType>&) const"
2035 ) << "Volume type not supported for distributed surfaces."
2036 << exit(FatalError);
2040 // Subset the part of surface that is overlapping bb.
2041 Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
2043 const triSurface& s,
2044 const List<treeBoundBox>& bbs,
2046 labelList& subPointMap,
2047 labelList& subFaceMap
2050 // Determine what triangles to keep.
2051 boolList includedFace(s.size(), false);
2053 // Create a slightly larger bounding box.
2054 List<treeBoundBox> bbsX(bbs.size());
2055 const scalar eps = 1.0e-4;
2058 const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2059 const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2061 bbsX[i].min() = mid - halfSpan;
2062 bbsX[i].max() = mid + halfSpan;
2067 const labelledTri& f = s[triI];
2068 const point& p0 = s.points()[f[0]];
2069 const point& p1 = s.points()[f[1]];
2070 const point& p2 = s.points()[f[2]];
2072 if (overlaps(bbsX, p0, p1, p2))
2074 includedFace[triI] = true;
2078 return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2082 void Foam::distributedTriSurfaceMesh::distribute
2084 const List<treeBoundBox>& bbs,
2085 const bool keepNonLocal,
2086 autoPtr<mapDistribute>& faceMap,
2087 autoPtr<mapDistribute>& pointMap
2090 // Get bbs of all domains
2091 // ~~~~~~~~~~~~~~~~~~~~~~
2094 List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
2099 newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2102 newProcBb[Pstream::myProcNo()][i] = bbs[i];
2104 Pstream::gatherList(newProcBb);
2105 Pstream::scatterList(newProcBb);
2109 newProcBb = independentlyDistributedBbs(*this);
2117 FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
2118 << "Unsupported distribution type." << exit(FatalError);
2124 // Info<< "old bb:" << procBb_ << endl << endl;
2125 // Info<< "new bb:" << newProcBb << endl << endl;
2126 // Info<< "Same:" << (newProcBb == procBb_) << endl;
2129 if (newProcBb == procBb_)
2135 procBb_.transfer(newProcBb);
2136 dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2141 // Debug information
2144 labelList nTris(Pstream::nProcs());
2145 nTris[Pstream::myProcNo()] = triSurface::size();
2146 Pstream::gatherList(nTris);
2147 Pstream::scatterList(nTris);
2149 Info<< "distributedTriSurfaceMesh::distribute : before distribution:"
2151 << "\tproc\ttris" << endl;
2153 forAll(nTris, procI)
2155 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2161 // Use procBbs to determine which faces go where
2162 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2164 labelListList faceSendMap(Pstream::nProcs());
2165 labelListList pointSendMap(Pstream::nProcs());
2167 forAll(procBb_, procI)
2173 pointSendMap[procI],
2179 //Pout<< "Overlapping with proc " << procI
2180 // << " faces:" << faceSendMap[procI].size()
2181 // << " points:" << pointSendMap[procI].size() << endl << endl;
2187 // Include in faceSendMap/pointSendMap the triangles that are
2188 // not mapped to any processor so they stay local.
2190 const triSurface& s = static_cast<const triSurface&>(*this);
2192 boolList includedFace(s.size(), true);
2194 forAll(faceSendMap, procI)
2196 if (procI != Pstream::myProcNo())
2198 forAll(faceSendMap[procI], i)
2200 includedFace[faceSendMap[procI][i]] = false;
2205 // Combine includedFace (all triangles that are not on any neighbour)
2208 forAll(faceSendMap[Pstream::myProcNo()], i)
2210 includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2217 pointSendMap[Pstream::myProcNo()],
2218 faceSendMap[Pstream::myProcNo()]
2223 // Send over how many faces/points I need to receive
2224 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2226 labelListList faceSendSizes(Pstream::nProcs());
2227 faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2228 forAll(faceSendMap, procI)
2230 faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size();
2232 Pstream::gatherList(faceSendSizes);
2233 Pstream::scatterList(faceSendSizes);
2237 // Exchange surfaces
2238 // ~~~~~~~~~~~~~~~~~
2240 // Storage for resulting surface
2241 List<labelledTri> allTris;
2242 pointField allPoints;
2244 labelListList faceConstructMap(Pstream::nProcs());
2245 labelListList pointConstructMap(Pstream::nProcs());
2248 // My own surface first
2249 // ~~~~~~~~~~~~~~~~~~~~
2253 triSurface subSurface
2258 faceSendMap[Pstream::myProcNo()],
2263 allTris = subSurface;
2264 allPoints = subSurface.points();
2266 faceConstructMap[Pstream::myProcNo()] = identity
2268 faceSendMap[Pstream::myProcNo()].size()
2270 pointConstructMap[Pstream::myProcNo()] = identity
2272 pointSendMap[Pstream::myProcNo()].size()
2281 forAll(faceSendSizes, procI)
2283 if (procI != Pstream::myProcNo())
2285 if (faceSendSizes[Pstream::myProcNo()][procI] > 0)
2287 OPstream str(Pstream::blocking, procI);
2290 triSurface subSurface
2302 // Pout<< "Sending to " << procI
2303 // << " faces:" << faceSendMap[procI].size()
2304 // << " points:" << subSurface.points().size() << endl
2314 // Receive and merge all
2315 // ~~~~~~~~~~~~~~~~~~~~~
2317 forAll(faceSendSizes, procI)
2319 if (procI != Pstream::myProcNo())
2321 if (faceSendSizes[procI][Pstream::myProcNo()] > 0)
2323 IPstream str(Pstream::blocking, procI);
2326 triSurface subSurface(str);
2330 // Pout<< "Received from " << procI
2331 // << " faces:" << subSurface.size()
2332 // << " points:" << subSurface.points().size() << endl
2336 // Merge into allSurf
2341 subSurface.points(),
2345 faceConstructMap[procI],
2346 pointConstructMap[procI]
2351 // Pout<< "Current merged surface : faces:" << allTris.size()
2352 // << " points:" << allPoints.size() << endl << endl;
2380 // Construct triSurface. Reuse storage.
2381 triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2385 // Regions stays same
2386 // Volume type stays same.
2388 distributeFields<label>(faceMap());
2389 distributeFields<scalar>(faceMap());
2390 distributeFields<vector>(faceMap());
2391 distributeFields<sphericalTensor>(faceMap());
2392 distributeFields<symmTensor>(faceMap());
2393 distributeFields<tensor>(faceMap());
2397 labelList nTris(Pstream::nProcs());
2398 nTris[Pstream::myProcNo()] = triSurface::size();
2399 Pstream::gatherList(nTris);
2400 Pstream::scatterList(nTris);
2402 Info<< "distributedTriSurfaceMesh::distribute : after distribution:"
2404 << "\tproc\ttris" << endl;
2406 forAll(nTris, procI)
2408 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2415 //- Write using given format, version and compression
2416 bool Foam::distributedTriSurfaceMesh::writeObject
2418 IOstream::streamFormat fmt,
2419 IOstream::versionNumber ver,
2420 IOstream::compressionType cmp
2423 // Make sure dictionary goes to same directory as surface
2424 const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2426 // Dictionary needs to be written in ascii - binary output not supported.
2428 triSurfaceMesh::writeObject(fmt, ver, cmp)
2429 && dict_.writeObject(IOstream::ASCII, ver, cmp);
2433 void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
2437 calcBounds(bb, nPoints);
2438 reduce(bb.min(), minOp<point>());
2439 reduce(bb.max(), maxOp<point>());
2441 os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2443 << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2444 << "Bounding Box : " << bb << endl;
2448 // ************************************************************************* //