typename Foam::BlockSolverPerformance<Type> Foam::BlockAmgSolver<Type>::solve ( Field<Type>& x, const Field<Type>& b ) { // Prepare solver performance BlockSolverPerformance<Type> solverPerf ( typeName, this->fieldName() ); scalar norm = this->normFactor(x, b); // Calculate initial residual solverPerf.initialResidual() = gSum(cmptMag(amg_.residual(x, b)))/norm; solverPerf.finalResidual() = solverPerf.initialResidual(); if (!this->stop(solverPerf)) { do { amg_.cycle(x, b); solverPerf.finalResidual() = gSum(cmptMag(amg_.residual(x, b)))/norm; solverPerf.nIterations()++; } while (!this->stop(solverPerf)); } return solverPerf; }
typename Foam::BlockSolverPerformance<Type> Foam::BlockGaussSeidelSolver<Type>::solve ( Field<Type>& x, const Field<Type>& b ) { // Create local references to avoid the spread this-> ugliness const BlockLduMatrix<Type>& matrix = this->matrix_; // Prepare solver performance BlockSolverPerformance<Type> solverPerf ( typeName, this->fieldName() ); scalar norm = this->normFactor(x, b); Field<Type> wA(x.size()); // Calculate residual. Note: sign of residual swapped for efficiency matrix.Amul(wA, x); wA -= b; solverPerf.initialResidual() = gSum(cmptMag(wA))/norm; solverPerf.finalResidual() = solverPerf.initialResidual(); // Check convergence, solve if not converged if (!this->stop(solverPerf)) { // Iteration loop do { for (label i = 0; i < nSweeps_; i++) { gs_.precondition(x, b); solverPerf.nIterations()++; } // Re-calculate residual. Note: sign of residual swapped // for efficiency matrix.Amul(wA, x); wA -= b; solverPerf.finalResidual() = gSum(cmptMag(wA))/norm; solverPerf.nIterations()++; } while (!this->stop(solverPerf)); } return solverPerf; }
void Foam::prghPressureFvPatchScalarField::updateCoeffs() { if (updated()) { return; } const scalarField& rhop = patch().lookupPatchField<volScalarField, scalar> ( rhoName_ ); const uniformDimensionedVectorField& g = db().lookupObject<uniformDimensionedVectorField>("g"); const uniformDimensionedScalarField& hRef = db().lookupObject<uniformDimensionedScalarField>("hRef"); dimensionedScalar ghRef ( mag(g.value()) > SMALL ? g & (cmptMag(g.value())/mag(g.value()))*hRef : dimensionedScalar("ghRef", g.dimensions()*dimLength, 0) ); operator==(p_ - rhop*((g.value() & patch().Cf()) - ghRef.value())); fixedValueFvPatchScalarField::updateCoeffs(); }
void Foam::fv::tabulatedAccelerationSource::addSup ( const RhoFieldType& rho, fvMatrix<vector>& eqn, const label fieldi ) { Vector<vector> acceleration(motion_.acceleration()); // If gravitational force is present combine with the linear acceleration if (mesh_.foundObject<uniformDimensionedVectorField>("g")) { uniformDimensionedVectorField& g = mesh_.lookupObjectRef<uniformDimensionedVectorField>("g"); const uniformDimensionedScalarField& hRef = mesh_.lookupObject<uniformDimensionedScalarField>("hRef"); g = g0_ - dimensionedVector("a", dimAcceleration, acceleration.x()); dimensionedScalar ghRef ( mag(g.value()) > SMALL ? g & (cmptMag(g.value())/mag(g.value()))*hRef : dimensionedScalar("ghRef", g.dimensions()*dimLength, 0) ); mesh_.lookupObjectRef<volScalarField>("gh") = (g & mesh_.C()) - ghRef; mesh_.lookupObjectRef<surfaceScalarField>("ghf") = (g & mesh_.Cf()) - ghRef; } // ... otherwise include explicitly in the momentum equation else { eqn -= rho*dimensionedVector("a", dimAcceleration, acceleration.x()); } dimensionedVector Omega ( "Omega", dimensionSet(0, 0, -1, 0, 0), acceleration.y() ); dimensionedVector dOmegaDT ( "dOmegaDT", dimensionSet(0, 0, -2, 0, 0), acceleration.z() ); eqn -= ( rho*(2*Omega ^ eqn.psi()) // Coriolis force + rho*(Omega ^ (Omega ^ mesh_.C())) // Centrifugal force + rho*(dOmegaDT ^ mesh_.C()) // Angular tabulatedAcceleration force ); }
typename Foam::BlockSolverPerformance<Type> Foam::BlockGMRESSolver<Type>::solve ( Field<Type>& x, const Field<Type>& b ) { // Create local references to avoid the spread this-> ugliness const BlockLduMatrix<Type>& matrix = this->matrix_; // Prepare solver performance BlockSolverPerformance<Type> solverPerf ( typeName, this->fieldName() ); scalar norm = this->normFactor(x, b); // Multiplication helper typename BlockCoeff<Type>::multiply mult; Field<Type> wA(x.size()); // Calculate initial residual matrix.Amul(wA, x); Field<Type> rA(b - wA); solverPerf.initialResidual() = gSum(cmptMag(rA))/norm; solverPerf.finalResidual() = solverPerf.initialResidual(); // Check convergence, solve if not converged if (!solverPerf.checkConvergence(this->tolerance(), this->relTolerance())) { // Create the Hesenberg matrix scalarSquareMatrix H(nDirs_, 0); // Create y and b for Hessenberg matrix scalarField yh(nDirs_, 0); scalarField bh(nDirs_ + 1, 0); // Givens rotation vectors scalarField c(nDirs_, 0); scalarField s(nDirs_, 0); // Allocate Krylov space vectors FieldField<Field, Type> V(nDirs_ + 1); forAll (V, i) { V.set(i, new Field<Type>(x.size(), pTraits<Type>::zero)); }
void Foam::prghTotalPressureFvPatchScalarField::updateCoeffs() { if (updated()) { return; } const scalarField& rhop = patch().lookupPatchField<volScalarField, scalar>(rhoName_); const scalarField& phip = patch().lookupPatchField<surfaceScalarField, scalar>(phiName_); const vectorField& Up = patch().lookupPatchField<volVectorField, vector>(UName_); const uniformDimensionedVectorField& g = db().lookupObject<uniformDimensionedVectorField>("g"); const uniformDimensionedScalarField& hRef = db().lookupObject<uniformDimensionedScalarField>("hRef"); dimensionedScalar ghRef ( mag(g.value()) > SMALL ? g & (cmptMag(g.value())/mag(g.value()))*hRef : dimensionedScalar("ghRef", g.dimensions()*dimLength, 0) ); operator== ( p0_ - 0.5*rhop*(1.0 - pos(phip))*magSqr(Up) - rhop*((g.value() & patch().Cf()) - ghRef.value()) ); fixedValueFvPatchScalarField::updateCoeffs(); }
void Foam::polyMesh::calcDirections() const { for (direction cmpt=0; cmpt<vector::nComponents; cmpt++) { solutionD_[cmpt] = 1; } // Knock out empty and wedge directions. Note:they will be present on all // domains. label nEmptyPatches = 0; label nWedgePatches = 0; vector emptyDirVec = vector::zero; vector wedgeDirVec = vector::zero; forAll(boundaryMesh(), patchi) { if (boundaryMesh()[patchi].size()) { if (isA<emptyPolyPatch>(boundaryMesh()[patchi])) { nEmptyPatches++; emptyDirVec += sum(cmptMag(boundaryMesh()[patchi].faceAreas())); } else if (isA<wedgePolyPatch>(boundaryMesh()[patchi])) { const wedgePolyPatch& wpp = refCast<const wedgePolyPatch> ( boundaryMesh()[patchi] ); nWedgePatches++; wedgeDirVec += cmptMag(wpp.centreNormal()); } } } reduce(nEmptyPatches, maxOp<label>()); reduce(nWedgePatches, maxOp<label>()); if (nEmptyPatches) { reduce(emptyDirVec, sumOp<vector>()); emptyDirVec /= mag(emptyDirVec); for (direction cmpt=0; cmpt<vector::nComponents; cmpt++) { if (emptyDirVec[cmpt] > 1e-6) { solutionD_[cmpt] = -1; } else { solutionD_[cmpt] = 1; } } } // Knock out wedge directions geometricD_ = solutionD_; if (nWedgePatches) { reduce(wedgeDirVec, sumOp<vector>()); wedgeDirVec /= mag(wedgeDirVec); for (direction cmpt=0; cmpt<vector::nComponents; cmpt++) { if (wedgeDirVec[cmpt] > 1e-6) { geometricD_[cmpt] = -1; } else { geometricD_[cmpt] = 1; } } } }
typename Foam::SolverPerformance<Type> Foam::PCICG<Type, DType, LUType>::solve(Field<Type>& psi) const { word preconditionerName(this->controlDict_.lookup("preconditioner")); // --- Setup class containing solver performance data SolverPerformance<Type> solverPerf ( preconditionerName + typeName, this->fieldName_ ); label nCells = psi.size(); Type* __restrict__ psiPtr = psi.begin(); Field<Type> pA(nCells); Type* __restrict__ pAPtr = pA.begin(); Field<Type> wA(nCells); Type* __restrict__ wAPtr = wA.begin(); Type wArA = solverPerf.great_*pTraits<Type>::one; 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 if ( this->minIter_ > 0 || !solverPerf.checkConvergence(this->tolerance_, this->relTol_) ) { // --- 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); if (solverPerf.nIterations() == 0) { for (label cell=0; cell<nCells; cell++) { pAPtr[cell] = wAPtr[cell]; } } else { Type beta = cmptDivide ( wArA, stabilise(wArAold, solverPerf.vsmall_) ); for (label cell=0; cell<nCells; cell++) { pAPtr[cell] = wAPtr[cell] + cmptMultiply(beta, pAPtr[cell]); } } // --- Update preconditioned residual this->matrix_.Amul(wA, pA); Type wApA = gSumCmptProd(wA, pA); // --- Test for singularity if ( solverPerf.checkSingularity ( cmptDivide(cmptMag(wApA), normFactor) ) ) { break; } // --- Update solution and residual: Type alpha = cmptDivide ( wArA, stabilise(wApA, solverPerf.vsmall_) ); for (label cell=0; cell<nCells; cell++) { psiPtr[cell] += cmptMultiply(alpha, pAPtr[cell]); rAPtr[cell] -= cmptMultiply(alpha, wAPtr[cell]); } solverPerf.finalResidual() = cmptDivide(gSumCmptMag(rA), normFactor); } while ( ( solverPerf.nIterations()++ < this->maxIter_ && !solverPerf.checkConvergence(this->tolerance_, this->relTol_) ) || solverPerf.nIterations() < this->minIter_ ); } return solverPerf; }
void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::calcFit ( scalarList& coeffsi, const List<point>& C, const scalar wLin, const label facei ) { vector idir(1,0,0); vector jdir(0,1,0); vector kdir(0,0,1); findFaceDirs(idir, jdir, kdir, facei); // Setup the point weights scalarList wts(C.size(), scalar(1)); wts[0] = centralWeight_; if (linearCorrection_) { wts[1] = centralWeight_; } // Reference point point p0 = this->mesh().faceCentres()[facei]; // Info << "Face " << facei << " at " << p0 << " stencil points at:\n" // << C - p0 << endl; // p0 -> p vector in the face-local coordinate system vector d; // Local coordinate scaling scalar scale = 1; // Matrix of the polynomial components scalarRectangularMatrix B(C.size(), minSize_, scalar(0)); for(label ip = 0; ip < C.size(); ip++) { const point& p = C[ip]; d.x() = (p - p0)&idir; d.y() = (p - p0)&jdir; # ifndef SPHERICAL_GEOMETRY d.z() = (p - p0)&kdir; # else d.z() = mag(p) - mag(p0); # endif if (ip == 0) { scale = cmptMax(cmptMag((d))); } // Scale the radius vector d /= scale; Polynomial::addCoeffs ( B[ip], d, wts[ip], dim_ ); } // Additional weighting for constant and linear terms for(label i = 0; i < B.n(); i++) { B[i][0] *= wts[0]; B[i][1] *= wts[0]; } // Set the fit label stencilSize = C.size(); coeffsi.setSize(stencilSize); bool goodFit = false; for(int iIt = 0; iIt < 8 && !goodFit; iIt++) { SVD svd(B, SMALL); scalar maxCoeff = 0; label maxCoeffi = 0; for(label i=0; i<stencilSize; i++) { coeffsi[i] = wts[0]*wts[i]*svd.VSinvUt()[0][i]; if (mag(coeffsi[i]) > maxCoeff) { maxCoeff = mag(coeffsi[i]); maxCoeffi = i; } } if (linearCorrection_) { goodFit = (mag(coeffsi[0] - wLin) < linearLimitFactor_*wLin) && (mag(coeffsi[1] - (1 - wLin)) < linearLimitFactor_*(1 - wLin)) && maxCoeffi <= 1; } else { // Upwind: weight on face is 1. goodFit = (mag(coeffsi[0] - 1.0) < linearLimitFactor_*1.0) && maxCoeffi <= 1; } // if (goodFit && iIt > 0) // { // Info << "FitData<Polynomial>::calcFit" // << "(const List<point>& C, const label facei" << nl // << "Can now fit face " << facei << " iteration " << iIt // << " with sum of weights " << sum(coeffsi) << nl // << " Weights " << coeffsi << nl // << " Linear weights " << wLin << " " << 1 - wLin << nl // << " sing vals " << svd.S() << endl; // } if (!goodFit) // (not good fit so increase weight in the centre and weight // for constant and linear terms) { // if (iIt == 7) // { // WarningIn // ( // "FitData<Polynomial>::calcFit" // "(const List<point>& C, const label facei" // ) << "Cannot fit face " << facei << " iteration " << iIt // << " with sum of weights " << sum(coeffsi) << nl // << " Weights " << coeffsi << nl // << " Linear weights " << wLin << " " << 1 - wLin << nl // << " sing vals " << svd.S() << endl; // } wts[0] *= 10; if (linearCorrection_) { wts[1] *= 10; } for(label j = 0; j < B.m(); j++) { B[0][j] *= 10; B[1][j] *= 10; } for(label i = 0; i < B.n(); i++) { B[i][0] *= 10; B[i][1] *= 10; } } } if (goodFit) { if (linearCorrection_) { // Remove the uncorrected linear coefficients coeffsi[0] -= wLin; coeffsi[1] -= 1 - wLin; } else { // Remove the uncorrected upwind coefficients coeffsi[0] -= 1.0; } } else { // if (debug) // { WarningIn ( "FitData<Polynomial>::calcFit(..)" ) << "Could not fit face " << facei << " Weights = " << coeffsi << ", reverting to linear." << nl << " Linear weights " << wLin << " " << 1 - wLin << endl; // } coeffsi = 0; } }
// Returns miss or hit with face (0..5) and region(always 0) Foam::pointIndexHit Foam::searchableBox::findNearest ( const point& bbMid, const point& sample, const scalar nearestDistSqr ) const { // Point can be inside or outside. For every component direction can be // left of min, right of max or inbetween. // - outside points: project first one x plane (either min().x() // or max().x()), then onto y plane and finally z. You should be left // with intersection point // - inside point: find nearest side (compare to mid point). Project onto // that. // The face is set to the last projected face. // Outside point projected onto cube. Assume faces 0..5. pointIndexHit info(true, sample, -1); bool outside = false; // (for internal points) per direction what nearest cube side is point near; for (direction dir = 0; dir < vector::nComponents; dir++) { if (info.rawPoint()[dir] < min()[dir]) { projectOntoCoordPlane(dir, min(), info); outside = true; } else if (info.rawPoint()[dir] > max()[dir]) { projectOntoCoordPlane(dir, max(), info); outside = true; } else if (info.rawPoint()[dir] > bbMid[dir]) { near[dir] = max()[dir]; } else { near[dir] = min()[dir]; } } // For outside points the info will be correct now. Handle inside points // using the three near distances. Project onto the nearest plane. if (!outside) { vector dist(cmptMag(info.rawPoint() - near)); if (dist.x() < dist.y()) { if (dist.x() < dist.z()) { // Project onto x plane projectOntoCoordPlane(vector::X, near, info); } else { projectOntoCoordPlane(vector::Z, near, info); } } else { if (dist.y() < dist.z()) { projectOntoCoordPlane(vector::Y, near, info); } else { projectOntoCoordPlane(vector::Z, near, info); } } } // Check if outside. Optimisation: could do some checks on distance already // on components above if (magSqr(info.rawPoint() - sample) > nearestDistSqr) { info.setMiss(); info.setIndex(-1); } return info; }
forAll (nei, faceI) { sumMagClosed[nei[faceI]] += cmptMag(areas[faceI]); }
void Foam::CentredFitSnGradData<Polynomial>::calcFit ( scalarList& coeffsi, const List<point>& C, const scalar wLin, const scalar deltaCoeff, const label facei ) { vector idir(1,0,0); vector jdir(0,1,0); vector kdir(0,0,1); this->findFaceDirs(idir, jdir, kdir, facei); // Setup the point weights scalarList wts(C.size(), scalar(1)); wts[0] = this->centralWeight(); wts[1] = this->centralWeight(); // Reference point point p0 = this->mesh().faceCentres()[facei]; // p0 -> p vector in the face-local coordinate system vector d; // Local coordinate scaling scalar scale = 1; // Matrix of the polynomial components scalarRectangularMatrix B(C.size(), this->minSize(), scalar(0)); forAll(C, ip) { const point& p = C[ip]; const vector p0p = p - p0; d.x() = p0p & idir; d.y() = p0p & jdir; d.z() = p0p & kdir; if (ip == 0) { scale = cmptMax(cmptMag((d))); } // Scale the radius vector d /= scale; Polynomial::addCoeffs(B[ip], d, wts[ip], this->dim()); } // Additional weighting for constant and linear terms for (label i = 0; i < B.m(); i++) { B(i, 0) *= wts[0]; B(i, 1) *= wts[0]; } // Set the fit label stencilSize = C.size(); coeffsi.setSize(stencilSize); bool goodFit = false; for (int iIt = 0; iIt < 8 && !goodFit; iIt++) { SVD svd(B, small); scalarRectangularMatrix invB(svd.VSinvUt()); for (label i=0; i<stencilSize; i++) { coeffsi[i] = wts[1]*wts[i]*invB(1, i)/scale; } goodFit = ( mag(wts[0]*wts[0]*invB(0, 0) - wLin) < this->linearLimitFactor()*wLin) && (mag(wts[0]*wts[1]*invB(0, 1) - (1 - wLin) ) < this->linearLimitFactor()*(1 - wLin)) && coeffsi[0] < 0 && coeffsi[1] > 0 && mag(coeffsi[0] + deltaCoeff) < 0.5*deltaCoeff && mag(coeffsi[1] - deltaCoeff) < 0.5*deltaCoeff; if (!goodFit) { // (not good fit so increase weight in the centre and weight // for constant and linear terms) WarningInFunction << "Cannot fit face " << facei << " iteration " << iIt << " with sum of weights " << sum(coeffsi) << nl << " Weights " << coeffsi << nl << " Linear weights " << wLin << " " << 1 - wLin << nl << " deltaCoeff " << deltaCoeff << nl << " sing vals " << svd.S() << nl << "Components of goodFit:\n" << " wts[0]*wts[0]*invB(0, 0) = " << wts[0]*wts[0]*invB(0, 0) << nl << " wts[0]*wts[1]*invB(0, 1) = " << wts[0]*wts[1]*invB(0, 1) << " dim = " << this->dim() << endl; wts[0] *= 10; wts[1] *= 10; for (label j = 0; j < B.n(); j++) { B(0, j) *= 10; B(1, j) *= 10; } for (label i = 0; i < B.m(); i++) { B(i, 0) *= 10; B(i, 1) *= 10; } } } if (goodFit) { // Remove the uncorrected coefficients coeffsi[0] += deltaCoeff; coeffsi[1] -= deltaCoeff; } else { WarningInFunction << "Could not fit face " << facei << " Coefficients = " << coeffsi << ", reverting to uncorrected." << endl; coeffsi = 0; } }
Type Foam::functionObjects::fieldValues::volFieldValue::processValues ( const Field<Type>& values, const scalarField& V, const scalarField& weightField ) const { Type result = Zero; switch (operation_) { case opSum: { result = gSum(values); break; } case opSumMag: { result = gSum(cmptMag(values)); break; } case opAverage: { result = gSum(values)/nCells(); break; } case opWeightedAverage: { result = gSum(weightField*values)/gSum(weightField); break; } case opVolAverage: { result = gSum(V*values)/this->V(); break; } case opWeightedVolAverage: { result = gSum(weightField*V*values)/gSum(weightField*V); break; } case opVolIntegrate: { result = gSum(V*values); break; } case opMin: { result = gMin(values); break; } case opMax: { result = gMax(values); break; } case opCoV: { Type meanValue = gSum(values*V)/this->V(); const label nComp = pTraits<Type>::nComponents; for (direction d=0; d<nComp; ++d) { scalarField vals(values.component(d)); scalar mean = component(meanValue, d); scalar& res = setComponent(result, d); res = sqrt(gSum(V*sqr(vals - mean))/this->V())/mean; } break; } case opNone: {} } return result; }
Type Foam::fieldValues::cellSource::processValues ( const Field<Type>& values, const scalarField& V, const scalarField& weightField ) const { Type result = pTraits<Type>::zero; switch (operation_) { case opSum: { result = sum(values); break; } case opSumMag: { result = sum(cmptMag(values)); break; } case opAverage: { result = sum(values)/values.size(); break; } case opWeightedAverage: { result = sum(weightField*values)/sum(weightField); break; } case opVolAverage: { result = sum(V*values)/sum(V); break; } case opWeightedVolAverage: { result = sum(weightField*V*values)/sum(weightField*V); break; } case opVolIntegrate: { result = sum(V*values); break; } case opMin: { result = min(values); break; } case opMax: { result = max(values); break; } case opCoV: { Type meanValue = sum(values*V)/sum(V); const label nComp = pTraits<Type>::nComponents; for (direction d=0; d<nComp; ++d) { scalarField vals(values.component(d)); scalar mean = component(meanValue, d); scalar& res = setComponent(result, d); res = sqrt(sum(V*sqr(vals - mean))/sum(V))/mean; } break; } default: { // Do nothing } } return result; }
Foam::SolverPerformance<Type> Foam::PBiCICG<Type, DType, LUType>::solve(gpuField<Type>& psi) const { word preconditionerName(this->controlDict_.lookup("preconditioner")); if(preconditionerName != "none") preconditionerName = "diagonal"; // --- Setup class containing solver performance data SolverPerformance<Type> solverPerf ( preconditionerName + typeName, this->fieldName_ ); register label nCells = psi.size(); gpuField<Type> pA(nCells); gpuField<Type> pT(nCells, pTraits<Type>::zero); gpuField<Type> wA(nCells); gpuField<Type> wT(nCells); Type wArT = solverPerf.great_*pTraits<Type>::one; Type wArTold = wArT; // --- Calculate A.psi and T.psi this->matrix_.Amul(wA, psi); this->matrix_.Tmul(wT, psi); // --- Calculate initial residual and transpose residual fields gpuField<Type> rA(this->matrix_.source() - wA); gpuField<Type> rT(this->matrix_.source() - wT); // --- 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 if (!solverPerf.checkConvergence(this->tolerance_, this->relTol_)) { // --- 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 wArT wArTold = wArT; // --- Precondition residuals preconPtr->precondition(wA, rA); preconPtr->preconditionT(wT, rT); // --- Update search directions: wArT = gSumCmptProd(wA, rT); if (solverPerf.nIterations() == 0) { thrust::copy(wA.begin(),wA.end(),pA.begin()); thrust::copy(wT.begin(),wT.end(),pT.begin()); } else { Type beta = cmptDivide ( wArT, stabilise(wArTold, solverPerf.vsmall_) ); thrust::transform ( wA.begin(), wA.end(), thrust::make_transform_iterator ( pA.begin(), cmptMultiplyBinaryFunctionSFFunctor<Type,Type,Type>(beta) ), pA.begin(), addOperatorFunctor<Type,Type,Type>() ); thrust::transform ( wT.begin(), wT.end(), thrust::make_transform_iterator ( pT.begin(), cmptMultiplyBinaryFunctionSFFunctor<Type,Type,Type>(beta) ), pT.begin(), addOperatorFunctor<Type,Type,Type>() ); } // --- Update preconditioned residuals this->matrix_.Amul(wA, pA); this->matrix_.Tmul(wT, pT); Type wApT = gSumCmptProd(wA, pT); // --- Test for singularity if ( solverPerf.checkSingularity ( cmptDivide(cmptMag(wApT), normFactor) ) ) { break; } // --- Update solution and residual: Type alpha = cmptDivide ( wArT, stabilise(wApT, solverPerf.vsmall_) ); thrust::transform ( psi.begin(), psi.end(), thrust::make_transform_iterator ( pA.begin(), cmptMultiplyBinaryFunctionSFFunctor<Type,Type,Type>(alpha) ), psi.begin(), addOperatorFunctor<Type,Type,Type>() ); thrust::transform ( rA.begin(), rA.end(), thrust::make_transform_iterator ( wA.begin(), cmptMultiplyBinaryFunctionSFFunctor<Type,Type,Type>(alpha) ), rA.begin(), subtractOperatorFunctor<Type,Type,Type>() ); thrust::transform ( rT.begin(), rT.end(), thrust::make_transform_iterator ( wT.begin(), cmptMultiplyBinaryFunctionSFFunctor<Type,Type,Type>(alpha) ), rT.begin(), subtractOperatorFunctor<Type,Type,Type>() ); solverPerf.finalResidual() = cmptDivide(gSumCmptMag(rA), normFactor); } while ( solverPerf.nIterations()++ < this->maxIter_ && !(solverPerf.checkConvergence(this->tolerance_, this->relTol_)) ); } return solverPerf; }
void Foam::BlockLduMatrix<Type>::decoupledRelax ( const TypeField& x, TypeField& b, const scalar alpha ) { typedef typename TypeCoeffField::scalarTypeField scalarTypeField; typedef typename TypeCoeffField::linearTypeField linearTypeField; //HJ Missing code: add coupling coefficients to under-relaxation // HJ, 21/Feb/2008 if (alpha <= 0) { return; } TypeCoeffField& Diag = this->diag(); // Create multiplication function object typename BlockCoeff<Type>::multiply mult; const unallocLabelList& l = lduAddr().lowerAddr(); const unallocLabelList& u = lduAddr().upperAddr(); if (this->symmetric()) { // Symmetric matrix: re-use upper for lower coefficients const TypeCoeffField& Upper = const_cast<const BlockLduMatrix<Type>&>(*this).upper(); if ( Upper.activeType() == blockCoeffBase::LINEAR || Diag.activeType() == blockCoeffBase::LINEAR ) { const linearTypeField& activeUpper = Upper.asLinear(); linearTypeField& activeDiag = Diag.asLinear(); // Make a copy of diagonal before relaxation linearTypeField activeDiagOld = activeDiag; linearTypeField sumOff ( activeDiag.size(), pTraits<typename TypeCoeffField::linearType>::zero ); for (register label coeffI = 0; coeffI < l.size(); coeffI++) { sumOff[u[coeffI]] += cmptMag(activeUpper[coeffI]); sumOff[l[coeffI]] += cmptMag(activeUpper[coeffI]); } activeDiag = max(activeDiag, sumOff); activeDiag *= 1.0/alpha; // Add the relaxation contribution to b forAll (b, i) { b[i] += mult(activeDiag[i] - activeDiagOld[i], x[i]); } } else if