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