1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
46 addToRunTimeSelectionTable(searchableSurface, distributedTriSurfaceMesh, dict);
53 Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>::names[] =
60 const Foam::NamedEnum<Foam::distributedTriSurfaceMesh::distributionType, 3>
61 Foam::distributedTriSurfaceMesh::distributionTypeNames_;
64 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66 // Read my additional data from the dictionary
67 bool Foam::distributedTriSurfaceMesh::read()
69 // Get bb of all domains.
70 procBb_.setSize(Pstream::nProcs());
72 procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
73 Pstream::gatherList(procBb_);
74 Pstream::scatterList(procBb_);
77 distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
80 mergeDist_ = readScalar(dict_.lookup("mergeDistance"));
86 // Is segment fully local?
87 bool Foam::distributedTriSurfaceMesh::isLocal
89 const List<treeBoundBox>& myBbs,
96 if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
105 //void Foam::distributedTriSurfaceMesh::splitSegment
107 // const label segmentI,
108 // const point& start,
110 // const treeBoundBox& bb,
112 // DynamicList<segment>& allSegments,
113 // DynamicList<label>& allSegmentMap,
114 // DynamicList<label> sendMap
118 // point clipPt0, clipPt1;
120 // if (bb.contains(start))
122 // // start within, trim end to bb
123 // bool clipped = bb.intersects(end, start, clipPt0);
127 // // segment from start to clippedStart passes
129 // sendMap[procI].append(allSegments.size());
130 // allSegmentMap.append(segmentI);
131 // allSegments.append(segment(start, clipPt0));
134 // else if (bb.contains(end))
136 // // end within, trim start to bb
137 // bool clipped = bb.intersects(start, end, clipPt0);
141 // sendMap[procI].append(allSegments.size());
142 // allSegmentMap.append(segmentI);
143 // allSegments.append(segment(clipPt0, end));
149 // bool clippedStart = bb.intersects(start, end, clipPt0);
153 // bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
157 // // middle part of segment passes through proc.
158 // sendMap[procI].append(allSegments.size());
159 // allSegmentMap.append(segmentI);
160 // allSegments.append(segment(clipPt0, clipPt1));
167 void Foam::distributedTriSurfaceMesh::distributeSegment
169 const label segmentI,
173 DynamicList<segment>& allSegments,
174 DynamicList<label>& allSegmentMap,
175 List<DynamicList<label> >& sendMap
182 // 1. Fully local already handled outside. Note: retest is cheap.
183 if (isLocal(procBb_[Pstream::myProcNo()], start, end))
189 // 2. If fully inside one other processor, then only need to send
190 // to that one processor even if it intersects another. Rare occurrence
191 // but cheap to test.
192 forAll(procBb_, procI)
194 if (procI != Pstream::myProcNo())
196 const List<treeBoundBox>& bbs = procBb_[procI];
198 if (isLocal(bbs, start, end))
200 sendMap[procI].append(allSegments.size());
201 allSegmentMap.append(segmentI);
202 allSegments.append(segment(start, end));
209 // 3. If not contained in single processor send to all intersecting
211 forAll(procBb_, procI)
213 const List<treeBoundBox>& bbs = procBb_[procI];
217 const treeBoundBox& bb = bbs[bbI];
219 // Scheme a: any processor that intersects the segment gets
222 if (bb.intersects(start, end, clipPt))
224 sendMap[procI].append(allSegments.size());
225 allSegmentMap.append(segmentI);
226 allSegments.append(segment(start, end));
229 // Alternative: any processor only gets clipped bit of
230 // segment. This gives small problems with additional
231 // truncation errors.
248 Foam::autoPtr<Foam::mapDistribute>
249 Foam::distributedTriSurfaceMesh::distributeSegments
251 const pointField& start,
252 const pointField& end,
254 List<segment>& allSegments,
255 labelList& allSegmentMap
258 // Determine send map
259 // ~~~~~~~~~~~~~~~~~~
261 labelListList sendMap(Pstream::nProcs());
264 // Since intersection test is quite expensive compared to memory
265 // allocation we use DynamicList to immediately store the segment
266 // in the correct bin.
269 DynamicList<segment> dynAllSegments(start.size());
270 // Original index of segment
271 DynamicList<label> dynAllSegmentMap(start.size());
272 // Per processor indices into allSegments to send
273 List<DynamicList<label> > dynSendMap(Pstream::nProcs());
275 forAll(start, segmentI)
289 // Convert dynamicList to labelList
290 sendMap.setSize(Pstream::nProcs());
291 forAll(sendMap, procI)
293 dynSendMap[procI].shrink();
294 sendMap[procI].transfer(dynSendMap[procI]);
297 allSegments.transfer(dynAllSegments.shrink());
298 allSegmentMap.transfer(dynAllSegmentMap.shrink());
302 // Send over how many I need to receive.
303 labelListList sendSizes(Pstream::nProcs());
304 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
305 forAll(sendMap, procI)
307 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
309 Pstream::gatherList(sendSizes);
310 Pstream::scatterList(sendSizes);
313 // Determine order of receiving
314 labelListList constructMap(Pstream::nProcs());
316 // My local segments first
317 constructMap[Pstream::myProcNo()] = identity
319 sendMap[Pstream::myProcNo()].size()
322 label segmentI = constructMap[Pstream::myProcNo()].size();
323 forAll(constructMap, procI)
325 if (procI != Pstream::myProcNo())
327 // What I need to receive is what other processor is sending to me.
328 label nRecv = sendSizes[procI][Pstream::myProcNo()];
329 constructMap[procI].setSize(nRecv);
331 for (label i = 0; i < nRecv; i++)
333 constructMap[procI][i] = segmentI++;
338 return autoPtr<mapDistribute>
342 segmentI, // size after construction
345 true // reuse storage
351 void Foam::distributedTriSurfaceMesh::findLine
353 const bool nearestIntersection,
354 const pointField& start,
355 const pointField& end,
356 List<pointIndexHit>& info
359 const indexedOctree<treeDataTriSurface>& octree = tree();
361 // Important:force synchronised construction of indexing
362 const globalIndex& triIndexer = globalTris();
365 info.setSize(start.size());
372 // Do any local queries
373 // ~~~~~~~~~~~~~~~~~~~~
379 if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
381 if (nearestIntersection)
383 info[i] = octree.findLine(start[i], end[i]);
387 info[i] = octree.findLineAny(start[i], end[i]);
392 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
403 returnReduce(nLocal, sumOp<label>())
404 < returnReduce(start.size(), sumOp<label>())
408 // Not all can be resolved locally. Build segments and map, send over
409 // segments, do intersections, send back and merge.
412 // Construct queries (segments)
413 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416 List<segment> allSegments(start.size());
417 // Original index of segment
418 labelList allSegmentMap(start.size());
420 const autoPtr<mapDistribute> mapPtr
430 const mapDistribute& map = mapPtr();
432 label nOldAllSegments = allSegments.size();
435 // Exchange the segments
436 // ~~~~~~~~~~~~~~~~~~~~~
440 Pstream::nonBlocking, //Pstream::scheduled,
441 List<labelPair>(0), //map.schedule(),
443 map.subMap(), // what to send
444 map.constructMap(), // what to receive
449 // Do tests I need to do
450 // ~~~~~~~~~~~~~~~~~~~~~
453 List<pointIndexHit> intersections(allSegments.size());
455 forAll(allSegments, i)
457 if (nearestIntersection)
459 intersections[i] = octree.findLine
461 allSegments[i].first(),
462 allSegments[i].second()
467 intersections[i] = octree.findLineAny
469 allSegments[i].first(),
470 allSegments[i].second()
474 // Convert triangle index to global numbering
475 if (intersections[i].hit())
477 intersections[i].setIndex
479 triIndexer.toGlobal(intersections[i].index())
485 // Exchange the intersections (opposite to segments)
486 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
490 //Pstream::scheduled,
491 //map.schedule // Note reverse schedule
493 // map.constructMap(),
496 Pstream::nonBlocking,
499 map.constructMap(), // what to send
500 map.subMap(), // what to receive
508 forAll(intersections, i)
510 const pointIndexHit& allInfo = intersections[i];
511 label segmentI = allSegmentMap[i];
512 pointIndexHit& hitInfo = info[segmentI];
518 // No intersection yet so take this one
521 else if (nearestIntersection)
523 // Nearest intersection
526 magSqr(allInfo.hitPoint()-start[segmentI])
527 < magSqr(hitInfo.hitPoint()-start[segmentI])
539 // Exchanges indices to the processor they come from.
540 // - calculates exchange map
541 // - uses map to calculate local triangle index
542 Foam::autoPtr<Foam::mapDistribute>
543 Foam::distributedTriSurfaceMesh::calcLocalQueries
545 const List<pointIndexHit>& info,
546 labelList& triangleIndex
549 triangleIndex.setSize(info.size());
551 const globalIndex& triIndexer = globalTris();
554 // Determine send map
555 // ~~~~~~~~~~~~~~~~~~
557 // Since determining which processor the query should go to is
558 // cheap we do a multi-pass algorithm to save some memory temporarily.
561 labelList nSend(Pstream::nProcs(), 0);
567 label procI = triIndexer.whichProcID(info[i].index());
573 labelListList sendMap(Pstream::nProcs());
576 sendMap[procI].setSize(nSend[procI]);
585 label procI = triIndexer.whichProcID(info[i].index());
586 triangleIndex[i] = triIndexer.toLocal(procI, info[i].index());
587 sendMap[procI][nSend[procI]++] = i;
591 triangleIndex[i] = -1;
596 // Send over how many I need to receive
597 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
599 labelListList sendSizes(Pstream::nProcs());
600 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
601 forAll(sendMap, procI)
603 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
605 Pstream::gatherList(sendSizes);
606 Pstream::scatterList(sendSizes);
609 // Determine receive map
610 // ~~~~~~~~~~~~~~~~~~~~~
612 labelListList constructMap(Pstream::nProcs());
614 // My local segments first
615 constructMap[Pstream::myProcNo()] = identity
617 sendMap[Pstream::myProcNo()].size()
620 label segmentI = constructMap[Pstream::myProcNo()].size();
621 forAll(constructMap, procI)
623 if (procI != Pstream::myProcNo())
625 // What I need to receive is what other processor is sending to me.
626 label nRecv = sendSizes[procI][Pstream::myProcNo()];
627 constructMap[procI].setSize(nRecv);
629 for (label i = 0; i < nRecv; i++)
631 constructMap[procI][i] = segmentI++;
637 // Pack into distribution map
638 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
640 autoPtr<mapDistribute> mapPtr
644 segmentI, // size after construction
647 true // reuse storage
650 const mapDistribute& map = mapPtr();
658 //Pstream::scheduled,
660 Pstream::nonBlocking,
663 map.subMap(), // what to send
664 map.constructMap(), // what to receive
673 Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs
676 const scalar radiusSqr,
683 forAll(procBb_, procI)
685 const List<treeBoundBox>& bbs = procBb_[procI];
689 if (bbs[bbI].overlaps(centre, radiusSqr))
691 overlaps[procI] = true;
701 // Generate queries for parallel distance calculation
702 // - calculates exchange map
703 // - uses map to exchange points and radius
704 Foam::autoPtr<Foam::mapDistribute>
705 Foam::distributedTriSurfaceMesh::calcLocalQueries
707 const pointField& centres,
708 const scalarField& radiusSqr,
710 pointField& allCentres,
711 scalarField& allRadiusSqr,
712 labelList& allSegmentMap
718 labelListList sendMap(Pstream::nProcs());
722 DynamicList<point> dynAllCentres(centres.size());
723 DynamicList<scalar> dynAllRadiusSqr(centres.size());
724 // Original index of segment
725 DynamicList<label> dynAllSegmentMap(centres.size());
726 // Per processor indices into allSegments to send
727 List<DynamicList<label> > dynSendMap(Pstream::nProcs());
729 // Work array - whether processor bb overlaps the bounding sphere.
730 boolList procBbOverlaps(Pstream::nProcs());
732 forAll(centres, centreI)
734 // Find the processor this sample+radius overlaps.
742 forAll(procBbOverlaps, procI)
744 if (procI != Pstream::myProcNo() && procBbOverlaps[procI])
746 dynSendMap[procI].append(dynAllCentres.size());
747 dynAllSegmentMap.append(centreI);
748 dynAllCentres.append(centres[centreI]);
749 dynAllRadiusSqr.append(radiusSqr[centreI]);
754 // Convert dynamicList to labelList
755 sendMap.setSize(Pstream::nProcs());
756 forAll(sendMap, procI)
758 dynSendMap[procI].shrink();
759 sendMap[procI].transfer(dynSendMap[procI]);
762 allCentres.transfer(dynAllCentres.shrink());
763 allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
764 allSegmentMap.transfer(dynAllSegmentMap.shrink());
768 // Send over how many I need to receive.
769 labelListList sendSizes(Pstream::nProcs());
770 sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
771 forAll(sendMap, procI)
773 sendSizes[Pstream::myProcNo()][procI] = sendMap[procI].size();
775 Pstream::gatherList(sendSizes);
776 Pstream::scatterList(sendSizes);
779 // Determine order of receiving
780 labelListList constructMap(Pstream::nProcs());
782 // My local segments first
783 constructMap[Pstream::myProcNo()] = identity
785 sendMap[Pstream::myProcNo()].size()
788 label segmentI = constructMap[Pstream::myProcNo()].size();
789 forAll(constructMap, procI)
791 if (procI != Pstream::myProcNo())
793 // What I need to receive is what other processor is sending to me.
794 label nRecv = sendSizes[procI][Pstream::myProcNo()];
795 constructMap[procI].setSize(nRecv);
797 for (label i = 0; i < nRecv; i++)
799 constructMap[procI][i] = segmentI++;
804 autoPtr<mapDistribute> mapPtr
808 segmentI, // size after construction
811 true // reuse storage
818 // Find bounding boxes that guarantee a more or less uniform distribution
819 // of triangles. Decomposition in here is only used to get the bounding
820 // boxes, actual decomposition is done later on.
821 // Returns a per processor a list of bounding boxes that most accurately
822 // describe the shape. For now just a single bounding box per processor but
823 // optimisation might be to determine a better fitting shape.
824 Foam::List<Foam::List<Foam::treeBoundBox> >
825 Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
830 if (!decomposer_.valid())
832 // Use current decomposer.
833 // Note: or always use hierarchical?
834 IOdictionary decomposeDict
839 searchableSurface::time().system(),
840 searchableSurface::time(),
846 decomposer_ = decompositionMethod::New(decomposeDict);
848 if (!decomposer_().parallelAware())
852 "distributedTriSurfaceMesh::independentlyDistributedBbs"
853 "(const triSurface&)"
854 ) << "The decomposition method " << decomposer_().typeName
855 << " does not decompose in parallel."
856 << " Please choose one that does." << exit(FatalError);
860 // Do decomposition according to triangle centre
861 pointField triCentres(s.size());
864 triCentres[triI] = s[triI].centre(s.points());
867 // Do the actual decomposition
868 labelList distribution(decomposer_->decompose(triCentres));
870 // Find bounding box for all triangles on new distribution.
872 // Initialise to inverted box (VGREAT, -VGREAT)
873 List<List<treeBoundBox> > bbs(Pstream::nProcs());
876 bbs[procI].setSize(1);
877 //bbs[procI][0] = boundBox::invertedBox;
878 bbs[procI][0].min() = point( VGREAT, VGREAT, VGREAT);
879 bbs[procI][0].max() = point(-VGREAT, -VGREAT, -VGREAT);
884 point& bbMin = bbs[distribution[triI]][0].min();
885 point& bbMax = bbs[distribution[triI]][0].max();
887 const labelledTri& f = s[triI];
888 const point& p0 = s.points()[f[0]];
889 const point& p1 = s.points()[f[1]];
890 const point& p2 = s.points()[f[2]];
892 bbMin = min(bbMin, p0);
893 bbMin = min(bbMin, p1);
894 bbMin = min(bbMin, p2);
896 bbMax = max(bbMax, p0);
897 bbMax = max(bbMax, p1);
898 bbMax = max(bbMax, p2);
901 // Now combine for all processors and convert to correct format.
904 forAll(bbs[procI], i)
906 reduce(bbs[procI][i].min(), minOp<point>());
907 reduce(bbs[procI][i].max(), maxOp<point>());
914 void Foam::distributedTriSurfaceMesh::calcBounds
920 // Unfortunately nPoints constructs meshPoints() so do compact version
923 PackedList<1> pointIsUsed(points().size());
927 bb.min() = point(VGREAT, VGREAT, VGREAT);
928 bb.max() = point(-VGREAT, -VGREAT, -VGREAT);
930 const triSurface& s = static_cast<const triSurface&>(*this);
934 const labelledTri& f = s[triI];
938 label pointI = f[fp];
939 if (pointIsUsed.set(pointI, 1))
941 bb.min() = ::Foam::min(bb.min(), points()[pointI]);
942 bb.max() = ::Foam::max(bb.max(), points()[pointI]);
950 // Does any part of triangle overlap bb.
951 bool Foam::distributedTriSurfaceMesh::overlaps
953 const List<treeBoundBox>& bbs,
961 const treeBoundBox& bb = bbs[bbI];
963 boundBox triBb(p0, p0);
964 triBb.min() = min(triBb.min(), p1);
965 triBb.min() = min(triBb.min(), p2);
967 triBb.max() = max(triBb.max(), p1);
968 triBb.max() = max(triBb.max(), p2);
970 //- Exact test of triangle intersecting bb
972 // Quick rejection. If whole bounding box of tri is outside cubeBb then
973 // there will be no intersection.
974 if (bb.overlaps(triBb))
976 // Check if one or more triangle point inside
977 if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
979 // One or more points inside
983 // Now we have the difficult case: all points are outside but
984 // connecting edges might go through cube. Use fast intersection
986 bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
998 void Foam::distributedTriSurfaceMesh::subsetMeshMap
1000 const triSurface& s,
1001 const boolList& include,
1002 const label nIncluded,
1003 labelList& newToOldPoints,
1004 labelList& oldToNewPoints,
1005 labelList& newToOldFaces
1008 newToOldFaces.setSize(nIncluded);
1009 newToOldPoints.setSize(s.points().size());
1010 oldToNewPoints.setSize(s.points().size());
1011 oldToNewPoints = -1;
1016 forAll(include, oldFacei)
1018 if (include[oldFacei])
1020 // Store new faces compact
1021 newToOldFaces[faceI++] = oldFacei;
1023 // Renumber labels for triangle
1024 const labelledTri& tri = s[oldFacei];
1028 label oldPointI = tri[fp];
1030 if (oldToNewPoints[oldPointI] == -1)
1032 oldToNewPoints[oldPointI] = pointI;
1033 newToOldPoints[pointI++] = oldPointI;
1038 newToOldPoints.setSize(pointI);
1043 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1045 const triSurface& s,
1046 const labelList& newToOldPoints,
1047 const labelList& oldToNewPoints,
1048 const labelList& newToOldFaces
1052 pointField newPoints(newToOldPoints.size());
1053 forAll(newToOldPoints, i)
1055 newPoints[i] = s.points()[newToOldPoints[i]];
1058 List<labelledTri> newTriangles(newToOldFaces.size());
1060 forAll(newToOldFaces, i)
1062 // Get old vertex labels
1063 const labelledTri& tri = s[newToOldFaces[i]];
1065 newTriangles[i][0] = oldToNewPoints[tri[0]];
1066 newTriangles[i][1] = oldToNewPoints[tri[1]];
1067 newTriangles[i][2] = oldToNewPoints[tri[2]];
1068 newTriangles[i].region() = tri.region();
1072 return triSurface(newTriangles, s.patches(), newPoints, true);
1076 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1078 const triSurface& s,
1079 const boolList& include,
1080 labelList& newToOldPoints,
1081 labelList& newToOldFaces
1094 labelList oldToNewPoints;
1115 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1117 const triSurface& s,
1118 const labelList& newToOldFaces,
1119 labelList& newToOldPoints
1122 const boolList include
1124 createWithValues<boolList>
1133 newToOldPoints.setSize(s.points().size());
1134 labelList oldToNewPoints(s.points().size(), -1);
1138 forAll(include, oldFacei)
1140 if (include[oldFacei])
1142 // Renumber labels for triangle
1143 const labelledTri& tri = s[oldFacei];
1147 label oldPointI = tri[fp];
1149 if (oldToNewPoints[oldPointI] == -1)
1151 oldToNewPoints[oldPointI] = pointI;
1152 newToOldPoints[pointI++] = oldPointI;
1157 newToOldPoints.setSize(pointI);
1170 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
1172 const List<labelledTri>& allFaces,
1173 const labelListList& allPointFaces,
1174 const labelledTri& otherF
1177 // allFaces connected to otherF[0]
1178 const labelList& pFaces = allPointFaces[otherF[0]];
1182 const labelledTri& f = allFaces[pFaces[i]];
1184 if (f.region() == otherF.region())
1186 // Find index of otherF[0]
1187 label fp0 = findIndex(f, otherF[0]);
1188 // Check rest of triangle in same order
1189 label fp1 = f.fcIndex(fp0);
1190 label fp2 = f.fcIndex(fp1);
1192 if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1202 // Merge into allSurf.
1203 void Foam::distributedTriSurfaceMesh::merge
1205 const scalar mergeDist,
1206 const List<labelledTri>& subTris,
1207 const pointField& subPoints,
1209 List<labelledTri>& allTris,
1210 pointField& allPoints,
1212 labelList& faceConstructMap,
1213 labelList& pointConstructMap
1221 scalarField(subPoints.size(), mergeDist), // match distance
1226 label nOldAllPoints = allPoints.size();
1229 // Add all unmatched points
1230 // ~~~~~~~~~~~~~~~~~~~~~~~~
1232 label allPointI = nOldAllPoints;
1233 forAll(pointConstructMap, pointI)
1235 if (pointConstructMap[pointI] == -1)
1237 pointConstructMap[pointI] = allPointI++;
1241 if (allPointI > nOldAllPoints)
1243 allPoints.setSize(allPointI);
1245 forAll(pointConstructMap, pointI)
1247 if (pointConstructMap[pointI] >= nOldAllPoints)
1249 allPoints[pointConstructMap[pointI]] = subPoints[pointI];
1255 // To check whether triangles are same we use pointFaces.
1256 labelListList allPointFaces;
1257 invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1260 // Add all unmatched triangles
1261 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1263 label allTriI = allTris.size();
1264 allTris.setSize(allTriI + subTris.size());
1266 faceConstructMap.setSize(subTris.size());
1268 forAll(subTris, triI)
1270 const labelledTri& subTri = subTris[triI];
1272 // Get triangle in new numbering
1273 labelledTri mappedTri
1275 pointConstructMap[subTri[0]],
1276 pointConstructMap[subTri[1]],
1277 pointConstructMap[subTri[2]],
1282 // Check if all points were already in surface
1283 bool fullMatch = true;
1285 forAll(mappedTri, fp)
1287 if (mappedTri[fp] >= nOldAllPoints)
1296 // All three points are mapped to old points. See if same
1298 label i = findTriangle
1308 faceConstructMap[triI] = allTriI;
1309 allTris[allTriI] = mappedTri;
1314 faceConstructMap[triI] = i;
1320 faceConstructMap[triI] = allTriI;
1321 allTris[allTriI] = mappedTri;
1325 allTris.setSize(allTriI);
1329 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1331 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1334 const triSurface& s,
1335 const dictionary& dict
1338 triSurfaceMesh(io, s),
1343 searchableSurface::name() + "Dict",
1344 searchableSurface::instance(),
1345 searchableSurface::local(),
1346 searchableSurface::db(),
1347 searchableSurface::NO_READ,
1348 searchableSurface::writeOpt(),
1349 searchableSurface::registerObject()
1358 Info<< "Constructed from triSurface:" << endl;
1361 labelList nTris(Pstream::nProcs());
1362 nTris[Pstream::myProcNo()] = triSurface::size();
1363 Pstream::gatherList(nTris);
1364 Pstream::scatterList(nTris);
1366 Info<< endl<< "\tproc\ttris\tbb" << endl;
1367 forAll(nTris, procI)
1369 Info<< '\t' << procI << '\t' << nTris[procI]
1370 << '\t' << procBb_[procI] << endl;
1377 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
1379 //triSurfaceMesh(io),
1385 io.time().findInstance(io.local(), word::null),
1397 searchableSurface::name() + "Dict",
1398 searchableSurface::instance(),
1399 searchableSurface::local(),
1400 searchableSurface::db(),
1401 searchableSurface::readOpt(),
1402 searchableSurface::writeOpt(),
1403 searchableSurface::registerObject()
1411 Info<< "Read distributedTriSurface from " << io.objectPath()
1415 labelList nTris(Pstream::nProcs());
1416 nTris[Pstream::myProcNo()] = triSurface::size();
1417 Pstream::gatherList(nTris);
1418 Pstream::scatterList(nTris);
1420 Info<< endl<< "\tproc\ttris\tbb" << endl;
1421 forAll(nTris, procI)
1423 Info<< '\t' << procI << '\t' << nTris[procI]
1424 << '\t' << procBb_[procI] << endl;
1431 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1434 const dictionary& dict
1437 //triSurfaceMesh(io, dict),
1443 io.time().findInstance(io.local(), word::null),
1456 searchableSurface::name() + "Dict",
1457 searchableSurface::instance(),
1458 searchableSurface::local(),
1459 searchableSurface::db(),
1460 searchableSurface::readOpt(),
1461 searchableSurface::writeOpt(),
1462 searchableSurface::registerObject()
1470 Info<< "Read distributedTriSurface from " << io.objectPath()
1471 << " and dictionary:" << endl;
1474 labelList nTris(Pstream::nProcs());
1475 nTris[Pstream::myProcNo()] = triSurface::size();
1476 Pstream::gatherList(nTris);
1477 Pstream::scatterList(nTris);
1479 Info<< endl<< "\tproc\ttris\tbb" << endl;
1480 forAll(nTris, procI)
1482 Info<< '\t' << procI << '\t' << nTris[procI]
1483 << '\t' << procBb_[procI] << endl;
1490 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1492 Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh()
1498 void Foam::distributedTriSurfaceMesh::clearOut()
1500 globalTris_.clear();
1501 triSurfaceMesh::clearOut();
1505 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1507 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
1509 if (!globalTris_.valid())
1511 globalTris_.reset(new globalIndex(triSurface::size()));
1517 void Foam::distributedTriSurfaceMesh::findNearest
1519 const pointField& samples,
1520 const scalarField& nearestDistSqr,
1521 List<pointIndexHit>& info
1524 const indexedOctree<treeDataTriSurface>& octree = tree();
1526 // Important:force synchronised construction of indexing
1527 const globalIndex& triIndexer = globalTris();
1533 info.setSize(samples.size());
1541 // Do any local queries
1542 // ~~~~~~~~~~~~~~~~~~~~
1547 // Work array - whether processor bb overlaps the bounding sphere.
1548 boolList procBbOverlaps(Pstream::nProcs());
1552 // Find the processor this sample+radius overlaps.
1553 label nProcs = calcOverlappingProcs
1560 // Overlaps local processor?
1561 if (procBbOverlaps[Pstream::myProcNo()])
1563 info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1566 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1582 returnReduce(nLocal, sumOp<label>())
1583 < returnReduce(samples.size(), sumOp<label>())
1587 // Not all can be resolved locally. Build queries and map, send over
1588 // queries, do intersections, send back and merge.
1590 // Calculate queries and exchange map
1591 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1593 pointField allCentres;
1594 scalarField allRadiusSqr;
1595 labelList allSegmentMap;
1596 autoPtr<mapDistribute> mapPtr
1608 const mapDistribute& map = mapPtr();
1611 // swap samples to local processor
1612 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1616 //Pstream::scheduled,
1618 Pstream::nonBlocking,
1620 map.constructSize(),
1621 map.subMap(), // what to send
1622 map.constructMap(), // what to receive
1627 //Pstream::scheduled,
1629 Pstream::nonBlocking,
1631 map.constructSize(),
1632 map.subMap(), // what to send
1633 map.constructMap(), // what to receive
1641 List<pointIndexHit> allInfo(allCentres.size());
1644 allInfo[i] = octree.findNearest
1649 if (allInfo[i].hit())
1651 allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1656 // Send back results
1657 // ~~~~~~~~~~~~~~~~~
1661 //Pstream::scheduled,
1662 //map.schedule // note reverse schedule
1664 // map.constructMap(),
1667 Pstream::nonBlocking,
1669 allSegmentMap.size(),
1670 map.constructMap(), // what to send
1671 map.subMap(), // what to receive
1676 // Extract information
1677 // ~~~~~~~~~~~~~~~~~~~
1681 if (allInfo[i].hit())
1683 label pointI = allSegmentMap[i];
1685 if (!info[pointI].hit())
1687 // No intersection yet so take this one
1688 info[pointI] = allInfo[i];
1692 // Nearest intersection
1695 magSqr(allInfo[i].hitPoint()-samples[pointI])
1696 < magSqr(info[pointI].hitPoint()-samples[pointI])
1699 info[pointI] = allInfo[i];
1708 void Foam::distributedTriSurfaceMesh::findLine
1710 const pointField& start,
1711 const pointField& end,
1712 List<pointIndexHit>& info
1717 true, // nearestIntersection
1725 void Foam::distributedTriSurfaceMesh::findLineAny
1727 const pointField& start,
1728 const pointField& end,
1729 List<pointIndexHit>& info
1734 true, // nearestIntersection
1742 void Foam::distributedTriSurfaceMesh::findLineAll
1744 const pointField& start,
1745 const pointField& end,
1746 List<List<pointIndexHit> >& info
1749 // Reuse fineLine. We could modify all of findLine to do multiple
1750 // intersections but this would mean a lot of data transferred so
1751 // for now we just find nearest intersection and retest from that
1752 // intersection onwards.
1755 List<pointIndexHit> hitInfo(start.size());
1759 true, // nearestIntersection
1766 // To find all intersections we add a small vector to the last intersection
1767 // This is chosen such that
1768 // - it is significant (SMALL is smallest representative relative tolerance;
1769 // we need something bigger since we're doing calculations)
1770 // - if the start-end vector is zero we still progress
1771 const vectorField dirVec(end-start);
1772 const scalarField magSqrDirVec(magSqr(dirVec));
1773 const vectorField smallVec
1775 Foam::sqrt(SMALL)*dirVec
1776 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
1779 // Copy to input and compact any hits
1780 labelList pointMap(start.size());
1781 pointField e0(start.size());
1782 pointField e1(start.size());
1785 info.setSize(hitInfo.size());
1786 forAll(hitInfo, pointI)
1788 if (hitInfo[pointI].hit())
1790 info[pointI].setSize(1);
1791 info[pointI][0] = hitInfo[pointI];
1793 point pt = hitInfo[pointI].hitPoint() + smallVec[pointI];
1795 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1798 e1[compactI] = end[pointI];
1799 pointMap[compactI] = pointI;
1805 info[pointI].clear();
1809 e0.setSize(compactI);
1810 e1.setSize(compactI);
1811 pointMap.setSize(compactI);
1813 while (returnReduce(e0.size(), sumOp<label>()) > 0)
1817 true, // nearestIntersection
1828 if (hitInfo[i].hit())
1830 label pointI = pointMap[i];
1832 label sz = info[pointI].size();
1833 info[pointI].setSize(sz+1);
1834 info[pointI][sz] = hitInfo[i];
1836 point pt = hitInfo[i].hitPoint() + smallVec[pointI];
1838 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1841 e1[compactI] = end[pointI];
1842 pointMap[compactI] = pointI;
1849 e0.setSize(compactI);
1850 e1.setSize(compactI);
1851 pointMap.setSize(compactI);
1856 void Foam::distributedTriSurfaceMesh::getRegion
1858 const List<pointIndexHit>& info,
1862 if (!Pstream::parRun())
1864 region.setSize(info.size());
1869 region[i] = triSurface::operator[](info[i].index()).region();
1880 // Get query data (= local index of triangle)
1883 labelList triangleIndex(info.size());
1884 autoPtr<mapDistribute> mapPtr
1892 const mapDistribute& map = mapPtr();
1898 const triSurface& s = static_cast<const triSurface&>(*this);
1900 region.setSize(triangleIndex.size());
1902 forAll(triangleIndex, i)
1904 label triI = triangleIndex[i];
1905 region[i] = s[triI].region();
1909 // Send back results
1910 // ~~~~~~~~~~~~~~~~~
1914 //Pstream::scheduled,
1915 //map.schedule // note reverse schedule
1917 // map.constructMap(),
1920 Pstream::nonBlocking,
1923 map.constructMap(), // what to send
1924 map.subMap(), // what to receive
1930 void Foam::distributedTriSurfaceMesh::getNormal
1932 const List<pointIndexHit>& info,
1936 if (!Pstream::parRun())
1938 normal.setSize(info.size());
1944 normal[i] = faceNormals()[info[i].index()];
1949 normal[i] = vector::zero;
1956 // Get query data (= local index of triangle)
1959 labelList triangleIndex(info.size());
1960 autoPtr<mapDistribute> mapPtr
1968 const mapDistribute& map = mapPtr();
1974 const triSurface& s = static_cast<const triSurface&>(*this);
1976 normal.setSize(triangleIndex.size());
1978 forAll(triangleIndex, i)
1980 label triI = triangleIndex[i];
1981 normal[i] = s[triI].normal(s.points());
1982 normal[i] /= mag(normal[i]) + VSMALL;
1986 // Send back results
1987 // ~~~~~~~~~~~~~~~~~
1991 //Pstream::scheduled,
1992 //map.schedule // note reverse schedule
1994 // map.constructMap(),
1997 Pstream::nonBlocking,
2000 map.constructMap(), // what to send
2001 map.subMap(), // what to receive
2007 void Foam::distributedTriSurfaceMesh::getField
2009 const word& fieldName,
2010 const List<pointIndexHit>& info,
2014 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
2020 if (!Pstream::parRun())
2022 values.setSize(info.size());
2027 values[i] = fld[info[i].index()];
2034 // Get query data (= local index of triangle)
2037 labelList triangleIndex(info.size());
2038 autoPtr<mapDistribute> mapPtr
2046 const mapDistribute& map = mapPtr();
2052 values.setSize(triangleIndex.size());
2054 forAll(triangleIndex, i)
2056 label triI = triangleIndex[i];
2057 values[i] = fld[triI];
2061 // Send back results
2062 // ~~~~~~~~~~~~~~~~~
2066 Pstream::nonBlocking,
2069 map.constructMap(), // what to send
2070 map.subMap(), // what to receive
2076 void Foam::distributedTriSurfaceMesh::getVolumeType
2078 const pointField& points,
2079 List<volumeType>& volType
2084 "distributedTriSurfaceMesh::getVolumeType"
2085 "(const pointField&, List<volumeType>&) const"
2086 ) << "Volume type not supported for distributed surfaces."
2087 << exit(FatalError);
2091 // Subset the part of surface that is overlapping bb.
2092 Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
2094 const triSurface& s,
2095 const List<treeBoundBox>& bbs,
2097 labelList& subPointMap,
2098 labelList& subFaceMap
2101 // Determine what triangles to keep.
2102 boolList includedFace(s.size(), false);
2104 // Create a slightly larger bounding box.
2105 List<treeBoundBox> bbsX(bbs.size());
2106 const scalar eps = 1.0e-4;
2109 const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2110 const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2112 bbsX[i].min() = mid - halfSpan;
2113 bbsX[i].max() = mid + halfSpan;
2118 const labelledTri& f = s[triI];
2119 const point& p0 = s.points()[f[0]];
2120 const point& p1 = s.points()[f[1]];
2121 const point& p2 = s.points()[f[2]];
2123 if (overlaps(bbsX, p0, p1, p2))
2125 includedFace[triI] = true;
2129 return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2133 void Foam::distributedTriSurfaceMesh::distribute
2135 const List<treeBoundBox>& bbs,
2136 const bool keepNonLocal,
2137 autoPtr<mapDistribute>& faceMap,
2138 autoPtr<mapDistribute>& pointMap
2141 // Get bbs of all domains
2142 // ~~~~~~~~~~~~~~~~~~~~~~
2145 List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
2150 newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2153 newProcBb[Pstream::myProcNo()][i] = bbs[i];
2155 Pstream::gatherList(newProcBb);
2156 Pstream::scatterList(newProcBb);
2160 newProcBb = independentlyDistributedBbs(*this);
2168 FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
2169 << "Unsupported distribution type." << exit(FatalError);
2175 // Info<< "old bb:" << procBb_ << endl << endl;
2176 // Info<< "new bb:" << newProcBb << endl << endl;
2177 // Info<< "Same:" << (newProcBb == procBb_) << endl;
2180 if (newProcBb == procBb_)
2186 procBb_.transfer(newProcBb);
2187 dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2192 // Debug information
2195 labelList nTris(Pstream::nProcs());
2196 nTris[Pstream::myProcNo()] = triSurface::size();
2197 Pstream::gatherList(nTris);
2198 Pstream::scatterList(nTris);
2200 Info<< "distributedTriSurfaceMesh::distribute : before distribution:"
2202 << "\tproc\ttris" << endl;
2204 forAll(nTris, procI)
2206 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2212 // Use procBbs to determine which faces go where
2213 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2215 labelListList faceSendMap(Pstream::nProcs());
2216 labelListList pointSendMap(Pstream::nProcs());
2218 forAll(procBb_, procI)
2224 pointSendMap[procI],
2230 //Pout<< "Overlapping with proc " << procI
2231 // << " faces:" << faceSendMap[procI].size()
2232 // << " points:" << pointSendMap[procI].size() << endl << endl;
2238 // Include in faceSendMap/pointSendMap the triangles that are
2239 // not mapped to any processor so they stay local.
2241 const triSurface& s = static_cast<const triSurface&>(*this);
2243 boolList includedFace(s.size(), true);
2245 forAll(faceSendMap, procI)
2247 if (procI != Pstream::myProcNo())
2249 forAll(faceSendMap[procI], i)
2251 includedFace[faceSendMap[procI][i]] = false;
2256 // Combine includedFace (all triangles that are not on any neighbour)
2259 forAll(faceSendMap[Pstream::myProcNo()], i)
2261 includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2268 pointSendMap[Pstream::myProcNo()],
2269 faceSendMap[Pstream::myProcNo()]
2274 // Send over how many faces/points I need to receive
2275 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2277 labelListList faceSendSizes(Pstream::nProcs());
2278 faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2279 forAll(faceSendMap, procI)
2281 faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size();
2283 Pstream::gatherList(faceSendSizes);
2284 Pstream::scatterList(faceSendSizes);
2288 // Exchange surfaces
2289 // ~~~~~~~~~~~~~~~~~
2291 // Storage for resulting surface
2292 List<labelledTri> allTris;
2293 pointField allPoints;
2295 labelListList faceConstructMap(Pstream::nProcs());
2296 labelListList pointConstructMap(Pstream::nProcs());
2299 // My own surface first
2300 // ~~~~~~~~~~~~~~~~~~~~
2304 triSurface subSurface
2309 faceSendMap[Pstream::myProcNo()],
2314 allTris = subSurface;
2315 allPoints = subSurface.points();
2317 faceConstructMap[Pstream::myProcNo()] = identity
2319 faceSendMap[Pstream::myProcNo()].size()
2321 pointConstructMap[Pstream::myProcNo()] = identity
2323 pointSendMap[Pstream::myProcNo()].size()
2332 forAll(faceSendSizes, procI)
2334 if (procI != Pstream::myProcNo())
2336 if (faceSendSizes[Pstream::myProcNo()][procI] > 0)
2338 OPstream str(Pstream::blocking, procI);
2341 triSurface subSurface
2353 // Pout<< "Sending to " << procI
2354 // << " faces:" << faceSendMap[procI].size()
2355 // << " points:" << subSurface.points().size() << endl
2365 // Receive and merge all
2366 // ~~~~~~~~~~~~~~~~~~~~~
2368 forAll(faceSendSizes, procI)
2370 if (procI != Pstream::myProcNo())
2372 if (faceSendSizes[procI][Pstream::myProcNo()] > 0)
2374 IPstream str(Pstream::blocking, procI);
2377 triSurface subSurface(str);
2381 // Pout<< "Received from " << procI
2382 // << " faces:" << subSurface.size()
2383 // << " points:" << subSurface.points().size() << endl
2387 // Merge into allSurf
2392 subSurface.points(),
2396 faceConstructMap[procI],
2397 pointConstructMap[procI]
2402 // Pout<< "Current merged surface : faces:" << allTris.size()
2403 // << " points:" << allPoints.size() << endl << endl;
2431 // Construct triSurface. Reuse storage.
2432 triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2436 // Regions stays same
2437 // Volume type stays same.
2439 distributeFields<label>(faceMap());
2440 distributeFields<scalar>(faceMap());
2441 distributeFields<vector>(faceMap());
2442 distributeFields<sphericalTensor>(faceMap());
2443 distributeFields<symmTensor>(faceMap());
2444 distributeFields<tensor>(faceMap());
2448 labelList nTris(Pstream::nProcs());
2449 nTris[Pstream::myProcNo()] = triSurface::size();
2450 Pstream::gatherList(nTris);
2451 Pstream::scatterList(nTris);
2453 Info<< "distributedTriSurfaceMesh::distribute : after distribution:"
2455 << "\tproc\ttris" << endl;
2457 forAll(nTris, procI)
2459 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2466 //- Write using given format, version and compression
2467 bool Foam::distributedTriSurfaceMesh::writeObject
2469 IOstream::streamFormat fmt,
2470 IOstream::versionNumber ver,
2471 IOstream::compressionType cmp
2474 // Make sure dictionary goes to same directory as surface
2475 const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2477 // Dictionary needs to be written in ascii - binary output not supported.
2479 triSurfaceMesh::writeObject(fmt, ver, cmp)
2480 && dict_.writeObject(IOstream::ASCII, ver, cmp);
2484 void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
2488 calcBounds(bb, nPoints);
2489 reduce(bb.min(), minOp<point>());
2490 reduce(bb.max(), maxOp<point>());
2492 os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2494 << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2495 << "Bounding Box : " << bb << endl;
2499 // ************************************************************************* //