Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
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
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
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;
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 }
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;
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;
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// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition HashTable.C:156
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition List.C:347
void append(const T &val)
Append an element at the end of the list.
Definition List.H:497
void setSize(label n)
Alias for resize().
Definition List.H:536
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
Buffers for inter-processor communications streams (UOPstream, UIPstream).
label recvDataCount(const label proci) const
Number of unconsumed receive bytes for the specified processor. Must call finishedSends() or other fi...
void finishedSends(const bool wait=true)
Mark the send phase as being finished.
Inter-processor communications stream.
Definition Pstream.H:59
Input inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UIPstream.H:313
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:89
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
Output inter-processor communications stream using MPI send/recv etc. - operating on external buffer.
Definition UOPstream.H:408
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
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:1697
static rangeType allProcs(const label communicator=worldComm)
Range of process indices for all processes.
Definition UPstream.H:1857
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition autoPtr.H:178
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
layoutTypes
The map layout (eg, of the constructMap).
Base class to generate a parallel distribution map for sending sufficient target objects to cover a d...
label maxObjectsPerLeaf_
Maximum number of objects per leaf.
processorLOD(const label maxObjectsPerLeaf, const label nObjectsOfType) noexcept
Construct from components.
label nObjectsOfType_
Number of objects of this type. e.g. number of faces/cells on this processor.
Creates the parallel distribution map by describing the source and target objects using box shapes.
Definition box.H:55
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
label nRefineIterMax_
Maximum number of refinement iterations.
Definition box.H:98
List< labelList > newToOld_
Addressing per proc of new to old bound boxes.
Definition box.H:111
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
virtual treeBoundBox calcSrcBox(const label srcObji) const =0
The local boundBox associated with given source object.
static const label DROP
Drop/discard.
Definition box.H:65
static const label FIXED
Fixed - do not touch.
Definition box.H:75
static const label nStartUpIter
Number of iterations before element indices are cached.
Definition box.H:106
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
List< List< treeBoundBox > > boxes_
Per processor, the list of src bound boxes.
Definition box.H:93
void writeBoxes(const List< DynamicList< treeBoundBox > > &fixedBoxes, const label iter) const
Helper function to write the boxes in OBJ format.
Definition box.C:42
bool doRefineBoxes(const label refineIter, const label nSrcFaces, const List< labelList > &refineFlags, List< DynamicList< treeBoundBox > > &fixedBoxes)
Apply the box refinements.
Definition box.C:304
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
static const label REFINE
Refine.
Definition box.H:70
const UList< point > & tgtPoints_
Reference to the target points.
Definition box.H:86
virtual treeBoundBox calcTgtBox(const label tgtObji) const =0
The local boundBox associated with given target object.
const UList< point > & srcPoints_
Reference to the source points.
Definition box.H:81
List< List< labelList > > boxSrcElems_
Indices of elements in the src boxes.
Definition box.H:116
Standard boundBox with extra functionality for use in octree.
static const faceList faces
Face to point addressing, using octant corner points.
bool overlaps(const boundBox &bb) const
Overlaps with other bounding box, sphere etc?
Definition boundBoxI.H:439
treeBoundBox subBbox(const direction octant) const
Sub-box of given octant. Midpoint calculated.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
Namespace for handling debugging switches.
Definition debug.C:45
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition meshTools.C:196
Namespace for OpenFOAM.
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
List< label > labelList
A List of labels.
Definition List.H:62
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition label.H:63
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
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...
errorManip< error > abort(error &err)
Definition errorManip.H:139
uint8_t direction
Definition direction.H:49
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
constexpr char tab
The tab '\t' character(0x09).
Definition Ostream.H:49
label timeIndex
labelList f(nPoints)
const pointField & pts
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299