PCICG.C 5.63 KB
Newer Older
Henry's avatar
Henry committed
1 2 3 4
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
OpenFOAM bot's avatar
OpenFOAM bot committed
5
    \\  /    A nd           | www.openfoam.com
Henry's avatar
Henry committed
6
     \\/     M anipulation  |
OpenFOAM bot's avatar
OpenFOAM bot committed
7
-------------------------------------------------------------------------------
OpenFOAM bot's avatar
OpenFOAM bot committed
8
    Copyright (C) 2011-2016 OpenFOAM Foundation
Henry's avatar
Henry committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

    OpenFOAM is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.

    You should have received a copy of the GNU General Public License
    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.

\*---------------------------------------------------------------------------*/

28
#include "PCICG.H"
Henry's avatar
Henry committed
29 30 31 32

// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

template<class Type, class DType, class LUType>
33
Foam::PCICG<Type, DType, LUType>::PCICG
Henry's avatar
Henry committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
(
    const word& fieldName,
    const LduMatrix<Type, DType, LUType>& matrix,
    const dictionary& solverDict
)
:
    LduMatrix<Type, DType, LUType>::solver
    (
        fieldName,
        matrix,
        solverDict
    )
{}


// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //

template<class Type, class DType, class LUType>
52
typename Foam::SolverPerformance<Type>
53
Foam::PCICG<Type, DType, LUType>::solve(Field<Type>& psi) const
Henry's avatar
Henry committed
54
{
55
    const word preconditionerName(this->controlDict_.getWord("preconditioner"));
Henry's avatar
Henry committed
56 57

    // --- Setup class containing solver performance data
58
    SolverPerformance<Type> solverPerf
Henry's avatar
Henry committed
59 60 61 62 63
    (
        preconditionerName + typeName,
        this->fieldName_
    );

64 65
    label nIter = 0;

66
    label nCells = psi.size();
Henry's avatar
Henry committed
67 68 69 70 71 72 73 74 75

    Type* __restrict__ psiPtr = psi.begin();

    Field<Type> pA(nCells);
    Type* __restrict__ pAPtr = pA.begin();

    Field<Type> wA(nCells);
    Type* __restrict__ wAPtr = wA.begin();

76
    Type wArA = solverPerf.great_*pTraits<Type>::one;
Henry's avatar
Henry committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    Type wArAold = wArA;

    // --- Calculate A.psi
    this->matrix_.Amul(wA, psi);

    // --- Calculate initial residual field
    Field<Type> rA(this->matrix_.source() - wA);
    Type* __restrict__ rAPtr = rA.begin();

    // --- Calculate normalisation factor
    Type normFactor = this->normFactor(psi, wA, pA);

    if (LduMatrix<Type, DType, LUType>::debug >= 2)
    {
        Info<< "   Normalisation factor = " << normFactor << endl;
    }

    // --- Calculate normalised residual norm
    solverPerf.initialResidual() = cmptDivide(gSumCmptMag(rA), normFactor);
    solverPerf.finalResidual() = solverPerf.initialResidual();

    // --- Check convergence, solve if not converged
99 100 101 102 103
    if
    (
        this->minIter_ > 0
     || !solverPerf.checkConvergence(this->tolerance_, this->relTol_)
    )
Henry's avatar
Henry committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    {
        // --- Select and construct the preconditioner
        autoPtr<typename LduMatrix<Type, DType, LUType>::preconditioner>
        preconPtr = LduMatrix<Type, DType, LUType>::preconditioner::New
        (
            *this,
            this->controlDict_
        );

        // --- Solver iteration
        do
        {
            // --- Store previous wArA
            wArAold = wArA;

            // --- Precondition residual
            preconPtr->precondition(wA, rA);

            // --- Update search directions:
            wArA = gSumCmptProd(wA, rA);

125
            if (nIter == 0)
Henry's avatar
Henry committed
126
            {
127
                for (label cell=0; cell<nCells; cell++)
Henry's avatar
Henry committed
128 129 130 131 132 133 134 135 136
                {
                    pAPtr[cell] = wAPtr[cell];
                }
            }
            else
            {
                Type beta = cmptDivide
                (
                    wArA,
137
                    stabilise(wArAold, solverPerf.vsmall_)
Henry's avatar
Henry committed
138 139
                );

140
                for (label cell=0; cell<nCells; cell++)
Henry's avatar
Henry committed
141 142 143 144 145 146 147 148 149 150 151 152 153
                {
                    pAPtr[cell] = wAPtr[cell] + cmptMultiply(beta, pAPtr[cell]);
                }
            }


            // --- Update preconditioned residual
            this->matrix_.Amul(wA, pA);

            Type wApA = gSumCmptProd(wA, pA);


            // --- Test for singularity
154 155 156 157 158 159 160
            if
            (
                solverPerf.checkSingularity
                (
                    cmptDivide(cmptMag(wApA), normFactor)
                )
            )
Henry's avatar
Henry committed
161 162 163 164 165 166 167 168 169 170
            {
                break;
            }


            // --- Update solution and residual:

            Type alpha = cmptDivide
            (
                wArA,
171
                stabilise(wApA, solverPerf.vsmall_)
Henry's avatar
Henry committed
172 173
            );

174
            for (label cell=0; cell<nCells; cell++)
Henry's avatar
Henry committed
175 176 177 178 179 180 181 182 183 184
            {
                psiPtr[cell] += cmptMultiply(alpha, pAPtr[cell]);
                rAPtr[cell] -= cmptMultiply(alpha, wAPtr[cell]);
            }

            solverPerf.finalResidual() =
                cmptDivide(gSumCmptMag(rA), normFactor);

        } while
        (
185
            (
186
                nIter++ < this->maxIter_
187 188
            && !solverPerf.checkConvergence(this->tolerance_, this->relTol_)
            )
189
         || nIter < this->minIter_
Henry's avatar
Henry committed
190 191 192
        );
    }

193 194 195
    solverPerf.nIterations() =
        pTraits<typename pTraits<Type>::labelType>::one*nIter;

Henry's avatar
Henry committed
196 197 198 199 200
    return solverPerf;
}


// ************************************************************************* //