1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
5 \\ / A nd | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 ILU preconditioning with arbitrary level of fill in (p), based on Crout
31 Reference: Saad, Y.: Iterative Methods for Sparse Linear Systems (2nd
35 Vuko Vukcevic, FMENA Zagreb. All rights reserved
37 \*---------------------------------------------------------------------------*/
40 #include "addToRunTimeSelectionTable.H"
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
46 defineTypeNameAndDebug(ILUCp, 0);
49 addasymMatrixConstructorToTable<ILUCp>
50 addILUCpPreconditionerAsymMatrixConstructorToTable_;
52 // Add to symmetric constructor table as well until we implement Choleskyp
53 // preconditioner. VV, 27/Jun/2015.
55 addsymMatrixConstructorToTable<ILUCp>
56 addILUCpPreconditionerSymMatrixConstructorToTable_;
60 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
63 void Foam::ILUCp::calcFactorization()
65 if (!matrix_.diagonal())
67 // Get necessary const access to extended ldu addressing
68 const extendedLduAddressing& addr = extMatrix_.extendedLduAddr();
70 // Get upper/lower extended addressing
71 const label* const __restrict__ uPtr = addr.extendedUpperAddr().begin();
72 const label* const __restrict__ lPtr = addr.extendedLowerAddr().begin();
74 // Get extended owner start addressing
75 const label* const __restrict__ ownStartPtr =
76 addr.extendedOwnerStartAddr().begin();
78 // Get extended losort and losort start addressing
79 const label* const __restrict__ lsrPtr =
80 addr.extendedLosortAddr().begin();
81 const label* const __restrict__ lsrStartPtr =
82 addr.extendedLosortStartAddr().begin();
84 // Get access to factored matrix entries
85 scalar* __restrict__ diagPtr = preconDiag_.begin();
86 scalar* __restrict__ upperPtr = extMatrix_.extendedUpper().begin();
87 scalar* __restrict__ lowerPtr = extMatrix_.extendedLower().begin();
89 // Get access to working fields
90 scalar* __restrict__ zPtr = z_.begin();
91 scalar* __restrict__ wPtr = w_.begin();
94 const label nRows = preconDiag_.size();
96 // Define start and end face ("virtual" face when extended addressing is
97 // used) of this row/column, and number of non zero off diagonal entries
98 register label fStart, fEnd, fLsrStart, fLsrEnd;
100 // Crout LU factorization
102 // Row by row loop (k - loop).
103 for (register label rowI = 0; rowI < nRows; ++rowI)
105 // Start and end of k-th row (upper) and k-th column (lower)
106 fStart = ownStartPtr[rowI];
107 fEnd = ownStartPtr[rowI + 1];
109 // Initialize temporary working diagonal
110 zDiag_ = diagPtr[rowI];
112 // Initialize temporary working row field
113 for (register label faceI = fStart; faceI < fEnd; ++faceI)
115 // Note: z addressed by neighbour of face (column index for
116 // upper), w addressed by neighbour of face (row index for
118 zPtr[uPtr[faceI]] = upperPtr[faceI];
119 wPtr[uPtr[faceI]] = lowerPtr[faceI];
122 // Start and end of k-th row (lower) and k-th column (upper)
123 fLsrStart = lsrStartPtr[rowI];
124 fLsrEnd = lsrStartPtr[rowI + 1];
126 // Lower coeff loop (first i - loop)
129 register label faceLsrI = fLsrStart;
134 // Get losort coefficient for this face
135 const register label losortCoeff = lsrPtr[faceLsrI];
137 // Get corresponding row index for upper (i label)
138 const label i = lPtr[losortCoeff];
141 zDiag_ -= lowerPtr[losortCoeff]*upperPtr[losortCoeff];
143 // Get end of row for cell i
144 const register label fEndRowi = ownStartPtr[i + 1];
146 // Upper coeff loop (additional loop to avoid checking the
147 // existence of certain upper coeffs)
150 // Diagonal is already updated (losortCoeff + 1 = start)
151 register label faceI = losortCoeff + 1;
156 zPtr[uPtr[faceI]] -= lowerPtr[losortCoeff]*upperPtr[faceI];
157 wPtr[uPtr[faceI]] -= upperPtr[losortCoeff]*lowerPtr[faceI];
161 // Update diagonal entry, inverting it for future use
162 scalar& diagRowI = diagPtr[rowI];
163 diagRowI = 1.0/zDiag_;
165 // Index for updating L and U
166 register label zwIndex;
168 // Update upper and lower coeffs
169 for (register label faceI = fStart; faceI < fEnd; ++faceI)
171 // Get index for current face
172 zwIndex = uPtr[faceI];
174 // Update L and U decomposition for this row (column)
175 upperPtr[faceI] = zPtr[zwIndex];
176 lowerPtr[faceI] = wPtr[zwIndex]*diagRowI;
179 // Reset temporary working fields
182 // Only reset parts of the working fields that have been updated in
183 // this step (for this row and column)
186 register label faceLsrI = fLsrStart;
191 // Get losort coefficient for this face
192 const register label losortCoeff = lsrPtr[faceLsrI];
194 // Get corresponding row index for upper (i label)
195 const label i = lPtr[losortCoeff];
197 // Get end of row for cell i
198 const register label fEndRowi = ownStartPtr[i + 1];
202 register label faceI = losortCoeff + 1;
207 zPtr[uPtr[faceI]] = 0.0;
208 wPtr[uPtr[faceI]] = 0.0;
215 forAll (preconDiag_, i)
217 preconDiag_[i] = 1.0/preconDiag_[i];
223 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
227 const lduMatrix& matrix,
228 const FieldField<Field, scalar>& coupleBouCoeffs,
229 const FieldField<Field, scalar>& coupleIntCoeffs,
230 const lduInterfaceFieldPtrsList& interfaces,
231 const dictionary& dict
241 preconDiag_(matrix_.diag()),
242 p_(readLabel(dict.lookup("fillInLevel"))),
247 matrix.mesh().thisDb().parent().lookupObject
250 >(polyMesh::defaultRegion)
253 z_(preconDiag_.size(), 0),
254 w_(preconDiag_.size(), 0)
260 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
262 Foam::ILUCp::~ILUCp()
266 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
268 void Foam::ILUCp::precondition
271 const scalarField& b,
275 if (!matrix_.diagonal())
277 // Get matrix addressing
278 const extendedLduAddressing& addr = extMatrix_.extendedLduAddr();
279 const unallocLabelList& upperAddr = addr.extendedUpperAddr();
280 const unallocLabelList& lowerAddr = addr.extendedLowerAddr();
281 const unallocLabelList& losortAddr = addr.extendedLosortAddr();
283 // Get upper and lower matrix factors
284 const scalarField& lower = extMatrix_.extendedLower();
285 const scalarField& upper = extMatrix_.extendedUpper();
287 // Solve Lz = b with forward substitution. lower is chosen to be unit
288 // triangular. z does not need to be stored
290 // Initialize x field
293 register label losortCoeffI;
296 // Forward substitution loop
297 forAll (lower, coeffI)
299 // Get current losortCoeff to ensure row by row access
300 losortCoeffI = losortAddr[coeffI];
302 // Subtract already updated lower part from the solution
303 x[upperAddr[losortCoeffI]] -=
304 lower[losortCoeffI]*x[lowerAddr[losortCoeffI]];
307 // Solve Ux = b with back substitution. U is chosen to be upper
308 // triangular with diagonal entries corresponding to preconDiag_
310 // Multiply with inverse diagonal
313 // Back substitution loop
314 forAllReverse (upper, coeffI)
317 rowI = lowerAddr[coeffI];
319 // Subtract already updated upper part from the solution
320 x[rowI] -= upper[coeffI]*x[upperAddr[coeffI]]*preconDiag_[rowI];
327 "void ILUCp::precondition"
328 "(scalarField& x, const scalarField& b, const direction cmpt)"
329 ) << "Unnecessary use of ILUCp preconditioner for diagonal matrix. "
331 << "Use diagonal preconditioner instead."
334 // Diagonal preconditioning
337 x[i] = b[i]*preconDiag_[i];
343 void Foam::ILUCp::preconditionT
346 const scalarField& b,
350 if (!matrix_.diagonal())
352 // Get matrix addressing
353 const extendedLduAddressing& addr = extMatrix_.extendedLduAddr();
354 const unallocLabelList& upperAddr = addr.extendedUpperAddr();
355 const unallocLabelList& lowerAddr = addr.extendedLowerAddr();
356 const unallocLabelList& losortAddr = addr.extendedLosortAddr();
358 // Get upper and lower matrix factors
359 const scalarField& lower = extMatrix_.extendedLower();
360 const scalarField& upper = extMatrix_.extendedUpper();
362 // Solve U^T z = b with forward substitution. lower is chosen to
363 // be unit triangular - U^T (transpose U) "contains" diagonal entries. z
364 // does not need to be stored.
366 // Initialize x field
369 x[i] = b[i]*preconDiag_[i];
372 register label losortCoeffI;
375 // Forward substitution loop
376 forAll (upper, coeffI)
378 // Get current losortCoeff to ensure row by row access
379 losortCoeffI = losortAddr[coeffI];
382 rowI = upperAddr[losortCoeffI];
384 // Subtract already updated lower (upper transpose) part from the
386 x[rowI] -= upper[losortCoeffI]*x[lowerAddr[losortCoeffI]]*
390 // Solve L^T x = z with back substitution. L^T is unit upper triangular
392 // Back substitution loop
393 forAllReverse (lower, coeffI)
395 // Subtract already updated upper part from the solution
396 x[lowerAddr[coeffI]] -= lower[coeffI]*x[upperAddr[coeffI]];
403 "void ILUCp::preconditionT"
404 "(scalarField& x, const scalarField& b, const direction cmpt)"
405 ) << "Unnecessary use of ILUCp preconditioner for diagonal matrix. "
407 << "Use diagonal preconditioner instead."
410 // Diagonal preconditioning
413 x[i] = b[i]*preconDiag_[i];
419 // ************************************************************************* //