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-2024 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 "randomGenerator.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 "geometric.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<decompositionMethods::geometric>(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  decompositionMethods::geometric& distributor =
845  refCast<decompositionMethods::geometric>(distributor_());
846 
847  // Do the actual decomposition
848  labelList distribution(distributor.decompose(triCentres));
849 
850  // Find bounding box for all triangles on new distribution.
851 
852  // Initialise to inverted box (vGreat, -vGreat)
853  List<List<treeBoundBox>> bbs(Pstream::nProcs());
854  forAll(bbs, proci)
855  {
856  bbs[proci].setSize(1);
857  // bbs[proci][0] = boundBox::invertedBox;
858  bbs[proci][0].min() = point( vGreat, vGreat, vGreat);
859  bbs[proci][0].max() = point(-vGreat, -vGreat, -vGreat);
860  }
861 
862  forAll(s, triI)
863  {
864  point& bbMin = bbs[distribution[triI]][0].min();
865  point& bbMax = bbs[distribution[triI]][0].max();
866 
867  const triSurface::FaceType& f = s[triI];
868  forAll(f, fp)
869  {
870  const point& pt = s.points()[f[fp]];
871  bbMin = ::Foam::min(bbMin, pt);
872  bbMax = ::Foam::max(bbMax, pt);
873  }
874  }
875 
876  // Now combine for all processors and convert to correct format.
877  forAll(bbs, proci)
878  {
879  forAll(bbs[proci], i)
880  {
881  reduce(bbs[proci][i].min(), minOp<point>());
882  reduce(bbs[proci][i].max(), maxOp<point>());
883  }
884  }
885  return bbs;
886 }
887 
888 
889 // Does any part of triangle overlap bb.
890 bool Foam::distributedTriSurfaceMesh::overlaps
891 (
892  const List<treeBoundBox>& bbs,
893  const point& p0,
894  const point& p1,
895  const point& p2
896 )
897 {
898  forAll(bbs, bbI)
899  {
900  const treeBoundBox& bb = bbs[bbI];
901 
902  treeBoundBox triBb(p0, p0);
903  triBb.min() = min(triBb.min(), p1);
904  triBb.min() = min(triBb.min(), p2);
905 
906  triBb.max() = max(triBb.max(), p1);
907  triBb.max() = max(triBb.max(), p2);
908 
909  // Exact test of triangle intersecting bb
910 
911  // Quick rejection. If whole bounding box of tri is outside cubeBb then
912  // there will be no intersection.
913  if (bb.overlaps(triBb))
914  {
915  // Check if one or more triangle point inside
916  if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
917  {
918  // One or more points inside
919  return true;
920  }
921 
922  // Now we have the difficult case: all points are outside but
923  // connecting edges might go through cube. Use fast intersection
924  // of bounding box.
925  bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
926 
927  if (intersect)
928  {
929  return true;
930  }
931  }
932  }
933  return false;
934 }
935 
936 
937 void Foam::distributedTriSurfaceMesh::subsetMeshMap
938 (
939  const triSurface& s,
940  const boolList& include,
941  const label nIncluded,
942  labelList& newToOldPoints,
943  labelList& oldToNewPoints,
944  labelList& newToOldFaces
945 )
946 {
947  newToOldFaces.setSize(nIncluded);
948  newToOldPoints.setSize(s.points().size());
949  oldToNewPoints.setSize(s.points().size());
950  oldToNewPoints = -1;
951  {
952  label facei = 0;
953  label pointi = 0;
954 
955  forAll(include, oldFacei)
956  {
957  if (include[oldFacei])
958  {
959  // Store new faces compact
960  newToOldFaces[facei++] = oldFacei;
961 
962  // Renumber labels for face
963  const triSurface::FaceType& f = s[oldFacei];
964 
965  forAll(f, fp)
966  {
967  label oldPointi = f[fp];
968 
969  if (oldToNewPoints[oldPointi] == -1)
970  {
971  oldToNewPoints[oldPointi] = pointi;
972  newToOldPoints[pointi++] = oldPointi;
973  }
974  }
975  }
976  }
977  newToOldPoints.setSize(pointi);
978  }
979 }
980 
981 
982 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
983 (
984  const triSurface& s,
985  const labelList& newToOldPoints,
986  const labelList& oldToNewPoints,
987  const labelList& newToOldFaces
988 )
989 {
990  // Extract points
991  pointField newPoints(newToOldPoints.size());
992  forAll(newToOldPoints, i)
993  {
994  newPoints[i] = s.points()[newToOldPoints[i]];
995  }
996  // Extract faces
997  List<labelledTri> newTriangles(newToOldFaces.size());
998 
999  forAll(newToOldFaces, i)
1000  {
1001  // Get old vertex labels
1002  const labelledTri& tri = s[newToOldFaces[i]];
1003 
1004  newTriangles[i][0] = oldToNewPoints[tri[0]];
1005  newTriangles[i][1] = oldToNewPoints[tri[1]];
1006  newTriangles[i][2] = oldToNewPoints[tri[2]];
1007  newTriangles[i].region() = tri.region();
1008  }
1009 
1010  // Reuse storage.
1011  return triSurface(newTriangles, s.patches(), newPoints, true);
1012 }
1013 
1014 
1015 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1016 (
1017  const triSurface& s,
1018  const boolList& include,
1019  labelList& newToOldPoints,
1020  labelList& newToOldFaces
1021 )
1022 {
1023  label n = 0;
1024 
1025  forAll(include, i)
1026  {
1027  if (include[i])
1028  {
1029  n++;
1030  }
1031  }
1032 
1033  labelList oldToNewPoints;
1034  subsetMeshMap
1035  (
1036  s,
1037  include,
1038  n,
1039  newToOldPoints,
1040  oldToNewPoints,
1041  newToOldFaces
1042  );
1043 
1044  return subsetMesh
1045  (
1046  s,
1047  newToOldPoints,
1048  oldToNewPoints,
1049  newToOldFaces
1050  );
1051 }
1052 
1053 
1054 Foam::triSurface Foam::distributedTriSurfaceMesh::subsetMesh
1055 (
1056  const triSurface& s,
1057  const labelList& newToOldFaces,
1058  labelList& newToOldPoints
1059 )
1060 {
1061  const boolList include
1062  (
1063  createWithValues<boolList>
1064  (
1065  s.size(),
1066  false,
1067  newToOldFaces,
1068  true
1069  )
1070  );
1071 
1072  newToOldPoints.setSize(s.points().size());
1073  labelList oldToNewPoints(s.points().size(), -1);
1074  {
1075  label pointi = 0;
1076 
1077  forAll(include, oldFacei)
1078  {
1079  if (include[oldFacei])
1080  {
1081  // Renumber labels for face
1082  const triSurface::FaceType& f = s[oldFacei];
1083 
1084  forAll(f, fp)
1085  {
1086  label oldPointi = f[fp];
1087 
1088  if (oldToNewPoints[oldPointi] == -1)
1089  {
1090  oldToNewPoints[oldPointi] = pointi;
1091  newToOldPoints[pointi++] = oldPointi;
1092  }
1093  }
1094  }
1095  }
1096  newToOldPoints.setSize(pointi);
1097  }
1098 
1099  return subsetMesh
1100  (
1101  s,
1102  newToOldPoints,
1103  oldToNewPoints,
1104  newToOldFaces
1105  );
1106 }
1107 
1108 
1109 Foam::label Foam::distributedTriSurfaceMesh::findTriangle
1110 (
1111  const List<labelledTri>& allFaces,
1112  const labelListList& allPointFaces,
1113  const labelledTri& otherF
1114 )
1115 {
1116  // allFaces connected to otherF[0]
1117  const labelList& pFaces = allPointFaces[otherF[0]];
1118 
1119  forAll(pFaces, i)
1120  {
1121  const labelledTri& f = allFaces[pFaces[i]];
1122 
1123  if (f.region() == otherF.region())
1124  {
1125  // Find index of otherF[0]
1126  label fp0 = findIndex(f, otherF[0]);
1127  // Check rest of triangle in same order
1128  label fp1 = f.fcIndex(fp0);
1129  label fp2 = f.fcIndex(fp1);
1130 
1131  if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1132  {
1133  return pFaces[i];
1134  }
1135  }
1136  }
1137  return -1;
1138 }
1139 
1140 
1141 // Merge into allSurf.
1142 void Foam::distributedTriSurfaceMesh::merge
1143 (
1144  const scalar mergeDist,
1145  const List<labelledTri>& subTris,
1146  const pointField& subPoints,
1147 
1148  List<labelledTri>& allTris,
1149  pointField& allPoints,
1150 
1151  labelList& faceConstructMap,
1152  labelList& pointConstructMap
1153 )
1154 {
1155  labelList subToAll;
1156  matchPoints
1157  (
1158  subPoints,
1159  allPoints,
1160  scalarField(subPoints.size(), mergeDist), // match distance
1161  false, // verbose
1162  pointConstructMap
1163  );
1164 
1165  label nOldAllPoints = allPoints.size();
1166 
1167 
1168  // Add all unmatched points
1169  // ~~~~~~~~~~~~~~~~~~~~~~~~
1170 
1171  label allPointi = nOldAllPoints;
1172  forAll(pointConstructMap, pointi)
1173  {
1174  if (pointConstructMap[pointi] == -1)
1175  {
1176  pointConstructMap[pointi] = allPointi++;
1177  }
1178  }
1179 
1180  if (allPointi > nOldAllPoints)
1181  {
1182  allPoints.setSize(allPointi);
1183 
1184  forAll(pointConstructMap, pointi)
1185  {
1186  if (pointConstructMap[pointi] >= nOldAllPoints)
1187  {
1188  allPoints[pointConstructMap[pointi]] = subPoints[pointi];
1189  }
1190  }
1191  }
1192 
1193 
1194  // To check whether triangles are same we use pointFaces.
1195  labelListList allPointFaces;
1196  invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1197 
1198 
1199  // Add all unmatched triangles
1200  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1201 
1202  label allTriI = allTris.size();
1203  allTris.setSize(allTriI + subTris.size());
1204 
1205  faceConstructMap.setSize(subTris.size());
1206 
1207  forAll(subTris, triI)
1208  {
1209  const labelledTri& subTri = subTris[triI];
1210 
1211  // Get triangle in new numbering
1212  labelledTri mappedTri
1213  (
1214  pointConstructMap[subTri[0]],
1215  pointConstructMap[subTri[1]],
1216  pointConstructMap[subTri[2]],
1217  subTri.region()
1218  );
1219 
1220 
1221  // Check if all points were already in surface
1222  bool fullMatch = true;
1223 
1224  forAll(mappedTri, fp)
1225  {
1226  if (mappedTri[fp] >= nOldAllPoints)
1227  {
1228  fullMatch = false;
1229  break;
1230  }
1231  }
1232 
1233  if (fullMatch)
1234  {
1235  // All three points are mapped to old points. See if same
1236  // triangle.
1237  label i = findTriangle
1238  (
1239  allTris,
1240  allPointFaces,
1241  mappedTri
1242  );
1243 
1244  if (i == -1)
1245  {
1246  // Add
1247  faceConstructMap[triI] = allTriI;
1248  allTris[allTriI] = mappedTri;
1249  allTriI++;
1250  }
1251  else
1252  {
1253  faceConstructMap[triI] = i;
1254  }
1255  }
1256  else
1257  {
1258  // Add
1259  faceConstructMap[triI] = allTriI;
1260  allTris[allTriI] = mappedTri;
1261  allTriI++;
1262  }
1263  }
1264  allTris.setSize(allTriI);
1265 }
1266 
1267 
1268 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1269 
1271 (
1272  const IOobject& io,
1273  const triSurface& s,
1274  const dictionary& dict
1275 )
1276 :
1277  triSurfaceMesh(io, s),
1278  dict_
1279  (
1280  IOobject
1281  (
1282  searchableSurface::name() + "Dict",
1283  searchableSurface::instance(),
1284  searchableSurface::local(),
1285  searchableSurface::db(),
1286  searchableSurface::NO_READ,
1287  searchableSurface::writeOpt(),
1288  searchableSurface::registerObject()
1289  ),
1290  dict
1291  )
1292 {
1293  read();
1294 
1295  reduce(bounds().min(), minOp<point>());
1296  reduce(bounds().max(), maxOp<point>());
1297 
1298  if (debug)
1299  {
1300  InfoInFunction << "Constructed from triSurface:" << endl;
1301  writeStats(Info);
1302 
1303  labelList nTris(Pstream::nProcs());
1304  nTris[Pstream::myProcNo()] = triSurface::size();
1305  Pstream::gatherList(nTris);
1306  Pstream::scatterList(nTris);
1307 
1308  Info<< endl<< "\tproc\ttris\tbb" << endl;
1309  forAll(nTris, proci)
1310  {
1311  Info<< '\t' << proci << '\t' << nTris[proci]
1312  << '\t' << procBb_[proci] << endl;
1313  }
1314  Info<< endl;
1315  }
1316 }
1317 
1318 
1320 :
1322  (
1323  IOobject
1324  (
1325  io.name(),
1326  io.time().findInstance(io.local(), word::null),
1327  io.local(),
1328  io.db(),
1329  io.readOpt(),
1330  io.writeOpt(),
1331  io.registerObject()
1332  ),
1333  false
1334  ),
1335  dict_
1336  (
1337  IOobject
1338  (
1339  searchableSurface::name() + "Dict",
1340  searchableSurface::instance(),
1341  searchableSurface::local(),
1342  searchableSurface::db(),
1343  searchableSurface::readOpt(),
1344  searchableSurface::writeOpt(),
1345  searchableSurface::registerObject()
1346  )
1347  )
1348 {
1349  if
1350  (
1351  Pstream::parRun()
1352  && (
1353  dict_.readOpt() == IOobject::MUST_READ
1355  )
1356  && (
1359  )
1360  )
1361  {
1363  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1364  << " Modify the entry fileModificationChecking\n"
1365  << " in the etc/controlDict.\n"
1366  << " Use 'timeStamp' instead."
1367  << exit(FatalError);
1368  }
1369 
1370  read();
1371 
1372  reduce(bounds().min(), minOp<point>());
1373  reduce(bounds().max(), maxOp<point>());
1374 
1375  if (debug)
1376  {
1377  InfoInFunction << "Read distributedTriSurface from "
1378  << searchableSurface::objectPath() << ':' << endl;
1379  writeStats(Info);
1380 
1381  labelList nTris(Pstream::nProcs());
1382  nTris[Pstream::myProcNo()] = triSurface::size();
1383  Pstream::gatherList(nTris);
1384  Pstream::scatterList(nTris);
1385 
1386  Info<< endl<< "\tproc\ttris\tbb" << endl;
1387  forAll(nTris, proci)
1388  {
1389  Info<< '\t' << proci << '\t' << nTris[proci]
1390  << '\t' << procBb_[proci] << endl;
1391  }
1392  Info<< endl;
1393  }
1394 }
1395 
1396 
1398 (
1399  const IOobject& io,
1400  const dictionary& dict
1401 )
1402 :
1403  // triSurfaceMesh(io, dict),
1405  (
1406  IOobject
1407  (
1408  io.name(),
1409  io.time().findInstance(io.local(), word::null),
1410  io.local(),
1411  io.db(),
1412  io.readOpt(),
1413  io.writeOpt(),
1414  io.registerObject()
1415  ),
1416  dict,
1417  false
1418  ),
1419  dict_
1420  (
1421  IOobject
1422  (
1423  searchableSurface::name() + "Dict",
1424  searchableSurface::instance(),
1425  searchableSurface::local(),
1426  searchableSurface::db(),
1427  searchableSurface::readOpt(),
1428  searchableSurface::writeOpt(),
1429  searchableSurface::registerObject()
1430  )
1431  )
1432 {
1433  if
1434  (
1435  Pstream::parRun()
1436  && (
1437  dict_.readOpt() == IOobject::MUST_READ
1439  )
1440  && (
1443  )
1444  )
1445  {
1447  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1448  << " Modify the entry fileModificationChecking\n"
1449  << " in the etc/controlDict.\n"
1450  << " Use 'timeStamp' instead."
1451  << exit(FatalError);
1452  }
1453 
1454  read();
1455 
1456  reduce(bounds().min(), minOp<point>());
1457  reduce(bounds().max(), maxOp<point>());
1458 
1459  if (debug)
1460  {
1461  InfoInFunction << "Read distributedTriSurface from "
1462  << searchableSurface::objectPath() << " and dictionary:" << endl;
1463  writeStats(Info);
1464 
1465  labelList nTris(Pstream::nProcs());
1466  nTris[Pstream::myProcNo()] = triSurface::size();
1467  Pstream::gatherList(nTris);
1468  Pstream::scatterList(nTris);
1469 
1470  Info<< endl<< "\tproc\ttris\tbb" << endl;
1471  forAll(nTris, proci)
1472  {
1473  Info<< '\t' << proci << '\t' << nTris[proci]
1474  << '\t' << procBb_[proci] << endl;
1475  }
1476  Info<< endl;
1477  }
1478 }
1479 
1480 
1481 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1482 
1484 {
1485  clearOut();
1486 }
1487 
1488 
1490 {
1491  globalTris_.clear();
1493 }
1494 
1495 
1496 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1497 
1499 {
1500  if (!globalTris_.valid())
1501  {
1502  globalTris_.reset(new globalIndex(triSurface::size()));
1503  }
1504  return globalTris_;
1505 }
1506 
1507 
1509 (
1510  const pointField& samples,
1511  const scalarField& nearestDistSqr,
1512  List<pointIndexHit>& info
1513 ) const
1514 {
1515  const indexedOctree<treeDataTriSurface>& octree = tree();
1516 
1517  // Important:force synchronised construction of indexing
1518  const globalIndex& triIndexer = globalTris();
1519 
1520 
1521  // Initialise
1522  // ~~~~~~~~~~
1523 
1524  info.setSize(samples.size());
1525  forAll(info, i)
1526  {
1527  info[i].setMiss();
1528  }
1529 
1530 
1531 
1532  // Do any local queries
1533  // ~~~~~~~~~~~~~~~~~~~~
1534 
1535  label nLocal = 0;
1536 
1537  {
1538  // Work array - whether processor bb overlaps the bounding sphere.
1539  boolList procBbOverlaps(Pstream::nProcs());
1540 
1541  forAll(samples, i)
1542  {
1543  // Find the processor this sample+radius overlaps.
1544  label nProcs = calcOverlappingProcs
1545  (
1546  samples[i],
1547  nearestDistSqr[i],
1548  procBbOverlaps
1549  );
1550 
1551  // Overlaps local processor?
1552  if (procBbOverlaps[Pstream::myProcNo()])
1553  {
1554  info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1555  if (info[i].hit())
1556  {
1557  info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1558  }
1559  if (nProcs == 1)
1560  {
1561  // Fully local
1562  nLocal++;
1563  }
1564  }
1565  }
1566  }
1567 
1568 
1569  if
1570  (
1571  Pstream::parRun()
1572  && (
1573  returnReduce(nLocal, sumOp<label>())
1575  )
1576  )
1577  {
1578  // Not all can be resolved locally. Build queries and map, send over
1579  // queries, do intersections, send back and merge.
1580 
1581  // Calculate queries and exchange map
1582  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1583 
1584  pointField allCentres;
1585  scalarField allRadiusSqr;
1586  labelList allSegmentMap;
1588  (
1589  calcLocalQueries
1590  (
1591  samples,
1592  nearestDistSqr,
1593 
1594  allCentres,
1595  allRadiusSqr,
1596  allSegmentMap
1597  )
1598  );
1599  const distributionMap& map = mapPtr();
1600 
1601 
1602  // swap samples to local processor
1603  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1604 
1605  map.distribute(allCentres);
1606  map.distribute(allRadiusSqr);
1607 
1608 
1609  // Do my tests
1610  // ~~~~~~~~~~~
1611 
1612  List<pointIndexHit> allInfo(allCentres.size());
1613  forAll(allInfo, i)
1614  {
1615  allInfo[i] = octree.findNearest
1616  (
1617  allCentres[i],
1618  allRadiusSqr[i]
1619  );
1620  if (allInfo[i].hit())
1621  {
1622  allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1623  }
1624  }
1625 
1626 
1627  // Send back results
1628  // ~~~~~~~~~~~~~~~~~
1629 
1630  map.reverseDistribute(allSegmentMap.size(), allInfo);
1631 
1632 
1633  // Extract information
1634  // ~~~~~~~~~~~~~~~~~~~
1635 
1636  forAll(allInfo, i)
1637  {
1638  if (allInfo[i].hit())
1639  {
1640  label pointi = allSegmentMap[i];
1641 
1642  if (!info[pointi].hit())
1643  {
1644  // No intersection yet so take this one
1645  info[pointi] = allInfo[i];
1646  }
1647  else
1648  {
1649  // Nearest intersection
1650  if
1651  (
1652  magSqr(allInfo[i].hitPoint()-samples[pointi])
1653  < magSqr(info[pointi].hitPoint()-samples[pointi])
1654  )
1655  {
1656  info[pointi] = allInfo[i];
1657  }
1658  }
1659  }
1660  }
1661  }
1662 }
1663 
1664 
1665 void Foam::distributedTriSurfaceMesh::findLine
1666 (
1667  const pointField& start,
1668  const pointField& end,
1669  List<pointIndexHit>& info
1670 ) const
1671 {
1672  findLine
1673  (
1674  true, // nearestIntersection
1675  start,
1676  end,
1677  info
1678  );
1679 }
1680 
1681 
1683 (
1684  const pointField& start,
1685  const pointField& end,
1686  List<pointIndexHit>& info
1687 ) const
1688 {
1689  findLine
1690  (
1691  true, // nearestIntersection
1692  start,
1693  end,
1694  info
1695  );
1696 }
1697 
1698 
1700 (
1701  const pointField& start,
1702  const pointField& end,
1703  List<List<pointIndexHit>>& info
1704 ) const
1705 {
1706  // Reuse fineLine. We could modify all of findLine to do multiple
1707  // intersections but this would mean a lot of data transferred so
1708  // for now we just find nearest intersection and retest from that
1709  // intersection onwards.
1710 
1711  // Work array.
1712  List<pointIndexHit> hitInfo(start.size());
1713 
1714  findLine
1715  (
1716  true, // nearestIntersection
1717  start,
1718  end,
1719  hitInfo
1720  );
1721 
1722  // Tolerances:
1723  // To find all intersections we add a small vector to the last intersection
1724  // This is chosen such that
1725  // - it is significant (small is smallest representative relative tolerance;
1726  // we need something bigger since we're doing calculations)
1727  // - if the start-end vector is zero we still progress
1728  const vectorField dirVec(end-start);
1729  const scalarField magSqrDirVec(magSqr(dirVec));
1730  const vectorField smallVec
1731  (
1732  rootSmall*dirVec
1733  + vector(rootVSmall,rootVSmall,rootVSmall)
1734  );
1735 
1736  // Copy to input and compact any hits
1737  labelList pointMap(start.size());
1738  pointField e0(start.size());
1739  pointField e1(start.size());
1740  label compactI = 0;
1741 
1742  info.setSize(hitInfo.size());
1743  forAll(hitInfo, pointi)
1744  {
1745  if (hitInfo[pointi].hit())
1746  {
1747  info[pointi].setSize(1);
1748  info[pointi][0] = hitInfo[pointi];
1749 
1750  point pt = hitInfo[pointi].hitPoint() + smallVec[pointi];
1751 
1752  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1753  {
1754  e0[compactI] = pt;
1755  e1[compactI] = end[pointi];
1756  pointMap[compactI] = pointi;
1757  compactI++;
1758  }
1759  }
1760  else
1761  {
1762  info[pointi].clear();
1763  }
1764  }
1765 
1766  e0.setSize(compactI);
1767  e1.setSize(compactI);
1768  pointMap.setSize(compactI);
1769 
1770  while (returnReduce(e0.size(), sumOp<label>()) > 0)
1771  {
1772  findLine
1773  (
1774  true, // nearestIntersection
1775  e0,
1776  e1,
1777  hitInfo
1778  );
1779 
1780 
1781  // Extract
1782  label compactI = 0;
1783  forAll(hitInfo, i)
1784  {
1785  if (hitInfo[i].hit())
1786  {
1787  label pointi = pointMap[i];
1788 
1789  label sz = info[pointi].size();
1790  info[pointi].setSize(sz+1);
1791  info[pointi][sz] = hitInfo[i];
1792 
1793  point pt = hitInfo[i].hitPoint() + smallVec[pointi];
1794 
1795  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1796  {
1797  e0[compactI] = pt;
1798  e1[compactI] = end[pointi];
1799  pointMap[compactI] = pointi;
1800  compactI++;
1801  }
1802  }
1803  }
1804 
1805  // Trim
1806  e0.setSize(compactI);
1807  e1.setSize(compactI);
1808  pointMap.setSize(compactI);
1809  }
1810 }
1811 
1812 
1814 (
1815  const List<pointIndexHit>& info,
1816  labelList& region
1817 ) const
1818 {
1819  if (!Pstream::parRun())
1820  {
1821  region.setSize(info.size());
1822  forAll(info, i)
1823  {
1824  if (info[i].hit())
1825  {
1826  region[i] = triSurface::operator[](info[i].index()).region();
1827  }
1828  else
1829  {
1830  region[i] = -1;
1831  }
1832  }
1833  return;
1834  }
1835 
1836 
1837  // Get query data (= local index of triangle)
1838  // ~~~~~~~~~~~~~~
1839 
1840  labelList triangleIndex(info.size());
1842  (
1843  calcLocalQueries
1844  (
1845  info,
1846  triangleIndex
1847  )
1848  );
1849  const distributionMap& map = mapPtr();
1850 
1851 
1852  // Do my tests
1853  // ~~~~~~~~~~~
1854 
1855  const triSurface& s = static_cast<const triSurface&>(*this);
1856 
1857  region.setSize(triangleIndex.size());
1858 
1859  forAll(triangleIndex, i)
1860  {
1861  label triI = triangleIndex[i];
1862  region[i] = s[triI].region();
1863  }
1864 
1865 
1866  // Send back results
1867  // ~~~~~~~~~~~~~~~~~
1868 
1869  map.reverseDistribute(info.size(), region);
1870 }
1871 
1872 
1874 (
1875  const List<pointIndexHit>& info,
1876  vectorField& normal
1877 ) const
1878 {
1879  if (!Pstream::parRun())
1880  {
1881  triSurfaceMesh::getNormal(info, normal);
1882  return;
1883  }
1884 
1885 
1886  // Get query data (= local index of triangle)
1887  // ~~~~~~~~~~~~~~
1888 
1889  labelList triangleIndex(info.size());
1891  (
1892  calcLocalQueries
1893  (
1894  info,
1895  triangleIndex
1896  )
1897  );
1898  const distributionMap& map = mapPtr();
1899 
1900 
1901  // Do my tests
1902  // ~~~~~~~~~~~
1903 
1904  const triSurface& s = static_cast<const triSurface&>(*this);
1905 
1906  normal.setSize(triangleIndex.size());
1907 
1908  forAll(triangleIndex, i)
1909  {
1910  label triI = triangleIndex[i];
1911  normal[i] = s[triI].normal(s.points());
1912  }
1913 
1914 
1915  // Send back results
1916  // ~~~~~~~~~~~~~~~~~
1917 
1918  map.reverseDistribute(info.size(), normal);
1919 }
1920 
1921 
1923 (
1924  const List<pointIndexHit>& info,
1925  labelList& values
1926 ) const
1927 {
1928  if (!Pstream::parRun())
1929  {
1930  triSurfaceMesh::getField(info, values);
1931  return;
1932  }
1933 
1934  if (foundObject<triSurfaceLabelField>("values"))
1935  {
1936  const triSurfaceLabelField& fld = lookupObject<triSurfaceLabelField>
1937  (
1938  "values"
1939  );
1940 
1941 
1942  // Get query data (= local index of triangle)
1943  // ~~~~~~~~~~~~~~
1944 
1945  labelList triangleIndex(info.size());
1947  (
1948  calcLocalQueries
1949  (
1950  info,
1951  triangleIndex
1952  )
1953  );
1954  const distributionMap& map = mapPtr();
1955 
1956 
1957  // Do my tests
1958  // ~~~~~~~~~~~
1959 
1960  values.setSize(triangleIndex.size());
1961 
1962  forAll(triangleIndex, i)
1963  {
1964  label triI = triangleIndex[i];
1965  values[i] = fld[triI];
1966  }
1967 
1968 
1969  // Send back results
1970  // ~~~~~~~~~~~~~~~~~
1971 
1972  map.reverseDistribute(info.size(), values);
1973  }
1974 }
1975 
1976 
1978 (
1979  const pointField& points,
1980  List<volumeType>& volType
1981 ) const
1982 {
1984  << "Volume type not supported for distributed surfaces."
1985  << exit(FatalError);
1986 }
1987 
1988 
1989 // Subset the part of surface that is overlapping bb.
1991 (
1992  const triSurface& s,
1993  const List<treeBoundBox>& bbs,
1994 
1995  labelList& subPointMap,
1996  labelList& subFaceMap
1997 )
1998 {
1999  // Determine what triangles to keep.
2000  boolList includedFace(s.size(), false);
2001 
2002  // Create a slightly larger bounding box.
2003  List<treeBoundBox> bbsX(bbs.size());
2004  const scalar eps = 1.0e-4;
2005  forAll(bbs, i)
2006  {
2007  const point mid = 0.5*(bbs[i].min() + bbs[i].max());
2008  const vector halfSpan = (1.0+eps)*(bbs[i].max() - mid);
2009 
2010  bbsX[i].min() = mid - halfSpan;
2011  bbsX[i].max() = mid + halfSpan;
2012  }
2013 
2014  forAll(s, triI)
2015  {
2016  const labelledTri& f = s[triI];
2017  const point& p0 = s.points()[f[0]];
2018  const point& p1 = s.points()[f[1]];
2019  const point& p2 = s.points()[f[2]];
2020 
2021  if (overlaps(bbsX, p0, p1, p2))
2022  {
2023  includedFace[triI] = true;
2024  }
2025  }
2026 
2027  return subsetMesh(s, includedFace, subPointMap, subFaceMap);
2028 }
2029 
2030 
2032 (
2033  const List<treeBoundBox>& bbs,
2034  const bool keepNonLocal,
2036  autoPtr<distributionMap>& pointMap
2037 )
2038 {
2039  // Get bbs of all domains
2040  // ~~~~~~~~~~~~~~~~~~~~~~
2041 
2042  {
2044 
2045  switch(distType_)
2046  {
2047  case FOLLOW:
2048  newProcBb[Pstream::myProcNo()].setSize(bbs.size());
2049  forAll(bbs, i)
2050  {
2051  newProcBb[Pstream::myProcNo()][i] = bbs[i];
2052  }
2053  Pstream::gatherList(newProcBb);
2054  Pstream::scatterList(newProcBb);
2055  break;
2056 
2057  case INDEPENDENT:
2058  newProcBb = independentlyDistributedBbs(*this);
2059  break;
2060 
2061  case FROZEN:
2062  return;
2063  break;
2064 
2065  default:
2067  << "Unsupported distribution type." << exit(FatalError);
2068  break;
2069  }
2070 
2071  if (newProcBb == procBb_)
2072  {
2073  return;
2074  }
2075  else
2076  {
2077  procBb_.transfer(newProcBb);
2078  dict_.set("bounds", procBb_[Pstream::myProcNo()]);
2079  }
2080  }
2081 
2082 
2083  // Debug information
2084  if (debug)
2085  {
2086  labelList nTris(Pstream::nProcs());
2087  nTris[Pstream::myProcNo()] = triSurface::size();
2088  Pstream::gatherList(nTris);
2089  Pstream::scatterList(nTris);
2090 
2092  << "before distribution:" << endl << "\tproc\ttris" << endl;
2093 
2094  forAll(nTris, proci)
2095  {
2096  Info<< '\t' << proci << '\t' << nTris[proci] << endl;
2097  }
2098  Info<< endl;
2099  }
2100 
2101 
2102  // Use procBbs to determine which faces go where
2103  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2104 
2105  labelListList faceSendMap(Pstream::nProcs());
2106  labelListList pointSendMap(Pstream::nProcs());
2107 
2108  forAll(procBb_, proci)
2109  {
2110  overlappingSurface
2111  (
2112  *this,
2113  procBb_[proci],
2114  pointSendMap[proci],
2115  faceSendMap[proci]
2116  );
2117 
2118  if (debug)
2119  {
2120  // Pout<< "Overlapping with proc " << proci
2121  // << " faces:" << faceSendMap[proci].size()
2122  // << " points:" << pointSendMap[proci].size() << endl << endl;
2123  }
2124  }
2125 
2126  if (keepNonLocal)
2127  {
2128  // Include in faceSendMap/pointSendMap the triangles that are
2129  // not mapped to any processor so they stay local.
2130 
2131  const triSurface& s = static_cast<const triSurface&>(*this);
2132 
2133  boolList includedFace(s.size(), true);
2134 
2135  forAll(faceSendMap, proci)
2136  {
2137  if (proci != Pstream::myProcNo())
2138  {
2139  forAll(faceSendMap[proci], i)
2140  {
2141  includedFace[faceSendMap[proci][i]] = false;
2142  }
2143  }
2144  }
2145 
2146  // Combine includedFace (all triangles that are not on any neighbour)
2147  // with overlap.
2148 
2149  forAll(faceSendMap[Pstream::myProcNo()], i)
2150  {
2151  includedFace[faceSendMap[Pstream::myProcNo()][i]] = true;
2152  }
2153 
2154  subsetMesh
2155  (
2156  s,
2157  includedFace,
2158  pointSendMap[Pstream::myProcNo()],
2159  faceSendMap[Pstream::myProcNo()]
2160  );
2161  }
2162 
2163 
2164  // Send over how many faces/points I need to receive
2165  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2166 
2167  labelListList faceSendSizes(Pstream::nProcs());
2168  faceSendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
2169  forAll(faceSendMap, proci)
2170  {
2171  faceSendSizes[Pstream::myProcNo()][proci] = faceSendMap[proci].size();
2172  }
2173  Pstream::gatherList(faceSendSizes);
2174  Pstream::scatterList(faceSendSizes);
2175 
2176 
2177 
2178  // Exchange surfaces
2179  // ~~~~~~~~~~~~~~~~~
2180 
2181  // Storage for resulting surface
2182  List<labelledTri> allTris;
2183  pointField allPoints;
2184 
2185  labelListList faceConstructMap(Pstream::nProcs());
2186  labelListList pointConstructMap(Pstream::nProcs());
2187 
2188 
2189  // My own surface first
2190  // ~~~~~~~~~~~~~~~~~~~~
2191 
2192  {
2193  labelList pointMap;
2194  triSurface subSurface
2195  (
2196  subsetMesh
2197  (
2198  *this,
2199  faceSendMap[Pstream::myProcNo()],
2200  pointMap
2201  )
2202  );
2203 
2204  allTris = subSurface;
2205  allPoints = subSurface.points();
2206 
2207  faceConstructMap[Pstream::myProcNo()] = identityMap
2208  (
2209  faceSendMap[Pstream::myProcNo()].size()
2210  );
2211  pointConstructMap[Pstream::myProcNo()] = identityMap
2212  (
2213  pointSendMap[Pstream::myProcNo()].size()
2214  );
2215  }
2216 
2217 
2218 
2219  // Send all
2220  // ~~~~~~~~
2221 
2222  forAll(faceSendSizes, proci)
2223  {
2224  if (proci != Pstream::myProcNo())
2225  {
2226  if (faceSendSizes[Pstream::myProcNo()][proci] > 0)
2227  {
2229 
2230  labelList pointMap;
2231  triSurface subSurface
2232  (
2233  subsetMesh
2234  (
2235  *this,
2236  faceSendMap[proci],
2237  pointMap
2238  )
2239  );
2240 
2241  // if (debug)
2242  //{
2243  // Pout<< "Sending to " << proci
2244  // << " faces:" << faceSendMap[proci].size()
2245  // << " points:" << subSurface.points().size() << endl
2246  // << endl;
2247  //}
2248 
2249  str << subSurface;
2250  }
2251  }
2252  }
2253 
2254 
2255  // Receive and merge all
2256  // ~~~~~~~~~~~~~~~~~~~~~
2257 
2258  forAll(faceSendSizes, proci)
2259  {
2260  if (proci != Pstream::myProcNo())
2261  {
2262  if (faceSendSizes[proci][Pstream::myProcNo()] > 0)
2263  {
2265 
2266  // Receive
2267  triSurface subSurface(str);
2268 
2269  // if (debug)
2270  //{
2271  // Pout<< "Received from " << proci
2272  // << " faces:" << subSurface.size()
2273  // << " points:" << subSurface.points().size() << endl
2274  // << endl;
2275  //}
2276 
2277  // Merge into allSurf
2278  merge
2279  (
2280  mergeDist_,
2281  subSurface,
2282  subSurface.points(),
2283 
2284  allTris,
2285  allPoints,
2286  faceConstructMap[proci],
2287  pointConstructMap[proci]
2288  );
2289 
2290  // if (debug)
2291  //{
2292  // Pout<< "Current merged surface : faces:" << allTris.size()
2293  // << " points:" << allPoints.size() << endl << endl;
2294  //}
2295  }
2296  }
2297  }
2298 
2299 
2300  faceMap.reset
2301  (
2302  new distributionMap
2303  (
2304  allTris.size(),
2305  move(faceSendMap),
2306  move(faceConstructMap)
2307  )
2308  );
2309  pointMap.reset
2310  (
2311  new distributionMap
2312  (
2313  allPoints.size(),
2314  move(pointSendMap),
2315  move(pointConstructMap)
2316  )
2317  );
2318 
2319  // Construct triSurface. Reuse storage.
2320  triSurface::operator=(triSurface(allTris, patches(), allPoints, true));
2321 
2322  clearOut();
2323 
2324  // Set the bounds() value to the boundBox of the undecomposed surface
2326 
2327  reduce(bounds().min(), minOp<point>());
2328  reduce(bounds().max(), maxOp<point>());
2329 
2330  // Regions stays same
2331  // Volume type stays same.
2332 
2333  distributeFields<label>(faceMap());
2334  distributeFields<scalar>(faceMap());
2335  distributeFields<vector>(faceMap());
2336  distributeFields<sphericalTensor>(faceMap());
2337  distributeFields<symmTensor>(faceMap());
2338  distributeFields<tensor>(faceMap());
2339 
2340  if (debug)
2341  {
2342  labelList nTris(Pstream::nProcs());
2343  nTris[Pstream::myProcNo()] = triSurface::size();
2344  Pstream::gatherList(nTris);
2345  Pstream::scatterList(nTris);
2346 
2348  << "after distribution:" << endl << "\tproc\ttris" << endl;
2349 
2350  forAll(nTris, proci)
2351  {
2352  Info<< '\t' << proci << '\t' << nTris[proci] << endl;
2353  }
2354  Info<< endl;
2355  }
2356 }
2357 
2358 
2360 (
2364  const bool write
2365 ) const
2366 {
2367  // Make sure dictionary goes to same directory as surface
2368  const_cast<fileName&>(dict_.instance()) = searchableSurface::instance();
2369 
2370  // Copy of triSurfaceMesh::writeObject except for the sorting of
2371  // triangles by region. This is done so we preserve region names,
2372  // even if locally we have zero triangles.
2373  {
2375 
2376  if (!mkDir(fullPath.path()))
2377  {
2378  return false;
2379  }
2380 
2381  // Important: preserve any zero-sized patches
2382  triSurface::write(fullPath, true);
2383 
2384  if (!isFile(fullPath))
2385  {
2386  return false;
2387  }
2388  }
2389 
2390  // Dictionary needs to be written in ascii - binary output not supported.
2391  return dict_.writeObject(IOstream::ASCII, ver, cmp, true);
2392 }
2393 
2394 
2396 {
2397  boundBox bb;
2398  label nPoints;
2399  PatchTools::calcBounds(static_cast<const triSurface&>(*this), bb, nPoints);
2400  reduce(bb.min(), minOp<point>());
2401  reduce(bb.max(), maxOp<point>());
2402 
2403  os << "Triangles : " << returnReduce(triSurface::size(), sumOp<label>())
2404  << endl
2405  << "Vertices : " << returnReduce(nPoints, sumOp<label>()) << endl
2406  << "Bounding Box : " << bb << endl;
2407 }
2408 
2409 
2410 // ************************************************************************* //
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:120
static const Form min
Definition: VectorSpace.H:121
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:60
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:66
static IOdictionary decomposeParDict(const Time &time)
Read and return the decomposeParDict.
static autoPtr< decompositionMethod > NewDistributor(const dictionary &decompositionDict)
Return a reference to the selected decomposition method.
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
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:158
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:1386
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:334
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
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
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:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
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
dimensioned< scalar > magSqr(const dimensioned< Type > &)
void invertManyToMany(const label len, const UList< InList > &, List< OutList > &)
Invert many-to-many.
Pair< point > segment
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)