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-2026 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"
29 #include "triangleFuncs.H"
30 #include "matchPoints.H"
31 #include "globalIndex.H"
32 #include "Time.H"
33 
34 #include "IFstream.H"
35 #include "decompositionMethod.H"
36 #include "geometric.H"
37 #include "vectorList.H"
38 #include "PackedBoolList.H"
39 #include "PatchTools.H"
40 #include "labelIOField.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47  namespace searchableSurfaces
48  {
50 
52  (
56  );
57 
59  (
62  dictionary,
63  distributedTriSurfaceMesh,
64  "distributedTriSurfaceMesh"
65  );
66  }
67 }
68 
69 const Foam::NamedEnum
70 <
72  3
74 {
75  "follow",
76  "independent",
77  "frozen"
78 };
79 
80 
81 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
82 
83 bool Foam::searchableSurfaces::distributedTriSurface::read()
84 {
85  // Get bb of all domains.
86  procBb_.setSize(Pstream::nProcs());
87 
88  procBb_[Pstream::myProcNo()] = List<treeBoundBox>(dict_.lookup("bounds"));
89  Pstream::gatherList(procBb_);
90  Pstream::scatterList(procBb_);
91 
92  // Distribution type
93  distType_ = distributionTypeNames_.read(dict_.lookup("distributionType"));
94 
95  // Merge distance
96  mergeDist_ = dict_.lookup<scalar>("mergeDistance");
97 
98  return true;
99 }
100 
101 
102 // Is segment fully local?
103 bool Foam::searchableSurfaces::distributedTriSurface::isLocal
104 (
105  const List<treeBoundBox>& myBbs,
106  const point& start,
107  const point& end
108 )
109 {
110  forAll(myBbs, bbI)
111  {
112  if (myBbs[bbI].contains(start) && myBbs[bbI].contains(end))
113  {
114  return true;
115  }
116  }
117  return false;
118 }
119 
120 
121 //void Foam::searchableSurfaces::distributedTriSurface::splitSegment
122 //(
123 // const label segmentI,
124 // const point& start,
125 // const point& end,
126 // const treeBoundBox& bb,
127 //
128 // DynamicList<segment>& allSegments,
129 // DynamicList<label>& allSegmentMap,
130 // DynamicList<label> sendMap
131 //) const
132 //{
133 // // Work points
134 // point clipPt0, clipPt1;
135 //
136 // if (bb.contains(start))
137 // {
138 // // start within, trim end to bb
139 // bool clipped = bb.intersects(end, start, clipPt0);
140 //
141 // if (clipped)
142 // {
143 // // segment from start to clippedStart passes
144 // // through proc.
145 // sendMap[proci].append(allSegments.size());
146 // allSegmentMap.append(segmentI);
147 // allSegments.append(segment(start, clipPt0));
148 // }
149 // }
150 // else if (bb.contains(end))
151 // {
152 // // end within, trim start to bb
153 // bool clipped = bb.intersects(start, end, clipPt0);
154 //
155 // if (clipped)
156 // {
157 // sendMap[proci].append(allSegments.size());
158 // allSegmentMap.append(segmentI);
159 // allSegments.append(segment(clipPt0, end));
160 // }
161 // }
162 // else
163 // {
164 // // trim both
165 // bool clippedStart = bb.intersects(start, end, clipPt0);
166 //
167 // if (clippedStart)
168 // {
169 // bool clippedEnd = bb.intersects(end, clipPt0, clipPt1);
170 //
171 // if (clippedEnd)
172 // {
173 // // middle part of segment passes through proc.
174 // sendMap[proci].append(allSegments.size());
175 // allSegmentMap.append(segmentI);
176 // allSegments.append(segment(clipPt0, clipPt1));
177 // }
178 // }
179 // }
180 //}
181 
182 
183 void Foam::searchableSurfaces::distributedTriSurface::distributeSegment
184 (
185  const label segmentI,
186  const point& start,
187  const point& end,
188 
189  DynamicList<segment>& allSegments,
190  DynamicList<label>& allSegmentMap,
191  List<DynamicList<label>>& sendMap
192 ) const
193 {
194  // 1. Fully local already handled outside. Note: retest is cheap.
195  if (isLocal(procBb_[Pstream::myProcNo()], start, end))
196  {
197  return;
198  }
199 
200 
201  // 2. If fully inside one other processor, then only need to send
202  // to that one processor even if it intersects another. Rare occurrence
203  // but cheap to test.
204  forAll(procBb_, proci)
205  {
206  if (proci != Pstream::myProcNo())
207  {
208  const List<treeBoundBox>& bbs = procBb_[proci];
209 
210  if (isLocal(bbs, start, end))
211  {
212  sendMap[proci].append(allSegments.size());
213  allSegmentMap.append(segmentI);
214  allSegments.append(segment(start, end));
215  return;
216  }
217  }
218  }
219 
220 
221  // 3. If not contained in single processor send to all intersecting
222  // processors.
223  forAll(procBb_, proci)
224  {
225  const List<treeBoundBox>& bbs = procBb_[proci];
226 
227  forAll(bbs, bbI)
228  {
229  const treeBoundBox& bb = bbs[bbI];
230 
231  // Scheme a: any processor that intersects the segment gets
232  // the segment.
233 
234  // Intersection point
235  point clipPt;
236 
237  if (bb.intersects(start, end, clipPt))
238  {
239  sendMap[proci].append(allSegments.size());
240  allSegmentMap.append(segmentI);
241  allSegments.append(segment(start, end));
242  }
243 
244  // Alternative: any processor only gets clipped bit of
245  // segment. This gives small problems with additional
246  // truncation errors.
247  // splitSegment
248  //(
249  // segmentI,
250  // start,
251  // end,
252  // bb,
253  //
254  // allSegments,
255  // allSegmentMap,
256  // sendMap[proci]
257  //);
258  }
259  }
260 }
261 
262 
264 Foam::searchableSurfaces::distributedTriSurface::distributeSegments
265 (
266  const pointField& start,
267  const pointField& end,
268 
269  List<segment>& allSegments,
270  labelList& allSegmentMap
271 ) const
272 {
273  // Determine send map
274  // ~~~~~~~~~~~~~~~~~~
275 
276  labelListList sendMap(Pstream::nProcs());
277 
278  {
279  // Since intersection test is quite expensive compared to memory
280  // allocation we use DynamicList to immediately store the segment
281  // in the correct bin.
282 
283  // Segments to test
284  DynamicList<segment> dynAllSegments(start.size());
285  // Original index of segment
286  DynamicList<label> dynAllSegmentMap(start.size());
287  // Per processor indices into allSegments to send
289 
290  forAll(start, segmentI)
291  {
292  distributeSegment
293  (
294  segmentI,
295  start[segmentI],
296  end[segmentI],
297 
298  dynAllSegments,
299  dynAllSegmentMap,
300  dynSendMap
301  );
302  }
303 
304  // Convert dynamicList to labelList
305  sendMap.setSize(Pstream::nProcs());
306  forAll(sendMap, proci)
307  {
308  dynSendMap[proci].shrink();
309  sendMap[proci].transfer(dynSendMap[proci]);
310  }
311 
312  allSegments.transfer(dynAllSegments.shrink());
313  allSegmentMap.transfer(dynAllSegmentMap.shrink());
314  }
315 
316 
317  // Send over how many I need to receive.
318  labelListList sendSizes(Pstream::nProcs());
319  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
320  forAll(sendMap, proci)
321  {
322  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
323  }
324  Pstream::gatherList(sendSizes);
325  Pstream::scatterList(sendSizes);
326 
327 
328  // Determine order of receiving
329  labelListList constructMap(Pstream::nProcs());
330 
331  // My local segments first
332  constructMap[Pstream::myProcNo()] = identityMap
333  (
334  sendMap[Pstream::myProcNo()].size()
335  );
336 
337  label segmentI = constructMap[Pstream::myProcNo()].size();
338  forAll(constructMap, proci)
339  {
340  if (proci != Pstream::myProcNo())
341  {
342  // What I need to receive is what other processor is sending to me.
343  label nRecv = sendSizes[proci][Pstream::myProcNo()];
344  constructMap[proci].setSize(nRecv);
345 
346  for (label i = 0; i < nRecv; i++)
347  {
348  constructMap[proci][i] = segmentI++;
349  }
350  }
351  }
352 
353  return autoPtr<distributionMap>
354  (
355  new distributionMap
356  (
357  segmentI, // size after construction
358  move(sendMap),
359  move(constructMap)
360  )
361  );
362 }
363 
364 
365 void Foam::searchableSurfaces::distributedTriSurface::findLine
366 (
367  const bool nearestIntersection,
368  const pointField& start,
369  const pointField& end,
370  List<pointIndexHit>& info
371 ) const
372 {
373  const indexedOctree<treeDataTriSurface>& octree = tree();
374 
375  // Initialise
376  info.setSize(start.size());
377  forAll(info, i)
378  {
379  info[i].setMiss();
380  }
381 
382  if (!Pstream::parRun())
383  {
384  forAll(start, i)
385  {
386  if (nearestIntersection)
387  {
388  info[i] = octree.findLine(start[i], end[i]);
389  }
390  else
391  {
392  info[i] = octree.findLineAny(start[i], end[i]);
393  }
394  }
395  }
396  else
397  {
398  // Important:force synchronised construction of indexing
399  const globalIndex& triIndexer = globalTris();
400 
401 
402  // Do any local queries
403  // ~~~~~~~~~~~~~~~~~~~~
404 
405  label nLocal = 0;
406 
407  forAll(start, i)
408  {
409  if (isLocal(procBb_[Pstream::myProcNo()], start[i], end[i]))
410  {
411  if (nearestIntersection)
412  {
413  info[i] = octree.findLine(start[i], end[i]);
414  }
415  else
416  {
417  info[i] = octree.findLineAny(start[i], end[i]);
418  }
419 
420  if (info[i].hit())
421  {
422  info[i].setIndex(triIndexer.toGlobal(info[i].index()));
423  }
424  nLocal++;
425  }
426  }
427 
428 
429  if
430  (
431  returnReduce(nLocal, sumOp<label>())
432  < returnReduce(start.size(), sumOp<label>())
433  )
434  {
435  // Not all can be resolved locally. Build segments and map,
436  // send over segments, do intersections, send back and merge.
437 
438 
439  // Construct queries (segments)
440  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
441 
442  // Segments to test
443  List<segment> allSegments(start.size());
444  // Original index of segment
445  labelList allSegmentMap(start.size());
446 
447  const autoPtr<distributionMap> mapPtr
448  (
449  distributeSegments
450  (
451  start,
452  end,
453  allSegments,
454  allSegmentMap
455  )
456  );
457  const distributionMap& map = mapPtr();
458 
459  label nOldAllSegments = allSegments.size();
460 
461 
462  // Exchange the segments
463  // ~~~~~~~~~~~~~~~~~~~~~
464 
465  map.distribute(allSegments);
466 
467 
468  // Do tests I need to do
469  // ~~~~~~~~~~~~~~~~~~~~~
470 
471  // Intersections
472  List<pointIndexHit> intersections(allSegments.size());
473 
474  forAll(allSegments, i)
475  {
476  if (nearestIntersection)
477  {
478  intersections[i] = octree.findLine
479  (
480  allSegments[i].first(),
481  allSegments[i].second()
482  );
483  }
484  else
485  {
486  intersections[i] = octree.findLineAny
487  (
488  allSegments[i].first(),
489  allSegments[i].second()
490  );
491  }
492 
493  // Convert triangle index to global numbering
494  if (intersections[i].hit())
495  {
496  intersections[i].setIndex
497  (
498  triIndexer.toGlobal(intersections[i].index())
499  );
500  }
501  }
502 
503 
504  // Exchange the intersections (opposite to segments)
505  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
506 
507  map.reverseDistribute(nOldAllSegments, intersections);
508 
509 
510  // Extract the hits
511  // ~~~~~~~~~~~~~~~~
512 
513  forAll(intersections, i)
514  {
515  const pointIndexHit& allInfo = intersections[i];
516  label segmentI = allSegmentMap[i];
517  pointIndexHit& hitInfo = info[segmentI];
518 
519  if (allInfo.hit())
520  {
521  if (!hitInfo.hit())
522  {
523  // No intersection yet so take this one
524  hitInfo = allInfo;
525  }
526  else if (nearestIntersection)
527  {
528  // Nearest intersection
529  if
530  (
531  magSqr(allInfo.hitPoint()-start[segmentI])
532  < magSqr(hitInfo.hitPoint()-start[segmentI])
533  )
534  {
535  hitInfo = allInfo;
536  }
537  }
538  }
539  }
540  }
541  }
542 }
543 
544 
545 // Exchanges indices to the processor they come from.
546 // - calculates exchange map
547 // - uses map to calculate local triangle index
549 Foam::searchableSurfaces::distributedTriSurface::calcLocalQueries
550 (
551  const List<pointIndexHit>& info,
552  labelList& triangleIndex
553 ) const
554 {
555  triangleIndex.setSize(info.size());
556 
557  const globalIndex& triIndexer = globalTris();
558 
559 
560  // Determine send map
561  // ~~~~~~~~~~~~~~~~~~
562 
563  // Since determining which processor the query should go to is
564  // cheap we do a multi-pass algorithm to save some memory temporarily.
565 
566  // 1. Count
567  labelList nSend(Pstream::nProcs(), 0);
568 
569  forAll(info, i)
570  {
571  if (info[i].hit())
572  {
573  label proci = triIndexer.whichProcID(info[i].index());
574  nSend[proci]++;
575  }
576  }
577 
578  // 2. Size sendMap
579  labelListList sendMap(Pstream::nProcs());
580  forAll(nSend, proci)
581  {
582  sendMap[proci].setSize(nSend[proci]);
583  nSend[proci] = 0;
584  }
585 
586  // 3. Fill sendMap
587  forAll(info, i)
588  {
589  if (info[i].hit())
590  {
591  label proci = triIndexer.whichProcID(info[i].index());
592  triangleIndex[i] = triIndexer.toLocal(proci, info[i].index());
593  sendMap[proci][nSend[proci]++] = i;
594  }
595  else
596  {
597  triangleIndex[i] = -1;
598  }
599  }
600 
601 
602  // Send over how many I need to receive
603  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
604 
605  labelListList sendSizes(Pstream::nProcs());
606  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
607  forAll(sendMap, proci)
608  {
609  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
610  }
611  Pstream::gatherList(sendSizes);
612  Pstream::scatterList(sendSizes);
613 
614 
615  // Determine receive map
616  // ~~~~~~~~~~~~~~~~~~~~~
617 
618  labelListList constructMap(Pstream::nProcs());
619 
620  // My local segments first
621  constructMap[Pstream::myProcNo()] = identityMap
622  (
623  sendMap[Pstream::myProcNo()].size()
624  );
625 
626  label segmentI = constructMap[Pstream::myProcNo()].size();
627  forAll(constructMap, proci)
628  {
629  if (proci != Pstream::myProcNo())
630  {
631  // What I need to receive is what other processor is sending to me.
632  label nRecv = sendSizes[proci][Pstream::myProcNo()];
633  constructMap[proci].setSize(nRecv);
634 
635  for (label i = 0; i < nRecv; i++)
636  {
637  constructMap[proci][i] = segmentI++;
638  }
639  }
640  }
641 
642 
643  // Pack into distribution map
644  // ~~~~~~~~~~~~~~~~~~~~~~~~~~
645 
646  autoPtr<distributionMap> mapPtr
647  (
648  new distributionMap
649  (
650  segmentI, // size after construction
651  move(sendMap),
652  move(constructMap)
653  )
654  );
655  const distributionMap& map = mapPtr();
656 
657 
658  // Send over queries
659  // ~~~~~~~~~~~~~~~~~
660 
661  map.distribute(triangleIndex);
662 
663 
664  return mapPtr;
665 }
666 
667 
669 Foam::searchableSurfaces::distributedTriSurface::calcOverlappingProcs
670 (
671  const point& centre,
672  const scalar radiusSqr,
673  boolList& overlaps
674 ) const
675 {
676  overlaps = false;
677  label nOverlaps = 0;
678 
679  forAll(procBb_, proci)
680  {
681  const List<treeBoundBox>& bbs = procBb_[proci];
682 
683  forAll(bbs, bbI)
684  {
685  if (bbs[bbI].overlaps(centre, radiusSqr))
686  {
687  overlaps[proci] = true;
688  nOverlaps++;
689  break;
690  }
691  }
692  }
693  return nOverlaps;
694 }
695 
696 
697 // Generate queries for parallel distance calculation
698 // - calculates exchange map
699 // - uses map to exchange points and radius
701 Foam::searchableSurfaces::distributedTriSurface::calcLocalQueries
702 (
703  const pointField& centres,
704  const scalarField& radiusSqr,
705 
706  pointField& allCentres,
707  scalarField& allRadiusSqr,
708  labelList& allSegmentMap
709 ) const
710 {
711  // Determine queries
712  // ~~~~~~~~~~~~~~~~~
713 
714  labelListList sendMap(Pstream::nProcs());
715 
716  {
717  // Queries
718  DynamicList<point> dynAllCentres(centres.size());
719  DynamicList<scalar> dynAllRadiusSqr(centres.size());
720  // Original index of segment
721  DynamicList<label> dynAllSegmentMap(centres.size());
722  // Per processor indices into allSegments to send
724 
725  // Work array - whether processor bb overlaps the bounding sphere.
726  boolList procBbOverlaps(Pstream::nProcs());
727 
728  forAll(centres, centreI)
729  {
730  // Find the processor this sample+radius overlaps.
731  calcOverlappingProcs
732  (
733  centres[centreI],
734  radiusSqr[centreI],
735  procBbOverlaps
736  );
737 
738  forAll(procBbOverlaps, proci)
739  {
740  if (proci != Pstream::myProcNo() && procBbOverlaps[proci])
741  {
742  dynSendMap[proci].append(dynAllCentres.size());
743  dynAllSegmentMap.append(centreI);
744  dynAllCentres.append(centres[centreI]);
745  dynAllRadiusSqr.append(radiusSqr[centreI]);
746  }
747  }
748  }
749 
750  // Convert dynamicList to labelList
751  sendMap.setSize(Pstream::nProcs());
752  forAll(sendMap, proci)
753  {
754  dynSendMap[proci].shrink();
755  sendMap[proci].transfer(dynSendMap[proci]);
756  }
757 
758  allCentres.transfer(dynAllCentres.shrink());
759  allRadiusSqr.transfer(dynAllRadiusSqr.shrink());
760  allSegmentMap.transfer(dynAllSegmentMap.shrink());
761  }
762 
763 
764  // Send over how many I need to receive.
765  labelListList sendSizes(Pstream::nProcs());
766  sendSizes[Pstream::myProcNo()].setSize(Pstream::nProcs());
767  forAll(sendMap, proci)
768  {
769  sendSizes[Pstream::myProcNo()][proci] = sendMap[proci].size();
770  }
771  Pstream::gatherList(sendSizes);
772  Pstream::scatterList(sendSizes);
773 
774 
775  // Determine order of receiving
776  labelListList constructMap(Pstream::nProcs());
777 
778  // My local segments first
779  constructMap[Pstream::myProcNo()] = identityMap
780  (
781  sendMap[Pstream::myProcNo()].size()
782  );
783 
784  label segmentI = constructMap[Pstream::myProcNo()].size();
785  forAll(constructMap, proci)
786  {
787  if (proci != Pstream::myProcNo())
788  {
789  // What I need to receive is what other processor is sending to me.
790  label nRecv = sendSizes[proci][Pstream::myProcNo()];
791  constructMap[proci].setSize(nRecv);
792 
793  for (label i = 0; i < nRecv; i++)
794  {
795  constructMap[proci][i] = segmentI++;
796  }
797  }
798  }
799 
800  autoPtr<distributionMap> mapPtr
801  (
802  new distributionMap
803  (
804  segmentI, // size after construction
805  move(sendMap),
806  move(constructMap)
807  )
808  );
809  return mapPtr;
810 }
811 
812 
813 // Find bounding boxes that guarantee a more or less uniform distribution
814 // of triangles. Decomposition in here is only used to get the bounding
815 // boxes, actual decomposition is done later on.
816 // Returns a per processor a list of bounding boxes that most accurately
817 // describe the shape. For now just a single bounding box per processor but
818 // optimisation might be to determine a better fitting shape.
820 Foam::searchableSurfaces::distributedTriSurface::independentlyDistributedBbs
821 (
822  const Foam::triSurface& s
823 )
824 {
825  if (!distributor_.valid())
826  {
827  // Use current distributor.
828  // Note: or always use hierarchical?
830  (
832  );
833 
834  if (!isA<decompositionMethods::geometric>(distributor_()))
835  {
837  << "The decomposition method " << distributor_().typeName
838  << " is not a geometric decomposition method." << endl
839  << "Only geometric decomposition methods are currently"
840  << " supported."
841  << exit(FatalError);
842  }
843  }
844 
845  // Do decomposition according to triangle centre
846  pointField triCentres(s.size());
847  forAll(s, triI)
848  {
849  triCentres[triI] = s[triI].centre(s.points());
850  }
851 
852 
853  decompositionMethods::geometric& distributor =
854  refCast<decompositionMethods::geometric>(distributor_());
855 
856  // Do the actual decomposition
857  labelList distribution(distributor.decompose(triCentres));
858 
859  // Find bounding box for all triangles on new distribution.
860 
861  // Initialise to inverted box (vGreat, -vGreat)
863  forAll(bbs, proci)
864  {
865  bbs[proci].setSize(1);
866  // bbs[proci][0] = boundBox::invertedBox;
867  bbs[proci][0].min() = point( vGreat, vGreat, vGreat);
868  bbs[proci][0].max() = point(-vGreat, -vGreat, -vGreat);
869  }
870 
871  forAll(s, triI)
872  {
873  point& bbMin = bbs[distribution[triI]][0].min();
874  point& bbMax = bbs[distribution[triI]][0].max();
875 
876  const Foam::triSurface::FaceType& f = s[triI];
877  forAll(f, fp)
878  {
879  const point& pt = s.points()[f[fp]];
880  bbMin = ::Foam::min(bbMin, pt);
881  bbMax = ::Foam::max(bbMax, pt);
882  }
883  }
884 
885  // Now combine for all processors and convert to correct format.
886  forAll(bbs, proci)
887  {
888  forAll(bbs[proci], i)
889  {
890  reduce(bbs[proci][i].min(), minOp<point>());
891  reduce(bbs[proci][i].max(), maxOp<point>());
892  }
893  }
894  return bbs;
895 }
896 
897 
898 // Does any part of triangle overlap bb.
900 (
901  const List<treeBoundBox>& bbs,
902  const point& p0,
903  const point& p1,
904  const point& p2
905 )
906 {
907  forAll(bbs, bbI)
908  {
909  const treeBoundBox& bb = bbs[bbI];
910 
911  treeBoundBox triBb(p0, p0);
912  triBb.min() = min(triBb.min(), p1);
913  triBb.min() = min(triBb.min(), p2);
914 
915  triBb.max() = max(triBb.max(), p1);
916  triBb.max() = max(triBb.max(), p2);
917 
918  // Exact test of triangle intersecting bb
919 
920  // Quick rejection. If whole bounding box of tri is outside cubeBb then
921  // there will be no intersection.
922  if (bb.overlaps(triBb))
923  {
924  // Check if one or more triangle point inside
925  if (bb.contains(p0) || bb.contains(p1) || bb.contains(p2))
926  {
927  // One or more points inside
928  return true;
929  }
930 
931  // Now we have the difficult case: all points are outside but
932  // connecting edges might go through cube. Use fast intersection
933  // of bounding box.
934  bool intersect = triangleFuncs::intersectBb(p0, p1, p2, bb);
935 
936  if (intersect)
937  {
938  return true;
939  }
940  }
941  }
942  return false;
943 }
944 
945 
946 void Foam::searchableSurfaces::distributedTriSurface::subsetMeshMap
947 (
948  const Foam::triSurface& s,
949  const boolList& include,
950  const label nIncluded,
951  labelList& newToOldPoints,
952  labelList& oldToNewPoints,
953  labelList& newToOldFaces
954 )
955 {
956  newToOldFaces.setSize(nIncluded);
957  newToOldPoints.setSize(s.points().size());
958  oldToNewPoints.setSize(s.points().size());
959  oldToNewPoints = -1;
960  {
961  label facei = 0;
962  label pointi = 0;
963 
964  forAll(include, oldFacei)
965  {
966  if (include[oldFacei])
967  {
968  // Store new faces compact
969  newToOldFaces[facei++] = oldFacei;
970 
971  // Renumber labels for face
972  const Foam::triSurface::FaceType& f = s[oldFacei];
973 
974  forAll(f, fp)
975  {
976  label oldPointi = f[fp];
977 
978  if (oldToNewPoints[oldPointi] == -1)
979  {
980  oldToNewPoints[oldPointi] = pointi;
981  newToOldPoints[pointi++] = oldPointi;
982  }
983  }
984  }
985  }
986  newToOldPoints.setSize(pointi);
987  }
988 }
989 
990 
991 Foam::triSurface Foam::searchableSurfaces::distributedTriSurface::subsetMesh
992 (
993  const Foam::triSurface& s,
994  const labelList& newToOldPoints,
995  const labelList& oldToNewPoints,
996  const labelList& newToOldFaces
997 )
998 {
999  // Extract points
1000  pointField newPoints(newToOldPoints.size());
1001  forAll(newToOldPoints, i)
1002  {
1003  newPoints[i] = s.points()[newToOldPoints[i]];
1004  }
1005  // Extract faces
1006  List<labelledTri> newTriangles(newToOldFaces.size());
1007 
1008  forAll(newToOldFaces, i)
1009  {
1010  // Get old vertex labels
1011  const labelledTri& tri = s[newToOldFaces[i]];
1012 
1013  newTriangles[i][0] = oldToNewPoints[tri[0]];
1014  newTriangles[i][1] = oldToNewPoints[tri[1]];
1015  newTriangles[i][2] = oldToNewPoints[tri[2]];
1016  newTriangles[i].region() = tri.region();
1017  }
1018 
1019  // Reuse storage.
1020  return Foam::triSurface(newTriangles, s.patches(), newPoints, true);
1021 }
1022 
1023 
1024 Foam::triSurface Foam::searchableSurfaces::distributedTriSurface::subsetMesh
1025 (
1026  const Foam::triSurface& s,
1027  const boolList& include,
1028  labelList& newToOldPoints,
1029  labelList& newToOldFaces
1030 )
1031 {
1032  label n = 0;
1033 
1034  forAll(include, i)
1035  {
1036  if (include[i])
1037  {
1038  n++;
1039  }
1040  }
1041 
1042  labelList oldToNewPoints;
1043  subsetMeshMap
1044  (
1045  s,
1046  include,
1047  n,
1048  newToOldPoints,
1049  oldToNewPoints,
1050  newToOldFaces
1051  );
1052 
1053  return subsetMesh
1054  (
1055  s,
1056  newToOldPoints,
1057  oldToNewPoints,
1058  newToOldFaces
1059  );
1060 }
1061 
1062 
1063 Foam::triSurface Foam::searchableSurfaces::distributedTriSurface::subsetMesh
1064 (
1065  const Foam::triSurface& s,
1066  const labelList& newToOldFaces,
1067  labelList& newToOldPoints
1068 )
1069 {
1070  const boolList include
1071  (
1072  createWithValues<boolList>
1073  (
1074  s.size(),
1075  false,
1076  newToOldFaces,
1077  true
1078  )
1079  );
1080 
1081  newToOldPoints.setSize(s.points().size());
1082  labelList oldToNewPoints(s.points().size(), -1);
1083  {
1084  label pointi = 0;
1085 
1086  forAll(include, oldFacei)
1087  {
1088  if (include[oldFacei])
1089  {
1090  // Renumber labels for face
1091  const Foam::triSurface::FaceType& f = s[oldFacei];
1092 
1093  forAll(f, fp)
1094  {
1095  label oldPointi = f[fp];
1096 
1097  if (oldToNewPoints[oldPointi] == -1)
1098  {
1099  oldToNewPoints[oldPointi] = pointi;
1100  newToOldPoints[pointi++] = oldPointi;
1101  }
1102  }
1103  }
1104  }
1105  newToOldPoints.setSize(pointi);
1106  }
1107 
1108  return subsetMesh
1109  (
1110  s,
1111  newToOldPoints,
1112  oldToNewPoints,
1113  newToOldFaces
1114  );
1115 }
1116 
1117 
1118 Foam::label Foam::searchableSurfaces::distributedTriSurface::findTriangle
1119 (
1120  const List<labelledTri>& allFaces,
1121  const labelListList& allPointFaces,
1122  const labelledTri& otherF
1123 )
1124 {
1125  // allFaces connected to otherF[0]
1126  const labelList& pFaces = allPointFaces[otherF[0]];
1127 
1128  forAll(pFaces, i)
1129  {
1130  const labelledTri& f = allFaces[pFaces[i]];
1131 
1132  if (f.region() == otherF.region())
1133  {
1134  // Find index of otherF[0]
1135  label fp0 = findIndex(f, otherF[0]);
1136  // Check rest of triangle in same order
1137  label fp1 = f.fcIndex(fp0);
1138  label fp2 = f.fcIndex(fp1);
1139 
1140  if (f[fp1] == otherF[1] && f[fp2] == otherF[2])
1141  {
1142  return pFaces[i];
1143  }
1144  }
1145  }
1146  return -1;
1147 }
1148 
1149 
1150 // Merge into allSurf.
1151 void Foam::searchableSurfaces::distributedTriSurface::merge
1152 (
1153  const scalar mergeDist,
1154  const List<labelledTri>& subTris,
1155  const pointField& subPoints,
1156 
1157  List<labelledTri>& allTris,
1158  pointField& allPoints,
1159 
1160  labelList& faceConstructMap,
1161  labelList& pointConstructMap
1162 )
1163 {
1164  labelList subToAll;
1165  matchPoints
1166  (
1167  subPoints,
1168  allPoints,
1169  scalarField(subPoints.size(), mergeDist), // match distance
1170  false, // verbose
1171  pointConstructMap
1172  );
1173 
1174  label nOldAllPoints = allPoints.size();
1175 
1176 
1177  // Add all unmatched points
1178  // ~~~~~~~~~~~~~~~~~~~~~~~~
1179 
1180  label allPointi = nOldAllPoints;
1181  forAll(pointConstructMap, pointi)
1182  {
1183  if (pointConstructMap[pointi] == -1)
1184  {
1185  pointConstructMap[pointi] = allPointi++;
1186  }
1187  }
1188 
1189  if (allPointi > nOldAllPoints)
1190  {
1191  allPoints.setSize(allPointi);
1192 
1193  forAll(pointConstructMap, pointi)
1194  {
1195  if (pointConstructMap[pointi] >= nOldAllPoints)
1196  {
1197  allPoints[pointConstructMap[pointi]] = subPoints[pointi];
1198  }
1199  }
1200  }
1201 
1202 
1203  // To check whether triangles are same we use pointFaces.
1204  labelListList allPointFaces;
1205  invertManyToMany(nOldAllPoints, allTris, allPointFaces);
1206 
1207 
1208  // Add all unmatched triangles
1209  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1210 
1211  label allTriI = allTris.size();
1212  allTris.setSize(allTriI + subTris.size());
1213 
1214  faceConstructMap.setSize(subTris.size());
1215 
1216  forAll(subTris, triI)
1217  {
1218  const labelledTri& subTri = subTris[triI];
1219 
1220  // Get triangle in new numbering
1221  labelledTri mappedTri
1222  (
1223  pointConstructMap[subTri[0]],
1224  pointConstructMap[subTri[1]],
1225  pointConstructMap[subTri[2]],
1226  subTri.region()
1227  );
1228 
1229 
1230  // Check if all points were already in surface
1231  bool fullMatch = true;
1232 
1233  forAll(mappedTri, fp)
1234  {
1235  if (mappedTri[fp] >= nOldAllPoints)
1236  {
1237  fullMatch = false;
1238  break;
1239  }
1240  }
1241 
1242  if (fullMatch)
1243  {
1244  // All three points are mapped to old points. See if same
1245  // triangle.
1246  label i = findTriangle
1247  (
1248  allTris,
1249  allPointFaces,
1250  mappedTri
1251  );
1252 
1253  if (i == -1)
1254  {
1255  // Add
1256  faceConstructMap[triI] = allTriI;
1257  allTris[allTriI] = mappedTri;
1258  allTriI++;
1259  }
1260  else
1261  {
1262  faceConstructMap[triI] = i;
1263  }
1264  }
1265  else
1266  {
1267  // Add
1268  faceConstructMap[triI] = allTriI;
1269  allTris[allTriI] = mappedTri;
1270  allTriI++;
1271  }
1272  }
1273  allTris.setSize(allTriI);
1274 }
1275 
1276 
1277 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1278 
1280 (
1281  const IOobject& io,
1282  const Foam::triSurface& s,
1283  const dictionary& dict
1284 )
1285 :
1286  triSurface(io, s),
1287  dict_
1288  (
1289  IOobject
1290  (
1291  searchableSurface::name() + "Dict",
1292  searchableSurface::instance(),
1293  searchableSurface::local(),
1294  searchableSurface::db(),
1295  searchableSurface::NO_READ,
1296  searchableSurface::writeOpt(),
1297  searchableSurface::registerObject()
1298  ),
1299  dict
1300  )
1301 {
1302  read();
1303 
1304  reduce(bounds().min(), minOp<point>());
1305  reduce(bounds().max(), maxOp<point>());
1306 
1307  if (debug)
1308  {
1309  InfoInFunction << "Constructed from triSurface:" << endl;
1310  writeStats(Info);
1311 
1312  labelList nTris(Pstream::nProcs());
1314  Pstream::gatherList(nTris);
1315  Pstream::scatterList(nTris);
1316 
1317  Info<< endl<< "\tproc\ttris\tbb" << endl;
1318  forAll(nTris, proci)
1319  {
1320  Info<< '\t' << proci << '\t' << nTris[proci]
1321  << '\t' << procBb_[proci] << endl;
1322  }
1323  Info<< endl;
1324  }
1325 }
1326 
1327 
1329 (
1330  const IOobject& io
1331 )
1332 :
1333  triSurface
1334  (
1335  IOobject
1336  (
1337  io.name(),
1338  io.time().findInstance(io.local(), word::null),
1339  io.local(),
1340  io.db(),
1341  io.readOpt(),
1342  io.writeOpt(),
1343  io.registerObject()
1344  ),
1345  false
1346  ),
1347  dict_
1348  (
1349  IOobject
1350  (
1351  searchableSurface::name() + "Dict",
1352  searchableSurface::instance(),
1353  searchableSurface::local(),
1354  searchableSurface::db(),
1355  searchableSurface::readOpt(),
1356  searchableSurface::writeOpt(),
1357  searchableSurface::registerObject()
1358  )
1359  )
1360 {
1361  if
1362  (
1363  Pstream::parRun()
1364  && (
1365  dict_.readOpt() == IOobject::MUST_READ
1367  )
1368  && (
1371  )
1372  )
1373  {
1375  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1376  << " Modify the entry fileModificationChecking\n"
1377  << " in the etc/controlDict.\n"
1378  << " Use 'timeStamp' instead."
1379  << exit(FatalError);
1380  }
1381 
1382  read();
1383 
1384  reduce(bounds().min(), minOp<point>());
1385  reduce(bounds().max(), maxOp<point>());
1386 
1387  if (debug)
1388  {
1389  InfoInFunction << "Read distributedTriSurface from "
1390  << searchableSurface::objectPath() << ':' << endl;
1391  writeStats(Info);
1392 
1393  labelList nTris(Pstream::nProcs());
1395  Pstream::gatherList(nTris);
1396  Pstream::scatterList(nTris);
1397 
1398  Info<< endl<< "\tproc\ttris\tbb" << endl;
1399  forAll(nTris, proci)
1400  {
1401  Info<< '\t' << proci << '\t' << nTris[proci]
1402  << '\t' << procBb_[proci] << endl;
1403  }
1404  Info<< endl;
1405  }
1406 }
1407 
1408 
1410 (
1411  const IOobject& io,
1412  const dictionary& dict
1413 )
1414 :
1415  // triSurface(io, dict),
1416  triSurface
1417  (
1418  IOobject
1419  (
1420  io.name(),
1421  io.time().findInstance(io.local(), word::null),
1422  io.local(),
1423  io.db(),
1424  io.readOpt(),
1425  io.writeOpt(),
1426  io.registerObject()
1427  ),
1428  dict,
1429  false
1430  ),
1431  dict_
1432  (
1433  IOobject
1434  (
1435  searchableSurface::name() + "Dict",
1436  searchableSurface::instance(),
1437  searchableSurface::local(),
1438  searchableSurface::db(),
1439  searchableSurface::readOpt(),
1440  searchableSurface::writeOpt(),
1441  searchableSurface::registerObject()
1442  )
1443  )
1444 {
1445  if
1446  (
1447  Pstream::parRun()
1448  && (
1449  dict_.readOpt() == IOobject::MUST_READ
1451  )
1452  && (
1455  )
1456  )
1457  {
1459  << " using 'timeStampMaster' or 'inotifyMaster.'\n"
1460  << " Modify the entry fileModificationChecking\n"
1461  << " in the etc/controlDict.\n"
1462  << " Use 'timeStamp' instead."
1463  << exit(FatalError);
1464  }
1465 
1466  read();
1467 
1468  reduce(bounds().min(), minOp<point>());
1469  reduce(bounds().max(), maxOp<point>());
1470 
1471  if (debug)
1472  {
1473  InfoInFunction << "Read distributedTriSurface from "
1474  << searchableSurface::objectPath() << " and dictionary:" << endl;
1475  writeStats(Info);
1476 
1477  labelList nTris(Pstream::nProcs());
1479  Pstream::gatherList(nTris);
1480  Pstream::scatterList(nTris);
1481 
1482  Info<< endl<< "\tproc\ttris\tbb" << endl;
1483  forAll(nTris, proci)
1484  {
1485  Info<< '\t' << proci << '\t' << nTris[proci]
1486  << '\t' << procBb_[proci] << endl;
1487  }
1488  Info<< endl;
1489  }
1490 }
1491 
1492 
1493 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1494 
1497 {
1498  clearOut();
1499 }
1500 
1501 
1503 {
1504  globalTris_.clear();
1506 }
1507 
1508 
1509 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1510 
1512 globalTris() const
1513 {
1514  if (!globalTris_.valid())
1515  {
1516  globalTris_.reset(new globalIndex(triSurface::size()));
1517  }
1518  return globalTris_;
1519 }
1520 
1521 
1523 (
1524  const pointField& samples,
1525  const scalarField& nearestDistSqr,
1526  List<pointIndexHit>& info
1527 ) const
1528 {
1529  const indexedOctree<treeDataTriSurface>& octree = tree();
1530 
1531  // Important:force synchronised construction of indexing
1532  const globalIndex& triIndexer = globalTris();
1533 
1534 
1535  // Initialise
1536  // ~~~~~~~~~~
1537 
1538  info.setSize(samples.size());
1539  forAll(info, i)
1540  {
1541  info[i].setMiss();
1542  }
1543 
1544 
1545 
1546  // Do any local queries
1547  // ~~~~~~~~~~~~~~~~~~~~
1548 
1549  label nLocal = 0;
1550 
1551  {
1552  // Work array - whether processor bb overlaps the bounding sphere.
1553  boolList procBbOverlaps(Pstream::nProcs());
1554 
1555  forAll(samples, i)
1556  {
1557  // Find the processor this sample+radius overlaps.
1558  label nProcs = calcOverlappingProcs
1559  (
1560  samples[i],
1561  nearestDistSqr[i],
1562  procBbOverlaps
1563  );
1564 
1565  // Overlaps local processor?
1566  if (procBbOverlaps[Pstream::myProcNo()])
1567  {
1568  info[i] = octree.findNearest(samples[i], nearestDistSqr[i]);
1569  if (info[i].hit())
1570  {
1571  info[i].setIndex(triIndexer.toGlobal(info[i].index()));
1572  }
1573  if (nProcs == 1)
1574  {
1575  // Fully local
1576  nLocal++;
1577  }
1578  }
1579  }
1580  }
1581 
1582 
1583  if
1584  (
1585  Pstream::parRun()
1586  && (
1587  returnReduce(nLocal, sumOp<label>())
1588  < returnReduce(samples.size(), sumOp<label>())
1589  )
1590  )
1591  {
1592  // Not all can be resolved locally. Build queries and map, send over
1593  // queries, do intersections, send back and merge.
1594 
1595  // Calculate queries and exchange map
1596  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1597 
1598  pointField allCentres;
1599  scalarField allRadiusSqr;
1600  labelList allSegmentMap;
1602  (
1603  calcLocalQueries
1604  (
1605  samples,
1606  nearestDistSqr,
1607 
1608  allCentres,
1609  allRadiusSqr,
1610  allSegmentMap
1611  )
1612  );
1613  const distributionMap& map = mapPtr();
1614 
1615 
1616  // swap samples to local processor
1617  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1618 
1619  map.distribute(allCentres);
1620  map.distribute(allRadiusSqr);
1621 
1622 
1623  // Do my tests
1624  // ~~~~~~~~~~~
1625 
1626  List<pointIndexHit> allInfo(allCentres.size());
1627  forAll(allInfo, i)
1628  {
1629  allInfo[i] = octree.findNearest
1630  (
1631  allCentres[i],
1632  allRadiusSqr[i]
1633  );
1634  if (allInfo[i].hit())
1635  {
1636  allInfo[i].setIndex(triIndexer.toGlobal(allInfo[i].index()));
1637  }
1638  }
1639 
1640 
1641  // Send back results
1642  // ~~~~~~~~~~~~~~~~~
1643 
1644  map.reverseDistribute(allSegmentMap.size(), allInfo);
1645 
1646 
1647  // Extract information
1648  // ~~~~~~~~~~~~~~~~~~~
1649 
1650  forAll(allInfo, i)
1651  {
1652  if (allInfo[i].hit())
1653  {
1654  label pointi = allSegmentMap[i];
1655 
1656  if (!info[pointi].hit())
1657  {
1658  // No intersection yet so take this one
1659  info[pointi] = allInfo[i];
1660  }
1661  else
1662  {
1663  // Nearest intersection
1664  if
1665  (
1666  magSqr(allInfo[i].hitPoint()-samples[pointi])
1667  < magSqr(info[pointi].hitPoint()-samples[pointi])
1668  )
1669  {
1670  info[pointi] = allInfo[i];
1671  }
1672  }
1673  }
1674  }
1675  }
1676 }
1677 
1678 
1679 void Foam::searchableSurfaces::distributedTriSurface::findLine
1680 (
1681  const pointField& start,
1682  const pointField& end,
1683  List<pointIndexHit>& info
1684 ) const
1685 {
1686  findLine
1687  (
1688  true, // nearestIntersection
1689  start,
1690  end,
1691  info
1692  );
1693 }
1694 
1695 
1697 (
1698  const pointField& start,
1699  const pointField& end,
1700  List<pointIndexHit>& info
1701 ) const
1702 {
1703  findLine
1704  (
1705  true, // nearestIntersection
1706  start,
1707  end,
1708  info
1709  );
1710 }
1711 
1712 
1714 (
1715  const pointField& start,
1716  const pointField& end,
1717  List<List<pointIndexHit>>& info
1718 ) const
1719 {
1720  // Reuse fineLine. We could modify all of findLine to do multiple
1721  // intersections but this would mean a lot of data transferred so
1722  // for now we just find nearest intersection and retest from that
1723  // intersection onwards.
1724 
1725  // Work array.
1726  List<pointIndexHit> hitInfo(start.size());
1727 
1728  findLine
1729  (
1730  true, // nearestIntersection
1731  start,
1732  end,
1733  hitInfo
1734  );
1735 
1736  // Tolerances:
1737  // To find all intersections we add a small vector to the last intersection
1738  // This is chosen such that
1739  // - it is significant (small is smallest representative relative tolerance;
1740  // we need something bigger since we're doing calculations)
1741  // - if the start-end vector is zero we still progress
1742  const vectorField dirVec(end-start);
1743  const scalarField magSqrDirVec(magSqr(dirVec));
1744  const vectorField smallVec
1745  (
1746  rootSmall*dirVec
1747  + vector(rootVSmall,rootVSmall,rootVSmall)
1748  );
1749 
1750  // Copy to input and compact any hits
1751  labelList pointMap(start.size());
1752  pointField e0(start.size());
1753  pointField e1(start.size());
1754  label compactI = 0;
1755 
1756  info.setSize(hitInfo.size());
1757  forAll(hitInfo, pointi)
1758  {
1759  if (hitInfo[pointi].hit())
1760  {
1761  info[pointi].setSize(1);
1762  info[pointi][0] = hitInfo[pointi];
1763 
1764  point pt = hitInfo[pointi].hitPoint() + smallVec[pointi];
1765 
1766  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1767  {
1768  e0[compactI] = pt;
1769  e1[compactI] = end[pointi];
1770  pointMap[compactI] = pointi;
1771  compactI++;
1772  }
1773  }
1774  else
1775  {
1776  info[pointi].clear();
1777  }
1778  }
1779 
1780  e0.setSize(compactI);
1781  e1.setSize(compactI);
1782  pointMap.setSize(compactI);
1783 
1784  while (returnReduce(e0.size(), sumOp<label>()) > 0)
1785  {
1786  findLine
1787  (
1788  true, // nearestIntersection
1789  e0,
1790  e1,
1791  hitInfo
1792  );
1793 
1794 
1795  // Extract
1796  label compactI = 0;
1797  forAll(hitInfo, i)
1798  {
1799  if (hitInfo[i].hit())
1800  {
1801  label pointi = pointMap[i];
1802 
1803  label sz = info[pointi].size();
1804  info[pointi].setSize(sz+1);
1805  info[pointi][sz] = hitInfo[i];
1806 
1807  point pt = hitInfo[i].hitPoint() + smallVec[pointi];
1808 
1809  if (((pt-start[pointi])&dirVec[pointi]) <= magSqrDirVec[pointi])
1810  {
1811  e0[compactI] = pt;
1812  e1[compactI] = end[pointi];
1813  pointMap[compactI] = pointi;
1814  compactI++;
1815  }
1816  }
1817  }
1818 
1819  // Trim
1820  e0.setSize(compactI);
1821  e1.setSize(compactI);
1822  pointMap.setSize(compactI);
1823  }
1824 }
1825 
1826 
1828 (
1829  const List<pointIndexHit>& info,
1830  labelList& region
1831 ) const
1832 {
1833  if (!Pstream::parRun())
1834  {
1835  region.setSize(info.size());
1836  forAll(info, i)
1837  {
1838  if (info[i].hit())
1839  {
1840  region[i] =
1841  Foam::triSurface::operator[](info[i].index()).region();
1842  }
1843  else
1844  {
1845  region[i] = -1;
1846  }
1847  }
1848  return;
1849  }
1850 
1851 
1852  // Get query data (= local index of triangle)
1853  // ~~~~~~~~~~~~~~
1854 
1855  labelList triangleIndex(info.size());
1857  (
1858  calcLocalQueries
1859  (
1860  info,
1861  triangleIndex
1862  )
1863  );
1864  const distributionMap& map = mapPtr();
1865 
1866 
1867  // Do my tests
1868  // ~~~~~~~~~~~
1869 
1870  const Foam::triSurface& s = static_cast<const Foam::triSurface&>(*this);
1871 
1872  region.setSize(triangleIndex.size());
1873 
1874  forAll(triangleIndex, i)
1875  {
1876  label triI = triangleIndex[i];
1877  region[i] = s[triI].region();
1878  }
1879 
1880 
1881  // Send back results
1882  // ~~~~~~~~~~~~~~~~~
1883 
1884  map.reverseDistribute(info.size(), region);
1885 }
1886 
1887 
1889 (
1890  const List<pointIndexHit>& info,
1891  vectorField& normal
1892 ) const
1893 {
1894  if (!Pstream::parRun())
1895  {
1896  triSurface::getNormal(info, normal);
1897  return;
1898  }
1899 
1900 
1901  // Get query data (= local index of triangle)
1902  // ~~~~~~~~~~~~~~
1903 
1904  labelList triangleIndex(info.size());
1906  (
1907  calcLocalQueries
1908  (
1909  info,
1910  triangleIndex
1911  )
1912  );
1913  const distributionMap& map = mapPtr();
1914 
1915 
1916  // Do my tests
1917  // ~~~~~~~~~~~
1918 
1919  const Foam::triSurface& s = static_cast<const Foam::triSurface&>(*this);
1920 
1921  normal.setSize(triangleIndex.size());
1922 
1923  forAll(triangleIndex, i)
1924  {
1925  label triI = triangleIndex[i];
1926  normal[i] = s[triI].normal(s.points());
1927  }
1928 
1929 
1930  // Send back results
1931  // ~~~~~~~~~~~~~~~~~
1932 
1933  map.reverseDistribute(info.size(), normal);
1934 }
1935 
1936 
1938 (
1939  const List<pointIndexHit>& info,
1940  labelList& values
1941 ) const
1942 {
1943  if (!Pstream::parRun())
1944  {
1945  triSurface::getField(info, values);
1946  return;
1947  }
1948 
1949  if (foundObject<labelIOField>("values"))
1950  {
1951  const Foam::labelIOField& fld = lookupObject<labelIOField>("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 << indent << "Triangles : "
2428  << indent << "Vertices : "
2430  << indent << "Bounding Box : " << bb << endl;
2431 }
2432 
2433 
2434 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
A primitive field of type <Type> with automated input and output.
Definition: IOField.H:53
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
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:55
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
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:60
const point & min() const
Minimum point defining the bounding box.
Definition: boundBoxI.H:88
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:94
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:669
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
Motion of the mesh specified as a list of pointMeshMovers.
fileName objectPath() const
Return complete path + object name.
Definition: regIOobject.H:155
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 bool overlaps(const boundBox &bb) const
Does any part of the surface overlap the supplied bound box?
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.
label size() const
Return size.
Triangulated surface description with patch information.
Definition: triSurface.H:68
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:63
#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.
const dimensionSet time
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:288
messageStream Info
const fvMesh & region(const dictionary &dict)
Cast the give dictionary to the corresponding region fvMesh.
Definition: fvMesh.C:1831
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
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)
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
bool matchPoints(const Field< point > &pts0, const Field< point > &pts1, const Field< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:33
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
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
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:243
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
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)