1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "distributedTriSurfaceMesh.H"
27 #include "mapDistribute.H"
29 #include "addToRunTimeSelectionTable.H"
30 #include "triangleFuncs.H"
31 #include "matchPoints.H"
32 #include "globalIndex.H"
36 #include "decompositionMethod.H"
37 #include "vectorList.H"
38 #include "PackedBoolList.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
45 addToRunTimeSelectionTable
48 distributedTriSurfaceMesh,
56 Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>::names[] =
63 const Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>
64 Foam::distributedTriSurfaceMesh::distributionTypeNames_;
67 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
69 // Read my additional data from the dictionary
70 bool Foam::distributedTriSurfaceMesh::read()
72 // Get bb of all domains.
73 procBb_.setSize(Pstream::nProcs());
75 procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
76 Pstream::gatherList(procBb_);
77 Pstream::scatterList(procBb_);
80 distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
83 mergeDist_ = readScalar(dict_.lookup("mergeDistance"));
89 // Is segment fully local?
90 bool Foam::distributedTriSurfaceMesh::isLocal
92 const List<treeBoundBox>& myBbs,
99 if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
108 //void Foam::distributedTriSurfaceMesh::splitSegment
110 // const label segmentI,
111 // const point& start,
113 // const treeBoundBox& bb,
115 // DynamicList<segment>& allSegments,
116 // dynamicLabelList& allSegmentMap,
117 // dynamicLabelList sendMap
121 // point clipPt0, clipPt1;
123 // if (bb.contains(start))
125 // // start within, trim end to bb
126 // bool clipped = bb.intersects(end, start, clipPt0);
130 // // segment from start to clippedStart passes
132 // sendMap[procI].append(allSegments.size());
133 // allSegmentMap.append(segmentI);
134 // allSegments.append(segment(start, clipPt0));
137 // else if (bb.contains(end))
139 // // end within, trim start to bb
140 // bool clipped = bb.intersects(start, end, clipPt0);
144 // sendMap[procI].append(allSegments.size());
145 // allSegmentMap.append(segmentI);
146 // allSegments.append(segment(clipPt0, end));
152 // bool clippedStart = bb.intersects(start, end, clipPt0);
156 // bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
160 // // middle part of segment passes through proc.
161 // sendMap[procI].append(allSegments.size());
162 // allSegmentMap.append(segmentI);
163 // allSegments.append(segment(clipPt0, clipPt1));
170 void Foam::distributedTriSurfaceMesh::distributeSegment
172 const label segmentI,
176 DynamicList<segment>& allSegments,
177 dynamicLabelList& allSegmentMap,
178 List<dynamicLabelList >& sendMap
185 // 1. Fully local already handled outside. Note: retest is cheap.
186 if (isLocal(procBb_[Pstream::myProcNo()], start, end))
192 // 2. If fully inside one other processor, then only need to send
193 // to that one processor even if it intersects another. Rare occurrence
194 // but cheap to test.
195 forAll(procBb_, procI)
197 if (procI != Pstream::myProcNo())
199 const List<treeBoundBox>& bbs = procBb_[procI];
201 if (isLocal(bbs, start, end))
203 sendMap[procI].append(allSegments.size());
204 allSegmentMap.append(segmentI);
205 allSegments.append(segment(start, end));
212 // 3. If not contained in single processor send to all intersecting
214 forAll(procBb_, procI)
216 const List<treeBoundBox>& bbs = procBb_[procI];
220 const treeBoundBox& bb = bbs[bbI];
222 // Scheme a: any processor that intersects the segment gets
225 if (bb.intersects(start, end, clipPt))
227 sendMap[procI].append(allSegments.size());
228 allSegmentMap.append(segmentI);
229 allSegments.append(segment(start, end));
232 // Alternative: any processor only gets clipped bit of
233 // segment. This gives small problems with additional
234 // truncation errors.
251 Foam::autoPtr<Foam::mapDistribute>
252 Foam::distributedTriSurfaceMesh::distributeSegments
254 const pointField& start,
255 const pointField& end,
257 List<segment>& allSegments,
258 labelList& allSegmentMap
261 // Determine send map
262 // ~~~~~~~~~~~~~~~~~~
264 labelListList sendMap(Pstream::nProcs());
267 // Since intersection test is quite expensive compared to memory
268 // allocation we use DynamicList to immediately store the segment
269 // in the correct bin.
272 DynamicList<segment> dynAllSegments(start.size());
273 // Original index of segment
274 dynamicLabelList dynAllSegmentMap(start.size());
275 // Per processor indices into allSegments to send
276 List<dynamicLabelList > dynSendMap(Pstream::nProcs());
278 forAll(start, segmentI)
292 // Convert dynamicList to labelList
293 sendMap.setSize(Pstream::nProcs());
294 forAll(sendMap, procI)
296 dynSendMap[procI].shrink();
297 sendMap[procI].transfer(dynSendMap[procI]);
300 allSegments.transfer(dynAllSegments.shrink());
301 allSegmentMap.transfer(dynAllSegmentMap.shrink());
305 // Send over how many I need to receive.
306 labelListList sendSizes(Pstream::nProcs());
307 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
308 forAll(sendMap, procI)
310 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
312 Pstream::gatherList(sendSizes);
313 Pstream::scatterList(sendSizes);
316 // Determine order of receiving
317 labelListList constructMap(Pstream::nProcs());
319 // My local segments first
320 constructMap[Pstream::myProcNo()] = identity
322 sendMap[Pstream::myProcNo()].size()
325 label segmentI = constructMap[Pstream::myProcNo()].size();
326 forAll(constructMap, procI)
328 if (procI != Pstream::myProcNo())
330 // What I need to receive is what other processor is sending to me.
331 label nRecv = sendSizes[procI][Pstream::myProcNo()];
332 constructMap[procI].setSize(nRecv);
334 for (label i = 0; i < nRecv; i++)
336 constructMap[procI][i] = segmentI++;
341 return autoPtr<mapDistribute>
345 segmentI, // size after construction
348 true // reuse storage
354 void Foam::distributedTriSurfaceMesh::findLine
356 const bool nearestIntersection,
357 const pointField& start,
358 const pointField& end,
359 List<pointIndexHit>& info
362 const indexedOctree<treeDataTriSurface>& octree = tree();
364 // Important:force synchronised construction of indexing
365 const globalIndex& triIndexer = globalTris();
368 info.setSize(start.size());
375 // Do any local queries
376 // ~~~~~~~~~~~~~~~~~~~~
382 if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
384 if (nearestIntersection)
386 info[i] = octree.findLine(start[i], end[i]);
390 info[i] = octree.findLineAny(start[i], end[i]);
395 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
406 returnReduce(nLocal, sumOp<label>())
407 < returnReduce(start.size(), sumOp<label>())
411 // Not all can be resolved locally. Build segments and map, send over
412 // segments, do intersections, send back and merge.
415 // Construct queries (segments)
416 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
419 List<segment> allSegments(start.size());
420 // Original index of segment
421 labelList allSegmentMap(start.size());
423 const autoPtr<mapDistribute> mapPtr
433 const mapDistribute& map = mapPtr();
435 label nOldAllSegments = allSegments.size();
438 // Exchange the segments
439 // ~~~~~~~~~~~~~~~~~~~~~
443 Pstream::nonBlocking, //Pstream::scheduled,
444 List<labelPair>(0), //map.schedule(),
446 map.subMap(), // what to send
447 map.constructMap(), // what to receive
452 // Do tests I need to do
453 // ~~~~~~~~~~~~~~~~~~~~~
456 List<pointIndexHit> intersections(allSegments.size());
458 forAll(allSegments, i)
460 if (nearestIntersection)
462 intersections[i] = octree.findLine
464 allSegments[i].first(),
465 allSegments[i].second()
470 intersections[i] = octree.findLineAny
472 allSegments[i].first(),
473 allSegments[i].second()
477 // Convert triangle index to global numbering
478 if (intersections[i].hit())
480 intersections[i].setIndex
482 triIndexer.toGlobal(intersections[i].index())
488 // Exchange the intersections (opposite to segments)
489 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
493 //Pstream::scheduled,
494 //map.schedule // Note reverse schedule
496 // map.constructMap(),
499 Pstream::nonBlocking,
502 map.constructMap(), // what to send
503 map.subMap(), // what to receive
511 forAll(intersections, i)
513 const pointIndexHit& allInfo = intersections[i];
514 label segmentI = allSegmentMap[i];
515 pointIndexHit& hitInfo = info[segmentI];
521 // No intersection yet so take this one
524 else if (nearestIntersection)
526 // Nearest intersection
529 magSqr(allInfo.hitPoint()-start[segmentI])
530 < magSqr(hitInfo.hitPoint()-start[segmentI])
542 // Exchanges indices to the processor they come from.
543 // - calculates exchange map
544 // - uses map to calculate local triangle index
545 Foam::autoPtr<Foam::mapDistribute>
546 Foam::distributedTriSurfaceMesh::calcLocalQueries
548 const List<pointIndexHit>& info,
549 labelList& triangleIndex
552 triangleIndex.setSize(info.size());
554 const globalIndex& triIndexer = globalTris();
557 // Determine send map
558 // ~~~~~~~~~~~~~~~~~~
560 // Since determining which processor the query should go to is
561 // cheap we do a multi-pass algorithm to save some memory temporarily.
564 labelList nSend(Pstream::nProcs(), 0);
570 label procI = triIndexer.whichProcID(info[i].index());
576 labelListList sendMap(Pstream::nProcs());
579 sendMap[procI].setSize(nSend[procI]);
588 label procI = triIndexer.whichProcID(info[i].index());
589 triangleIndex[i] = triIndexer.toLocal(procI, info[i].index());
590 sendMap[procI][nSend[procI]++] = i;
594 triangleIndex[i] = -1;
599 // Send over how many I need to receive
600 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
602 labelListList sendSizes(Pstream::nProcs());
603 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
604 forAll(sendMap, procI)
606 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
608 Pstream::gatherList(sendSizes);
609 Pstream::scatterList(sendSizes);
612 // Determine receive map
613 // ~~~~~~~~~~~~~~~~~~~~~
615 labelListList constructMap(Pstream::nProcs());
617 // My local segments first
618 constructMap[Pstream::myProcNo()] = identity
620 sendMap[Pstream::myProcNo()].size()
623 label segmentI = constructMap[Pstream::myProcNo()].size();
624 forAll(constructMap, procI)
626 if (procI != Pstream::myProcNo())
628 // What I need to receive is what other processor is sending to me.
629 label nRecv = sendSizes[procI][Pstream::myProcNo()];
630 constructMap[procI].setSize(nRecv);
632 for (label i = 0; i < nRecv; i++)
634 constructMap[procI][i] = segmentI++;
640 // Pack into distribution map
641 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
643 autoPtr<mapDistribute> mapPtr
647 segmentI, // size after construction
650 true // reuse storage
653 const mapDistribute& map = mapPtr();
661 //Pstream::scheduled,
663 Pstream::nonBlocking,
666 map.subMap(), // what to send
667 map.constructMap(), // what to receive
676 Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs
679 const scalar radiusSqr,
686 forAll(procBb_, procI)
688 const List<treeBoundBox>& bbs = procBb_[procI];
692 if (bbs[bbI].overlaps(centre, radiusSqr))
694 overlaps[procI] = true;
704 // Generate queries for parallel distance calculation
705 // - calculates exchange map
706 // - uses map to exchange points and radius
707 Foam::autoPtr<Foam::mapDistribute>
708 Foam::distributedTriSurfaceMesh::calcLocalQueries
710 const pointField& centres,
711 const scalarField& radiusSqr,
713 pointField& allCentres,
714 scalarField& allRadiusSqr,
715 labelList& allSegmentMap
721 labelListList sendMap(Pstream::nProcs());
725 DynamicList<point> dynAllCentres(centres.size());
726 DynamicList<scalar> dynAllRadiusSqr(centres.size());
727 // Original index of segment
728 dynamicLabelList dynAllSegmentMap(centres.size());
729 // Per processor indices into allSegments to send
730 List<dynamicLabelList > dynSendMap(Pstream::nProcs());
732 // Work array - whether processor bb overlaps the bounding sphere.
733 boolList procBbOverlaps(Pstream::nProcs());
735 forAll(centres, centreI)
737 // Find the processor this sample+radius overlaps.
745 forAll(procBbOverlaps, procI)
747 if (procI != Pstream::myProcNo() && procBbOverlaps[procI])
749 dynSendMap[procI].append(dynAllCentres.size());
750 dynAllSegmentMap.append(centreI);
751 dynAllCentres.append(centres[centreI]);
752 dynAllRadiusSqr.append(radiusSqr[centreI]);
757 // Convert dynamicList to labelList
758 sendMap.setSize(Pstream::nProcs());
759 forAll(sendMap, procI)
761 dynSendMap[procI].shrink();
762 sendMap[procI].transfer(dynSendMap[procI]);
765 allCentres.transfer(dynAllCentres.shrink());
766 allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
767 allSegmentMap.transfer(dynAllSegmentMap.shrink());
771 // Send over how many I need to receive.
772 labelListList sendSizes(Pstream::nProcs());
773 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
774 forAll(sendMap, procI)
776 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
778 Pstream::gatherList(sendSizes);
779 Pstream::scatterList(sendSizes);
782 // Determine order of receiving
783 labelListList constructMap(Pstream::nProcs());
785 // My local segments first
786 constructMap[Pstream::myProcNo()] = identity
788 sendMap[Pstream::myProcNo()].size()
791 label segmentI = constructMap[Pstream::myProcNo()].size();
792 forAll(constructMap, procI)
794 if (procI != Pstream::myProcNo())
796 // What I need to receive is what other processor is sending to me.
797 label nRecv = sendSizes[procI][Pstream::myProcNo()];
798 constructMap[procI].setSize(nRecv);
800 for (label i = 0; i < nRecv; i++)
802 constructMap[procI][i] = segmentI++;
807 autoPtr<mapDistribute> mapPtr
811 segmentI, // size after construction
814 true // reuse storage
821 // Find bounding boxes that guarantee a more or less uniform distribution
822 // of triangles. Decomposition in here is only used to get the bounding
823 // boxes, actual decomposition is done later on.
824 // Returns a per processor a list of bounding boxes that most accurately
825 // describe the shape. For now just a single bounding box per processor but
826 // optimisation might be to determine a better fitting shape.
827 Foam::List<Foam::List<Foam::treeBoundBox> >
828 Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
833 if (!decomposer_.valid())
835 // Use current decomposer.
836 // Note: or always use hierarchical?
837 IOdictionary decomposeDict
842 searchableSurface::time().system(),
843 searchableSurface::time(),
849 decomposer_ = decompositionMethod::New(decomposeDict);
851 if (!decomposer_().parallelAware())
855 "distributedTriSurfaceMesh::independentlyDistributedBbs"
856 "(const triSurface&)"
857 ) << "The decomposition method " << decomposer_().typeName
858 << " does not decompose in parallel."
859 << " Please choose one that does." << exit(FatalError);
863 // Do decomposition according to triangle centre
864 pointField triCentres(s.size());
867 triCentres[triI] = s[triI].centre(s.points());
870 // Do the actual decomposition
871 labelList distribution(decomposer_->decompose(triCentres));
873 // Find bounding box for all triangles on new distribution.
875 // Initialise to inverted box (VGREAT, -VGREAT)
876 List<List<treeBoundBox> > bbs(Pstream::nProcs());
879 bbs[procI].setSize(1);
880 //bbs[procI][0] = boundBox::invertedBox;
881 bbs[procI][0].min() = point( VGREAT, VGREAT, VGREAT);
882 bbs[procI][0].max() = point(-VGREAT, -VGREAT, -VGREAT);
887 point& bbMin = bbs[distribution[triI]][0].min();
888 point& bbMax = bbs[distribution[triI]][0].max();
890 const labelledTri& f = s[triI];
891 const point& p0 = s.points()[f[0]];
892 const point& p1 = s.points()[f[1]];
893 const point& p2 = s.points()[f[2]];
895 bbMin = min(bbMin, p0);
896 bbMin = min(bbMin, p1);
897 bbMin = min(bbMin, p2);
899 bbMax = max(bbMax, p0);
900 bbMax = max(bbMax, p1);
901 bbMax = max(bbMax, p2);
904 // Now combine for all processors and convert to correct format.
907 forAll(bbs[procI], i)
909 reduce(bbs[procI][i].min(), minOp<point>());
910 reduce(bbs[procI][i].max(), maxOp<point>());
917 // Does any part of triangle overlap bb.
918 bool Foam::distributedTriSurfaceMesh::overlaps
920 const List<treeBoundBox>& bbs,
928 const treeBoundBox& bb = bbs[bbI];
930 treeBoundBox triBb(p0, p0);
931 triBb.min() = min(triBb.min(), p1);
932 triBb.min() = min(triBb.min(), p2);
934 triBb.max() = max(triBb.max(), p1);
935 triBb.max() = max(triBb.max(), p2);
937 //- Exact test of triangle intersecting bb
939 // Quick rejection. If whole bounding box of tri is outside cubeBb then
940 // there will be no intersection.
941 if (bb.overlaps(triBb))
943 // Check if one or more triangle point inside
944 if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
946 // One or more points inside
950 // Now we have the difficult case: all points are outside but
951 // connecting edges might go through cube. Use fast intersection
953 bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
965 void Foam::distributedTriSurfaceMesh::subsetMeshMap
968 const boolList& include,
969 const label nIncluded,
970 labelList& newToOldPoints,
971 labelList& oldToNewPoints,
972 labelList& newToOldFaces
975 newToOldFaces.setSize(nIncluded);
976 newToOldPoints.setSize(s.points().size());
977 oldToNewPoints.setSize(s.points().size());
983 forAll(include, oldFacei)
985 if (include[oldFacei])
987 // Store new faces compact
988 newToOldFaces[faceI++] = oldFacei;
990 // Renumber labels for triangle
991 const labelledTri& tri = s[oldFacei];
995 label oldPointI = tri[fp];
997 if (oldToNewPoints[oldPointI] == -1)
999 oldToNewPoints[oldPointI] = pointI;
1000 newToOldPoints[pointI++] = oldPointI;
1005 newToOldPoints.setSize(pointI);
1010 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1012 const triSurface& s,
1013 const labelList& newToOldPoints,
1014 const labelList& oldToNewPoints,
1015 const labelList& newToOldFaces
1019 pointField newPoints(newToOldPoints.size());
1020 forAll(newToOldPoints, i)
1022 newPoints[i] = s.points()[newToOldPoints[i]];
1025 List<labelledTri> newTriangles(newToOldFaces.size());
1027 forAll(newToOldFaces, i)
1029 // Get old vertex labels
1030 const labelledTri& tri = s[newToOldFaces[i]];
1032 newTriangles[i][0] = oldToNewPoints[tri[0]];
1033 newTriangles[i][1] = oldToNewPoints[tri[1]];
1034 newTriangles[i][2] = oldToNewPoints[tri[2]];
1035 newTriangles[i].region() = tri.region();
1039 return triSurface(newTriangles, s.patches(), newPoints, true);
1043 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1045 const triSurface& s,
1046 const boolList& include,
1047 labelList& newToOldPoints,
1048 labelList& newToOldFaces
1061 labelList oldToNewPoints;
1082 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1084 const triSurface& s,
1085 const labelList& newToOldFaces,
1086 labelList& newToOldPoints
1089 const boolList include
1091 createWithValues<boolList>
1100 newToOldPoints.setSize(s.points().size());
1101 labelList oldToNewPoints(s.points().size(), -1);
1105 forAll(include, oldFacei)
1107 if (include[oldFacei])
1109 // Renumber labels for triangle
1110 const labelledTri& tri = s[oldFacei];
1114 label oldPointI = tri[fp];
1116 if (oldToNewPoints[oldPointI] == -1)
1118 oldToNewPoints[oldPointI] = pointI;
1119 newToOldPoints[pointI++] = oldPointI;
1124 newToOldPoints.setSize(pointI);
1137 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
1139 const List<labelledTri>& allFaces,
1140 const labelListList& allPointFaces,
1141 const labelledTri& otherF
1144 // allFaces connected to otherF[0]
1145 const labelList& pFaces = allPointFaces[otherF[0]];
1149 const labelledTri& f = allFaces[pFaces[i]];
1151 if (f.region() == otherF.region())
1153 // Find index of otherF[0]
1154 label fp0 = findIndex(f, otherF[0]);
1155 // Check rest of triangle in same order
1156 label fp1 = f.fcIndex(fp0);
1157 label fp2 = f.fcIndex(fp1);
1159 if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1169 // Merge into allSurf.
1170 void Foam::distributedTriSurfaceMesh::merge
1172 const scalar mergeDist,
1173 const List<labelledTri>& subTris,
1174 const pointField& subPoints,
1176 List<labelledTri>& allTris,
1177 pointField& allPoints,
1179 labelList& faceConstructMap,
1180 labelList& pointConstructMap
1188 scalarField(subPoints.size(), mergeDist), // match distance
1193 label nOldAllPoints = allPoints.size();
1196 // Add all unmatched points
1197 // ~~~~~~~~~~~~~~~~~~~~~~~~
1199 label allPointI = nOldAllPoints;
1200 forAll(pointConstructMap, pointI)
1202 if (pointConstructMap[pointI] == -1)
1204 pointConstructMap[pointI] = allPointI++;
1208 if (allPointI > nOldAllPoints)
1210 allPoints.setSize(allPointI);
1212 forAll(pointConstructMap, pointI)
1214 if (pointConstructMap[pointI] >= nOldAllPoints)
1216 allPoints[pointConstructMap[pointI]] = subPoints[pointI];
1222 // To check whether triangles are same we use pointFaces.
1223 labelListList allPointFaces;
1224 invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1227 // Add all unmatched triangles
1228 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1230 label allTriI = allTris.size();
1231 allTris.setSize(allTriI + subTris.size());
1233 faceConstructMap.setSize(subTris.size());
1235 forAll(subTris, triI)
1237 const labelledTri& subTri = subTris[triI];
1239 // Get triangle in new numbering
1240 labelledTri mappedTri
1242 pointConstructMap[subTri[0]],
1243 pointConstructMap[subTri[1]],
1244 pointConstructMap[subTri[2]],
1249 // Check if all points were already in surface
1250 bool fullMatch = true;
1252 forAll(mappedTri, fp)
1254 if (mappedTri[fp] >= nOldAllPoints)
1263 // All three points are mapped to old points. See if same
1265 label i = findTriangle
1275 faceConstructMap[triI] = allTriI;
1276 allTris[allTriI] = mappedTri;
1281 faceConstructMap[triI] = i;
1287 faceConstructMap[triI] = allTriI;
1288 allTris[allTriI] = mappedTri;
1292 allTris.setSize(allTriI);
1296 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1298 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1301 const triSurface& s,
1302 const dictionary& dict
1305 triSurfaceMesh(io, s),
1310 searchableSurface::name() + "Dict",
1311 searchableSurface::instance(),
1312 searchableSurface::local(),
1313 searchableSurface::db(),
1314 searchableSurface::NO_READ,
1315 searchableSurface::writeOpt(),
1316 searchableSurface::registerObject()
1325 Info<< "Constructed from triSurface:" << endl;
1328 labelList nTris(Pstream::nProcs());
1329 nTris[Pstream::myProcNo()] = triSurface::size();
1330 Pstream::gatherList(nTris);
1331 Pstream::scatterList(nTris);
1333 Info<< endl<< "\tproc\ttris\tbb" << endl;
1334 forAll(nTris, procI)
1336 Info<< '\t' << procI << '\t' << nTris[procI]
1337 << '\t' << procBb_[procI] << endl;
1344 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
1346 //triSurfaceMesh(io),
1352 io.time().findInstance(io.local(), word::null),
1364 searchableSurface::name() + "Dict",
1365 searchableSurface::instance(),
1366 searchableSurface::local(),
1367 searchableSurface::db(),
1368 searchableSurface::readOpt(),
1369 searchableSurface::writeOpt(),
1370 searchableSurface::registerObject()
1378 Info<< "Read distributedTriSurface from " << io.objectPath()
1382 labelList nTris(Pstream::nProcs());
1383 nTris[Pstream::myProcNo()] = triSurface::size();
1384 Pstream::gatherList(nTris);
1385 Pstream::scatterList(nTris);
1387 Info<< endl<< "\tproc\ttris\tbb" << endl;
1388 forAll(nTris, procI)
1390 Info<< '\t' << procI << '\t' << nTris[procI]
1391 << '\t' << procBb_[procI] << endl;
1398 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1401 const dictionary& dict
1404 //triSurfaceMesh(io, dict),
1410 io.time().findInstance(io.local(), word::null),
1423 searchableSurface::name() + "Dict",
1424 searchableSurface::instance(),
1425 searchableSurface::local(),
1426 searchableSurface::db(),
1427 searchableSurface::readOpt(),
1428 searchableSurface::writeOpt(),
1429 searchableSurface::registerObject()
1437 Info<< "Read distributedTriSurface from " << io.objectPath()
1438 << " and dictionary:" << endl;
1441 labelList nTris(Pstream::nProcs());
1442 nTris[Pstream::myProcNo()] = triSurface::size();
1443 Pstream::gatherList(nTris);
1444 Pstream::scatterList(nTris);
1446 Info<< endl<< "\tproc\ttris\tbb" << endl;
1447 forAll(nTris, procI)
1449 Info<< '\t' << procI << '\t' << nTris[procI]
1450 << '\t' << procBb_[procI] << endl;
1457 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1459 Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh()
1465 void Foam::distributedTriSurfaceMesh::clearOut()
1467 globalTris_.clear();
1468 triSurfaceMesh::clearOut();
1472 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1474 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
1476 if (!globalTris_.valid())
1478 globalTris_.reset(new globalIndex(triSurface::size()));
1484 void Foam::distributedTriSurfaceMesh::findNearest
1486 const pointField& samples,
1487 const scalarField& nearestDistSqr,
1488 List<pointIndexHit>& info
1491 const indexedOctree<treeDataTriSurface>& octree = tree();
1493 // Important:force synchronised construction of indexing
1494 const globalIndex& triIndexer = globalTris();
1500 info.setSize(samples.size());
1508 // Do any local queries
1509 // ~~~~~~~~~~~~~~~~~~~~
1514 // Work array - whether processor bb overlaps the bounding sphere.
1515 boolList procBbOverlaps(Pstream::nProcs());
1519 // Find the processor this sample+radius overlaps.
1520 label nProcs = calcOverlappingProcs
1527 // Overlaps local processor?
1528 if (procBbOverlaps[Pstream::myProcNo()])
1530 info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1533 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1549 returnReduce(nLocal, sumOp<label>())
1550 < returnReduce(samples.size(), sumOp<label>())
1554 // Not all can be resolved locally. Build queries and map, send over
1555 // queries, do intersections, send back and merge.
1557 // Calculate queries and exchange map
1558 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1560 pointField allCentres;
1561 scalarField allRadiusSqr;
1562 labelList allSegmentMap;
1563 autoPtr<mapDistribute> mapPtr
1575 const mapDistribute& map = mapPtr();
1578 // swap samples to local processor
1579 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1583 //Pstream::scheduled,
1585 Pstream::nonBlocking,
1587 map.constructSize(),
1588 map.subMap(), // what to send
1589 map.constructMap(), // what to receive
1594 //Pstream::scheduled,
1596 Pstream::nonBlocking,
1598 map.constructSize(),
1599 map.subMap(), // what to send
1600 map.constructMap(), // what to receive
1608 List<pointIndexHit> allInfo(allCentres.size());
1611 allInfo[i] = octree.findNearest
1616 if (allInfo[i].hit())
1618 allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1623 // Send back results
1624 // ~~~~~~~~~~~~~~~~~
1628 //Pstream::scheduled,
1629 //map.schedule // note reverse schedule
1631 // map.constructMap(),
1634 Pstream::nonBlocking,
1636 allSegmentMap.size(),
1637 map.constructMap(), // what to send
1638 map.subMap(), // what to receive
1643 // Extract information
1644 // ~~~~~~~~~~~~~~~~~~~
1648 if (allInfo[i].hit())
1650 label pointI = allSegmentMap[i];
1652 if (!info[pointI].hit())
1654 // No intersection yet so take this one
1655 info[pointI] = allInfo[i];
1659 // Nearest intersection
1662 magSqr(allInfo[i].hitPoint()-samples[pointI])
1663 < magSqr(info[pointI].hitPoint()-samples[pointI])
1666 info[pointI] = allInfo[i];
1675 void Foam::distributedTriSurfaceMesh::findLine
1677 const pointField& start,
1678 const pointField& end,
1679 List<pointIndexHit>& info
1684 true, // nearestIntersection
1692 void Foam::distributedTriSurfaceMesh::findLineAny
1694 const pointField& start,
1695 const pointField& end,
1696 List<pointIndexHit>& info
1701 true, // nearestIntersection
1709 void Foam::distributedTriSurfaceMesh::findLineAll
1711 const pointField& start,
1712 const pointField& end,
1713 List<List<pointIndexHit> >& info
1716 // Reuse fineLine. We could modify all of findLine to do multiple
1717 // intersections but this would mean a lot of data transferred so
1718 // for now we just find nearest intersection and retest from that
1719 // intersection onwards.
1722 List<pointIndexHit> hitInfo(start.size());
1726 true, // nearestIntersection
1733 // To find all intersections we add a small vector to the last intersection
1734 // This is chosen such that
1735 // - it is significant (SMALL is smallest representative relative tolerance;
1736 // we need something bigger since we're doing calculations)
1737 // - if the start-end vector is zero we still progress
1738 const vectorField dirVec(end-start);
1739 const scalarField magSqrDirVec(magSqr(dirVec));
1740 const vectorField smallVec
1742 Foam::sqrt(SMALL)*dirVec
1743 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
1746 // Copy to input and compact any hits
1747 labelList pointMap(start.size());
1748 pointField e0(start.size());
1749 pointField e1(start.size());
1752 info.setSize(hitInfo.size());
1753 forAll(hitInfo, pointI)
1755 if (hitInfo[pointI].hit())
1757 info[pointI].setSize(1);
1758 info[pointI][0] = hitInfo[pointI];
1760 point pt = hitInfo[pointI].hitPoint() + smallVec[pointI];
1762 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1765 e1[compactI] = end[pointI];
1766 pointMap[compactI] = pointI;
1772 info[pointI].clear();
1776 e0.setSize(compactI);
1777 e1.setSize(compactI);
1778 pointMap.setSize(compactI);
1780 while (returnReduce(e0.size(), sumOp<label>()) > 0)
1784 true, // nearestIntersection
1795 if (hitInfo[i].hit())
1797 label pointI = pointMap[i];
1799 label sz = info[pointI].size();
1800 info[pointI].setSize(sz+1);
1801 info[pointI][sz] = hitInfo[i];
1803 point pt = hitInfo[i].hitPoint() + smallVec[pointI];
1805 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1808 e1[compactI] = end[pointI];
1809 pointMap[compactI] = pointI;
1816 e0.setSize(compactI);
1817 e1.setSize(compactI);
1818 pointMap.setSize(compactI);
1823 void Foam::distributedTriSurfaceMesh::getRegion
1825 const List<pointIndexHit>& info,
1829 if (!Pstream::parRun())
1831 region.setSize(info.size());
1836 region[i] = triSurface::operator[](info[i].index()).region();
1847 // Get query data (= local index of triangle)
1850 labelList triangleIndex(info.size());
1851 autoPtr<mapDistribute> mapPtr
1859 const mapDistribute& map = mapPtr();
1865 const triSurface& s = static_cast<const triSurface&>(*this);
1867 region.setSize(triangleIndex.size());
1869 forAll(triangleIndex, i)
1871 label triI = triangleIndex[i];
1872 region[i] = s[triI].region();
1876 // Send back results
1877 // ~~~~~~~~~~~~~~~~~
1881 //Pstream::scheduled,
1882 //map.schedule // note reverse schedule
1884 // map.constructMap(),
1887 Pstream::nonBlocking,
1890 map.constructMap(), // what to send
1891 map.subMap(), // what to receive
1897 void Foam::distributedTriSurfaceMesh::getNormal
1899 const List<pointIndexHit>& info,
1903 if (!Pstream::parRun())
1905 triSurfaceMesh::getNormal(info, normal);
1910 // Get query data (= local index of triangle)
1913 labelList triangleIndex(info.size());
1914 autoPtr<mapDistribute> mapPtr
1922 const mapDistribute& map = mapPtr();
1928 const triSurface& s = static_cast<const triSurface&>(*this);
1930 normal.setSize(triangleIndex.size());
1932 forAll(triangleIndex, i)
1934 label triI = triangleIndex[i];
1935 normal[i] = s[triI].normal(s.points());
1936 normal[i] /= mag(normal[i]) + VSMALL;
1940 // Send back results
1941 // ~~~~~~~~~~~~~~~~~
1945 //Pstream::scheduled,
1946 //map.schedule // note reverse schedule
1948 // map.constructMap(),
1951 Pstream::nonBlocking,
1954 map.constructMap(), // what to send
1955 map.subMap(), // what to receive
1961 void Foam::distributedTriSurfaceMesh::getField
1963 const List<pointIndexHit>& info,
1967 if (!Pstream::parRun())
1969 triSurfaceMesh::getField(info, values);
1973 if (foundObject<triSurfaceLabelField>("values"))
1975 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
1981 // Get query data (= local index of triangle)
1984 labelList triangleIndex(info.size());
1985 autoPtr<mapDistribute> mapPtr
1993 const mapDistribute& map = mapPtr();
1999 values.setSize(triangleIndex.size());
2001 forAll(triangleIndex, i)
2003 label triI = triangleIndex[i];
2004 values[i] = fld[triI];
2008 // Send back results
2009 // ~~~~~~~~~~~~~~~~~
2013 Pstream::nonBlocking,
2016 map.constructMap(), // what to send
2017 map.subMap(), // what to receive
2024 void Foam::distributedTriSurfaceMesh::getVolumeType
2026 const pointField& points,
2027 List<volumeType>& volType
2032 "distributedTriSurfaceMesh::getVolumeType"
2033 "(const pointField&, List<volumeType>&) const"
2034 ) << "Volume type not supported for distributed surfaces."
2035 << exit(FatalError);
2039 // Subset the part of surface that is overlapping bb.
2040 Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
2042 const triSurface& s,
2043 const List<treeBoundBox>& bbs,
2045 labelList& subPointMap,
2046 labelList& subFaceMap
2049 // Determine what triangles to keep.
2050 boolList includedFace(s.size(), false);
2052 // Create a slightly larger bounding box.
2053 List<treeBoundBox> bbsX(bbs.size());
2054 const scalar eps = 1.0e-4;
2057 const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2058 const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2060 bbsX[i].min() = mid - halfSpan;
2061 bbsX[i].max() = mid + halfSpan;
2066 const labelledTri& f = s[triI];
2067 const point& p0 = s.points()[f[0]];
2068 const point& p1 = s.points()[f[1]];
2069 const point& p2 = s.points()[f[2]];
2071 if (overlaps(bbsX, p0, p1, p2))
2073 includedFace[triI] = true;
2077 return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2081 void Foam::distributedTriSurfaceMesh::distribute
2083 const List<treeBoundBox>& bbs,
2084 const bool keepNonLocal,
2085 autoPtr<mapDistribute>& faceMap,
2086 autoPtr<mapDistribute>& pointMap
2089 // Get bbs of all domains
2090 // ~~~~~~~~~~~~~~~~~~~~~~
2093 List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
2098 newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2101 newProcBb[Pstream::myProcNo()][i] = bbs[i];
2103 Pstream::gatherList(newProcBb);
2104 Pstream::scatterList(newProcBb);
2108 newProcBb = independentlyDistributedBbs(*this);
2116 FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
2117 << "Unsupported distribution type." << exit(FatalError);
2123 // Info<< "old bb:" << procBb_ << endl << endl;
2124 // Info<< "new bb:" << newProcBb << endl << endl;
2125 // Info<< "Same:" << (newProcBb == procBb_) << endl;
2128 if (newProcBb == procBb_)
2134 procBb_.transfer(newProcBb);
2135 dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2140 // Debug information
2143 labelList nTris(Pstream::nProcs());
2144 nTris[Pstream::myProcNo()] = triSurface::size();
2145 Pstream::gatherList(nTris);
2146 Pstream::scatterList(nTris);
2148 Info<< "distributedTriSurfaceMesh::distribute : before distribution:"
2150 << "\tproc\ttris" << endl;
2152 forAll(nTris, procI)
2154 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2160 // Use procBbs to determine which faces go where
2161 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2163 labelListList faceSendMap(Pstream::nProcs());
2164 labelListList pointSendMap(Pstream::nProcs());
2166 forAll(procBb_, procI)
2172 pointSendMap[procI],
2178 //Pout<< "Overlapping with proc " << procI
2179 // << " faces:" << faceSendMap[procI].size()
2180 // << " points:" << pointSendMap[procI].size() << endl << endl;
2186 // Include in faceSendMap/pointSendMap the triangles that are
2187 // not mapped to any processor so they stay local.
2189 const triSurface& s = static_cast<const triSurface&>(*this);
2191 boolList includedFace(s.size(), true);
2193 forAll(faceSendMap, procI)
2195 if (procI != Pstream::myProcNo())
2197 forAll(faceSendMap[procI], i)
2199 includedFace[faceSendMap[procI][i]] = false;
2204 // Combine includedFace (all triangles that are not on any neighbour)
2207 forAll(faceSendMap[Pstream::myProcNo()], i)
2209 includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2216 pointSendMap[Pstream::myProcNo()],
2217 faceSendMap[Pstream::myProcNo()]
2222 // Send over how many faces/points I need to receive
2223 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2225 labelListList faceSendSizes(Pstream::nProcs());
2226 faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2227 forAll(faceSendMap, procI)
2229 faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size();
2231 Pstream::gatherList(faceSendSizes);
2232 Pstream::scatterList(faceSendSizes);
2236 // Exchange surfaces
2237 // ~~~~~~~~~~~~~~~~~
2239 // Storage for resulting surface
2240 List<labelledTri> allTris;
2241 pointField allPoints;
2243 labelListList faceConstructMap(Pstream::nProcs());
2244 labelListList pointConstructMap(Pstream::nProcs());
2247 // My own surface first
2248 // ~~~~~~~~~~~~~~~~~~~~
2252 triSurface subSurface
2257 faceSendMap[Pstream::myProcNo()],
2262 allTris = subSurface;
2263 allPoints = subSurface.points();
2265 faceConstructMap[Pstream::myProcNo()] = identity
2267 faceSendMap[Pstream::myProcNo()].size()
2269 pointConstructMap[Pstream::myProcNo()] = identity
2271 pointSendMap[Pstream::myProcNo()].size()
2280 forAll(faceSendSizes, procI)
2282 if (procI != Pstream::myProcNo())
2284 if (faceSendSizes[Pstream::myProcNo()][procI] > 0)
2286 OPstream str(Pstream::blocking, procI);
2289 triSurface subSurface
2301 // Pout<< "Sending to " << procI
2302 // << " faces:" << faceSendMap[procI].size()
2303 // << " points:" << subSurface.points().size() << endl
2313 // Receive and merge all
2314 // ~~~~~~~~~~~~~~~~~~~~~
2316 forAll(faceSendSizes, procI)
2318 if (procI != Pstream::myProcNo())
2320 if (faceSendSizes[procI][Pstream::myProcNo()] > 0)
2322 IPstream str(Pstream::blocking, procI);
2325 triSurface subSurface(str);
2329 // Pout<< "Received from " << procI
2330 // << " faces:" << subSurface.size()
2331 // << " points:" << subSurface.points().size() << endl
2335 // Merge into allSurf
2340 subSurface.points(),
2344 faceConstructMap[procI],
2345 pointConstructMap[procI]
2350 // Pout<< "Current merged surface : faces:" << allTris.size()
2351 // << " points:" << allPoints.size() << endl << endl;
2379 // Construct triSurface. Reuse storage.
2380 triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2384 // Regions stays same
2385 // Volume type stays same.
2387 distributeFields<label>(faceMap());
2388 distributeFields<scalar>(faceMap());
2389 distributeFields<vector>(faceMap());
2390 distributeFields<sphericalTensor>(faceMap());
2391 distributeFields<symmTensor>(faceMap());
2392 distributeFields<tensor>(faceMap());
2396 labelList nTris(Pstream::nProcs());
2397 nTris[Pstream::myProcNo()] = triSurface::size();
2398 Pstream::gatherList(nTris);
2399 Pstream::scatterList(nTris);
2401 Info<< "distributedTriSurfaceMesh::distribute : after distribution:"
2403 << "\tproc\ttris" << endl;
2405 forAll(nTris, procI)
2407 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2414 //- Write using given format, version and compression
2415 bool Foam::distributedTriSurfaceMesh::writeObject
2417 IOstream::streamFormat fmt,
2418 IOstream::versionNumber ver,
2419 IOstream::compressionType cmp
2422 // Make sure dictionary goes to same directory as surface
2423 const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2425 // Dictionary needs to be written in ascii - binary output not supported.
2427 triSurfaceMesh::writeObject(fmt, ver, cmp)
2428 && dict_.writeObject(IOstream::ASCII, ver, cmp);
2432 void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
2436 calcBounds(bb, nPoints);
2437 reduce(bb.min(), minOp<point>());
2438 reduce(bb.max(), maxOp<point>());
2440 os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2442 << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2443 << "Bounding Box : " << bb << endl;
2447 // ************************************************************************* //