box.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2017-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "box.H"
29 #include "mapDistribute.H"
30 #include "OFstream.H"
31 #include "meshTools.H"
32 
33 const Foam::label Foam::processorLODs::box::DROP = 0;
34 const Foam::label Foam::processorLODs::box::REFINE = 1;
35 const Foam::label Foam::processorLODs::box::FIXED = 2;
36 const Foam::label Foam::processorLODs::box::nStartUpIter = 2;
37 
38 namespace Foam
39 {
40 namespace processorLODs
41 {
43 }
44 }
45 
46 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
47 
49 (
50  const List<DynamicList<treeBoundBox>>& fixedBoxes,
51  const label iter
52 ) const
53 {
54  static label timeIndex = 0;
55 
56  OFstream os
57  (
58  "processor" + Foam::name(Pstream::myProcNo())
59  + "_time" + Foam::name(timeIndex)
60  + "_iter" + Foam::name(iter) + ".obj"
61  );
62 
63  ++timeIndex;
64 
65  label verti = 0;
66  for (const int proci : UPstream::allProcs())
67  {
68  if (proci == UPstream::myProcNo())
69  {
70  continue;
71  }
72 
73  for (const treeBoundBox& bb : fixedBoxes[proci])
74  {
75  // Write the points
76  const pointField pts(bb.points());
78 
79  // Write the box faces
80  for (const face& f : treeBoundBox::faces)
81  {
82  os << 'f';
83  for (const label fpi : f)
84  {
85  os << ' ' << fpi + verti + 1;
86  }
87  os << nl;
88  }
89  verti += pts.size();
90  }
91  }
92 }
93 
94 
96 (
97  const label refineIter,
98  const label nTgtObjects,
99  List<labelHashSet>& fixedSendElems,
100  List<List<labelList>>& localTgtElems,
101  List<labelList>& refineFlags,
102  labelList& nElems
103 ) const
104 {
105  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
106 
107  // Identify src boxes that can be refined and send to all remote procs
108  for (const int proci : Pstream::allProcs())
109  {
110  if (proci != Pstream::myProcNo() && !boxes_[proci].empty())
111  {
112  UOPstream toProc(proci, pBufs);
113  toProc << nObjectsOfType_ << boxes_[proci] << newToOld_[proci];
114  }
115  }
116 
117  pBufs.finishedSends();
118 
119  // Test each remote src bb with local tgt objects to identify which remote
120  // src boxes can/should be refined
121  for (const int proci : Pstream::allProcs())
122  {
123  if (proci == Pstream::myProcNo() || !pBufs.recvDataCount(proci))
124  {
125  continue;
126  }
127 
128  // Receive the subset of changing src bound boxes for proci
129  UIPstream fromProc(proci, pBufs);
130  const label nObjects = readLabel(fromProc);
131  List<treeBoundBox> remoteSrcBoxes(fromProc);
132  const List<label> newToOld(fromProc);
133 
134  if (remoteSrcBoxes.empty())
135  {
136  continue;
137  }
138 
139 
140  labelList& procRefineFlags = refineFlags[proci];
141  procRefineFlags.setSize(remoteSrcBoxes.size(), FIXED);
142 
143  if (nObjects == 0 || scalar(nTgtObjects)/scalar(nObjects) < 0.1)
144  {
145  // Sending less than 10% of objects of this type
146  // - shortcut by sending all
147  fixedSendElems[proci].insert(identity(nTgtObjects));
148  nElems[proci] = nTgtObjects;
149 
150  continue;
151  }
152 
153  label nElem = 0;
154  List<labelList>& localProcTgtElems = localTgtElems[proci];
155  List<labelList> newLocalProcTgtElems(remoteSrcBoxes.size());
156 
157  forAll(remoteSrcBoxes, srcBoxi)
158  {
159  const treeBoundBox& remSrcBb = remoteSrcBoxes[srcBoxi];
160  DynamicList<label> selectedElems(maxObjectsPerLeaf_);
161 
162  if (refineIter > nStartUpIter)
163  {
164  // Iterate over cached subset of tgt elements
165  const label oldBoxi = newToOld[srcBoxi];
166  const labelList& tgtBoxElems = localProcTgtElems[oldBoxi];
167 
168  for (const label tgtObji : tgtBoxElems)
169  {
170  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
171  {
172  selectedElems.append(tgtObji);
173  }
174  }
175  }
176  else
177  {
178  // Iterating over all target elements
179  for (label tgtObji = 0; tgtObji < nTgtObjects; ++tgtObji)
180  {
181  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
182  {
183  selectedElems.append(tgtObji);
184  }
185  }
186  }
187 
188  nElem += selectedElems.size();
189 
190  if
191  (
192  proci == Pstream::myProcNo()
193  || selectedElems.size() < maxObjectsPerLeaf_
194  )
195  {
196  procRefineFlags[srcBoxi] = FIXED;
197  fixedSendElems[proci].insert(selectedElems);
198  }
199  else
200  {
201  procRefineFlags[srcBoxi] = REFINE;
202  if (refineIter >= nStartUpIter)
203  {
204  newLocalProcTgtElems[srcBoxi].transfer(selectedElems);
205  }
206  }
207  }
208 
209  localProcTgtElems.transfer(newLocalProcTgtElems);
210  nElems[proci] = nElem;
211  }
212 }
213 
214 
216 (
217  const label boxi,
218  const label refineIter,
219  const label nSrcElem,
220  const treeBoundBox& origBox,
221  DynamicList<treeBoundBox>& procBoxes,
222  DynamicList<labelList>& procBoxElems,
223  DynamicList<label>& procNewToOld
224 ) const
225 {
226  // Create the new boxes
227 
228  if (refineIter == nStartUpIter)
229  {
230  // Start caching the addressing
231  for (direction octant = 0; octant < 8; ++octant)
232  {
233  const treeBoundBox subBb(origBox.subBbox(octant));
234 
235  // Identify the src elements for each box
236  DynamicList<label> newElems(nSrcElem/2);
237 
238  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
239  {
240  if (subBb.overlaps(calcSrcBox(srcElemi)))
241  {
242  newElems.append(srcElemi);
243  }
244  }
245 
246  if (newElems.size())
247  {
248  procBoxes.append(subBb);
249  procBoxElems.append(newElems);
250  procNewToOld.append(boxi);
251  }
252  }
253  }
254  else
255  {
256  for (direction octant = 0; octant < 8; ++octant)
257  {
258  const treeBoundBox subBb(origBox.subBbox(octant));
259 
260  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
261  {
262  if (subBb.overlaps(calcSrcBox(srcElemi)))
263  {
264  procBoxes.append(subBb);
265  break;
266  }
267  }
268  }
269  }
270 }
271 
272 
274 (
275  const label boxi,
276  const labelList& srcAddr,
277  const treeBoundBox& origBox,
278  DynamicList<treeBoundBox>& procBoxes,
279  DynamicList<labelList>& procBoxElems,
280  DynamicList<label>& procNewToOld
281 ) const
282 {
283  // Create the new boxes
284  for (direction octant = 0; octant < 8; ++octant)
285  {
286  const treeBoundBox subBb(origBox.subBbox(octant));
287 
288  // Identify the src elements for each box
289  DynamicList<label> newElems(srcAddr.size()/2);
290 
291  for (const label srcElemi : srcAddr)
292  {
293  if (subBb.overlaps(calcSrcBox(srcElemi)))
294  {
295  newElems.append(srcElemi);
296  }
297  }
298 
299  // Only keeping new box if it overlaps src objects
300  if (newElems.size())
301  {
302  procBoxes.append(subBb);
303  procBoxElems.append(newElems);
304  procNewToOld.append(boxi);
305  }
306  }
307 }
308 
309 
311 (
312  const label refineIter,
313  const label nSrcFaces,
314  const List<labelList>& refineFlags,
315  List<DynamicList<treeBoundBox>>& fixedBoxes
316 )
317 {
318  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
319 
320  // Send refine info back for list of evolving src boxes
321  forAll(refineFlags, proci)
322  {
323  if (proci != Pstream::myProcNo())
324  {
325  UOPstream toProc(proci, pBufs);
326  toProc << refineFlags[proci];
327  }
328  }
329 
330  pBufs.finishedSends();
331 
332  // Receive refine refinement actions from remote procs and use to refine
333  // local src boxes
334  bool refineBoxes = false;
335  List<DynamicList<label>> newToOld(Pstream::nProcs());
336 
337 
338  for (const int proci : Pstream::allProcs())
339  {
340  if (proci == Pstream::myProcNo())
341  {
342  continue;
343  }
344 
345  UIPstream fromProc(proci, pBufs);
346  const labelList refineFlags(fromProc);
347 
348  const List<treeBoundBox>& procBoxes = boxes_[proci];
349  DynamicList<treeBoundBox> newProcBoxes(procBoxes.size());
350  DynamicList<labelList> newProcBoxElems(procBoxes.size());
351  newToOld[proci].setCapacity(boxes_[proci].size());
352  DynamicList<label>& newProcNewToOld = newToOld[proci];
353 
354 
355  forAll(procBoxes, boxi)
356  {
357  if (refineFlags[boxi] == DROP)
358  {
359  // Skip box
360  }
361  else if (refineFlags[boxi] == REFINE)
362  {
363  if (refineIter > nStartUpIter)
364  {
365  // Can use locally cached info to speed up intersection
366  // tests
367  refineBox
368  (
369  boxi,
370  boxSrcElems_[proci][boxi],
371  procBoxes[boxi],
372  newProcBoxes,
373  newProcBoxElems,
374  newProcNewToOld
375  );
376  }
377  else
378  {
379  refineBox
380  (
381  boxi,
382  refineIter,
383  nSrcFaces,
384  procBoxes[boxi],
385  newProcBoxes,
386  newProcBoxElems,
387  newProcNewToOld
388  );
389  }
390 
391  refineBoxes = true;
392  }
393  else if (refineFlags[boxi] == FIXED)
394  {
395  fixedBoxes[proci].append(procBoxes[boxi]);
396  }
397  else
398  {
400  << "Unhandled refine action " << refineFlags[boxi]
401  << abort(FatalError);
402  }
403  }
404 
405  // Only keeping boxes that are to be refined
406  boxes_[proci].transfer(newProcBoxes);
407  boxSrcElems_[proci].transfer(newProcBoxElems);
408  newToOld_[proci].transfer(newProcNewToOld);
409  }
410 
411  return returnReduceOr(refineBoxes);
412 }
413 
414 
416 (
417  const label nSrcElems,
418  const label nTgtElems,
419  const mapDistributeBase::layoutTypes constructLayout
420 )
421 {
422  // Store elements to send - will be used to build the mapDistribute
423  List<labelHashSet> fixedSendElems(Pstream::nProcs());
424 
425  // List of local tgt elems to optimise searching for tgt elements inside
426  // remote src boxes
427  List<List<labelList>> localTgtElems(Pstream::nProcs());
428 
429  // Storage of boxes per processor - only useful for debugging
431 
432  // Iterate to subdivide src boxes
433  label refinementIter = 1;
434  bool refineSrcBoxes = true;
435  while (refineSrcBoxes && (refinementIter <= nRefineIterMax_))
436  {
437  // Per processor refinement info
438  List<labelList> refineFlags(Pstream::nProcs());
439  labelList nElems(Pstream::nProcs(), Zero);
440 
441  // Assess how many target elements intersect the source bounding boxes
442  // and use the info to flag how the source boxes should be refined
443  setRefineFlags
444  (
445  refinementIter,
446  nTgtElems,
447  fixedSendElems,
448  localTgtElems,
449  refineFlags,
450  nElems
451  );
452 
453  // Refine the source bounding boxes
454  refineSrcBoxes =
455  doRefineBoxes
456  (
457  refinementIter,
458  nSrcElems,
459  refineFlags,
460  fixedBoxes
461  );
462 
463  ++refinementIter;
464 
465  if (debug > 1)
466  {
467  // Include any boxes that are still evolving
468  List<DynamicList<treeBoundBox>> allBoxes(fixedBoxes);
469  forAll(allBoxes, proci)
470  {
471  allBoxes[proci].append(boxes_[proci]);
472  }
473  writeBoxes(allBoxes, refinementIter);
474  }
475  }
476 
477  if (debug)
478  {
479  Pout<< "Local src boxes after " << refinementIter-1 << " iterations:"
480  << nl;
481 
482  forAll(fixedBoxes, proci)
483  {
484  // Include any boxes that are still evolving in box count
485  label nBox = fixedBoxes[proci].size() + boxes_[proci].size();
486  Pout<< " proc:" << proci << " nBoxes:" << nBox << nl;
487  }
488  Pout<< endl;
489  }
490 
491  // Convert send elems into a List<labelList>
492  List<labelList> sendElems(Pstream::nProcs());
493  forAll(localTgtElems, proci)
494  {
495  if (proci == Pstream::myProcNo() && nSrcElems)
496  {
497  sendElems[proci] = identity(nTgtElems);
498  }
499  else
500  {
501  labelHashSet& allIDs = fixedSendElems[proci];
502 
503  const List<labelList>& procBoxElems = localTgtElems[proci];
504 
505  for (const labelList& elems: procBoxElems)
506  {
507  allIDs.insert(elems);
508  }
509 
510  sendElems[proci] = allIDs.sortedToc();
511  }
512  }
513 
514  fixedSendElems.clear();
515  localTgtElems.clear();
516 
517  if (debug)
518  {
519  Pout<< "Local objects: " << nTgtElems << " Send map:" << nl
520  << tab << "proc" << tab << "objects" << endl;
521 
522  forAll(sendElems, proci)
523  {
524  Pout<< tab << proci << tab << sendElems[proci].size()
525  << endl;
526  }
527  }
528 
530  (
531  constructLayout,
532  std::move(sendElems)
533  );
534 }
535 
536 
537 // * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
538 
540 (
541  const UList<point>& srcPoints,
542  const UList<point>& tgtPoints,
543  const label maxObjectsPerLeaf,
544  const label nObjectsOfType,
545  const label nRefineIterMax
546 )
547 :
548  processorLOD(maxObjectsPerLeaf, nObjectsOfType),
549  srcPoints_(srcPoints),
550  tgtPoints_(tgtPoints),
551  boxes_(Pstream::nProcs()),
552  nRefineIterMax_(nRefineIterMax),
553  newToOld_(Pstream::nProcs()),
554  boxSrcElems_(Pstream::nProcs())
555 {
556  // Initialise each processor with a single box large enough to include all
557  // of its local src points
558  if (srcPoints_.size())
559  {
560  forAll(boxes_, proci)
561  {
562  List<treeBoundBox>& procBoxes = boxes_[proci];
563 
564  // Note: inflate to ease overlap operations and to handle 2-D
565  // axis-aligned objects
566  treeBoundBox srcBb(srcPoints_);
567  srcBb.inflate(0.01);
568 
569  procBoxes.resize(1);
570  procBoxes.front() = srcBb;
571  }
572  }
573 }
574 
575 
576 // ************************************************************************* //
defineTypeNameAndDebug(box, 0)
uint8_t direction
Definition: direction.H:46
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void writeBoxes(const List< DynamicList< treeBoundBox >> &fixedBoxes, const label iter) const
Helper function to write the boxes in OBJ format.
Definition: box.C:42
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:1176
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
T & front()
Access first element of the list, position [0].
Definition: UListI.H:237
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
List< List< treeBoundBox > > boxes_
Per processor, the list of src bound boxes.
Definition: box.H:93
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:63
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:196
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
static const faceList faces
Face to point addressing, using octant corner points.
Definition: treeBoundBox.H:174
static const label REFINE
Refine.
Definition: box.H:70
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:232
Base class to generate a parallel distribution map for sending sufficient target objects to cover a d...
Definition: processorLOD.H:48
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
bool doRefineBoxes(const label refineIter, const label nSrcFaces, const List< labelList > &refineFlags, List< DynamicList< treeBoundBox >> &fixedBoxes)
Apply the box refinements.
Definition: box.C:304
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1065
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
layoutTypes
The map layout (eg, of the constructMap)
void setSize(const label n)
Alias for resize()
Definition: List.H:316
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
Inter-processor communications stream.
Definition: Pstream.H:57
treeBoundBox subBbox(const direction octant) const
Sub-box of given octant. Midpoint calculated.
Definition: treeBoundBox.C:204
static const label nStartUpIter
Number of iterations before element indices are cached.
Definition: box.H:106
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:584
box(const UList< point > &srcPoints, const UList< point > &tgtPoints, const label maxObjectsPerLeaf, const label nObjectsOfType, const label nRefineIterMax=100)
Construct from list of points for source and target.
Definition: box.C:533
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:105
Creates the parallel distribution map by describing the source and target objects using box shapes...
Definition: box.H:52
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
labelList f(nPoints)
void refineBox(const label boxi, const label refineIter, const label nSrcElem, const treeBoundBox &origBox, DynamicList< treeBoundBox > &procBoxes, DynamicList< labelList > &procBoxElems, DynamicList< label > &procNewToOld) const
Definition: box.C:209
const UList< point > & srcPoints_
Reference to the source points.
Definition: box.H:81
void setRefineFlags(const label refineIter, const label nTgtObjects, List< labelHashSet > &fixedSendElems, List< List< labelList >> &localTgtElems, List< labelList > &refineFlags, labelList &nElems) const
Set the box refinement flags.
Definition: box.C:89
autoPtr< mapDistribute > createMap(const label nSrcElems, const label nTgtElems, const mapDistributeBase::layoutTypes constructLayout)
Return the parallel distribution map (often linear construct order)
Definition: box.C:409
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
"nonBlocking" : (MPI_Isend, MPI_Irecv)
static const label FIXED
Fixed - do not touch.
Definition: box.H:75
static const label DROP
Drop/discard.
Definition: box.H:65
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.
label timeIndex
Definition: getTimeIndex.H:24
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127