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-2022 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())
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())
127  {
128  // Not refining boxes I send to myself - will be sending all local
129  // elements
130  continue;
131  }
132 
133  // Receive the subset of changing src bound boxes for proci
134  UIPstream fromProc(proci, pBufs);
135  const label nObjects = readLabel(fromProc);
136  List<treeBoundBox> remoteSrcBoxes(fromProc);
137  const List<label> newToOld(fromProc);
138 
139  if (remoteSrcBoxes.empty())
140  {
141  continue;
142  }
143 
144 
145  labelList& procRefineFlags = refineFlags[proci];
146  procRefineFlags.setSize(remoteSrcBoxes.size(), FIXED);
147 
148  if (nObjects == 0 || scalar(nTgtObjects)/scalar(nObjects) < 0.1)
149  {
150  // Sending less than 10% of objects of this type
151  // - shortcut by sending all
152  fixedSendElems[proci].insert(identity(nTgtObjects));
153  nElems[proci] = nTgtObjects;
154 
155  continue;
156  }
157 
158  label nElem = 0;
159  List<labelList>& localProcTgtElems = localTgtElems[proci];
160  List<labelList> newLocalProcTgtElems(remoteSrcBoxes.size());
161 
162  forAll(remoteSrcBoxes, srcBoxi)
163  {
164  const treeBoundBox& remSrcBb = remoteSrcBoxes[srcBoxi];
165  DynamicList<label> selectedElems(maxObjectsPerLeaf_);
166 
167  if (refineIter > nStartUpIter)
168  {
169  // Iterate over cached subset of tgt elements
170  const label oldBoxi = newToOld[srcBoxi];
171  const labelList& tgtBoxElems = localProcTgtElems[oldBoxi];
172 
173  for (const label tgtObji : tgtBoxElems)
174  {
175  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
176  {
177  selectedElems.append(tgtObji);
178  }
179  }
180  }
181  else
182  {
183  // Iterating over all target elements
184  for (label tgtObji = 0; tgtObji < nTgtObjects; ++tgtObji)
185  {
186  if (calcTgtBox(tgtObji).overlaps(remSrcBb))
187  {
188  selectedElems.append(tgtObji);
189  }
190  }
191  }
192 
193  nElem += selectedElems.size();
194 
195  if
196  (
197  proci == Pstream::myProcNo()
198  || selectedElems.size() < maxObjectsPerLeaf_
199  )
200  {
201  procRefineFlags[srcBoxi] = FIXED;
202  fixedSendElems[proci].insert(selectedElems);
203  }
204  else
205  {
206  procRefineFlags[srcBoxi] = REFINE;
207  if (refineIter >= nStartUpIter)
208  {
209  newLocalProcTgtElems[srcBoxi].transfer(selectedElems);
210  }
211  }
212  }
213 
214  localProcTgtElems.transfer(newLocalProcTgtElems);
215  nElems[proci] = nElem;
216  }
217 }
218 
219 
221 (
222  const label boxi,
223  const label refineIter,
224  const label nSrcElem,
225  const treeBoundBox& origBox,
226  DynamicList<treeBoundBox>& procBoxes,
227  DynamicList<labelList>& procBoxElems,
228  DynamicList<label>& procNewToOld
229 ) const
230 {
231  // Create the new boxes
232 
233  if (refineIter == nStartUpIter)
234  {
235  // Start caching the addressing
236  for (direction octant = 0; octant < 8; ++octant)
237  {
238  const treeBoundBox subBb(origBox.subBbox(octant));
239 
240  // Identify the src elements for each box
241  DynamicList<label> newElems(nSrcElem/2);
242 
243  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
244  {
245  if (subBb.overlaps(calcSrcBox(srcElemi)))
246  {
247  newElems.append(srcElemi);
248  }
249  }
250 
251  if (newElems.size())
252  {
253  procBoxes.append(subBb);
254  procBoxElems.append(newElems);
255  procNewToOld.append(boxi);
256  }
257  }
258  }
259  else
260  {
261  for (direction octant = 0; octant < 8; ++octant)
262  {
263  const treeBoundBox subBb(origBox.subBbox(octant));
264 
265  for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
266  {
267  if (subBb.overlaps(calcSrcBox(srcElemi)))
268  {
269  procBoxes.append(subBb);
270  break;
271  }
272  }
273  }
274  }
275 }
276 
277 
279 (
280  const label boxi,
281  const labelList& srcAddr,
282  const treeBoundBox& origBox,
283  DynamicList<treeBoundBox>& procBoxes,
284  DynamicList<labelList>& procBoxElems,
285  DynamicList<label>& procNewToOld
286 ) const
287 {
288  // Create the new boxes
289  for (direction octant = 0; octant < 8; ++octant)
290  {
291  const treeBoundBox subBb(origBox.subBbox(octant));
292 
293  // Identify the src elements for each box
294  DynamicList<label> newElems(srcAddr.size()/2);
295 
296  for (const label srcElemi : srcAddr)
297  {
298  if (subBb.overlaps(calcSrcBox(srcElemi)))
299  {
300  newElems.append(srcElemi);
301  }
302  }
303 
304  // Only keeping new box if it overlaps src objects
305  if (newElems.size())
306  {
307  procBoxes.append(subBb);
308  procBoxElems.append(newElems);
309  procNewToOld.append(boxi);
310  }
311  }
312 }
313 
314 
316 (
317  const label refineIter,
318  const label nSrcFaces,
319  const List<labelList>& refineFlags,
320  List<DynamicList<treeBoundBox>>& fixedBoxes
321 )
322 {
323  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
324 
325  // Send refine info back for list of evolving src boxes
326  forAll(refineFlags, proci)
327  {
328  if (proci != Pstream::myProcNo())
329  {
330  UOPstream toProc(proci, pBufs);
331  toProc << refineFlags[proci];
332  }
333  }
334 
335  pBufs.finishedSends();
336 
337  // Receive refine refinement actions from remote procs and use to refine
338  // local src boxes
339  bool refineBoxes = false;
340  List<DynamicList<label>> newToOld(Pstream::nProcs());
341 
342 
343  for (const int proci : Pstream::allProcs())
344  {
345  if (proci == Pstream::myProcNo())
346  {
347  continue;
348  }
349 
350  UIPstream fromProc(proci, pBufs);
351  const labelList refineFlags(fromProc);
352 
353  const List<treeBoundBox>& procBoxes = boxes_[proci];
354  DynamicList<treeBoundBox> newProcBoxes(procBoxes.size());
355  DynamicList<labelList> newProcBoxElems(procBoxes.size());
356  newToOld[proci].setCapacity(boxes_[proci].size());
357  DynamicList<label>& newProcNewToOld = newToOld[proci];
358 
359 
360  forAll(procBoxes, boxi)
361  {
362  if (refineFlags[boxi] == DROP)
363  {
364  // Skip box
365  }
366  else if (refineFlags[boxi] == REFINE)
367  {
368  if (refineIter > nStartUpIter)
369  {
370  // Can use locally cached info to speed up intersection
371  // tests
372  refineBox
373  (
374  boxi,
375  boxSrcElems_[proci][boxi],
376  procBoxes[boxi],
377  newProcBoxes,
378  newProcBoxElems,
379  newProcNewToOld
380  );
381  }
382  else
383  {
384  refineBox
385  (
386  boxi,
387  refineIter,
388  nSrcFaces,
389  procBoxes[boxi],
390  newProcBoxes,
391  newProcBoxElems,
392  newProcNewToOld
393  );
394  }
395 
396  refineBoxes = true;
397  }
398  else if (refineFlags[boxi] == FIXED)
399  {
400  fixedBoxes[proci].append(procBoxes[boxi]);
401  }
402  else
403  {
405  << "Unhandled refine action " << refineFlags[boxi]
406  << abort(FatalError);
407  }
408  }
409 
410  // Only keeping boxes that are to be refined
411  boxes_[proci].transfer(newProcBoxes);
412  boxSrcElems_[proci].transfer(newProcBoxElems);
413  newToOld_[proci].transfer(newProcNewToOld);
414  }
415 
416  return returnReduceOr(refineBoxes);
417 }
418 
419 
421 (
422  const label nSrcElems,
423  const label nTgtElems
424 )
425 {
426  // Store elements to send - will be used to build the mapDistribute
427  List<labelHashSet> fixedSendElems(Pstream::nProcs());
428 
429  // List of local tgt elems to optimise searching for tgt elements inside
430  // remote src boxes
431  List<List<labelList>> localTgtElems(Pstream::nProcs());
432 
433  // Storage of boxes per processor - only useful for debugging
435 
436  // Iterate to subdivide src boxes
437  label refinementIter = 1;
438  bool refineSrcBoxes = true;
439  while (refineSrcBoxes && (refinementIter <= nRefineIterMax_))
440  {
441  // Per processor refinement info
442  List<labelList> refineFlags(Pstream::nProcs());
443  labelList nElems(Pstream::nProcs(), Zero);
444 
445  // Assess how many target elements intersect the source bounding boxes
446  // and use the info to flag how the source boxes should be refined
447  setRefineFlags
448  (
449  refinementIter,
450  nTgtElems,
451  fixedSendElems,
452  localTgtElems,
453  refineFlags,
454  nElems
455  );
456 
457  // Refine the source bounding boxes
458  refineSrcBoxes =
459  doRefineBoxes
460  (
461  refinementIter,
462  nSrcElems,
463  refineFlags,
464  fixedBoxes
465  );
466 
467  ++refinementIter;
468 
469  if (debug > 1)
470  {
471  // Include any boxes that are still evolving
472  List<DynamicList<treeBoundBox>> allBoxes(fixedBoxes);
473  forAll(allBoxes, proci)
474  {
475  allBoxes[proci].append(boxes_[proci]);
476  }
477  writeBoxes(allBoxes, refinementIter);
478  }
479  }
480 
481  if (debug)
482  {
483  Pout<< "Local src boxes after " << refinementIter-1 << " iterations:"
484  << nl;
485 
486  forAll(fixedBoxes, proci)
487  {
488  // Include any boxes that are still evolving in box count
489  label nBox = fixedBoxes[proci].size() + boxes_[proci].size();
490  Pout<< " proc:" << proci << " nBoxes:" << nBox << nl;
491  }
492  Pout<< endl;
493  }
494 
495  // Convert send elems into a List<labelList>
496  List<labelList> sendElems(Pstream::nProcs());
497  forAll(localTgtElems, proci)
498  {
499  if (proci == Pstream::myProcNo() && nSrcElems)
500  {
501  sendElems[proci] = identity(nTgtElems);
502  }
503  else
504  {
505  labelHashSet& allIDs = fixedSendElems[proci];
506 
507  const List<labelList>& procBoxElems = localTgtElems[proci];
508 
509  for (const labelList& elems: procBoxElems)
510  {
511  allIDs.insert(elems);
512  }
513 
514  sendElems[proci] = allIDs.toc();
515  }
516  }
517 
518  fixedSendElems.clear();
519  localTgtElems.clear();
520 
521  if (debug)
522  {
523  Pout<< "Local objects: " << nTgtElems << " Send map:" << nl
524  << tab << "proc" << tab << "objects" << endl;
525 
526  forAll(sendElems, proci)
527  {
528  Pout<< tab << proci << tab << sendElems[proci].size()
529  << endl;
530  }
531  }
532 
533  return createLODMap(sendElems);
534 }
535 
536 
538 (
539  List<labelList>& sendElems
540 ) const
541 {
542  // Send over how many objects I need to receive
543  const label localProci = Pstream::myProcNo();
544  labelListList sendSizes(Pstream::nProcs());
545  sendSizes[localProci].setSize(Pstream::nProcs());
546  forAll(sendElems, proci)
547  {
548  sendSizes[localProci][proci] = sendElems[proci].size();
549  }
550  Pstream::allGatherList(sendSizes);
551 
552 
553  // Determine order of receiving
554  labelListList constructMap(Pstream::nProcs());
555 
556  // My local segment first
557  constructMap[localProci] = identity(sendElems[localProci].size());
558 
559  label segmenti = constructMap[localProci].size();
560  forAll(constructMap, proci)
561  {
562  if (proci != localProci)
563  {
564  // What I need to receive is what other processor is sending to me
565  label nRecv = sendSizes[proci][localProci];
566  constructMap[proci].setSize(nRecv);
567 
568  for (label& addr : constructMap[proci])
569  {
570  addr = segmenti++;
571  }
572  }
573  }
574 
575  autoPtr<mapDistribute> mapPtr
576  (
577  new mapDistribute
578  (
579  segmenti, // size after construction
580  std::move(sendElems),
581  std::move(constructMap)
582  )
583  );
584 
585  return mapPtr;
586 }
587 
588 
589 // * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
590 
592 (
593  const UList<point>& srcPoints,
594  const UList<point>& tgtPoints,
595  const label maxObjectsPerLeaf,
596  const label nObjectsOfType,
597  const label nRefineIterMax
598 )
599 :
600  processorLOD(maxObjectsPerLeaf, nObjectsOfType),
601  srcPoints_(srcPoints),
602  tgtPoints_(tgtPoints),
603  boxes_(Pstream::nProcs()),
604  nRefineIterMax_(nRefineIterMax),
605  newToOld_(Pstream::nProcs()),
606  boxSrcElems_(Pstream::nProcs())
607 {
608  // Initialise each processor with a single box large enough to include all
609  // of its local src points
610  if (srcPoints_.size())
611  {
612  forAll(boxes_, proci)
613  {
614  List<treeBoundBox>& procBoxes = boxes_[proci];
615 
616  // Note: inflate to ease overlap operations and to handle 2-D
617  // axis-aligned objects
618  treeBoundBox srcBb(srcPoints_);
619  srcBb.inflate(0.01);
620 
621  DynamicList<treeBoundBox> newProcBoxes(1);
622  newProcBoxes.append(srcBb);
623  procBoxes.transfer(newProcBoxes);
624  }
625  }
626 }
627 
628 
629 // ************************************************************************* //
defineTypeNameAndDebug(box, 0)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:51
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
uint8_t direction
Definition: direction.H:46
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:439
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:491
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
void inflate(const scalar factor)
Expand box by factor*mag(span) in all dimensions.
Definition: boundBoxI.H:367
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition: UPstream.H:748
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
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:94
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)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
static const faceList faces
Face to point addressing, using octant corner points.
Definition: treeBoundBox.H:174
static const label REFINE
Refine.
Definition: box.H:71
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:413
bool doRefineBoxes(const label refineIter, const label nSrcFaces, const List< labelList > &refineFlags, List< DynamicList< treeBoundBox >> &fixedBoxes)
Apply the box refinements.
Definition: box.C:309
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
autoPtr< mapDistribute > createLODMap(List< labelList > &sendElems) const
Use the current list of send elements to create the mapDistribute.
Definition: box.C:531
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
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:56
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:107
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:558
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:585
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:53
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer...
Definition: UOPstream.H:357
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:214
const UList< point > & srcPoints_
Reference to the source points.
Definition: box.H:82
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:76
static const label DROP
Drop/discard.
Definition: box.H:66
List< label > labelList
A List of labels.
Definition: List.H:62
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:414
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157