distributedTriSurfaceMesh.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "distributionMap.H"
28 #include "Random.H"
30 #include "triangleFuncs.H"
31 #include "matchPoints.H"
32 #include "globalIndex.H"
33 #include "Time.H"
34 
35 #include "IFstream.H"
36 #include "decompositionMethod.H"
37 #include "geomDecomp.H"
38 #include "vectorList.H"
39 #include "PackedBoolList.H"
40 #include "PatchTools.H"
41 
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46  defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
48  (
49  searchableSurface,
50  distributedTriSurfaceMesh,
51  dict
52  );
53 
54  template<>
55  const char* Foam::NamedEnum
56  <
58  3
59  >::names[] =
60  {
61  "follow",
62  "independent",
63  "frozen"
64  };
65 }
66 
67 
70 
71 
72 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
73 
74 // Read my additional data from the dictionary
75 bool Foam::distributedTriSurfaceMesh::read()
76 {
77  // Get bb of all domains.
78  procBb_.setSize(Pstream::nProcs());
79 
80  procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
81  Pstream::gatherList(procBb_);
82  Pstream::scatterList(procBb_);
83 
84  // Distribution type
85  distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
86 
87  // Merge distance
88  mergeDist_ = dict_.lookup<scalar>("mergeDistance");
89 
90  return true;
91 }
92 
93 
94 // Is segment fully local?
95 bool Foam::distributedTriSurfaceMesh::isLocal
96 (
97  const List<treeBoundBox>& myBbs,
98  const point& start,
99  const point& end
100 )
101 {
102  forAll(myBbs, bbI)
103  {
104  if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
105  {
106  return true;
107  }
108  }
109  return false;
110 }
111 
112 
113 //void Foam::distributedTriSurfaceMesh::splitSegment
114 //(
115 // const label segmentI,
116 // const point& start,
117 // const point& end,
118 // const treeBoundBox& bb,
119 //
120 // DynamicList<segment>& allSegments,
121 // DynamicList<label>& allSegmentMap,
122 // DynamicList<label> sendMap
123 //) const
124 //{
125 // // Work points
126 // point clipPt0, clipPt1;
127 //
128 // if (bb.contains(start))
129 // {
130 // // start within, trim end to bb
131 // bool clipped = bb.intersects(end, start, clipPt0);
132 //
133 // if (clipped)
134 // {
135 // // segment from start to clippedStart passes
136 // // through proc.
137 // sendMap[proci].append(allSegments.size());
138 // allSegmentMap.append(segmentI);
139 // allSegments.append(segment(start, clipPt0));
140 // }
141 // }
142 // else if (bb.contains(end))
143 // {
144 // // end within, trim start to bb
145 // bool clipped = bb.intersects(start, end, clipPt0);
146 //
147 // if (clipped)
148 // {
149 // sendMap[proci].append(allSegments.size());
150 // allSegmentMap.append(segmentI);
151 // allSegments.append(segment(clipPt0, end));
152 // }
153 // }
154 // else
155 // {
156 // // trim both
157 // bool clippedStart = bb.intersects(start, end, clipPt0);
158 //
159 // if (clippedStart)
160 // {
161 // bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
162 //
163 // if (clippedEnd)
164 // {
165 // // middle part of segment passes through proc.
166 // sendMap[proci].append(allSegments.size());
167 // allSegmentMap.append(segmentI);
168 // allSegments.append(segment(clipPt0, clipPt1));
169 // }
170 // }
171 // }
172 //}
173 
174 
175 void Foam::distributedTriSurfaceMesh::distributeSegment
176 (
177  const label segmentI,
178  const point& start,
179  const point& end,
180 
181  DynamicList<segment>& allSegments,
182  DynamicList<label>& allSegmentMap,
183  List<DynamicList<label>>& sendMap
184 ) const
185 {
186  // 1. Fully local already handled outside. Note: retest is cheap.
187  if (isLocal(procBb_[Pstream::myProcNo()], start, end))
188  {
189  return;
190  }
191 
192 
193  // 2. If fully inside one other processor, then only need to send
194  // to that one processor even if it intersects another. Rare occurrence
195  // but cheap to test.
196  forAll(procBb_, proci)
197  {
198  if (proci != Pstream::myProcNo())
199  {
200  const List<treeBoundBox>& bbs = procBb_[proci];
201 
202  if (isLocal(bbs, start, end))
203  {
204  sendMap[proci].append(allSegments.size());
205  allSegmentMap.append(segmentI);
206  allSegments.append(segment(start, end));
207  return;
208  }
209  }
210  }
211 
212 
213  // 3. If not contained in single processor send to all intersecting
214  // processors.
215  forAll(procBb_, proci)
216  {
217  const List<treeBoundBox>& bbs = procBb_[proci];
218 
219  forAll(bbs, bbI)
220  {
221  const treeBoundBox& bb = bbs[bbI];
222 
223  // Scheme a: any processor that intersects the segment gets
224  // the segment.
225 
226  // Intersection point
227  point clipPt;
228 
229  if (bb.intersects(start, end, clipPt))
230  {
231  sendMap[proci].append(allSegments.size());
232  allSegmentMap.append(segmentI);
233  allSegments.append(segment(start, end));
234  }
235 
236  // Alternative: any processor only gets clipped bit of
237  // segment. This gives small problems with additional
238  // truncation errors.
239  // splitSegment
240  //(
241  // segmentI,
242  // start,
243  // end,
244  // bb,
245  //
246  // allSegments,
247  // allSegmentMap,
248  // sendMap[proci]
249  //);
250  }
251  }
252 }
253 
254 
256 Foam::distributedTriSurfaceMesh::distributeSegments
257 (
258  const pointField& start,
259  const pointField& end,
260 
261  List<segment>& allSegments,
262  labelList& allSegmentMap
263 ) const
264 {
265  // Determine send map
266  // ~~~~~~~~~~~~~~~~~~
267 
268  labelListList sendMap(Pstream::nProcs());
269 
270  {
271  // Since intersection test is quite expensive compared to memory
272  // allocation we use DynamicList to immediately store the segment
273  // in the correct bin.
274 
275  // Segments to test
276  DynamicList<segment> dynAllSegments(start.size());
277  // Original index of segment
278  DynamicList<label> dynAllSegmentMap(start.size());
279  // Per processor indices into allSegments to send
281 
282  forAll(start, segmentI)
283  {
284  distributeSegment
285  (
286  segmentI,
287  start[segmentI],
288  end[segmentI],
289 
290  dynAllSegments,
291  dynAllSegmentMap,
292  dynSendMap
293  );
294  }
295 
296  // Convert dynamicList to labelList
297  sendMap.setSize(Pstream::nProcs());
298  forAll(sendMap, proci)
299  {
300  dynSendMap[proci].shrink();
301  sendMap[proci].transfer(dynSendMap[proci]);
302  }
303 
304  allSegments.transfer(dynAllSegments.shrink());
305  allSegmentMap.transfer(dynAllSegmentMap.shrink());
306  }
307 
308 
309  // Send over how many I need to receive.
310  labelListList sendSizes(Pstream::nProcs());
311  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
312  forAll(sendMap, proci)
313  {
314  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
315  }
316  Pstream::gatherList(sendSizes);
317  Pstream::scatterList(sendSizes);
318 
319 
320  // Determine order of receiving
321  labelListList constructMap(Pstream::nProcs());
322 
323  // My local segments first
324  constructMap[Pstream::myProcNo()] = identity
325  (
326  sendMap[Pstream::myProcNo()].size()
327  );
328 
329  label segmentI = constructMap[Pstream::myProcNo()].size();
330  forAll(constructMap, proci)
331  {
332  if (proci != Pstream::myProcNo())
333  {
334  // What I need to receive is what other processor is sending to me.
335  label nRecv = sendSizes[proci][Pstream::myProcNo()];
336  constructMap[proci].setSize(nRecv);
337 
338  for (label i = 0; i < nRecv; i++)
339  {
340  constructMap[proci][i] = segmentI++;
341  }
342  }
343  }
344 
346  (
347  new distributionMap
348  (
349  segmentI, // size after construction
350  move(sendMap),
351  move(constructMap)
352  )
353  );
354 }
355 
356 
357 void Foam::distributedTriSurfaceMesh::findLine
358 (
359  const bool nearestIntersection,
360  const pointField& start,
361  const pointField& end,
362  List<pointIndexHit>& info
363 ) const
364 {
365  const indexedOctree<treeDataTriSurface>& octree = tree();
366 
367  // Initialise
368  info.setSize(start.size());
369  forAll(info, i)
370  {
371  info[i].setMiss();
372  }
373 
374  if (!Pstream::parRun())
375  {
376  forAll(start, i)
377  {
378  if (nearestIntersection)
379  {
380  info[i] = octree.findLine(start[i], end[i]);
381  }
382  else
383  {
384  info[i] = octree.findLineAny(start[i], end[i]);
385  }
386  }
387  }
388  else
389  {
390  // Important:force synchronised construction of indexing
391  const globalIndex& triIndexer = globalTris();
392 
393 
394  // Do any local queries
395  // ~~~~~~~~~~~~~~~~~~~~
396 
397  label nLocal = 0;
398 
399  forAll(start, i)
400  {
401  if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
402  {
403  if (nearestIntersection)
404  {
405  info[i] = octree.findLine(start[i], end[i]);
406  }
407  else
408  {
409  info[i] = octree.findLineAny(start[i], end[i]);
410  }
411 
412  if (info[i].hit())
413  {
414  info[i].setIndex(triIndexer.toGlobal(info[i].index()));
415  }
416  nLocal++;
417  }
418  }
419 
420 
421  if
422  (
423  returnReduce(nLocal, sumOp<label>())
424  < returnReduce(start.size(), sumOp<label>())
425  )
426  {
427  // Not all can be resolved locally. Build segments and map,
428  // send over segments, do intersections, send back and merge.
429 
430 
431  // Construct queries (segments)
432  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433 
434  // Segments to test
435  List<segment> allSegments(start.size());
436  // Original index of segment
437  labelList allSegmentMap(start.size());
438 
439  const autoPtr<distributionMap> mapPtr
440  (
441  distributeSegments
442  (
443  start,
444  end,
445  allSegments,
446  allSegmentMap
447  )
448  );
449  const distributionMap& map = mapPtr();
450 
451  label nOldAllSegments = allSegments.size();
452 
453 
454  // Exchange the segments
455  // ~~~~~~~~~~~~~~~~~~~~~
456 
457  map.distribute(allSegments);
458 
459 
460  // Do tests I need to do
461  // ~~~~~~~~~~~~~~~~~~~~~
462 
463  // Intersections
464  List<pointIndexHit> intersections(allSegments.size());
465 
466  forAll(allSegments, i)
467  {
468  if (nearestIntersection)
469  {
470  intersections[i] = octree.findLine
471  (
472  allSegments[i].first(),
473  allSegments[i].second()
474  );
475  }
476  else
477  {
478  intersections[i] = octree.findLineAny
479  (
480  allSegments[i].first(),
481  allSegments[i].second()
482  );
483  }
484 
485  // Convert triangle index to global numbering
486  if (intersections[i].hit())
487  {
488  intersections[i].setIndex
489  (
490  triIndexer.toGlobal(intersections[i].index())
491  );
492  }
493  }
494 
495 
496  // Exchange the intersections (opposite to segments)
497  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
498 
499  map.reverseDistribute(nOldAllSegments, intersections);
500 
501 
502  // Extract the hits
503  // ~~~~~~~~~~~~~~~~
504 
505  forAll(intersections, i)
506  {
507  const pointIndexHit& allInfo = intersections[i];
508  label segmentI = allSegmentMap[i];
509  pointIndexHit& hitInfo = info[segmentI];
510 
511  if (allInfo.hit())
512  {
513  if (!hitInfo.hit())
514  {
515  // No intersection yet so take this one
516  hitInfo = allInfo;
517  }
518  else if (nearestIntersection)
519  {
520  // Nearest intersection
521  if
522  (
523  magSqr(allInfo.hitPoint()-start[segmentI])
524  < magSqr(hitInfo.hitPoint()-start[segmentI])
525  )
526  {
527  hitInfo = allInfo;
528  }
529  }
530  }
531  }
532  }
533  }
534 }
535 
536 
537 // Exchanges indices to the processor they come from.
538 // - calculates exchange map
539 // - uses map to calculate local triangle index
541 Foam::distributedTriSurfaceMesh::calcLocalQueries
542 (
543  const List<pointIndexHit>& info,
544  labelList& triangleIndex
545 ) const
546 {
547  triangleIndex.setSize(info.size());
548 
549  const globalIndex& triIndexer = globalTris();
550 
551 
552  // Determine send map
553  // ~~~~~~~~~~~~~~~~~~
554 
555  // Since determining which processor the query should go to is
556  // cheap we do a multi-pass algorithm to save some memory temporarily.
557 
558  // 1. Count
559  labelList nSend(Pstream::nProcs(), 0);
560 
561  forAll(info, i)
562  {
563  if (info[i].hit())
564  {
565  label proci = triIndexer.whichProcID(info[i].index());
566  nSend[proci]++;
567  }
568  }
569 
570  // 2. Size sendMap
571  labelListList sendMap(Pstream::nProcs());
572  forAll(nSend, proci)
573  {
574  sendMap[proci].setSize(nSend[proci]);
575  nSend[proci] = 0;
576  }
577 
578  // 3. Fill sendMap
579  forAll(info, i)
580  {
581  if (info[i].hit())
582  {
583  label proci = triIndexer.whichProcID(info[i].index());
584  triangleIndex[i] = triIndexer.toLocal(proci, info[i].index());
585  sendMap[proci][nSend[proci]++] = i;
586  }
587  else
588  {
589  triangleIndex[i] = -1;
590  }
591  }
592 
593 
594  // Send over how many I need to receive
595  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
596 
597  labelListList sendSizes(Pstream::nProcs());
598  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
599  forAll(sendMap, proci)
600  {
601  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
602  }
603  Pstream::gatherList(sendSizes);
604  Pstream::scatterList(sendSizes);
605 
606 
607  // Determine receive map
608  // ~~~~~~~~~~~~~~~~~~~~~
609 
610  labelListList constructMap(Pstream::nProcs());
611 
612  // My local segments first
613  constructMap[Pstream::myProcNo()] = identity
614  (
615  sendMap[Pstream::myProcNo()].size()
616  );
617 
618  label segmentI = constructMap[Pstream::myProcNo()].size();
619  forAll(constructMap, proci)
620  {
621  if (proci != Pstream::myProcNo())
622  {
623  // What I need to receive is what other processor is sending to me.
624  label nRecv = sendSizes[proci][Pstream::myProcNo()];
625  constructMap[proci].setSize(nRecv);
626 
627  for (label i = 0; i < nRecv; i++)
628  {
629  constructMap[proci][i] = segmentI++;
630  }
631  }
632  }
633 
634 
635  // Pack into distribution map
636  // ~~~~~~~~~~~~~~~~~~~~~~~~~~
637 
639  (
640  new distributionMap
641  (
642  segmentI, // size after construction
643  move(sendMap),
644  move(constructMap)
645  )
646  );
647  const distributionMap& map = mapPtr();
648 
649 
650  // Send over queries
651  // ~~~~~~~~~~~~~~~~~
652 
653  map.distribute(triangleIndex);
654 
655 
656  return mapPtr;
657 }
658 
659 
660 Foam::label Foam::distributedTriSurfaceMesh::calcOverlappingProcs
661 (
662  const point& centre,
663  const scalar radiusSqr,
664  boolList& overlaps
665 ) const
666 {
667  overlaps = false;
668  label nOverlaps = 0;
669 
670  forAll(procBb_, proci)
671  {
672  const List<treeBoundBox>& bbs = procBb_[proci];
673 
674  forAll(bbs, bbI)
675  {
676  if (bbs[bbI].overlaps(centre, radiusSqr))
677  {
678  overlaps[proci] = true;
679  nOverlaps++;
680  break;
681  }
682  }
683  }
684  return nOverlaps;
685 }
686 
687 
688 // Generate queries for parallel distance calculation
689 // - calculates exchange map
690 // - uses map to exchange points and radius
692 Foam::distributedTriSurfaceMesh::calcLocalQueries
693 (
694  const pointField& centres,
695  const scalarField& radiusSqr,
696 
697  pointField& allCentres,
698  scalarField& allRadiusSqr,
699  labelList& allSegmentMap
700 ) const
701 {
702  // Determine queries
703  // ~~~~~~~~~~~~~~~~~
704 
705  labelListList sendMap(Pstream::nProcs());
706 
707  {
708  // Queries
709  DynamicList<point> dynAllCentres(centres.size());
710  DynamicList<scalar> dynAllRadiusSqr(centres.size());
711  // Original index of segment
712  DynamicList<label> dynAllSegmentMap(centres.size());
713  // Per processor indices into allSegments to send
715 
716  // Work array - whether processor bb overlaps the bounding sphere.
717  boolList procBbOverlaps(Pstream::nProcs());
718 
719  forAll(centres, centreI)
720  {
721  // Find the processor this sample+radius overlaps.
722  calcOverlappingProcs
723  (
724  centres[centreI],
725  radiusSqr[centreI],
726  procBbOverlaps
727  );
728 
729  forAll(procBbOverlaps, proci)
730  {
731  if (proci != Pstream::myProcNo() && procBbOverlaps[proci])
732  {
733  dynSendMap[proci].append(dynAllCentres.size());
734  dynAllSegmentMap.append(centreI);
735  dynAllCentres.append(centres[centreI]);
736  dynAllRadiusSqr.append(radiusSqr[centreI]);
737  }
738  }
739  }
740 
741  // Convert dynamicList to labelList
742  sendMap.setSize(Pstream::nProcs());
743  forAll(sendMap, proci)
744  {
745  dynSendMap[proci].shrink();
746  sendMap[proci].transfer(dynSendMap[proci]);
747  }
748 
749  allCentres.transfer(dynAllCentres.shrink());
750  allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
751  allSegmentMap.transfer(dynAllSegmentMap.shrink());
752  }
753 
754 
755  // Send over how many I need to receive.
756  labelListList sendSizes(Pstream::nProcs());
757  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
758  forAll(sendMap, proci)
759  {
760  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
761  }
762  Pstream::gatherList(sendSizes);
763  Pstream::scatterList(sendSizes);
764 
765 
766  // Determine order of receiving
767  labelListList constructMap(Pstream::nProcs());
768 
769  // My local segments first
770  constructMap[Pstream::myProcNo()] = identity
771  (
772  sendMap[Pstream::myProcNo()].size()
773  );
774 
775  label segmentI = constructMap[Pstream::myProcNo()].size();
776  forAll(constructMap, proci)
777  {
778  if (proci != Pstream::myProcNo())
779  {
780  // What I need to receive is what other processor is sending to me.
781  label nRecv = sendSizes[proci][Pstream::myProcNo()];
782  constructMap[proci].setSize(nRecv);
783 
784  for (label i = 0; i < nRecv; i++)
785  {
786  constructMap[proci][i] = segmentI++;
787  }
788  }
789  }
790 
792  (
793  new distributionMap
794  (
795  segmentI, // size after construction
796  move(sendMap),
797  move(constructMap)
798  )
799  );
800  return mapPtr;
801 }
802 
803 
804 // Find bounding boxes that guarantee a more or less uniform distribution
805 // of triangles. Decomposition in here is only used to get the bounding
806 // boxes, actual decomposition is done later on.
807 // Returns a per processor a list of bounding boxes that most accurately
808 // describe the shape. For now just a single bounding box per processor but
809 // optimisation might be to determine a better fitting shape.
811 Foam::distributedTriSurfaceMesh::independentlyDistributedBbs
812 (
813  const triSurface& s
814 )
815 {
816  if (!distributor_.valid())
817  {
818  // Use current distributor.
819  // Note: or always use hierarchical?
821  (
823  );
824 
825  if (!isA<geomDecomp>(distributor_()))
826  {
828  << "The decomposition method " << distributor_().typeName
829  << " is not a geometric decomposition method." << endl
830  << "Only geometric decomposition methods are currently"
831  << " supported."
832  << exit(FatalError);
833  }
834  }
835 
836  // Do decomposition according to triangle centre
837  pointField triCentres(s.size());
838  forAll(s, triI)
839  {
840  triCentres[triI] = s[triI].centre(s.points());
841  }
842 
843 
844  geomDecomp& distributor = refCast<geomDecomp>(distributor_());
845 
846  // Do the actual decomposition
847  labelList distribution(distributor.decompose(triCentres));
848 
849  // Find bounding box for all triangles on new distribution.
850 
851  // Initialise to inverted box (vGreat, -vGreat)
853  forAll(bbs, proci)
854  {
855  bbs[proci].setSize(1);
856  // bbs[proci][0] = boundBox::invertedBox;
857  bbs[proci][0].min() = point( vGreat, vGreat, vGreat);
858  bbs[proci][0].max() = point(-vGreat, -vGreat, -vGreat);
859  }
860 
861  forAll(s, triI)
862  {
863  point& bbMin = bbs[distribution[triI]][0].min();
864  point& bbMax = bbs[distribution[triI]][0].max();
865 
866  const triSurface::FaceType& f = s[triI];
867  forAll(f, fp)
868  {
869  const point& pt = s.points()[f[fp]];
870  bbMin = ::Foam::min(bbMin, pt);
871  bbMax = ::Foam::max(bbMax, pt);
872  }
873  }
874 
875  // Now combine for all processors and convert to correct format.
876  forAll(bbs, proci)
877  {
878  forAll(bbs[proci], i)
879  {
880  reduce(bbs[proci][i].min(), minOp<point>());
881  reduce(bbs[proci][i].max(), maxOp<point>());
882  }
883  }
884  return bbs;
885 }
886 
887 
888 // Does any part of triangle overlap bb.
889 bool Foam::distributedTriSurfaceMesh::overlaps
890 (
891  const List<treeBoundBox>& bbs,
892  const point& p0,
893  const point& p1,
894  const point& p2
895 )
896 {
897  forAll(bbs, bbI)
898  {
899  const treeBoundBox& bb = bbs[bbI];
900 
901  treeBoundBox triBb(p0, p0);
902  triBb.min() = min(triBb.min(), p1);
903  triBb.min() = min(triBb.min(), p2);
904 
905  triBb.max() = max(triBb.max(), p1);
906  triBb.max() = max(triBb.max(), p2);
907 
908  // Exact test of triangle intersecting bb
909 
910  // Quick rejection. If whole bounding box of tri is outside cubeBb then
911  // there will be no intersection.
912  if (bb.overlaps(triBb))
913  {
914  // Check if one or more triangle point inside
915  if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
916  {
917  // One or more points inside
918  return true;
919  }
920 
921  // Now we have the difficult case: all points are outside but
922  // connecting edges might go through cube. Use fast intersection
923  // of bounding box.
924  bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
925 
926  if (intersect)
927  {
928  return true;
929  }
930  }
931  }
932  return false;
933 }
934 
935 
936 void Foam::distributedTriSurfaceMesh::subsetMeshMap
937 (
938  const triSurface& s,
939  const boolList& include,
940  const label nIncluded,
941  labelList& newToOldPoints,
942  labelList& oldToNewPoints,
943  labelList& newToOldFaces
944 )
945 {
946  newToOldFaces.setSize(nIncluded);
947  newToOldPoints.setSize(s.points().size());
948  oldToNewPoints.setSize(s.points().size());
949  oldToNewPoints = -1;
950  {
951  label facei = 0;
952  label pointi = 0;
953 
954  forAll(include, oldFacei)
955  {
956  if (include[oldFacei])
957  {
958  // Store new faces compact
959  newToOldFaces[facei++] = oldFacei;
960 
961  // Renumber labels for face
962  const triSurface::FaceType& f = s[oldFacei];
963 
964  forAll(f, fp)
965  {
966  label oldPointi = f[fp];
967 
968  if (oldToNewPoints[oldPointi] == -1)
969  {
970  oldToNewPoints[oldPointi] = pointi;
971  newToOldPoints[pointi++] = oldPointi;
972  }
973  }
974  }
975  }
976  newToOldPoints.setSize(pointi);
977  }
978 }
979 
980 
981 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
982 (
983  const triSurface& s,
984  const labelList& newToOldPoints,
985  const labelList& oldToNewPoints,
986  const labelList& newToOldFaces
987 )
988 {
989  // Extract points
990  pointField newPoints(newToOldPoints.size());
991  forAll(newToOldPoints, i)
992  {
993  newPoints[i] = s.points()[newToOldPoints[i]];
994  }
995  // Extract faces
996  List<labelledTri> newTriangles(newToOldFaces.size());
997 
998  forAll(newToOldFaces, i)
999  {
1000  // Get old vertex labels
1001  const labelledTri& tri = s[newToOldFaces[i]];
1002 
1003  newTriangles[i][0] = oldToNewPoints[tri[0]];
1004  newTriangles[i][1] = oldToNewPoints[tri[1]];
1005  newTriangles[i][2] = oldToNewPoints[tri[2]];
1006  newTriangles[i].region() = tri.region();
1007  }
1008 
1009  // Reuse storage.
1010  return triSurface(newTriangles, s.patches(), newPoints, true);
1011 }
1012 
1013 
1014 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1015 (
1016  const triSurface& s,
1017  const boolList& include,
1018  labelList& newToOldPoints,
1019  labelList& newToOldFaces
1020 )
1021 {
1022  label n = 0;
1023 
1024  forAll(include, i)
1025  {
1026  if (include[i])
1027  {
1028  n++;
1029  }
1030  }
1031 
1032  labelList oldToNewPoints;
1033  subsetMeshMap
1034  (
1035  s,
1036  include,
1037  n,
1038  newToOldPoints,
1039  oldToNewPoints,
1040  newToOldFaces
1041  );
1042 
1043  return subsetMesh
1044  (
1045  s,
1046  newToOldPoints,
1047  oldToNewPoints,
1048  newToOldFaces
1049  );
1050 }
1051 
1052 
1053 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1054 (
1055  const triSurface& s,
1056  const labelList& newToOldFaces,
1057  labelList& newToOldPoints
1058 )
1059 {
1060  const boolList include
1061  (
1062  createWithValues<boolList>
1063  (
1064  s.size(),
1065  false,
1066  newToOldFaces,
1067  true
1068  )
1069  );
1070 
1071  newToOldPoints.setSize(s.points().size());
1072  labelList oldToNewPoints(s.points().size(), -1);
1073  {
1074  label pointi = 0;
1075 
1076  forAll(include, oldFacei)
1077  {
1078  if (include[oldFacei])
1079  {
1080  // Renumber labels for face
1081  const triSurface::FaceType& f = s[oldFacei];
1082 
1083  forAll(f, fp)
1084  {
1085  label oldPointi = f[fp];
1086 
1087  if (oldToNewPoints[oldPointi] == -1)
1088  {
1089  oldToNewPoints[oldPointi] = pointi;
1090  newToOldPoints[pointi++] = oldPointi;
1091  }
1092  }
1093  }
1094  }
1095  newToOldPoints.setSize(pointi);
1096  }
1097 
1098  return subsetMesh
1099  (
1100  s,
1101  newToOldPoints,
1102  oldToNewPoints,
1103  newToOldFaces
1104  );
1105 }
1106 
1107 
1108 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
1109 (
1110  const List<labelledTri>& allFaces,
1111  const labelListList& allPointFaces,
1112  const labelledTri& otherF
1113 )
1114 {
1115  // allFaces connected to otherF[0]
1116  const labelList& pFaces = allPointFaces[otherF[0]];
1117 
1118  forAll(pFaces, i)
1119  {
1120  const labelledTri& f = allFaces[pFaces[i]];
1121 
1122  if (f.region() == otherF.region())
1123  {
1124  // Find index of otherF[0]
1125  label fp0 = findIndex(f, otherF[0]);
1126  // Check rest of triangle in same order
1127  label fp1 = f.fcIndex(fp0);
1128  label fp2 = f.fcIndex(fp1);
1129 
1130  if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1131  {
1132  return pFaces[i];
1133  }
1134  }
1135  }
1136  return -1;
1137 }
1138 
1139 
1140 // Merge into allSurf.
1141 void Foam::distributedTriSurfaceMesh::merge
1142 (
1143  const scalar mergeDist,
1144  const List<labelledTri>& subTris,
1145  const pointField& subPoints,
1146 
1147  List<labelledTri>& allTris,
1148  pointField& allPoints,
1149 
1150  labelList& faceConstructMap,
1151  labelList& pointConstructMap
1152 )
1153 {
1154  labelList subToAll;
1155  matchPoints
1156  (
1157  subPoints,
1158  allPoints,
1159  scalarField(subPoints.size(), mergeDist), // match distance
1160  false, // verbose
1161  pointConstructMap
1162  );
1163 
1164  label nOldAllPoints = allPoints.size();
1165 
1166 
1167  // Add all unmatched points
1168  // ~~~~~~~~~~~~~~~~~~~~~~~~
1169 
1170  label allPointi = nOldAllPoints;
1171  forAll(pointConstructMap, pointi)
1172  {
1173  if (pointConstructMap[pointi] == -1)
1174  {
1175  pointConstructMap[pointi] = allPointi++;
1176  }
1177  }
1178 
1179  if (allPointi > nOldAllPoints)
1180  {
1181  allPoints.setSize(allPointi);
1182 
1183  forAll(pointConstructMap, pointi)
1184  {
1185  if (pointConstructMap[pointi] >= nOldAllPoints)
1186  {
1187  allPoints[pointConstructMap[pointi]] = subPoints[pointi];
1188  }
1189  }
1190  }
1191 
1192 
1193  // To check whether triangles are same we use pointFaces.
1194  labelListList allPointFaces;
1195  invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1196 
1197 
1198  // Add all unmatched triangles
1199  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1200 
1201  label allTriI = allTris.size();
1202  allTris.setSize(allTriI + subTris.size());
1203 
1204  faceConstructMap.setSize(subTris.size());
1205 
1206  forAll(subTris, triI)
1207  {
1208  const labelledTri& subTri = subTris[triI];
1209 
1210  // Get triangle in new numbering
1211  labelledTri mappedTri
1212  (
1213  pointConstructMap[subTri[0]],
1214  pointConstructMap[subTri[1]],
1215  pointConstructMap[subTri[2]],
1216  subTri.region()
1217  );
1218 
1219 
1220  // Check if all points were already in surface
1221  bool fullMatch = true;
1222 
1223  forAll(mappedTri, fp)
1224  {
1225  if (mappedTri[fp] >= nOldAllPoints)
1226  {
1227  fullMatch = false;
1228  break;
1229  }
1230  }
1231 
1232  if (fullMatch)
1233  {
1234  // All three points are mapped to old points. See if same
1235  // triangle.
1236  label i = findTriangle
1237  (
1238  allTris,
1239  allPointFaces,
1240  mappedTri
1241  );
1242 
1243  if (i == -1)
1244  {
1245  // Add
1246  faceConstructMap[triI] = allTriI;
1247  allTris[allTriI] = mappedTri;
1248  allTriI++;
1249  }
1250  else
1251  {
1252  faceConstructMap[triI] = i;
1253  }
1254  }
1255  else
1256  {
1257  // Add
1258  faceConstructMap[triI] = allTriI;
1259  allTris[allTriI] = mappedTri;
1260  allTriI++;
1261  }
1262  }
1263  allTris.setSize(allTriI);
1264 }
1265 
1266 
1267 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1268 
1271  const IOobject& io,
1272  const triSurface& s,
1273  const dictionary& dict
1274 )
1275 :
1276  triSurfaceMesh(io, s),
1277  dict_
1278  (
1279  IOobject
1280  (
1281  searchableSurface::name() + "Dict",
1288  ),
1289  dict
1290  )
1291 {
1292  read();
1293 
1294  reduce(bounds().min(), minOp<point>());
1295  reduce(bounds().max(), maxOp<point>());
1296 
1297  if (debug)
1298  {
1299  InfoInFunction << "Constructed from triSurface:" << endl;
1300  writeStats(Info);
1301 
1302  labelList nTris(Pstream::nProcs());
1303  nTris[Pstream::myProcNo()] = triSurface::size();
1304  Pstream::gatherList(nTris);
1305  Pstream::scatterList(nTris);
1306 
1307  Info<< endl<< "\tproc\ttris\tbb" << endl;
1308  forAll(nTris, proci)
1309  {
1310  Info<< '\t' << proci << '\t' << nTris[proci]
1311  << '\t' << procBb_[proci] << endl;
1312  }
1313  Info<< endl;
1314  }
1315 }
1316 
1317 
1319 :
1321  (
1322  IOobject
1323  (
1324  io.name(),
1325  io.time().findInstance(io.local(), word::null),
1326  io.local(),
1327  io.db(),
1328  io.readOpt(),
1329  io.writeOpt(),
1330  io.registerObject()
1331  ),
1332  false
1333  ),
1334  dict_
1335  (
1336  IOobject
1337  (
1338  searchableSurface::name() + "Dict",
1339  searchableSurface::instance(),
1340  searchableSurface::local(),
1341  searchableSurface::db(),
1342  searchableSurface::readOpt(),
1343  searchableSurface::writeOpt(),
1344  searchableSurface::registerObject()
1345  )
1346  )
1347 {
1348  if
1349  (
1350  Pstream::parRun()
1351  && (
1352  dict_.readOpt() == IOobject::MUST_READ
1354  )
1355  && (
1358  )
1359  )
1360  {
1362  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1363  << " Modify the entry fileModificationChecking\n"
1364  << " in the etc/controlDict.\n"
1365  << " Use 'timeStamp' instead."
1366  << exit(FatalError);
1367  }
1368 
1369  read();
1370 
1371  reduce(bounds().min(), minOp<point>());
1372  reduce(bounds().max(), maxOp<point>());
1373 
1374  if (debug)
1375  {
1376  InfoInFunction << "Read distributedTriSurface from "
1377  << searchableSurface::objectPath() << ':' << endl;
1378  writeStats(Info);
1379 
1380  labelList nTris(Pstream::nProcs());
1381  nTris[Pstream::myProcNo()] = triSurface::size();
1382  Pstream::gatherList(nTris);
1383  Pstream::scatterList(nTris);
1384 
1385  Info<< endl<< "\tproc\ttris\tbb" << endl;
1386  forAll(nTris, proci)
1387  {
1388  Info<< '\t' << proci << '\t' << nTris[proci]
1389  << '\t' << procBb_[proci] << endl;
1390  }
1391  Info<< endl;
1392  }
1393 }
1394 
1395 
1398  const IOobject& io,
1399  const dictionary& dict
1400 )
1401 :
1402  // triSurfaceMesh(io, dict),
1404  (
1405  IOobject
1406  (
1407  io.name(),
1408  io.time().findInstance(io.local(), word::null),
1409  io.local(),
1410  io.db(),
1411  io.readOpt(),
1412  io.writeOpt(),
1413  io.registerObject()
1414  ),
1415  dict,
1416  false
1417  ),
1418  dict_
1419  (
1420  IOobject
1421  (
1422  searchableSurface::name() + "Dict",
1429  )
1430  )
1431 {
1432  if
1433  (
1434  Pstream::parRun()
1435  && (
1436  dict_.readOpt() == IOobject::MUST_READ
1438  )
1439  && (
1442  )
1443  )
1444  {
1446  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1447  << " Modify the entry fileModificationChecking\n"
1448  << " in the etc/controlDict.\n"
1449  << " Use 'timeStamp' instead."
1450  << exit(FatalError);
1451  }
1452 
1453  read();
1454 
1455  reduce(bounds().min(), minOp<point>());
1456  reduce(bounds().max(), maxOp<point>());
1457 
1458  if (debug)
1459  {
1460  InfoInFunction << "Read distributedTriSurface from "
1461  << searchableSurface::objectPath() << " and dictionary:" << endl;
1462  writeStats(Info);
1463 
1464  labelList nTris(Pstream::nProcs());
1465  nTris[Pstream::myProcNo()] = triSurface::size();
1466  Pstream::gatherList(nTris);
1467  Pstream::scatterList(nTris);
1468 
1469  Info<< endl<< "\tproc\ttris\tbb" << endl;
1470  forAll(nTris, proci)
1471  {
1472  Info<< '\t' << proci << '\t' << nTris[proci]
1473  << '\t' << procBb_[proci] << endl;
1474  }
1475  Info<< endl;
1476  }
1477 }
1478 
1479 
1480 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1481 
1483 {
1484  clearOut();
1485 }
1486 
1487 
1489 {
1490  globalTris_.clear();
1492 }
1493 
1494 
1495 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1496 
1498 {
1499  if (!globalTris_.valid())
1500  {
1501  globalTris_.reset(new globalIndex(triSurface::size()));
1502  }
1503  return globalTris_;
1504 }
1505 
1506 
1509  const pointField& samples,
1510  const scalarField& nearestDistSqr,
1511  List<pointIndexHit>& info
1512 ) const
1513 {
1514  const indexedOctree<treeDataTriSurface>& octree = tree();
1515 
1516  // Important:force synchronised construction of indexing
1517  const globalIndex& triIndexer = globalTris();
1518 
1519 
1520  // Initialise
1521  // ~~~~~~~~~~
1522 
1523  info.setSize(samples.size());
1524  forAll(info, i)
1525  {
1526  info[i].setMiss();
1527  }
1528 
1529 
1530 
1531  // Do any local queries
1532  // ~~~~~~~~~~~~~~~~~~~~
1533 
1534  label nLocal = 0;
1535 
1536  {
1537  // Work array - whether processor bb overlaps the bounding sphere.
1538  boolList procBbOverlaps(Pstream::nProcs());
1539 
1540  forAll(samples, i)
1541  {
1542  // Find the processor this sample+radius overlaps.
1543  label nProcs = calcOverlappingProcs
1544  (
1545  samples[i],
1546  nearestDistSqr[i],
1547  procBbOverlaps
1548  );
1549 
1550  // Overlaps local processor?
1551  if (procBbOverlaps[Pstream::myProcNo()])
1552  {
1553  info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1554  if (info[i].hit())
1555  {
1556  info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1557  }
1558  if (nProcs == 1)
1559  {
1560  // Fully local
1561  nLocal++;
1562  }
1563  }
1564  }
1565  }
1566 
1567 
1568  if
1569  (
1570  Pstream::parRun()
1571  && (
1572  returnReduce(nLocal, sumOp<label>())
1573  < returnReduce(samples.size(), sumOp<label>())
1574  )
1575  )
1576  {
1577  // Not all can be resolved locally. Build queries and map, send over
1578  // queries, do intersections, send back and merge.
1579 
1580  // Calculate queries and exchange map
1581  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1582 
1583  pointField allCentres;
1584  scalarField allRadiusSqr;
1585  labelList allSegmentMap;
1587  (
1588  calcLocalQueries
1589  (
1590  samples,
1591  nearestDistSqr,
1592 
1593  allCentres,
1594  allRadiusSqr,
1595  allSegmentMap
1596  )
1597  );
1598  const distributionMap& map = mapPtr();
1599 
1600 
1601  // swap samples to local processor
1602  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1603 
1604  map.distribute(allCentres);
1605  map.distribute(allRadiusSqr);
1606 
1607 
1608  // Do my tests
1609  // ~~~~~~~~~~~
1610 
1611  List<pointIndexHit> allInfo(allCentres.size());
1612  forAll(allInfo, i)
1613  {
1614  allInfo[i] = octree.findNearest
1615  (
1616  allCentres[i],
1617  allRadiusSqr[i]
1618  );
1619  if (allInfo[i].hit())
1620  {
1621  allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1622  }
1623  }
1624 
1625 
1626  // Send back results
1627  // ~~~~~~~~~~~~~~~~~
1628 
1629  map.reverseDistribute(allSegmentMap.size(), allInfo);
1630 
1631 
1632  // Extract information
1633  // ~~~~~~~~~~~~~~~~~~~
1634 
1635  forAll(allInfo, i)
1636  {
1637  if (allInfo[i].hit())
1638  {
1639  label pointi = allSegmentMap[i];
1640 
1641  if (!info[pointi].hit())
1642  {
1643  // No intersection yet so take this one
1644  info[pointi] = allInfo[i];
1645  }
1646  else
1647  {
1648  // Nearest intersection
1649  if
1650  (
1651  magSqr(allInfo[i].hitPoint()-samples[pointi])
1652  < magSqr(info[pointi].hitPoint()-samples[pointi])
1653  )
1654  {
1655  info[pointi] = allInfo[i];
1656  }
1657  }
1658  }
1659  }
1660  }
1661 }
1662 
1663 
1664 void Foam::distributedTriSurfaceMesh::findLine
1666  const pointField& start,
1667  const pointField& end,
1668  List<pointIndexHit>& info
1669 ) const
1670 {
1671  findLine
1672  (
1673  true, // nearestIntersection
1674  start,
1675  end,
1676  info
1677  );
1678 }
1679 
1680 
1683  const pointField& start,
1684  const pointField& end,
1685  List<pointIndexHit>& info
1686 ) const
1687 {
1688  findLine
1689  (
1690  true, // nearestIntersection
1691  start,
1692  end,
1693  info
1694  );
1695 }
1696 
1697 
1700  const pointField& start,
1701  const pointField& end,
1702  List<List<pointIndexHit>>& info
1703 ) const
1704 {
1705  // Reuse fineLine. We could modify all of findLine to do multiple
1706  // intersections but this would mean a lot of data transferred so
1707  // for now we just find nearest intersection and retest from that
1708  // intersection onwards.
1709 
1710  // Work array.
1711  List<pointIndexHit> hitInfo(start.size());
1712 
1713  findLine
1714  (
1715  true, // nearestIntersection
1716  start,
1717  end,
1718  hitInfo
1719  );
1720 
1721  // Tolerances:
1722  // To find all intersections we add a small vector to the last intersection
1723  // This is chosen such that
1724  // - it is significant (small is smallest representative relative tolerance;
1725  // we need something bigger since we're doing calculations)
1726  // - if the start-end vector is zero we still progress
1727  const vectorField dirVec(end-start);
1728  const scalarField magSqrDirVec(magSqr(dirVec));
1729  const vectorField smallVec
1730  (
1731  rootSmall*dirVec
1732  + vector(rootVSmall,rootVSmall,rootVSmall)
1733  );
1734 
1735  // Copy to input and compact any hits
1736  labelList pointMap(start.size());
1737  pointField e0(start.size());
1738  pointField e1(start.size());
1739  label compactI = 0;
1740 
1741  info.setSize(hitInfo.size());
1742  forAll(hitInfo, pointi)
1743  {
1744  if (hitInfo[pointi].hit())
1745  {
1746  info[pointi].setSize(1);
1747  info[pointi][0] = hitInfo[pointi];
1748 
1749  point pt = hitInfo[pointi].hitPoint() + smallVec[pointi];
1750 
1751  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1752  {
1753  e0[compactI] = pt;
1754  e1[compactI] = end[pointi];
1755  pointMap[compactI] = pointi;
1756  compactI++;
1757  }
1758  }
1759  else
1760  {
1761  info[pointi].clear();
1762  }
1763  }
1764 
1765  e0.setSize(compactI);
1766  e1.setSize(compactI);
1767  pointMap.setSize(compactI);
1768 
1769  while (returnReduce(e0.size(), sumOp<label>()) > 0)
1770  {
1771  findLine
1772  (
1773  true, // nearestIntersection
1774  e0,
1775  e1,
1776  hitInfo
1777  );
1778 
1779 
1780  // Extract
1781  label compactI = 0;
1782  forAll(hitInfo, i)
1783  {
1784  if (hitInfo[i].hit())
1785  {
1786  label pointi = pointMap[i];
1787 
1788  label sz = info[pointi].size();
1789  info[pointi].setSize(sz+1);
1790  info[pointi][sz] = hitInfo[i];
1791 
1792  point pt = hitInfo[i].hitPoint() + smallVec[pointi];
1793 
1794  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1795  {
1796  e0[compactI] = pt;
1797  e1[compactI] = end[pointi];
1798  pointMap[compactI] = pointi;
1799  compactI++;
1800  }
1801  }
1802  }
1803 
1804  // Trim
1805  e0.setSize(compactI);
1806  e1.setSize(compactI);
1807  pointMap.setSize(compactI);
1808  }
1809 }
1810 
1811 
1814  const List<pointIndexHit>& info,
1815  labelList& region
1816 ) const
1817 {
1818  if (!Pstream::parRun())
1819  {
1820  region.setSize(info.size());
1821  forAll(info, i)
1822  {
1823  if (info[i].hit())
1824  {
1825  region[i] = triSurface::operator[](info[i].index()).region();
1826  }
1827  else
1828  {
1829  region[i] = -1;
1830  }
1831  }
1832  return;
1833  }
1834 
1835 
1836  // Get query data (= local index of triangle)
1837  // ~~~~~~~~~~~~~~
1838 
1839  labelList triangleIndex(info.size());
1841  (
1842  calcLocalQueries
1843  (
1844  info,
1845  triangleIndex
1846  )
1847  );
1848  const distributionMap& map = mapPtr();
1849 
1850 
1851  // Do my tests
1852  // ~~~~~~~~~~~
1853 
1854  const triSurface& s = static_cast<const triSurface&>(*this);
1855 
1856  region.setSize(triangleIndex.size());
1857 
1858  forAll(triangleIndex, i)
1859  {
1860  label triI = triangleIndex[i];
1861  region[i] = s[triI].region();
1862  }
1863 
1864 
1865  // Send back results
1866  // ~~~~~~~~~~~~~~~~~
1867 
1868  map.reverseDistribute(info.size(), region);
1869 }
1870 
1871 
1874  const List<pointIndexHit>& info,
1875  vectorField& normal
1876 ) const
1877 {
1878  if (!Pstream::parRun())
1879  {
1880  triSurfaceMesh::getNormal(info, normal);
1881  return;
1882  }
1883 
1884 
1885  // Get query data (= local index of triangle)
1886  // ~~~~~~~~~~~~~~
1887 
1888  labelList triangleIndex(info.size());
1890  (
1891  calcLocalQueries
1892  (
1893  info,
1894  triangleIndex
1895  )
1896  );
1897  const distributionMap& map = mapPtr();
1898 
1899 
1900  // Do my tests
1901  // ~~~~~~~~~~~
1902 
1903  const triSurface& s = static_cast<const triSurface&>(*this);
1904 
1905  normal.setSize(triangleIndex.size());
1906 
1907  forAll(triangleIndex, i)
1908  {
1909  label triI = triangleIndex[i];
1910  normal[i] = s[triI].normal(s.points());
1911  }
1912 
1913 
1914  // Send back results
1915  // ~~~~~~~~~~~~~~~~~
1916 
1917  map.reverseDistribute(info.size(), normal);
1918 }
1919 
1920 
1923  const List<pointIndexHit>& info,
1924  labelList& values
1925 ) const
1926 {
1927  if (!Pstream::parRun())
1928  {
1929  triSurfaceMesh::getField(info, values);
1930  return;
1931  }
1932 
1933  if (foundObject<triSurfaceLabelField>("values"))
1934  {
1935  const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
1936  (
1937  "values"
1938  );
1939 
1940 
1941  // Get query data (= local index of triangle)
1942  // ~~~~~~~~~~~~~~
1943 
1944  labelList triangleIndex(info.size());
1946  (
1947  calcLocalQueries
1948  (
1949  info,
1950  triangleIndex
1951  )
1952  );
1953  const distributionMap& map = mapPtr();
1954 
1955 
1956  // Do my tests
1957  // ~~~~~~~~~~~
1958 
1959  values.setSize(triangleIndex.size());
1960 
1961  forAll(triangleIndex, i)
1962  {
1963  label triI = triangleIndex[i];
1964  values[i] = fld[triI];
1965  }
1966 
1967 
1968  // Send back results
1969  // ~~~~~~~~~~~~~~~~~
1970 
1971  map.reverseDistribute(info.size(), values);
1972  }
1973 }
1974 
1975 
1978  const pointField& points,
1979  List<volumeType>& volType
1980 ) const
1981 {
1983  << "Volume type not supported for distributed surfaces."
1984  << exit(FatalError);
1985 }
1986 
1987 
1988 // Subset the part of surface that is overlapping bb.
1991  const triSurface& s,
1992  const List<treeBoundBox>& bbs,
1993 
1994  labelList& subPointMap,
1995  labelList& subFaceMap
1996 )
1997 {
1998  // Determine what triangles to keep.
1999  boolList includedFace(s.size(), false);
2000 
2001  // Create a slightly larger bounding box.
2002  List<treeBoundBox> bbsX(bbs.size());
2003  const scalar eps = 1.0e-4;
2004  forAll(bbs, i)
2005  {
2006  const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2007  const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2008 
2009  bbsX[i].min() = mid - halfSpan;
2010  bbsX[i].max() = mid + halfSpan;
2011  }
2012 
2013  forAll(s, triI)
2014  {
2015  const labelledTri& f = s[triI];
2016  const point& p0 = s.points()[f[0]];
2017  const point& p1 = s.points()[f[1]];
2018  const point& p2 = s.points()[f[2]];
2019 
2020  if (overlaps(bbsX, p0, p1, p2))
2021  {
2022  includedFace[triI] = true;
2023  }
2024  }
2025 
2026  return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2027 }
2028 
2029 
2032  const List<treeBoundBox>& bbs,
2033  const bool keepNonLocal,
2034  autoPtr<distributionMap>& faceMap,
2035  autoPtr<distributionMap>& pointMap
2036 )
2037 {
2038  // Get bbs of all domains
2039  // ~~~~~~~~~~~~~~~~~~~~~~
2040 
2041  {
2043 
2044  switch(distType_)
2045  {
2046  case FOLLOW:
2047  newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2048  forAll(bbs, i)
2049  {
2050  newProcBb[Pstream::myProcNo()][i] = bbs[i];
2051  }
2052  Pstream::gatherList(newProcBb);
2053  Pstream::scatterList(newProcBb);
2054  break;
2055 
2056  case INDEPENDENT:
2057  newProcBb = independentlyDistributedBbs(*this);
2058  break;
2059 
2060  case FROZEN:
2061  return;
2062  break;
2063 
2064  default:
2066  << "Unsupported distribution type." << exit(FatalError);
2067  break;
2068  }
2069 
2070  if (newProcBb == procBb_)
2071  {
2072  return;
2073  }
2074  else
2075  {
2076  procBb_.transfer(newProcBb);
2077  dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2078  }
2079  }
2080 
2081 
2082  // Debug information
2083  if (debug)
2084  {
2085  labelList nTris(Pstream::nProcs());
2086  nTris[Pstream::myProcNo()] = triSurface::size();
2087  Pstream::gatherList(nTris);
2088  Pstream::scatterList(nTris);
2089 
2091  << "before distribution:" << endl << "\tproc\ttris" << endl;
2092 
2093  forAll(nTris, proci)
2094  {
2095  Info<< '\t' << proci << '\t' << nTris[proci] << endl;
2096  }
2097  Info<< endl;
2098  }
2099 
2100 
2101  // Use procBbs to determine which faces go where
2102  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2103 
2104  labelListList faceSendMap(Pstream::nProcs());
2105  labelListList pointSendMap(Pstream::nProcs());
2106 
2107  forAll(procBb_, proci)
2108  {
2110  (
2111  *this,
2112  procBb_[proci],
2113  pointSendMap[proci],
2114  faceSendMap[proci]
2115  );
2116 
2117  if (debug)
2118  {
2119  // Pout<< "Overlapping with proc " << proci
2120  // << " faces:" << faceSendMap[proci].size()
2121  // << " points:" << pointSendMap[proci].size() << endl << endl;
2122  }
2123  }
2124 
2125  if (keepNonLocal)
2126  {
2127  // Include in faceSendMap/pointSendMap the triangles that are
2128  // not mapped to any processor so they stay local.
2129 
2130  const triSurface& s = static_cast<const triSurface&>(*this);
2131 
2132  boolList includedFace(s.size(), true);
2133 
2134  forAll(faceSendMap, proci)
2135  {
2136  if (proci != Pstream::myProcNo())
2137  {
2138  forAll(faceSendMap[proci], i)
2139  {
2140  includedFace[faceSendMap[proci][i]] = false;
2141  }
2142  }
2143  }
2144 
2145  // Combine includedFace (all triangles that are not on any neighbour)
2146  // with overlap.
2147 
2148  forAll(faceSendMap[Pstream::myProcNo()], i)
2149  {
2150  includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2151  }
2152 
2153  subsetMesh
2154  (
2155  s,
2156  includedFace,
2157  pointSendMap[Pstream::myProcNo()],
2158  faceSendMap[Pstream::myProcNo()]
2159  );
2160  }
2161 
2162 
2163  // Send over how many faces/points I need to receive
2164  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2165 
2166  labelListList faceSendSizes(Pstream::nProcs());
2167  faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2168  forAll(faceSendMap, proci)
2169  {
2170  faceSendSizes[Pstream::myProcNo()][proci] = faceSendMap[proci].size();
2171  }
2172  Pstream::gatherList(faceSendSizes);
2173  Pstream::scatterList(faceSendSizes);
2174 
2175 
2176 
2177  // Exchange surfaces
2178  // ~~~~~~~~~~~~~~~~~
2179 
2180  // Storage for resulting surface
2181  List<labelledTri> allTris;
2183 
2184  labelListList faceConstructMap(Pstream::nProcs());
2185  labelListList pointConstructMap(Pstream::nProcs());
2186 
2187 
2188  // My own surface first
2189  // ~~~~~~~~~~~~~~~~~~~~
2190 
2191  {
2192  labelList pointMap;
2193  triSurface subSurface
2194  (
2195  subsetMesh
2196  (
2197  *this,
2198  faceSendMap[Pstream::myProcNo()],
2199  pointMap
2200  )
2201  );
2202 
2203  allTris = subSurface;
2204  allPoints = subSurface.points();
2205 
2206  faceConstructMap[Pstream::myProcNo()] = identity
2207  (
2208  faceSendMap[Pstream::myProcNo()].size()
2209  );
2210  pointConstructMap[Pstream::myProcNo()] = identity
2211  (
2212  pointSendMap[Pstream::myProcNo()].size()
2213  );
2214  }
2215 
2216 
2217 
2218  // Send all
2219  // ~~~~~~~~
2220 
2221  forAll(faceSendSizes, proci)
2222  {
2223  if (proci != Pstream::myProcNo())
2224  {
2225  if (faceSendSizes[Pstream::myProcNo()][proci] > 0)
2226  {
2228 
2229  labelList pointMap;
2230  triSurface subSurface
2231  (
2232  subsetMesh
2233  (
2234  *this,
2235  faceSendMap[proci],
2236  pointMap
2237  )
2238  );
2239 
2240  // if (debug)
2241  //{
2242  // Pout<< "Sending to " << proci
2243  // << " faces:" << faceSendMap[proci].size()
2244  // << " points:" << subSurface.points().size() << endl
2245  // << endl;
2246  //}
2247 
2248  str << subSurface;
2249  }
2250  }
2251  }
2252 
2253 
2254  // Receive and merge all
2255  // ~~~~~~~~~~~~~~~~~~~~~
2256 
2257  forAll(faceSendSizes, proci)
2258  {
2259  if (proci != Pstream::myProcNo())
2260  {
2261  if (faceSendSizes[proci][Pstream::myProcNo()] > 0)
2262  {
2264 
2265  // Receive
2266  triSurface subSurface(str);
2267 
2268  // if (debug)
2269  //{
2270  // Pout<< "Received from " << proci
2271  // << " faces:" << subSurface.size()
2272  // << " points:" << subSurface.points().size() << endl
2273  // << endl;
2274  //}
2275 
2276  // Merge into allSurf
2277  merge
2278  (
2279  mergeDist_,
2280  subSurface,
2281  subSurface.points(),
2282 
2283  allTris,
2284  allPoints,
2285  faceConstructMap[proci],
2286  pointConstructMap[proci]
2287  );
2288 
2289  // if (debug)
2290  //{
2291  // Pout<< "Current merged surface : faces:" << allTris.size()
2292  // << " points:" << allPoints.size() << endl << endl;
2293  //}
2294  }
2295  }
2296  }
2297 
2298 
2299  faceMap.reset
2300  (
2301  new distributionMap
2302  (
2303  allTris.size(),
2304  move(faceSendMap),
2305  move(faceConstructMap)
2306  )
2307  );
2308  pointMap.reset
2309  (
2310  new distributionMap
2311  (
2312  allPoints.size(),
2313  move(pointSendMap),
2314  move(pointConstructMap)
2315  )
2316  );
2317 
2318  // Construct triSurface. Reuse storage.
2319  triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2320 
2321  clearOut();
2322 
2323  // Set the bounds() value to the boundBox of the undecomposed surface
2325 
2326  reduce(bounds().min(), minOp<point>());
2327  reduce(bounds().max(), maxOp<point>());
2328 
2329  // Regions stays same
2330  // Volume type stays same.
2331 
2332  distributeFields<label>(faceMap());
2333  distributeFields<scalar>(faceMap());
2334  distributeFields<vector>(faceMap());
2335  distributeFields<sphericalTensor>(faceMap());
2336  distributeFields<symmTensor>(faceMap());
2337  distributeFields<tensor>(faceMap());
2338 
2339  if (debug)
2340  {
2341  labelList nTris(Pstream::nProcs());
2342  nTris[Pstream::myProcNo()] = triSurface::size();
2343  Pstream::gatherList(nTris);
2344  Pstream::scatterList(nTris);
2345 
2347  << "after distribution:" << endl << "\tproc\ttris" << endl;
2348 
2349  forAll(nTris, proci)
2350  {
2351  Info<< '\t' << proci << '\t' << nTris[proci] << endl;
2352  }
2353  Info<< endl;
2354  }
2355 }
2356 
2357 
2363  const bool write
2364 ) const
2365 {
2366  // Make sure dictionary goes to same directory as surface
2367  const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2368 
2369  // Copy of triSurfaceMesh::writeObject except for the sorting of
2370  // triangles by region. This is done so we preserve region names,
2371  // even if locally we have zero triangles.
2372  {
2374 
2375  if (!mkDir(fullPath.path()))
2376  {
2377  return false;
2378  }
2379 
2380  // Important: preserve any zero-sized patches
2381  triSurface::write(fullPath, true);
2382 
2383  if (!isFile(fullPath))
2384  {
2385  return false;
2386  }
2387  }
2388 
2389  // Dictionary needs to be written in ascii - binary output not supported.
2390  return dict_.writeObject(IOstream::ASCII, ver, cmp, true);
2391 }
2392 
2393 
2395 {
2396  boundBox bb;
2397  label nPoints;
2398  PatchTools::calcBounds(static_cast<const triSurface&>(*this), bb, nPoints);
2399  reduce(bb.min(), minOp<point>());
2400  reduce(bb.max(), maxOp<point>());
2401 
2402  os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2403  << endl
2404  << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2405  << "Bounding Box : " << bb << endl;
2406 }
2407 
2408 
2409 // ************************************************************************* //
virtual void getField(const List< pointIndexHit > &, labelList &) const
WIP. From a set of hits (points and.
bool overlaps(const boundBox &) const
Overlaps/touches boundingBox?
Definition: boundBoxI.H:120
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:38
label nPoints() const
Return number of points supporting patch faces.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
const word & name() const
Return name.
Definition: IOobject.H:315
A class for handling file names.
Definition: fileName.H:79
triSurfaceMesh(const IOobject &, const triSurface &)
Construct from triSurface.
virtual void findLineAny(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Return any intersection on segment from start to end.
static const Form max
Definition: VectorSpace.H:115
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
void clearOut()
Clear storage.
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
void reverseDistribute(const label constructSize, List< T > &, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType.
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
void operator=(const triSurface &)
Definition: triSurface.C:1385
T & operator[](const label)
Return element of UList.
Definition: UListI.H:167
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
pointIndexHit findLineAny(const point &start, const point &end) const
Find any intersection of line between start and end.
virtual tmp< pointField > points() const
Get the points that define the surface.
bool isFile(const fileName &, const bool checkVariants=true, const bool followLink=true)
Does the name exist as a file in the file system?
Definition: POSIX.C:555
const globalIndex & globalTris() const
Triangle indexing (demand driven)
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setIndex(const label index)
static bool intersectBb(const point &p0, const point &p1, const point &p2, const treeBoundBox &cubeBb)
Does triangle intersect bounding box.
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
fileName objectPath() const
Return complete path + object name.
Definition: regIOobject.H:159
word findInstance(const fileName &dir, const word &name=word::null, const IOobject::readOption rOpt=IOobject::MUST_READ, const word &stopInstance=word::null) const
Return the location of "dir" containing the file "name".
Definition: Time.C:689
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Pair< point > segment
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:58
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
static const NamedEnum< distributionType, 3 > distributionTypeNames_
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:51
Determine correspondence between points. See below.
Macros for easy insertion into run-time selection tables.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
virtual void getVolumeType(const pointField &, List< volumeType > &) const
Determine type (inside/outside/mixed) for point. unknown if.
static const Form min
Definition: VectorSpace.H:116
A surface geometry formed of discrete facets, e.g. triangles and/or quadrilaterals, defined in a file using formats such as Wavefront OBJ, or stereolithography STL.
Input inter-processor communications stream.
Definition: IPstream.H:50
const Point & hitPoint() const
Return hit point.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
label region() const
Return region label.
Definition: labelledTriI.H:68
bool read(const char *, int32_t &)
Definition: int32IO.C:85
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:33
static void calcBounds(const PrimitivePatch< FaceList, PointField > &p, boundBox &bb, label &nPoints)
bool intersects(const point &overallStart, const vector &overallVec, const point &start, const point &end, point &pt, direction &ptBits) const
Intersects segment; set point to intersection position and face,.
Definition: treeBoundBox.C:236
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< ' ';}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< ' ';}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< ' ';}gmvFile<< nl;forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Geometrical domain decomposition.
Definition: geomDecomp.H:47
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
virtual void getRegion(const List< pointIndexHit > &, labelList &region) const
From a set of points and indices get the region.
A class for handling words, derived from string.
Definition: word.H:59
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
const fileName & local() const
Definition: IOobject.H:409
static autoPtr< decompositionMethod > NewDistributor(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:86
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
bool hit() const
Is there a hit.
const Field< PointType > & points() const
Return reference to global points.
static const word null
An empty word.
Definition: word.H:77
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
label toLocal(const label i) const
From global to local on current processor.
Definition: globalIndexI.H:117
Triangle with additional region number.
Definition: labelledTri.H:57
label whichProcID(const label i) const
Which processor does global come from? Binary search.
Definition: globalIndexI.H:123
Accumulating histogram of values. Specified bin resolution automatic generation of bins...
Definition: distribution.H:58
static dictionary decomposeParDict(const Time &time)
Read and return the decomposeParDict.
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: FixedListI.H:125
virtual void findLineAll(const pointField &start, const pointField &end, List< List< pointIndexHit >> &) const
Get all intersections in order from start to end.
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("hex"));labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< small) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &mergedCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
compressionType
Enumeration for the format of data in the stream.
Definition: IOstream.H:193
bool contains(const vector &dir, const point &) const
Contains point (inside or on edge) and moving in direction.
Definition: treeBoundBox.C:394
dimensioned< scalar > magSqr(const dimensioned< Type > &)
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:54
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:252
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const
defineTypeNameAndDebug(combustionModel, 0)
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:231
labelList f(nPoints)
Output inter-processor communications stream.
Definition: OPstream.H:50
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
virtual labelList decompose(const pointField &points, const scalarField &pointWeights)=0
Return for every coordinate the wanted processor number.
static triSurface overlappingSurface(const triSurface &, const List< treeBoundBox > &, labelList &subPointMap, labelList &subFaceMap)
Subset the part of surface that is overlapping bounds.
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:48
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
void setSize(const label)
Reset size of List.
Definition: List.C:281
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:60
const geometricSurfacePatchList & patches() const
Definition: triSurface.H:322
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Class containing processor-to-processor mapping information.
writeOption writeOpt() const
Definition: IOobject.H:375
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
triSurface()
Construct null.
Definition: triSurface.C:534
std::remove_reference< ::Foam::List< labelledTri > >::type::value_type FaceType
vector point
Point is a vector.
Definition: point.H:41
Non-pointer based hierarchical recursive searching.
Definition: treeDataEdge.H:47
virtual label size() const
Range of local indices that can be returned.
const Time & time() const
Return time.
Definition: IOobject.C:318
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
void invertManyToMany(const label len, const UList< InList > &, List< OutList > &)
Invert many-to-many.
Version number type.
Definition: IOstream.H:96
void set(entry *)
Assign a new entry, overwrite any existing entry.
Definition: dictionary.C:1291
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:87
messageStream Info
virtual bool writeObject(IOstream::streamFormat, IOstream::versionNumber, IOstream::compressionType, const bool write) const
Write using given format, version and compression.
virtual bool writeObject(IOstream::streamFormat fmt, IOstream::versionNumber ver, IOstream::compressionType cmp, const bool write=true) const
Write using given format, version and compression.
label n
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:265
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
const boundBox & bounds() const
Return const reference to boundBox.
fileName & instance() const
Return the instance directory, constant, system, <time> etc.
Definition: IOobject.C:355
const point & min() const
Minimum point defining the bounding box.
Definition: boundBoxI.H:54
virtual void distribute(const List< treeBoundBox > &, const bool keepNonLocal, autoPtr< distributionMap > &faceMap, autoPtr< distributionMap > &pointMap)
Set bounds of surface. Bounds currently set as list of.
const objectRegistry & db() const
Return the local objectRegistry.
Definition: IOobject.C:312
Triangulated surface description with patch information.
Definition: triSurface.H:66
bool & registerObject()
Register object created from this IOobject with registry if true.
Definition: IOobject.H:351
readOption readOpt() const
Definition: IOobject.H:365
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:98
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
label size() const
Return the number of elements in the UList.
Definition: ListI.H:171
const indexedOctree< treeDataTriSurface > & tree() const
Demand driven construction of the octree.
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
distributedTriSurfaceMesh(const IOobject &, const triSurface &, const dictionary &dict)
Construct from triSurface.
Namespace for OpenFOAM.
virtual void getField(const List< pointIndexHit > &, labelList &) const
WIP. From a set of hits (points and.
void writeStats(Ostream &os) const
Print some stats. Parallel aware version of.
#define InfoInFunction
Report an information message using Foam::Info.