/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2023-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 .
\*---------------------------------------------------------------------------*/
#include "GAMGSolver.H"
#include "GAMGInterfaceField.H"
#include "processorLduInterfaceField.H"
#include "processorGAMGInterfaceField.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::GAMGSolver::agglomerateMatrix
(
const label fineLevelIndex,
const lduMesh& coarseMesh,
const lduInterfacePtrsList& coarseMeshInterfaces
)
{
// Get fine matrix
const lduMatrix& fineMatrix = matrixLevel(fineLevelIndex);
if (UPstream::myProcNo(fineMatrix.mesh().comm()) != -1)
{
const label nCoarseFaces = agglomeration_.nFaces(fineLevelIndex);
const label nCoarseCells = agglomeration_.nCells(fineLevelIndex);
// Set the coarse level matrix
matrixLevels_.set
(
fineLevelIndex,
new lduMatrix(coarseMesh)
);
lduMatrix& coarseMatrix = matrixLevels_[fineLevelIndex];
// Coarse matrix diagonal initialised by restricting the finer mesh
// diagonal. Note that we size with the cached coarse nCells and not
// the actual coarseMesh size since this might be dummy when processor
// agglomerating.
scalarField& coarseDiag = coarseMatrix.diag(nCoarseCells);
agglomeration_.restrictField
(
coarseDiag,
fineMatrix.diag(),
fineLevelIndex,
false // no processor agglomeration
);
// Get reference to fine-level interfaces
const lduInterfaceFieldPtrsList& fineInterfaces =
interfaceLevel(fineLevelIndex);
// Create coarse-level interfaces
primitiveInterfaceLevels_.set
(
fineLevelIndex,
new PtrList(fineInterfaces.size())
);
PtrList& coarsePrimInterfaces =
primitiveInterfaceLevels_[fineLevelIndex];
interfaceLevels_.set
(
fineLevelIndex,
new lduInterfaceFieldPtrsList(fineInterfaces.size())
);
lduInterfaceFieldPtrsList& coarseInterfaces =
interfaceLevels_[fineLevelIndex];
// Set coarse-level boundary coefficients
interfaceLevelsBouCoeffs_.set
(
fineLevelIndex,
new FieldField(fineInterfaces.size())
);
FieldField& coarseInterfaceBouCoeffs =
interfaceLevelsBouCoeffs_[fineLevelIndex];
// Set coarse-level internal coefficients
interfaceLevelsIntCoeffs_.set
(
fineLevelIndex,
new FieldField(fineInterfaces.size())
);
FieldField& coarseInterfaceIntCoeffs =
interfaceLevelsIntCoeffs_[fineLevelIndex];
// Add the coarse level
agglomerateInterfaceCoefficients
(
fineLevelIndex,
coarseMeshInterfaces,
coarsePrimInterfaces,
coarseInterfaces,
coarseInterfaceBouCoeffs,
coarseInterfaceIntCoeffs
);
// Get face restriction map for current level
const labelList& faceRestrictAddr =
agglomeration_.faceRestrictAddressing(fineLevelIndex);
const boolList& faceFlipMap =
agglomeration_.faceFlipMap(fineLevelIndex);
// Check if matrix is asymmetric and if so agglomerate both upper
// and lower coefficients ...
if (fineMatrix.hasLower())
{
// Get off-diagonal matrix coefficients
const scalarField& fineUpper = fineMatrix.upper();
const scalarField& fineLower = fineMatrix.lower();
// Coarse matrix upper coefficients. Note passed in size
scalarField& coarseUpper = coarseMatrix.upper(nCoarseFaces);
scalarField& coarseLower = coarseMatrix.lower(nCoarseFaces);
forAll(faceRestrictAddr, fineFacei)
{
label cFace = faceRestrictAddr[fineFacei];
if (cFace >= 0)
{
// Check the orientation of the fine-face relative to the
// coarse face it is being agglomerated into
if (!faceFlipMap[fineFacei])
{
coarseUpper[cFace] += fineUpper[fineFacei];
coarseLower[cFace] += fineLower[fineFacei];
}
else
{
coarseUpper[cFace] += fineLower[fineFacei];
coarseLower[cFace] += fineUpper[fineFacei];
}
}
else
{
// Add the fine face coefficients into the diagonal.
coarseDiag[-1 - cFace] +=
fineUpper[fineFacei] + fineLower[fineFacei];
}
}
}
else // ... Otherwise it is symmetric so agglomerate just the upper
{
// Get off-diagonal matrix coefficients
const scalarField& fineUpper = fineMatrix.upper();
// Coarse matrix upper coefficients
scalarField& coarseUpper = coarseMatrix.upper(nCoarseFaces);
forAll(faceRestrictAddr, fineFacei)
{
label cFace = faceRestrictAddr[fineFacei];
if (cFace >= 0)
{
coarseUpper[cFace] += fineUpper[fineFacei];
}
else
{
// Add the fine face coefficient into the diagonal.
coarseDiag[-1 - cFace] += 2*fineUpper[fineFacei];
}
}
}
}
}
void Foam::GAMGSolver::agglomerateInterfaceCoefficients
(
const label fineLevelIndex,
const lduInterfacePtrsList& coarseMeshInterfaces,
PtrList& coarsePrimInterfaces,
lduInterfaceFieldPtrsList& coarseInterfaces,
FieldField& coarseInterfaceBouCoeffs,
FieldField& coarseInterfaceIntCoeffs
) const
{
// Get reference to fine-level interfaces
const lduInterfaceFieldPtrsList& fineInterfaces =
interfaceLevel(fineLevelIndex);
// Get reference to fine-level boundary coefficients
const FieldField& fineInterfaceBouCoeffs =
interfaceBouCoeffsLevel(fineLevelIndex);
// Get reference to fine-level internal coefficients
const FieldField& fineInterfaceIntCoeffs =
interfaceIntCoeffsLevel(fineLevelIndex);
const labelListList& patchFineToCoarse =
agglomeration_.patchFaceRestrictAddressing(fineLevelIndex);
const labelList& nPatchFaces =
agglomeration_.nPatchFaces(fineLevelIndex);
// Add the coarse level
forAll(fineInterfaces, inti)
{
if (fineInterfaces.set(inti))
{
const GAMGInterface& coarseInterface =
refCast
(
coarseMeshInterfaces[inti]
);
coarsePrimInterfaces.set
(
inti,
GAMGInterfaceField::New
(
coarseInterface,
fineInterfaces[inti]
).ptr()
);
coarseInterfaces.set
(
inti,
&coarsePrimInterfaces[inti]
);
const labelList& faceRestrictAddressing = patchFineToCoarse[inti];
coarseInterfaceBouCoeffs.set
(
inti,
new scalarField(nPatchFaces[inti], Zero)
);
agglomeration_.restrictField
(
coarseInterfaceBouCoeffs[inti],
fineInterfaceBouCoeffs[inti],
faceRestrictAddressing
);
coarseInterfaceIntCoeffs.set
(
inti,
new scalarField(nPatchFaces[inti], Zero)
);
agglomeration_.restrictField
(
coarseInterfaceIntCoeffs[inti],
fineInterfaceIntCoeffs[inti],
faceRestrictAddressing
);
}
}
}
void Foam::GAMGSolver::gatherMatrices
(
const label destLevel,
const label comm,
// Local matrix
const lduMatrix& mat,
const FieldField& interfaceBouCoeffs,
const FieldField& interfaceIntCoeffs,
const lduInterfaceFieldPtrsList& interfaces,
// Remote matrices
PtrList& otherMats,
PtrList>& otherBouCoeffs,
PtrList>& otherIntCoeffs,
PtrList>& otherInterfaces
) const
{
if (debug & 2)
{
const auto& procIDs = UPstream::procID(comm);
Pout<< "GAMGSolver::gatherMatrices :"
<< " collecting matrices from procs:" << procIDs
<< " using comm:" << comm << endl;
}
const auto& boundaryMap = agglomeration_.boundaryMap(destLevel);
PstreamBuffers pBufs(comm);
// Send to master
if (!UPstream::master(comm))
{
// Mark valid interfaces
// -1 : not set
// >= 0 : coupled interface (might also be unmerged processor boundary)
//
// Note: most processor interfaces will disappear. Originally
// we did not know which ones were kept but this is now stored
// on the boundaryMap (even on the slave processors). So we can
// already filter here and avoid sending across typeNames etc.
const label proci = UPstream::myProcNo(comm);
// All interfaceBouCoeffs need to be sent across
bitSet validCoeffs(interfaces.size());
forAll(interfaceBouCoeffs, intI)
{
if (interfaceBouCoeffs.set(intI))
{
validCoeffs.set(intI);
}
}
// Only preserved interfaces need to be sent across
bitSet validInterface(interfaces.size());
forAll(interfaces, intI)
{
const label allIntI = boundaryMap[proci][intI];
if (interfaces.set(intI) && allIntI != -1)
{
validInterface.set(intI);
}
}
UOPstream toMaster(UPstream::masterNo(), pBufs);
toMaster
<< mat
<< token::SPACE << validCoeffs
<< token::SPACE << validInterface;
for (const label intI : validCoeffs)
{
toMaster
<< interfaceBouCoeffs[intI]
<< interfaceIntCoeffs[intI];
}
for (const label intI : validInterface)
{
const auto& interface = refCast
(
interfaces[intI]
);
toMaster << interface.type();
interface.write(toMaster);
}
}
// Wait for finish
pBufs.finishedGathers();
// Consume
if (UPstream::master(comm))
{
const label nProcs = UPstream::nProcs(comm);
const lduMesh& destMesh = agglomeration_.meshLevel(destLevel);
lduInterfacePtrsList destInterfaces = destMesh.interfaces();
// Master.
otherMats.resize(nProcs-1);
otherBouCoeffs.resize(nProcs-1);
otherIntCoeffs.resize(nProcs-1);
otherInterfaces.resize(nProcs-1);
for (const int proci : UPstream::subProcs(comm))
{
const label otherI = proci-1;
UIPstream fromProc(proci, pBufs);
otherMats.set(otherI, new lduMatrix(destMesh, fromProc));
// Receive bit-sets of valid interfaceCoeffs/interfaces
const bitSet validCoeffs(fromProc);
const bitSet validInterface(fromProc);
otherBouCoeffs.emplace_set(otherI, validCoeffs.size());
otherIntCoeffs.emplace_set(otherI, validCoeffs.size());
otherInterfaces.emplace_set(otherI, validInterface.size());
// Receive individual interface contributions
for (const label intI : validCoeffs)
{
otherBouCoeffs[otherI].emplace_set(intI, fromProc);
otherIntCoeffs[otherI].emplace_set(intI, fromProc);
}
// Receive individual interface contributions
for (const label intI : validInterface)
{
const word coupleType(fromProc);
const label allIntI = boundaryMap[proci][intI];
otherInterfaces[otherI].set
(
intI,
GAMGInterfaceField::New
(
coupleType,
refCast
(
destInterfaces[allIntI]
),
fromProc
).release()
);
}
}
}
}
void Foam::GAMGSolver::procAgglomerateMatrix
(
// Agglomeration information
const labelList& procAgglomMap,
const List