Merge branch 'ami-cache-weights-addressing' into 'develop'

Draft: AMI - added caching of weights and addressing

See merge request Development/openfoam!744
This commit is contained in:
Andrew Heather
2025-10-27 19:05:33 +00:00
48 changed files with 3361 additions and 450 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd. Copyright (C) 2016-2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -189,6 +189,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const deltaData&, TrackingData& td) const; inline bool equal(const deltaData&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const deltaData& f0,
const label i1,
const deltaData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators
@ -296,6 +313,17 @@ public:
template<> template<>
struct is_contiguous<LESModels::smoothDelta::deltaData> : std::true_type {}; struct is_contiguous<LESModels::smoothDelta::deltaData> : std::true_type {};
//- Interpolation - used in e.g. cyclicAMI interpolation
inline LESModels::smoothDelta::deltaData lerp
(
const LESModels::smoothDelta::deltaData& a,
const LESModels::smoothDelta::deltaData& b,
const scalar t
)
{
return LESModels::smoothDelta::deltaData(lerp(a.delta(), b.delta(), t));
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd. Copyright (C) 2019,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,6 +191,40 @@ inline bool Foam::LESModels::smoothDelta::deltaData::equal
} }
template<class TrackingData>
inline bool Foam::LESModels::smoothDelta::deltaData::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const deltaData& f0,
const label i1,
const deltaData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td) && f1.valid(td))
{
const deltaData w2(lerp(f0.delta(), f1.delta(), weight));
return update(w2, 1.0, tol, td);
}
else if (f0.valid(td))
{
return update(f0, 1.0, tol, td);
}
else if (f1.valid(td))
{
return update(f1, 1.0, tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::LESModels::smoothDelta::deltaData::operator== inline bool Foam::LESModels::smoothDelta::deltaData::operator==

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -242,6 +242,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const directionInfo&, TrackingData& td) const; inline bool equal(const directionInfo&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const directionInfo& f0,
const label i1,
const directionInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -287,6 +287,35 @@ inline bool Foam::directionInfo::equal
} }
template<class TrackingData>
inline bool Foam::directionInfo::interpolate
(
const polyMesh& mesh,
const point& pt,
const label i0,
const directionInfo& f0,
const label i1,
const directionInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return updateFace(mesh, -1, f0, tol, td);
}
if (f1.valid(td))
{
return updateFace(mesh, -1, f1, tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::directionInfo::operator== inline bool Foam::directionInfo::operator==

View File

@ -186,6 +186,23 @@ public:
TrackingData& td TrackingData& td
); );
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallNormalInfo& f0,
const label i1,
const wallNormalInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
//- Test for equality, with TrackingData //- Test for equality, with TrackingData
template<class TrackingData> template<class TrackingData>
inline bool equal(const wallNormalInfo&, TrackingData& td) const; inline bool equal(const wallNormalInfo&, TrackingData& td) const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,6 +191,35 @@ inline bool Foam::wallNormalInfo::equal
} }
template<class TrackingData>
inline bool Foam::wallNormalInfo::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallNormalInfo& f0,
const label i1,
const wallNormalInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return update(f0, td);
}
if (f1.valid(td))
{
return update(f1, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::wallNormalInfo::operator== inline bool Foam::wallNormalInfo::operator==

View File

@ -197,6 +197,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const refinementData&, TrackingData& td) const; inline bool equal(const refinementData&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const refinementData& f0,
const label i1,
const refinementData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -248,6 +248,35 @@ inline bool Foam::refinementData::equal
} }
template<class TrackingData>
inline bool Foam::refinementData::interpolate
(
const polyMesh& mesh,
const point& pt,
const label i0,
const refinementData& f0,
const label i1,
const refinementData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return updateFace(mesh, -1, f0, tol, td);
}
if (f1.valid(td))
{
return updateFace(mesh, -1, f1, tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::refinementData::operator== inline bool Foam::refinementData::operator==

View File

@ -229,6 +229,23 @@ public:
inline bool equal(const refinementDistanceData&, TrackingData&) inline bool equal(const refinementDistanceData&, TrackingData&)
const; const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const refinementDistanceData& f0,
const label i1,
const refinementDistanceData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -278,6 +278,35 @@ inline bool Foam::refinementDistanceData::equal
} }
template<class TrackingData>
inline bool Foam::refinementDistanceData::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const refinementDistanceData& f0,
const label i1,
const refinementDistanceData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return update(pt, f0, tol, td);
}
if (f1.valid(td))
{
return update(pt, f1, tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::refinementDistanceData::operator== inline bool Foam::refinementDistanceData::operator==

View File

@ -227,9 +227,15 @@ bool Foam::cyclicACMIFvPatchField<Type>::all_ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
++done; ++done;
} }
@ -240,9 +246,15 @@ bool Foam::cyclicACMIFvPatchField<Type>::all_ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
++done; ++done;
} }
@ -260,9 +272,15 @@ bool Foam::cyclicACMIFvPatchField<Type>::ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if if
( (
@ -271,9 +289,15 @@ bool Foam::cyclicACMIFvPatchField<Type>::ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
} }
return true; return true;
@ -483,7 +507,7 @@ void Foam::cyclicACMIFvPatchField<Type>::initEvaluate
const Field<Type> pnf(this->primitiveField(), nbrFaceCells); const Field<Type> pnf(this->primitiveField(), nbrFaceCells);
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -494,14 +518,20 @@ void Foam::cyclicACMIFvPatchField<Type>::initEvaluate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cyclicACMIPatch_.initInterpolate cyclicACMIPatch_.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
sendBufs_,
recvRequests_, recvRequests_,
recvBufs_ sendBufs_,
recvBufs_,
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
} }
@ -547,12 +577,15 @@ void Foam::cyclicACMIFvPatchField<Type>::evaluate
( (
Field<Type>::null(), // Not used for distributed Field<Type>::null(), // Not used for distributed
recvRequests_, recvRequests_,
recvBufs_ recvBufs_,
recvRequests1_,
recvBufs1_
).ptr() ).ptr()
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if (doTransform()) if (doTransform())
{ {
@ -608,7 +641,7 @@ void Foam::cyclicACMIFvPatchField<Type>::initInterfaceMatrixUpdate
transformCoupleField(pnf, cmpt); transformCoupleField(pnf, cmpt);
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -619,14 +652,20 @@ void Foam::cyclicACMIFvPatchField<Type>::initInterfaceMatrixUpdate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cyclicACMIPatch_.initInterpolate cyclicACMIPatch_.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
scalarSendBufs_,
recvRequests_, recvRequests_,
scalarRecvBufs_ scalarSendBufs_,
scalarRecvBufs_,
sendRequests1_,
recvRequests1_,
scalarSendBufs1_,
scalarRecvBufs1_
); );
} }
@ -681,11 +720,14 @@ void Foam::cyclicACMIFvPatchField<Type>::updateInterfaceMatrix
( (
solveScalarField::null(), // Not used for distributed solveScalarField::null(), // Not used for distributed
recvRequests_, recvRequests_,
scalarRecvBufs_ scalarRecvBufs_,
recvRequests1_,
scalarRecvBufs1_
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
} }
else else
{ {
@ -738,7 +780,7 @@ void Foam::cyclicACMIFvPatchField<Type>::initInterfaceMatrixUpdate
transformCoupleField(pnf); transformCoupleField(pnf);
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -749,14 +791,20 @@ void Foam::cyclicACMIFvPatchField<Type>::initInterfaceMatrixUpdate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cyclicACMIPatch_.initInterpolate cyclicACMIPatch_.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
sendBufs_,
recvRequests_, recvRequests_,
recvBufs_ sendBufs_,
recvBufs_,
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
@ -798,11 +846,14 @@ void Foam::cyclicACMIFvPatchField<Type>::updateInterfaceMatrix
( (
Field<Type>::null(), // Not used for distributed Field<Type>::null(), // Not used for distributed
recvRequests_, recvRequests_,
recvBufs_ recvBufs_,
recvRequests1_,
recvBufs1_
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
} }
else else
{ {

View File

@ -102,6 +102,28 @@ class cyclicACMIFvPatchField
//- Scalar receive buffers //- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs_; mutable PtrList<List<solveScalar>> scalarRecvBufs_;
// Only used for AMI caching
//- Current range of send requests (non-blocking)
mutable labelRange sendRequests1_;
//- Current range of recv requests (non-blocking)
mutable labelRange recvRequests1_;
//- Send buffers
mutable PtrList<List<Type>> sendBufs1_;
//- Receive buffers_
mutable PtrList<List<Type>> recvBufs1_;
//- Scalar send buffers
mutable PtrList<List<solveScalar>> scalarSendBufs1_;
//- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs1_;
//- Neighbour coupled internal cell data //- Neighbour coupled internal cell data
mutable autoPtr<Field<Type>> patchNeighbourFieldPtr_; mutable autoPtr<Field<Type>> patchNeighbourFieldPtr_;

View File

@ -207,9 +207,15 @@ bool Foam::cyclicAMIFvPatchField<Type>::all_ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
++done; ++done;
} }
@ -220,9 +226,15 @@ bool Foam::cyclicAMIFvPatchField<Type>::all_ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
++done; ++done;
} }
@ -240,9 +252,15 @@ bool Foam::cyclicAMIFvPatchField<Type>::ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if if
( (
@ -251,9 +269,15 @@ bool Foam::cyclicAMIFvPatchField<Type>::ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
} }
return true; return true;
@ -319,10 +343,19 @@ Foam::cyclicAMIFvPatchField<Type>::getNeighbourField
template<class Type> template<class Type>
bool Foam::cyclicAMIFvPatchField<Type>::cacheNeighbourField() bool Foam::cyclicAMIFvPatchField<Type>::cacheNeighbourField() const
{
// const auto& AMI = this->ownerAMI();
// if (AMI.cacheActive())
// {
// return false;
// }
// else
{ {
return (FieldBase::localBoundaryConsistency() != 0); return (FieldBase::localBoundaryConsistency() != 0);
} }
}
template<class Type> template<class Type>
@ -350,11 +383,12 @@ Foam::cyclicAMIFvPatchField<Type>::getPatchNeighbourField
} }
const auto& fvp = this->patch(); const auto& fvp = this->patch();
const auto& mesh = fvp.boundaryMesh().mesh();
if if
( (
patchNeighbourFieldPtr_ patchNeighbourFieldPtr_
&& !fvp.boundaryMesh().mesh().upToDatePoints(this->internalField()) && !mesh.upToDatePoints(this->internalField())
) )
{ {
//DebugPout //DebugPout
@ -418,7 +452,8 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::cyclicAMIFvPatchField<Type>::patchNeighbourField() const Foam::cyclicAMIFvPatchField<Type>::patchNeighbourField() const
{ {
return this->getPatchNeighbourField(true); // checkCommunicator = true // checkCommunicator = true
return this->getPatchNeighbourField(true);
} }
@ -491,7 +526,7 @@ void Foam::cyclicAMIFvPatchField<Type>::initEvaluate
const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch(); const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -502,14 +537,20 @@ void Foam::cyclicAMIFvPatchField<Type>::initEvaluate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cpp.initInterpolate cpp.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
sendBufs_,
recvRequests_, recvRequests_,
recvBufs_ sendBufs_,
recvBufs_,
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
} }
@ -562,12 +603,15 @@ void Foam::cyclicAMIFvPatchField<Type>::evaluate
Field<Type>::null(), // Not used for distributed Field<Type>::null(), // Not used for distributed
recvRequests_, recvRequests_,
recvBufs_, recvBufs_,
recvRequests1_,
recvBufs1_,
defaultValues defaultValues
).ptr() ).ptr()
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if (doTransform()) if (doTransform())
{ {
@ -618,7 +662,7 @@ void Foam::cyclicAMIFvPatchField<Type>::initInterfaceMatrixUpdate
const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch(); const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -629,14 +673,20 @@ void Foam::cyclicAMIFvPatchField<Type>::initInterfaceMatrixUpdate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cpp.initInterpolate cpp.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
scalarSendBufs_,
recvRequests_, recvRequests_,
scalarRecvBufs_ scalarSendBufs_,
scalarRecvBufs_,
sendRequests1_,
recvRequests1_,
scalarSendBufs1_,
scalarRecvBufs1_
); );
} }
@ -691,11 +741,14 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
solveScalarField::null(), // Not used for distributed solveScalarField::null(), // Not used for distributed
recvRequests_, recvRequests_,
scalarRecvBufs_, scalarRecvBufs_,
recvRequests1_,
scalarRecvBufs1_,
defaultValues defaultValues
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
} }
else else
{ {
@ -757,7 +810,7 @@ void Foam::cyclicAMIFvPatchField<Type>::initInterfaceMatrixUpdate
const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch(); const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -768,14 +821,20 @@ void Foam::cyclicAMIFvPatchField<Type>::initInterfaceMatrixUpdate
// Assume that sends are also OK // Assume that sends are also OK
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
cpp.initInterpolate cpp.initInterpolate
( (
pnf, pnf,
sendRequests_, sendRequests_,
sendBufs_,
recvRequests_, recvRequests_,
recvBufs_ sendBufs_,
recvBufs_,
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
@ -829,11 +888,14 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
Field<Type>::null(), // Not used for distributed Field<Type>::null(), // Not used for distributed
recvRequests_, recvRequests_,
recvBufs_, recvBufs_,
recvRequests1_,
recvBufs1_,
defaultValues defaultValues
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
} }
else else
{ {
@ -918,7 +980,7 @@ void Foam::cyclicAMIFvPatchField<Type>::manipulateMatrix
} }
// Set internalCoeffs and boundaryCoeffs in the assembly matrix // Set internalCoeffs and boundaryCoeffs in the assembly matrix
// on clyclicAMI patches to be used in the individual matrix by // on cyclicAMI patches to be used in the individual matrix by
// matrix.flux() // matrix.flux()
if (matrix.psi(mat).mesh().fluxRequired(this->internalField().name())) if (matrix.psi(mat).mesh().fluxRequired(this->internalField().name()))
{ {

View File

@ -113,6 +113,28 @@ class cyclicAMIFvPatchField
//- Scalar receive buffers //- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs_; mutable PtrList<List<solveScalar>> scalarRecvBufs_;
// Only used for AMI caching
//- Current range of send requests (non-blocking)
mutable labelRange sendRequests1_;
//- Current range of recv requests (non-blocking)
mutable labelRange recvRequests1_;
//- Send buffers
mutable PtrList<List<Type>> sendBufs1_;
//- Receive buffers_
mutable PtrList<List<Type>> recvBufs1_;
//- Scalar send buffers
mutable PtrList<List<solveScalar>> scalarSendBufs1_;
//- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs1_;
//- Neighbour coupled internal cell data //- Neighbour coupled internal cell data
mutable autoPtr<Field<Type>> patchNeighbourFieldPtr_; mutable autoPtr<Field<Type>> patchNeighbourFieldPtr_;
@ -134,7 +156,7 @@ class cyclicAMIFvPatchField
virtual bool all_ready() const; virtual bool all_ready() const;
//- Use neighbour field caching //- Use neighbour field caching
static bool cacheNeighbourField(); bool cacheNeighbourField() const;
//- Return neighbour coupled internal cell data //- Return neighbour coupled internal cell data
tmp<Field<Type>> getNeighbourField(const UList<Type>&) const; tmp<Field<Type>> getNeighbourField(const UList<Type>&) const;

View File

@ -209,6 +209,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const smoothData&, TrackingData& td) const; inline bool equal(const smoothData&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const smoothData& f0,
const label i1,
const smoothData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,6 +191,45 @@ inline bool Foam::smoothData::equal
} }
template<class TrackingData>
inline bool Foam::smoothData::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const smoothData& f0,
const label i1,
const smoothData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
// TBD. What to interpolate? Do we have a position? cell/face centre?
if (!valid(td))
{
if (f0.valid(td))
{
operator=(f0);
}
else
{
operator=(f1);
}
}
else if (f0.valid(td))
{
operator=(f0);
}
else
{
operator=(f1);
}
return true;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::smoothData::operator== inline bool Foam::smoothData::operator==

View File

@ -207,6 +207,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const sweepData&, TrackingData& td) const; inline bool equal(const sweepData&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const sweepData& f0,
const label i1,
const sweepData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -210,6 +210,45 @@ inline bool Foam::sweepData::equal
} }
template<class TrackingData>
inline bool Foam::sweepData::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const sweepData& f0,
const label i1,
const sweepData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
// TBD. What to interpolate? Do we have a position? cell/face centre?
if (!valid(td))
{
if (f0.valid(td))
{
operator=(f0);
}
else
{
operator=(f1);
}
}
else if (f0.valid(td))
{
operator=(f0);
}
else
{
operator=(f1);
}
return true;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::sweepData::operator== inline bool Foam::sweepData::operator==

View File

@ -220,9 +220,14 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
PtrList<List<Type>>& sendBuffers,
labelRange& recvRequests, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers,
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const ) const
{ {
// Make sure areas are up-to-date // Make sure areas are up-to-date
@ -232,9 +237,14 @@ public:
( (
fld, fld,
sendRequests, sendRequests,
sendBuffers,
recvRequests, recvRequests,
recvBuffers sendBuffers,
recvBuffers,
sendRequests1,
recvRequests1,
sendBuffers1,
recvBuffers1
); );
} }
@ -243,7 +253,9 @@ public:
( (
const Field<Type>& localFld, const Field<Type>& localFld,
const labelRange& requests, // The receive requests const labelRange& requests, // The receive requests
const PtrList<List<Type>>& recvBuffers const PtrList<List<Type>>& recvBuffers,
const labelRange& requests1, // The receive requests
const PtrList<List<Type>>& recvBuffers1
) const ) const
{ {
return cyclicACMIPolyPatch_.interpolate return cyclicACMIPolyPatch_.interpolate
@ -251,6 +263,8 @@ public:
localFld, localFld,
requests, requests,
recvBuffers, recvBuffers,
requests1,
recvBuffers1,
UList<Type>() UList<Type>()
); );
} }

View File

@ -251,6 +251,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const wallPoints&, TrackingData&) const; inline bool equal(const wallPoints&, TrackingData&) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallPoints& f0,
const label i1,
const wallPoints& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2023 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -443,6 +443,41 @@ inline bool Foam::wallPoints::equal
} }
template<class TrackingData>
inline bool Foam::wallPoints::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallPoints& f0,
const label i1,
const wallPoints& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (valid(td))
{
return false;
}
else if (f0.valid(td))
{
operator=(f0);
return true;
}
else if (f1.valid(td))
{
operator=(f1);
return true;
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::wallPoints::operator== inline bool Foam::wallPoints::operator==

View File

@ -0,0 +1,651 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 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 "AMICache.H"
#include "AMIInterpolation.H"
#include "mathematicalConstants.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Foam::scalar Foam::AMICache::cacheThetaTolerance_ = 1e-8;
int Foam::AMICache::debug = 0;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::scalar Foam::AMICache::getRotationAngle(const point& globalPoint) const
{
if (!coordSysPtr_)
{
FatalErrorInFunction
<< "No co-ordinate system available for theta evaluation"
<< abort(FatalError);
}
scalar theta = coordSysPtr_->localPosition(globalPoint).y();
// Ensure 0 < theta < 2pi
if (mag(theta) < cacheThetaTolerance_)
{
theta = 0;
}
else if (theta < 0)
{
theta += constant::mathematical::twoPi;
}
return theta;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::AMICache::AMICache(const dictionary& dict, const bool toSource)
:
size_(dict.getOrDefault<label>("cacheSize", 0)),
rotationAxis_(dict.getOrDefault<vector>("rotationAxis", Zero)),
rotationCentre_(dict.getOrDefault<point>("rotationCentre", Zero)),
maxThetaDeg_(dict.getOrDefault<scalar>("maxThetaDeg", 5)),
complete_(false),
index0_(-1),
index1_(-1),
interpWeight_(0),
coordSysPtr_(nullptr),
theta_(),
cachedSrcAddress_(),
cachedSrcWeights_(),
cachedSrcWeightsSum_(),
cachedSrcMapPtr_(),
cachedTgtAddress_(),
cachedTgtWeights_(),
cachedTgtWeightsSum_(),
cachedTgtMapPtr_(),
toSource_(toSource)
{
if (size_ != 0)
{
theta_.resize(size_, GREAT);
cachedSrcAddress_.resize(size_);
cachedSrcWeights_.resize(size_);
cachedSrcWeightsSum_.resize(size_);
cachedSrcMapPtr_.resize(size_);
cachedTgtAddress_.resize(size_);
cachedTgtWeights_.resize(size_);
cachedTgtWeightsSum_.resize(size_);
cachedTgtMapPtr_.resize(size_);
}
}
Foam::AMICache::AMICache(const bool toSource)
:
size_(0),
rotationAxis_(Zero),
rotationCentre_(Zero),
complete_(false),
index0_(-1),
index1_(-1),
interpWeight_(0),
coordSysPtr_(nullptr),
theta_(),
cachedSrcAddress_(),
cachedSrcWeights_(),
cachedSrcWeightsSum_(),
cachedSrcMapPtr_(),
cachedTgtAddress_(),
cachedTgtWeights_(),
cachedTgtWeightsSum_(),
cachedTgtMapPtr_(),
toSource_(toSource)
{}
Foam::AMICache::AMICache(const AMICache& cache)
:
size_(cache.size_),
rotationAxis_(cache.rotationAxis_),
rotationCentre_(cache.rotationCentre_),
complete_(cache.complete_),
index0_(cache.index0_),
index1_(cache.index1_),
interpWeight_(cache.interpWeight_),
coordSysPtr_(nullptr), // Need to clone as cylindricalCS
theta_(cache.theta_),
cachedSrcAddress_(cache.cachedSrcAddress_),
cachedSrcWeights_(cache.cachedSrcWeights_),
cachedSrcWeightsSum_(cache.cachedSrcWeightsSum_),
cachedSrcMapPtr_(cache.cachedSrcMapPtr_.size()), // Need to clone
cachedTgtAddress_(cache.cachedTgtAddress_),
cachedTgtWeights_(cache.cachedTgtWeights_),
cachedTgtWeightsSum_(cache.cachedTgtWeightsSum_),
cachedTgtMapPtr_(cache.cachedTgtMapPtr_.size()), // Need to clone
toSource_(cache.toSource_)
{
if (cache.coordSysPtr_)
{
coordSysPtr_.reset(new coordSystem::cylindrical(cache.coordSysPtr_()));
}
forAll(cachedSrcMapPtr_, cachei)
{
cachedSrcMapPtr_[cachei].reset(cache.cachedSrcMapPtr_[cachei].clone());
}
forAll(cachedTgtMapPtr_, cachei)
{
cachedTgtMapPtr_[cachei].reset(cache.cachedTgtMapPtr_[cachei].clone());
}
}
Foam::AMICache::AMICache
(
const AMICache& cache,
const AMIInterpolation& fineAMI,
const labelList& sourceRestrictAddressing,
const labelList& targetRestrictAddressing
)
:
size_(cache.size_),
rotationAxis_(cache.rotationAxis_),
rotationCentre_(cache.rotationCentre_),
complete_(cache.complete_),
index0_(cache.index0_),
index1_(cache.index1_),
interpWeight_(cache.interpWeight_),
coordSysPtr_(nullptr),
theta_(cache.theta_),
cachedSrcAddress_(cache.size_),
cachedSrcWeights_(cache.size_),
cachedSrcWeightsSum_(cache.size_),
cachedSrcMapPtr_(cache.size_),
cachedTgtAddress_(cache.size_),
cachedTgtWeights_(cache.size_),
cachedTgtWeightsSum_(cache.size_),
cachedTgtMapPtr_(cache.size_),
toSource_(cache.toSource_)
{
if (size_ > 0 && fineAMI.comm() != -1)
{
for (label cachei : {index0_, index1_})
{
if (cachei == -1) continue;
scalarField dummySrcMagSf;
labelListList srcAddress;
scalarListList srcWeights;
scalarField srcWeightsSum;
autoPtr<mapDistribute> tgtMapPtr;
AMIInterpolation::agglomerate
(
cache.cachedTgtMapPtr()[cachei],
fineAMI.srcMagSf(),
cache.cachedSrcAddress()[cachei],
cache.cachedSrcWeights()[cachei],
sourceRestrictAddressing,
targetRestrictAddressing,
dummySrcMagSf,
srcAddress,
srcWeights,
srcWeightsSum,
tgtMapPtr,
fineAMI.comm()
);
scalarField dummyTgtMagSf;
labelListList tgtAddress;
scalarListList tgtWeights;
scalarField tgtWeightsSum;
autoPtr<mapDistribute> srcMapPtr;
AMIInterpolation::agglomerate
(
cache.cachedSrcMapPtr()[cachei],
fineAMI.tgtMagSf(),
cache.cachedTgtAddress()[cachei],
cache.cachedTgtWeights()[cachei],
targetRestrictAddressing,
sourceRestrictAddressing,
dummyTgtMagSf,
tgtAddress,
tgtWeights,
tgtWeightsSum,
srcMapPtr,
fineAMI.comm()
);
cachedSrcAddress_[cachei] = srcAddress;
cachedSrcWeights_[cachei] = srcWeights;
cachedSrcWeightsSum_[cachei] = srcWeightsSum;
cachedSrcMapPtr_[cachei] = srcMapPtr.clone();
cachedTgtAddress_[cachei] = tgtAddress;
cachedTgtWeights_[cachei] = tgtWeights;
cachedTgtWeightsSum_[cachei] = tgtWeightsSum;
cachedTgtMapPtr_[cachei] = tgtMapPtr.clone();
}
}
}
Foam::AMICache::AMICache(Istream& is)
:
size_(readLabel(is)),
rotationAxis_(is),
rotationCentre_(is),
maxThetaDeg_(readScalar(is)),
complete_(readBool(is)),
index0_(-1),
index1_(-1),
interpWeight_(0),
coordSysPtr_(nullptr),
theta_(),
cachedSrcAddress_(),
cachedSrcWeights_(),
cachedSrcWeightsSum_(),
cachedSrcMapPtr_(),
cachedTgtAddress_(),
cachedTgtWeights_(),
cachedTgtWeightsSum_(),
cachedTgtMapPtr_()
{
const bitSet goodMap(is);
if (goodMap.size())
{
is >> index0_
>> index1_
>> interpWeight_
>> theta_;
const bool goodCoord(readBool(is));
if (goodCoord)
{
coordSysPtr_.reset(new coordSystem::cylindrical(is));
}
is >> cachedSrcAddress_
>> cachedSrcWeights_
>> cachedSrcWeightsSum_;
cachedSrcMapPtr_.setSize(goodMap.size());
forAll(goodMap, cachei)
{
if (goodMap[cachei])
{
cachedSrcMapPtr_[cachei].reset(new mapDistribute(is));
}
}
is >> cachedTgtAddress_
>> cachedTgtWeights_
>> cachedTgtWeightsSum_;
cachedTgtMapPtr_.setSize(goodMap.size());
forAll(goodMap, cachei)
{
if (goodMap[cachei])
{
cachedTgtMapPtr_[cachei].reset(new mapDistribute(is));
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::AMICache::addToCache
(
const AMIInterpolation& ami,
const point& globalPoint
)
{
DebugPout<< "-- addToCache" << endl;
if (!active())
{
DebugInfo<< "-- addToCache - deactivated" << endl;
return;
}
if (!coordSysPtr_)
{
DebugInfo
<< "Creating rotation co-ordinate system:"
<< " rotationCentre:" << rotationCentre_
<< " rotationAxis:" << rotationAxis_
<< " p:" << globalPoint
<< endl;
coordSysPtr_.reset
(
new coordSystem::cylindrical(rotationCentre_, rotationAxis_)
);
DebugPout<< "Coord sys:" << coordSysPtr_() << endl;
}
// Check if cache is complete
if (!complete_)
{
for (const scalar angle : theta_)
{
// Check against null value; if any are present, cache is incomplete
if (angle > constant::mathematical::twoPi)
{
complete_ = false;
break;
}
}
}
if (!complete_)
{
const scalar theta = getRotationAngle(globalPoint);
const label bini = theta/constant::mathematical::twoPi*size_;
DebugPout<< " -- bini:" << bini << " for theta:" << theta << endl;
// Check if already have entry for this bin
if (theta_[bini] > constant::mathematical::twoPi)
{
DebugPout<< " -- setting cache at index " << bini << endl;
// New entry
theta_[bini] = theta;
cachedSrcAddress_[bini] = ami.srcAddress();
cachedSrcWeights_[bini] = ami.srcWeights();
cachedSrcWeightsSum_[bini] = ami.srcWeightsSum();
if (ami.hasSrcMap())
{
cachedSrcMapPtr_[bini] = ami.srcMap().clone();
}
cachedTgtAddress_[bini] = ami.tgtAddress();
cachedTgtWeights_[bini] = ami.tgtWeights();
cachedTgtWeightsSum_[bini] = ami.tgtWeightsSum();
if (ami.hasTgtMap())
{
cachedTgtMapPtr_[bini] = ami.tgtMap().clone();
}
}
}
}
bool Foam::AMICache::restoreCache(const point& globalPoint)
{
DebugPout<< "-- restoreCache" << endl;
index0_ = -1;
index1_ = -1;
interpWeight_ = -1;
if (!coordSysPtr_ || size_ == -1)
{
return false;
}
const scalar theta = getRotationAngle(globalPoint);
const scalar twoPi = constant::mathematical::twoPi;
const label bini = theta/twoPi*size_;
DebugPout<< " -- bini:" << bini << " for theta:" << theta << endl;
const auto validIndex = [&](const scalar bini)
{
return theta_[bini] < constant::mathematical::twoPi;
};
// Maximum angle in degrees for which to search for cached bins
const scalar maxThetaStencil = maxThetaDeg_*constant::mathematical::pi/180.0;
if
(
validIndex(bini)
&& (
mag(theta - theta_[bini]) < cacheThetaTolerance_
|| mag(theta - twoPi - theta_[bini]) < cacheThetaTolerance_
)
)
{
// Hit cached value - no interpolation needed
// index1_ = -1 indicates no interpolation
index0_ = bini;
index1_ = -1;
interpWeight_ = 0;
DebugInfo
<< " -- t0:" << theta_[index0_] << " theta:" << theta
<< " i0:" << index0_ << " i1:" << index1_
<< " w:" << interpWeight_ << endl;
return true;
}
else
{
// Find indices and values bracketing theta
const label nBin = theta_.size();
// Participating theta values and bin addresses
// - Note we add wrap-around values at start and end
DynamicList<scalar> thetap(nBin+2);
DynamicList<label> binAddresses(nBin+2);
// Initialise wrap-around values
thetap.push_back(0);
binAddresses.push_back(-1);
forAll(theta_, thetai)
{
if (validIndex(thetai))
{
thetap.push_back(theta_[thetai]);
binAddresses.push_back(thetai);
}
}
// Check that we have enough data points for interpolation
// - We added storage for lower wrap-around value, and we then need
// at least 2 additional values for the interpolation
if (thetap.size() < 3)
{
DebugPout<< " -- no cache available" << endl;
return false;
}
// Set wrap-around values if we have sufficient data
thetap[0] = thetap.last() - twoPi;
binAddresses[0] = binAddresses.last();
thetap.push_back(thetap[1] + twoPi);
binAddresses.push_back(binAddresses[1]);
// Find interpolation indices
label loweri = labelMax;
label i = 0;
while (i < thetap.size())
{
if (thetap[i] < theta)
{
loweri = i;
}
else
{
break;
}
++i;
}
if (loweri == labelMax)
{
DebugPout<< " -- no cache available" << endl;
return false;
}
label upperi = labelMax;
i = thetap.size() - 1;
while (i >= 0)
{
if (thetap[i] > theta)
{
upperi = i;
}
else
{
break;
}
--i;
}
if (upperi == labelMax)
{
DebugPout<< " -- no cache available" << endl;
return false;
}
// Ensure distances are valid
if (upperi == loweri)
{
DebugPout
<< " -- no cache available: theta:" << theta
<< " lower:" << loweri << " upper:" << upperi << endl;
return false;
}
if (mag(theta - thetap[loweri]) > maxThetaStencil)
{
DebugPout
<< " -- no cache available: theta:" << theta
<< " lower:" << thetap[loweri] << endl;
return false;
}
if (mag(theta - thetap[upperi]) > maxThetaStencil)
{
DebugPout
<< " -- no cache available: theta:" << theta
<< " upper:" << thetap[upperi] << endl;
return false;
}
index0_ = binAddresses[loweri];
index1_ = binAddresses[upperi];
interpWeight_ =
(theta - theta_[index0_])/(theta_[index1_] - theta_[index0_]);
DebugInfo
<< theta_.size()
<< " -- t0:" << theta_[index0_] << " theta:" << theta
<< " t1:" << theta_[index1_]
<< " i0:" << index0_ << " i1:" << index1_
<< " w:" << interpWeight_ << endl;
return true;
}
// If we get here then no valid cache found within stencil
DebugPout<< " -- no cache available" << endl;
return false;
}
void Foam::AMICache::write(Ostream& os) const
{
if (size_ > 0)
{
os.writeEntry("cacheSize", size_);
os.writeEntry("rotationAxis", rotationAxis_);
os.writeEntry("rotationCentre", rotationCentre_);
os.writeEntry("maxThetaDeg", maxThetaDeg_);
}
}
bool Foam::AMICache::writeData(Ostream& os) const
{
os << token::SPACE<< size_
<< token::SPACE<< rotationAxis_
<< token::SPACE<< rotationCentre_
<< token::SPACE<< maxThetaDeg_
<< token::SPACE<< complete_;
bitSet goodMap(cachedSrcMapPtr_.size());
forAll(goodMap, cachei)
{
goodMap.set(cachei, cachedSrcMapPtr_[cachei].good());
}
os << token::SPACE << goodMap;
if (goodMap.size())
{
os << token::SPACE << index0_
<< token::SPACE << index1_
<< token::SPACE << interpWeight_
<< token::SPACE << theta_;
os << token::SPACE << coordSysPtr_.good();
if (coordSysPtr_.good())
{
os << token::SPACE << coordSysPtr_();
}
os << token::SPACE << cachedSrcAddress_
<< token::SPACE << cachedSrcWeights_
<< token::SPACE << cachedSrcWeightsSum_;
for (const auto& index : goodMap)
{
os << token::SPACE << cachedSrcMapPtr_[index]();
}
os << token::SPACE << cachedTgtAddress_
<< token::SPACE << cachedTgtWeights_
<< token::SPACE << cachedTgtWeightsSum_;
for (const auto& index : goodMap)
{
os << token::SPACE << cachedTgtMapPtr_[index]();
}
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,388 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 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::AMICache
Description
Provides caching of weights and addressing to AMIInterpolation
SourceFiles
AMICache.C
SeeAlso
Foam::AMIInterpolation.H
\*---------------------------------------------------------------------------*/
#ifndef Foam_AMICache_H
#define Foam_AMICache_H
#include "cylindricalCS.H"
#include "mapDistribute.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class AMIInterpolation;
/*---------------------------------------------------------------------------*\
Class AMICache Declaration
\*---------------------------------------------------------------------------*/
class AMICache
{
public:
// Public Data Types
//- Tolerance used when caching the AMI to identify e.g. if the
//- current rotation angle has already been captured
static scalar cacheThetaTolerance_;
static int debug;
private:
// Private Data
//- Cache size
label size_;
//- Axis of rotation for rotational cyclics
vector rotationAxis_;
//- Point on axis of rotation for rotational cyclics
point rotationCentre_;
//- Maximum angle in degrees for which to search for cached bins
scalar maxThetaDeg_;
//- Flag to indicate that the cache is complete
bool complete_;
//- Cache index 0 in lists
label index0_;
//- Cache index 1 in lists
label index1_;
//- Interpolation weight between cache indices 0 and 1
scalar interpWeight_;
//- Local co-ordinate system
autoPtr<coordSystem::cylindrical> coordSysPtr_;
//- List of cached angle snapshots
List<scalar> theta_;
//- List of source addresses
List<labelListList> cachedSrcAddress_;
//- List of source weights
List<scalarListList> cachedSrcWeights_;
//- List of source weights sums
List<scalarField> cachedSrcWeightsSum_;
//- List of source parallel maps
List<autoPtr<mapDistribute>> cachedSrcMapPtr_;
//- List of target addresses
List<labelListList> cachedTgtAddress_;
//- List of target weights
List<scalarListList> cachedTgtWeights_;
//- List of target weights sums
List<scalarField> cachedTgtWeightsSum_;
//- List of target parallel maps
List<autoPtr<mapDistribute>> cachedTgtMapPtr_;
//- Flag to indicate interpolation direction
mutable bool toSource_;
// Private Member Functions
//- Get rotation angle for point using local co-ordinate system
scalar getRotationAngle(const point& globalPoint) const;
public:
// Constructors
//- Null constructor
AMICache(const bool toSource = true);
//- Construct from dictionary
AMICache(const dictionary& dict, const bool toSource = true);
//- Construct as copy
AMICache(const AMICache& cache);
//- Construct from agglomeration of AMIInterpolation. Agglomeration
//- passed in as new coarse size and addressing from fine from coarse
AMICache
(
const AMICache& cache,
const AMIInterpolation& fineAMI,
const labelList& sourceRestrictAddressing,
const labelList& targetRestrictAddressing
);
//- Construct from stream
AMICache(Istream& is);
// Member Functions
//- Return true if cache is active
constexpr bool active() const noexcept { return size_ > 0; }
//- Return cache size
constexpr label size() const noexcept { return size_; }
//- Return true if cache is complete
constexpr bool complete() const noexcept { return complete_; }
//- Return cache lower bound index
constexpr label index0() const noexcept { return index0_; }
//- Return cache upper bound index
constexpr label index1() const noexcept { return index1_; }
//- Return cache interpolation weight
constexpr label weight() const noexcept { return interpWeight_; }
//- Return list of cached rotation angles
const List<scalar>& theta() const noexcept { return theta_; }
//- Return List of source addresses
const List<labelListList>& cachedSrcAddress() const noexcept
{
return cachedSrcAddress_;
}
//- Return List of source weights
const List<scalarListList>& cachedSrcWeights() const noexcept
{
return cachedSrcWeights_;
}
//- Return List of source weights sums
const List<scalarField>& cachedSrcWeightsSum() const noexcept
{
return cachedSrcWeightsSum_;
}
//- Return List of source parallel maps
const List<autoPtr<mapDistribute>>& cachedSrcMapPtr() const noexcept
{
return cachedSrcMapPtr_;
}
//- Return List of target addresses
const List<labelListList>& cachedTgtAddress() const noexcept
{
return cachedTgtAddress_;
}
//- Return List of target weights
const List<scalarListList>& cachedTgtWeights() const noexcept
{
return cachedTgtWeights_;
}
//- Return List of target weights sums
const List<scalarField>& cachedTgtWeightsSum() const noexcept
{
return cachedTgtWeightsSum_;
}
//- Return List of target parallel maps
const List<autoPtr<mapDistribute>>& cachedTgtMapPtr() const noexcept
{
return cachedTgtMapPtr_;
}
//- Apply cached evaluation based on user supplied evaluation function
template<class Type, class EvalFunction>
bool apply(List<Type>& result, const EvalFunction& eval) const;
//- Flag that lower bound is applicable
constexpr bool applyLower() const noexcept
{
return index0_ != -1 && index1_ == -1;
}
//- Flag that upper bound is applicable
constexpr bool applyUpper() const noexcept
{
return index0_ == -1 && index1_ != -1;
}
//- Flag that interpolation is applicable
constexpr bool applyInterpolate() const noexcept
{
return index0_ != -1 && index1_ != -1;
}
//- Set the interpolation direction
constexpr bool setDirection(bool toSource) const noexcept
{
toSource_ = toSource;
return toSource_;
}
//- Restore AMI weights and addressing from the cache
bool restoreCache(const point& globalPoint);
//- Add AMI weights and addressing to the cache
void addToCache
(
const AMIInterpolation& ami,
const point& globalPoint
);
//- Check cache index is valid
void checkIndex(const label index) const
{
if ((index < 0) || (index > size_-1))
{
FatalErrorInFunction
<< "Supplied out of bounds: " << index << "/"
<< size_ << abort(FatalError);
}
}
// Helper functions to retrieve cached values at index0 and index1
// Note: uses interpolation direction toSource_
#undef defineMethods01
#define defineMethods01(Src, Tgt, idx) \
const labelListList& c##Src##Address##idx() const \
{ \
checkIndex(index##idx##_); \
return toSource_ ? \
cached##Src##Address_[index##idx##_] \
: cached##Tgt##Address_[index##idx##_]; \
} \
const scalarListList& c##Src##Weights##idx() const \
{ \
checkIndex(index##idx##_); \
return toSource_ ? \
cached##Src##Weights_[index##idx##_] \
: cached##Tgt##Weights_[index##idx##_]; \
} \
const scalarField& c##Src##WeightsSum##idx() const \
{ \
checkIndex(index##idx##_); \
return toSource_ ? \
cached##Src##WeightsSum_[index##idx##_] \
: cached##Tgt##WeightsSum_[index##idx##_]; \
} \
const autoPtr<mapDistribute>& c##Src##MapPtr##idx() const \
{ \
checkIndex(index##idx##_); \
return toSource_ ? \
cached##Src##MapPtr_[index##idx##_] \
: cached##Tgt##MapPtr_[index##idx##_]; \
}
defineMethods01(Src, Tgt, 0)
defineMethods01(Src, Tgt, 1)
defineMethods01(Tgt, Src, 0)
defineMethods01(Tgt, Src, 1)
// Helper functions to retrieve cached values at supplied index
// Note: uses interpolation direction toSource_
#undef defineMethodsIndex
#define defineMethodsIndex(Src, Tgt) \
const labelListList& c##Src##Address(const label index) const \
{ \
checkIndex(index); \
return toSource_ ? \
cached##Src##Address_[index] \
: cached##Tgt##Address_[index]; \
} \
const scalarListList& c##Src##Weights(const label index) const \
{ \
checkIndex(index); \
return toSource_ ? \
cached##Src##Weights_[index] \
: cached##Tgt##Weights_[index]; \
} \
const scalarField& c##Src##WeightsSum(const label index) const \
{ \
checkIndex(index); \
return toSource_ ? \
cached##Src##WeightsSum_[index] \
: cached##Tgt##WeightsSum_[index]; \
} \
const autoPtr<mapDistribute>& c##Src##MapPtr(const label index) \
const \
{ \
checkIndex(index); \
return toSource_ ? \
cached##Src##MapPtr_[index] \
: cached##Tgt##MapPtr_[index]; \
}
defineMethodsIndex(Src, Tgt)
defineMethodsIndex(Tgt, Src)
// I-O
//- Write AMI as a dictionary
void write(Ostream& os) const;
//- Write AMI raw
bool writeData(Ostream& os) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "AMICacheTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,63 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 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/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type, class EvalFunction>
bool Foam::AMICache::apply(List<Type>& result, const EvalFunction& eval) const
{
if (applyLower())
{
eval(result, index0_);
return true;
}
else if (applyUpper())
{
eval(result, index1_);
return true;
}
else if (applyInterpolate())
{
List<Type> r0(result);
eval(r0, index0_);
List<Type> r1(result);
eval(r1, index1_);
//result = (r1 - r0)*interpWeight_ + r0;
forAll(result, i)
{
result[i] = lerp(r0[i], r1[i], interpWeight_);
}
return true;
}
return false;
}
// ************************************************************************* //

View File

@ -61,11 +61,26 @@ registerOptSwitch
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::AMIInterpolation::addToCache(const point& refPt)
{
DebugInfo<< "-- addToCache" << endl;
cache_.addToCache(*this, refPt);
}
bool Foam::AMIInterpolation::restoreCache(const point& refPt)
{
DebugInfo<< "-- restoreCache" << endl;
upToDate_ = cache_.restoreCache(refPt);
return upToDate_;
}
Foam::autoPtr<Foam::indexedOctree<Foam::AMIInterpolation::treeType>> Foam::autoPtr<Foam::indexedOctree<Foam::AMIInterpolation::treeType>>
Foam::AMIInterpolation::createTree Foam::AMIInterpolation::createTree(const primitivePatch &patch) const
(
const primitivePatch& patch
) const
{ {
treeBoundBox bb(patch.points(), patch.meshPoints()); treeBoundBox bb(patch.points(), patch.meshPoints());
bb.inflate(0.01); bb.inflate(0.01);
@ -700,7 +715,8 @@ Foam::AMIInterpolation::AMIInterpolation
tgtWeightsSum_(), tgtWeightsSum_(),
tgtCentroids_(), tgtCentroids_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false) upToDate_(false),
cache_(dict)
{} {}
@ -730,7 +746,8 @@ Foam::AMIInterpolation::AMIInterpolation
tgtCentroids_(), tgtCentroids_(),
tgtPatchPts_(), tgtPatchPts_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false) upToDate_(false),
cache_()
{} {}
@ -743,7 +760,7 @@ Foam::AMIInterpolation::AMIInterpolation
: :
requireMatch_(fineAMI.requireMatch_), requireMatch_(fineAMI.requireMatch_),
reverseTarget_(fineAMI.reverseTarget_), reverseTarget_(fineAMI.reverseTarget_),
lowWeightCorrection_(-1.0), lowWeightCorrection_(-1.0), // Deactivated?
singlePatchProc_(fineAMI.singlePatchProc_), singlePatchProc_(fineAMI.singlePatchProc_),
comm_(fineAMI.comm()), // use fineAMI geomComm if present, comm otherwise comm_(fineAMI.comm()), // use fineAMI geomComm if present, comm otherwise
geomComm_(), geomComm_(),
@ -759,16 +776,17 @@ Foam::AMIInterpolation::AMIInterpolation
tgtWeightsSum_(), tgtWeightsSum_(),
tgtPatchPts_(), tgtPatchPts_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false) upToDate_(false),
cache_(fineAMI.cache(), fineAMI, sourceRestrictAddressing, targetRestrictAddressing)
{ {
label sourceCoarseSize = const label sourceCoarseSize =
( (
sourceRestrictAddressing.size() sourceRestrictAddressing.size()
? max(sourceRestrictAddressing)+1 ? max(sourceRestrictAddressing)+1
: 0 : 0
); );
label neighbourCoarseSize = const label neighbourCoarseSize =
( (
targetRestrictAddressing.size() targetRestrictAddressing.size()
? max(targetRestrictAddressing)+1 ? max(targetRestrictAddressing)+1
@ -895,14 +913,15 @@ Foam::AMIInterpolation::AMIInterpolation(const AMIInterpolation& ami)
srcWeights_(ami.srcWeights_), srcWeights_(ami.srcWeights_),
srcWeightsSum_(ami.srcWeightsSum_), srcWeightsSum_(ami.srcWeightsSum_),
srcCentroids_(ami.srcCentroids_), srcCentroids_(ami.srcCentroids_),
srcMapPtr_(nullptr), srcMapPtr_(ami.srcMapPtr_.clone()),
tgtMagSf_(ami.tgtMagSf_), tgtMagSf_(ami.tgtMagSf_),
tgtAddress_(ami.tgtAddress_), tgtAddress_(ami.tgtAddress_),
tgtWeights_(ami.tgtWeights_), tgtWeights_(ami.tgtWeights_),
tgtWeightsSum_(ami.tgtWeightsSum_), tgtWeightsSum_(ami.tgtWeightsSum_),
tgtCentroids_(ami.tgtCentroids_), tgtCentroids_(ami.tgtCentroids_),
tgtMapPtr_(nullptr), tgtMapPtr_(ami.tgtMapPtr_.clone()),
upToDate_(false) upToDate_(ami.upToDate_),
cache_(ami.cache_)
{} {}
@ -930,7 +949,9 @@ Foam::AMIInterpolation::AMIInterpolation(Istream& is)
//tgtPatchPts_(is), //tgtPatchPts_(is),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(readBool(is)) upToDate_(readBool(is)),
cache_(is)
{ {
// Hopefully no need to stream geomComm_ since only used in processor // Hopefully no need to stream geomComm_ since only used in processor
// agglomeration? // agglomeration?
@ -1361,7 +1382,6 @@ const
} }
else if (ray.distance() < nearest.distance()) else if (ray.distance() < nearest.distance())
{ {
nearest = ray; nearest = ray;
nearestFacei = srcFacei; nearestFacei = srcFacei;
} }
@ -1539,6 +1559,8 @@ void Foam::AMIInterpolation::write(Ostream& os) const
{ {
os.writeEntry("lowWeightCorrection", lowWeightCorrection_); os.writeEntry("lowWeightCorrection", lowWeightCorrection_);
} }
cache_.write(os);
} }
@ -1564,6 +1586,8 @@ bool Foam::AMIInterpolation::writeData(Ostream& os) const
<< token::SPACE<< upToDate(); << token::SPACE<< upToDate();
cache_.writeData(os);
if (distributed() && comm() != -1) if (distributed() && comm() != -1)
{ {
os << token::SPACE<< srcMap() os << token::SPACE<< srcMap()

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -61,7 +61,7 @@ SourceFiles
#include "indexedOctree.H" #include "indexedOctree.H"
#include "treeDataPrimitivePatch.H" #include "treeDataPrimitivePatch.H"
#include "runTimeSelectionTables.H" #include "runTimeSelectionTables.H"
#include "AMICache.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -78,6 +78,7 @@ public:
// Public Data Types // Public Data Types
//- Flag to store face-to-face intersection triangles; default = false
static bool cacheIntersections_; static bool cacheIntersections_;
//- Control use of local communicator for AMI communication //- Control use of local communicator for AMI communication
@ -86,6 +87,10 @@ public:
// localComm : 2 : like 1 but always include master (for messages) // localComm : 2 : like 1 but always include master (for messages)
static int useLocalComm_; static int useLocalComm_;
//- Tolerance used when caching the AMI to identify e.g. if the
//- current rotation angle has already been captured
static scalar cacheThetaTolerance_;
protected: protected:
@ -145,7 +150,6 @@ protected:
autoPtr<mapDistribute> srcMapPtr_; autoPtr<mapDistribute> srcMapPtr_;
// Target patch // Target patch
//- Target face areas //- Target face areas
@ -173,9 +177,13 @@ protected:
//- Target map pointer - parallel running only //- Target map pointer - parallel running only
autoPtr<mapDistribute> tgtMapPtr_; autoPtr<mapDistribute> tgtMapPtr_;
//- Up-to-date flag //- Up-to-date flag
bool upToDate_; bool upToDate_;
//- Cache
AMICache cache_;
// Protected Member Functions // Protected Member Functions
@ -212,10 +220,10 @@ protected:
// Access // Access
//- Return the orginal src patch with optionally updated points //- Return the original src patch with optionally updated points
inline const primitivePatch& srcPatch0() const; inline const primitivePatch& srcPatch0() const;
//- Return the orginal tgt patch with optionally updated points //- Return the original tgt patch with optionally updated points
inline const primitivePatch& tgtPatch0() const; inline const primitivePatch& tgtPatch0() const;
@ -240,27 +248,6 @@ protected:
); );
// Constructor helpers
static void agglomerate
(
const autoPtr<mapDistribute>& targetMap,
const scalarList& fineSrcMagSf,
const labelListList& fineSrcAddress,
const scalarListList& fineSrcWeights,
const labelList& sourceRestrictAddressing,
const labelList& targetRestrictAddressing,
scalarList& srcMagSf,
labelListList& srcAddress,
scalarListList& srcWeights,
scalarField& srcWeightsSum,
autoPtr<mapDistribute>& tgtMap,
const label comm
);
public: public:
//- Runtime type information //- Runtime type information
@ -366,6 +353,26 @@ public:
// Member Functions // Member Functions
// Constructor helpers
static void agglomerate
(
const autoPtr<mapDistribute>& targetMap,
const scalarList& fineSrcMagSf,
const labelListList& fineSrcAddress,
const scalarListList& fineSrcWeights,
const labelList& sourceRestrictAddressing,
const labelList& targetRestrictAddressing,
scalarList& srcMagSf,
labelListList& srcAddress,
scalarListList& srcWeights,
scalarField& srcWeightsSum,
autoPtr<mapDistribute>& tgtMap,
const label comm
);
// Access // Access
//- Is up-to-date? //- Is up-to-date?
@ -379,6 +386,10 @@ public:
return old; return old;
} }
//- Return a reference to the AMI cache
const AMICache& cache() const noexcept { return cache_; }
AMICache& cache() noexcept { return cache_; }
//- Distributed across processors (singlePatchProc == -1) //- Distributed across processors (singlePatchProc == -1)
inline bool distributed() const noexcept; inline bool distributed() const noexcept;
@ -411,6 +422,8 @@ public:
// \returns old value // \returns old value
inline label comm(label communicator) noexcept; inline label comm(label communicator) noexcept;
//- Return true if caching is active
inline bool cacheActive() const;
// Source patch // Source patch
@ -531,7 +544,8 @@ public:
// Low-level // Low-level
//- Weighted sum of contributions //- Weighted sum of contributions. Note: cop operates on
//- single Type only.
template<class Type, class CombineOp> template<class Type, class CombineOp>
static void weightedSum static void weightedSum
( (
@ -545,20 +559,35 @@ public:
const UList<Type>& defaultValues const UList<Type>& defaultValues
); );
//- Weighted sum of contributions //- Weighted sum of contributions (includes caching+interp)
//- (for primitive types only)
template<class Type> template<class Type>
void weightedSum void weightedSum
( (
const bool interpolateToSource, const bool toSource,
const UList<Type>& fld, const UList<Type>& fld,
List<Type>& result, List<Type>& result,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const; ) const;
//- Interpolate from target to source with supplied op //- Weighted sum of (potentially distributed) contributions
//- and apply caching+interpolation. Note: iop
//- operates on single Type only
template<class Type, class CombineOp, class InterpolateOp>
void interpolate
(
const bool toSource,
const UList<Type>& fld,
const CombineOp& cop,
const InterpolateOp& iop,
List<Type>& result,
const UList<Type>& defaultValues
) const;
//- Interpolate from source to target with supplied op
//- to combine existing value with remote value and weight //- to combine existing value with remote value and weight
template<class Type, class CombineOp> template<class Type, class CombineOp>
void interpolateToSource void interpolateToTarget
( (
const UList<Type>& fld, const UList<Type>& fld,
const CombineOp& cop, const CombineOp& cop,
@ -566,10 +595,10 @@ public:
const UList<Type>& defaultValues = UList<Type>::null() const UList<Type>& defaultValues = UList<Type>::null()
) const; ) const;
//- Interpolate from source to target with supplied op //- Interpolate from target to source with supplied op
//- to combine existing value with remote value and weight //- to combine existing value with remote value and weight
template<class Type, class CombineOp> template<class Type, class CombineOp>
void interpolateToTarget void interpolateToSource
( (
const UList<Type>& fld, const UList<Type>& fld,
const CombineOp& cop, const CombineOp& cop,
@ -671,6 +700,12 @@ public:
) )
const; const;
//- Restore AMI weights and addressing from the cache
bool restoreCache(const point& refPt);
//- Add AMI weights and addressing to the cache
void addToCache(const point& refPt);
// Checks // Checks

View File

@ -123,6 +123,12 @@ inline Foam::label Foam::AMIInterpolation::comm(label communicator) noexcept
} }
inline bool Foam::AMIInterpolation::cacheActive() const
{
return cache_.active();
}
inline const Foam::List<Foam::scalar>& Foam::AMIInterpolation::srcMagSf() const inline const Foam::List<Foam::scalar>& Foam::AMIInterpolation::srcMagSf() const
{ {
return srcMagSf_; return srcMagSf_;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2023 OpenCFD Ltd. Copyright (C) 2015-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -83,18 +83,19 @@ void Foam::AMIInterpolation::weightedSum
template<class Type> template<class Type>
void Foam::AMIInterpolation::weightedSum void Foam::AMIInterpolation::weightedSum
( (
const bool interpolateToSource, const bool toSource,
const UList<Type>& fld, const UList<Type>& fld,
List<Type>& result, List<Type>& result,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const ) const
{ {
// Note: using non-caching AMI
weightedSum weightedSum
( (
lowWeightCorrection_, lowWeightCorrection_,
(interpolateToSource ? srcAddress_ : tgtAddress_), (toSource ? srcAddress_ : tgtAddress_),
(interpolateToSource ? srcWeights_ : tgtWeights_), (toSource ? srcWeights_ : tgtWeights_),
(interpolateToSource ? srcWeightsSum_ : tgtWeightsSum_), (toSource ? srcWeightsSum_ : tgtWeightsSum_),
fld, fld,
multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()), multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()),
result, result,
@ -103,48 +104,81 @@ void Foam::AMIInterpolation::weightedSum
} }
template<class Type, class CombineOp> template<class Type, class CombineOp, class InterpolateOp>
void Foam::AMIInterpolation::interpolateToTarget void Foam::AMIInterpolation::interpolate
( (
const bool toSource,
const UList<Type>& fld, const UList<Type>& fld,
const CombineOp& cop, const CombineOp& cop,
const InterpolateOp& iop,
List<Type>& result, List<Type>& result,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const ) const
{ {
addProfiling(ami, "AMIInterpolation::interpolateToTarget"); // Note
// - behaves as old AMIInterpolation::interpolateToSource if toSource=true
// - `result` should be preallocated to correct size and initialized to
// an appropriate value (e.g. Zero)
if (fld.size() != srcAddress_.size()) // Get data locally and do a weighted sum
addProfiling(ami, "AMIInterpolation::interpolate");
cache_.setDirection(toSource);
auto checkSizes = [&](
const UList<Type>& fld,
const labelListList& srcAddr,
const labelListList& tgtAddr,
const UList<Type>& defVals
)
{
if (fld.size() != tgtAddr.size())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Supplied field size is not equal to source patch size" << nl << "Supplied field size is not equal to "
<< " source patch = " << srcAddress_.size() << nl << (toSource ? "target" : "source") << " patch size" << nl
<< " target patch = " << tgtAddress_.size() << nl << " source patch = " << srcAddr.size() << nl
<< " target patch = " << tgtAddr.size() << nl
<< " supplied field = " << fld.size() << " supplied field = " << fld.size()
<< abort(FatalError); << abort(FatalError);
} }
else if else if
( (
(lowWeightCorrection_ > 0) (lowWeightCorrection_ > 0) && (defVals.size() != srcAddr.size())
&& (defaultValues.size() != tgtAddress_.size())
) )
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Employing default values when sum of weights falls below " << "Employing default values when sum of weights falls below "
<< lowWeightCorrection_ << lowWeightCorrection_
<< " but supplied default field size is not equal to target " << " but number of default values is not equal to "
<< "patch size" << nl << (toSource ? "source" : "target") << " patch size" << nl
<< " default values = " << defaultValues.size() << nl << " default values = " << defVals.size() << nl
<< " target patch = " << tgtAddress_.size() << nl << " source patch = " << srcAddr.size() << nl
<< abort(FatalError); << abort(FatalError);
} }
};
result.setSize(tgtAddress_.size());
// Work space for if distributed
List<Type> work; List<Type> work;
if (distributed() && srcMapPtr_) List<Type> result0;
if (cache_.index0() != -1)
{ {
const mapDistribute& map = srcMapPtr_(); result0 = result;
const auto& srcAddress = cache_.cSrcAddress0();
const auto& srcWeights = cache_.cSrcWeights0();
const auto& srcWeightsSum = cache_.cSrcWeightsSum0();
const auto& tgtAddress = cache_.cTgtAddress0();
checkSizes(fld, srcAddress, tgtAddress, defaultValues);
if (distributed() && cache_.cTgtMapPtr0())
{
const mapDistribute& map = cache_.cTgtMapPtr0()();
if (map.comm() == -1) if (map.comm() == -1)
{ {
@ -156,14 +190,171 @@ void Foam::AMIInterpolation::interpolateToTarget
map.distribute(work); map.distribute(work);
} }
// if constexpr (is_contiguous_scalar<Type>::value)
// {
// result0 = Zero;
// }
weightedSum weightedSum
( (
lowWeightCorrection_, lowWeightCorrection_,
tgtAddress_, srcAddress,
tgtWeights_, srcWeights,
tgtWeightsSum_, srcWeightsSum,
(distributed() ? work : fld), (distributed() ? work : fld),
cop, cop,
result0,
defaultValues
);
}
List<Type> result1;
if (cache_.index1() != -1)
{
result1 = result;
const auto& srcAddress = cache_.cSrcAddress1();
const auto& srcWeights = cache_.cSrcWeights1();
const auto& srcWeightsSum = cache_.cSrcWeightsSum1();
const auto& tgtAddress = cache_.cTgtAddress1();
checkSizes(fld, srcAddress, tgtAddress, defaultValues);
if (distributed() && cache_.cTgtMapPtr1())
{
const mapDistribute& map = cache_.cTgtMapPtr1()();
if (map.comm() == -1)
{
return;
}
work.resize_nocopy(map.constructSize());
SubList<Type>(work, fld.size()) = fld; // deep copy
map.distribute(work);
}
// if constexpr (is_contiguous_scalar<Type>::value)
// {
// result1 = Zero;
// }
weightedSum
(
lowWeightCorrection_,
srcAddress,
srcWeights,
srcWeightsSum,
(distributed() ? work : fld),
cop,
result1,
defaultValues
);
}
if (cache_.applyLower())
{
result = result0;
}
else if (cache_.applyUpper())
{
result = result1;
}
else if (cache_.applyInterpolate())
{
forAll(result, i)
{
iop(result[i], i, i, result0[i], i, result1[i], cache_.weight());
}
}
else
{
// No cache - evaluate the AMI
const auto& srcAddress = (toSource ? srcAddress_ : tgtAddress_);
const auto& srcWeights = (toSource ? srcWeights_ : tgtWeights_);
const auto& srcWeightsSum =
(toSource ? srcWeightsSum_ : tgtWeightsSum_);
const auto& tgtAddress = (toSource ? tgtAddress_ : srcAddress_);
checkSizes(fld, srcAddress, tgtAddress, defaultValues);
if (distributed() && tgtMapPtr_)
{
const mapDistribute& map =
(
toSource
? tgtMapPtr_()
: srcMapPtr_()
);
if (map.comm() == -1)
{
return;
}
work.resize_nocopy(map.constructSize());
SubList<Type>(work, fld.size()) = fld; // deep copy
map.distribute(work);
}
// result.resize_nocopy(srcAddress.size());
// if constexpr (is_contiguous_scalar<Type>::value)
// {
// result = Zero;
// }
weightedSum
(
lowWeightCorrection_,
srcAddress,
srcWeights,
srcWeightsSum,
(distributed() ? work : fld),
cop,
result,
defaultValues
);
}
}
// Leave API intact below!
template<class Type, class CombineOp>
void Foam::AMIInterpolation::interpolateToTarget
(
const UList<Type>& fld,
const CombineOp& cop,
List<Type>& result,
const UList<Type>& defaultValues
) const
{
// In-place interpolation
addProfiling(ami, "AMIInterpolation::interpolateToTarget");
// Wrap lerp operator to operate inplace
auto iop = [&]
(
Type& res,
const label i,
const label ia,
const Type& a,
const label ib,
const Type& b,
const scalar w
)
{
res = lerp(a, b, w);
};
interpolate
(
false, // interpolate to target
fld,
cop,
iop,
result, result,
defaultValues defaultValues
); );
@ -179,58 +370,32 @@ void Foam::AMIInterpolation::interpolateToSource
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const ) const
{ {
// In-place interpolation
addProfiling(ami, "AMIInterpolation::interpolateToSource"); addProfiling(ami, "AMIInterpolation::interpolateToSource");
if (fld.size() != tgtAddress_.size()) // Wrap lerp operator to operate inplace
{ auto iop = [&]
FatalErrorInFunction
<< "Supplied field size is not equal to target patch size" << nl
<< " source patch = " << srcAddress_.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< " supplied field = " << fld.size()
<< abort(FatalError);
}
else if
( (
(lowWeightCorrection_ > 0) Type& res,
&& (defaultValues.size() != srcAddress_.size()) const label i,
const label ia,
const Type& a,
const label ib,
const Type& b,
const scalar w
) )
{ {
FatalErrorInFunction res = lerp(a, b, w);
<< "Employing default values when sum of weights falls below " };
<< lowWeightCorrection_
<< " but number of default values is not equal to source "
<< "patch size" << nl
<< " default values = " << defaultValues.size() << nl
<< " source patch = " << srcAddress_.size() << nl
<< abort(FatalError);
}
result.setSize(srcAddress_.size());
List<Type> work;
if (distributed() && tgtMapPtr_) interpolate
{
const mapDistribute& map = tgtMapPtr_();
if (map.comm() == -1)
{
return;
}
work.resize_nocopy(map.constructSize());
SubList<Type>(work, fld.size()) = fld; // deep copy
map.distribute(work);
}
weightedSum
( (
lowWeightCorrection_, true, // toSource,
srcAddress_, fld,
srcWeights_,
srcWeightsSum_,
(distributed() ? work : fld),
cop, cop,
iop,
result, result,
defaultValues defaultValues
); );

View File

@ -67,9 +67,7 @@ Foam::cyclicACMIGAMGInterfaceField::cyclicACMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, fineInterface), GAMGInterfaceField(GAMGCp, fineInterface),
cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)), cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)),
doTransform_(false), doTransform_(false),
rank_(0), rank_(0)
sendRequests_(),
recvRequests_()
{ {
const cyclicAMILduInterfaceField& p = const cyclicAMILduInterfaceField& p =
refCast<const cyclicAMILduInterfaceField>(fineInterface); refCast<const cyclicAMILduInterfaceField>(fineInterface);
@ -89,9 +87,7 @@ Foam::cyclicACMIGAMGInterfaceField::cyclicACMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, doTransform, rank), GAMGInterfaceField(GAMGCp, doTransform, rank),
cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)), cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)),
doTransform_(doTransform), doTransform_(doTransform),
rank_(rank), rank_(rank)
sendRequests_(),
recvRequests_()
{} {}
@ -104,9 +100,7 @@ Foam::cyclicACMIGAMGInterfaceField::cyclicACMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, is), GAMGInterfaceField(GAMGCp, is),
cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)), cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)),
doTransform_(readBool(is)), doTransform_(readBool(is)),
rank_(readLabel(is)), rank_(readLabel(is))
sendRequests_(),
recvRequests_()
{} {}
@ -120,9 +114,7 @@ Foam::cyclicACMIGAMGInterfaceField::cyclicACMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, local), GAMGInterfaceField(GAMGCp, local),
cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)), cyclicACMIInterface_(refCast<const cyclicACMIGAMGInterface>(GAMGCp)),
doTransform_(false), doTransform_(false),
rank_(0), rank_(0)
sendRequests_(),
recvRequests_()
{ {
const auto& p = refCast<const cyclicACMILduInterfaceField>(local); const auto& p = refCast<const cyclicACMILduInterfaceField>(local);
@ -142,9 +134,15 @@ bool Foam::cyclicACMIGAMGInterfaceField::ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if if
( (
@ -153,9 +151,15 @@ bool Foam::cyclicACMIGAMGInterfaceField::ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
} }
return true; return true;
@ -210,15 +214,9 @@ void Foam::cyclicACMIGAMGInterfaceField::initInterfaceMatrixUpdate
// Transform according to the transformation tensors // Transform according to the transformation tensors
transformCoupleField(pnf, cmpt); transformCoupleField(pnf, cmpt);
const auto& map =
(
cyclicACMIInterface_.owner()
? AMI.tgtMap()
: AMI.srcMap()
);
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -226,8 +224,16 @@ void Foam::cyclicACMIGAMGInterfaceField::initInterfaceMatrixUpdate
<< abort(FatalError); << abort(FatalError);
} }
// Assume that sends are also OK const auto& cache = AMI.cache();
sendRequests_.clear();
if (cache.index0() == -1 && cache.index1() == -1)
{
const auto& map =
(
cyclicACMIInterface_.owner()
? AMI.tgtMap()
: AMI.srcMap()
);
// Insert send/receive requests (non-blocking). See e.g. // Insert send/receive requests (non-blocking). See e.g.
// cyclicAMIPolyPatchTemplates.C // cyclicAMIPolyPatchTemplates.C
@ -243,6 +249,39 @@ void Foam::cyclicACMIGAMGInterfaceField::initInterfaceMatrixUpdate
); );
UPstream::commWarn(oldWarnComm); UPstream::commWarn(oldWarnComm);
} }
else
{
cache.setDirection(cyclicACMIInterface_.owner());
if (cache.index0() != -1)
{
const auto& map0 = cache.cTgtMapPtr0()();
map0.send
(
pnf,
sendRequests_,
scalarSendBufs_,
recvRequests_,
scalarRecvBufs_,
19462+cyclicACMIInterface_.index() // unique offset + patch index
);
}
if (cache.index1() != -1)
{
const auto& map1 = cache.cTgtMapPtr1()();
map1.send
(
pnf,
sendRequests1_,
scalarSendBufs1_,
recvRequests1_,
scalarRecvBufs1_,
19463+cyclicACMIInterface_.index() // unique offset + patch index
);
}
}
}
this->updatedMatrix(false); this->updatedMatrix(false);
} }
@ -260,6 +299,8 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
const Pstream::commsTypes const Pstream::commsTypes
) const ) const
{ {
typedef multiplyWeightedOp<scalar, plusEqOp<scalar>> opType;
const labelUList& faceCells = lduAddr.patchAddr(patchId); const labelUList& faceCells = lduAddr.patchAddr(patchId);
const auto& AMI = const auto& AMI =
@ -269,15 +310,11 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
: cyclicACMIInterface_.neighbPatch().AMI() : cyclicACMIInterface_.neighbPatch().AMI()
); );
DebugPout<< "cyclicACMIGAMGInterfaceField::updateInterfaceMatrix() :" const auto& cache = AMI.cache();
<< " interface:" << cyclicACMIInterface_.index()
<< " size:" << cyclicACMIInterface_.size()
<< " owner:" << cyclicACMIInterface_.owner()
<< " AMI distributed:" << AMI.distributed()
<< endl;
if (AMI.distributed() && AMI.comm() != -1) if (AMI.distributed() && AMI.comm() != -1)
{
if (cache.index0() == -1 && cache.index1() == -1)
{ {
const auto& map = const auto& map =
( (
@ -313,29 +350,157 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
this->addToInternalField(result, !add, faceCells, coeffs, pnf); this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
else else
{
cache.setDirection(cyclicACMIInterface_.owner());
solveScalarField pnf(faceCells.size());
solveScalarField work(faceCells.size());
if (cache.index0() != -1)
{
// Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work.
work = Zero;
cache.cTgtMapPtr0()().receive
(
recvRequests_,
scalarRecvBufs_,
work,
19462+cyclicACMIInterface_.index() // unique offset + patch index
);
// Receive requests all handled by last function call
recvRequests_.clear();
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress0(),
cache.cSrcWeights0(),
cache.cSrcWeightsSum0(),
work,
opType(plusEqOp<scalar>()),
pnf,
solveScalarField::null()
);
pnf *= (1-cache.weight());
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
if (cache.index1() != -1)
{
// Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work.
work = Zero;
cache.cTgtMapPtr1()().receive
(
recvRequests1_,
scalarRecvBufs1_,
work,
19463+cyclicACMIInterface_.index() // unique offset + patch index
);
// Receive requests all handled by last function call
recvRequests1_.clear();
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress1(),
cache.cSrcWeights1(),
cache.cSrcWeightsSum1(),
work,
opType(plusEqOp<scalar>()),
pnf,
solveScalarField::null()
);
pnf *= cache.weight();
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
}
}
else
{ {
// Get neighbouring field // Get neighbouring field
const labelUList& nbrFaceCells = const labelUList& nbrFaceCells =
lduAddr.patchAddr(cyclicACMIInterface_.neighbPatchID()); lduAddr.patchAddr(cyclicACMIInterface_.neighbPatchID());
solveScalarField pnf(psiInternal, nbrFaceCells); solveScalarField work(psiInternal, nbrFaceCells);
// Transform according to the transformation tensors // Transform according to the transformation tensors
transformCoupleField(pnf, cmpt); transformCoupleField(work, cmpt);
if (cyclicACMIInterface_.owner()) if (cache.index0() == -1 && cache.index1() == -1)
{ {
pnf = AMI.interpolateToSource(pnf); solveScalarField pnf(faceCells.size(), Zero);
}
else AMI.weightedSum
{ (
pnf = AMI.interpolateToTarget(pnf); cyclicACMIInterface_.owner(),
} work,
pnf, // result
solveScalarField::null()
);
const labelUList& faceCells = lduAddr.patchAddr(patchId); const labelUList& faceCells = lduAddr.patchAddr(patchId);
this->addToInternalField(result, !add, faceCells, coeffs, pnf); this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
else
{
cache.setDirection(cyclicACMIInterface_.owner());
solveScalarField pnf(faceCells.size());
if (cache.index0() != -1)
{
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress0(),
cache.cSrcWeights0(),
cache.cSrcWeightsSum0(),
work,
opType(plusEqOp<scalar>()),
pnf,
solveScalarField::null()
);
pnf *= (1 - cache.weight());
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
if (cache.index1() != -1)
{
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress1(),
cache.cSrcWeights1(),
cache.cSrcWeightsSum1(),
work,
opType(plusEqOp<scalar>()),
pnf,
solveScalarField::null()
);
pnf *= cache.weight();
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
}
}
this->updatedMatrix(true); this->updatedMatrix(true);
} }

View File

@ -83,6 +83,20 @@ class cyclicACMIGAMGInterfaceField
//- Scalar receive buffers //- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs_; mutable PtrList<List<solveScalar>> scalarRecvBufs_;
// Only used for AMI caching
//- Current range of send requests (non-blocking)
mutable labelRange sendRequests1_;
//- Current range of recv requests (non-blocking)
mutable labelRange recvRequests1_;
//- Scalar send buffers
mutable PtrList<List<solveScalar>> scalarSendBufs1_;
//- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs1_;
// Private Member Functions // Private Member Functions

View File

@ -67,9 +67,7 @@ Foam::cyclicAMIGAMGInterfaceField::cyclicAMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, fineInterface), GAMGInterfaceField(GAMGCp, fineInterface),
cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)), cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)),
doTransform_(false), doTransform_(false),
rank_(0), rank_(0)
sendRequests_(),
recvRequests_()
{ {
const cyclicAMILduInterfaceField& p = const cyclicAMILduInterfaceField& p =
refCast<const cyclicAMILduInterfaceField>(fineInterface); refCast<const cyclicAMILduInterfaceField>(fineInterface);
@ -89,9 +87,7 @@ Foam::cyclicAMIGAMGInterfaceField::cyclicAMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, doTransform, rank), GAMGInterfaceField(GAMGCp, doTransform, rank),
cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)), cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)),
doTransform_(doTransform), doTransform_(doTransform),
rank_(rank), rank_(rank)
sendRequests_(),
recvRequests_()
{} {}
@ -104,9 +100,7 @@ Foam::cyclicAMIGAMGInterfaceField::cyclicAMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, is), GAMGInterfaceField(GAMGCp, is),
cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)), cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)),
doTransform_(readBool(is)), doTransform_(readBool(is)),
rank_(readLabel(is)), rank_(readLabel(is))
sendRequests_(),
recvRequests_()
{} {}
@ -120,9 +114,7 @@ Foam::cyclicAMIGAMGInterfaceField::cyclicAMIGAMGInterfaceField
GAMGInterfaceField(GAMGCp, local), GAMGInterfaceField(GAMGCp, local),
cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)), cyclicAMIInterface_(refCast<const cyclicAMIGAMGInterface>(GAMGCp)),
doTransform_(false), doTransform_(false),
rank_(0), rank_(0)
sendRequests_(), // assume no requests in flight for input field
recvRequests_()
{ {
const auto& p = refCast<const cyclicAMILduInterfaceField>(local); const auto& p = refCast<const cyclicAMILduInterfaceField>(local);
@ -142,9 +134,15 @@ bool Foam::cyclicAMIGAMGInterfaceField::ready() const
recvRequests_.start(), recvRequests_.start(),
recvRequests_.size() recvRequests_.size()
) )
&& UPstream::finishedRequests
(
recvRequests1_.start(),
recvRequests1_.size()
)
) )
{ {
recvRequests_.clear(); recvRequests_.clear();
recvRequests1_.clear();
if if
( (
@ -153,9 +151,15 @@ bool Foam::cyclicAMIGAMGInterfaceField::ready() const
sendRequests_.start(), sendRequests_.start(),
sendRequests_.size() sendRequests_.size()
) )
&& UPstream::finishedRequests
(
sendRequests1_.start(),
sendRequests1_.size()
)
) )
{ {
sendRequests_.clear(); sendRequests_.clear();
sendRequests1_.clear();
} }
return true; return true;
@ -183,7 +187,6 @@ void Foam::cyclicAMIGAMGInterfaceField::initInterfaceMatrixUpdate
? cyclicAMIInterface_.AMI() ? cyclicAMIInterface_.AMI()
: cyclicAMIInterface_.neighbPatch().AMI() : cyclicAMIInterface_.neighbPatch().AMI()
); );
if (AMI.distributed() && AMI.comm() != -1) if (AMI.distributed() && AMI.comm() != -1)
{ {
//DebugPout<< "cyclicAMIFvPatchField::initInterfaceMatrixUpdate() :" //DebugPout<< "cyclicAMIFvPatchField::initInterfaceMatrixUpdate() :"
@ -211,15 +214,8 @@ void Foam::cyclicAMIGAMGInterfaceField::initInterfaceMatrixUpdate
// Transform according to the transformation tensors // Transform according to the transformation tensors
transformCoupleField(pnf, cmpt); transformCoupleField(pnf, cmpt);
const auto& map =
(
cyclicAMIInterface_.owner()
? AMI.tgtMap()
: AMI.srcMap()
);
// Assert that all receives are known to have finished // Assert that all receives are known to have finished
if (!recvRequests_.empty()) if (!recvRequests_.empty() || !recvRequests1_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -227,8 +223,16 @@ void Foam::cyclicAMIGAMGInterfaceField::initInterfaceMatrixUpdate
<< abort(FatalError); << abort(FatalError);
} }
// Assume that sends are also OK const auto& cache = AMI.cache();
sendRequests_.clear();
if (cache.index0() == -1 && cache.index1() == -1)
{
const auto& map =
(
cyclicAMIInterface_.owner()
? AMI.tgtMap()
: AMI.srcMap()
);
// Insert send/receive requests (non-blocking). See e.g. // Insert send/receive requests (non-blocking). See e.g.
// cyclicAMIPolyPatchTemplates.C // cyclicAMIPolyPatchTemplates.C
@ -244,6 +248,39 @@ void Foam::cyclicAMIGAMGInterfaceField::initInterfaceMatrixUpdate
); );
UPstream::commWarn(oldWarnComm); UPstream::commWarn(oldWarnComm);
} }
else
{
cache.setDirection(cyclicAMIInterface_.owner());
if (cache.index0() != -1)
{
const auto& map0 = cache.cTgtMapPtr0()();
map0.send
(
pnf,
sendRequests_,
scalarSendBufs_,
recvRequests_,
scalarRecvBufs_,
19462+cyclicAMIInterface_.index() // unique offset + patch index
);
}
if (cache.index1() != -1)
{
const auto& map1 = cache.cTgtMapPtr1()();
map1.send
(
pnf,
sendRequests1_,
scalarSendBufs1_,
recvRequests1_,
scalarRecvBufs1_,
19463+cyclicAMIInterface_.index() // unique offset + patch index
);
}
}
}
this->updatedMatrix(false); this->updatedMatrix(false);
} }
@ -261,6 +298,8 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
const Pstream::commsTypes commsType const Pstream::commsTypes commsType
) const ) const
{ {
typedef multiplyWeightedOp<scalar, plusEqOp<scalar>> opType;
const labelUList& faceCells = lduAddr.patchAddr(patchId); const labelUList& faceCells = lduAddr.patchAddr(patchId);
const auto& AMI = const auto& AMI =
@ -284,6 +323,12 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
// << " AMI low-weight:" << AMI.applyLowWeightCorrection() // << " AMI low-weight:" << AMI.applyLowWeightCorrection()
// << endl; // << endl;
const auto& cache = AMI.cache();
// Assume that sends are also OK
sendRequests_.clear();
sendRequests1_.clear();
if (AMI.distributed() && AMI.comm() != -1) if (AMI.distributed() && AMI.comm() != -1)
{ {
if (commsType != UPstream::commsTypes::nonBlocking) if (commsType != UPstream::commsTypes::nonBlocking)
@ -293,6 +338,8 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
<< exit(FatalError); << exit(FatalError);
} }
if (cache.index0() == -1 && cache.index1() == -1)
{
const auto& map = const auto& map =
( (
cyclicAMIInterface_.owner() cyclicAMIInterface_.owner()
@ -327,6 +374,84 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
this->addToInternalField(result, !add, faceCells, coeffs, pnf); this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
else else
{
cache.setDirection(cyclicAMIInterface_.owner());
solveScalarField pnf(faceCells.size());
solveScalarField work(faceCells.size());
if (cache.index0() != -1)
{
// Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work.
work = Zero;
cache.cTgtMapPtr0()().receive
(
recvRequests_,
scalarRecvBufs_,
work,
19462+cyclicAMIInterface_.index() // unique offset + patch index
);
// Receive requests all handled by last function call
recvRequests_.clear();
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress0(),
cache.cSrcWeights0(),
cache.cSrcWeightsSum0(),
work,
opType(plusEqOp<scalar>()),
pnf,
defaultValues
);
pnf *= (1-cache.weight());
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
if (cache.index1() != -1)
{
// Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work.
work = Zero;
cache.cTgtMapPtr1()().receive
(
recvRequests1_,
scalarRecvBufs1_,
work,
19463+cyclicAMIInterface_.index() // unique offset + patch index
);
// Receive requests all handled by last function call
recvRequests1_.clear();
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress1(),
cache.cSrcWeights1(),
cache.cSrcWeightsSum1(),
work,
opType(plusEqOp<scalar>()),
pnf,
defaultValues
);
pnf *= cache.weight();
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
}
}
else
{ {
// Get neighbouring field // Get neighbouring field
const labelUList& nbrFaceCells = const labelUList& nbrFaceCells =
@ -337,7 +462,11 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
// Transform according to the transformation tensors // Transform according to the transformation tensors
transformCoupleField(work, cmpt); transformCoupleField(work, cmpt);
solveScalarField pnf(faceCells.size(), Zero); solveScalarField pnf(faceCells.size());
if (cache.index0() == -1 && cache.index1() == -1)
{
pnf = Zero;
AMI.weightedSum AMI.weightedSum
( (
cyclicAMIInterface_.owner(), cyclicAMIInterface_.owner(),
@ -349,6 +478,53 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
// Add result using coefficients // Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf); this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
else
{
cache.setDirection(cyclicAMIInterface_.owner());
if (cache.index0() != -1)
{
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress0(),
cache.cSrcWeights0(),
cache.cSrcWeightsSum0(),
work,
opType(plusEqOp<scalar>()),
pnf,
defaultValues
);
pnf *= (1 - cache.weight());
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
if (cache.index1() != -1)
{
pnf = Zero;
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress1(),
cache.cSrcWeights1(),
cache.cSrcWeightsSum1(),
work,
opType(plusEqOp<scalar>()),
pnf,
defaultValues
);
pnf *= cache.weight();
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}
}
}
this->updatedMatrix(true); this->updatedMatrix(true);
} }

View File

@ -83,6 +83,21 @@ class cyclicAMIGAMGInterfaceField
mutable PtrList<List<solveScalar>> scalarRecvBufs_; mutable PtrList<List<solveScalar>> scalarRecvBufs_;
// Only used for AMI caching
//- Current range of send requests (non-blocking)
mutable labelRange sendRequests1_;
//- Current range of recv requests (non-blocking)
mutable labelRange recvRequests1_;
//- Scalar send buffers
mutable PtrList<List<solveScalar>> scalarSendBufs1_;
//- Scalar receive buffers
mutable PtrList<List<solveScalar>> scalarRecvBufs1_;
// Private Member Functions // Private Member Functions
//- No copy construct //- No copy construct

View File

@ -381,6 +381,46 @@ void Foam::cyclicAMIPolyPatch::resetAMI(const UList<point>& points) const
return; return;
} }
point refPt = point::max;
bool restoredFromCache = false;
if (AMIPtr_->cacheActive())
{
const label comm = boundaryMesh().mesh().comm();
if (UPstream::parRun())
{
label refProci = -1;
if (size() > 0)
{
refProci = UPstream::myProcNo(comm);
}
reduce(refProci, maxOp<label>(), UPstream::msgType(), comm);
if (refProci == UPstream::myProcNo(comm))
{
refPt = points[meshPoints()[0]];
}
reduce(refPt, minOp<point>(), UPstream::msgType(), comm);
}
else
{
refPt = points[meshPoints()[0]];
}
// Sets cache indices to use and time interpolation weight
restoredFromCache = AMIPtr_->restoreCache(refPt);
if (returnReduceOr(restoredFromCache, comm))
{
// Restored AMI weight and addressing from cache - all done
Info<< "AMI: weights and addresses restored from cache" << endl;
return;
}
}
const cyclicAMIPolyPatch& nbr = neighbPatch(); const cyclicAMIPolyPatch& nbr = neighbPatch();
const pointField srcPoints(points, meshPoints()); const pointField srcPoints(points, meshPoints());
pointField nbrPoints(points, nbr.meshPoints()); pointField nbrPoints(points, nbr.meshPoints());
@ -432,7 +472,7 @@ void Foam::cyclicAMIPolyPatch::resetAMI(const UList<point>& points) const
meshTools::writeOBJ(osN, nbrPatch0.localFaces(), nbrPoints); meshTools::writeOBJ(osN, nbrPatch0.localFaces(), nbrPoints);
OFstream osO(t.path()/name() + "_ownerPatch.obj"); OFstream osO(t.path()/name() + "_ownerPatch.obj");
meshTools::writeOBJ(osO, this->localFaces(), localPoints()); meshTools::writeOBJ(osO, this->localFaces(), srcPoints);
} }
// Construct/apply AMI interpolation to determine addressing and weights // Construct/apply AMI interpolation to determine addressing and weights
@ -446,6 +486,8 @@ void Foam::cyclicAMIPolyPatch::resetAMI(const UList<point>& points) const
{ {
AMIPtr_->checkSymmetricWeights(true); AMIPtr_->checkSymmetricWeights(true);
} }
AMIPtr_->addToCache(refPt);
} }

View File

@ -99,7 +99,7 @@ protected:
//- Index of other half //- Index of other half
mutable label nbrPatchID_; mutable label nbrPatchID_;
//- Particle displacement fraction accross AMI //- Particle displacement fraction across AMI
const scalar fraction_; const scalar fraction_;
@ -166,6 +166,9 @@ protected:
//- Temporary storage for AMI face centres //- Temporary storage for AMI face centres
mutable vectorField faceCentres0_; mutable vectorField faceCentres0_;
// Cache
bool cacheAMI_;
// Protected Member Functions // Protected Member Functions
@ -520,9 +523,14 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
PtrList<List<Type>>& sendBuffers,
labelRange& recvRequests, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers,
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const; ) const;
template<class Type> template<class Type>
@ -530,9 +538,14 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
PtrList<List<Type>>& sendBuffers,
labelRange& recvRequests, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers,
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const; ) const;
template<class Type> template<class Type>
@ -541,6 +554,8 @@ public:
const Field<Type>& localFld, const Field<Type>& localFld,
const labelRange& requests, // The receive requests const labelRange& requests, // The receive requests
const PtrList<List<Type>>& recvBuffers, const PtrList<List<Type>>& recvBuffers,
const labelRange& requests1, // The receive requests
const PtrList<List<Type>>& recvBuffers1,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const; ) const;

View File

@ -63,6 +63,7 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
if constexpr (transform_supported) if constexpr (transform_supported)
{ {
// Only creates the co-ord system if using periodic AMI
cs.reset(cylindricalCS()); cs.reset(cylindricalCS());
} }
@ -130,7 +131,7 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
const tensorField ownT(cs().R(this->faceCentres())); const tensorField ownT(cs().R(this->faceCentres()));
Field<Type> localDeflt(defaultValues.size()); Field<Type> localDeflt(defaultValues.size());
if (defaultValues.size() == size()) if (defaultValues.size() != 0 && defaultValues.size() == size())
{ {
// Transform default values into cylindrical coords (using // Transform default values into cylindrical coords (using
// *this faceCentres) // *this faceCentres)
@ -176,15 +177,26 @@ void Foam::cyclicAMIPolyPatch::initInterpolateUntransformed
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
PtrList<List<Type>>& sendBuffers,
labelRange& recvRequests, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers,
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const ) const
{ {
const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI()); const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI());
if (AMI.distributed() && AMI.comm() != -1) if (AMI.distributed() && AMI.comm() != -1)
{ {
const auto& cache = AMI.cache();
if (cache.index0() == -1 && cache.index1() == -1)
{
// No caching
const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap()); const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap());
// Insert send/receive requests (non-blocking) // Insert send/receive requests (non-blocking)
@ -198,6 +210,45 @@ void Foam::cyclicAMIPolyPatch::initInterpolateUntransformed
3894+this->index() // unique offset + patch index 3894+this->index() // unique offset + patch index
); );
} }
else
{
// Caching is active
cache.setDirection(owner());
if (cache.index0() != -1)
{
const auto& map0 = cache.cTgtMapPtr0()();
// Insert send/receive requests (non-blocking)
map0.send
(
fld,
sendRequests,
sendBuffers,
recvRequests,
recvBuffers,
3894+this->index() // unique offset + patch index
);
}
if (cache.index1() != -1)
{
const auto& map1 = cache.cTgtMapPtr1()();
// Insert send/receive requests (non-blocking)
map1.send
(
fld,
sendRequests1,
sendBuffers1,
recvRequests1,
recvBuffers1,
3895+this->index() // unique offset + patch index
);
}
}
}
} }
@ -206,9 +257,14 @@ void Foam::cyclicAMIPolyPatch::initInterpolate
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
PtrList<List<Type>>& sendBuffers,
labelRange& recvRequests, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers,
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const ) const
{ {
const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI()); const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI());
@ -221,48 +277,52 @@ void Foam::cyclicAMIPolyPatch::initInterpolate
// Can rotate fields (vector and non-spherical tensors) // Can rotate fields (vector and non-spherical tensors)
constexpr bool transform_supported = is_rotational_vectorspace_v<Type>; constexpr bool transform_supported = is_rotational_vectorspace_v<Type>;
[[maybe_unused]]
autoPtr<coordSystem::cylindrical> cs;
if constexpr (transform_supported) if constexpr (transform_supported)
{ {
cs.reset(cylindricalCS()); // Only creates the co-ord system if using periodic AMI
} // - convert to cylindrical coordinate system
auto cs = cylindricalCS();
if (!cs) if (cs)
{ {
initInterpolateUntransformed
(
fld,
sendRequests,
sendBuffers,
recvRequests,
recvBuffers
);
}
else if constexpr (transform_supported)
{
const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
Field<Type> localFld(fld.size()); Field<Type> localFld(fld.size());
const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
// Transform to cylindrical coords
{
const tensorField nbrT(cs().R(nbrPp.faceCentres())); const tensorField nbrT(cs().R(nbrPp.faceCentres()));
Foam::invTransform(localFld, nbrT, fld); Foam::invTransform(localFld, nbrT, fld);
}
initInterpolateUntransformed initInterpolateUntransformed
( (
localFld, localFld,
sendRequests, sendRequests,
sendBuffers,
recvRequests, recvRequests,
recvBuffers sendBuffers,
recvBuffers,
sendRequests1,
recvRequests1,
sendBuffers1,
recvBuffers1
); );
return;
} }
} }
initInterpolateUntransformed
(
fld,
sendRequests,
recvRequests,
sendBuffers,
recvBuffers,
sendRequests1,
recvRequests1,
sendBuffers1,
recvBuffers1
);
}
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
@ -270,14 +330,21 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
const Field<Type>& localFld, const Field<Type>& localFld,
const labelRange& requests, const labelRange& requests,
const PtrList<List<Type>>& recvBuffers, const PtrList<List<Type>>& recvBuffers,
const labelRange& requests1,
const PtrList<List<Type>>& recvBuffers1,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const ) const
{ {
// Note: cannot be localFld.size() -> is set to null for distributed AMI
auto tresult = tmp<Field<Type>>::New(this->size(), Zero); auto tresult = tmp<Field<Type>>::New(this->size(), Zero);
const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI()); const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI());
const auto& cache = AMI.cache();
cache.setDirection(owner());
Field<Type> work; Field<Type> work;
Field<Type> work1;
if (AMI.distributed()) if (AMI.distributed())
{ {
if (AMI.comm() == -1) if (AMI.comm() == -1)
@ -285,10 +352,13 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
return tresult; return tresult;
} }
if (cache.index0() == -1 && cache.index1() == -1)
{
// No caching
const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap()); const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap());
// Receive (= copy) data from buffers into work. TBD: receive directly // Receive (= copy) data from buffers into work. TBD: receive
// into slices of work. // directly into slices of work.
map.receive map.receive
( (
requests, requests,
@ -297,35 +367,55 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
3894+this->index() // unique offset + patch index 3894+this->index() // unique offset + patch index
); );
} }
else
{
// Using AMI cache
if (cache.index0() != -1)
{
cache.cTgtMapPtr0()().receive
(
requests,
recvBuffers,
work,
3894+this->index() // unique offset + patch index
);
}
if (cache.index1() != -1)
{
cache.cTgtMapPtr1()().receive
(
requests1,
recvBuffers1,
work1,
3895+this->index() // unique offset + patch index
);
}
}
}
const Field<Type>& fld = (AMI.distributed() ? work : localFld); const Field<Type>& fld = (AMI.distributed() ? work : localFld);
const Field<Type>& fld1 = (AMI.distributed() ? work1 : localFld);
// Rotate fields (vector and non-spherical tensors) // Rotate fields (vector and non-spherical tensors)
constexpr bool transform_supported = is_rotational_vectorspace_v<Type>; constexpr bool transform_supported = is_rotational_vectorspace_v<Type>;
[[maybe_unused]] // Rotate fields (vector and non-spherical tensors) for periodic AMI
autoPtr<coordSystem::cylindrical> cs; tensorField ownTransform;
Field<Type> localDeflt;
// Rotate fields (vector and non-spherical tensors)
if constexpr (transform_supported) if constexpr (transform_supported)
{ {
cs.reset(cylindricalCS()); // Only creates the co-ord system if using periodic AMI
} // - convert to cylindrical coordinate system
auto cs = cylindricalCS();
if (!cs) if (cs)
{ {
AMI.weightedSum ownTransform = cs().R(this->faceCentres());
( localDeflt = defaultValues;
owner(),
fld,
tresult.ref(),
defaultValues
);
}
else if constexpr (transform_supported)
{
const tensorField ownT(cs().R(this->faceCentres()));
Field<Type> localDeflt(defaultValues.size());
if (defaultValues.size() == size()) if (defaultValues.size() == size())
{ {
// Transform default values into cylindrical coords (using // Transform default values into cylindrical coords (using
@ -334,23 +424,86 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
// Field so we can use transformField routines. // Field so we can use transformField routines.
const SubField<Type> defaultSubFld(defaultValues); const SubField<Type> defaultSubFld(defaultValues);
const Field<Type>& defaultFld(defaultSubFld); const Field<Type>& defaultFld(defaultSubFld);
Foam::invTransform(localDeflt, ownT, defaultFld); Foam::invTransform(localDeflt, ownTransform, defaultFld);
}
}
} }
const auto& localDefaultValues =
localDeflt.size() ? localDeflt : defaultValues;
if (cache.index0() == -1 && cache.index1() == -1)
{
// No caching
AMI.weightedSum AMI.weightedSum
( (
owner(), owner(),
fld, fld,
tresult.ref(), tresult.ref(),
localDeflt localDefaultValues
); );
// Transform back // Transform back
Foam::transform(tresult.ref(), ownT, tresult()); if (ownTransform.size())
{
Foam::transform(tresult.ref(), ownTransform, tresult());
} }
return tresult; return tresult;
} }
else
{
if (cache.index0() != -1)
{
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress0(),
cache.cSrcWeights0(),
cache.cSrcWeightsSum0(),
fld,
multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()),
tresult.ref(),
localDefaultValues
);
if (ownTransform.size())
{
Foam::transform(tresult.ref(), ownTransform, tresult());
}
// Assuming cache weight is zero when index1 is inactive (==-1)
tresult.ref() *= (1 - cache.weight());
}
if (cache.index1() != -1)
{
auto tresult1 = tmp<Field<Type>>::New(this->size(), Zero);
AMIInterpolation::weightedSum
(
AMI.lowWeightCorrection(),
cache.cSrcAddress1(),
cache.cSrcWeights1(),
cache.cSrcWeightsSum1(),
fld1,
multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()),
tresult1.ref(),
localDefaultValues
);
if (ownTransform.size())
{
Foam::transform(tresult1.ref(), ownTransform, tresult1());
}
tresult1.ref() *= cache.weight();
tresult.ref() += tresult1();
}
return tresult;
}
}
template<class Type, class CombineOp> template<class Type, class CombineOp>

View File

@ -281,6 +281,7 @@ processorLOD/faceBox/faceBox.C
AMI=AMIInterpolation AMI=AMIInterpolation
$(AMI)/AMIInterpolation/AMIInterpolation.C $(AMI)/AMIInterpolation/AMIInterpolation.C
$(AMI)/AMIInterpolation/AMIInterpolationNew.C $(AMI)/AMIInterpolation/AMIInterpolationNew.C
$(AMI)/AMIInterpolation/AMICache.C
$(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C $(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C
$(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C $(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C
$(AMI)/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C $(AMI)/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -95,6 +95,102 @@ namespace Foam
} }
} }
}; };
template<class Type, class TrackingData>
class interpolate
{
//- Combine operator for AMIInterpolation
FaceCellWave<Type, TrackingData>& solver_;
const cyclicAMIPolyPatch& patch_;
public:
interpolate
(
FaceCellWave<Type, TrackingData>& solver,
const cyclicAMIPolyPatch& patch
)
:
solver_(solver),
patch_(patch)
{}
void operator()
(
Type& x,
const label localFacei,
const label f0i,
const Type& y0,
const label f1i,
const Type& y1,
const scalar weight
) const
{
if (y0.valid(solver_.data()))
{
if (y1.valid(solver_.data()))
{
x.interpolate
(
solver_.mesh(),
patch_.faceCentres()[localFacei],
f0i,
y0,
f1i,
y1,
weight,
solver_.propagationTol(),
solver_.data()
);
}
else
{
// Convert patch face into mesh face
label meshFacei = -1;
if (patch_.owner())
{
meshFacei = patch_.start() + f0i;
}
else
{
meshFacei = patch_.neighbPatch().start() + f0i;
}
x.updateFace
(
solver_.mesh(),
meshFacei,
y0,
solver_.propagationTol(),
solver_.data()
);
}
}
else if (y1.valid(solver_.data()))
{
// Convert patch face into mesh face
label meshFacei = -1;
if (patch_.owner())
{
meshFacei = patch_.start() + f1i;
}
else
{
meshFacei = patch_.neighbPatch().start() + f1i;
}
x.updateFace
(
solver_.mesh(),
meshFacei,
y1,
solver_.propagationTol(),
solver_.data()
);
}
}
};
} }
@ -784,18 +880,43 @@ void Foam::FaceCellWave<Type, TrackingData>::handleAMICyclicPatches()
// Transfer sendInfo to cycPatch // Transfer sendInfo to cycPatch
combine<Type, TrackingData> cmb(*this, cycPatch); combine<Type, TrackingData> cmb(*this, cycPatch);
// Linear interpolation
interpolate<Type, TrackingData> interp(*this, cycPatch);
const auto& AMI =
(
cycPatch.owner()
? cycPatch.AMI()
: cycPatch.neighbPatch().AMI()
);
if (cycPatch.applyLowWeightCorrection()) if (cycPatch.applyLowWeightCorrection())
{ {
List<Type> defVals const List<Type> defVals
( (
cycPatch.patchInternalList(allCellInfo_) cycPatch.patchInternalList(allCellInfo_)
); );
AMI.interpolate
cycPatch.interpolate(sendInfo, cmb, receiveInfo, defVals); (
cycPatch.owner(),
sendInfo,
cmb,
interp,
receiveInfo,
defVals
);
} }
else else
{ {
cycPatch.interpolate(sendInfo, cmb, receiveInfo); AMI.interpolate
(
cycPatch.owner(),
sendInfo,
cmb,
interp,
receiveInfo,
UList<Type>::null() // no default values needed
);
} }
} }

View File

@ -197,6 +197,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const cellInfo&, TrackingData& td) const; inline bool equal(const cellInfo&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const cellInfo& f0,
const label i1,
const cellInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -249,6 +249,31 @@ inline bool Foam::cellInfo::equal
} }
template<class TrackingData>
inline bool Foam::cellInfo::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const cellInfo& f0,
const label i1,
const cellInfo& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (!f0.valid(td))
{
return update(f1, -1, -1, -1, -1, td);
}
else
{
return update(f0, -1, -1, -1, -1, td);
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::cellInfo::operator== inline bool Foam::cellInfo::operator==

View File

@ -76,6 +76,16 @@ class wallPoint
// Private Member Functions // Private Member Functions
// Update this with w2 if distance less
template<class TrackingData>
inline bool update
(
const wallPoint& w2,
const scalar dist2,
const scalar tol,
TrackingData& td
);
//- Evaluate distance to point. //- Evaluate distance to point.
// Update distSqr, origin from whomever is nearer pt. // Update distSqr, origin from whomever is nearer pt.
// \return true if w2 is closer to point, false otherwise. // \return true if w2 is closer to point, false otherwise.
@ -206,10 +216,41 @@ public:
TrackingData& td TrackingData& td
); );
//- Interpolate different values
template<class TrackingData>
wallPoint
(
const polyMesh&,
const scalar weight,
const label face0,
const wallPoint& info0,
const label face1,
const wallPoint& info1,
const scalar tol,
TrackingData& td
);
//- Test for equality, with TrackingData //- Test for equality, with TrackingData
template<class TrackingData> template<class TrackingData>
inline bool equal(const wallPoint&, TrackingData& td) const; inline bool equal(const wallPoint&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallPoint& f0,
const label i1,
const wallPoint& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020,2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -35,21 +35,12 @@ License
template<class TrackingData> template<class TrackingData>
inline bool Foam::wallPoint::update inline bool Foam::wallPoint::update
( (
const point& pt,
const wallPoint& w2, const wallPoint& w2,
const scalar dist2,
const scalar tol, const scalar tol,
TrackingData& td TrackingData& td
) )
{ {
//Already done in calling algorithm
//if (w2.origin() == origin_)
//{
// // Shortcut. Same input so same distance.
// return false;
//}
const scalar dist2 = magSqr(pt - w2.origin());
if (!valid(td)) if (!valid(td))
{ {
// current not yet set so use any value // current not yet set so use any value
@ -83,6 +74,26 @@ inline bool Foam::wallPoint::update
} }
// Update this with w2 if w2 nearer to pt.
template<class TrackingData>
inline bool Foam::wallPoint::update
(
const point& pt,
const wallPoint& w2,
const scalar tol,
TrackingData& td
)
{
return update
(
w2,
magSqr(pt - w2.origin()),
tol,
td
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
inline Foam::wallPoint::wallPoint() inline Foam::wallPoint::wallPoint()
@ -260,6 +271,58 @@ inline bool Foam::wallPoint::equal
} }
template<class TrackingData>
inline bool Foam::wallPoint::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const wallPoint& f0,
const label i1,
const wallPoint& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
if (f1.valid(td))
{
// What do we do about the origin? Should be consistent with the
// distance? But then interpolating between a point 'on the left'
// and a point 'on the right' the interpolate might just be on
// top of us so suddenly setting the distance to be zero...
const scalar dist2 =
sqr(lerp(sqrt(f0.distSqr()), sqrt(f1.distSqr()), weight));
if (f0.distSqr() < f1.distSqr())
{
// Update with interpolated distance and f0 origin
return update(f0, dist2, tol, td);
}
else
{
return update(f1, dist2, tol, td);
}
}
else
{
return update(f0, f0.distSqr(), tol, td);
}
}
else if (f1.valid(td))
{
return update(f1, f1.distSqr(), tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::wallPoint::operator== inline bool Foam::wallPoint::operator==

View File

@ -196,6 +196,23 @@ public:
TrackingData& td TrackingData& td
) const; ) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const topoDistanceData<Type>& f0,
const label i1,
const topoDistanceData<Type>& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2020 OpenCFD Ltd. Copyright (C) 2019-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -199,6 +199,38 @@ inline bool Foam::topoDistanceData<Type>::equal
} }
template<class Type>
template<class TrackingData>
inline bool Foam::topoDistanceData<Type>::interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const topoDistanceData<Type>& f0,
const label i1,
const topoDistanceData<Type>& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
// Topological distance - how to interpolate?
if (!valid(td))
{
if (f0.valid(td))
{
this->operator=(f0);
}
else
{
this->operator=(f1);
}
return true;
}
return false;
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class Type> template<class Type>

View File

@ -174,6 +174,23 @@ public:
template<class TrackingData> template<class TrackingData>
inline bool equal(const minData&, TrackingData& td) const; inline bool equal(const minData&, TrackingData& td) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const minData& f0,
const label i1,
const minData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2014-2016 OpenFOAM Foundation Copyright (C) 2014-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd. Copyright (C) 2015-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -173,6 +173,35 @@ inline bool Foam::minData::equal
} }
template<class TrackingData>
inline bool Foam::minData::interpolate
(
const polyMesh& mesh,
const point& pt,
const label i0,
const minData& f0,
const label i1,
const minData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return updateFace(mesh, -1, f0, tol, td);
}
if (f1.valid(td))
{
return updateFace(mesh, -1, f1, tol, td);
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::minData::operator== inline bool Foam::minData::operator==

View File

@ -200,6 +200,23 @@ public:
TrackingData& TrackingData&
) const; ) const;
//- Interpolate between two values (lerp). Returns true if
//- causes changes. Not sure if needs to be specialised between
//- face and cell and what index is needed...
template<class TrackingData>
inline bool interpolate
(
const polyMesh&,
const point& pt,
const label i0,
const meshToMeshData& f0,
const label i1,
const meshToMeshData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
);
// Member Operators // Member Operators

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017-2020 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -205,6 +205,35 @@ inline bool Foam::meshToMeshData::equal
} }
template<class TrackingData>
inline bool Foam::meshToMeshData::interpolate
(
const polyMesh& mesh,
const point& pt,
const label i0,
const meshToMeshData& f0,
const label i1,
const meshToMeshData& f1,
const scalar weight,
const scalar tol,
TrackingData& td
)
{
if (f0.valid(td))
{
return updateFace(mesh, -1, f0, tol, td);
}
if (f1.valid(td))
{
return updateFace(mesh, -1, f1, tol, td);;
}
else
{
return false;
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline bool Foam::meshToMeshData::operator== inline bool Foam::meshToMeshData::operator==

View File

@ -788,9 +788,14 @@ boundary
AMI1 AMI1
{ {
cacheSize 360;
type cyclicAMI; type cyclicAMI;
neighbourPatch AMI2; neighbourPatch AMI2;
transform noOrdering; transform noOrdering;
rotationCentre (0 0 0);
rotationAxis (0 0 1);
/* optional /* optional
surface surface
{ {
@ -815,9 +820,13 @@ boundary
AMI2 AMI2
{ {
cacheSize 360;
type cyclicAMI; type cyclicAMI;
neighbourPatch AMI1; neighbourPatch AMI1;
transform noOrdering; transform noOrdering;
rotationCentre (0 0 0);
rotationAxis (0 0 1);
/* optional /* optional
surface surface
{ {