Block solver development

This commit is contained in:
Hrvoje Jasak 2011-08-24 11:35:47 +01:00
parent 99169ff574
commit 105f6dd539
26 changed files with 637 additions and 336 deletions

View file

@ -95,25 +95,28 @@ int main(int argc, char *argv[])
// Prepare block system // Prepare block system
BlockLduMatrix<vector2> blockM(mesh); BlockLduMatrix<vector2> blockM(mesh);
//- Transfer the coupled interface list for processor/cyclic/etc.
// boundaries
blockM.interfaces() = blockT.boundaryField().blockInterfaces();
// Grab block diagonal and set it to zero // Grab block diagonal and set it to zero
Field<tensor2>& d = blockM.diag().asSquare(); Field<tensor2>& d = blockM.diag().asSquare();
d = tensor2::zero; d = tensor2::zero;
// Grab linear off-diagonal and set it to zero // Grab linear off-diagonal and set it to zero
Field<vector2>& u = blockM.upper().asLinear();
Field<vector2>& l = blockM.lower().asLinear(); Field<vector2>& l = blockM.lower().asLinear();
Field<vector2>& u = blockM.upper().asLinear();
u = vector2::zero; u = vector2::zero;
l = vector2::zero; l = vector2::zero;
vector2Field& blockX = blockT.internalField(); vector2Field& blockX = blockT.internalField();
// vector2Field blockX(mesh.nCells(), vector2::zero);
vector2Field blockB(mesh.nCells(), vector2::zero); vector2Field blockB(mesh.nCells(), vector2::zero);
//- Inset equations into block Matrix //- Inset equations into block Matrix
blockMatrixTools::insertEquation(0, TEqn, blockM, blockX, blockB); blockMatrixTools::insertEquation(0, TEqn, blockM, blockX, blockB);
blockMatrixTools::insertEquation(1, TsEqn, blockM, blockX, blockB); blockMatrixTools::insertEquation(1, TsEqn, blockM, blockX, blockB);
//- Add off-diagonal terms and remove from Block source //- Add off-diagonal terms and remove from block source
forAll(d, i) forAll(d, i)
{ {
d[i](0,1) = -alpha.value()*mesh.V()[i]; d[i](0,1) = -alpha.value()*mesh.V()[i];
@ -123,44 +126,13 @@ int main(int argc, char *argv[])
blockB[i][1] -= alpha.value()*blockX[i][0]*mesh.V()[i]; blockB[i][1] -= alpha.value()*blockX[i][0]*mesh.V()[i];
} }
//- Transfer the coupled interface list for processor/cyclic/etc.
// boundaries
blockM.interfaces() = blockT.boundaryField().blockInterfaces();
//- Transfer the coupled interface coefficients
forAll(mesh.boundaryMesh(), patchI)
{
if (blockM.interfaces().set(patchI))
{
Field<vector2>& coupledLower =
blockM.coupleLower()[patchI].asLinear();
Field<vector2>& coupledUpper =
blockM.coupleUpper()[patchI].asLinear();
const scalarField& TLower = TEqn.internalCoeffs()[patchI];
const scalarField& TUpper = TEqn.boundaryCoeffs()[patchI];
const scalarField& TsLower =
TsEqn.internalCoeffs()[patchI];
const scalarField& TsUpper =
TsEqn.boundaryCoeffs()[patchI];
blockMatrixTools::blockInsert(0, TLower, coupledLower);
blockMatrixTools::blockInsert(1, TsLower, coupledLower);
blockMatrixTools::blockInsert(0, TUpper, coupledUpper);
blockMatrixTools::blockInsert(1, TsUpper, coupledUpper);
}
}
//- Block coupled solver call //- Block coupled solver call
BlockSolverPerformance<vector2> solverPerf = BlockSolverPerformance<vector2> solverPerf =
BlockLduSolver<vector2>::New BlockLduSolver<vector2>::New
( (
word("blockVar"), blockT.name(),
blockM, blockM,
mesh.solutionDict().solver("blockVar") mesh.solutionDict().solver(blockT.name())
)->solve(blockX, blockB); )->solve(blockX, blockB);
solverPerf.print(); solverPerf.print();

View file

@ -1,130 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
InNamespace
Foam::
Description
Block matrix insertion and retrieval tools
SourceFiles
blockMatrixTools.C
\*---------------------------------------------------------------------------*/
#ifndef blockMatrixTools_H
#define blockMatrixTools_H
#include "blockLduMatrices.H"
#include "fvMatrices.H"
#include "surfaceFieldsFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Namespace blockMatrixTools functions Declaration
\*---------------------------------------------------------------------------*/
namespace blockMatrixTools
{
//- Insert field into block field
template<class BlockType>
void blockInsert
(
const direction dir,
const scalarField& x,
Field<BlockType>& blockX
);
//- Retrieve field from block field
template<class BlockType>
void blockRetrieve
(
const direction dir,
scalarField& x,
const Field<BlockType>& blockX
);
//- Insert matrix diagonal and source into the block system
template<class BlockType>
void insertDiagSource
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockB
);
// Insert matrix into the block system
template<class Type, class BlockType>
void insertUpperLower
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM
);
// Insert matrix into the block system
template<class BlockType>
void insertEquation
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockX,
Field<BlockType>& blockB
);
// Update coupling of block system
// Subtracts the block-coefficient coupling as specified by the user
// from the source, leaving the implicit update given by linearisation
template<class BlockType>
void updateCoupling
(
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& x,
Field<BlockType>& b
);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "blockMatrixTools.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -28,7 +28,7 @@
); );
// Working coupled solution field // Working coupled solution field
Info<< "Creating field blockT\n" << endl; Info<< "Creating field blockT\n" << endl;
volVector2Field blockT volVector2Field blockT
( (
@ -41,7 +41,7 @@
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
mesh, mesh,
dimensionedVector2(word(), dimless, vector2::zero) dimensionedVector2("zero", dimless, vector2::zero)
); );
{ {
@ -53,38 +53,6 @@
blockT.write(); blockT.write();
// Removed comparison with the reference field. HJ, 17/Jun/2010
#if (0)
Info<< "Reading field Tref\n" << endl;
volScalarField Tref
(
IOobject
(
"Tref",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
Info<< "Reading field Tsref\n" << endl;
volScalarField Tsref
(
IOobject
(
"Tsref",
runTime.timeName(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
#endif
Info<< "Reading field U\n" << endl; Info<< "Reading field U\n" << endl;
volVectorField U volVectorField U

View file

@ -642,11 +642,11 @@ matrices/blockLduMatrix/BlockLduSmoothers/BlockILUSmoother/blockILUSmoothers.C
matrices/blockLduMatrix/BlockLduSolvers/BlockLduSolver/blockLduSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockLduSolver/blockLduSolvers.C
matrices/blockLduMatrix/BlockLduSolvers/BlockDiagonal/blockDiagonalSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockDiagonal/blockDiagonalSolvers.C
/*HJ matrices/blockLduMatrix/BlockLduSolvers/Segregated/segregatedSolvers.C */
matrices/blockLduMatrix/BlockLduSolvers/BlockGaussSeidel/blockGaussSeidelSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockGaussSeidel/blockGaussSeidelSolvers.C
matrices/blockLduMatrix/BlockLduSolvers/BlockCG/blockCGSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockCG/blockCGSolvers.C
matrices/blockLduMatrix/BlockLduSolvers/BlockBiCGStab/blockBiCGStabSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockBiCGStab/blockBiCGStabSolvers.C
matrices/blockLduMatrix/BlockLduSolvers/BlockGMRES/blockGMRESSolvers.C matrices/blockLduMatrix/BlockLduSolvers/BlockGMRES/blockGMRESSolvers.C
matrices/blockLduMatrix/BlockLduSolvers/Segregated/segregatedSolvers.C
matrices/blockLduMatrix/BlockLduMatrix/BlockLduInterface/BlockLduInterfaceFields.C matrices/blockLduMatrix/BlockLduMatrix/BlockLduInterface/BlockLduInterfaceFields.C

View file

@ -343,7 +343,8 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const BlockLduMatrix<Type>& ldum)
{ {
if (ldum.diagPtr_) if (ldum.diagPtr_)
{ {
os.writeKeyword("diagonal") << *ldum.diagPtr_ << token::END_STATEMENT << nl; os.writeKeyword("diagonal")
<< *ldum.diagPtr_ << token::END_STATEMENT << nl;
} }
else else
{ {

View file

@ -93,7 +93,7 @@ Foam::BlockBiCGStabSolver<Type>::solve
// Check convergence, solve if not converged // Check convergence, solve if not converged
if (!solverPerf.checkConvergence(this->tolerance(), this->relTolerance())) if (!stop(solverPerf))
{ {
scalar rho = this->great_; scalar rho = this->great_;
scalar rhoOld = rho; scalar rhoOld = rho;

View file

@ -92,7 +92,7 @@ typename Foam::BlockSolverPerformance<Type> Foam::BlockCGSolver<Type>::solve
// Check convergence, solve if not converged // Check convergence, solve if not converged
if (!solverPerf.checkConvergence(this->tolerance(), this->relTolerance())) if (!stop(solverPerf))
{ {
scalar rho = this->great_; scalar rho = this->great_;
scalar rhoOld = rho; scalar rhoOld = rho;

View file

@ -128,7 +128,7 @@ Foam::BlockGMRESSolver<Type>::solve
// Check convergence, solve if not converged // Check convergence, solve if not converged
if (!solverPerf.checkConvergence(this->tolerance(), this->relTolerance())) if (!stop(solverPerf))
{ {
// Create the Hesenberg matrix // Create the Hesenberg matrix
scalarSquareMatrix H(nDirs_, 0); scalarSquareMatrix H(nDirs_, 0);

View file

@ -49,7 +49,7 @@ Foam::BlockGaussSeidelSolver<Type>::BlockGaussSeidelSolver
dict dict
), ),
gs_(matrix), gs_(matrix),
nResSweeps_(readLabel(this->dict().lookup("nResSweeps"))) nSweeps_(readLabel(this->dict().lookup("nSweeps")))
{} {}
@ -86,13 +86,13 @@ Foam::BlockGaussSeidelSolver<Type>::solve
// Check convergence, solve if not converged // Check convergence, solve if not converged
if (!solverPerf.checkConvergence(this->tolerance(), this->relTolerance())) if (!stop(solverPerf))
{ {
// Iteration loop // Iteration loop
do do
{ {
for (label i = 0; i < nResSweeps_; i++) for (label i = 0; i < nSweeps_; i++)
{ {
gs_.precondition(x, b); gs_.precondition(x, b);

View file

@ -64,7 +64,7 @@ class BlockGaussSeidelSolver
BlockGaussSeidelPrecon<Type> gs_; BlockGaussSeidelPrecon<Type> gs_;
//- Number of sweeps before evaluating residual //- Number of sweeps before evaluating residual
label nResSweeps_; label nSweeps_;

View file

@ -82,7 +82,8 @@ Foam::scalar Foam::BlockIterativeSolver<Type>::normFactor
if (BlockLduMatrix<Type>::debug >= 2) if (BlockLduMatrix<Type>::debug >= 2)
{ {
Info<< "Iterative solver normalisation factor = " << normFactor << endl; Info<< "Iterative solver normalisation factor = "
<< normFactor << endl;
} }
return normFactor; return normFactor;

View file

@ -65,7 +65,7 @@ void Foam::BlockLduSolver<Type>::readControl
")", ")",
dict dict
) << "Cannot read control " << controlName ) << "Cannot read control " << controlName
<< abort(FatalIOError); << exit(FatalIOError);
} }
} }
@ -112,6 +112,52 @@ Foam::BlockLduSolver<Type>::New
{ {
word solverName(dict.lookup("solver")); word solverName(dict.lookup("solver"));
if (matrix.diagonal())
{
return autoPtr<BlockLduSolver<Type> >
(
new BlockDiagonalSolver<Type>(fieldName, matrix, dict)
);
}
else if (matrix.symmetric() || matrix.asymmetric())
{
return BlockLduSolver<Type>::New
(
solverName,
fieldName,
matrix,
dict
);
}
else
{
FatalErrorIn
(
"BlockLduSolver<Type>::New\n"
"(\n"
" const word& fieldName,\n"
" BlockLduMatrix<Type>& matrix,\n"
" const dictionary& dict\n"
")"
) << "cannot solve incomplete matrix, "
"no diagonal or off-diagonal coefficient"
<< exit(FatalError);
return autoPtr<BlockLduSolver<Type> >(NULL);
}
}
template<class Type>
Foam::autoPtr<typename Foam::BlockLduSolver<Type> >
Foam::BlockLduSolver<Type>::New
(
const word& solverName,
const word& fieldName,
BlockLduMatrix<Type>& matrix,
const dictionary& dict
)
{
if (matrix.diagonal()) if (matrix.diagonal())
{ {
return autoPtr<BlockLduSolver<Type> > return autoPtr<BlockLduSolver<Type> >
@ -143,6 +189,7 @@ Foam::BlockLduSolver<Type>::New
( (
"BlockLduSolver<Type>::New\n" "BlockLduSolver<Type>::New\n"
"(\n" "(\n"
" const word& solverName,\n"
" const word& fieldName,\n" " const word& fieldName,\n"
" BlockLduMatrix<Type>& matrix,\n" " BlockLduMatrix<Type>& matrix,\n"
" const dictionary& dict\n" " const dictionary& dict\n"
@ -173,6 +220,7 @@ Foam::BlockLduSolver<Type>::New
( (
"BlockLduSolver<Type>::New\n" "BlockLduSolver<Type>::New\n"
"(\n" "(\n"
" const word& solverName,\n"
" const word& fieldName,\n" " const word& fieldName,\n"
" BlockLduMatrix<Type>& matrix,\n" " BlockLduMatrix<Type>& matrix,\n"
" const dictionary& dict\n" " const dictionary& dict\n"
@ -189,6 +237,7 @@ Foam::BlockLduSolver<Type>::New
( (
"BlockLduSolver<Type>::New\n" "BlockLduSolver<Type>::New\n"
"(\n" "(\n"
" const word& solverName,\n"
" const word& fieldName,\n" " const word& fieldName,\n"
" BlockLduMatrix<Type>& matrix,\n" " BlockLduMatrix<Type>& matrix,\n"
" const dictionary& dict\n" " const dictionary& dict\n"
@ -217,6 +266,7 @@ Foam::BlockLduSolver<Type>::New
( (
"BlockLduSolver<Type>::New\n" "BlockLduSolver<Type>::New\n"
"(\n" "(\n"
" const word& solverName,\n"
" const word& fieldName,\n" " const word& fieldName,\n"
" BlockLduMatrix<Type>& matrix,\n" " BlockLduMatrix<Type>& matrix,\n"
" const dictionary& dict\n" " const dictionary& dict\n"

View file

@ -172,7 +172,7 @@ public:
// Selectors // Selectors
//- Return a new solver //- Return a new solver from a dictionary
static autoPtr<BlockLduSolver<Type> > New static autoPtr<BlockLduSolver<Type> > New
( (
const word& fieldName, const word& fieldName,
@ -180,6 +180,15 @@ public:
const dictionary& dict const dictionary& dict
); );
//- Return a new solver given type
static autoPtr<BlockLduSolver<Type> > New
(
const word& solverName,
const word& fieldName,
BlockLduMatrix<Type>& matrix,
const dictionary& dict
);
// Destructor // Destructor

View file

@ -74,21 +74,6 @@ Foam::BlockSolverPerformance<Type> Foam::SegregatedSolver<Type>::solve
switchingDiag = true; switchingDiag = true;
} }
// Check switching upper
bool switchingUpper = false;
if (blockMatrix.thereIsUpper())
{
if (blockMatrix.upper().activeType() == blockCoeffBase::SCALAR)
{
scalarMatrix_.upper() = blockMatrix.upper().asScalar();
}
else
{
switchingUpper = true;
}
}
// Check switching lower // Check switching lower
bool switchingLower = false; bool switchingLower = false;
@ -104,6 +89,21 @@ Foam::BlockSolverPerformance<Type> Foam::SegregatedSolver<Type>::solve
} }
} }
// Check switching upper
bool switchingUpper = false;
if (blockMatrix.thereIsUpper())
{
if (blockMatrix.upper().activeType() == blockCoeffBase::SCALAR)
{
scalarMatrix_.upper() = blockMatrix.upper().asScalar();
}
else
{
switchingUpper = true;
}
}
// Decouple quadratic coupling by multiplying out the square coefficient // Decouple quadratic coupling by multiplying out the square coefficient
// coupling // coupling
Field<Type>* dBPtr = NULL; Field<Type>* dBPtr = NULL;
@ -120,7 +120,7 @@ Foam::BlockSolverPerformance<Type> Foam::SegregatedSolver<Type>::solve
} }
// Prepare solver performance // Prepare solver performance
word segSolverName(this->dict().lookup("solver")); word segSolverName(this->dict().lookup("segSolver"));
BlockSolverPerformance<Type> solverPerf BlockSolverPerformance<Type> solverPerf
( (
@ -156,20 +156,21 @@ Foam::BlockSolverPerformance<Type> Foam::SegregatedSolver<Type>::solve
scalarMatrix_.diag() = blockMatrix.diag().component(cmpt); scalarMatrix_.diag() = blockMatrix.diag().component(cmpt);
} }
if (switchingUpper)
{
scalarMatrix_.upper() = blockMatrix.upper().component(cmpt);
}
if (switchingLower) if (switchingLower)
{ {
scalarMatrix_.lower() = blockMatrix.lower().component(cmpt); scalarMatrix_.lower() = blockMatrix.lower().component(cmpt);
} }
if (switchingUpper)
{
scalarMatrix_.upper() = blockMatrix.upper().component(cmpt);
}
// Call the scalar solver // Call the scalar solver
BlockSolverPerformance<scalar> scalarPerf = BlockSolverPerformance<scalar> scalarPerf =
blockScalarSolver::New blockScalarSolver::New
( (
segSolverName,
this->fieldName(), this->fieldName(),
scalarMatrix_, scalarMatrix_,
this->dict() this->dict()

View file

@ -139,7 +139,8 @@ public:
UList<Type>& UList<Type>&
) const; ) const;
//- Raw field receive function with data compression returning field //- Raw field receive function with data compression,
// returning a field
template<class Type> template<class Type>
tmp<Field<Type> > compressedReceive tmp<Field<Type> > compressedReceive
( (

View file

@ -46,9 +46,14 @@ void Foam::GAMGSolver::agglomerateMatrix(const label fineLevelIndex)
const labelList& faceRestrictAddr = const labelList& faceRestrictAddr =
agglomeration_.faceRestrictAddressing(fineLevelIndex); agglomeration_.faceRestrictAddressing(fineLevelIndex);
// Coarse matrix diagonal initialised by restricting the finer mesh diagonal // Coarse matrix diagonal initialised by restricting the fine mesh diagonal
scalarField& coarseDiag = coarseMatrix.diag(); scalarField& coarseDiag = coarseMatrix.diag();
agglomeration_.restrictField(coarseDiag, fineMatrix.diag(), fineLevelIndex); agglomeration_.restrictField
(
coarseDiag,
fineMatrix.diag(),
fineLevelIndex
);
// Get reference to fine-level interfaces // Get reference to fine-level interfaces
const lduInterfaceFieldPtrsList& fineInterfaces = const lduInterfaceFieldPtrsList& fineInterfaces =

View file

@ -43,6 +43,7 @@ License
#include "BlockCGSolver.H" #include "BlockCGSolver.H"
#include "BlockGaussSeidelSolver.H" #include "BlockGaussSeidelSolver.H"
#include "BlockGMRESSolver.H" #include "BlockGMRESSolver.H"
#include "SegregatedSolver.H"
#include "VectorTensorNFields.H" #include "VectorTensorNFields.H"
#include "ExpandTensorN.H" #include "ExpandTensorN.H"
@ -105,23 +106,29 @@ defineTemplateRunTimeSelectionTable \
typedef BlockDiagonalSolver<type > block##Type##DiagonalSolver; \ typedef BlockDiagonalSolver<type > block##Type##DiagonalSolver; \
defineNamedTemplateTypeNameAndDebug(block##Type##DiagonalSolver, 0); \ defineNamedTemplateTypeNameAndDebug(block##Type##DiagonalSolver, 0); \
\ \
typedef BlockBiCGStabSolver<type > block##Type##BiCGStabSolver; \ typedef BlockGaussSeidelSolver<type > block##Type##GaussSeidelSolver; \
makeBlockSolverTypeName(block##Type##BiCGStabSolver); \ makeBlockSolverTypeName(block##Type##GaussSeidelSolver); \
addSolverToBlockMatrix(Type, block##Type##BiCGStabSolver, symMatrix); \ addSolverToBlockMatrix(Type, block##Type##GaussSeidelSolver, symMatrix); \
addSolverToBlockMatrix(Type, block##Type##BiCGStabSolver, asymMatrix); \ addSolverToBlockMatrix(Type, block##Type##GaussSeidelSolver, asymMatrix); \
\ \
typedef BlockCGSolver<type > block##Type##CGSolver; \ typedef BlockCGSolver<type > block##Type##CGSolver; \
makeBlockSolverTypeName(block##Type##CGSolver); \ makeBlockSolverTypeName(block##Type##CGSolver); \
addSolverToBlockMatrix(Type, block##Type##CGSolver, symMatrix); \ addSolverToBlockMatrix(Type, block##Type##CGSolver, symMatrix); \
\ \
typedef BlockGaussSeidelSolver<type > block##Type##GaussSeidelSolver; \ typedef BlockBiCGStabSolver<type > block##Type##BiCGStabSolver; \
makeBlockSolverTypeName(block##Type##GaussSeidelSolver); \ makeBlockSolverTypeName(block##Type##BiCGStabSolver); \
addSolverToBlockMatrix(Type, block##Type##GaussSeidelSolver, symMatrix); \ addSolverToBlockMatrix(Type, block##Type##BiCGStabSolver, symMatrix); \
addSolverToBlockMatrix(Type, block##Type##BiCGStabSolver, asymMatrix); \
\ \
typedef BlockGMRESSolver<type > block##Type##GMRESSolver; \ typedef BlockGMRESSolver<type > block##Type##GMRESSolver; \
makeBlockSolverTypeName(block##Type##GMRESSolver); \ makeBlockSolverTypeName(block##Type##GMRESSolver); \
addSolverToBlockMatrix(Type, block##Type##GMRESSolver, symMatrix); \ addSolverToBlockMatrix(Type, block##Type##GMRESSolver, symMatrix); \
addSolverToBlockMatrix(Type, block##Type##GMRESSolver, asymMatrix); addSolverToBlockMatrix(Type, block##Type##GMRESSolver, asymMatrix); \
\
typedef SegregatedSolver<type > block##Type##SegregatedSolver; \
makeBlockSolverTypeName(block##Type##SegregatedSolver); \
addSolverToBlockMatrix(Type, block##Type##SegregatedSolver, symMatrix); \
addSolverToBlockMatrix(Type, block##Type##SegregatedSolver, asymMatrix);
forAllVectorNTypes(makeSolver) forAllVectorNTypes(makeSolver)

View file

@ -32,46 +32,54 @@ Description
#define VectorNFieldTypes_H #define VectorNFieldTypes_H
#include "vector2.H" #include "vector2.H"
#include "vector3.H"
#include "vector4.H" #include "vector4.H"
#include "vector6.H" #include "vector6.H"
#include "vector8.H" #include "vector8.H"
#include "tensor2.H" #include "tensor2.H"
#include "tensor3.H"
#include "tensor4.H" #include "tensor4.H"
#include "tensor6.H" #include "tensor6.H"
#include "tensor8.H" #include "tensor8.H"
#include "diagTensor2.H" #include "diagTensor2.H"
#include "diagTensor3.H"
#include "diagTensor4.H" #include "diagTensor4.H"
#include "diagTensor6.H" #include "diagTensor6.H"
#include "diagTensor8.H" #include "diagTensor8.H"
#define forAllVectorNTypes(m, args...) \ #define forAllVectorNTypes(m, args...) \
m(vector2, Vector2, args) \ m(vector2, Vector2, args) \
m(vector3, Vector3, args) \
m(vector4, Vector4, args) \ m(vector4, Vector4, args) \
m(vector6, Vector6, args) \ m(vector6, Vector6, args) \
m(vector8, Vector8, args) m(vector8, Vector8, args)
#define forAllTensorNTypes(m, args...) \ #define forAllTensorNTypes(m, args...) \
m(tensor2, Tensor2, args) \ m(tensor2, Tensor2, args) \
m(tensor3, Tensor3, args) \
m(tensor4, Tensor4, args) \ m(tensor4, Tensor4, args) \
m(tensor6, Tensor6, args) \ m(tensor6, Tensor6, args) \
m(tensor8, Tensor8, args) m(tensor8, Tensor8, args)
#define forAllDiagTensorNTypes(m, args...) \ #define forAllDiagTensorNTypes(m, args...) \
m(diagTensor2, DiagTensor2, args) \ m(diagTensor2, DiagTensor2, args) \
m(diagTensor3, DiagTensor3, args) \
m(diagTensor4, DiagTensor4, args) \ m(diagTensor4, DiagTensor4, args) \
m(diagTensor6, DiagTensor6, args) \ m(diagTensor6, DiagTensor6, args) \
m(diagTensor8, DiagTensor8, args) m(diagTensor8, DiagTensor8, args)
#define forAllSphericalTensorNTypes(m, args...) \ #define forAllSphericalTensorNTypes(m, args...) \
m(sphericalTensor2, SphericalTensor2, args) \ m(sphericalTensor2, SphericalTensor2, args) \
m(sphericalTensor3, SphericalTensor3, args) \
m(sphericalTensor4, SphericalTensor4, args) \ m(sphericalTensor4, SphericalTensor4, args) \
m(sphericalTensor6, SphericalTensor6, args) \ m(sphericalTensor6, SphericalTensor6, args) \
m(sphericalTensor8, SphericalTensor8, args) m(sphericalTensor8, SphericalTensor8, args)
#define forAllVectorTensorNTypes(m, args...) \ #define forAllVectorTensorNTypes(m, args...) \
m(tensor2, diagTensor2, sphericalTensor2, vector2, scalar, args) \ m(tensor2, diagTensor2, sphericalTensor2, vector2, scalar, args) \
m(tensor3, diagTensor3, sphericalTensor3, vector3, scalar, args) \
m(tensor4, diagTensor4, sphericalTensor4, vector4, scalar, args) \ m(tensor4, diagTensor4, sphericalTensor4, vector4, scalar, args) \
m(tensor6, diagTensor6, sphericalTensor6, vector6, scalar, args) \ m(tensor6, diagTensor6, sphericalTensor6, vector6, scalar, args) \
m(tensor8, diagTensor8, sphericalTensor8, vector8, scalar, args) m(tensor8, diagTensor8, sphericalTensor8, vector8, scalar, args)

View file

@ -51,6 +51,21 @@ void blockInsert
} }
template<class BlockType>
void blockAdd
(
const direction dir,
const scalarField& x,
Field<BlockType>& blockX
)
{
forAll (x, i)
{
blockX[i](dir) += x[i];
}
}
template<class BlockType> template<class BlockType>
void blockRetrieve void blockRetrieve
( (
@ -131,6 +146,46 @@ void insertUpperLower
return; return;
} }
if (m.symmetric() && blockM.symmetric())
{
Info<< "Both m and blockM are symmetric: inserting only upper triangle"
<< endl;
}
else
{
// Either scalar or block matrix is asymmetric: insert lower triangle
const scalarField& lower = m.lower();
if (blockM.lower().activeType() == blockCoeffBase::UNALLOCATED)
{
blockM.lower().asScalar() = lower;
}
else if
(
blockM.lower().activeType() == blockCoeffBase::SCALAR
|| blockM.lower().activeType() == blockCoeffBase::LINEAR
)
{
typename CoeffField<BlockType>::linearTypeField& blockLower =
blockM.lower().asLinear();
forAll (lower, i)
{
blockLower[i](dir) = lower[i];
}
}
else if (blockM.lower().activeType() == blockCoeffBase::SQUARE)
{
typename CoeffField<BlockType>::squareTypeField& blockLower =
blockM.lower().asSquare();
forAll (lower, i)
{
blockLower[i](dir, dir) = lower[i];
}
}
}
if (m.hasUpper()) if (m.hasUpper())
{ {
const scalarField& upper = m.upper(); const scalarField& upper = m.upper();
@ -178,42 +233,61 @@ void insertUpperLower
<< abort(FatalError); << abort(FatalError);
} }
if (m.symmetric() && blockM.symmetric()) // Insert block interface fields
forAll(blockM.interfaces(), patchI)
{ {
Info<< "Both m and blockM are symmetric: inserting only upper triangle" if (blockM.interfaces().set(patchI))
<< endl;
}
else
{
// Either scalar or block matrix is asymmetric: insert lower triangle
const scalarField& lower = m.lower();
if (blockM.lower().activeType() == blockCoeffBase::UNALLOCATED)
{ {
blockM.lower().asScalar() = lower; // Couple upper and lower
} const scalarField& cUpper = m.boundaryCoeffs()[patchI];
else if const scalarField& cLower = m.internalCoeffs()[patchI];
(
blockM.lower().activeType() == blockCoeffBase::SCALAR
|| blockM.lower().activeType() == blockCoeffBase::LINEAR
)
{
typename CoeffField<BlockType>::linearTypeField& blockLower =
blockM.lower().asLinear();
forAll (lower, i) if
(
blockM.coupleUpper()[patchI].activeType()
== blockCoeffBase::UNALLOCATED
)
{ {
blockLower[i](dir) = lower[i]; blockM.coupleUpper()[patchI].asScalar() = cUpper;
blockM.coupleLower()[patchI].asScalar() = cLower;
} }
} else if
else if (blockM.lower().activeType() == blockCoeffBase::SQUARE) (
{ blockM.coupleUpper()[patchI].activeType()
typename CoeffField<BlockType>::squareTypeField& blockLower = == blockCoeffBase::SCALAR
blockM.lower().asSquare(); || blockM.coupleUpper()[patchI].activeType()
== blockCoeffBase::LINEAR
forAll (lower, i) )
{ {
blockLower[i](dir, dir) = lower[i]; typename CoeffField<BlockType>::linearTypeField& blockUpper =
blockM.coupleUpper()[patchI].asLinear();
typename CoeffField<BlockType>::linearTypeField& blockLower =
blockM.coupleLower()[patchI].asLinear();
forAll (cUpper, i)
{
blockUpper[i](dir) = cUpper[i];
blockLower[i](dir) = cLower[i];
}
}
else if
(
blockM.coupleUpper()[patchI].activeType()
== blockCoeffBase::SQUARE
)
{
typename CoeffField<BlockType>::squareTypeField& blockUpper =
blockM.coupleUpper()[patchI].asSquare();
typename CoeffField<BlockType>::squareTypeField& blockLower =
blockM.coupleLower()[patchI].asSquare();
forAll (cUpper, i)
{
blockUpper[i](dir, dir) = cUpper[i];
blockLower[i](dir, dir) = cLower[i];
}
} }
} }
} }
@ -236,6 +310,142 @@ void insertEquation
} }
template<class BlockType>
void insertCouplingDiagSource
(
const direction dirI,
const direction dirJ,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockB
)
{
// Prepare the diagonal and source
scalarField diag = m.diag();
scalarField source = m.source();
// Add boundary source contribution
m.addBoundaryDiag(diag, 0);
m.addBoundarySource(source, false);
// Add off-diagonal block coefficients
typename CoeffField<BlockType>::squareTypeField& blockDiag =
blockM.diag().asSquare();
// Set off-diagonal coefficient
forAll (diag, i)
{
blockDiag[i](dirI, dirJ) = diag[i];
}
blockAdd(dirI, source, blockB);
}
template<class BlockType>
void insertCouplingUpperLower
(
const direction dirI,
const direction dirJ,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM
)
{
if (m.diagonal())
{
// Matrix for insertion is diagonal-only: nothing to do
return;
}
if (m.symmetric() && blockM.symmetric())
{
Info<< "Both m and blockM are symmetric: inserting only upper triangle"
<< endl;
}
else
{
// Either scalar or block matrix is asymmetric: insert lower triangle
const scalarField& lower = m.lower();
typename CoeffField<BlockType>::squareTypeField& blockLower =
blockM.lower().asSquare();
forAll (lower, i)
{
blockLower[i](dirI, dirJ) = lower[i];
}
}
if (m.hasUpper())
{
const scalarField& upper = m.upper();
typename CoeffField<BlockType>::squareTypeField& blockUpper =
blockM.upper().asSquare();
forAll (upper, i)
{
blockUpper[i](dirI, dirJ) = upper[i];
}
}
else
{
FatalErrorIn
(
"void insertCouplingUpperLower\n"
"(\n"
" const direction dirI,\n"
" const direction dirJ,\n"
" const fvScalarMatrix& m,\n"
" BlockLduMatrix<BlockType>& blockM\n"
")"
) << "Error in matrix insertion: problem with block structure"
<< abort(FatalError);
}
// Insert block interface fields
forAll(blockM.interfaces(), patchI)
{
if (blockM.interfaces().set(patchI))
{
// Couple upper and lower
const scalarField& cUpper = m.boundaryCoeffs()[patchI];
const scalarField& cLower = m.internalCoeffs()[patchI];
typename CoeffField<BlockType>::squareTypeField& blockUpper =
blockM.coupleUpper()[patchI].asSquare();
typename CoeffField<BlockType>::squareTypeField& blockLower =
blockM.coupleLower()[patchI].asSquare();
forAll (cUpper, i)
{
blockUpper[i](dirI, dirJ) = cUpper[i];
blockLower[i](dirI, dirJ) = cLower[i];
}
}
}
}
template<class BlockType>
void insertCoupling
(
const direction dirI,
const direction dirJ,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockX,
Field<BlockType>& blockB
)
{
insertCouplingDiagSource(dirI, dirJ, m, blockM, blockB);
insertCouplingUpperLower(dirI, dirJ, m, blockM);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace blockMatrixTools } // End namespace blockMatrixTools

View file

@ -0,0 +1,179 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ M anipulation |
-------------------------------------------------------------------------------
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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
InNamespace
Foam::
Description
Block matrix insertion and retrieval tools
SourceFiles
blockMatrixTools.C
\*---------------------------------------------------------------------------*/
#ifndef blockMatrixTools_H
#define blockMatrixTools_H
#include "blockLduMatrices.H"
#include "fvMatrices.H"
#include "surfaceFieldsFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Namespace blockMatrixTools functions Declaration
\*---------------------------------------------------------------------------*/
namespace blockMatrixTools
{
// Field operations
//- Insert field into block field
template<class BlockType>
void blockInsert
(
const direction dir,
const scalarField& x,
Field<BlockType>& blockX
);
//- Add field into block field
template<class BlockType>
void blockAdd
(
const direction dir,
const scalarField& x,
Field<BlockType>& blockX
);
//- Retrieve field from block field
template<class BlockType>
void blockRetrieve
(
const direction dir,
scalarField& x,
const Field<BlockType>& blockX
);
// Diagonal block operations
//- Insert matrix diagonal and source into the block system
template<class BlockType>
void insertDiagSource
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockB
);
// Insert upper and lower coefficients matrix into the block system
template<class Type, class BlockType>
void insertUpperLower
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM
);
// Insert matrix into the block system
template<class BlockType>
void insertEquation
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockX,
Field<BlockType>& blockB
);
// Coupling block operations
//- Insert coupling matrix diagonal and source into the block system
template<class BlockType>
void insertCouplingDiagSource
(
const direction dirI,
const direction dirJ,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockB
);
// Insert coupling matrix into the block system
template<class Type, class BlockType>
void insertCouplingUpperLower
(
const direction dirI,
const direction dirJ,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM
);
// Insert coupling matrix into the block system
template<class BlockType>
void insertCoupling
(
const direction dir,
const fvScalarMatrix& m,
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& blockX,
Field<BlockType>& blockB
);
// Update coupling of block system
// Subtracts the block-coefficient coupling as specified by the user
// from the source, leaving the implicit update given by linearisation
template<class BlockType>
void updateCoupling
(
BlockLduMatrix<BlockType>& blockM,
Field<BlockType>& x,
Field<BlockType>& b
);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "blockMatrixTools.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View file

@ -34,65 +34,65 @@ namespace Foam
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
#define VectorNMatrixInterfaceFunc(Type) \ #define VectorNMatrixInterfaceFunc(Type) \
template <> \ template <> \
void processorFvPatchField<Type>::initInterfaceMatrixUpdate \ void processorFvPatchField<Type>::initInterfaceMatrixUpdate \
( \ ( \
const Field<Type>& psiInternal, \ const Field<Type>& psiInternal, \
Field<Type>&, \ Field<Type>&, \
const BlockLduMatrix<Type>&, \ const BlockLduMatrix<Type>&, \
const CoeffField<Type>&, \ const CoeffField<Type>&, \
const Pstream::commsTypes commsType \ const Pstream::commsTypes commsType \
) const \ ) const \
{ \ { \
procPatch_.compressedSend \ procPatch_.compressedSend \
( \ ( \
commsType, \ commsType, \
this->patch().patchInternalField(psiInternal)() \ this->patch().patchInternalField(psiInternal)() \
); \ ); \
} \ } \
\ \
template <> \ template <> \
void processorFvPatchField<Type>::updateInterfaceMatrix \ void processorFvPatchField<Type>::updateInterfaceMatrix \
( \ ( \
const Field<Type>& psiInternal, \ const Field<Type>& psiInternal, \
Field<Type>& result, \ Field<Type>& result, \
const BlockLduMatrix<Type>&, \ const BlockLduMatrix<Type>&, \
const CoeffField<Type>& coeffs, \ const CoeffField<Type>& coeffs, \
const Pstream::commsTypes commsType \ const Pstream::commsTypes commsType \
) const \ ) const \
{ \ { \
Field<Type> pnf(this->size()); \ Field<Type> pnf(this->size()); \
\ \
if (coeffs.activeType() == blockCoeffBase::SCALAR) \ if (coeffs.activeType() == blockCoeffBase::SCALAR) \
{ \ { \
pnf = coeffs.asScalar() * \ pnf = coeffs.asScalar() * \
procPatch_.compressedReceive<Type>(commsType, this->size())(); \ procPatch_.compressedReceive<Type>(commsType, this->size())(); \
} \ } \
else if (coeffs.activeType() == blockCoeffBase::LINEAR) \ else if (coeffs.activeType() == blockCoeffBase::LINEAR) \
{ \ { \
pnf = cmptMultiply(coeffs.asLinear(), \ pnf = cmptMultiply(coeffs.asLinear(), \
procPatch_.compressedReceive<Type>(commsType, this->size())() \ procPatch_.compressedReceive<Type>(commsType, this->size())() \
); \ ); \
} \ } \
else if (coeffs.activeType() == blockCoeffBase::SQUARE) \ else if (coeffs.activeType() == blockCoeffBase::SQUARE) \
{ \ { \
pnf = coeffs.asSquare() & \ pnf = coeffs.asSquare() & \
procPatch_.compressedReceive<Type>(commsType, this->size())(); \ procPatch_.compressedReceive<Type>(commsType, this->size())(); \
} \ } \
\ \
const unallocLabelList& faceCells = this->patch().faceCells(); \ const unallocLabelList& faceCells = this->patch().faceCells(); \
\ \
forAll(faceCells, facei) \ forAll(faceCells, facei) \
{ \ { \
result[faceCells[facei]] -= pnf[facei]; \ result[faceCells[facei]] -= pnf[facei]; \
} \ } \
} }
#define doMakePatchTypeField(type, Type, args...) \ #define doMakePatchTypeField(type, Type, args...) \
VectorNMatrixInterfaceFunc(type) \ VectorNMatrixInterfaceFunc(type) \
\ \
makePatchTypeField(fvPatch##Type##Field, processorFvPatch##Type##Field); makePatchTypeField(fvPatch##Type##Field, processorFvPatch##Type##Field);
forAllVectorNTypes(doMakePatchTypeField) forAllVectorNTypes(doMakePatchTypeField)

View file

@ -39,21 +39,25 @@ namespace Foam
template<class Type> class fvsPatchField; template<class Type> class fvsPatchField;
typedef fvsPatchField<vector2> fvsPatchVector2Field; typedef fvsPatchField<vector2> fvsPatchVector2Field;
typedef fvsPatchField<vector3> fvsPatchVector3Field;
typedef fvsPatchField<vector4> fvsPatchVector4Field; typedef fvsPatchField<vector4> fvsPatchVector4Field;
typedef fvsPatchField<vector6> fvsPatchVector6Field; typedef fvsPatchField<vector6> fvsPatchVector6Field;
typedef fvsPatchField<vector8> fvsPatchVector8Field; typedef fvsPatchField<vector8> fvsPatchVector8Field;
typedef fvsPatchField<tensor2> fvsPatchTensor2Field; typedef fvsPatchField<tensor2> fvsPatchTensor2Field;
typedef fvsPatchField<tensor3> fvsPatchTensor3Field;
typedef fvsPatchField<tensor4> fvsPatchTensor4Field; typedef fvsPatchField<tensor4> fvsPatchTensor4Field;
typedef fvsPatchField<tensor6> fvsPatchTensor6Field; typedef fvsPatchField<tensor6> fvsPatchTensor6Field;
typedef fvsPatchField<tensor8> fvsPatchTensor8Field; typedef fvsPatchField<tensor8> fvsPatchTensor8Field;
typedef fvsPatchField<diagTensor2> fvsPatchDiagTensor2Field; typedef fvsPatchField<diagTensor2> fvsPatchDiagTensor2Field;
typedef fvsPatchField<diagTensor3> fvsPatchDiagTensor3Field;
typedef fvsPatchField<diagTensor4> fvsPatchDiagTensor4Field; typedef fvsPatchField<diagTensor4> fvsPatchDiagTensor4Field;
typedef fvsPatchField<diagTensor6> fvsPatchDiagTensor6Field; typedef fvsPatchField<diagTensor6> fvsPatchDiagTensor6Field;
typedef fvsPatchField<diagTensor8> fvsPatchDiagTensor8Field; typedef fvsPatchField<diagTensor8> fvsPatchDiagTensor8Field;
typedef fvsPatchField<sphericalTensor2> fvsPatchSphericalTensor2Field; typedef fvsPatchField<sphericalTensor2> fvsPatchSphericalTensor2Field;
typedef fvsPatchField<sphericalTensor3> fvsPatchSphericalTensor3Field;
typedef fvsPatchField<sphericalTensor4> fvsPatchSphericalTensor4Field; typedef fvsPatchField<sphericalTensor4> fvsPatchSphericalTensor4Field;
typedef fvsPatchField<sphericalTensor6> fvsPatchSphericalTensor6Field; typedef fvsPatchField<sphericalTensor6> fvsPatchSphericalTensor6Field;
typedef fvsPatchField<sphericalTensor8> fvsPatchSphericalTensor8Field; typedef fvsPatchField<sphericalTensor8> fvsPatchSphericalTensor8Field;

View file

@ -90,8 +90,9 @@ void Foam::setRefCell
" bool\n" " bool\n"
")", ")",
dict dict
) << "Unable to set reference cell for field " << field.name() ) << "Unable to set reference cell for field "
<< nl << " Reference point " << refPointName << field.name() << nl
<< " Reference point " << refPointName
<< " " << refPointi << " " << refPointi
<< " found on " << sumHasRef << " domains (should be one)" << " found on " << sumHasRef << " domains (should be one)"
<< nl << exit(FatalIOError); << nl << exit(FatalIOError);

View file

@ -276,6 +276,13 @@ public:
return source_; return source_;
} }
//- Access to fvBoundary scalar field containing
// pseudo-matrix coeffs for internal cells
const FieldField<Field, Type>& internalCoeffs() const
{
return internalCoeffs_;
}
//- fvBoundary scalar field containing pseudo-matrix coeffs //- fvBoundary scalar field containing pseudo-matrix coeffs
// for internal cells // for internal cells
FieldField<Field, Type>& internalCoeffs() FieldField<Field, Type>& internalCoeffs()
@ -283,6 +290,13 @@ public:
return internalCoeffs_; return internalCoeffs_;
} }
//- Access to fvBoundary scalar field containing
// pseudo-matrix coeffs for boundary cells
const FieldField<Field, Type>& boundaryCoeffs() const
{
return boundaryCoeffs_;
}
//- fvBoundary scalar field containing pseudo-matrix coeffs //- fvBoundary scalar field containing pseudo-matrix coeffs
// for boundary cells // for boundary cells
FieldField<Field, Type>& boundaryCoeffs() FieldField<Field, Type>& boundaryCoeffs()