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 without fill in based on Crout algorithm. L and U are
29 calculated and stored.
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(ILUC0, 0);
49 addasymMatrixConstructorToTable<ILUC0>
50 addILUC0ditionerAsymMatrixConstructorToTable_;
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
57 void Foam::ILUC0::calcFactorization()
59 if (!matrix_.diagonal())
61 // Get necessary const access to matrix addressing
62 const lduAddressing& addr = matrix_.lduAddr();
64 // Get upper/lower addressing
65 const label* const __restrict__ uPtr = addr.upperAddr().begin();
66 const label* const __restrict__ lPtr = addr.lowerAddr().begin();
68 // Get owner start addressing
69 const label* const __restrict__ ownStartPtr =
70 addr.ownerStartAddr().begin();
72 // Get losort and losort start addressing
73 const label* const __restrict__ lsrPtr = addr.losortAddr().begin();
74 const label* const __restrict__ lsrStartPtr =
75 addr.losortStartAddr().begin();
77 // Get access to factored matrix entries
78 scalar* __restrict__ diagPtr = preconDiag_.begin();
79 scalar* __restrict__ upperPtr = preconUpper_.begin();
80 scalar* __restrict__ lowerPtr = preconLower_.begin();
82 // Get access to working fields
83 scalar* __restrict__ zPtr = z_.begin();
84 scalar* __restrict__ wPtr = w_.begin();
87 const label nRows = preconDiag_.size();
89 // Define start and end face of this row/column, and number of non zero
90 // off diagonal entries
91 register label fStart, fEnd, fLsrStart, fLsrEnd;
93 // Crout LU factorization
95 // Row by row loop (k - loop).
96 for (register label rowI = 0; rowI < nRows; ++rowI)
98 // Start and end of k-th row (upper) and k-th column (lower)
99 fStart = ownStartPtr[rowI];
100 fEnd = ownStartPtr[rowI + 1];
102 // Initialize temporary working diagonal
103 zDiag_ = diagPtr[rowI];
105 // Initialize temporary working row field
106 for (register label faceI = fStart; faceI < fEnd; ++faceI)
108 // Note: z addressed by neighbour of face (column index for
109 // upper), w addressed by neighbour of face (row index for
111 zPtr[uPtr[faceI]] = upperPtr[faceI];
112 wPtr[uPtr[faceI]] = lowerPtr[faceI];
115 // Start and end of k-th row (lower) and k-th column (upper)
116 fLsrStart = lsrStartPtr[rowI];
117 fLsrEnd = lsrStartPtr[rowI + 1];
119 // Lower coeff loop (first i - loop)
122 register label faceLsrI = fLsrStart;
127 // Get losort coefficient for this face
128 const register label losortCoeff = lsrPtr[faceLsrI];
130 // Get corresponding row index for upper (i label)
131 const label i = lPtr[losortCoeff];
134 zDiag_ -= lowerPtr[losortCoeff]*upperPtr[losortCoeff];
136 // Get end of row for cell i
137 const register label fEndRowi = ownStartPtr[i + 1];
139 // Upper coeff loop (additional loop to avoid checking the
140 // existence of certain upper coeffs)
143 // Diagonal is already updated (losortCoeff + 1 = start)
144 register label faceI = losortCoeff + 1;
149 zPtr[uPtr[faceI]] -= lowerPtr[losortCoeff]*upperPtr[faceI];
150 wPtr[uPtr[faceI]] -= upperPtr[losortCoeff]*lowerPtr[faceI];
154 // Update diagonal entry, inverting it for future use
155 scalar& diagRowI = diagPtr[rowI];
156 diagRowI = 1.0/zDiag_;
158 // Index for updating L and U
159 register label zwIndex;
161 // Update upper and lower coeffs
162 for (register label faceI = fStart; faceI < fEnd; ++faceI)
164 // Get index for current face
165 zwIndex = uPtr[faceI];
167 // Update L and U decomposition for this row (column)
168 upperPtr[faceI] = zPtr[zwIndex];
169 lowerPtr[faceI] = wPtr[zwIndex]*diagRowI;
172 // Reset temporary working fields
175 // Only reset parts of the working fields that have been updated in
176 // this step (for this row and column)
179 register label faceLsrI = fLsrStart;
184 // Get losort coefficient for this face
185 const register label losortCoeff = lsrPtr[faceLsrI];
187 // Get corresponding row index for upper (i label)
188 const label i = lPtr[losortCoeff];
190 // Get end of row for cell i
191 const register label fEndRowi = ownStartPtr[i + 1];
195 register label faceI = losortCoeff + 1;
200 zPtr[uPtr[faceI]] = 0.0;
201 wPtr[uPtr[faceI]] = 0.0;
208 forAll (preconDiag_, i)
210 preconDiag_[i] = 1.0/preconDiag_[i];
216 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
220 const lduMatrix& matrix,
221 const FieldField<Field, scalar>& coupleBouCoeffs,
222 const FieldField<Field, scalar>& coupleIntCoeffs,
223 const lduInterfaceFieldPtrsList& interfaces,
224 const dictionary& dict
234 preconDiag_(matrix_.diag()),
235 preconLower_(matrix.lower()),
236 preconUpper_(matrix.upper()),
238 z_(preconDiag_.size(), 0),
239 w_(preconDiag_.size(), 0)
247 const lduMatrix& matrix,
248 const FieldField<Field, scalar>& coupleBouCoeffs,
249 const FieldField<Field, scalar>& coupleIntCoeffs,
250 const lduInterfaceFieldPtrsList& interfaces
260 preconDiag_(matrix_.diag()),
261 preconLower_(matrix.lower()),
262 preconUpper_(matrix.upper()),
264 z_(preconDiag_.size(), 0),
265 w_(preconDiag_.size(), 0)
271 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
273 Foam::ILUC0::~ILUC0()
277 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
279 void Foam::ILUC0::precondition
282 const scalarField& b,
286 if (!matrix_.diagonal())
288 // Get matrix addressing
289 const lduAddressing& addr = matrix_.lduAddr();
290 const unallocLabelList& upperAddr = addr.upperAddr();
291 const unallocLabelList& lowerAddr = addr.lowerAddr();
292 const unallocLabelList& losortAddr = addr.losortAddr();
294 // Solve Lz = b with forward substitution. preconLower_ is chosen to
295 // be unit triangular. z does not need to be stored
297 // Initialize x field
300 register label losortCoeffI;
303 // Forward substitution loop
304 forAll (preconLower_, coeffI)
306 // Get current losortCoeff to ensure row by row access
307 losortCoeffI = losortAddr[coeffI];
309 // Subtract already updated lower part from the solution
310 x[upperAddr[losortCoeffI]] -=
311 preconLower_[losortCoeffI]*x[lowerAddr[losortCoeffI]];
314 // Solve Ux = b with back substitution. U is chosen to be upper
315 // triangular with diagonal entries corresponding to preconDiag_
317 // Multiply with inverse diagonal
320 // Back substitution loop
321 forAllReverse (preconUpper_, coeffI)
324 rowI = lowerAddr[coeffI];
326 // Subtract already updated upper part from the solution
328 preconUpper_[coeffI]*x[upperAddr[coeffI]]*preconDiag_[rowI];
335 "void ILUC0::precondition"
336 "(scalarField& x, const scalarField& b, const direction cmpt)"
337 ) << "Unnecessary use of ILUC0 preconditioner for diagonal matrix. "
339 << "Use diagonal preconditioner instead."
342 // Diagonal preconditioning
345 x[i] = b[i]*preconDiag_[i];
351 void Foam::ILUC0::preconditionT
354 const scalarField& b,
358 if (!matrix_.diagonal())
360 // Get matrix addressing
361 const lduAddressing& addr = matrix_.lduAddr();
362 const unallocLabelList& upperAddr = addr.upperAddr();
363 const unallocLabelList& lowerAddr = addr.lowerAddr();
364 const unallocLabelList& losortAddr = addr.losortAddr();
366 // Solve U^T z = b with forward substitution. preconLower_ is chosen to
367 // be unit triangular - U^T (transpose U) "contains" diagonal entries. z
368 // does not need to be stored.
370 // Initialize x field
373 x[i] = b[i]*preconDiag_[i];
376 register label losortCoeffI;
379 // Forward substitution loop
380 forAll (preconUpper_, coeffI)
382 // Get current losortCoeff to ensure row by row access
383 losortCoeffI = losortAddr[coeffI];
386 rowI = upperAddr[losortCoeffI];
388 // Subtract already updated lower (upper transpose) part from the
390 x[rowI] -= preconUpper_[losortCoeffI]*x[lowerAddr[losortCoeffI]]*
394 // Solve L^T x = z with back substitution. L^T is unit upper triangular
396 // Back substitution loop
397 forAllReverse (preconLower_, coeffI)
399 // Subtract already updated upper part from the solution
400 x[lowerAddr[coeffI]] -= preconLower_[coeffI]*x[upperAddr[coeffI]];
407 "void ILUC0::preconditionT"
408 "(scalarField& x, const scalarField& b, const direction cmpt)"
409 ) << "Unnecessary use of ILUC0 preconditioner for diagonal matrix. "
411 << "Use diagonal preconditioner instead."
414 // Diagonal preconditioning
417 x[i] = b[i]*preconDiag_[i];
423 // ************************************************************************* //