ILUCp preconditioner - ILU with run-time selectable level of fill in
[foam-extend-4.0.git] / src / lduSolvers / lduPrecon / ILUCp / ILUCp.C
blobc80ea1d1ef6ebb91f4d170216c50e22299ebeb24
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     |
5     \\  /    A nd           | For copyright notice see file Copyright
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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/>.
24 Class
25     ILUCp
27 Description
28     ILU preconditioning with arbitrary level of fill in (p), based on Crout
29     algorithm.
31     Reference: Saad, Y.: Iterative Methods for Sparse Linear Systems (2nd
32     Edition), SIAM, 2003.
34 Author
35     Vuko Vukcevic, FMENA Zagreb. All rights reserved
37 \*---------------------------------------------------------------------------*/
39 #include "ILUCp.H"
40 #include "addToRunTimeSelectionTable.H"
42 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 namespace Foam
46     defineTypeNameAndDebug(ILUCp, 0);
48     lduPreconditioner::
49         addasymMatrixConstructorToTable<ILUCp>
50         addILUCpPreconditionerAsymMatrixConstructorToTable_;
52     // Add to symmetric constructor table as well until we implement Choleskyp
53     // preconditioner. VV, 27/Jun/2015.
54     lduPreconditioner::
55         addsymMatrixConstructorToTable<ILUCp>
56         addILUCpPreconditionerSymMatrixConstructorToTable_;
60 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
63 void Foam::ILUCp::calcFactorization()
65     if (!matrix_.diagonal())
66     {
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();
93         // Get number of rows
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)
104         {
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)
114             {
115                 // Note: z addressed by neighbour of face (column index for
116                 // upper), w addressed by neighbour of face (row index for
117                 // lower)
118                 zPtr[uPtr[faceI]] = upperPtr[faceI];
119                 wPtr[uPtr[faceI]] = lowerPtr[faceI];
120             }
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)
127             for
128             (
129                 register label faceLsrI = fLsrStart;
130                 faceLsrI < fLsrEnd;
131                 ++faceLsrI
132             )
133             {
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];
140                 // Update diagonal
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)
148                 for
149                 (
150                     // Diagonal is already updated (losortCoeff + 1 = start)
151                     register label faceI = losortCoeff + 1;
152                     faceI < fEndRowi;
153                     ++faceI
154                 )
155                 {
156                     zPtr[uPtr[faceI]] -= lowerPtr[losortCoeff]*upperPtr[faceI];
157                     wPtr[uPtr[faceI]] -= upperPtr[losortCoeff]*lowerPtr[faceI];
158                 }
159             }
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)
170             {
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;
177             }
179             // Reset temporary working fields
180             zDiag_ = 0;
182             // Only reset parts of the working fields that have been updated in
183             // this step (for this row and column)
184             for
185             (
186                 register label faceLsrI = fLsrStart;
187                 faceLsrI < fLsrEnd;
188                 ++faceLsrI
189             )
190             {
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];
200                 for
201                 (
202                     register label faceI = losortCoeff + 1;
203                     faceI < fEndRowi;
204                     ++faceI
205                 )
206                 {
207                     zPtr[uPtr[faceI]] = 0.0;
208                     wPtr[uPtr[faceI]] = 0.0;
209                 }
210             }
211         }
212     }
213     else
214     {
215         forAll (preconDiag_, i)
216         {
217             preconDiag_[i] = 1.0/preconDiag_[i];
218         }
219     }
223 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
225 Foam::ILUCp::ILUCp
227     const lduMatrix& matrix,
228     const FieldField<Field, scalar>& coupleBouCoeffs,
229     const FieldField<Field, scalar>& coupleIntCoeffs,
230     const lduInterfaceFieldPtrsList& interfaces,
231     const dictionary& dict
234     lduPreconditioner
235     (
236         matrix,
237         coupleBouCoeffs,
238         coupleIntCoeffs,
239         interfaces
240     ),
241     preconDiag_(matrix_.diag()),
242     p_(readLabel(dict.lookup("fillInLevel"))),
243     extMatrix_
244     (
245         matrix,
246         p_,
247         matrix.mesh().thisDb().parent().lookupObject
248         <
249             polyMesh
250         >(polyMesh::defaultRegion)
251     ),
252     zDiag_(0),
253     z_(preconDiag_.size(), 0),
254     w_(preconDiag_.size(), 0)
256     calcFactorization();
260 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
262 Foam::ILUCp::~ILUCp()
266 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
268 void Foam::ILUCp::precondition
270     scalarField& x,
271     const scalarField& b,
272     const direction
273 ) const
275     if (!matrix_.diagonal())
276     {
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
291         x = b;
293         register label losortCoeffI;
294         register label rowI;
296         // Forward substitution loop
297         forAll (lower, coeffI)
298         {
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]];
305         }
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
311         x *= preconDiag_;
313         // Back substitution loop
314         forAllReverse (upper, coeffI)
315         {
316             // Get row index
317             rowI = lowerAddr[coeffI];
319             // Subtract already updated upper part from the solution
320             x[rowI] -= upper[coeffI]*x[upperAddr[coeffI]]*preconDiag_[rowI];
321         }
322     }
323     else
324     {
325         WarningIn
326         (
327             "void ILUCp::precondition"
328             "(scalarField& x, const scalarField& b, const direction cmpt)"
329         )   << "Unnecessary use of ILUCp preconditioner for diagonal matrix. "
330             << nl
331             << "Use diagonal preconditioner instead."
332             << endl;
334         // Diagonal preconditioning
335         forAll(x, i)
336         {
337             x[i] = b[i]*preconDiag_[i];
338         }
339     }
343 void Foam::ILUCp::preconditionT
345     scalarField& x,
346     const scalarField& b,
347     const direction cmpt
348 ) const
350     if (!matrix_.diagonal())
351     {
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
367         forAll(x, i)
368         {
369             x[i] = b[i]*preconDiag_[i];
370         }
372         register label losortCoeffI;
373         register label rowI;
375         // Forward substitution loop
376         forAll (upper, coeffI)
377         {
378             // Get current losortCoeff to ensure row by row access
379             losortCoeffI = losortAddr[coeffI];
381             // Get row index
382             rowI = upperAddr[losortCoeffI];
384             // Subtract already updated lower (upper transpose) part from the
385             // solution
386             x[rowI] -= upper[losortCoeffI]*x[lowerAddr[losortCoeffI]]*
387                 preconDiag_[rowI];
388         }
390         // Solve L^T x = z with back substitution. L^T is unit upper triangular
392         // Back substitution loop
393         forAllReverse (lower, coeffI)
394         {
395             // Subtract already updated upper part from the solution
396             x[lowerAddr[coeffI]] -= lower[coeffI]*x[upperAddr[coeffI]];
397         }
398     }
399     else
400     {
401         WarningIn
402         (
403             "void ILUCp::preconditionT"
404             "(scalarField& x, const scalarField& b, const direction cmpt)"
405         )   << "Unnecessary use of ILUCp preconditioner for diagonal matrix. "
406             << nl
407             << "Use diagonal preconditioner instead."
408             << endl;
410         // Diagonal preconditioning
411         forAll(x, i)
412         {
413             x[i] = b[i]*preconDiag_[i];
414         }
415     }
419 // ************************************************************************* //