mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'feature-distributedDIC' into 'develop'
Feature distributed DIC/DILU preconditioners See merge request Development/openfoam!608
This commit is contained in:
@ -309,6 +309,11 @@ $(ACMICycPatches)/cyclicACMIPointPatchField/cyclicACMIPointPatchFields.C
|
||||
PeriodicAMICycPatches=$(AMI)/patches/cyclicPeriodicAMI
|
||||
$(PeriodicAMICycPatches)/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
|
||||
|
||||
extraPreconditioners=matrices/lduMatrix/preconditioners/distributedDILUPreconditioner
|
||||
$(extraPreconditioners)/distributedDILUPreconditioner.C
|
||||
$(extraPreconditioners)/distributedDICPreconditioner.C
|
||||
$(extraPreconditioners)/processorColour.C
|
||||
|
||||
multiWorld/multiWorldConnectionsObject.C
|
||||
|
||||
mappedPatches/mappedPolyPatch/mappedPatchBase.C
|
||||
|
||||
@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "distributedDICPreconditioner.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(distributedDICPreconditioner, 0);
|
||||
|
||||
lduMatrix::preconditioner::
|
||||
addsymMatrixConstructorToTable<distributedDICPreconditioner>
|
||||
adddistributedDICPreconditionerSymMatrixConstructorToTable_;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::distributedDICPreconditioner::forwardInternalDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
// Add forward constributions to diagonal
|
||||
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
|
||||
const label* const __restrict__ uPtr = lduAddr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = lduAddr.lowerAddr().begin();
|
||||
const scalar* const __restrict__ upperPtr = matrix.upper().begin();
|
||||
|
||||
const label nFaces = matrix.upper().size();
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
const auto& cellColour = cellColourPtr_();
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
const label cell = lPtr[face];
|
||||
if (cellColour[cell] == colouri)
|
||||
{
|
||||
rD[uPtr[face]] -= upperPtr[face]*upperPtr[face]/rD[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
rD[uPtr[face]] -= upperPtr[face]*upperPtr[face]/rD[lPtr[face]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDICPreconditioner::forwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
|
||||
solveScalar* __restrict__ wAPtr = wA.begin();
|
||||
const solveScalar* __restrict__ rDPtr = rD_.begin();
|
||||
|
||||
const label* const __restrict__ uPtr = lduAddr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = lduAddr.lowerAddr().begin();
|
||||
const scalar* const __restrict__ upperPtr = matrix.upper().begin();
|
||||
|
||||
const label nFaces = matrix.upper().size();
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
const auto& cellColour = cellColourPtr_();
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
const label cell = lPtr[face];
|
||||
if (cellColour[cell] == colouri)
|
||||
{
|
||||
wAPtr[uPtr[face]] -=
|
||||
rDPtr[uPtr[face]]*upperPtr[face]*wAPtr[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
wAPtr[uPtr[face]] -=
|
||||
rDPtr[uPtr[face]]*upperPtr[face]*wAPtr[lPtr[face]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::distributedDICPreconditioner::distributedDICPreconditioner
|
||||
(
|
||||
const lduMatrix::solver& sol,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
distributedDILUPreconditioner(sol, dict)
|
||||
{}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,131 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::distributedDICPreconditioner
|
||||
|
||||
Group
|
||||
grpLduMatrixPreconditioners
|
||||
|
||||
Description
|
||||
Version of DICpreconditioner that uses preconditioning across processor
|
||||
(and coupled) boundaries. Based on 'Parallel Preconditioners' chapter from
|
||||
'Iterative Methods for Sparse Linear Systems' by Yousef Saad.
|
||||
|
||||
Leaves out the handling of boundary nodes after internal nodes since
|
||||
probably not beneficial (so no overlap of comms and internal calculation)
|
||||
|
||||
By default preconditions across coupled boundaries (currently only
|
||||
tested for cyclicAMI). This can be disabled with the 'coupled' setting
|
||||
|
||||
solver PCG;
|
||||
preconditioner
|
||||
{
|
||||
preconditioner distributedDIC;
|
||||
coupled false;
|
||||
}
|
||||
|
||||
The cyclicAMI boundary behaviour will only work if
|
||||
- running non-parallel or
|
||||
- different sides of cyclicAMI run on different processors i.e.
|
||||
there is no processor which has cells on both owner and neighbour
|
||||
of the patch pair.
|
||||
|
||||
See Also
|
||||
Foam::DICPreconditioner
|
||||
Foam::distributedDILUPreconditioner
|
||||
|
||||
SourceFiles
|
||||
distributedDICPreconditioner.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef distributedDICPreconditioner_H
|
||||
#define distributedDICPreconditioner_H
|
||||
|
||||
#include "distributedDILUPreconditioner.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class distributedDICPreconditioner Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class distributedDICPreconditioner
|
||||
:
|
||||
public distributedDILUPreconditioner
|
||||
{
|
||||
protected:
|
||||
|
||||
// Protected member functions
|
||||
|
||||
//- Update diagonal for colour
|
||||
virtual void forwardInternalDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
//- Update preconditioned variable walking forward on internal faces
|
||||
virtual void forwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("distributedDIC");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from matrix components and preconditioner solver controls
|
||||
distributedDICPreconditioner
|
||||
(
|
||||
const lduMatrix::solver&,
|
||||
const dictionary& solverControlsUnused
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~distributedDICPreconditioner() = default;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,897 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "distributedDILUPreconditioner.H"
|
||||
#include "processorLduInterface.H"
|
||||
#include "cyclicLduInterface.H"
|
||||
#include "cyclicAMILduInterface.H"
|
||||
#include "processorColour.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(distributedDILUPreconditioner, 0);
|
||||
|
||||
lduMatrix::preconditioner::
|
||||
addasymMatrixConstructorToTable<distributedDILUPreconditioner>
|
||||
adddistributedDILUPreconditionerAsymMatrixConstructorToTable_;
|
||||
|
||||
const lduMesh* distributedDILUPreconditioner::meshPtr_ = nullptr;
|
||||
|
||||
autoPtr<labelList> distributedDILUPreconditioner::procColoursPtr_(nullptr);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
void Foam::distributedDILUPreconditioner::updateMatrixInterfaces
|
||||
(
|
||||
const bool add,
|
||||
const FieldField<Field, solveScalar>& coupleCoeffs,
|
||||
const labelList& selectedInterfaces,
|
||||
const solveScalarField& psiif,
|
||||
solveScalarField& result,
|
||||
const direction cmpt
|
||||
) const
|
||||
{
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
|
||||
const label startOfRequests = Pstream::nRequests();
|
||||
|
||||
// From lduMatrix::initMatrixInterfaces
|
||||
|
||||
// Avoid any conflicts with inter-processor comms
|
||||
UPstream::msgType() += 321;
|
||||
|
||||
for (const label interfacei : selectedInterfaces)
|
||||
{
|
||||
interfaces[interfacei].initInterfaceMatrixUpdate
|
||||
(
|
||||
result,
|
||||
add,
|
||||
lduAddr,
|
||||
interfacei,
|
||||
psiif,
|
||||
coupleCoeffs[interfacei],
|
||||
cmpt,
|
||||
UPstream::commsTypes::nonBlocking
|
||||
);
|
||||
}
|
||||
|
||||
UPstream::waitRequests(startOfRequests);
|
||||
|
||||
// Consume
|
||||
for (const label interfacei : selectedInterfaces)
|
||||
{
|
||||
interfaces[interfacei].updateInterfaceMatrix
|
||||
(
|
||||
result,
|
||||
add,
|
||||
lduAddr,
|
||||
interfacei,
|
||||
psiif,
|
||||
coupleCoeffs[interfacei],
|
||||
cmpt,
|
||||
UPstream::commsTypes::nonBlocking
|
||||
);
|
||||
}
|
||||
|
||||
UPstream::msgType() -= 321;
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::sendGlobal
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
solveScalarField& psi,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
|
||||
if (selectedInterfaces.size())
|
||||
{
|
||||
// Save old data
|
||||
FieldField<Field, solveScalar> one(interfaces.size());
|
||||
FieldField<Field, solveScalar> old(interfaces.size());
|
||||
for (const label inti : selectedInterfaces)
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto& fc = intf.faceCells();
|
||||
one.set(inti, new solveScalarField(fc.size(), 1.0));
|
||||
old.set(inti, new solveScalarField(psi, intf.faceCells()));
|
||||
}
|
||||
updateMatrixInterfaces
|
||||
(
|
||||
false, // add to psi
|
||||
one,
|
||||
selectedInterfaces,
|
||||
psi, // send data
|
||||
psi, // result
|
||||
0 // cmpt
|
||||
);
|
||||
|
||||
if (!colourBufs_.set(colouri))
|
||||
{
|
||||
colourBufs_.set
|
||||
(
|
||||
colouri,
|
||||
new FieldField<Field, solveScalar>
|
||||
(
|
||||
interfaces.size()
|
||||
)
|
||||
);
|
||||
}
|
||||
auto& colourBuf = colourBufs_[colouri];
|
||||
colourBuf.setSize(interfaces.size());
|
||||
for (const label inti : selectedInterfaces)
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto& fc = intf.faceCells();
|
||||
if (!colourBuf.set(inti))
|
||||
{
|
||||
colourBuf.set(inti, new Field<solveScalar>(fc.size()));
|
||||
}
|
||||
auto& cb = colourBuf[inti];
|
||||
//cb.resize_nocopy(fc.size());
|
||||
auto& oldValues = old[inti];
|
||||
|
||||
forAll(cb, face)
|
||||
{
|
||||
const label cell = fc[face];
|
||||
// Store change in boundary value
|
||||
cb[face] = psi[cell]-oldValues[face];
|
||||
// Restore old value
|
||||
std::swap(psi[cell], oldValues[face]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::receive
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
DynamicList<UPstream::Request>& requests
|
||||
) const
|
||||
{
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
const auto& interfaceBouCoeffs = solver_.interfaceBouCoeffs();
|
||||
|
||||
// Start reads
|
||||
for (const label inti : selectedInterfaces)
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto* ppp = isA<const processorLduInterface>(intf);
|
||||
|
||||
auto& recvBuf = recvBufs_[inti];
|
||||
recvBuf.resize_nocopy(interfaceBouCoeffs[inti].size());
|
||||
|
||||
requests.push_back(UPstream::Request());
|
||||
UIPstream::read
|
||||
(
|
||||
requests.back(),
|
||||
ppp->neighbProcNo(),
|
||||
recvBuf.data_bytes(),
|
||||
recvBuf.size_bytes(),
|
||||
ppp->tag()+70, // random offset
|
||||
ppp->comm()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::send
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
const solveScalarField& psiInternal,
|
||||
DynamicList<UPstream::Request>& requests
|
||||
) const
|
||||
{
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
|
||||
// Start writes
|
||||
for (const label inti : selectedInterfaces)
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto* ppp = isA<const processorLduInterface>(intf);
|
||||
const auto& faceCells = intf.faceCells();
|
||||
|
||||
auto& sendBuf = sendBufs_[inti];
|
||||
|
||||
sendBuf.resize_nocopy(faceCells.size());
|
||||
forAll(faceCells, face)
|
||||
{
|
||||
sendBuf[face] = psiInternal[faceCells[face]];
|
||||
}
|
||||
|
||||
requests.push_back(UPstream::Request());
|
||||
UOPstream::write
|
||||
(
|
||||
requests.back(),
|
||||
ppp->neighbProcNo(),
|
||||
sendBuf.cdata_bytes(),
|
||||
sendBuf.size_bytes(),
|
||||
ppp->tag()+70, // random offset
|
||||
ppp->comm()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::wait
|
||||
(
|
||||
DynamicList<UPstream::Request>& requests
|
||||
) const
|
||||
{
|
||||
UPstream::waitRequests(requests);
|
||||
requests.clear();
|
||||
}
|
||||
|
||||
|
||||
// Diagonal calculation
|
||||
// ~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void Foam::distributedDILUPreconditioner::addInterfaceDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label inti,
|
||||
const Field<solveScalar>& recvBuf
|
||||
) const
|
||||
{
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
const auto& interfaceBouCoeffs = solver_.interfaceBouCoeffs();
|
||||
const auto& interfaceIntCoeffs = solver_.interfaceIntCoeffs();
|
||||
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
// TBD: do not use patch faceCells but passed-in addressing?
|
||||
const auto& faceCells = intf.faceCells();
|
||||
const auto& bc = interfaceBouCoeffs[inti];
|
||||
const auto& ic = interfaceIntCoeffs[inti];
|
||||
|
||||
forAll(recvBuf, face)
|
||||
{
|
||||
// Note:interfaceBouCoeffs, interfaceIntCoeffs on the receiving
|
||||
// side are negated
|
||||
rD[faceCells[face]] -= bc[face]*ic[face]/recvBuf[face];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::forwardInternalDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
// Add forward constributions to diagonal
|
||||
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
|
||||
const label* const __restrict__ uPtr = lduAddr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = lduAddr.lowerAddr().begin();
|
||||
const scalar* const __restrict__ upperPtr = matrix.upper().begin();
|
||||
const scalar* const __restrict__ lowerPtr = matrix.lower().begin();
|
||||
|
||||
const label nFaces = matrix.upper().size();
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
const auto& cellColour = cellColourPtr_();
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
const label cell = lPtr[face];
|
||||
if (cellColour[cell] == colouri)
|
||||
{
|
||||
rD[uPtr[face]] -= upperPtr[face]*lowerPtr[face]/rD[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
rD[uPtr[face]] -= upperPtr[face]*lowerPtr[face]/rD[lPtr[face]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::addInterface
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label inti,
|
||||
const Field<solveScalar>& recvBuf
|
||||
) const
|
||||
{
|
||||
const auto& interfaces = solver_.interfaces();
|
||||
const auto& interfaceBouCoeffs = solver_.interfaceBouCoeffs();
|
||||
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto& faceCells = intf.faceCells();
|
||||
const auto& bc = interfaceBouCoeffs[inti];
|
||||
const solveScalar* __restrict__ rDPtr = rD_.begin();
|
||||
solveScalar* __restrict__ wAPtr = wA.begin();
|
||||
|
||||
forAll(recvBuf, face)
|
||||
{
|
||||
// Note: interfaceBouCoeffs is -upperPtr
|
||||
const label cell = faceCells[face];
|
||||
wAPtr[cell] += rDPtr[cell]*bc[face]*recvBuf[face];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::forwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
|
||||
solveScalar* __restrict__ wAPtr = wA.begin();
|
||||
const solveScalar* __restrict__ rDPtr = rD_.begin();
|
||||
|
||||
const label* const __restrict__ uPtr = lduAddr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = lduAddr.lowerAddr().begin();
|
||||
const label* const __restrict__ losortPtr = lduAddr.losortAddr().begin();
|
||||
const scalar* const __restrict__ lowerPtr = matrix.lower().begin();
|
||||
|
||||
const label nFaces = matrix.upper().size();
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
const auto& cellColour = cellColourPtr_();
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
const label sface = losortPtr[face];
|
||||
const label cell = lPtr[sface];
|
||||
if (cellColour[cell] == colouri)
|
||||
{
|
||||
wAPtr[uPtr[sface]] -=
|
||||
rDPtr[uPtr[sface]]*lowerPtr[sface]*wAPtr[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label face=0; face<nFaces; face++)
|
||||
{
|
||||
const label sface = losortPtr[face];
|
||||
wAPtr[uPtr[sface]] -=
|
||||
rDPtr[uPtr[sface]]*lowerPtr[sface]*wAPtr[lPtr[sface]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::backwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const
|
||||
{
|
||||
const auto& matrix = solver_.matrix();
|
||||
const auto& lduAddr = matrix.lduAddr();
|
||||
|
||||
solveScalar* __restrict__ wAPtr = wA.begin();
|
||||
const solveScalar* __restrict__ rDPtr = rD_.begin();
|
||||
|
||||
const label* const __restrict__ uPtr = lduAddr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = lduAddr.lowerAddr().begin();
|
||||
const scalar* const __restrict__ upperPtr = matrix.upper().begin();
|
||||
|
||||
const label nFacesM1 = matrix.upper().size() - 1;
|
||||
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
const auto& cellColour = cellColourPtr_();
|
||||
for (label face=nFacesM1; face>=0; face--)
|
||||
{
|
||||
const label cell = uPtr[face];
|
||||
if (cellColour[cell] == colouri)
|
||||
{
|
||||
// Note: lower cell guaranteed in same colour
|
||||
wAPtr[lPtr[face]] -=
|
||||
rDPtr[lPtr[face]]*upperPtr[face]*wAPtr[cell];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (label face=nFacesM1; face>=0; face--)
|
||||
{
|
||||
wAPtr[lPtr[face]] -=
|
||||
rDPtr[lPtr[face]]*upperPtr[face]*wAPtr[uPtr[face]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distributedDILUPreconditioner::calcReciprocalD
|
||||
(
|
||||
solveScalarField& rD
|
||||
) const
|
||||
{
|
||||
const auto& matrix = solver_.matrix();
|
||||
|
||||
// Make sure no outstanding receives
|
||||
wait(lowerRecvRequests_);
|
||||
|
||||
// Start reads (into recvBufs_)
|
||||
receive(lowerNbrs_, lowerRecvRequests_);
|
||||
|
||||
// Start with diagonal
|
||||
const scalarField& diag = matrix.diag();
|
||||
rD.resize_nocopy(diag.size());
|
||||
std::copy(diag.begin(), diag.end(), rD.begin());
|
||||
|
||||
|
||||
// Subtract coupled contributions
|
||||
{
|
||||
// Wait for finish. Received result in recvBufs
|
||||
wait(lowerRecvRequests_);
|
||||
|
||||
for (const label inti : lowerNbrs_)
|
||||
{
|
||||
addInterfaceDiag(rD, inti, recvBufs_[inti]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// - divide the internal mesh into domains/colour, similar to domain
|
||||
// decomposition
|
||||
// - we could use subsetted bits of the mesh or just loop over only
|
||||
// the cells of the current domain
|
||||
// - a domain only uses boundary values of lower numbered domains
|
||||
// - this also limits the interfaces that need to be evaluated since
|
||||
// we assume an interface only changes local faceCells and these
|
||||
// are all of the same colour
|
||||
|
||||
for (label colouri = 0; colouri < nColours_; colouri++)
|
||||
{
|
||||
if (cellColourPtr_.valid())// && colourBufs_.set(colouri))
|
||||
{
|
||||
for (const label inti : lowerGlobalRecv_[colouri])
|
||||
{
|
||||
addInterfaceDiag(rD, inti, colourBufs_[colouri][inti]);
|
||||
}
|
||||
}
|
||||
|
||||
forwardInternalDiag(rD, colouri);
|
||||
|
||||
// Store effect of exchanging rD to higher interfaces in colourBufs_
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
sendGlobal(higherGlobalSend_[colouri], rD, higherColour_[colouri]);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure no outstanding sends
|
||||
wait(higherSendRequests_);
|
||||
|
||||
// Start writes of rD (using sendBufs)
|
||||
send(higherNbrs_, rD, higherSendRequests_);
|
||||
|
||||
// Calculate the reciprocal of the preconditioned diagonal
|
||||
const label nCells = rD.size();
|
||||
|
||||
for (label cell=0; cell<nCells; cell++)
|
||||
{
|
||||
rD[cell] = 1.0/rD[cell];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::distributedDILUPreconditioner::distributedDILUPreconditioner
|
||||
(
|
||||
const lduMatrix::solver& sol,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
lduMatrix::preconditioner(sol),
|
||||
coupled_(dict.getOrDefault<bool>("coupled", true, keyType::LITERAL)),
|
||||
rD_(sol.matrix().diag().size())
|
||||
{
|
||||
const lduMesh& mesh = sol.matrix().mesh();
|
||||
const auto& interfaces = sol.interfaces();
|
||||
const auto& interfaceBouCoeffs = sol.interfaceBouCoeffs();
|
||||
|
||||
// Allocate buffers
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
|
||||
sendBufs_.setSize(interfaces.size());
|
||||
recvBufs_.setSize(interfaces.size());
|
||||
forAll(interfaceBouCoeffs, inti)
|
||||
{
|
||||
if (interfaces.set(inti))
|
||||
{
|
||||
const auto& bc = interfaceBouCoeffs[inti];
|
||||
sendBufs_.set(inti, new scalarField(bc.size(), Zero));
|
||||
recvBufs_.set(inti, new scalarField(bc.size(), Zero));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Determine processor colouring
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
//const processorColour& colours = processorColour::New(mesh);
|
||||
//const label myColour = colours[Pstream::myProcNo()];
|
||||
if (&mesh != meshPtr_)
|
||||
{
|
||||
procColoursPtr_.reset(new labelList(Pstream::nProcs(mesh.comm())));
|
||||
const label nProcColours =
|
||||
processorColour::colour(mesh, procColoursPtr_());
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName << " : calculated processor colours:"
|
||||
<< nProcColours << endl;
|
||||
}
|
||||
|
||||
meshPtr_ = &mesh;
|
||||
}
|
||||
const labelList& procColours = procColoursPtr_();
|
||||
|
||||
const label myColour = procColours[Pstream::myProcNo(mesh.comm())];
|
||||
|
||||
bool haveGlobalCoupled = false;
|
||||
bool haveDistributedAMI = false;
|
||||
forAll(interfaces, inti)
|
||||
{
|
||||
if (interfaces.set(inti))
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
const auto* ppp = isA<const processorLduInterface>(intf);
|
||||
if (ppp)
|
||||
{
|
||||
const label nbrColour = procColours[ppp->neighbProcNo()];
|
||||
//const label nbrColour = ppp->neighbProcNo();
|
||||
if (nbrColour < myColour)
|
||||
{
|
||||
lowerNbrs_.append(inti);
|
||||
}
|
||||
else if (nbrColour > myColour)
|
||||
{
|
||||
higherNbrs_.append(inti);
|
||||
}
|
||||
else
|
||||
{
|
||||
WarningInFunction
|
||||
<< "weird processorLduInterface"
|
||||
<< " from " << ppp->myProcNo()
|
||||
<< " to " << ppp->neighbProcNo()
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
else //if (isA<const cyclicAMILduInterface>(intf))
|
||||
{
|
||||
haveGlobalCoupled = true;
|
||||
|
||||
const auto* AMIpp = isA<const cyclicAMILduInterface>(intf);
|
||||
if (AMIpp)
|
||||
{
|
||||
//const auto& AMI =
|
||||
//(
|
||||
// AMIpp->owner()
|
||||
// ? AMIpp->AMI()
|
||||
// : AMIpp->neighbPatch().AMI()
|
||||
//);
|
||||
//haveDistributedAMI = AMI.distributed();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName << " : interface " << inti
|
||||
<< " of type " << intf.type()
|
||||
<< " is distributed:" << haveDistributedAMI << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName
|
||||
<< " : lower proc interfaces:" << flatOutput(lowerNbrs_)
|
||||
<< " higher proc interfaces:" << flatOutput(higherNbrs_)
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
// Determine local colouring/zoneing
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Start off with all cells colour 0
|
||||
nColours_ = 1;
|
||||
cellColourPtr_.clear();
|
||||
if (coupled_ && haveGlobalCoupled)
|
||||
{
|
||||
labelList patchToColour;
|
||||
cellColourPtr_.reset(new labelList(mesh.lduAddr().size()));
|
||||
//if (haveDistributedAMI)
|
||||
//{
|
||||
// nColours_ = 1;
|
||||
// cellColourPtr_() = 0;
|
||||
// patchToColour = labelList(interfaces.size(), 0);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
nColours_ = processorColour::cellColour
|
||||
(
|
||||
mesh,
|
||||
cellColourPtr_(),
|
||||
patchToColour
|
||||
);
|
||||
}
|
||||
|
||||
lowerGlobalRecv_.resize_nocopy(nColours_);
|
||||
lowerGlobalSend_.resize_nocopy(nColours_);
|
||||
lowerColour_.setSize(nColours_, -1);
|
||||
higherGlobalRecv_.resize_nocopy(nColours_);
|
||||
higherGlobalSend_.resize_nocopy(nColours_);
|
||||
higherColour_.setSize(nColours_, -1);
|
||||
colourBufs_.setSize(nColours_);
|
||||
|
||||
forAll(interfaces, inti)
|
||||
{
|
||||
if (interfaces.set(inti))
|
||||
{
|
||||
const auto& intf = interfaces[inti].interface();
|
||||
|
||||
label nbrInti = -1;
|
||||
const auto* AMIpp = isA<const cyclicAMILduInterface>(intf);
|
||||
if (AMIpp)
|
||||
{
|
||||
nbrInti = AMIpp->neighbPatchID();
|
||||
}
|
||||
const auto* cycpp = isA<const cyclicLduInterface>(intf);
|
||||
if (cycpp)
|
||||
{
|
||||
nbrInti = cycpp->neighbPatchID();
|
||||
}
|
||||
|
||||
if (nbrInti != -1)
|
||||
{
|
||||
const label colouri = patchToColour[inti];
|
||||
const label nbrColouri = patchToColour[nbrInti];
|
||||
|
||||
if
|
||||
(
|
||||
(haveDistributedAMI && (inti < nbrInti))
|
||||
|| (!haveDistributedAMI && (colouri < nbrColouri))
|
||||
)
|
||||
{
|
||||
// Send to higher
|
||||
higherGlobalSend_[colouri].append(nbrInti);
|
||||
higherColour_[colouri] = nbrColouri;
|
||||
// Receive from higher
|
||||
higherGlobalRecv_[colouri].append(inti);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send to lower
|
||||
lowerGlobalSend_[colouri].append(nbrInti);
|
||||
lowerColour_[colouri] = nbrColouri;
|
||||
// Receive from lower
|
||||
lowerGlobalRecv_[colouri].append(inti);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName << " : local colours:" << nColours_ << endl;
|
||||
Info<< incrIndent;
|
||||
forAll(lowerGlobalRecv_, colouri)
|
||||
{
|
||||
const auto& lowerRecv = lowerGlobalRecv_[colouri];
|
||||
if (lowerRecv.size())
|
||||
{
|
||||
const auto& lowerSend = lowerGlobalSend_[colouri];
|
||||
const auto& lowerCol = lowerColour_[colouri];
|
||||
Info<< indent
|
||||
<< "Lower global interfaces for colour:" << colouri
|
||||
<< " receiving from:" << flatOutput(lowerRecv)
|
||||
<< " sending to:" << flatOutput(lowerSend)
|
||||
<< " with colour:" << lowerCol << endl;
|
||||
}
|
||||
}
|
||||
forAll(higherGlobalRecv_, colouri)
|
||||
{
|
||||
const auto& higherRecv = higherGlobalRecv_[colouri];
|
||||
if (higherRecv.size())
|
||||
{
|
||||
const auto& higherSend = higherGlobalSend_[colouri];
|
||||
const auto& higherCol = higherColour_[colouri];
|
||||
Info<< indent
|
||||
<< "Higher global interfaces for colour:" << colouri
|
||||
<< " receiving from:" << flatOutput(higherRecv)
|
||||
<< " sending to:" << flatOutput(higherSend)
|
||||
<< " with colour:" << higherCol << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calcReciprocalD(rD_);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::distributedDILUPreconditioner::~distributedDILUPreconditioner()
|
||||
{
|
||||
// Wait on all requests before storage is being taken down
|
||||
// (could rely on construction order?)
|
||||
wait(lowerSendRequests_);
|
||||
wait(lowerRecvRequests_);
|
||||
wait(higherSendRequests_);
|
||||
wait(higherRecvRequests_);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::distributedDILUPreconditioner::precondition
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const solveScalarField& rA,
|
||||
const direction
|
||||
) const
|
||||
{
|
||||
solveScalar* __restrict__ wAPtr = wA.begin();
|
||||
const solveScalar* __restrict__ rAPtr = rA.begin();
|
||||
const solveScalar* __restrict__ rDPtr = rD_.begin();
|
||||
|
||||
const label nCells = wA.size();
|
||||
|
||||
|
||||
// Forward sweep
|
||||
// ~~~~~~~~~~~~~
|
||||
|
||||
// Make sure no receives are still in flight (should not happen)
|
||||
wait(lowerRecvRequests_);
|
||||
|
||||
// Start reads (into recvBufs)
|
||||
receive(lowerNbrs_, lowerRecvRequests_);
|
||||
|
||||
// Initialise 'internal' cells
|
||||
for (label cell=0; cell<nCells; cell++)
|
||||
{
|
||||
wAPtr[cell] = rDPtr[cell]*rAPtr[cell];
|
||||
}
|
||||
|
||||
// Do 'halo' contributions from lower numbered procs
|
||||
{
|
||||
// Wait for finish. Received result in recvBufs
|
||||
wait(lowerRecvRequests_);
|
||||
|
||||
for (const label inti : lowerNbrs_)
|
||||
{
|
||||
addInterface(wA, inti, recvBufs_[inti]);
|
||||
}
|
||||
|
||||
for (label colouri = 0; colouri < nColours_; colouri++)
|
||||
{
|
||||
// Do non-processor boundaries for this colour
|
||||
if (cellColourPtr_.valid())// && colourBufs_.set(colouri))
|
||||
{
|
||||
for (const label inti : lowerGlobalRecv_[colouri])
|
||||
{
|
||||
addInterface(wA, inti, colourBufs_[colouri][inti]);
|
||||
}
|
||||
}
|
||||
|
||||
forwardInternal(wA, colouri);
|
||||
|
||||
// Store effect of exchanging rD to higher interfaces
|
||||
// in colourBufs_
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
sendGlobal
|
||||
(
|
||||
higherGlobalSend_[colouri],
|
||||
wA,
|
||||
higherColour_[colouri]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure no outstanding sends from previous iteration
|
||||
wait(higherSendRequests_);
|
||||
|
||||
// Start writes of wA (using sendBufs)
|
||||
send(higherNbrs_, wA, higherSendRequests_);
|
||||
|
||||
|
||||
// Backward sweep
|
||||
// ~~~~~~~~~~~~~~
|
||||
|
||||
// Make sure no outstanding receives
|
||||
wait(higherRecvRequests_);
|
||||
|
||||
// Start receives
|
||||
receive(higherNbrs_, higherRecvRequests_);
|
||||
|
||||
{
|
||||
// Wait until receives finished
|
||||
wait(higherRecvRequests_);
|
||||
|
||||
for (const label inti : higherNbrs_)
|
||||
{
|
||||
addInterface(wA, inti, recvBufs_[inti]);
|
||||
}
|
||||
|
||||
for (label colouri = nColours_-1; colouri >= 0; colouri--)
|
||||
{
|
||||
// Do non-processor boundaries for this colour
|
||||
if (cellColourPtr_.valid())// && colourBufs_.set(colouri))
|
||||
{
|
||||
for (const label inti : higherGlobalRecv_[colouri])
|
||||
{
|
||||
addInterface(wA, inti, colourBufs_[colouri][inti]);
|
||||
}
|
||||
}
|
||||
|
||||
backwardInternal(wA, colouri);
|
||||
|
||||
// Store effect of exchanging rD to higher interfaces
|
||||
// in colourBufs_
|
||||
if (cellColourPtr_.valid())
|
||||
{
|
||||
sendGlobal
|
||||
(
|
||||
lowerGlobalSend_[colouri],
|
||||
wA,
|
||||
lowerColour_[colouri]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure no outstanding sends
|
||||
wait(lowerSendRequests_);
|
||||
|
||||
// Start writes of wA (using sendBufs)
|
||||
send(lowerNbrs_, wA, lowerSendRequests_);
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,274 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::distributedDILUPreconditioner
|
||||
|
||||
Group
|
||||
grpLduMatrixPreconditioners
|
||||
|
||||
Description
|
||||
Version of DILUpreconditioner that uses preconditioning across processor
|
||||
(and coupled) boundaries. Based on 'Parallel Preconditioners' chapter from
|
||||
'Iterative Methods for Sparse Linear Systems' by Yousef Saad.
|
||||
|
||||
Leaves out the handling of boundary nodes after internal nodes since
|
||||
probably not beneficial (so no overlap of comms and internal calculation)
|
||||
|
||||
By default preconditions across coupled boundaries (currently only
|
||||
tested for cyclicAMI). This can be disabled with the 'coupled' setting
|
||||
|
||||
solver PCG;
|
||||
preconditioner
|
||||
{
|
||||
preconditioner distributedDILU;
|
||||
coupled false;
|
||||
}
|
||||
|
||||
The cyclicAMI boundary behaviour will only work if
|
||||
- running non-parallel or
|
||||
- different sides of cyclicAMI run on different processors i.e.
|
||||
there is no processor which has cells on both owner and neighbour
|
||||
of the patch pair.
|
||||
|
||||
See Also
|
||||
Foam::DILUPreconditioner
|
||||
Foam::distributedDICPreconditioner
|
||||
|
||||
SourceFiles
|
||||
distributedDILUPreconditioner.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef distributedDILUPreconditioner_H
|
||||
#define distributedDILUPreconditioner_H
|
||||
|
||||
#include "lduMatrix.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class distributedDILUPreconditioner Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class distributedDILUPreconditioner
|
||||
:
|
||||
public lduMatrix::preconditioner
|
||||
{
|
||||
protected:
|
||||
|
||||
// Protected data
|
||||
|
||||
//- Precondition across global coupled bc
|
||||
const bool coupled_;
|
||||
|
||||
|
||||
//- Processor interface buffers and colouring
|
||||
|
||||
//- Previous mesh
|
||||
static const lduMesh* meshPtr_;
|
||||
|
||||
//- Previous processor colours
|
||||
static autoPtr<labelList> procColoursPtr_;
|
||||
|
||||
//- Buffers for sending and receiving data
|
||||
mutable FieldField<Field, solveScalar> sendBufs_;
|
||||
mutable FieldField<Field, solveScalar> recvBufs_;
|
||||
mutable DynamicList<UPstream::Request> recvRequests_;
|
||||
|
||||
//- Interfaces to lower coloured processors
|
||||
DynamicList<label> lowerNbrs_;
|
||||
mutable DynamicList<UPstream::Request> lowerSendRequests_;
|
||||
mutable DynamicList<UPstream::Request> lowerRecvRequests_;
|
||||
|
||||
//- Interfaces to higher coloured processors
|
||||
DynamicList<label> higherNbrs_;
|
||||
mutable DynamicList<UPstream::Request> higherSendRequests_;
|
||||
mutable DynamicList<UPstream::Request> higherRecvRequests_;
|
||||
|
||||
|
||||
//- Local (cell) colouring from global interfaces
|
||||
|
||||
//- Colour/zone per cell
|
||||
autoPtr<labelList> cellColourPtr_;
|
||||
|
||||
//- Number of colours (in case of multiple disconnected regions
|
||||
// in single mesh)
|
||||
label nColours_;
|
||||
|
||||
|
||||
//- Global interfaces. Per colour the interfaces that (might)
|
||||
//- influence it
|
||||
|
||||
mutable PtrList<FieldField<Field, solveScalar>> colourBufs_;
|
||||
|
||||
//- Interfaces to non-processor lower coupled interfaces
|
||||
List<DynamicList<label>> lowerGlobalRecv_;
|
||||
|
||||
//- Interfaces to non-processor lower coupled interfaces
|
||||
List<DynamicList<label>> lowerGlobalSend_;
|
||||
|
||||
//- Corresponding destination colour (for lowerGlobal)
|
||||
List<label> lowerColour_;
|
||||
|
||||
//- Interfaces to non-processor higher coupled interfaces
|
||||
List<DynamicList<label>> higherGlobalRecv_;
|
||||
|
||||
//- Interfaces to non-processor higher coupled interfaces
|
||||
List<DynamicList<label>> higherGlobalSend_;
|
||||
|
||||
//- Corresponding destination colour (for higherGlobal)
|
||||
List<label> higherColour_;
|
||||
|
||||
|
||||
//- The reciprocal preconditioned diagonal
|
||||
solveScalarField rD_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Variant of lduMatrix::updateMatrixInterfaces on selected interfaces
|
||||
void updateMatrixInterfaces
|
||||
(
|
||||
const bool add,
|
||||
const FieldField<Field, solveScalar>& coupleCoeffs,
|
||||
const labelList& selectedInterfaces,
|
||||
const solveScalarField& psiif,
|
||||
solveScalarField& result,
|
||||
const direction cmpt
|
||||
) const;
|
||||
|
||||
//- Send (and store in colourBufs_[colouri]) the effect of
|
||||
// doing selectedInterfaces
|
||||
void sendGlobal
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
solveScalarField& psi,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
//- Start receiving in recvBufs_
|
||||
void receive
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
DynamicList<UPstream::Request>& requests
|
||||
) const;
|
||||
|
||||
//- Start sending sendBufs_
|
||||
void send
|
||||
(
|
||||
const labelList& selectedInterfaces,
|
||||
const solveScalarField& psiInternal,
|
||||
DynamicList<UPstream::Request>& requests
|
||||
) const;
|
||||
|
||||
//- Wait for explicit requests
|
||||
void wait(DynamicList<UPstream::Request>& requests) const;
|
||||
|
||||
//- Update diagonal for interface
|
||||
virtual void addInterfaceDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label inti,
|
||||
const Field<solveScalar>& recvBuf
|
||||
) const;
|
||||
|
||||
//- Update diagonal for all faces of a certain colour
|
||||
virtual void forwardInternalDiag
|
||||
(
|
||||
solveScalarField& rD,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
//- Update preconditioned variable from interface
|
||||
virtual void addInterface
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label inti,
|
||||
const Field<solveScalar>& recvBuf
|
||||
) const;
|
||||
|
||||
//- Update preconditioned variable walking forward on internal faces
|
||||
virtual void forwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
//- Update preconditioned variable walking backward on internal faces
|
||||
virtual void backwardInternal
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const label colouri
|
||||
) const;
|
||||
|
||||
//- Calculate reciprocal of diagonal
|
||||
virtual void calcReciprocalD(solveScalarField& rD) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("distributedDILU");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from matrix components and preconditioner solver controls
|
||||
distributedDILUPreconditioner
|
||||
(
|
||||
const lduMatrix::solver&,
|
||||
const dictionary& solverControlsUnused
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~distributedDILUPreconditioner();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Return wA the preconditioned form of residual rA
|
||||
virtual void precondition
|
||||
(
|
||||
solveScalarField& wA,
|
||||
const solveScalarField& rA,
|
||||
const direction cmpt=0
|
||||
) const;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,363 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 M. Janssens
|
||||
-------------------------------------------------------------------------------
|
||||
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/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "processorColour.H"
|
||||
#include "processorLduInterface.H"
|
||||
#include "processorTopologyNew.H"
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(processorColour, 0);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::label Foam::processorColour::colour
|
||||
(
|
||||
const lduMesh& mesh,
|
||||
labelList& procColour
|
||||
)
|
||||
{
|
||||
procColour.resize_nocopy(Pstream::nProcs(mesh.comm()));
|
||||
procColour = -1;
|
||||
|
||||
// Re-use processor-topology analysis
|
||||
|
||||
labelListList procNeighbours(Pstream::nProcs(mesh.comm()));
|
||||
|
||||
// Fill my entry
|
||||
{
|
||||
const lduInterfacePtrsList patches = mesh.interfaces();
|
||||
|
||||
auto& procToProcs = procNeighbours[Pstream::myProcNo(mesh.comm())];
|
||||
label n = 0;
|
||||
forAll(patches, patchi)
|
||||
{
|
||||
if (patches.set(patchi))
|
||||
{
|
||||
if (isA<processorLduInterface>(patches[patchi]))
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
procToProcs.resize_nocopy(n);
|
||||
n = 0;
|
||||
forAll(patches, patchi)
|
||||
{
|
||||
if (patches.set(patchi))
|
||||
{
|
||||
const auto* ppPtr = isA<processorLduInterface>(patches[patchi]);
|
||||
if (ppPtr)
|
||||
{
|
||||
procToProcs[n++] = ppPtr->neighbProcNo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send to master
|
||||
Pstream::gatherList(procNeighbours, UPstream::msgType(), mesh.comm());
|
||||
|
||||
|
||||
// Use greedy algorithm for now
|
||||
// (see e.g. https://iq.opengenus.org/graph-colouring-greedy-algorithm/)
|
||||
|
||||
if (Pstream::master(mesh.comm()))
|
||||
{
|
||||
DynamicList<label> front;
|
||||
front.append(0); // start from processor 0
|
||||
|
||||
DynamicList<label> newFront;
|
||||
while (front.size())
|
||||
{
|
||||
//Pout<< "Front:" << front << endl;
|
||||
|
||||
newFront.clear();
|
||||
for (const label proci : front)
|
||||
{
|
||||
if (procColour[proci] == -1)
|
||||
{
|
||||
const labelList& nbrs = procNeighbours[proci];
|
||||
const UIndirectList<label> nbrColour(procColour, nbrs);
|
||||
|
||||
for
|
||||
(
|
||||
label colouri = 0;
|
||||
colouri < Pstream::nProcs();
|
||||
colouri++
|
||||
)
|
||||
{
|
||||
if (!nbrColour.found(colouri))
|
||||
{
|
||||
procColour[proci] = colouri;
|
||||
for (label nbrProci : nbrs)
|
||||
{
|
||||
if (procColour[nbrProci] == -1)
|
||||
{
|
||||
newFront.append(nbrProci);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
front = std::move(newFront);
|
||||
}
|
||||
}
|
||||
|
||||
Pstream::broadcast(procColour, mesh.comm());
|
||||
|
||||
|
||||
//if (false)
|
||||
//{
|
||||
// volScalarField volColour
|
||||
// (
|
||||
// IOobject
|
||||
// (
|
||||
// "colour",
|
||||
// mesh.time().timeName(),
|
||||
// mesh,
|
||||
// IOobject::NO_READ,
|
||||
// IOobject::AUTO_WRITE,
|
||||
// false
|
||||
// ),
|
||||
// mesh,
|
||||
// dimensionedScalar(dimless, procColour[Pstream::myProcNo()]),
|
||||
// zeroGradientFvPatchScalarField::typeName
|
||||
// );
|
||||
// volColour.write();
|
||||
//}
|
||||
|
||||
const label nColours = max(procColour)+1;
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName << " : coloured " << Pstream::nProcs(mesh.comm())
|
||||
<< " processors with in total " << nColours << " colours" << endl;
|
||||
}
|
||||
|
||||
return nColours;
|
||||
}
|
||||
|
||||
|
||||
void Foam::processorColour::walkFront
|
||||
(
|
||||
const lduMesh& mesh,
|
||||
DynamicList<label>& front,
|
||||
labelList& cellColour
|
||||
)
|
||||
{
|
||||
// Colour with the (min) coupled (global) patch
|
||||
|
||||
const lduAddressing& addr = mesh.lduAddr();
|
||||
const label* const __restrict__ uPtr = addr.upperAddr().begin();
|
||||
const label* const __restrict__ lPtr = addr.lowerAddr().begin();
|
||||
const label* const __restrict__ ownStartPtr = addr.ownerStartAddr().begin();
|
||||
const label* const __restrict__ losortStartAddrPtr =
|
||||
addr.losortStartAddr().begin();
|
||||
const label* const __restrict__ losortAddrPtr = addr.losortAddr().begin();
|
||||
|
||||
DynamicList<label> newFront;
|
||||
while (true)
|
||||
{
|
||||
newFront.clear();
|
||||
for (const label celli : front)
|
||||
{
|
||||
const label colouri = cellColour[celli];
|
||||
|
||||
{
|
||||
const label fStart = ownStartPtr[celli];
|
||||
const label fEnd = ownStartPtr[celli + 1];
|
||||
|
||||
for (label facei=fStart; facei<fEnd; facei++)
|
||||
{
|
||||
const label nbr =
|
||||
(
|
||||
lPtr[facei] == celli
|
||||
? uPtr[facei]
|
||||
: lPtr[facei]
|
||||
);
|
||||
if (cellColour[nbr] == -1)
|
||||
{
|
||||
cellColour[nbr] = colouri;
|
||||
newFront.append(nbr);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const label fStart = losortStartAddrPtr[celli];
|
||||
const label fEnd = losortStartAddrPtr[celli + 1];
|
||||
|
||||
for (label i=fStart; i<fEnd; i++)
|
||||
{
|
||||
label facei = losortAddrPtr[i];
|
||||
const label nbr =
|
||||
(
|
||||
lPtr[facei] == celli
|
||||
? uPtr[facei]
|
||||
: lPtr[facei]
|
||||
);
|
||||
if (cellColour[nbr] == -1)
|
||||
{
|
||||
cellColour[nbr] = colouri;
|
||||
newFront.append(nbr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (newFront.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
front.transfer(newFront);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::processorColour::cellColour
|
||||
(
|
||||
const lduMesh& mesh,
|
||||
labelList& cellColour,
|
||||
labelList& patchToColour
|
||||
)
|
||||
{
|
||||
// Colour with the (min) coupled (global) patch. Compact to have colour 0
|
||||
// if a single region. Problematic if same patch on multiple disconnected
|
||||
// regions.
|
||||
|
||||
const lduAddressing& addr = mesh.lduAddr();
|
||||
const lduInterfacePtrsList patches = mesh.interfaces();
|
||||
|
||||
const label nCells = addr.size();
|
||||
|
||||
patchToColour.resize_nocopy(patches.size());
|
||||
patchToColour = -1;
|
||||
cellColour.resize_nocopy(nCells);
|
||||
cellColour = -1;
|
||||
|
||||
|
||||
label colouri = 0;
|
||||
|
||||
// Starting front from patch faceCells
|
||||
DynamicList<label> front;
|
||||
forAll(patches, inti)
|
||||
{
|
||||
if
|
||||
(
|
||||
patches.set(inti)
|
||||
&& !isA<const processorLduInterface>(patches[inti])
|
||||
)
|
||||
{
|
||||
// 'global' interface. Seed faceCells with patch index
|
||||
|
||||
if (patchToColour[inti] == -1)
|
||||
{
|
||||
patchToColour[inti] = colouri++;
|
||||
}
|
||||
|
||||
const auto& fc = patches[inti].faceCells();
|
||||
forAll(fc, face)
|
||||
{
|
||||
const label cell = fc[face];
|
||||
if (cellColour[cell] != patchToColour[inti])
|
||||
{
|
||||
cellColour[cell] = patchToColour[inti];
|
||||
front.append(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Walk current mesh
|
||||
walkFront(mesh, front, cellColour);
|
||||
|
||||
|
||||
// Any unvisited cell is still labelMax. Put into colour 0.
|
||||
for (auto& colour : cellColour)
|
||||
{
|
||||
if (colour == -1)
|
||||
{
|
||||
colour = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< typeName << " : coloured " << nCells
|
||||
<< " cells with in total " << colouri << " colours" << endl;
|
||||
}
|
||||
|
||||
return colouri;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::processorColour::processorColour(const lduMesh& mesh)
|
||||
:
|
||||
MeshObject<lduMesh, Foam::MoveableMeshObject, processorColour>(mesh)
|
||||
{
|
||||
nColours_ = colour(mesh, *this);
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::processorColour& Foam::processorColour::New(const lduMesh& mesh)
|
||||
{
|
||||
const processorColour* ptr =
|
||||
mesh.thisDb().objectRegistry::template cfindObject<processorColour>
|
||||
(
|
||||
processorColour::typeName
|
||||
);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
processorColour* objectPtr = new processorColour(mesh);
|
||||
|
||||
//regIOobject::store(static_cast<MoveableMeshObject<lduMesh>*>(objectPtr));
|
||||
regIOobject::store(objectPtr);
|
||||
|
||||
return *objectPtr;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -0,0 +1,156 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2022 M. Janssens
|
||||
-------------------------------------------------------------------------------
|
||||
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/>.
|
||||
|
||||
Class
|
||||
Foam::processorColour
|
||||
|
||||
Description
|
||||
Colouring processors such that no neighbours have the same colour
|
||||
|
||||
SourceFiles
|
||||
processorColour.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef Foam_processorColour_H
|
||||
#define Foam_processorColour_H
|
||||
|
||||
#include "MeshObject.H"
|
||||
#include "lduMesh.H"
|
||||
#include "lduInterfacePtrsList.H"
|
||||
#include "primitiveFields.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
class lduMatrix;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class processorColour Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class processorColour
|
||||
:
|
||||
public MeshObject<lduMesh, MoveableMeshObject, processorColour>,
|
||||
public labelList
|
||||
{
|
||||
protected:
|
||||
|
||||
// Protected data
|
||||
|
||||
//- Max number of colours
|
||||
label nColours_;
|
||||
|
||||
|
||||
// Protected Member Fucntions
|
||||
|
||||
static void walkFront
|
||||
(
|
||||
const lduMesh& mesh,
|
||||
DynamicList<label>& front,
|
||||
labelList& cellColour
|
||||
);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
//- No copy construct
|
||||
processorColour(const processorColour&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const processorColour&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("processorColour");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct given mesh
|
||||
processorColour(const lduMesh& mesh);
|
||||
|
||||
|
||||
// Selectors
|
||||
|
||||
//- Should use the MeshObject provided one but that needs a
|
||||
// mesh.name() ...
|
||||
static const processorColour& New(const lduMesh& mesh);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~processorColour() = default;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Access
|
||||
|
||||
label nColours() const
|
||||
{
|
||||
return nColours_;
|
||||
}
|
||||
|
||||
label myColour() const
|
||||
{
|
||||
return operator[](Pstream::myProcNo());
|
||||
}
|
||||
|
||||
|
||||
//- Calculate processor colouring from processor connectivity. Sets
|
||||
//- colour per processor such that no neighbouring processors have the
|
||||
//- same colour. Returns number of colours used.
|
||||
static label colour(const lduMesh& mesh, labelList& procColour);
|
||||
|
||||
//- Calculate (locally) per cell colour according to walking from
|
||||
//- global patches. Returns number of colours used.
|
||||
//- Note: asssumes all non-processor interfaces are global.
|
||||
static label cellColour
|
||||
(
|
||||
const lduMesh& mesh,
|
||||
labelList& cellColour,
|
||||
labelList& patchToColour
|
||||
);
|
||||
|
||||
virtual bool movePoints()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user