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),
1345 Info<< "Constructed from triSurface:" << endl;
1348 labelList nTris(Pstream::nProcs());
1349 nTris[Pstream::myProcNo()] = triSurface::size();
1350 Pstream::gatherList(nTris);
1351 Pstream::scatterList(nTris);
1353 Info<< endl<< "\tproc\ttris\tbb" << endl;
1354 forAll(nTris, procI)
1356 Info<< '\t' << procI << '\t' << nTris[procI]
1357 << '\t' << procBb_[procI] << endl;
1364 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh(const IOobject& io)
1366 //triSurfaceMesh(io),
1372 io.time().findInstance(io.local(), word::null),
1384 searchableSurface::name() + "Dict",
1385 searchableSurface::instance(),
1386 searchableSurface::local(),
1387 searchableSurface::db(),
1388 searchableSurface::readOpt(),
1389 searchableSurface::writeOpt(),
1390 searchableSurface::registerObject()
1398 Info<< "Read distributedTriSurface from " << io.objectPath()
1402 labelList nTris(Pstream::nProcs());
1403 nTris[Pstream::myProcNo()] = triSurface::size();
1404 Pstream::gatherList(nTris);
1405 Pstream::scatterList(nTris);
1407 Info<< endl<< "\tproc\ttris\tbb" << endl;
1408 forAll(nTris, procI)
1410 Info<< '\t' << procI << '\t' << nTris[procI]
1411 << '\t' << procBb_[procI] << endl;
1418 Foam::distributedTriSurfaceMesh::distributedTriSurfaceMesh
1421 const dictionary& dict
1424 //triSurfaceMesh(io, dict),
1430 io.time().findInstance(io.local(), word::null),
1443 searchableSurface::name() + "Dict",
1444 searchableSurface::instance(),
1445 searchableSurface::local(),
1446 searchableSurface::db(),
1447 searchableSurface::readOpt(),
1448 searchableSurface::writeOpt(),
1449 searchableSurface::registerObject()
1457 Info<< "Read distributedTriSurface from " << io.objectPath()
1458 << " and dictionary:" << endl;
1461 labelList nTris(Pstream::nProcs());
1462 nTris[Pstream::myProcNo()] = triSurface::size();
1463 Pstream::gatherList(nTris);
1464 Pstream::scatterList(nTris);
1466 Info<< endl<< "\tproc\ttris\tbb" << endl;
1467 forAll(nTris, procI)
1469 Info<< '\t' << procI << '\t' << nTris[procI]
1470 << '\t' << procBb_[procI] << endl;
1477 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1479 Foam::distributedTriSurfaceMesh::~distributedTriSurfaceMesh()
1485 void Foam::distributedTriSurfaceMesh::clearOut()
1487 globalTris_.clear();
1488 triSurfaceMesh::clearOut();
1492 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1494 const Foam::globalIndex& Foam::distributedTriSurfaceMesh::globalTris() const
1496 if (!globalTris_.valid())
1498 globalTris_.reset(new globalIndex(triSurface::size()));
1504 void Foam::distributedTriSurfaceMesh::findNearest
1506 const pointField& samples,
1507 const scalarField& nearestDistSqr,
1508 List<pointIndexHit>& info
1511 const indexedOctree<treeDataTriSurface>& octree = tree();
1513 // Important:force synchronised construction of indexing
1514 const globalIndex& triIndexer = globalTris();
1520 info.setSize(samples.size());
1528 // Do any local queries
1529 // ~~~~~~~~~~~~~~~~~~~~
1534 // Work array - whether processor bb overlaps the bounding sphere.
1535 boolList procBbOverlaps(Pstream::nProcs());
1539 // Find the processor this sample+radius overlaps.
1540 label nProcs = calcOverlappingProcs
1547 // Overlaps local processor?
1548 if (procBbOverlaps[Pstream::myProcNo()])
1550 info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1553 info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1569 returnReduce(nLocal, sumOp<label>())
1570 < returnReduce(samples.size(), sumOp<label>())
1574 // Not all can be resolved locally. Build queries and map, send over
1575 // queries, do intersections, send back and merge.
1577 // Calculate queries and exchange map
1578 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1580 pointField allCentres;
1581 scalarField allRadiusSqr;
1582 labelList allSegmentMap;
1583 autoPtr<mapDistribute> mapPtr
1595 const mapDistribute& map = mapPtr();
1598 // swap samples to local processor
1599 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1603 //Pstream::scheduled,
1605 Pstream::nonBlocking,
1607 map.constructSize(),
1608 map.subMap(), // what to send
1609 map.constructMap(), // what to receive
1614 //Pstream::scheduled,
1616 Pstream::nonBlocking,
1618 map.constructSize(),
1619 map.subMap(), // what to send
1620 map.constructMap(), // what to receive
1628 List<pointIndexHit> allInfo(allCentres.size());
1631 allInfo[i] = octree.findNearest
1636 if (allInfo[i].hit())
1638 allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1643 // Send back results
1644 // ~~~~~~~~~~~~~~~~~
1648 //Pstream::scheduled,
1649 //map.schedule // note reverse schedule
1651 // map.constructMap(),
1654 Pstream::nonBlocking,
1656 allSegmentMap.size(),
1657 map.constructMap(), // what to send
1658 map.subMap(), // what to receive
1663 // Extract information
1664 // ~~~~~~~~~~~~~~~~~~~
1668 if (allInfo[i].hit())
1670 label pointI = allSegmentMap[i];
1672 if (!info[pointI].hit())
1674 // No intersection yet so take this one
1675 info[pointI] = allInfo[i];
1679 // Nearest intersection
1682 magSqr(allInfo[i].hitPoint()-samples[pointI])
1683 < magSqr(info[pointI].hitPoint()-samples[pointI])
1686 info[pointI] = allInfo[i];
1695 void Foam::distributedTriSurfaceMesh::findLine
1697 const pointField& start,
1698 const pointField& end,
1699 List<pointIndexHit>& info
1704 true, // nearestIntersection
1712 void Foam::distributedTriSurfaceMesh::findLineAny
1714 const pointField& start,
1715 const pointField& end,
1716 List<pointIndexHit>& info
1721 true, // nearestIntersection
1729 void Foam::distributedTriSurfaceMesh::findLineAll
1731 const pointField& start,
1732 const pointField& end,
1733 List<List<pointIndexHit> >& info
1736 // Reuse fineLine. We could modify all of findLine to do multiple
1737 // intersections but this would mean a lot of data transferred so
1738 // for now we just find nearest intersection and retest from that
1739 // intersection onwards.
1742 List<pointIndexHit> hitInfo(start.size());
1746 true, // nearestIntersection
1753 // To find all intersections we add a small vector to the last intersection
1754 // This is chosen such that
1755 // - it is significant (SMALL is smallest representative relative tolerance;
1756 // we need something bigger since we're doing calculations)
1757 // - if the start-end vector is zero we still progress
1758 const vectorField dirVec(end-start);
1759 const scalarField magSqrDirVec(magSqr(dirVec));
1760 const vectorField smallVec
1762 Foam::sqrt(SMALL)*dirVec
1763 + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
1766 // Copy to input and compact any hits
1767 labelList pointMap(start.size());
1768 pointField e0(start.size());
1769 pointField e1(start.size());
1772 info.setSize(hitInfo.size());
1773 forAll(hitInfo, pointI)
1775 if (hitInfo[pointI].hit())
1777 info[pointI].setSize(1);
1778 info[pointI][0] = hitInfo[pointI];
1780 point pt = hitInfo[pointI].hitPoint() + smallVec[pointI];
1782 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1785 e1[compactI] = end[pointI];
1786 pointMap[compactI] = pointI;
1792 info[pointI].clear();
1796 e0.setSize(compactI);
1797 e1.setSize(compactI);
1798 pointMap.setSize(compactI);
1800 while (returnReduce(e0.size(), sumOp<label>()) > 0)
1804 true, // nearestIntersection
1815 if (hitInfo[i].hit())
1817 label pointI = pointMap[i];
1819 label sz = info[pointI].size();
1820 info[pointI].setSize(sz+1);
1821 info[pointI][sz] = hitInfo[i];
1823 point pt = hitInfo[i].hitPoint() + smallVec[pointI];
1825 if (((pt-start[pointI])&dirVec[pointI]) <= magSqrDirVec[pointI])
1828 e1[compactI] = end[pointI];
1829 pointMap[compactI] = pointI;
1836 e0.setSize(compactI);
1837 e1.setSize(compactI);
1838 pointMap.setSize(compactI);
1843 void Foam::distributedTriSurfaceMesh::getRegion
1845 const List<pointIndexHit>& info,
1849 if (!Pstream::parRun())
1851 region.setSize(info.size());
1856 region[i] = triSurface::operator[](info[i].index()).region();
1867 // Get query data (= local index of triangle)
1870 labelList triangleIndex(info.size());
1871 autoPtr<mapDistribute> mapPtr
1879 const mapDistribute& map = mapPtr();
1885 const triSurface& s = static_cast<const triSurface&>(*this);
1887 region.setSize(triangleIndex.size());
1889 forAll(triangleIndex, i)
1891 label triI = triangleIndex[i];
1892 region[i] = s[triI].region();
1896 // Send back results
1897 // ~~~~~~~~~~~~~~~~~
1901 //Pstream::scheduled,
1902 //map.schedule // note reverse schedule
1904 // map.constructMap(),
1907 Pstream::nonBlocking,
1910 map.constructMap(), // what to send
1911 map.subMap(), // what to receive
1917 void Foam::distributedTriSurfaceMesh::getNormal
1919 const List<pointIndexHit>& info,
1923 if (!Pstream::parRun())
1925 normal.setSize(info.size());
1931 normal[i] = faceNormals()[info[i].index()];
1936 normal[i] = vector::zero;
1943 // Get query data (= local index of triangle)
1946 labelList triangleIndex(info.size());
1947 autoPtr<mapDistribute> mapPtr
1955 const mapDistribute& map = mapPtr();
1961 const triSurface& s = static_cast<const triSurface&>(*this);
1963 normal.setSize(triangleIndex.size());
1965 forAll(triangleIndex, i)
1967 label triI = triangleIndex[i];
1968 normal[i] = s[triI].normal(s.points());
1969 normal[i] /= mag(normal[i]) + VSMALL;
1973 // Send back results
1974 // ~~~~~~~~~~~~~~~~~
1978 //Pstream::scheduled,
1979 //map.schedule // note reverse schedule
1981 // map.constructMap(),
1984 Pstream::nonBlocking,
1987 map.constructMap(), // what to send
1988 map.subMap(), // what to receive
1994 void Foam::distributedTriSurfaceMesh::getField
1996 const word& fieldName,
1997 const List<pointIndexHit>& info,
2001 const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
2007 if (!Pstream::parRun())
2009 values.setSize(info.size());
2014 values[i] = fld[info[i].index()];
2021 // Get query data (= local index of triangle)
2024 labelList triangleIndex(info.size());
2025 autoPtr<mapDistribute> mapPtr
2033 const mapDistribute& map = mapPtr();
2039 values.setSize(triangleIndex.size());
2041 forAll(triangleIndex, i)
2043 label triI = triangleIndex[i];
2044 values[i] = fld[triI];
2048 // Send back results
2049 // ~~~~~~~~~~~~~~~~~
2053 Pstream::nonBlocking,
2056 map.constructMap(), // what to send
2057 map.subMap(), // what to receive
2063 void Foam::distributedTriSurfaceMesh::getVolumeType
2065 const pointField& points,
2066 List<volumeType>& volType
2071 "distributedTriSurfaceMesh::getVolumeType"
2072 "(const pointField&, List<volumeType>&) const"
2073 ) << "Volume type not supported for distributed surfaces."
2074 << exit(FatalError);
2078 // Subset the part of surface that is overlapping bb.
2079 Foam::triSurface Foam::distributedTriSurfaceMesh::overlappingSurface
2081 const triSurface& s,
2082 const List<treeBoundBox>& bbs,
2084 labelList& subPointMap,
2085 labelList& subFaceMap
2088 // Determine what triangles to keep.
2089 boolList includedFace(s.size(), false);
2091 // Create a slightly larger bounding box.
2092 List<treeBoundBox> bbsX(bbs.size());
2093 const scalar eps = 1.0e-4;
2096 const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2097 const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2099 bbsX[i].min() = mid - halfSpan;
2100 bbsX[i].max() = mid + halfSpan;
2105 const labelledTri& f = s[triI];
2106 const point& p0 = s.points()[f[0]];
2107 const point& p1 = s.points()[f[1]];
2108 const point& p2 = s.points()[f[2]];
2110 if (overlaps(bbsX, p0, p1, p2))
2112 includedFace[triI] = true;
2116 return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2120 void Foam::distributedTriSurfaceMesh::distribute
2122 const List<treeBoundBox>& bbs,
2123 const bool keepNonLocal,
2124 autoPtr<mapDistribute>& faceMap,
2125 autoPtr<mapDistribute>& pointMap
2128 // Get bbs of all domains
2129 // ~~~~~~~~~~~~~~~~~~~~~~
2132 List<List<treeBoundBox> > newProcBb(Pstream::nProcs());
2137 newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2140 newProcBb[Pstream::myProcNo()][i] = bbs[i];
2142 Pstream::gatherList(newProcBb);
2143 Pstream::scatterList(newProcBb);
2147 newProcBb = independentlyDistributedBbs(*this);
2155 FatalErrorIn("distributedTriSurfaceMesh::distribute(..)")
2156 << "Unsupported distribution type." << exit(FatalError);
2162 // Info<< "old bb:" << procBb_ << endl << endl;
2163 // Info<< "new bb:" << newProcBb << endl << endl;
2164 // Info<< "Same:" << (newProcBb == procBb_) << endl;
2167 if (newProcBb == procBb_)
2173 procBb_.transfer(newProcBb);
2174 dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2179 // Debug information
2182 labelList nTris(Pstream::nProcs());
2183 nTris[Pstream::myProcNo()] = triSurface::size();
2184 Pstream::gatherList(nTris);
2185 Pstream::scatterList(nTris);
2187 Info<< "distributedTriSurfaceMesh::distribute : before distribution:"
2189 << "\tproc\ttris" << endl;
2191 forAll(nTris, procI)
2193 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2199 // Use procBbs to determine which faces go where
2200 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2202 labelListList faceSendMap(Pstream::nProcs());
2203 labelListList pointSendMap(Pstream::nProcs());
2205 forAll(procBb_, procI)
2211 pointSendMap[procI],
2217 //Pout<< "Overlapping with proc " << procI
2218 // << " faces:" << faceSendMap[procI].size()
2219 // << " points:" << pointSendMap[procI].size() << endl << endl;
2225 // Include in faceSendMap/pointSendMap the triangles that are
2226 // not mapped to any processor so they stay local.
2228 const triSurface& s = static_cast<const triSurface&>(*this);
2230 boolList includedFace(s.size(), true);
2232 forAll(faceSendMap, procI)
2234 if (procI != Pstream::myProcNo())
2236 forAll(faceSendMap[procI], i)
2238 includedFace[faceSendMap[procI][i]] = false;
2243 // Combine includedFace (all triangles that are not on any neighbour)
2246 forAll(faceSendMap[Pstream::myProcNo()], i)
2248 includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2255 pointSendMap[Pstream::myProcNo()],
2256 faceSendMap[Pstream::myProcNo()]
2261 // Send over how many faces/points I need to receive
2262 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2264 labelListList faceSendSizes(Pstream::nProcs());
2265 faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2266 forAll(faceSendMap, procI)
2268 faceSendSizes[Pstream::myProcNo()][procI] = faceSendMap[procI].size();
2270 Pstream::gatherList(faceSendSizes);
2271 Pstream::scatterList(faceSendSizes);
2275 // Exchange surfaces
2276 // ~~~~~~~~~~~~~~~~~
2278 // Storage for resulting surface
2279 List<labelledTri> allTris;
2280 pointField allPoints;
2282 labelListList faceConstructMap(Pstream::nProcs());
2283 labelListList pointConstructMap(Pstream::nProcs());
2286 // My own surface first
2287 // ~~~~~~~~~~~~~~~~~~~~
2291 triSurface subSurface
2296 faceSendMap[Pstream::myProcNo()],
2301 allTris = subSurface;
2302 allPoints = subSurface.points();
2304 faceConstructMap[Pstream::myProcNo()] = identity
2306 faceSendMap[Pstream::myProcNo()].size()
2308 pointConstructMap[Pstream::myProcNo()] = identity
2310 pointSendMap[Pstream::myProcNo()].size()
2319 forAll(faceSendSizes, procI)
2321 if (procI != Pstream::myProcNo())
2323 if (faceSendSizes[Pstream::myProcNo()][procI] > 0)
2325 OPstream str(Pstream::blocking, procI);
2328 triSurface subSurface
2340 // Pout<< "Sending to " << procI
2341 // << " faces:" << faceSendMap[procI].size()
2342 // << " points:" << subSurface.points().size() << endl
2352 // Receive and merge all
2353 // ~~~~~~~~~~~~~~~~~~~~~
2355 forAll(faceSendSizes, procI)
2357 if (procI != Pstream::myProcNo())
2359 if (faceSendSizes[procI][Pstream::myProcNo()] > 0)
2361 IPstream str(Pstream::blocking, procI);
2364 triSurface subSurface(str);
2368 // Pout<< "Received from " << procI
2369 // << " faces:" << subSurface.size()
2370 // << " points:" << subSurface.points().size() << endl
2374 // Merge into allSurf
2379 subSurface.points(),
2383 faceConstructMap[procI],
2384 pointConstructMap[procI]
2389 // Pout<< "Current merged surface : faces:" << allTris.size()
2390 // << " points:" << allPoints.size() << endl << endl;
2418 // Construct triSurface. Reuse storage.
2419 triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2423 // Regions stays same
2424 // Volume type stays same.
2426 distributeFields<label>(faceMap());
2427 distributeFields<scalar>(faceMap());
2428 distributeFields<vector>(faceMap());
2429 distributeFields<sphericalTensor>(faceMap());
2430 distributeFields<symmTensor>(faceMap());
2431 distributeFields<tensor>(faceMap());
2435 labelList nTris(Pstream::nProcs());
2436 nTris[Pstream::myProcNo()] = triSurface::size();
2437 Pstream::gatherList(nTris);
2438 Pstream::scatterList(nTris);
2440 Info<< "distributedTriSurfaceMesh::distribute : after distribution:"
2442 << "\tproc\ttris" << endl;
2444 forAll(nTris, procI)
2446 Info<< '\t' << procI << '\t' << nTris[procI] << endl;
2453 //- Write using given format, version and compression
2454 bool Foam::distributedTriSurfaceMesh::writeObject
2456 IOstream::streamFormat fmt,
2457 IOstream::versionNumber ver,
2458 IOstream::compressionType cmp
2461 // Make sure dictionary goes to same directory as surface
2462 const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2464 // Dictionary needs to be written in ascii - binary output not supported.
2466 triSurfaceMesh::writeObject(fmt, ver, cmp)
2467 && dict_.writeObject(IOstream::ASCII, ver, cmp);
2471 void Foam::distributedTriSurfaceMesh::writeStats(Ostream& os) const
2475 calcBounds(bb, nPoints);
2476 reduce(bb.min(), minOp<point>());
2477 reduce(bb.max(), maxOp<point>());
2479 os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2481 << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2482 << "Bounding Box : " << bb << endl;
2486 // ************************************************************************* //