1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of cfMesh.
11 cfMesh is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 3 of the License, or (at your
14 option) any later version.
16 cfMesh is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
26 \*---------------------------------------------------------------------------*/
28 #include "meshOctreeAddressing.H"
29 #include "meshOctree.H"
30 #include "demandDrivenData.H"
31 #include "helperFunctions.H"
39 //#define DEBUGAddressing
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 void meshOctreeAddressing::calcGlobalPointLabels() const
50 if( !Pstream::parRun() )
51 FatalErrorIn("void meshOctreeAddressing::calcGlobalPointLabels() const")
52 << "Cannot calculate global labels! Exitting" << exit(FatalError);
54 const VRWGraph& nodeLabels = this->nodeLabels();
55 const FRWGraph<label, 8>& nodeLeaves = this->nodeLeaves();
57 //- allocate containers
58 globalPointLabelPtr_ = new labelLongList(nodeLeaves.size(), -1);
59 labelLongList& globalPointLabel = *globalPointLabelPtr_;
61 globalPointToLocalPtr_ = new Map<label>();
62 Map<label>& globalToLocal = *globalPointToLocalPtr_;
64 pointProcsPtr_ = new VRWGraph(nodeLeaves.size());
65 VRWGraph& pointProcs = *pointProcsPtr_;
67 //- find the number of points local to each processor
68 //- The point is taken to be local if it belongs to one processor, only,
69 //- or to the leaf with the smallest label
70 labelList nLocalPoints(Pstream::nProcs(), 0);
72 forAll(nodeLeaves, pointI)
75 procs.append(Pstream::myProcNo());
76 FixedList<bool, 8> validLeaf(true);
78 for(label nlI=0;nlI<8;++nlI)
80 const label leafI = nodeLeaves(pointI, nlI);
84 validLeaf[nlI] = false;
88 for(label i=0;i<nlI;++i)
89 if( nodeLeaves(pointI, i) == nodeLeaves(pointI, nlI) )
91 validLeaf[nlI] = false;
95 procs.appendIfNotIn(octree_.returnLeaf(leafI).procNo());
98 label minLeaf(octree_.numberOfLeaves());
101 for(label nlI=0;nlI<8;++nlI)
103 if( !validLeaf[nlI] )
106 const label leafI = nodeLeaves(pointI, nlI);
108 minLeaf = Foam::min(leafI, minLeaf);
112 if( found && octree_.returnLeaf(minLeaf).procNo() == Pstream::myProcNo() )
114 if( procs.size() > 1 )
115 pointProcs.setRow(pointI, procs);
117 globalPointLabel[pointI] = -2;
118 ++nLocalPoints[Pstream::myProcNo()];
122 //- exchange data with other processors
123 Pstream::gatherList(nLocalPoints);
124 Pstream::scatterList(nLocalPoints);
126 //- find the starting point label
128 for(label procI=0;procI<Pstream::myProcNo();++procI)
129 startPoint += nLocalPoints[procI];
131 //- assign global labels to local points
132 forAll(globalPointLabel, pointI)
134 if( globalPointLabel[pointI] == -2 )
136 globalPointLabel[pointI] = startPoint++;
138 if( pointProcs.sizeOfRow(pointI) != 0 )
139 globalToLocal.insert(globalPointLabel[pointI], pointI);
143 //- distribute the labels to other processors
144 //- it is done by sending the global leaf label and the node labels
145 //- to processors which contain the leaves as part of buffer layers
146 //- it is performed in reduce-like manner
147 const labelLongList& globalLeafLabel = this->globalLeafLabel();
148 const Map<label>& globalToLocalLeaf = this->globalToLocalLeafAddressing();
149 const VRWGraph& leafAtProcs = this->leafAtProcs();
150 const labelList& neiProcs = octree_.neiProcs();
152 DynList<label> below, above;
155 if( neiProcs[i] < Pstream::myProcNo() )
157 above.append(neiProcs[i]);
159 else if( neiProcs[i] > Pstream::myProcNo() )
161 below.append(neiProcs[i]);
166 procLeaves.reverseAddressing(Pstream::nProcs(), leafAtProcs);
168 //- scatter the data from the processors above to the processors below
169 //- receive the data from the processors above
170 forAll(above, aboveI)
173 labelList receivedLabels;
174 IPstream fromOtherProc(Pstream::blocking, above[aboveI]);
175 fromOtherProc >> receivedLabels;
178 while( counter < receivedLabels.size() )
180 const label leafI = globalToLocalLeaf[receivedLabels[counter++]];
182 if( nodeLabels.sizeOfRow(leafI) == 0 )
185 "void meshOctreeAddressing::"
186 "calcGlobalPointLabels() const"
187 ) << "1. Leaf " << leafI << " is not used in the mesh!"
188 << " Exitting.." << abort(FatalError);
190 for(label i=0;i<8;++i)
192 const label nI = nodeLabels(leafI, i);
194 const label globalLabel = receivedLabels[counter++];
196 const label nProcs = receivedLabels[counter++];
197 for(label ppI=0;ppI<nProcs;++ppI)
198 pointProcs.appendIfNotIn(nI, receivedLabels[counter++]);
200 if( globalLabel < 0 )
203 label& gpl = globalPointLabel[nI];
205 if( (gpl != -1) && (gpl != globalLabel) )
208 "void meshOctreeAddressing::"
209 "calcGlobalPointLabels() const"
210 ) << "Wrong global label for point " << nI
211 << " Exitting.." << abort(FatalError);
214 globalToLocal.insert(globalLabel, nI);
219 //- send the data to the processors below
220 forAll(below, belowI)
222 const label neiProc = below[belowI];
225 forAllRow(procLeaves, neiProc, i)
227 const label leafI = procLeaves(neiProc, i);
229 if( nodeLabels.sizeOfRow(leafI) == 0 )
232 dts.append(globalLeafLabel[leafI]);
233 for(label nI=0;nI<8;++nI)
235 const label nodeI = nodeLabels(leafI, nI);
236 dts.append(globalPointLabel[nodeI]);
238 //- add the current processor
239 pointProcs.appendIfNotIn(nodeI, Pstream::myProcNo());
241 dts.append(pointProcs.sizeOfRow(nodeI));
242 forAllRow(pointProcs, nodeI, ppI)
243 dts.append(pointProcs(nodeI, ppI));
248 OPstream toOtherProc(Pstream::blocking, neiProc, dts.byteSize());
252 //- gather the data from the processors below to the processors above
253 //- receive the data from the processors below
254 forAllReverse(below, belowI)
257 labelList receivedLabels;
258 IPstream fromOtherProc(Pstream::blocking, below[belowI]);
259 fromOtherProc >> receivedLabels;
262 while( counter < receivedLabels.size() )
264 const label leafI = globalToLocalLeaf[receivedLabels[counter++]];
266 if( nodeLabels.sizeOfRow(leafI) == 0 )
269 "void meshOctreeAddressing::"
270 "calcGlobalPointLabels() const"
271 ) << "2. Leaf " << leafI << " is not used in the mesh!"
272 << " Exitting.." << abort(FatalError);
274 for(label i=0;i<8;++i)
276 const label nI = nodeLabels(leafI, i);
278 const label globalLabel = receivedLabels[counter++];
280 const label nProcs = receivedLabels[counter++];
281 for(label ppI=0;ppI<nProcs;++ppI)
282 pointProcs.appendIfNotIn(nI, receivedLabels[counter++]);
284 if( globalLabel < 0 )
287 label & gpl = globalPointLabel[nI];
289 if( (gpl != -1) && (gpl != globalLabel) )
292 "void meshOctreeAddressing::"
293 "calcGlobalPointLabels() const"
294 ) << "Wrong global label for point " << nI
295 << " Exitting.." << abort(FatalError);
298 globalToLocal.insert(globalLabel, nI);
303 //- send the data to the processors below
304 forAllReverse(above, aboveI)
306 const label neiProc = above[aboveI];
309 forAllRow(procLeaves, neiProc, i)
311 const label leafI = procLeaves(neiProc, i);
313 if( nodeLabels.sizeOfRow(leafI) == 0 )
316 dts.append(globalLeafLabel[leafI]);
317 for(label nI=0;nI<8;++nI)
319 const label nodeI = nodeLabels(leafI, nI);
320 dts.append(globalPointLabel[nodeI]);
322 //- add the current processor
323 pointProcs.appendIfNotIn(nodeI, Pstream::myProcNo());
325 dts.append(pointProcs.sizeOfRow(nodeI));
326 forAllRow(pointProcs, nodeI, ppI)
327 dts.append(pointProcs(nodeI, ppI));
332 OPstream toOtherProc(Pstream::blocking, neiProc, dts.byteSize());
337 void meshOctreeAddressing::calcGlobalFaceLabels() const
339 if( !Pstream::parRun() )
340 FatalErrorIn("void meshOctreeAddressing::calcGlobalFaceLabels() const")
341 << "Cannot calculate global labels! Exitting" << exit(FatalError);
343 FatalError << "Not implemented" << exit(FatalError);
346 void meshOctreeAddressing::calcGlobalLeafLabels() const
348 if( !Pstream::parRun() )
349 FatalErrorIn("void meshOctreeAddressing::calcGlobalLeafLabels() const")
350 << "Cannot calculate global labels! Exitting" << exit(FatalError);
352 //- allocate the memory
353 globalLeafLabelPtr_ = new labelLongList(octree_.numberOfLeaves(), -1);
354 labelLongList& globalLeafLabel = *globalLeafLabelPtr_;
356 globalLeafToLocalPtr_ = new Map<label>();
357 Map<label>& globalToLocal = *globalLeafToLocalPtr_;
359 leafAtProcsPtr_ = new VRWGraph(octree_.numberOfLeaves());
360 VRWGraph& leafAtProcs = *leafAtProcsPtr_;
362 //- find the number of leaves local to each processor
363 labelList nLeavesAtProc(Pstream::nProcs(), 0);
368 # pragma omp parallel for schedule(static) reduction(+:nLeaves)
370 for(label leafI=0;leafI<octree_.numberOfLeaves();++leafI)
372 const meshOctreeCubeBasic& oc = octree_.returnLeaf(leafI);
374 if( oc.procNo() == Pstream::myProcNo() )
378 nLeavesAtProc[Pstream::myProcNo()] = nLeaves;
380 //- exchange the data with other processors
381 Pstream::gatherList(nLeavesAtProc);
382 Pstream::scatterList(nLeavesAtProc);
384 //- find the starting labels for
386 for(label procI=0;procI<Pstream::myProcNo();++procI)
387 nLeaves += nLeavesAtProc[procI];
389 //- set the global labels to local leaves
390 labelLongList otherProcLeaves;
391 for(label leafI=0;leafI<octree_.numberOfLeaves();++leafI)
393 const meshOctreeCubeBasic& oc = octree_.returnLeaf(leafI);
395 if( oc.procNo() == Pstream::myProcNo() )
397 globalLeafLabel[leafI] = nLeaves++;
401 otherProcLeaves.append(leafI);
402 leafAtProcs.append(leafI, Pstream::myProcNo());
403 leafAtProcs.append(leafI, oc.procNo());
407 //- the rest of the code is needed in case an additional layer of
408 //- of octree leaves belonging to other processors is added in order to
409 //- simplify the procedure for generation of mesh templates
411 //- allocate the map for exchanging of data
412 std::map<label, LongList<meshOctreeCubeBasic> > exchangeData;
413 const labelList& neiProcs = octree_.neiProcs();
414 forAll(neiProcs, procI)
416 const std::pair<label, LongList<meshOctreeCubeBasic> > pp
419 LongList<meshOctreeCubeBasic>()
422 exchangeData.insert(pp);
425 //- Here we have to combine the information from all processors
426 //- it is started such that all processors send the leaves to the processor
427 //- that contains them locally
429 //- fill the map with data
430 forAll(otherProcLeaves, i)
432 const meshOctreeCubeBasic& oc = octree_.returnLeaf(otherProcLeaves[i]);
433 meshOctreeCubeBasic coc(oc);
434 coc.setProcNo(Pstream::myProcNo());
435 exchangeData[oc.procNo()].append(coc);
438 //- exchange the data with other processors
439 LongList<meshOctreeCubeBasic> rLeaves;
440 help::exchangeMap(exchangeData, rLeaves, Pstream::scheduled);
442 //- update the local data
445 const label cLabel = octree_.findLeafLabelForPosition(rLeaves[i]);
447 globalToLocal.insert(globalLeafLabel[cLabel], cLabel);
448 leafAtProcs.appendIfNotIn(cLabel, Pstream::myProcNo());
449 leafAtProcs.appendIfNotIn(cLabel, rLeaves[i].procNo());
452 //- now the global leaf labels shall be sent from the processors
453 //- that own the leaves to the processors that also contain them
454 std::map<label, labelLongList> exchangeLabels;
455 std::map<label, LongList<meshOctreeCubeBasic> >::iterator it;
456 for(it=exchangeData.begin();it!=exchangeData.end();++it)
459 exchangeLabels.insert(std::make_pair(it->first, labelLongList()));
463 forAll(leafAtProcs, leafI)
465 if( octree_.returnLeaf(leafI).procNo() == Pstream::myProcNo() )
467 forAllRow(leafAtProcs, leafI, i)
469 const label procI = leafAtProcs(leafI, i);
471 if( procI == Pstream::myProcNo() )
474 exchangeData[procI].append(octree_.returnLeaf(leafI));
475 exchangeLabels[procI].append(globalLeafLabel[leafI]);
480 //- exchange the data
482 help::exchangeMap(exchangeData, rLeaves, Pstream::scheduled);
483 labelLongList rLabels;
484 help::exchangeMap(exchangeLabels, rLabels, Pstream::scheduled);
486 if( rLeaves.size() != rLabels.size() )
487 FatalErrorIn("void meshOctreeAddressing::calcGlobalLeafLabels() const")
488 << "Invalid list size!" << abort(FatalError);
490 //- set the labels to the leaves originating from other processors
493 const label cLabel = octree_.findLeafLabelForPosition(rLeaves[i]);
495 globalLeafLabel[cLabel] = rLabels[i];
496 globalToLocal.insert(rLabels[i], cLabel);
499 //- update leafAtProcs for all processors
500 exchangeLabels.clear();
501 forAll(neiProcs, procI)
502 exchangeLabels.insert(std::make_pair(neiProcs[procI], labelLongList()));
504 forAllConstIter(Map<label>, globalToLocal, iter)
506 const label leafI = iter();
508 if( octree_.returnLeaf(leafI).procNo() != Pstream::myProcNo() )
511 forAllRow(leafAtProcs, leafI, i)
513 const label procI = leafAtProcs(leafI, i);
515 if( procI == Pstream::myProcNo() )
518 labelLongList& dts = exchangeLabels[procI];
519 dts.append(iter.key());
521 dts.append(leafAtProcs.sizeOfRow(leafI));
522 forAllRow(leafAtProcs, leafI, j)
523 dts.append(leafAtProcs(leafI, j));
527 //- exchange the data
529 help::exchangeMap(exchangeLabels, rLabels, Pstream::scheduled);
531 //- update the local data
533 while( counter < rLabels.size() )
535 const label gLabel = rLabels[counter++];
537 if( !globalToLocal.found(gLabel) )
538 FatalError << "Cannot find global label " << gLabel
541 const label leafI = globalToLocal[gLabel];
543 const label numberOfProcs = rLabels[counter++];
544 for(label i=0;i<numberOfProcs;++i)
545 leafAtProcs.append(leafI, rLabels[counter++]);
548 # ifdef DEBUGAddressing
549 returnReduce(1, sumOp<label>());
550 const List<direction>& boxType = this->boxType();
551 const VRWGraph& nodeLabels = this->nodeLabels();
552 for(label i=0;i<Pstream::nProcs();++i)
554 if( i == Pstream::myProcNo() )
556 forAll(globalLeafLabel, leafI)
558 Pout << "Leaf " << leafI << "of type " << label(boxType[leafI])
559 << " has global label " << globalLeafLabel[leafI]
560 << " and coordinates " << octree_.returnLeaf(leafI)
561 << " and located at procs " << leafAtProcs[leafI]
562 << " node labels " << nodeLabels[leafI] << endl;
564 if( octree_.returnLeaf(leafI).procNo() == Pstream::myProcNo() )
566 if( globalToLocal[globalLeafLabel[leafI]] != leafI )
567 FatalError << "Crap!!" << abort(FatalError);
571 returnReduce(1, sumOp<label>());
574 //- check if the leaf at procs is ok
575 exchangeData.clear();
576 for(label i=0;i<Pstream::nProcs();++i)
578 if( i == Pstream::myProcNo() )
584 for(label leafI=0;leafI<octree_.numberOfLeaves();++leafI)
585 for(label i=0;i<Pstream::nProcs();++i)
587 if( i == Pstream::myProcNo() )
590 exchangeData[i].append(octree_.returnLeaf(leafI));
593 std::map<label, List<meshOctreeCubeBasic> > rMap;
594 help::exchangeMap(exchangeData, rMap);
596 for(std::map<label, List<meshOctreeCubeBasic> >::const_iterator it=rMap.begin();it!=rMap.end();++it)
598 const List<meshOctreeCubeBasic>& data = it->second;
602 const label leafI = octree_.findLeafLabelForPosition(data[i]);
607 if( !leafAtProcs.contains(leafI, it->first) )
608 FatalError << "Problem!!" << leafI
609 << " does not contain processor " << it->first
610 << " contains procs " << leafAtProcs[leafI]
611 << abort(FatalError);
615 returnReduce(1, sumOp<label>());
619 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
621 } // End namespace Foam
623 // ************************************************************************* //