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 time = 0;
55 
56  OFstream os
57  (
58  "processor" + Foam::name(Pstream::myProcNo())
59  + "_time" + Foam::name(time)
60  + "_iter" + Foam::name(iter) + ".obj"
61  );
62 
63  label verti = 0;
64  for (const int proci : Pstream::allProcs())
65  {
66  if (proci == Pstream::myProcNo())
67  {
68  continue;
69  }
70 
71  const DynamicList<treeBoundBox>& procBoxes = fixedBoxes[proci];
72  forAll(procBoxes, boxi)
73  {
74  const treeBoundBox& bb = procBoxes[boxi];
75 
76  // Write the points
77  const pointField pts(bb.points());
79 
80  // Write the box faces
81  for (const face& f : treeBoundBox::faces)
82  {
83  os << 'f';
84  for (const label fpi : f)
85  {
86  os << ' ' << fpi + verti + 1;
87  }
88  os << nl;
89  }
90  verti += pts.size();
91  }
92  }
93 
94  ++time;
95 }
96 
97 
99 (
100  const label refineIter,
101  const label nTgtObjects,
102  List<labelHashSet>& fixedSendElems,
103  List<List<labelList>>& localTgtElems,
104  List<labelList>& refineFlags,
105  labelList& nElems
106 ) const
107 {
109 
110  // Identify src boxes that can be refined and send to all remote procs
111  for (const int proci : Pstream::allProcs())
112  {
113  if (proci != Pstream::myProcNo() && !boxes_[proci].empty())
114  {
115  UOPstream toProc(proci, pBufs);
116  toProc << nObjectsOfType_ << boxes_[proci] << newToOld_[proci];
117  }
118  }
119 
120  pBufs.finishedSends();
121 
122  // Test each remote src bb with local tgt objects to identify which remote
123  // src boxes can/should be refined
124  for (const int proci : Pstream::allProcs())
125  {
126  if (proci == Pstream::myProcNo() || !pBufs.recvDataCount(proci))
127  {
128  continue;
129  }
130 
131  // Receive the subset of changing src bound boxes for proci
132  UIPstream fromProc(proci, pBufs);
133  const label nObjects = readLabel(fromProc);
134  List<treeBoundBox> remoteSrcBoxes(fromProc);
135  const List<label> newToOld(fromProc);
136 
137  if (remoteSrcBoxes.empty())
138  {
139  continue;
140  }
141 
142 
143  labelList& procRefineFlags = refineFlags[proci];
144  procRefineFlags.setSize(remoteSrcBoxes.size(), FIXED);
145 
146  if (nObjects == 0 || scalar(nTgtObjects)/scalar(nObjects) < 0.1)
147  {
148  // Sending less than 10% of objects of this type
149  // - shortcut by sending all
150  fixedSendElems[proci].insert(identity(nTgtObjects));
151  nElems[proci] = nTgtObjects;
152 
153  continue;
154  }
155 
156  label nElem = 0;
157  List<labelList>& localProcTgtElems = localTgtElems[proci];
158  List<labelList> newLocalProcTgtElems(remoteSrcBoxes.size());
159 
160  forAll(remoteSrcBoxes, srcBoxi)
161  {
162  const treeBoundBox& remSrcBb = remoteSrcBoxes[srcBoxi];
163  DynamicList<label> selectedElems(maxObjectsPerLeaf_);
164 
165  if (refineIter > nStartUpIter)
166  {
167  // Iterate over cached subset of tgt elements
168  const label oldBoxi = newToOld[srcBoxi];
169  const labelList& tgtBoxElems = localProcTgtElems[oldBoxi];
170 
171  for (const label tgtObji : tgtBoxElems)
172  {
173  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
174  {
175  selectedElems.append(tgtObji);
176  }
177  }
178  }
179  else
180  {
181  // Iterating over all target elements
182  for (label tgtObji = 0; tgtObji < nTgtObjects; ++tgtObji)
183  {
184  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
185  {
186  selectedElems.append(tgtObji);
187  }
188  }
189  }
190 
191  nElem += selectedElems.size();
192 
193  if
194  (
195  proci == Pstream::myProcNo()
196  || selectedElems.size() < maxObjectsPerLeaf_
197  )
198  {
199  procRefineFlags[srcBoxi] = FIXED;
200  fixedSendElems[proci].insert(selectedElems);
201  }
202  else
203  {
204  procRefineFlags[srcBoxi] = REFINE;
205  if (refineIter >= nStartUpIter)
206  {
207  newLocalProcTgtElems[srcBoxi].transfer(selectedElems);
208  }
209  }
210  }
211 
212  localProcTgtElems.transfer(newLocalProcTgtElems);
213  nElems[proci] = nElem;
214  }
215 }
216 
217 
219 (
220  const label boxi,
221  const label refineIter,
222  const label nSrcElem,
223  const treeBoundBox& origBox,
224  DynamicList<treeBoundBox>& procBoxes,
225  DynamicList<labelList>& procBoxElems,
226  DynamicList<label>& procNewToOld
227 ) const
228 {
229  // Create the new boxes
230 
231  if (refineIter == nStartUpIter)
232  {
233  // Start caching the addressing
234  for (direction octant = 0; octant < 8; ++octant)
235  {
236  const treeBoundBox subBb(origBox.subBbox(octant));
237 
238  // Identify the src elements for each box
239  DynamicList<label> newElems(nSrcElem/2);
240 
241  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
242  {
243  if (subBb.overlaps(calcSrcBox(srcElemi)))
244  {
245  newElems.append(srcElemi);
246  }
247  }
248 
249  if (newElems.size())
250  {
251  procBoxes.append(subBb);
252  procBoxElems.append(newElems);
253  procNewToOld.append(boxi);
254  }
255  }
256  }
257  else
258  {
259  for (direction octant = 0; octant < 8; ++octant)
260  {
261  const treeBoundBox subBb(origBox.subBbox(octant));
262 
263  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
264  {
265  if (subBb.overlaps(calcSrcBox(srcElemi)))
266  {
267  procBoxes.append(subBb);
268  break;
269  }
270  }
271  }
272  }
273 }
274 
275 
277 (
278  const label boxi,
279  const labelList& srcAddr,
280  const treeBoundBox& origBox,
281  DynamicList<treeBoundBox>& procBoxes,
282  DynamicList<labelList>& procBoxElems,
283  DynamicList<label>& procNewToOld
284 ) const
285 {
286  // Create the new boxes
287  for (direction octant = 0; octant < 8; ++octant)
288  {
289  const treeBoundBox subBb(origBox.subBbox(octant));
290 
291  // Identify the src elements for each box
292  DynamicList<label> newElems(srcAddr.size()/2);
293 
294  for (const label srcElemi : srcAddr)
295  {
296  if (subBb.overlaps(calcSrcBox(srcElemi)))
297  {
298  newElems.append(srcElemi);
299  }
300  }
301 
302  // Only keeping new box if it overlaps src objects
303  if (newElems.size())
304  {
305  procBoxes.append(subBb);
306  procBoxElems.append(newElems);
307  procNewToOld.append(boxi);
308  }
309  }
310 }
311 
312 
314 (
315  const label refineIter,
316  const label nSrcFaces,
317  const List<labelList>& refineFlags,
318  List<DynamicList<treeBoundBox>>& fixedBoxes
319 )
320 {
321  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
322 
323  // Send refine info back for list of evolving src boxes
324  forAll(refineFlags, proci)
325  {
326  if (proci != Pstream::myProcNo())
327  {
328  UOPstream toProc(proci, pBufs);
329  toProc << refineFlags[proci];
330  }
331  }
332 
333  pBufs.finishedSends();
334 
335  // Receive refine refinement actions from remote procs and use to refine
336  // local src boxes
337  bool refineBoxes = false;
338  List<DynamicList<label>> newToOld(Pstream::nProcs());
339 
340 
341  for (const int proci : Pstream::allProcs())
342  {
343  if (proci == Pstream::myProcNo())
344  {
345  continue;
346  }
347 
348  UIPstream fromProc(proci, pBufs);
349  const labelList refineFlags(fromProc);
350 
351  const List<treeBoundBox>& procBoxes = boxes_[proci];
352  DynamicList<treeBoundBox> newProcBoxes(procBoxes.size());
353  DynamicList<labelList> newProcBoxElems(procBoxes.size());
354  newToOld[proci].setCapacity(boxes_[proci].size());
355  DynamicList<label>& newProcNewToOld = newToOld[proci];
356 
357 
358  forAll(procBoxes, boxi)
359  {
360  if (refineFlags[boxi] == DROP)
361  {
362  // Skip box
363  }
364  else if (refineFlags[boxi] == REFINE)
365  {
366  if (refineIter > nStartUpIter)
367  {
368  // Can use locally cached info to speed up intersection
369  // tests
370  refineBox
371  (
372  boxi,
373  boxSrcElems_[proci][boxi],
374  procBoxes[boxi],
375  newProcBoxes,
376  newProcBoxElems,
377  newProcNewToOld
378  );
379  }
380  else
381  {
382  refineBox
383  (
384  boxi,
385  refineIter,
386  nSrcFaces,
387  procBoxes[boxi],
388  newProcBoxes,
389  newProcBoxElems,
390  newProcNewToOld
391  );
392  }
393 
394  refineBoxes = true;
395  }
396  else if (refineFlags[boxi] == FIXED)
397  {
398  fixedBoxes[proci].append(procBoxes[boxi]);
399  }
400  else
401  {
403  << "Unhandled refine action " << refineFlags[boxi]
404  << abort(FatalError);
405  }
406  }
407 
408  // Only keeping boxes that are to be refined
409  boxes_[proci].transfer(newProcBoxes);
410  boxSrcElems_[proci].transfer(newProcBoxElems);
411  newToOld_[proci].transfer(newProcNewToOld);
412  }
413 
414  return returnReduceOr(refineBoxes);
415 }
416 
417 
419 (
420  const label nSrcElems,
421  const label nTgtElems
422 )
423 {
424  // Store elements to send - will be used to build the mapDistribute
425  List<labelHashSet> fixedSendElems(Pstream::nProcs());
426 
427  // List of local tgt elems to optimise searching for tgt elements inside
428  // remote src boxes
429  List<List<labelList>> localTgtElems(Pstream::nProcs());
430 
431  // Storage of boxes per processor - only useful for debugging
433 
434  // Iterate to subdivide src boxes
435  label refinementIter = 1;
436  bool refineSrcBoxes = true;
437  while (refineSrcBoxes && (refinementIter <= nRefineIterMax_))
438  {
439  // Per processor refinement info
440  List<labelList> refineFlags(Pstream::nProcs());
441  labelList nElems(Pstream::nProcs(), Zero);
442 
443  // Assess how many target elements intersect the source bounding boxes
444  // and use the info to flag how the source boxes should be refined
445  setRefineFlags
446  (
447  refinementIter,
448  nTgtElems,
449  fixedSendElems,
450  localTgtElems,
451  refineFlags,
452  nElems
453  );
454 
455  // Refine the source bounding boxes
456  refineSrcBoxes =
457  doRefineBoxes
458  (
459  refinementIter,
460  nSrcElems,
461  refineFlags,
462  fixedBoxes
463  );
464 
465  ++refinementIter;
466 
467  if (debug > 1)
468  {
469  // Include any boxes that are still evolving
470  List<DynamicList<treeBoundBox>> allBoxes(fixedBoxes);
471  forAll(allBoxes, proci)
472  {
473  allBoxes[proci].append(boxes_[proci]);
474  }
475  writeBoxes(allBoxes, refinementIter);
476  }
477  }
478 
479  if (debug)
480  {
481  Pout<< "Local src boxes after " << refinementIter-1 << " iterations:"
482  << nl;
483 
484  forAll(fixedBoxes, proci)
485  {
486  // Include any boxes that are still evolving in box count
487  label nBox = fixedBoxes[proci].size() + boxes_[proci].size();
488  Pout<< " proc:" << proci << " nBoxes:" << nBox << nl;
489  }
490  Pout<< endl;
491  }
492 
493  // Convert send elems into a List<labelList>
494  List<labelList> sendElems(Pstream::nProcs());
495  forAll(localTgtElems, proci)
496  {
497  if (proci == Pstream::myProcNo() && nSrcElems)
498  {
499  sendElems[proci] = identity(nTgtElems);
500  }
501  else
502  {
503  labelHashSet& allIDs = fixedSendElems[proci];
504 
505  const List<labelList>& procBoxElems = localTgtElems[proci];
506 
507  for (const labelList& elems: procBoxElems)
508  {
509  allIDs.insert(elems);
510  }
511 
512  sendElems[proci] = allIDs.sortedToc();
513  }
514  }
515 
516  fixedSendElems.clear();
517  localTgtElems.clear();
518 
519  if (debug)
520  {
521  Pout<< "Local objects: " << nTgtElems << " Send map:" << nl
522  << tab << "proc" << tab << "objects" << endl;
523 
524  forAll(sendElems, proci)
525  {
526  Pout<< tab << proci << tab << sendElems[proci].size()
527  << endl;
528  }
529  }
530 
531  return autoPtr<mapDistribute>::New(std::move(sendElems));
532 }
533 
534 
535 // * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
536 
538 (
539  const UList<point>& srcPoints,
540  const UList<point>& tgtPoints,
541  const label maxObjectsPerLeaf,
542  const label nObjectsOfType,
543  const label nRefineIterMax
544 )
545 :
546  processorLOD(maxObjectsPerLeaf, nObjectsOfType),
547  srcPoints_(srcPoints),
548  tgtPoints_(tgtPoints),
549  boxes_(Pstream::nProcs()),
550  nRefineIterMax_(nRefineIterMax),
551  newToOld_(Pstream::nProcs()),
552  boxSrcElems_(Pstream::nProcs())
553 {
554  // Initialise each processor with a single box large enough to include all
555  // of its local src points
556  if (srcPoints_.size())
557  {
558  forAll(boxes_, proci)
559  {
560  List<treeBoundBox>& procBoxes = boxes_[proci];
561 
562  // Note: inflate to ease overlap operations and to handle 2-D
563  // axis-aligned objects
564  treeBoundBox srcBb(srcPoints_);
565  srcBb.inflate(0.01);
566 
567  procBoxes.resize(1);
568  procBoxes.front() = srcBb;
569  }
570  }
571 }
572 
573 
574 // ************************************************************************* //
defineTypeNameAndDebug(box, 0)
uint8_t direction
Definition: direction.H:48
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:132
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:452
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:578
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:500
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:1131
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
T & front()
Access first element of the list, position [0].
Definition: UListI.H:194
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
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:48
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:1029
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
Base class to generate a parallel distribution map for sending sufficient target objects to cover a d...
Definition: processorLOD.H:46
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
bool doRefineBoxes(const label refineIter, const label nSrcFaces, const List< labelList > &refineFlags, List< DynamicList< treeBoundBox >> &fixedBoxes)
Apply the box refinements.
Definition: box.C:307
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:1020
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:289
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
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)
Definition: labelList.C:31
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:109
Inter-processor communications stream.
Definition: Pstream.H:57
void finishedSends(const bool wait=true)
Mark sends as done.
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:570
box(const UList< point > &srcPoints, const UList< point > &tgtPoints, const label maxObjectsPerLeaf, const label nObjectsOfType, const label nRefineIterMax=100)
Construct from list of points.
Definition: box.C:531
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:99
Creates the parallel distribution map by describing the source and target objects using box shapes...
Definition: box.H:52
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer...
Definition: UOPstream.H:380
label recvDataCount(const label proci) const
Number of unconsumed receive bytes for the specified processor. Must call finishedSends() or other fi...
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
labelList f(nPoints)
Buffers for inter-processor communications streams (UOPstream, UIPstream).
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:212
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:92
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.
autoPtr< mapDistribute > createMap(const label nSrcElems, const label nTgtElems)
Definition: box.C:412
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:133