Loading...
Searching...
No Matches
decompositionGAMGAgglomeration.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) 2023 M. Janssens
9 Copyright (C) 2025 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
30#include "fvMesh.H"
32#include "decompositionMethod.H"
33// #include "OBJstream.H"
34#include "bandCompression.H"
36// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37
38namespace Foam
39{
41
43 (
47 );
48
50 (
53 geometry
54 );
55}
56
57
58// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
59
61(
62 const lduMesh& mesh,
64)
65:
67 doRenumber_(controlDict.getOrDefault<bool>("renumber", false)),
68 forceConnected_(controlDict.getOrDefault<bool>("forceConnected", true)),
69 decomposerPtr_
70 (
72 (
73 controlDict.optionalSubDict(type() + "Coeffs")
74 )
75 ), // regionName
76 clusterSize_(decomposerPtr_().nDomains()),
77 hasWarned_(false)
78{
79 hasWarned_ = false;
80 agglomerate
81 (
83 0, // starting mesh,
84 scalarField(mesh.lduAddr().upperAddr().size(), scalar(1.0)),
85 true
86 );
87}
88
89
91(
92 const lduMesh& mesh,
93 const scalarField& cellVolumes,
94 const vectorField& faceAreas,
96)
97:
99 doRenumber_(controlDict.getOrDefault<bool>("renumber", false)),
100 forceConnected_(controlDict.getOrDefault<bool>("forceConnected", true)),
101 decomposerPtr_
102 (
104 (
105 controlDict.optionalSubDict(type() + "Coeffs")
106 )
107 ), // regionName
108 clusterSize_(decomposerPtr_().nDomains()),
109 hasWarned_(false)
110{
111 agglomerate
112 (
114 0, // starting mesh,
115 mag(faceAreas),
116 true
117 );
118}
119
120
121// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122
123bool Foam::decompositionGAMGAgglomeration::checkRestriction
124(
125 labelList& newRestrict,
126 label& nNewCoarse,
127 const lduAddressing& fineAddressing,
128 const labelUList& restriction,
129 const label nCoarse
130)
131{
132 // A decomposition method does not guarantee a single connected
133 // region - it is an approximate minimisation of some cost function -
134 // so split additionally the regions into locally connected bits. Usually
135 // there is one large bit and a few small bits.
136 // Done by walking.
137
138 if (fineAddressing.size() != restriction.size())
139 {
141 << "nCells:" << fineAddressing.size()
142 << " agglom:" << restriction.size()
143 << abort(FatalError);
144 }
145
146 // Seed (master) for every region
147 labelList master(identity(fineAddressing.size()));
148
149 // Now loop and transport master through region. Could maintain a front
150 // but that requires cell addressing. Instead just keep on looping
151 // in face order and hope the fineAddressing isn't a single stack of
152 // cells ...
153 const labelUList& lower = fineAddressing.lowerAddr();
154 const labelUList& upper = fineAddressing.upperAddr();
155
156 while (true)
157 {
158 label nChanged = 0;
159
160 forAll(lower, facei)
161 {
162 const label own = lower[facei];
163 const label nei = upper[facei];
164
165 if (restriction[own] == restriction[nei])
166 {
167 // coarse-mesh-internal face
168
169 if (master[own] < master[nei])
170 {
171 master[nei] = master[own];
172 nChanged++;
173 }
174 else if (master[own] > master[nei])
175 {
176 master[own] = master[nei];
177 nChanged++;
178 }
179 }
180 }
181
182 if (nChanged == 0)
183 {
184 break;
185 }
186 }
187
188
189 // Now master[celli] will be the lowest numbered cell for each disconnected
190 // region.
191 labelList oldToNewRegion(restriction.size(), -1);
192 labelList masterToRegion(restriction.size(), -1);
193 nNewCoarse = 0;
194 forAll(restriction, celli)
195 {
196 if (master[celli] == celli) // 'master' of the region
197 {
198 // Allocate new coarse
199 masterToRegion[celli] = nNewCoarse++;
200 const label oldRegion = restriction[celli];
201 oldToNewRegion[oldRegion] = masterToRegion[celli];
202 }
203 }
204 if (nNewCoarse != nCoarse)
205 {
206 newRestrict = UIndirectList<label>(masterToRegion, master);
207 return false;
208 }
209
210 return true;
211}
212
213
214Foam::bitSet Foam::decompositionGAMGAgglomeration::blockedFaces
215(
216 const lduAddressing& addr,
217 const labelUList& region // region per cell
218)
219{
220 const labelUList& nbr = addr.upperAddr();
221 const labelUList& own = addr.lowerAddr();
222
223 bitSet isBlockedFace(nbr.size());
224 forAll(nbr, facei)
226 isBlockedFace[facei] = (region[own[facei]] != region[nbr[facei]]);
227 }
228 return isBlockedFace;
229}
230
231
233(
234 const lduAddressing& addr,
235 const bitSet& isBlockedFace,
236 CompactListList<label>& cellCells
237)
238{
239 // Since have only internal addressing cannot get global cell connectivity?
240
241 const labelUList& nbr = addr.upperAddr();
242 const labelUList& own = addr.lowerAddr();
243
244 labelList nNbrs(addr.size(), Zero);
245 forAll(nbr, facei)
246 {
247 if (!isBlockedFace[facei])
248 {
249 nNbrs[nbr[facei]]++;
250 nNbrs[own[facei]]++;
251 }
252 }
253
254 // Calculate&store offsets
255 cellCells.resize_nocopy(nNbrs);
256
257 auto& values = cellCells.values();
258 auto& offsets = cellCells.offsets();
259
260 // Fill in neighbours
261 nNbrs = Zero;
262 forAll(nbr, facei)
263 {
264 if (!isBlockedFace[facei])
265 {
266 const label n = nbr[facei];
267 const label o = own[facei];
268 values[offsets[n]+(nNbrs[n]++)] = o;
269 values[offsets[o]+(nNbrs[o]++)] = n;
270 }
271 }
272}
273
274
276(
277 const lduAddressing& addr,
278 const labelList& regions, // marker per cell
279 const label regioni, // which marker to keep
280 CompactListList<label>& cellCells
281)
282{
283 const labelUList& nbr = addr.upperAddr();
284 const labelUList& own = addr.lowerAddr();
285
286 if (regions.size() != addr.size())
287 {
288 FatalErrorInFunction<< "Wrong size" << exit(FatalError);
289 }
290
291 // Compact cell numbering for region cells
292 labelList oldToNew(regions.size(), -1);
293 label nCells = 0;
294 forAll(regions, i)
295 {
296 if (regions[i] == regioni)
297 {
298 oldToNew[i] = nCells++;
299 }
300 }
301
302 labelList nNbrs(nCells, Zero);
303 forAll(nbr, facei)
304 {
305 const label n = oldToNew[nbr[facei]];
306 const label o = oldToNew[own[facei]];
307 if (n != -1 && o != -1)
308 {
309 nNbrs[n]++;
310 nNbrs[o]++;
311 }
312 }
313
314 // Calculate&store offsets
315 cellCells.resize_nocopy(nNbrs);
316
317 auto& values = cellCells.values();
318 const auto& offsets = cellCells.offsets();
319
320 // Fill in neighbours
321 nNbrs = Zero;
322 forAll(nbr, facei)
323 {
324 const label n = oldToNew[nbr[facei]];
325 const label o = oldToNew[own[facei]];
326 if (n != -1 && o != -1)
327 {
328 values[offsets[n]+(nNbrs[n]++)] = o;
329 values[offsets[o]+(nNbrs[o]++)] = n;
330 }
331 }
332 return oldToNew;
333}
334
335
336void Foam::decompositionGAMGAgglomeration::coarseCellCells
337(
338 const lduAddressing& addr,
339 const labelList& regions, // coarse cell
340 CompactListList<label>& cellCells // coarse-to-coarse cells
341)
342{
343 const labelUList& nbr = addr.upperAddr();
344 const labelUList& own = addr.lowerAddr();
345
346 const label nCoarse = max(regions)+1;
347
348 labelList nNbrs(nCoarse, Zero);
349 forAll(nbr, facei)
350 {
351 const label n = regions[nbr[facei]];
352 const label o = regions[own[facei]];
353 if (n != o)
354 {
355 nNbrs[n]++;
356 nNbrs[o]++;
357 }
358 }
359 // Calculate&store offsets
360 cellCells.resize_nocopy(nNbrs);
361
362 auto& values = cellCells.values();
363 const auto& offsets = cellCells.offsets();
364
365 // Fill in neighbours
366 nNbrs = Zero;
367 forAll(nbr, facei)
368 {
369 const label n = regions[nbr[facei]];
370 const label o = regions[own[facei]];
371 if (n != o)
372 {
373 values[offsets[n]+(nNbrs[n]++)] = o;
374 values[offsets[o]+(nNbrs[o]++)] = n;
375 }
376 }
377}
378
379
380Foam::tmp<Foam::labelField> Foam::decompositionGAMGAgglomeration::agglomerate
381(
382 const bool partByPart,
383 const label nCoarseCells,
384
385 // Current mesh
386 const lduMesh& mesh,
387 const pointField& cellCentres,
388 const scalarField& cellWeights,
389 const scalarField& faceWeights,
390
391 // Agglomeration of current mesh
392 const labelUList& region
393) const
394{
395 const lduAddressing& addr = mesh.lduAddr();
396
397 // Return addressing from current mesh (addr) to coarse mesh
398 decompositionMethod& decomposer = decomposerPtr_();
399
400 const label nRegions = max(region) + 1;
401
402 auto tagglom = tmp<labelField>::New(addr.size(), -1);
403 auto& agglom = tagglom.ref();
404
405 if (partByPart)
406 {
407 // Most decomposition methods cannot handle multiple graphs so
408 // split the original mesh according to the marker and do each
409 // individually.
410
411 for (label regioni = 0; regioni < nRegions; regioni++)
412 {
413 CompactListList<label> cellCells;
414 const labelList oldToNew
415 (
416 localCellCells
417 (
418 addr,
419 region, // marker per cell
420 regioni, // which marker to keep
421 cellCells
422 )
423 );
424
425 auto cc(avg(cellCentres, cellCells.size(), oldToNew));
426 decomposer.nDomains(nCoarseCells);
427 const bool oldParRun = UPstream::parRun(false);
428 const label nRegionCells = cellCells.size();
429 labelList cellToProc;
430 if (nRegionCells >= 2*nCoarseCells)
431 {
432 cellToProc = decomposer.decompose(cellCells, cc);
433 }
434 else
435 {
436 // Small cluster. Can
437 // - call decomposition method anyway (but e.g. scotch will
438 // fail)
439 // - or assign each to different region
440 // - or all to same region
441 static label fallBackCell = 0;
442 cellToProc.resize_nocopy(nRegionCells);
443 cellToProc = fallBackCell; //identity(nRegionCells)
444 fallBackCell = ((fallBackCell +1) % nCoarseCells);
445 }
446 UPstream::parRun(oldParRun);
447
448 // Combine
449 forAll(oldToNew, celli)
450 {
451 const label compactCelli = oldToNew[celli];
452 if (compactCelli != -1)
453 {
454 agglom[celli] =
455 regioni*nCoarseCells + cellToProc[compactCelli];
456 }
457 }
458 }
459 }
460 else
461 {
462 // Single step
463 const bitSet isBlockedFace(blockedFaces(addr, region));
464
465 CompactListList<label> cellCells;
466 localCellCells(addr, isBlockedFace, cellCells);
467
468 decomposer.nDomains(nCoarseCells);
469 const bool oldParRun = UPstream::parRun(false);
470 agglom = decomposer.decompose
471 (
472 cellCells,
473 cellCentres // pointField(cellCells.size(), Zero)
474 );
475 UPstream::parRun(oldParRun);
476 }
477
478 if (forceConnected_)
479 {
480 label nAgglom = max(agglom)+1;
481
482 label nNewAgglom;
483 labelList newAgglom;
484 const bool ok = checkRestriction
485 (
486 newAgglom,
487 nNewAgglom,
488 addr,
489 agglom,
490 nAgglom
491 );
492
493 if (!ok)
494 {
496 << "Extending agglomeration from:" << nAgglom << " to:"
497 << nNewAgglom << endl;
498 agglom = std::move(newAgglom);
499 }
501 reduce(nNewAgglom, sumOp<label>(), UPstream::msgType(), mesh.comm());
502
503 if (nNewAgglom > nAgglom)
504 {
505 if (!hasWarned_)
506 {
507 hasWarned_ = true;
509 << "When splitting coarse mesh into " << nAgglom
510 << " cells created " << nNewAgglom
511 << " disconnected domains." << nl
512 << " This might give numerical problems. Either choose"
513 << " a decomposition method that guarantees a single domain"
514 << " or keep the result of the decomposition by setting"
515 << " 'forceConnected' to false" << nl
516 << " Disabling further warnings."
517 << endl;
518 }
519 }
520 }
521
522 // Renumbering - does not seem to help
523 if (doRenumber_)
524 {
525 // Get addressing between the agglomerated cells
526 CompactListList<label> cellCells;
527 coarseCellCells(addr, agglom, cellCells);
528 const labelList newToOld(meshTools::bandCompression(cellCells));
529 const labelList oldToNew(invert(cellCells.size(), newToOld));
530 forAll(agglom, celli)
531 {
532 agglom[celli] = oldToNew[agglom[celli]];
534 }
535
536 return tagglom;
537}
538
539
540void Foam::decompositionGAMGAgglomeration::agglomerate
541(
542 const label nCellsInCoarsestLevel,
543 const label startLevel,
544 // const pointField& startCellCentres,
545 // const scalarField& startCellWeights,
546 const scalarField& startFaceWeights,
547 const bool doProcessorAgglomerate
548)
549{
550 // Straight copy of pairGAMGAgglomeration::agglomerate without the
551 // mergeLevels
552
553 if (nCells_.size() < maxLevels_)
554 {
555 // See compactLevels. Make space if not enough
556 nCells_.resize(maxLevels_);
557 restrictAddressing_.resize(maxLevels_);
558 nFaces_.resize(maxLevels_);
559 faceRestrictAddressing_.resize(maxLevels_);
560 faceFlipMap_.resize(maxLevels_);
561 nPatchFaces_.resize(maxLevels_);
562 patchFaceRestrictAddressing_.resize(maxLevels_);
563 meshLevels_.resize(maxLevels_);
564 // Have procCommunicator_ always, even if not procAgglomerating.
565 // Use value -1 to indicate nothing is proc-agglomerated
566 procCommunicator_.resize(maxLevels_ + 1, -1);
567 if (processorAgglomerate())
568 {
569 procAgglomMap_.resize(maxLevels_);
570 agglomProcIDs_.resize(maxLevels_);
571 procCommunicator_.resize(maxLevels_);
572 procCellOffsets_.resize(maxLevels_);
573 procFaceMap_.resize(maxLevels_);
574 procBoundaryMap_.resize(maxLevels_);
575 procBoundaryFaceMap_.resize(maxLevels_);
576 }
577 }
578
579 const auto& startMesh = meshLevel(startLevel);
580 const lduAddressing& startAddr = startMesh.lduAddr();
581
582
583 // Start geometric agglomeration from the given faceWeights
584 scalarField faceWeights(startFaceWeights);
585
586 // TBD. Fudge - cell centres not yet passed through
587 pointField cellCentres;
588 scalarField cellWeights;
589 const auto* startMeshPtr = isA<primitiveMesh>(startMesh);
590 if (startMeshPtr)
591 {
592 cellCentres = startMeshPtr->cellCentres();
593 cellWeights = startMeshPtr->cellVolumes();
594 }
595
596 // Note: per level (starting from coarsest), per start mesh cell the
597 // agglomeration (= region)
598 DynamicList<labelList> startAgglomeration(maxLevels_);
599 {
600 // Fine mesh is a single region so can be done one-shot? But not when
601 // running parallel - decomposition methods do not guarantee this.
602 // Pout<< "Doing initial level nCells:" << startAddr.size() << endl;
603
604 // Determine reasonable nCellsInCoarsestLevel to have better
605 // first level
606 label nCoarsestCells = startAddr.size();
607 while (nCoarsestCells/clusterSize_ >= nCellsInCoarsestLevel)
608 {
609 nCoarsestCells /= clusterSize_;
610 }
612 << "Doing coarsest:" << nCoarsestCells
613 << " instead of:" << startAddr.size()
614 << endl;
615 const labelList fineToCoarsest
616 (
617 agglomerate
618 (
619 UPstream::parRun(), // partByPart,
620 nCoarsestCells, //nCellsInCoarsestLevel,
621
622 // Current mesh
623 startMesh,
624 cellCentres,
625 cellWeights,
626 faceWeights,
627
628 labelList(startAddr.size(), 0)
629 )
630 );
631 // {
632 // auto cc(avg(cellCentres, nCellsInCoarsestLevel, fineToCoarsest));
633 // const label level = startAgglomeration.size();
634 // OBJstream os("cellCentres_" + Foam::name(level) + ".obj");
635 // forAll(fineToCoarsest, celli)
636 // {
637 // const label coarsei = fineToCoarsest[celli];
638 // os.write(linePointRef(cellCentres[celli], cc()[coarsei]));
639 // }
640 // }
641 // From fine to coarsest mesh
642 startAgglomeration.append(std::move(fineToCoarsest));
643 // Pout<< "Done initial level nCells:" << startAddr.size() << endl;
644 }
645 while (startAgglomeration.size() < maxLevels_)
646 {
647 const label nFineCells = max(startAgglomeration.last())+1;
648 // Pout<< "Doing level:" << startAgglomeration.size()
649 // << " nCells:" << nFineCells << endl;
650
651 if
652 (
654 (
655 nFineCells >= startAddr.size()/(2*clusterSize_),
656 startMesh.comm()
657 )
658 )
659 {
660 break;
661 }
662
663 // Do next levels
664 // - construct the less-coarse to coarse agglomeration
665 const labelList fineToCoarse
666 (
667 agglomerate
668 (
669 true, // multi-pass
670 clusterSize_, //nCellsInCoarsestLevel,
671
672 // Current mesh
673 startMesh,
674 cellCentres,
675 cellWeights,
676 faceWeights,
677
678 startAgglomeration.last()
679 )
680 );
681 // {
682 // auto cc(avg(cellCentres, max(fineToCoarse)+1, fineToCoarse));
683 // const label level = startAgglomeration.size();
684 // OBJstream os("cellCentres_" + Foam::name(level) + ".obj");
685 // forAll(fineToCoarse, celli)
686 // {
687 // const label coarsei = fineToCoarse[celli];
688 // os.write(linePointRef(cellCentres[celli], cc()[coarsei]));
689 // }
690 // }
691
692 startAgglomeration.append(fineToCoarse);
693 // Pout<< "Done level:" << startAgglomeration.size()
694 // << " nCells:" << max(startAgglomeration.last())+1 << endl;
695 }
696 reverse(startAgglomeration);
697
698
699 // Agglomerate until the required number of cells in the coarsest level
700 // is reached
701 label nCreatedLevels = startLevel;
702
703 forAll(startAgglomeration, i)
704 {
705 if (!hasMeshLevel(nCreatedLevels))
706 {
707 FatalErrorInFunction<< "No mesh at nCreatedLevels:"
708 << nCreatedLevels
709 << exit(FatalError);
710 }
711
712 const auto& fineMesh = meshLevel(nCreatedLevels);
713
714 // Determine mapping from fine to coarse. This normally calls
715 // a single-level agglomeration but we use the previously calculated
716 // splitting.
717 const auto& startToCoarse = startAgglomeration[i];
718 const label nCoarseCells = max(startToCoarse)+1;
719 auto tfinalAgglomPtr = tmp<labelField>::New(fineMesh.lduAddr().size());
720 auto& finalAgglom = tfinalAgglomPtr.ref();
721 if (i == 0)
722 {
723 finalAgglom = startToCoarse;
724 }
725 else
726 {
727 // Renumber since agglomeration is from the starting mesh, not the
728 // previous mesh
729 const auto& startToPrev = startAgglomeration[i-1];
730 UIndirectList<label>(finalAgglom, startToPrev) = startToCoarse;
731 }
732 nCells_[nCreatedLevels] = nCoarseCells;
733 restrictAddressing_.set(nCreatedLevels, tfinalAgglomPtr);
734
735 // Create coarse mesh
736 agglomerateLduAddressing(nCreatedLevels);
737
738 // // Agglomerate the faceWeights field for the next level
739 // {
740 // scalarField aggFaceWeights
741 // (
742 // meshLevels_[nCreatedLevels].upperAddr().size(),
743 // 0.0
744 // );
745
746 // restrictFaceField
747 // (
748 // aggFaceWeights,
749 // faceWeights,
750 // nCreatedLevels
751 // );
752
753 // faceWeights = std::move(aggFaceWeights);
754 // }
755
756 nCreatedLevels++;
757 }
758
759 // Shrink the storage of the levels to those created
760 compactLevels(nCreatedLevels, doProcessorAgglomerate);
761}
762
763
764// Foam::autoPtr<Foam::lduPrimitiveMesh>
765// Foam::decompositionGAMGAgglomeration::createMesh
766// (
767// const label comm,
768// const CompactListList<label>& cellCells
769// )
770// {
771// // CSR connections
772// const labelList& connect = cellCells.values();
773//
774// DynamicList<label> lower(connect.size()/2);
775// DynamicList<label> upper(connect.size()/2);
776//
777// DynamicList<label> nbrs;
778// forAll(cellCells, celli)
779// {
780// const SubList<label> row(connect, cellCells.range(celli));
781// nbrs.clear();
782// for (const label nbr : row)
783// {
784// if (nbr > celli)
785// {
786// nbrs.append(nbr);
787// }
788// }
789// sort(nbrs);
790// for (const label nbr : nbrs)
791// {
792// lower.append(celli);
793// upper.append(nbr);
794// }
795// }
796//
797// autoPtr<lduPrimitiveMesh> coarseMeshPtr
798// (
799// new lduPrimitiveMesh
800// (
801// cellCells.size(),
802// lower,
803// upper,
804// comm,
805// true
806// )
807// );
808//
809// // Debug
810// {
811// const auto& coarseMesh = coarseMeshPtr();
812// Pout<< "CoarseMesh:" << coarseMesh.lduAddr().size() << endl;
813// forAll(coarseMesh.lduAddr().lowerAddr(), facei)
814// {
815// Pout<< " coarseface:" << facei
816// << " owner:" << coarseMesh.lduAddr().lowerAddr()[facei]
817// << " neighbour:"
818// << coarseMesh.lduAddr().upperAddr()[facei]
819// << endl;
820// }
821// Pout<< endl;
822// }
823// return coarseMeshPtr;
824// }
825// Foam::autoPtr<Foam::lduPrimitiveMesh>
826// Foam::decompositionGAMGAgglomeration::createMesh
827// (
828// const lduMesh& mesh,
829// const labelUList& agglom
830// )
831// {
832// // Convert mesh and agglomeration into lduPrimitiveMesh
833// if (!agglom.size())
834// {
835// return nullptr;
836// }
837//
838// const label nCoarseCells = max(agglom)+1;
839// const auto& lower = mesh.lduAddr().lowerAddr();
840// const auto& upper = mesh.lduAddr().upperAddr();
841//
842// labelPairHashSet doneCellCell(lower.size());
843//
844// labelList faceMap(lower.size(), -1);
845// labelList coarseLower(lower.size());
846// labelList coarseUpper(lower.size());
847// label nCoarseFaces = 0;
848// forAll(lower, facei)
849// {
850// if (faceMap[facei] == -1)
851// {
852// const label l = agglom[lower[facei]];
853// const label u = agglom[upper[facei]];
854//
855// if (l < u)
856// {
857// if (doneCellCell.insert(labelPair(l, u)))
858// {
859// const label coarseFacei = nCoarseFaces++;
860// faceMap[facei] = coarseFacei;
861// coarseLower[coarseFacei] = l;
862// coarseUpper[coarseFacei] = u;
863// }
864// }
865// else if (u < l)
866// {
867// if (doneCellCell.insert(labelPair(u, l)))
868// {
869// const label coarseFacei = nCoarseFaces++;
870// faceMap[facei] = coarseFacei;
871// coarseLower[coarseFacei] = u;
872// coarseUpper[coarseFacei] = l;
873// }
874// }
875// }
876// }
877// coarseLower.setSize(nCoarseFaces);
878// coarseUpper.setSize(nCoarseFaces);
879//
880// Pout<< "Going from" << nl
881// << " nCells:" << mesh.lduAddr().size()
882// << " nFaces:" << mesh.lduAddr().lowerAddr().size() << nl
883// << "to" << nl
884// << " nCells:" << nCoarseCells
885// << " nFaces:" << coarseLower.size() << endl;
886//
887// autoPtr<lduPrimitiveMesh> coarseMeshPtr
888// (
889// new lduPrimitiveMesh
890// (
891// nCoarseCells,
892// coarseLower,
893// coarseUpper,
894// mesh.comm(),
895// true
896// )
897// );
898//
899// // Debug
900// {
901// const auto& coarseMesh = coarseMeshPtr();
902// Pout<< "CoarseMesh:" << coarseMesh.lduAddr().size() << endl;
903// forAll(coarseMesh.lduAddr().lowerAddr(), facei)
904// {
905// Pout<< " coarseface:" << facei
906// << " owner:" << coarseMesh.lduAddr().lowerAddr()[facei]
907// << " neighbour:"
908// << coarseMesh.lduAddr().upperAddr()[facei]
909// << endl;
910// }
911// Pout<< endl;
912// }
913// return coarseMeshPtr;
914// }
915
916
917// ************************************************************************* //
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
The bandCompression function renumbers the addressing such that the band of the matrix is reduced....
A packed storage of objects of type <T> using an offset table for access.
void resize_nocopy(const label mRows, const label nVals)
Redimension without preserving existing content.
const labelList & offsets() const noexcept
Return the offset table (= size()+1).
const List< T > & values() const noexcept
Return the packed values.
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.
Geometric agglomerated algebraic multigrid agglomeration class.
bool processorAgglomerate() const
Whether to agglomerate across processors.
static const GAMGAgglomeration & New(const lduMesh &mesh, const dictionary &controlDict)
Return the selected geometric agglomerator.
void agglomerateLduAddressing(const label fineLevelIndex)
Assemble coarse mesh addressing.
PtrList< labelListList > patchFaceRestrictAddressing_
Patch-local face restriction addressing array.
PtrList< boolList > faceFlipMap_
Face flip: for faces mapped to internal faces stores whether.
PtrList< labelList > nPatchFaces_
The number of (coarse) patch faces in each level.
const label maxLevels_
Max number of levels.
void compactLevels(const label nCreatedLevels, const bool doProcessorAgglomerate)
Shrink the number of levels to that specified. Optionally do.
label nCellsInCoarsestLevel_
Number of cells in coarsest level.
labelList nFaces_
The number of (coarse) faces in each level.
PtrList< lduPrimitiveMesh > meshLevels_
Hierarchy of mesh addressing.
GAMGAgglomeration(const GAMGAgglomeration &)=delete
No copy construct.
labelList nCells_
The number of cells in each level.
labelList procCommunicator_
Communicator for given level.
PtrList< labelList > agglomProcIDs_
Per level the set of processors to agglomerate. Element 0 is.
PtrList< labelList > procAgglomMap_
Per level, per processor the processor it agglomerates into.
PtrList< labelListList > procBoundaryMap_
Mapping from processor to procMeshLevel boundary.
PtrList< labelList > procCellOffsets_
Mapping from processor to procMeshLevel cells.
PtrList< labelField > restrictAddressing_
Cell restriction addressing array.
PtrList< labelListList > procFaceMap_
Mapping from processor to procMeshLevel face.
PtrList< labelList > faceRestrictAddressing_
Face restriction addressing array.
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
label nCells(const label leveli) const
Return number of coarse cells (before processor agglomeration).
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
PtrList< labelListListList > procBoundaryFaceMap_
Mapping from processor to procMeshLevel boundary face.
A List with indirect addressing. Like IndirectList but does not store addressing.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static int & msgType() noexcept
Message tag of standard messages.
Definition UPstream.H:1926
static bool & parRun() noexcept
Test if this a parallel run.
Definition UPstream.H:1681
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
Agglomerate using the decomposition algorithm.
decompositionGAMGAgglomeration(const lduMesh &mesh, const dictionary &controlDict)
Construct given mesh and controls.
static void localCellCells(const lduAddressing &addr, const bitSet &isBlockedFace, CompactListList< label > &cellCells)
Abstract base class for domain decomposition.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
virtual const lduAddressing & lduAddr() const
Return ldu addressing.
Definition fvMesh.C:707
virtual label comm() const
Return communicator used for parallel communication.
Definition fvMesh.H:415
The class contains the addressing required by the lduMatrix: upper, lower and losort.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
label size() const noexcept
Return number of equations.
Abstract base class for meshes which provide LDU addressing for the construction of lduMatrix and LDU...
Definition lduMesh.H:54
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition tmp.H:215
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
runTime controlDict().readEntry("adjustTimeStep"
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const bitSet isBlockedFace(intersectedFaces())
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
#define DebugPout
Report an information message using Foam::Pout.
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition HashOps.H:164
labelList bandCompression(const polyMesh &mesh)
Renumber (mesh) addressing to reduce the band of the mesh connectivity, using the Cuthill-McKee algor...
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
List< label > labelList
A List of labels.
Definition List.H:62
void reverse(UList< T > &list, const label n)
Reverse the first n elements of the list.
Definition UListI.H:539
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
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
Field< vector > vectorField
Specialisation of Field<T> for vector.
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...
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition ListOps.C:28
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299