GAMGAgglomeration.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 | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM 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
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "GAMGAgglomeration.H"
27 #include "lduMesh.H"
28 #include "lduMatrix.H"
29 #include "Time.H"
30 #include "GAMGInterface.H"
31 #include "GAMGProcAgglomeration.H"
32 #include "pairGAMGAgglomeration.H"
33 #include "IOmanip.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39  defineTypeNameAndDebug(GAMGAgglomeration, 0);
40  defineRunTimeSelectionTable(GAMGAgglomeration, lduMesh);
41  defineRunTimeSelectionTable(GAMGAgglomeration, lduMatrix);
42  defineRunTimeSelectionTable(GAMGAgglomeration, geometry);
43 }
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
49 {
50  nCells_.setSize(nCreatedLevels);
51  restrictAddressing_.setSize(nCreatedLevels);
52  nFaces_.setSize(nCreatedLevels);
53  faceRestrictAddressing_.setSize(nCreatedLevels);
54  faceFlipMap_.setSize(nCreatedLevels);
55  nPatchFaces_.setSize(nCreatedLevels);
56  patchFaceRestrictAddressing_.setSize(nCreatedLevels);
57  meshLevels_.setSize(nCreatedLevels);
58 
59  // Have procCommunicator_ always, even if not procAgglomerating
60  procCommunicator_.setSize(nCreatedLevels + 1);
61  if (processorAgglomerate())
62  {
63  procAgglomMap_.setSize(nCreatedLevels);
64  agglomProcIDs_.setSize(nCreatedLevels);
65  procCellOffsets_.setSize(nCreatedLevels);
66  procFaceMap_.setSize(nCreatedLevels);
67  procBoundaryMap_.setSize(nCreatedLevels);
68  procBoundaryFaceMap_.setSize(nCreatedLevels);
69 
70  procAgglomeratorPtr_().agglomerate();
71 
72 
73  }
74 
75  // Print a bit
76  if (processorAgglomerate() && debug)
77  {
78  Info<< "GAMGAgglomeration:" << nl
79  << " local agglomerator : " << type() << nl;
80  if (processorAgglomerate())
81  {
82  Info<< " processor agglomerator : "
83  << procAgglomeratorPtr_().type() << nl
84  << nl;
85  }
86 
87  Info<< setw(36) << "nCells"
88  << setw(20) << "nFaces/nCells"
89  << setw(20) << "nInterfaces"
90  << setw(20) << "nIntFaces/nCells"
91  << setw(12) << "profile"
92  << nl
93  << setw(8) << "Level"
94  << setw(8) << "nProcs"
95  << " "
96  << setw(8) << "avg"
97  << setw(8) << "max"
98  << " "
99  << setw(8) << "avg"
100  << setw(8) << "max"
101  << " "
102  << setw(8) << "avg"
103  << setw(8) << "max"
104  << " "
105  << setw(8) << "avg"
106  << setw(8) << "max"
107  //<< " "
108  << setw(12) << "avg"
109  << nl
110  << setw(8) << "-----"
111  << setw(8) << "------"
112  << " "
113  << setw(8) << "---"
114  << setw(8) << "---"
115  << " "
116  << setw(8) << "---"
117  << setw(8) << "---"
118  << " "
119  << setw(8) << "---"
120  << setw(8) << "---"
121  << " "
122  << setw(8) << "---"
123  << setw(8) << "---"
124  //<< " "
125  << setw(12) << "---"
126  //<< " "
127  << nl;
128 
129  for (label levelI = 0; levelI <= size(); levelI++)
130  {
131  label nProcs = 0;
132  label nCells = 0;
133  scalar faceCellRatio = 0;
134  label nInterfaces = 0;
135  label nIntFaces = 0;
136  scalar ratio = 0.0;
137  scalar profile = 0.0;
138 
139  if (hasMeshLevel(levelI))
140  {
141  nProcs = 1;
142 
143  const lduMesh& fineMesh = meshLevel(levelI);
144  nCells = fineMesh.lduAddr().size();
145  faceCellRatio =
146  scalar(fineMesh.lduAddr().lowerAddr().size())/nCells;
147 
148  const lduInterfacePtrsList interfaces =
149  fineMesh.interfaces();
150  forAll(interfaces, i)
151  {
152  if (interfaces.set(i))
153  {
154  nInterfaces++;
155  nIntFaces += interfaces[i].faceCells().size();
156  }
157  }
158  ratio = scalar(nIntFaces)/nCells;
159 
160  profile = fineMesh.lduAddr().band().second();
161  }
162 
163  label totNprocs = returnReduce(nProcs, sumOp<label>());
164 
165  label maxNCells = returnReduce(nCells, maxOp<label>());
166  label totNCells = returnReduce(nCells, sumOp<label>());
167 
168  scalar maxFaceCellRatio =
169  returnReduce(faceCellRatio, maxOp<scalar>());
170  scalar totFaceCellRatio =
171  returnReduce(faceCellRatio, sumOp<scalar>());
172 
173  label maxNInt = returnReduce(nInterfaces, maxOp<label>());
174  label totNInt = returnReduce(nInterfaces, sumOp<label>());
175 
176  scalar maxRatio = returnReduce(ratio, maxOp<scalar>());
177  scalar totRatio = returnReduce(ratio, sumOp<scalar>());
178 
179  scalar totProfile = returnReduce(profile, sumOp<scalar>());
180 
181  int oldPrecision = Info().precision(4);
182 
183  Info<< setw(8) << levelI
184  << setw(8) << totNprocs
185  << " "
186  << setw(8) << totNCells/totNprocs
187  << setw(8) << maxNCells
188  << " "
189  << setw(8) << totFaceCellRatio/totNprocs
190  << setw(8) << maxFaceCellRatio
191  << " "
192  << setw(8) << scalar(totNInt)/totNprocs
193  << setw(8) << maxNInt
194  << " "
195  << setw(8) << totRatio/totNprocs
196  << setw(8) << maxRatio
197  << setw(12) << totProfile/totNprocs
198  << nl;
199 
200  Info().precision(oldPrecision);
201  }
202  Info<< endl;
203  }
204 }
205 
206 
208 (
209  const label nCoarseCells
210 ) const
211 {
212  // Check the need for further agglomeration on all processors
213  bool contAgg = nCoarseCells >= nCellsInCoarsestLevel_;
214  mesh().reduce(contAgg, andOp<bool>());
215  return contAgg;
216 }
217 
218 
219 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
220 
221 Foam::GAMGAgglomeration::GAMGAgglomeration
222 (
223  const lduMesh& mesh,
224  const dictionary& controlDict
225 )
226 :
228 
229  maxLevels_(50),
230 
231  nCellsInCoarsestLevel_
232  (
233  controlDict.lookupOrDefault<label>("nCellsInCoarsestLevel", 10)
234  ),
235  meshInterfaces_(mesh.interfaces()),
236  procAgglomeratorPtr_
237  (
238  (
239  (UPstream::nProcs(mesh.comm()) > 1)
240  && controlDict.found("processorAgglomerator")
241  )
243  (
244  controlDict.lookup("processorAgglomerator"),
245  *this,
247  )
249  ),
250 
251  nCells_(maxLevels_),
252  restrictAddressing_(maxLevels_),
253  nFaces_(maxLevels_),
254  faceRestrictAddressing_(maxLevels_),
255  faceFlipMap_(maxLevels_),
256  nPatchFaces_(maxLevels_),
257  patchFaceRestrictAddressing_(maxLevels_),
258 
259  meshLevels_(maxLevels_)
260 {
261  procCommunicator_.setSize(maxLevels_ + 1, -1);
262  if (processorAgglomerate())
263  {
264  procAgglomMap_.setSize(maxLevels_);
265  agglomProcIDs_.setSize(maxLevels_);
266  procCellOffsets_.setSize(maxLevels_);
267  procFaceMap_.setSize(maxLevels_);
268  procBoundaryMap_.setSize(maxLevels_);
269  procBoundaryFaceMap_.setSize(maxLevels_);
270  }
271 }
272 
273 
275 (
276  const lduMesh& mesh,
277  const dictionary& controlDict
278 )
279 {
280  if
281  (
283  (
284  GAMGAgglomeration::typeName
285  )
286  )
287  {
288  const word agglomeratorType
289  (
290  controlDict.lookupOrDefault<word>("agglomerator", "faceAreaPair")
291  );
292 
293  const_cast<Time&>(mesh.thisDb().time()).libs().open
294  (
295  controlDict,
296  "geometricGAMGAgglomerationLibs",
297  lduMeshConstructorTablePtr_
298  );
299 
300  lduMeshConstructorTable::iterator cstrIter =
301  lduMeshConstructorTablePtr_->find(agglomeratorType);
302 
303  if (cstrIter == lduMeshConstructorTablePtr_->end())
304  {
306  << "Unknown GAMGAgglomeration type "
307  << agglomeratorType << ".\n"
308  << "Valid matrix GAMGAgglomeration types are :"
309  << lduMatrixConstructorTablePtr_->sortedToc() << endl
310  << "Valid geometric GAMGAgglomeration types are :"
311  << lduMeshConstructorTablePtr_->sortedToc()
312  << exit(FatalError);
313  }
314 
315  return store(cstrIter()(mesh, controlDict).ptr());
316  }
317  else
318  {
319  return mesh.thisDb().lookupObject<GAMGAgglomeration>
320  (
321  GAMGAgglomeration::typeName
322  );
323  }
324 }
325 
326 
328 (
329  const lduMatrix& matrix,
330  const dictionary& controlDict
331 )
332 {
333  const lduMesh& mesh = matrix.mesh();
334 
335  if
336  (
338  (
339  GAMGAgglomeration::typeName
340  )
341  )
342  {
343  const word agglomeratorType
344  (
345  controlDict.lookupOrDefault<word>("agglomerator", "faceAreaPair")
346  );
347 
348  const_cast<Time&>(mesh.thisDb().time()).libs().open
349  (
350  controlDict,
351  "algebraicGAMGAgglomerationLibs",
352  lduMatrixConstructorTablePtr_
353  );
354 
355  if
356  (
357  !lduMatrixConstructorTablePtr_
358  || !lduMatrixConstructorTablePtr_->found(agglomeratorType)
359  )
360  {
361  return New(mesh, controlDict);
362  }
363  else
364  {
365  lduMatrixConstructorTable::iterator cstrIter =
366  lduMatrixConstructorTablePtr_->find(agglomeratorType);
367 
368  return store(cstrIter()(matrix, controlDict).ptr());
369  }
370  }
371  else
372  {
373  return mesh.thisDb().lookupObject<GAMGAgglomeration>
374  (
375  GAMGAgglomeration::typeName
376  );
377  }
378 }
379 
380 
382 (
383  const lduMesh& mesh,
384  const scalarField& cellVolumes,
385  const vectorField& faceAreas,
386  const dictionary& controlDict
387 )
388 {
389  const word agglomeratorType
390  (
391  controlDict.lookupOrDefault<word>("agglomerator", "faceAreaPair")
392  );
393 
394  const_cast<Time&>(mesh.thisDb().time()).libs().open
395  (
396  controlDict,
397  "geometricGAMGAgglomerationLibs",
398  geometryConstructorTablePtr_
399  );
400 
401  geometryConstructorTable::iterator cstrIter =
402  geometryConstructorTablePtr_->find(agglomeratorType);
403 
404  if (cstrIter == geometryConstructorTablePtr_->end())
405  {
407  << "Unknown GAMGAgglomeration type "
408  << agglomeratorType << ".\n"
409  << "Valid geometric GAMGAgglomeration types are :"
410  << geometryConstructorTablePtr_->sortedToc()
411  << exit(FatalError);
412  }
413 
415  (
416  cstrIter()
417  (
418  mesh,
419  cellVolumes,
420  faceAreas,
422  )
423  );
424 }
425 
426 
427 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
428 
430 {}
431 
432 
433 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
434 
436 (
437  const label i
438 ) const
439 {
440  if (i == 0)
441  {
442  return mesh_;
443  }
444  else
445  {
446  return meshLevels_[i - 1];
447  }
448 }
449 
450 
452 {
453  if (i == 0)
454  {
455  return true;
456  }
457  else
458  {
459  return meshLevels_.set(i - 1);
460  }
461 }
462 
463 
465 (
466  const label i
467 ) const
468 {
469  if (i == 0)
470  {
471  return meshInterfaces_;
472  }
473  else
474  {
475  return meshLevels_[i - 1].rawInterfaces();
476  }
477 }
478 
479 
481 {
482  if (hasMeshLevel(i))
483  {
484  meshLevels_.set(i - 1, NULL);
485 
486  if (i < nCells_.size())
487  {
488  nCells_[i] = -555;
489  restrictAddressing_.set(i, NULL);
490  nFaces_[i] = -666;
491  faceRestrictAddressing_.set(i, NULL);
492  faceFlipMap_.set(i, NULL);
493  nPatchFaces_.set(i, NULL);
494  patchFaceRestrictAddressing_.set(i, NULL);
495  }
496  }
497 }
498 
499 
501 (
502  const label leveli
503 ) const
504 {
505  return procAgglomMap_[leveli];
506 }
507 
508 
510 (
511  const label leveli
512 ) const
513 {
514  return agglomProcIDs_[leveli];
515 }
516 
517 
519 {
520  return procCommunicator_[leveli] != -1;
521 }
522 
523 
525 {
526  return procCommunicator_[leveli];
527 }
528 
529 
531 (
532  const label leveli
533 ) const
534 {
535  return procCellOffsets_[leveli];
536 }
537 
538 
540 (
541  const label leveli
542 ) const
543 {
544  return procFaceMap_[leveli];
545 }
546 
547 
549 (
550  const label leveli
551 ) const
552 {
553  return procBoundaryMap_[leveli];
554 }
555 
556 
558 (
559  const label leveli
560 ) const
561 {
562  return procBoundaryFaceMap_[leveli];
563 }
564 
565 
567 (
568  labelList& newRestrict,
569  label& nNewCoarse,
570  const lduAddressing& fineAddressing,
571  const labelUList& restrict,
572  const label nCoarse
573 )
574 {
575  if (fineAddressing.size() != restrict.size())
576  {
578  << "nCells:" << fineAddressing.size()
579  << " agglom:" << restrict.size()
580  << abort(FatalError);
581  }
582 
583  // Seed (master) for every region
584  labelList master(identity(fineAddressing.size()));
585 
586  // Now loop and transport master through region
587  const labelUList& lower = fineAddressing.lowerAddr();
588  const labelUList& upper = fineAddressing.upperAddr();
589 
590  while (true)
591  {
592  label nChanged = 0;
593 
594  forAll(lower, facei)
595  {
596  label own = lower[facei];
597  label nei = upper[facei];
598 
599  if (restrict[own] == restrict[nei])
600  {
601  // coarse-mesh-internal face
602 
603  if (master[own] < master[nei])
604  {
605  master[nei] = master[own];
606  nChanged++;
607  }
608  else if (master[own] > master[nei])
609  {
610  master[own] = master[nei];
611  nChanged++;
612  }
613  }
614  }
615 
616  reduce(nChanged, sumOp<label>());
617 
618  if (nChanged == 0)
619  {
620  break;
621  }
622  }
623 
624 
625  // Count number of regions/masters per coarse cell
626  labelListList coarseToMasters(nCoarse);
627  nNewCoarse = 0;
628  forAll(restrict, celli)
629  {
630  labelList& masters = coarseToMasters[restrict[celli]];
631 
632  if (findIndex(masters, master[celli]) == -1)
633  {
634  masters.append(master[celli]);
635  nNewCoarse++;
636  }
637  }
638 
639  if (nNewCoarse > nCoarse)
640  {
641  //WarningInFunction
642  // << "Have " << nCoarse
643  // << " agglomerated cells but " << nNewCoarse
644  // << " disconnected regions" << endl;
645 
646  // Keep coarseToMasters[0] the original coarse, allocate new ones
647  // for the others
648  labelListList coarseToNewCoarse(coarseToMasters.size());
649 
650  nNewCoarse = nCoarse;
651 
652  forAll(coarseToMasters, coarseI)
653  {
654  const labelList& masters = coarseToMasters[coarseI];
655 
656  labelList& newCoarse = coarseToNewCoarse[coarseI];
657  newCoarse.setSize(masters.size());
658  newCoarse[0] = coarseI;
659  for (label i=1; i<newCoarse.size(); i++)
660  {
661  newCoarse[i] = nNewCoarse++;
662  }
663  }
664 
665  newRestrict.setSize(fineAddressing.size());
666  forAll(restrict, celli)
667  {
668  label coarseI = restrict[celli];
669 
670  label index = findIndex(coarseToMasters[coarseI], master[celli]);
671  newRestrict[celli] = coarseToNewCoarse[coarseI][index];
672  }
673 
674  return false;
675  }
676  else
677  {
678  return true;
679  }
680 }
681 
682 
683 // ************************************************************************* //
virtual lduInterfacePtrsList interfaces() const =0
Return a list of pointers for each patch.
const Time & time() const
Return time.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
const labelList & procAgglomMap(const label fineLeveli) const
Mapping from processor to agglomerated processor (global, all.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
runTime controlDict().lookup("adjustTimeStep") >> adjustTimeStep
bool hasProcMesh(const label fineLeveli) const
Check that level has combined mesh.
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
bool foundObject(const word &name) const
Is the named Type found?
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Tuple2< label, scalar > band() const
Calculate bandwidth and profile of addressing.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
virtual const objectRegistry & thisDb() const
Return the object registry.
Definition: lduMesh.C:40
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
~GAMGAgglomeration()
Destructor.
const lduMesh & mesh() const
Return the LDU mesh from which the addressing is obtained.
Definition: lduMatrix.H:541
Abstract base class for meshes which provide LDU addressing for the construction of lduMatrix and LDU...
Definition: lduMesh.H:59
static const GAMGAgglomeration & New(const lduMesh &mesh, const dictionary &controlDict)
Return the selected geometric agglomerator.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
const labelList & cellOffsets(const label fineLeveli) const
Mapping from processor to procMesh cells.
virtual label comm() const =0
Return communicator used for parallel communication.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
static bool checkRestriction(labelList &newRestrict, label &nNewCoarse, const lduAddressing &fineAddressing, const labelUList &restrict, const label nCoarse)
Given restriction determines if coarse cells are connected.
void clearLevel(const label leveli)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
static autoPtr< GAMGProcAgglomeration > New(const word &type, GAMGAgglomeration &agglom, const dictionary &controlDict)
Return the selected agglomerator.
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:138
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:85
const labelListList & faceMap(const label fineLeveli) const
Mapping from processor to procMesh face.
const Type & lookupObject(const word &name) const
Lookup and return the object of the given Type.
dynamicFvMesh & mesh
label size() const
Return number of equations.
A class for handling words, derived from string.
Definition: word.H:59
void reduce(T &Value, const BinaryOp &bop) const
Helper: reduce with current communicator.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:97
virtual const lduAddressing & lduAddr() const =0
Return ldu addressing.
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:306
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const labelListListList & boundaryFaceMap(const label fineLeveli) const
Mapping from processor to procMesh boundary face.
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:60
Istream and Ostream manipulators taking arguments.
static const char nl
Definition: Ostream.H:262
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
defineTypeNameAndDebug(combustionModel, 0)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
const lduInterfacePtrsList & interfaceLevel(const label leveli) const
Return LDU interface addressing of given level.
label size() const
Return the number of elements in the UList.
Definition: UListI.H:299
void setSize(const label)
Reset size of List.
Definition: List.C:295
lduMatrix is a general matrix class in which the coefficients are stored as three arrays...
Definition: lduMatrix.H:79
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:399
fileName::Type type(const fileName &)
Return the file type: DIRECTORY or FILE.
Definition: POSIX.C:461
messageStream Info
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:53
The class contains the addressing required by the lduMatrix: upper, lower and losort.
bool continueAgglomerating(const label nCoarseCells) const
Check the need for further agglomeration.
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
label procCommunicator(const label fineLeveli) const
Communicator for current level or -1.
const labelListList & boundaryMap(const label fineLeveli) const
Mapping from processor to procMesh boundary.
Geometric agglomerated algebraic multigrid agglomeration class.
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
Namespace for OpenFOAM.
const labelList & agglomProcIDs(const label fineLeveli) const
Set of processors to agglomerate. Element 0 is the.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:451
void compactLevels(const label nCreatedLevels)
Shrink the number of levels to that specified.