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-------------------------------------------------------------------------------
10License
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
33const Foam::label Foam::processorLODs::box::DROP = 0;
34const Foam::label Foam::processorLODs::box::REFINE = 1;
35const Foam::label Foam::processorLODs::box::FIXED = 2;
36const Foam::label Foam::processorLODs::box::nStartUpIter = 2;
37
38namespace Foam
39{
40namespace 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
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());
78 for (const point& p : pts)
79 {
81 }
82
83 // Write the box faces
84 for (const face& f : bb.faces)
85 {
86 os << 'f';
87 for (const label fpi : f)
88 {
89 os << ' ' << fpi + verti + 1;
90 }
91 os << nl;
92 }
93 verti += pts.size();
94 }
95 }
96
97 ++time;
98}
99
100
102(
103 const label refineIter,
104 const label nTgtObjects,
105 List<labelHashSet>& fixedSendElems,
106 List<List<labelList>>& localTgtElems,
107 List<labelList>& refineFlags,
108 labelList& nElems
109) const
110{
112
113 // Identify src boxes that can be refined and send to all remote procs
114 for (const int proci : Pstream::allProcs())
115 {
116 if (proci != Pstream::myProcNo())
117 {
118 UOPstream toProc(proci, pBufs);
119 toProc << nObjectsOfType_ << boxes_[proci] << newToOld_[proci];
120 }
121 }
122
123 pBufs.finishedSends();
124
125 // Test each remote src bb with local tgt objects to identify which remote
126 // src boxes can/should be refined
127 for (const int proci : Pstream::allProcs())
128 {
129 if (proci == Pstream::myProcNo())
130 {
131 // Not refining boxes I send to myself - will be sending all local
132 // elements
133 continue;
134 }
135
136 // Receive the subset of changing src bound boxes for proci
137 UIPstream fromProc(proci, pBufs);
138 const label nObjects = readLabel(fromProc);
139 List<treeBoundBox> remoteSrcBoxes(fromProc);
140 const List<label> newToOld(fromProc);
141
142 if (remoteSrcBoxes.empty())
143 {
144 continue;
145 }
146
147
148 labelList& procRefineFlags = refineFlags[proci];
149 procRefineFlags.setSize(remoteSrcBoxes.size(), FIXED);
150
151 if (nObjects == 0 || scalar(nTgtObjects)/scalar(nObjects) < 0.1)
152 {
153 // Sending less than 10% of objects of this type
154 // - shortcut by sending all
155 fixedSendElems[proci].insert(identity(nTgtObjects));
156 nElems[proci] = nTgtObjects;
157
158 continue;
159 }
160
161 label nElem = 0;
162 List<labelList>& localProcTgtElems = localTgtElems[proci];
163 List<labelList> newLocalProcTgtElems(remoteSrcBoxes.size());
164
165 forAll(remoteSrcBoxes, srcBoxi)
166 {
167 const treeBoundBox& remSrcBb = remoteSrcBoxes[srcBoxi];
168 DynamicList<label> selectedElems(maxObjectsPerLeaf_);
169
170 if (refineIter > nStartUpIter)
171 {
172 // Iterate over cached subset of tgt elements
173 const label oldBoxi = newToOld[srcBoxi];
174 const labelList& tgtBoxElems = localProcTgtElems[oldBoxi];
175
176 for (const label tgtObji : tgtBoxElems)
177 {
178 if (calcTgtBox(tgtObji).overlaps(remSrcBb))
179 {
180 selectedElems.append(tgtObji);
181 }
182 }
183 }
184 else
185 {
186 // Iterating over all target elements
187 for (label tgtObji = 0; tgtObji < nTgtObjects; ++tgtObji)
188 {
189 if (calcTgtBox(tgtObji).overlaps(remSrcBb))
190 {
191 selectedElems.append(tgtObji);
192 }
193 }
194 }
195
196 nElem += selectedElems.size();
197
198 if
199 (
200 proci == Pstream::myProcNo()
201 || selectedElems.size() < maxObjectsPerLeaf_
202 )
203 {
204 procRefineFlags[srcBoxi] = FIXED;
205 fixedSendElems[proci].insert(selectedElems);
206 }
207 else
208 {
209 procRefineFlags[srcBoxi] = REFINE;
210 if (refineIter >= nStartUpIter)
211 {
212 newLocalProcTgtElems[srcBoxi].transfer(selectedElems);
213 }
214 }
215 }
216
217 localProcTgtElems.transfer(newLocalProcTgtElems);
218 nElems[proci] = nElem;
219 }
220}
221
222
224(
225 const label boxi,
226 const label refineIter,
227 const label nSrcElem,
228 const treeBoundBox& origBox,
229 DynamicList<treeBoundBox>& procBoxes,
230 DynamicList<labelList>& procBoxElems,
231 DynamicList<label>& procNewToOld
232) const
233{
234 // Create the new boxes
235
236 if (refineIter == nStartUpIter)
237 {
238 // Start caching the addressing
239 for (direction octant = 0; octant < 8; ++octant)
240 {
241 const treeBoundBox subBb(origBox.subBbox(octant));
242
243 // Identify the src elements for each box
244 DynamicList<label> newElems(nSrcElem/2);
245
246 for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
247 {
248 if (subBb.overlaps(calcSrcBox(srcElemi)))
249 {
250 newElems.append(srcElemi);
251 }
252 }
253
254 if (newElems.size())
255 {
256 procBoxes.append(subBb);
257 procBoxElems.append(newElems);
258 procNewToOld.append(boxi);
259 }
260 }
261 }
262 else
263 {
264 for (direction octant = 0; octant < 8; ++octant)
265 {
266 const treeBoundBox subBb(origBox.subBbox(octant));
267
268 for (label srcElemi = 0; srcElemi < nSrcElem; ++srcElemi)
269 {
270 if (subBb.overlaps(calcSrcBox(srcElemi)))
271 {
272 procBoxes.append(subBb);
273 break;
274 }
275 }
276 }
277 }
278}
279
280
282(
283 const label boxi,
284 const labelList& srcAddr,
285 const treeBoundBox& origBox,
286 DynamicList<treeBoundBox>& procBoxes,
287 DynamicList<labelList>& procBoxElems,
288 DynamicList<label>& procNewToOld
289) const
290{
291 // Create the new boxes
292 for (direction octant = 0; octant < 8; ++octant)
293 {
294 const treeBoundBox subBb(origBox.subBbox(octant));
295
296 // Identify the src elements for each box
297 DynamicList<label> newElems(srcAddr.size()/2);
298
299 for (const label srcElemi : srcAddr)
300 {
301 if (subBb.overlaps(calcSrcBox(srcElemi)))
302 {
303 newElems.append(srcElemi);
304 }
305 }
306
307 // Only keeping new box if it overlaps src objects
308 if (newElems.size())
309 {
310 procBoxes.append(subBb);
311 procBoxElems.append(newElems);
312 procNewToOld.append(boxi);
313 }
314 }
315}
316
317
319(
320 const label refineIter,
321 const label nSrcFaces,
322 const List<labelList>& refineFlags,
324)
325{
327
328 // Send refine info back for list of evolving src boxes
329 forAll(refineFlags, proci)
330 {
331 if (proci != Pstream::myProcNo())
332 {
333 UOPstream toProc(proci, pBufs);
334 toProc << refineFlags[proci];
335 }
336 }
337
338 pBufs.finishedSends();
339
340 // Receive refine refinement actions from remote procs and use to refine
341 // local src boxes
342 bool refineBoxes = false;
344
345
346 for (const int proci : Pstream::allProcs())
347 {
348 if (proci == Pstream::myProcNo())
349 {
350 continue;
351 }
352
353 UIPstream fromProc(proci, pBufs);
354 const labelList refineFlags(fromProc);
355
356 const List<treeBoundBox>& procBoxes = boxes_[proci];
357 DynamicList<treeBoundBox> newProcBoxes(procBoxes.size());
358 DynamicList<labelList> newProcBoxElems(procBoxes.size());
359 newToOld[proci].setCapacity(boxes_[proci].size());
360 DynamicList<label>& newProcNewToOld = newToOld[proci];
361
362
363 forAll(procBoxes, boxi)
364 {
365 if (refineFlags[boxi] == DROP)
366 {
367 // Skip box
368 }
369 else if (refineFlags[boxi] == REFINE)
370 {
371 if (refineIter > nStartUpIter)
372 {
373 // Can use locally cached info to speed up intersection
374 // tests
375 refineBox
376 (
377 boxi,
378 boxSrcElems_[proci][boxi],
379 procBoxes[boxi],
380 newProcBoxes,
381 newProcBoxElems,
382 newProcNewToOld
383 );
384 }
385 else
386 {
387 refineBox
388 (
389 boxi,
390 refineIter,
391 nSrcFaces,
392 procBoxes[boxi],
393 newProcBoxes,
394 newProcBoxElems,
395 newProcNewToOld
396 );
397 }
398
399 refineBoxes = true;
400 }
401 else if (refineFlags[boxi] == FIXED)
402 {
403 fixedBoxes[proci].append(procBoxes[boxi]);
404 }
405 else
406 {
408 << "Unhandled refine action " << refineFlags[boxi]
409 << abort(FatalError);
410 }
411 }
412
413 // Only keeping boxes that are to be refined
414 boxes_[proci].transfer(newProcBoxes);
415 boxSrcElems_[proci].transfer(newProcBoxElems);
416 newToOld_[proci].transfer(newProcNewToOld);
417 }
418
419 return returnReduce(refineBoxes, orOp<bool>());
420}
421
422
424(
425 const label nSrcElems,
426 const label nTgtElems
427)
428{
429 // Store elements to send - will be used to build the mapDistribute
430 List<labelHashSet> fixedSendElems(Pstream::nProcs());
431
432 // List of local tgt elems to optimise searching for tgt elements inside
433 // remote src boxes
434 List<List<labelList>> localTgtElems(Pstream::nProcs());
435
436 // Storage of boxes per processor - only useful for debugging
438
439 // Iterate to subdivide src boxes
440 label refinementIter = 1;
441 bool refineSrcBoxes = true;
442 while (refineSrcBoxes && (refinementIter <= nRefineIterMax_))
443 {
444 // Per processor refinement info
445 List<labelList> refineFlags(Pstream::nProcs());
446 labelList nElems(Pstream::nProcs(), Zero);
447
448 // Assess how many target elements intersect the source bounding boxes
449 // and use the info to flag how the source boxes should be refined
450 setRefineFlags
451 (
452 refinementIter,
453 nTgtElems,
454 fixedSendElems,
455 localTgtElems,
456 refineFlags,
457 nElems
458 );
459
460 // Refine the source bounding boxes
461 refineSrcBoxes =
462 doRefineBoxes
463 (
464 refinementIter,
465 nSrcElems,
466 refineFlags,
467 fixedBoxes
468 );
469
470 ++refinementIter;
471
472 if (debug > 1)
473 {
474 // Include any boxes that are still evolving
475 List<DynamicList<treeBoundBox>> allBoxes(fixedBoxes);
476 forAll(allBoxes, proci)
477 {
478 allBoxes[proci].append(boxes_[proci]);
479 }
480 writeBoxes(allBoxes, refinementIter);
481 }
482 }
483
484 if (debug)
485 {
486 Pout<< "Local src boxes after " << refinementIter-1 << " iterations:"
487 << nl;
488
489 forAll(fixedBoxes, proci)
490 {
491 // Include any boxes that are still evolving in box count
492 label nBox = fixedBoxes[proci].size() + boxes_[proci].size();
493 Pout<< " proc:" << proci << " nBoxes:" << nBox << nl;
494 }
495 Pout<< endl;
496 }
497
498 // Convert send elems into a List<labelList>
499 List<labelList> sendElems(Pstream::nProcs());
500 forAll(localTgtElems, proci)
501 {
502 if (proci == Pstream::myProcNo() && nSrcElems)
503 {
504 sendElems[proci] = identity(nTgtElems);
505 }
506 else
507 {
508 labelHashSet& allIDs = fixedSendElems[proci];
509
510 const List<labelList>& procBoxElems = localTgtElems[proci];
511
512 for (const labelList& elems: procBoxElems)
513 {
514 allIDs.insert(elems);
515 }
516
517 sendElems[proci] = allIDs.toc();
518 }
519 }
520
521 fixedSendElems.clear();
522 localTgtElems.clear();
523
524 if (debug)
525 {
526 Pout<< "Local objects: " << nTgtElems << " Send map:" << nl
527 << tab << "proc" << tab << "objects" << endl;
528
529 forAll(sendElems, proci)
530 {
531 Pout<< tab << proci << tab << sendElems[proci].size()
532 << endl;
533 }
534 }
535
536 return createLODMap(sendElems);
537}
538
539
541(
542 List<labelList>& sendElems
543) const
544{
545 // Send over how many objects I need to receive
546 const label localProci = Pstream::myProcNo();
547 labelListList sendSizes(Pstream::nProcs());
548 sendSizes[localProci].setSize(Pstream::nProcs());
549 forAll(sendElems, proci)
550 {
551 sendSizes[localProci][proci] = sendElems[proci].size();
552 }
553 Pstream::allGatherList(sendSizes);
554
555
556 // Determine order of receiving
557 labelListList constructMap(Pstream::nProcs());
558
559 // My local segment first
560 constructMap[localProci] = identity(sendElems[localProci].size());
561
562 label segmenti = constructMap[localProci].size();
563 forAll(constructMap, proci)
564 {
565 if (proci != localProci)
566 {
567 // What I need to receive is what other processor is sending to me
568 label nRecv = sendSizes[proci][localProci];
569 constructMap[proci].setSize(nRecv);
570
571 for (label& addr : constructMap[proci])
572 {
573 addr = segmenti++;
574 }
575 }
576 }
577
579 (
580 new mapDistribute
581 (
582 segmenti, // size after construction
583 std::move(sendElems),
584 std::move(constructMap)
585 )
586 );
587
588 return mapPtr;
589}
590
591
592// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
593
595(
596 const UList<point>& srcPoints,
597 const UList<point>& tgtPoints,
598 const label maxObjectsPerLeaf,
599 const label nObjectsOfType,
600 const label nRefineIterMax
601)
602:
603 processorLOD(maxObjectsPerLeaf, nObjectsOfType),
604 srcPoints_(srcPoints),
605 tgtPoints_(tgtPoints),
606 boxes_(Pstream::nProcs()),
607 nRefineIterMax_(nRefineIterMax),
608 newToOld_(Pstream::nProcs()),
609 boxSrcElems_(Pstream::nProcs())
610{
611 // Initialise each processor with a single box large enough to include all
612 // of its local src points
613 if (srcPoints_.size())
614 {
615 forAll(boxes_, proci)
616 {
617 List<treeBoundBox>& procBoxes = boxes_[proci];
618
619 // Note: inflate to ease overlap operations and to handle 2-D
620 // axis-aligned objects
622 srcBb.inflate(0.01);
623
624 DynamicList<treeBoundBox> newProcBoxes(1);
625 newProcBoxes.append(srcBb);
626 procBoxes.transfer(newProcBoxes);
627 }
628 }
629}
630
631
632// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:122
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
void transfer(List< T > &list)
Definition: List.C:447
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
Output to file stream, using an OSstream.
Definition: OFstream.H:57
Buffers for inter-processor communications streams (UOPstream, UIPstream).
UPstream::rangeType allProcs() const noexcept
Range of ranks indices associated with PstreamBuffers.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
void finishedSends(const bool wait=true)
Mark sends as done.
Inter-processor communications stream.
Definition: Pstream.H:63
static void allGatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:94
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
@ nonBlocking
"nonBlocking"
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:175
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Class containing processor-to-processor mapping information.
int myProcNo() const noexcept
Return processor number.
Base class to generate a parallel distribution map for sending sufficient target objects to cover a d...
Definition: processorLOD.H:53
Creates the parallel distribution map by describing the source and target objects using box shapes.
Definition: box.H:62
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:102
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:224
static const label DROP
Drop/discard.
Definition: box.H:70
static const label FIXED
Fixed - do not touch.
Definition: box.H:76
autoPtr< mapDistribute > createMap(const label nSrcElems, const label nTgtElems)
Definition: box.C:424
static const label nStartUpIter
Number of iterations before element indices are cached.
Definition: box.H:96
List< List< treeBoundBox > > boxes_
Per processor, the list of src bound boxes.
Definition: box.H:87
void writeBoxes(const List< DynamicList< treeBoundBox > > &fixedBoxes, const label iter) const
Helper function to write the boxes in OBJ format.
Definition: box.C:49
bool doRefineBoxes(const label refineIter, const label nSrcFaces, const List< labelList > &refineFlags, List< DynamicList< treeBoundBox > > &fixedBoxes)
Apply the box refinements.
Definition: box.C:319
static const label REFINE
Refine.
Definition: box.H:73
const UList< point > & srcPoints_
Reference to the source points.
Definition: box.H:80
autoPtr< mapDistribute > createLODMap(List< labelList > &sendElems) const
Use the current list of send elements to create the mapDistribute.
Definition: box.C:541
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:89
bool overlaps(const boundBox &bb) const
Overlaps other bounding box?
Definition: boundBoxI.H:221
treeBoundBox subBbox(const direction octant) const
Sub-box of given octant. Midpoint calculated.
Definition: treeBoundBox.C:106
static const faceList faces
Face to point addressing.
Definition: treeBoundBox.H:151
tmp< pointField > points() const
Vertex coordinates. In octant coding.
Definition: treeBoundBox.C:92
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
volScalarField & p
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Namespace for OpenFOAM.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:66
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManip< error > abort(error &err)
Definition: errorManip.H:144
uint8_t direction
Definition: direction.H:56
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr char tab
The tab '\t' character(0x09)
Definition: Ostream.H:52
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333