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-2023 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 {
48  (
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
280  List<DynamicList<label>> dynSendMap(Pstream::nProcs());
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()] = identityMap
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 
345  return autoPtr<distributionMap>
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()] = identityMap
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 
638  autoPtr<distributionMap> mapPtr
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
714  List<DynamicList<label>> dynSendMap(Pstream::nProcs());
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()] = identityMap
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 
791  autoPtr<distributionMap> mapPtr
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)
852  List<List<treeBoundBox>> bbs(Pstream::nProcs());
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 
1270 (
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",
1282  searchableSurface::instance(),
1283  searchableSurface::local(),
1284  searchableSurface::db(),
1285  searchableSurface::NO_READ,
1286  searchableSurface::writeOpt(),
1287  searchableSurface::registerObject()
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 
1397 (
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",
1423  searchableSurface::instance(),
1424  searchableSurface::local(),
1425  searchableSurface::db(),
1426  searchableSurface::readOpt(),
1427  searchableSurface::writeOpt(),
1428  searchableSurface::registerObject()
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 
1508 (
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>())
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
1665 (
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 
1682 (
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 
1699 (
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 
1813 (
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 
1873 (
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 
1922 (
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 
1977 (
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.
1990 (
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 
2031 (
2032  const List<treeBoundBox>& bbs,
2033  const bool keepNonLocal,
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  {
2109  overlappingSurface
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;
2182  pointField allPoints;
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()] = identityMap
2207  (
2208  faceSendMap[Pstream::myProcNo()].size()
2209  );
2210  pointConstructMap[Pstream::myProcNo()] = identityMap
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 
2359 (
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 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Macros for easy insertion into run-time selection tables.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
const Time & time() const
Return time.
Definition: IOobject.C:318
@ MUST_READ_IF_MODIFIED
Definition: IOobject.H:119
fileName & instance() const
Return the instance directory, constant, system, <time> etc.
Definition: IOobject.C:355
readOption readOpt() const
Definition: IOobject.H:360
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:226
Version number type.
Definition: IOstream.H:97
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:87
compressionType
Enumeration for the format of data in the stream.
Definition: IOstream.H:194
Input inter-processor communications stream.
Definition: IPstream.H:54
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
label size() const
Return the number of elements in the UList.
Definition: ListI.H:171
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
void setSize(const label)
Reset size of List.
Definition: List.C:281
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:54
Enum read(Istream &) const
Read a word from Istream and return the corresponding.
Definition: NamedEnum.C:61
Output inter-processor communications stream.
Definition: OPstream.H:54
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
static void calcBounds(const PrimitivePatch< FaceList, PointField > &p, boundBox &bb, label &nPoints)
const Field< PointType > & points() const
Return reference to global points.
std::remove_reference< ::Foam::List< labelledTri > >::type::value_type FaceType
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
T & operator[](const label)
Return element of UList.
Definition: UListI.H:167
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static const Form max
Definition: VectorSpace.H:115
static const Form min
Definition: VectorSpace.H:116
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:59
const point & min() const
Minimum point defining the bounding box.
Definition: boundBoxI.H:54
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:60
static autoPtr< decompositionMethod > NewDistributor(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
static dictionary decomposeParDict(const Time &time)
Read and return the decomposeParDict.
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:860
IOoject and searching on distributed triSurface. All processor hold (possibly overlapping) part of th...
virtual void getVolumeType(const pointField &, List< volumeType > &) const
Determine type (inside/outside/mixed) for point. unknown if.
static triSurface overlappingSurface(const triSurface &, const List< treeBoundBox > &, labelList &subPointMap, labelList &subFaceMap)
Subset the part of surface that is overlapping bounds.
virtual void findLineAny(const pointField &start, const pointField &end, List< pointIndexHit > &) const
Return any intersection on segment from start to end.
static const NamedEnum< distributionType, 3 > distributionTypeNames_
virtual void getField(const List< pointIndexHit > &, labelList &) const
WIP. From a set of hits (points and.
virtual bool writeObject(IOstream::streamFormat fmt, IOstream::versionNumber ver, IOstream::compressionType cmp, const bool write=true) const
Write using given format, version and compression.
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
virtual void getRegion(const List< pointIndexHit > &, labelList &region) const
From a set of points and indices get the region.
const globalIndex & globalTris() const
Triangle indexing (demand driven)
void writeStats(Ostream &os) const
Print some stats. Parallel aware version of.
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const
distributedTriSurfaceMesh(const IOobject &, const triSurface &, const dictionary &dict)
Construct from triSurface.
virtual void findLineAll(const pointField &start, const pointField &end, List< List< pointIndexHit >> &) const
Get all intersections in order from start to end.
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.
Class containing processor-to-processor mapping information.
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
void reverseDistribute(const label constructSize, List< T > &, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Reverse distribute data using default commsType.
A class for handling file names.
Definition: fileName.H:82
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:265
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Non-pointer based hierarchical recursive searching.
Definition: indexedOctree.H:72
Triangle with additional region number.
Definition: labelledTri.H:60
fileName objectPath() const
Return complete path + object name.
Definition: regIOobject.H:159
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
const boundBox & bounds() const
Return const reference to boundBox.
A surface geometry formed of discrete facets, e.g. triangles and/or quadrilaterals,...
virtual void getField(const List< pointIndexHit > &, labelList &) const
WIP. From a set of hits (points and.
virtual void getNormal(const List< pointIndexHit > &, vectorField &normal) const
From a set of points and indices get the normal.
void clearOut()
Clear storage.
Triangulated surface description with patch information.
Definition: triSurface.H:69
void operator=(const triSurface &)
Definition: triSurface.C:1385
static bool intersectBb(const point &p0, const point &p1, const point &p2, const treeBoundBox &cubeBb)
Does triangle intersect bounding box.
A class for handling words, derived from string.
Definition: word.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
const pointField & points
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
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){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const fvPatchList & patches
Determine correspondence between points. See below.
#define InfoInFunction
Report an information message using Foam::Info.
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
messageStream Info
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vector point
Point is a vector.
Definition: point.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
defineTypeNameAndDebug(combustionModel, 0)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
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
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
dimensioned< scalar > magSqr(const dimensioned< Type > &)
void invertManyToMany(const label len, const UList< InList > &, List< OutList > &)
Invert many-to-many.
Pair< point > segment
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
labelList f(nPoints)
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:229
dictionary dict
scalarField samples(nIntervals, 0)