GAMGSolver.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2021-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 
29 #include "GAMGSolver.H"
30 #include "GAMGInterface.H"
31 #include "PCG.H"
32 #include "PBiCGStab.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
39 
40  lduMatrix::solver::addsymMatrixConstructorToTable<GAMGSolver>
42 
43  lduMatrix::solver::addasymMatrixConstructorToTable<GAMGSolver>
45 }
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
51 (
52  const word& fieldName,
53  const lduMatrix& matrix,
54  const FieldField<Field, scalar>& interfaceBouCoeffs,
55  const FieldField<Field, scalar>& interfaceIntCoeffs,
56  const lduInterfaceFieldPtrsList& interfaces,
57  const dictionary& solverControls
58 )
59 :
61  (
62  fieldName,
63  matrix,
64  interfaceBouCoeffs,
65  interfaceIntCoeffs,
66  interfaces,
67  solverControls
68  ),
69 
70  // Default values for all controls
71  // which may be overridden by those in controlDict
72  nPreSweeps_(0),
73  preSweepsLevelMultiplier_(1),
74  maxPreSweeps_(4),
75  nPostSweeps_(2),
76  postSweepsLevelMultiplier_(1),
77  maxPostSweeps_(4),
78  nFinestSweeps_(2),
79 
80  cacheAgglomeration_(true),
81  interpolateCorrection_(false),
82  scaleCorrection_(matrix.symmetric()),
83  directSolveCoarsest_(false),
84 
85  agglomeration_(GAMGAgglomeration::New(matrix_, controlDict_)),
86 
87  matrixLevels_(agglomeration_.size()),
88  primitiveInterfaceLevels_(agglomeration_.size()),
89  interfaceLevels_(agglomeration_.size()),
90  interfaceLevelsBouCoeffs_(agglomeration_.size()),
91  interfaceLevelsIntCoeffs_(agglomeration_.size())
92 {
93  readControls();
94 
95  if (agglomeration_.processorAgglomerate())
96  {
97  forAll(agglomeration_, fineLevelIndex)
98  {
99  if (agglomeration_.hasMeshLevel(fineLevelIndex))
100  {
101  if
102  (
103  (fineLevelIndex+1) < agglomeration_.size()
104  && agglomeration_.hasProcMesh(fineLevelIndex+1)
105  )
106  {
107  // Construct matrix without referencing the coarse mesh so
108  // construct a dummy mesh instead. This will get overwritten
109  // by the call to procAgglomerateMatrix so is only to get
110  // it through agglomerateMatrix
111 
112 
113  const lduInterfacePtrsList& fineMeshInterfaces =
114  agglomeration_.interfaceLevel(fineLevelIndex);
115 
116  PtrList<GAMGInterface> dummyPrimMeshInterfaces
117  (
118  fineMeshInterfaces.size()
119  );
120  lduInterfacePtrsList dummyMeshInterfaces
121  (
122  dummyPrimMeshInterfaces.size()
123  );
124  forAll(fineMeshInterfaces, intI)
125  {
126  if (fineMeshInterfaces.set(intI))
127  {
129  refCast<const GAMGInterface>
130  (
131  fineMeshInterfaces[intI]
132  ).write(os);
133  IStringStream is(os.str());
134 
135  dummyPrimMeshInterfaces.set
136  (
137  intI,
139  (
140  fineMeshInterfaces[intI].type(),
141  intI,
142  dummyMeshInterfaces,
143  is
144  )
145  );
146  }
147  }
148 
149  forAll(dummyPrimMeshInterfaces, intI)
150  {
151  if (dummyPrimMeshInterfaces.set(intI))
152  {
153  dummyMeshInterfaces.set
154  (
155  intI,
156  &dummyPrimMeshInterfaces[intI]
157  );
158  }
159  }
160 
161  // So:
162  // - pass in incorrect mesh (= fine mesh instead of coarse)
163  // - pass in dummy interfaces
164  agglomerateMatrix
165  (
166  fineLevelIndex,
167  agglomeration_.meshLevel(fineLevelIndex),
168  dummyMeshInterfaces
169  );
170 
171 
172  const labelList& procAgglomMap =
173  agglomeration_.procAgglomMap(fineLevelIndex+1);
174  const List<label>& procIDs =
175  agglomeration_.agglomProcIDs(fineLevelIndex+1);
176 
177  procAgglomerateMatrix
178  (
179  procAgglomMap,
180  procIDs,
181  fineLevelIndex
182  );
183  }
184  else
185  {
186  agglomerateMatrix
187  (
188  fineLevelIndex,
189  agglomeration_.meshLevel(fineLevelIndex + 1),
190  agglomeration_.interfaceLevel(fineLevelIndex + 1)
191  );
192  }
193  }
194  else
195  {
196  // No mesh. Not involved in calculation anymore
197  }
198  }
199  }
200  else
201  {
202  forAll(agglomeration_, fineLevelIndex)
203  {
204  // Agglomerate on to coarse level mesh
205  agglomerateMatrix
206  (
207  fineLevelIndex,
208  agglomeration_.meshLevel(fineLevelIndex + 1),
209  agglomeration_.interfaceLevel(fineLevelIndex + 1)
210  );
211  }
212  }
213 
214  if ((log_ >= 2) || (debug & 2))
215  {
216  for
217  (
218  label fineLevelIndex = 0;
219  fineLevelIndex <= matrixLevels_.size();
220  fineLevelIndex++
221  )
222  {
223  if (fineLevelIndex == 0 || matrixLevels_.set(fineLevelIndex-1))
224  {
225  const lduMatrix& matrix = matrixLevel(fineLevelIndex);
227  interfaceLevel(fineLevelIndex);
228 
229  Pout<< "level:" << fineLevelIndex << nl
230  << " nCells:" << matrix.diag().size() << nl
231  << " nFaces:" << matrix.lower().size() << nl
232  << " nInterfaces:" << interfaces.size()
233  << endl;
234 
235  forAll(interfaces, i)
236  {
237  if (interfaces.set(i))
238  {
239  Pout<< " " << i
240  << "\ttype:" << interfaces[i].type()
241  << endl;
242  }
243  }
244  }
245  else
246  {
247  Pout<< "level:" << fineLevelIndex << " : no matrix" << endl;
248  }
249  }
250  Pout<< endl;
251  }
252 
253 
254  if (matrixLevels_.size())
255  {
256  const label coarsestLevel = matrixLevels_.size() - 1;
257 
258  if (matrixLevels_.set(coarsestLevel))
259  {
260  if (directSolveCoarsest_)
261  {
262  coarsestLUMatrixPtr_.reset
263  (
264  new LUscalarMatrix
265  (
266  matrixLevels_[coarsestLevel],
267  interfaceLevelsBouCoeffs_[coarsestLevel],
268  interfaceLevels_[coarsestLevel]
269  )
270  );
271  }
272  else
273  {
274  entry* coarseEntry = controlDict_.findEntry
275  (
276  "coarsestLevelCorr",
278  );
279  if (coarseEntry && coarseEntry->isDict())
280  {
281  coarsestSolverPtr_ = lduMatrix::solver::New
282  (
283  "coarsestLevelCorr",
284  matrixLevels_[coarsestLevel],
285  interfaceLevelsBouCoeffs_[coarsestLevel],
286  interfaceLevelsIntCoeffs_[coarsestLevel],
287  interfaceLevels_[coarsestLevel],
288  coarseEntry->dict()
289  );
290  }
291  else if (matrixLevels_[coarsestLevel].asymmetric())
292  {
293  coarsestSolverPtr_.reset
294  (
295  new PBiCGStab
296  (
297  "coarsestLevelCorr",
298  matrixLevels_[coarsestLevel],
299  interfaceLevelsBouCoeffs_[coarsestLevel],
300  interfaceLevelsIntCoeffs_[coarsestLevel],
301  interfaceLevels_[coarsestLevel],
302  PBiCGStabSolverDict(tolerance_, relTol_)
303  )
304  );
305  }
306  else
307  {
308  coarsestSolverPtr_.reset
309  (
310  new PCG
311  (
312  "coarsestLevelCorr",
313  matrixLevels_[coarsestLevel],
314  interfaceLevelsBouCoeffs_[coarsestLevel],
315  interfaceLevelsIntCoeffs_[coarsestLevel],
316  interfaceLevels_[coarsestLevel],
317  PCGsolverDict(tolerance_, relTol_)
318  )
319  );
320  }
321  }
322  }
323  }
324  else
325  {
327  << "No coarse levels created, either matrix too small for GAMG"
328  " or nCellsInCoarsestLevel too large.\n"
329  " Either choose another solver of reduce "
330  "nCellsInCoarsestLevel."
332  }
333 }
334 
335 
336 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
337 
339 {
340  if (!cacheAgglomeration_)
341  {
342  delete &agglomeration_;
343  }
344 }
345 
346 
347 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
348 
349 void Foam::GAMGSolver::readControls()
350 {
352 
353  controlDict_.readIfPresent("cacheAgglomeration", cacheAgglomeration_);
354  controlDict_.readIfPresent("nPreSweeps", nPreSweeps_);
355  controlDict_.readIfPresent
356  (
357  "preSweepsLevelMultiplier",
358  preSweepsLevelMultiplier_
359  );
360  controlDict_.readIfPresent("maxPreSweeps", maxPreSweeps_);
361  controlDict_.readIfPresent("nPostSweeps", nPostSweeps_);
362  controlDict_.readIfPresent
363  (
364  "postSweepsLevelMultiplier",
365  postSweepsLevelMultiplier_
366  );
367  controlDict_.readIfPresent("maxPostSweeps", maxPostSweeps_);
368  controlDict_.readIfPresent("nFinestSweeps", nFinestSweeps_);
369  controlDict_.readIfPresent("interpolateCorrection", interpolateCorrection_);
370  controlDict_.readIfPresent("scaleCorrection", scaleCorrection_);
371  controlDict_.readIfPresent("directSolveCoarsest", directSolveCoarsest_);
372 
373  if ((log_ >= 2) || debug)
374  {
375  Info<< "GAMGSolver settings :"
376  << " cacheAgglomeration:" << cacheAgglomeration_
377  << " nPreSweeps:" << nPreSweeps_
378  << " preSweepsLevelMultiplier:" << preSweepsLevelMultiplier_
379  << " maxPreSweeps:" << maxPreSweeps_
380  << " nPostSweeps:" << nPostSweeps_
381  << " postSweepsLevelMultiplier:" << postSweepsLevelMultiplier_
382  << " maxPostSweeps:" << maxPostSweeps_
383  << " nFinestSweeps:" << nFinestSweeps_
384  << " interpolateCorrection:" << interpolateCorrection_
385  << " scaleCorrection:" << scaleCorrection_
386  << " directSolveCoarsest:" << directSolveCoarsest_
387  << endl;
388  }
389 }
390 
391 
392 const Foam::lduMatrix& Foam::GAMGSolver::matrixLevel(const label i) const
393 {
394  return i ? matrixLevels_[i-1] : matrix_;
395 }
396 
397 
398 const Foam::lduInterfaceFieldPtrsList& Foam::GAMGSolver::interfaceLevel
399 (
400  const label i
401 ) const
402 {
403  return i ? interfaceLevels_[i-1] : interfaces_;
404 }
405 
406 
408 Foam::GAMGSolver::interfaceBouCoeffsLevel
409 (
410  const label i
411 ) const
412 {
413  return i ? interfaceLevelsBouCoeffs_[i-1] : interfaceBouCoeffs_;
414 }
415 
416 
418 Foam::GAMGSolver::interfaceIntCoeffsLevel
419 (
420  const label i
421 ) const
422 {
423  return i ? interfaceLevelsIntCoeffs_[i-1] : interfaceIntCoeffs_;
424 }
425 
426 
427 // ************************************************************************* //
UPtrList< const lduInterfaceField > lduInterfaceFieldPtrsList
List of coupled interface fields to be used in coupling.
bool hasProcMesh(const label fineLeveli) const
Check that level has combined mesh.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
static autoPtr< GAMGInterface > New(const label index, const lduInterfacePtrsList &coarseInterfaces, const lduInterface &fineInterface, const labelField &localRestrictAddressing, const labelField &neighbourRestrictAddressing, const label fineLevelIndex, const label coarseComm)
Return a pointer to a new interface created on freestore given.
GAMGSolver(const word &fieldName, const lduMatrix &matrix, const FieldField< Field, scalar > &interfaceBouCoeffs, const FieldField< Field, scalar > &interfaceIntCoeffs, const lduInterfaceFieldPtrsList &interfaces, const dictionary &solverControls)
Construct from lduMatrix and solver controls.
Definition: GAMGSolver.C:44
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
Base class for solution control classes.
Definition: solver.H:45
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
const lduMatrix & matrix() const noexcept
Definition: lduMatrix.H:292
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
int log_
Verbosity level for solver output statements.
Definition: lduMatrix.H:149
A field of fields is a PtrList of fields with reference counting.
Definition: FieldField.H:51
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: UPtrListI.H:134
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
scalar tolerance_
Final convergence tolerance.
Definition: lduMatrix.H:169
bool processorAgglomerate() const
Whether to agglomerate across processors.
A class for handling words, derived from Foam::string.
Definition: word.H:63
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:99
const labelList & agglomProcIDs(const label fineLeveli) const
Set of processors to agglomerate. Element 0 is the master processor. (local, same only on those proce...
const lduInterfaceFieldPtrsList & interfaces() const noexcept
Definition: lduMatrix.H:307
virtual const word & type() const =0
Runtime type information.
static autoPtr< solver > New(const word &fieldName, const lduMatrix &matrix, const FieldField< Field, scalar > &interfaceBouCoeffs, const FieldField< Field, scalar > &interfaceIntCoeffs, const lduInterfaceFieldPtrsList &interfaces, const dictionary &solverControls)
Return a new solver.
lduMatrix::solver::addsymMatrixConstructorToTable< GAMGSolver > addGAMGSolverMatrixConstructorToTable_
Definition: GAMGSolver.C:34
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
dictionary controlDict_
Dictionary of solution controls.
Definition: lduMatrix.H:144
Geometric agglomerated algebraic multigrid solver.
Definition: GAMGSolver.H:71
virtual ~GAMGSolver()
Destructor.
Definition: GAMGSolver.C:331
lduMatrix is a general matrix class in which the coefficients are stored as three arrays...
Definition: lduMatrix.H:79
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
scalarField & lower()
Definition: lduMatrix.C:178
const labelList & procAgglomMap(const label fineLeveli) const
Mapping from processor to agglomerated processor (global, all processors have the same information)...
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:120
lduMatrix::solver::addasymMatrixConstructorToTable< GAMGSolver > addGAMGAsymSolverMatrixConstructorToTable_
Definition: GAMGSolver.C:37
const lduInterfacePtrsList & interfaceLevel(const label leveli) const
Return LDU interface addressing of given level.
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:80
messageStream Info
Information stream (stdout output on master, null elsewhere)
scalarField & diag()
Definition: lduMatrix.C:196
Geometric agglomerated algebraic multigrid agglomeration class.
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:256
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.
virtual void readControls()
Read the control parameters from controlDict_.
scalar relTol_
Convergence tolerance relative to the initial.
Definition: lduMatrix.H:174