GAMGSolver.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2026 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 "GAMGSolver.H"
27 #include "GAMGInterface.H"
28 #include "diagonalSolver.H"
29 #include "PCG.H"
30 #include "PBiCGStab.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
37 
38  lduMatrix::solver::addsymMatrixConstructorToTable<GAMGSolver>
40 
41  lduMatrix::solver::addasymMatrixConstructorToTable<GAMGSolver>
43 }
44 
45 
46 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
47 
49 (
50  const word& fieldName,
51  const lduMatrix& matrix,
52  const FieldField<Field, scalar>& interfaceBouCoeffs,
53  const FieldField<Field, scalar>& interfaceIntCoeffs,
54  const lduInterfaceFieldPtrsList& interfaces,
55  const dictionary& solverControls
56 )
57 :
59  (
60  fieldName,
61  matrix,
62  interfaceBouCoeffs,
63  interfaceIntCoeffs,
64  interfaces,
65  solverControls
66  ),
67 
68  // Default values for all controls
69  // which may be overridden by those in controlDict
70  cacheAgglomeration_(true),
71  nPreSweeps_(0),
72  preSweepsLevelMultiplier_(1),
73  maxPreSweeps_(4),
74  nPostSweeps_(2),
75  postSweepsLevelMultiplier_(1),
76  maxPostSweeps_(4),
77  nFinestSweeps_(2),
78  interpolateCorrection_(false),
79  scaleCorrection_(matrix.symmetric()),
80  directSolveCoarsest_(false),
81  agglomeration_(GAMGAgglomeration::New(matrix_, controlDict_)),
82 
83  matrixLevels_(agglomeration_.size()),
84  primitiveInterfaceLevels_(agglomeration_.size()),
85  interfaceLevels_(agglomeration_.size()),
86  interfaceLevelsBouCoeffs_(agglomeration_.size()),
87  interfaceLevelsIntCoeffs_(agglomeration_.size())
88 {
89  readControls();
90 
91  if (agglomeration_.processorAgglomerate())
92  {
93  forAll(agglomeration_, fineLevelIndex)
94  {
95  if (agglomeration_.hasMeshLevel(fineLevelIndex))
96  {
97  if
98  (
99  (fineLevelIndex+1) < agglomeration_.size()
100  && agglomeration_.hasProcMesh(fineLevelIndex+1)
101  )
102  {
103  // Construct matrix without referencing the coarse mesh so
104  // construct a dummy mesh instead. This will get overwritten
105  // by the call to procAgglomerateMatrix so is only to get
106  // it through agglomerateMatrix
107 
108 
109  const lduInterfacePtrsList& fineMeshInterfaces =
110  agglomeration_.interfaceLevel(fineLevelIndex);
111 
112  PtrList<GAMGInterface> dummyPrimMeshInterfaces
113  (
114  fineMeshInterfaces.size()
115  );
116  lduInterfacePtrsList dummyMeshInterfaces
117  (
118  dummyPrimMeshInterfaces.size()
119  );
120  forAll(fineMeshInterfaces, intI)
121  {
122  if (fineMeshInterfaces.set(intI))
123  {
124  OStringStream os;
125  refCast<const GAMGInterface>
126  (
127  fineMeshInterfaces[intI]
128  ).write(os);
129  IStringStream is(os.str());
130 
131  dummyPrimMeshInterfaces.set
132  (
133  intI,
135  (
136  fineMeshInterfaces[intI].type(),
137  intI,
138  dummyMeshInterfaces,
139  is
140  )
141  );
142  }
143  }
144 
145  forAll(dummyPrimMeshInterfaces, intI)
146  {
147  if (dummyPrimMeshInterfaces.set(intI))
148  {
149  dummyMeshInterfaces.set
150  (
151  intI,
152  &dummyPrimMeshInterfaces[intI]
153  );
154  }
155  }
156 
157  // So:
158  // - pass in incorrect mesh (= fine mesh instead of coarse)
159  // - pass in dummy interfaces
160  agglomerateMatrix
161  (
162  fineLevelIndex,
163  agglomeration_.meshLevel(fineLevelIndex),
164  dummyMeshInterfaces
165  );
166 
167 
168  const labelList& procAgglomMap =
169  agglomeration_.procAgglomMap(fineLevelIndex+1);
170  const List<label>& procIDs =
171  agglomeration_.agglomProcIDs(fineLevelIndex+1);
172 
173  procAgglomerateMatrix
174  (
175  procAgglomMap,
176  procIDs,
177  fineLevelIndex
178  );
179  }
180  else
181  {
182  agglomerateMatrix
183  (
184  fineLevelIndex,
185  agglomeration_.meshLevel(fineLevelIndex + 1),
186  agglomeration_.interfaceLevel(fineLevelIndex + 1)
187  );
188  }
189  }
190  else
191  {
192  // No mesh. Not involved in calculation anymore
193  }
194  }
195  }
196  else
197  {
198  forAll(agglomeration_, fineLevelIndex)
199  {
200  // Agglomerate on to coarse level mesh
201  agglomerateMatrix
202  (
203  fineLevelIndex,
204  agglomeration_.meshLevel(fineLevelIndex + 1),
205  agglomeration_.interfaceLevel(fineLevelIndex + 1)
206  );
207  }
208  }
209 
210 
211  if (debug)
212  {
213  for
214  (
215  label fineLevelIndex = 0;
216  fineLevelIndex <= matrixLevels_.size();
217  fineLevelIndex++
218  )
219  {
220  if (fineLevelIndex == 0 || matrixLevels_.set(fineLevelIndex-1))
221  {
222  const lduMatrix& matrix = matrixLevel(fineLevelIndex);
224  interfaceLevel(fineLevelIndex);
225 
226  Pout<< "level:" << fineLevelIndex << nl
227  << " nCells:" << matrix.diag().size() << nl
228  << " nFaces:" << matrix.lower().size() << nl
229  << " nInterfaces:" << interfaces.size()
230  << endl;
231 
232  forAll(interfaces, i)
233  {
234  if (interfaces.set(i))
235  {
236  Pout<< " " << i
237  << "\ttype:" << interfaces[i].type()
238  << endl;
239  }
240  }
241  }
242  else
243  {
244  Pout<< "level:" << fineLevelIndex << " : no matrix" << endl;
245  }
246  }
247  Pout<< endl;
248  }
249 
250 
251  if (matrixLevels_.size())
252  {
253  const label coarsestLevel = matrixLevels_.size() - 1;
254 
255  if (matrixLevels_.set(coarsestLevel))
256  {
257  if (directSolveCoarsest_)
258  {
259  coarsestLUMatrixPtr_.set
260  (
261  new LUscalarMatrix
262  (
263  matrixLevels_[coarsestLevel],
264  interfaceLevelsBouCoeffs_[coarsestLevel],
265  interfaceLevels_[coarsestLevel]
266  )
267  );
268  }
269  else
270  {
271  coarsestSolverPtr_ =
272  matrixLevels_[coarsestLevel].diagonal()
274  (
275  new diagonalSolver
276  (
277  "coarsestLevelCorr",
278  matrixLevels_[coarsestLevel],
279  interfaceLevelsBouCoeffs_[coarsestLevel],
280  interfaceLevelsIntCoeffs_[coarsestLevel],
281  interfaceLevels_[coarsestLevel],
282  dictionary()
283  )
284  )
285  : matrixLevels_[coarsestLevel].asymmetric()
287  (
288  new PBiCGStab
289  (
290  "coarsestLevelCorr",
291  matrixLevels_[coarsestLevel],
292  interfaceLevelsBouCoeffs_[coarsestLevel],
293  interfaceLevelsIntCoeffs_[coarsestLevel],
294  interfaceLevels_[coarsestLevel],
296  (
297  "preconditioner", "DILU",
298  "tolerance", tolerance_,
299  "relTol", relTol_
300  )
301  )
302  )
304  (
305  new PCG
306  (
307  "coarsestLevelCorr",
308  matrixLevels_[coarsestLevel],
309  interfaceLevelsBouCoeffs_[coarsestLevel],
310  interfaceLevelsIntCoeffs_[coarsestLevel],
311  interfaceLevels_[coarsestLevel],
313  (
314  "preconditioner", "DIC",
315  "tolerance", tolerance_,
316  "relTol", relTol_
317  )
318  )
319  );
320  }
321  }
322  }
323  else
324  {
326  << "No coarse levels created, either matrix too small for GAMG"
327  " or minCellsPerProcessor too large.\n"
328  " Either choose another solver of reduce "
329  "minCellsPerProcessor."
330  << exit(FatalError);
331  }
332 }
333 
334 
335 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
336 
338 {
339  if (!cacheAgglomeration_)
340  {
341  delete &agglomeration_;
342  }
343 }
344 
345 
346 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
347 
348 void Foam::GAMGSolver::readControls()
349 {
351 
352  controlDict_.readIfPresent("cacheAgglomeration", cacheAgglomeration_);
353  controlDict_.readIfPresent("nPreSweeps", nPreSweeps_);
354  controlDict_.readIfPresent
355  (
356  "preSweepsLevelMultiplier",
357  preSweepsLevelMultiplier_
358  );
359  controlDict_.readIfPresent("maxPreSweeps", maxPreSweeps_);
360  controlDict_.readIfPresent("nPostSweeps", nPostSweeps_);
361  controlDict_.readIfPresent
362  (
363  "postSweepsLevelMultiplier",
364  postSweepsLevelMultiplier_
365  );
366  controlDict_.readIfPresent("maxPostSweeps", maxPostSweeps_);
367  controlDict_.readIfPresent("nFinestSweeps", nFinestSweeps_);
368  controlDict_.readIfPresent("interpolateCorrection", interpolateCorrection_);
369  controlDict_.readIfPresent("scaleCorrection", scaleCorrection_);
370  controlDict_.readIfPresent("directSolveCoarsest", directSolveCoarsest_);
371 
372  if (debug)
373  {
374  Pout<< "GAMGSolver settings :"
375  << " cacheAgglomeration:" << cacheAgglomeration_
376  << " nPreSweeps:" << nPreSweeps_
377  << " preSweepsLevelMultiplier:" << preSweepsLevelMultiplier_
378  << " maxPreSweeps:" << maxPreSweeps_
379  << " nPostSweeps:" << nPostSweeps_
380  << " postSweepsLevelMultiplier:" << postSweepsLevelMultiplier_
381  << " maxPostSweeps:" << maxPostSweeps_
382  << " nFinestSweeps:" << nFinestSweeps_
383  << " interpolateCorrection:" << interpolateCorrection_
384  << " scaleCorrection:" << scaleCorrection_
385  << " directSolveCoarsest:" << directSolveCoarsest_
386  << endl;
387  }
388 }
389 
390 
391 const Foam::lduMatrix& Foam::GAMGSolver::matrixLevel(const label i) const
392 {
393  if (i == 0)
394  {
395  return matrix_;
396  }
397  else
398  {
399  return matrixLevels_[i - 1];
400  }
401 }
402 
403 
404 const Foam::lduInterfaceFieldPtrsList& Foam::GAMGSolver::interfaceLevel
405 (
406  const label i
407 ) const
408 {
409  if (i == 0)
410  {
411  return interfaces_;
412  }
413  else
414  {
415  return interfaceLevels_[i - 1];
416  }
417 }
418 
419 
421 Foam::GAMGSolver::interfaceBouCoeffsLevel
422 (
423  const label i
424 ) const
425 {
426  if (i == 0)
427  {
428  return interfaceBouCoeffs_;
429  }
430  else
431  {
432  return interfaceLevelsBouCoeffs_[i - 1];
433  }
434 }
435 
436 
438 Foam::GAMGSolver::interfaceIntCoeffsLevel
439 (
440  const label i
441 ) const
442 {
443  if (i == 0)
444  {
445  return interfaceIntCoeffs_;
446  }
447  else
448  {
449  return interfaceLevelsIntCoeffs_[i - 1];
450  }
451 }
452 
453 
454 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Generic field type.
Definition: FieldField.H:77
Geometric agglomerated algebraic multigrid agglomeration class.
bool processorAgglomerate() const
Whether to agglomerate across processors.
const labelList & procAgglomMap(const label fineLeveli) const
Mapping from processor to agglomerated processor (global, all.
bool hasProcMesh(const label fineLeveli) const
Check that level has combined mesh.
const labelList & agglomProcIDs(const label fineLeveli) const
Set of processors to agglomerate. Element 0 is the.
const lduInterfacePtrsList & interfaceLevel(const label leveli) const
Return LDU interface addressing of given level.
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
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.
Geometric agglomerated algebraic multigrid solver.
Definition: GAMGSolver.H:73
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:49
virtual ~GAMGSolver()
Destructor.
Definition: GAMGSolver.C:337
Input from memory buffer stream.
Definition: IStringStream.H:52
Class to perform the LU decomposition on a symmetric matrix.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
virtual Ostream & write(const char)
Write character.
Definition: OSstream.C:32
Output to memory buffer stream.
Definition: OStringStream.H:52
string str() const
Return the string.
Preconditioned bi-conjugate gradient stabilised solver for asymmetric lduMatrices using a run-time se...
Definition: PBiCGStab.H:67
Preconditioned conjugate gradient solver for symmetric lduMatrices using a run-time selectable precon...
Definition: PCG.H:52
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
bool set(const label) const
Is element set.
Definition: PtrListI.H:62
bool set(const label) const
Is element set.
Definition: UPtrListI.H:87
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Foam::diagonalSolver.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
static std::tuple< const Entries &... > entries(const Entries &...)
Construct an entries tuple from which to make a dictionary.
virtual const word & type() const =0
Runtime type information.
const lduInterfaceFieldPtrsList & interfaces() const
Definition: lduMatrix.H:241
scalar tolerance_
Final convergence tolerance.
Definition: lduMatrix.H:118
scalar relTol_
Convergence tolerance relative to the initial.
Definition: lduMatrix.H:121
virtual void readControls()
Read the control parameters from the controlDict_.
const lduMatrix & matrix() const
Definition: lduMatrix.H:226
lduMatrix is a general matrix class in which the coefficients are stored as three arrays,...
Definition: lduMatrix.H:80
scalarField & lower()
Definition: lduMatrix.C:168
scalarField & diag()
Definition: lduMatrix.C:186
Abstract base class for run-time selectable region solvers.
Definition: solver.H:56
A class for handling words, derived from string.
Definition: word.H:63
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
lduMatrix::solver::addasymMatrixConstructorToTable< GAMGSolver > addGAMGAsymSolverMatrixConstructorToTable_
Definition: GAMGSolver.C:42
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
error FatalError
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
static const char nl
Definition: Ostream.H:297
lduMatrix::solver::addsymMatrixConstructorToTable< GAMGSolver > addGAMGSolverMatrixConstructorToTable_
Definition: GAMGSolver.C:39