Compare commits

..

17 Commits

Author SHA1 Message Date
6b3e65d17d STYLE: ListExpression: copyright, indenting 2025-10-23 11:48:36 +01:00
572fa22bae Merge branch 'feature-grad_update' into 'develop'
Feature grad update

See merge request Development/openfoam!764
2025-10-22 15:46:53 +00:00
e100e4d084 Feature grad update 2025-10-22 15:46:53 +00:00
f186b0098b Merge branch 'feature-et' into 'develop'
ENH: Expressions: basic expression template support

See merge request Development/openfoam!763
2025-10-22 15:45:08 +00:00
b0066fc550 ENH: ListExpression: support par_unseq, multi-storage container
(ListsRefWrap etc. supplied by AMD)
2025-10-22 15:44:22 +00:00
7fb4e77583 ENH: expressions: Expression Templates 2025-10-22 15:44:22 +00:00
78cf2ce5db ENH: dynamicContactAngle: enable zonal input using persistent field storage
Temporary field creation is replaced with persistent field storage,
so that contact-angle can be input per zone using setFields utility.
2025-10-20 14:22:33 +01:00
f2793f2ac8 ENH: atmBoundaryLayer: extend range of applicability of displacement height, d (#3451) 2025-10-17 16:44:27 +01:00
013dbb8248 BUG: Pstream: incorrect indexing. Fixes #3452 2025-10-16 11:52:12 +01:00
e9fcd75ec4 ENH: add default "constant" name for fileOperations::findTimes()
- makes fileHandler calling resemble Time more closely

ENH: provide natural_sort less/greater functions

- more succinct than (compare < 0) or (compare > 0).
  The corresponding wrappers for UList renamed as list_less, etc
  but they were only used in unit tests

ENH: handle (-allRegions | -all-regions, ..) directly when retrieving args

- makes handling independent of aliasing order

STYLE: include <string_view> when including <string>

- the standard does not guarantee which headers (if any) actually
  include string_view
2025-10-12 15:53:26 +02:00
ac34d9fd29 ENH: allow delayed construction of regionFaModel in volume bcs (#3419)
Ideally wish to delay construction of the finite-area mesh until
  updateCoeffs(), when it is actually needed.

  This helps avoid difficult to trace errors and avoids inadvertent
  parallel communication during construction from a dictionary.

  However, lazy evaluation fails at the later stage while attempting
  to load the corresponding initial fields, since the timeIndex has
  already advanced.

  Use the newly introduced regionModels::allowFaModels() switch
  to locally enable or disable lazy evaluation as needed.

  This allows selective disabling (eg, in post-processing utilities)
  where loading the volume field should not activate the associated
  regionFaModel and loading a finite-area mesh too (which may not
  exist or be defined at that point).
2025-10-11 19:51:51 +02:00
14bece937b ENH: added clean up function remove0DirFields (RunFunctions)
- less typing than before and avoids relying on bash-specific behaviour
  (fixes #3448)

ENH: add -region support for cleanFaMesh and cleanPolyMesh

CONFIG: add bash completion help for -area-region

ENH: general improvements for regionProperties

- robustness and failsafe for foamListRegions, regionProperties
- additional global model switches for regionModels
2025-10-10 18:18:31 +02:00
2396828a60 ENH: increase some string_view coverage
- remove some stdFoam::span<char> handling, which was just a stop-gap
  measure
2025-10-10 09:05:23 +02:00
9223d238bd STYLE: surface/volume writing function objects
- further hide implementation (cxx ending)

STYLE: better distinction between code/templates for fileFormats/conversion

- for ensight and vtk, a large part of the code is header only.
  Make this easier to identify
2025-10-10 08:54:03 +02:00
4b92bb6533 ENH: update globalIndex::mpiGather to use MPI intrinsic/user types
- add provisional support for selecting MPI_Gatherv
  when merging fields in the surface writers.
  Uses the 'gatherv' keyword [experimental]

BUG: gatherv/scatterv wrappers used the incorrect data type

- incorrectly checked against UPstream_basic_dataType trait instead of
  UPstream_dataType, which resulted in a count mismatch for
  user-defined types (eg, vector, tensor,...).

  This was not visibly active bug, since previous internal uses of
  gatherv were restricted to primitive types.

COMP: make UPstream dataType traits size(...) constexpr

- allows static asserts and/or compile-time selection
  of code based on size(1)
2025-10-10 08:51:20 +02:00
55c81bce1b ENH: GAMGAgglomeration: increase repeatability. Fixes #3450 2025-10-09 11:55:06 +01:00
1cb0b7b6c9 Merge branch 'extend-field-distributors' into 'develop'
cleanup of decompose/reconstruct/redistribute, adding area-name support

See merge request Development/openfoam!761
2025-10-09 10:29:56 +00:00
92 changed files with 8865 additions and 3609 deletions

View File

@ -0,0 +1,5 @@
Test-expressionTemplates-volFields.C
/* Test-expressionTemplates-pointFields.C */
/* Test-expressionTemplates-Fields.C */
EXE = $(FOAM_USER_APPBIN)/Test-expressionTemplates

View File

@ -0,0 +1,11 @@
EXE_INC = \
-O0 \
-I$(FOAM_SRC)/meshTools/lnInclude \
-I$(FOAM_SRC)/finiteVolume/lnInclude \
EXE_LIBS = \
/* -rpath /Volumes/case_sensitive/OpenFOAM/work/feature-et/platforms */ \
/* -rpath /Volumes/case_sensitive/OpenFOAM/work/feature-et/platforms/darwin64GccDPInt32Opt/lib */ \
/* -rpath /Volumes/case_sensitive/OpenFOAM/work/feature-et/platforms/darwin64GccDPInt32Opt/lib/$(FOAM_MPI) */\
-L/Volumes/case_sensitive/OpenFOAM/work/feature-et/platforms/darwin64GccDPInt32Opt/lib \
-lfiniteVolume

View File

@ -0,0 +1,126 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 M. Janssens
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-expressionTemplates
\*---------------------------------------------------------------------------*/
#include "Time.H"
#include "argList.H"
#include "polyMesh.H"
#include "pointMesh.H"
#include "pointFields.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createPolyMesh.H"
{
scalarField vals0({1.0, 2.0, 3.0});
const Expression::ListConstRefWrap<scalar> wvals0(vals0);
scalarField vals1;
Expression::ListRefWrap<scalar> wvals1(vals1.size(), vals1);
wvals1 = wvals0;
return 0;
}
const pointMesh& pMesh = pointMesh::New(mesh);
// Field, dimensionedScalar as List expression
{
scalarField vals({1.0, 2.0, 3.0});
dimensionedScalar d(dimless, 4.0);
scalarField result(d.expr(vals.size())*vals.expr());
Pout<< "result:" << result << endl;
}
Info<< "Reading field p\n" << endl;
pointScalarField p
(
IOobject
(
"pointDisplacement",
runTime.timeName(),
pMesh.thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
pMesh
);
pointScalarField result
(
IOobject
(
"result",
runTime.timeName(),
pMesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
pMesh,
dimensionedScalar("zero", Foam::sqr(p().dimensions()), 0)
);
// Construct value + dimensions with correct sizing
const auto oneField(dimensionedScalar(dimless, 1.0).expr(p));
// Make expression
auto expression = oneField * p.expr() + p.expr();
// Combine expressions
auto newExpression = sqr(expression);
// Assign values
result = newExpression;
DebugVar(result);
// Construct from expression
pointScalarField result2("result2", pMesh, sqrt(p.expr()));
DebugVar(result2);
return 0;
}
// ************************************************************************* //

View File

@ -0,0 +1,451 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
-------------------------------------------------------------------------------
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/>.
Application
volPointInterpolationTest
\*---------------------------------------------------------------------------*/
#include "Time.H"
#include "argList.H"
#include "fvMesh.H"
#include "ListExpression.H"
#include "GeometricFieldExpression.H"
#include "fvCFD.H"
#include "fvMatrixExpression.H"
#include <ratio>
#include <chrono>
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
tmp<volScalarField> someFunction(const volScalarField& fld)
{
return fld*1.0001;
}
template<class Type>
void fusedGaussFvmLaplacian
(
fvMatrix<Type>& fvm,
const surfaceInterpolationScheme<scalar>& interpGammaScheme,
const fv::snGradScheme<Type>& snGradScheme,
const GeometricField<scalar, fvPatchField, volMesh>& gamma,
const GeometricField<Type, fvPatchField, volMesh>& vf
)
{
// Replacement for gaussLaplacianScheme::fvmLaplacian with scalar gamma
typedef GeometricField<Type, fvsPatchField, surfaceMesh> surfaceType;
const auto& mesh = vf.mesh();
// Expression for weights
const auto weights = interpGammaScheme.weights(gamma).expr();
// Expression for gamma_face * magSf
const auto gammaMagSf =
Expression::interpolate(gamma.expr(), weights, mesh)
* mesh.magSf().expr();
// Expression for deltaCoeffs
const auto deltaCoeffs = snGradScheme.deltaCoeffs(vf).expr();
// Construct matrix
Expression::fvmLaplacianUncorrected(fvm, gammaMagSf, deltaCoeffs);
if (snGradScheme.corrected())
{
// Wrap correction
const auto corr(snGradScheme.correction(vf).expr());
const auto V = mesh.V().expr();
if (mesh.fluxRequired(vf.name()))
{
fvm.faceFluxCorrectionPtr() = std::make_unique<surfaceType>
(
IOobject
(
"faceFluxCorr",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
gamma.dimensions()
*mesh.magSf().dimensions()
*corr.data().dimensions()
);
auto& faceFluxCorr = *fvm.faceFluxCorrectionPtr();
faceFluxCorr = gammaMagSf*corr;
fvm.source() =
fvm.source().expr()
- (
V * fvc::div
(
faceFluxCorr
)().primitiveField().expr()
);
}
else
{
// Temporary field
surfaceType faceFluxCorr
(
IOobject
(
"faceFluxCorr",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
gamma.dimensions()
*mesh.magSf().dimensions()
*corr.data().dimensions()
);
faceFluxCorr = gammaMagSf*corr;
fvm.source() =
fvm.source().expr()
- (
V * fvc::div
(
faceFluxCorr
)().primitiveField().expr()
);
}
}
}
using namespace std::chrono;
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
Info<< "Reading field p\n" << endl;
volScalarField p
(
IOobject
(
"p",
runTime.timeName(),
mesh.thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
{
volScalarField p2("p2", p);
DebugVar(p2.boundaryFieldRef());
for (auto& pf : p.boundaryFieldRef())
{
scalarField newVals(pf.size());
forAll(pf, i)
{
newVals[i] = scalar(i);
}
pf == newVals;
}
//std::vector<const scalarField*> ptrs;
// List<const scalarField*> ptrs;
// for (const auto& pp : p.boundaryField())
// {
// ptrs.push_back(&pp);
// }
DebugVar(sizeof(long));
DebugVar(p.boundaryField());
Expression::ListsConstRefWrap<scalarField> expr(p.boundaryField());
const auto twoA = expr + expr;
Expression::ListsRefWrap<scalarField> expr2(p2.boundaryFieldRef());
Pout<< "**before assignment twoA:" << twoA.size()
<< " expr2:" << expr2.size() << endl;
expr2 = twoA;
Pout<< "**after assignment twoA:" << twoA.size()
<< " expr2:" << expr2.size() << endl;
DebugVar(p2.boundaryField());
// forAll(expr, i)
// {
// Pout<< "i:" << i
// //<< " expr:" << expr[i]
// //<< " twoA:" << twoA[i]
// << " expr2:" << expr2[i]
// << endl;
// }
return 0;
}
{
//DebugVar(linearInterpolate(p));
//auto tweights = linear<scalar>(mesh).weights(p);
//DebugVar(tweights);
surfaceScalarField result
(
IOobject
(
"result",
runTime.timeName(),
mesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
dimensionedScalar(p.dimensions(), 0)
);
//result = Expression::interpolate
//(
// p.expr(),
// tweights().expr(),
// mesh
//);
result = Expression::linearInterpolate(p.expr(), mesh);
DebugVar(result);
return 0;
}
volScalarField p2
(
IOobject
(
"p",
runTime.timeName(),
mesh.thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE,
IOobject::NO_REGISTER
),
mesh
);
// Expresions of volFields
{
volScalarField result
(
IOobject
(
"result",
runTime.timeName(),
mesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
dimensionedScalar(p.dimensions(), 0)
);
{
Pout<< "No expression templates:" << endl;
const high_resolution_clock::time_point t1 =
high_resolution_clock::now();
result = p + p2;
const high_resolution_clock::time_point t2 =
high_resolution_clock::now();
const duration<double> time_span = t2 - t1;
Pout<< "Operation time:" << time_span.count() << endl;
}
{
Pout<< "With expression templates:" << endl;
const high_resolution_clock::time_point t1 =
high_resolution_clock::now();
result = p.expr() + p2.expr();
const high_resolution_clock::time_point t2 =
high_resolution_clock::now();
const duration<double> time_span = t2 - t1;
Pout<< "Operation time:" << time_span.count() << endl;
}
// const auto oldDimensions = p.dimensions();
// p.dimensions().reset(dimless);
// p2.dimensions().reset(dimless);
// result.dimensions().reset(dimless);
// {
//
// Pout<< "Complex expression : No expression templates:" << endl;
// const high_resolution_clock::time_point t1 =
// high_resolution_clock::now();
// result = cos(p + 0.5*sqrt(p2-sin(p)));
// const high_resolution_clock::time_point t2 =
// high_resolution_clock::now();
// const duration<double> time_span = t2 - t1;
// Pout<< "Operation time:" << time_span.count() << endl;
// }
// {
// Pout<< "Complex expression : With expression templates:" << endl;
// const high_resolution_clock::time_point t1 =
// high_resolution_clock::now();
// const auto zeroDotFive
// (
// dimensionedScalar(dimless, 0.5).expr(p)
// );
// result = cos(p.expr() + zeroDotFive*sqrt(p2.expr()-sin(p.expr())));
// const high_resolution_clock::time_point t2 =
// high_resolution_clock::now();
// const duration<double> time_span = t2 - t1;
// Pout<< "Operation time:" << time_span.count() << endl;
// }
// p.dimensions().reset(oldDimensions);
// p2.dimensions().reset(oldDimensions);
// result.dimensions().reset(oldDimensions);
return 0;
// auto expression = someFunction(p).expr() + someFunction(p).expr();
// result = expression;
// DebugVar(result);
}
{
volScalarField result
(
IOobject
(
"result",
runTime.timeName(),
mesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
dimensionedScalar(p.dimensions(), 0)
);
auto expression = someFunction(p).expr() + someFunction(p).expr();
result = expression;
DebugVar(result);
}
// Expresions of volFields
{
volScalarField result
(
"result",
mesh,
sqr(p.expr() + p.expr())
);
DebugVar(result);
}
{
// Fill p with some values
forAll(p, celli)
{
p[celli] = celli;
}
p.correctBoundaryConditions();
// Interpolate to surface field
surfaceScalarField result
(
"result",
mesh,
Expression::interpolate //<volExpr, surfaceExpr>
(
p.expr(),
mesh.surfaceInterpolation::weights().expr(),
mesh
)
);
DebugVar(result);
}
{
// For testing as a replacement of laplacian weights
const volScalarField gamma
(
IOobject
(
"gamma",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
dimensionedScalar(dimless, 1.0)
);
fvMatrix<scalar> fvm
(
p,
gamma.dimensions()*mesh.magSf().dimensions()*p.dimensions()
);
const linear<scalar> interpGammaScheme(mesh);
const fv::correctedSnGrad<scalar> snGradScheme(mesh);
fusedGaussFvmLaplacian
(
fvm,
interpGammaScheme,
snGradScheme,
gamma,
p
);
DebugVar(fvm.source());
}
// Expressions of fvMatrix
{
tmp<fvMatrix<scalar>> tm0(fvm::laplacian(p));
const fvMatrix<scalar>& m0 = tm0();
DebugVar(m0.dimensions());
tmp<fvMatrix<scalar>> tm1(fvm::laplacian(p));
const fvMatrix<scalar>& m1 = tm1();
DebugVar(m1.dimensions());
fvMatrix<scalar> m2(p, m0.expr() + m1.expr());
DebugVar(m2.dimensions());
}
return 0;
}
// ************************************************************************* //

View File

@ -55,8 +55,6 @@ wmake $targetType fileFormats
wmake $targetType surfMesh wmake $targetType surfMesh
wmake $targetType meshTools wmake $targetType meshTools
#------------------------------------------------------------------------------
wmake $targetType finiteArea wmake $targetType finiteArea
wmake $targetType finiteVolume wmake $targetType finiteVolume
wmake $targetType fused/finiteVolume wmake $targetType fused/finiteVolume

View File

@ -45,6 +45,7 @@ SourceFiles
#include "autoPtr.H" #include "autoPtr.H"
#include "UList.H" #include "UList.H"
#include "SLListFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -65,7 +66,6 @@ typedef List<bool> boolList; //!< A List of bools
typedef List<char> charList; //!< A List of chars typedef List<char> charList; //!< A List of chars
typedef List<label> labelList; //!< A List of labels typedef List<label> labelList; //!< A List of labels
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class List Declaration Class List Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -395,6 +395,37 @@ public:
//- Alias for resize() //- Alias for resize()
void setSize(label n, const T& val) { this->resize(n, val); } void setSize(label n, const T& val) { this->resize(n, val); }
// Expression templates
//- Construct from value expression
template<typename E>
explicit List
(
const Expression::ListExpression
<
E,
typename E::value_type
>& expr
)
{
expr.evaluate(*this);
}
//- Assign values from expression
template<typename E>
void operator=
(
const Expression::ListExpression
<
E,
typename E::value_type
>& expr
)
{
expr.evaluate(*this);
}
}; };

View File

@ -80,6 +80,11 @@ typedef UList<bool> boolUList; //!< A UList of bools
typedef UList<char> charUList; //!< A UList of chars typedef UList<char> charUList; //!< A UList of chars
typedef UList<label> labelUList; //!< A UList of labels typedef UList<label> labelUList; //!< A UList of labels
namespace Expression
{
template<class E, typename ValType> class ListExpression;
template<class T> class ListConstRefWrap;
}
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class UList Declaration Class UList Declaration
@ -697,6 +702,39 @@ public:
{ {
return this->contains(val, pos); return this->contains(val, pos);
} }
// Expression templates
//- Have unique tag
using is_List = void;
//- Wrap value as expression
auto expr() const
{
return Expression::ListConstRefWrap<T>
(
reinterpret_cast<const List<T>&>(*this)
);
}
//- Assign values from expression
template<typename E>
void operator=
(
const Expression::ListExpression
<
E,
typename E::value_type
>& expr
)
{
// bypass expr.evaluate to avoid resize ...
for (label i = 0; i < expr.size(); ++i)
{
operator[](i) = expr[i];
}
}
}; };

View File

@ -60,6 +60,12 @@ template<class Type> class dimensioned;
template<class Type> template<class Type>
Istream& operator>>(Istream& is, dimensioned<Type>& dt); Istream& operator>>(Istream& is, dimensioned<Type>& dt);
namespace Expression
{
template<class T> class UniformListWrap;
template<class GeoField> class UniformGeometricFieldWrap;
}
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class dimensioned Declaration Class dimensioned Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -449,6 +455,28 @@ public:
{ {
return getOrAddToDict(name, dict, deflt); return getOrAddToDict(name, dict, deflt);
} }
// Expression templates
//- Wrap value as constant-value List expression
auto expr(const label size) const
{
return Expression::UniformListWrap<Type>(size, value_);
}
//- Wrap value as constant-value GeometricField expression. Supplied
// fields is used for sizing only and needs to be valid at time of
// evaluation.
template<class GeoField>
auto expr(const GeoField& fld) const
{
return Expression::UniformGeometricFieldWrap<GeoField>
(
fld,
*this
);
}
}; };

View File

@ -0,0 +1,252 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 M. Janssens
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::GenericExpression
Description
Expression templates.
SourceFiles
GenericExpression.H
\*---------------------------------------------------------------------------*/
#ifndef Foam_GenericExpression_H
#define Foam_GenericExpression_H
#include <cassert>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Expression
{
/*---------------------------------------------------------------------------*\
Class GenericExpression Declarations
\*---------------------------------------------------------------------------*/
template<typename E>
class GenericExpression
{
public:
static constexpr bool is_leaf = false;
auto evaluate() const
{
// Delegation to the actual expression type. This avoids dynamic
// polymorphism (a.k.a. virtual functions in C++)
return static_cast<E const&>(*this).evaluate();
}
};
// Macros
// ~~~~~~
#define EXPRESSION_FUNCTION1(BaseClass, Func, BaseFunc, OpFunc) \
template<typename E1> \
class OpFunc \
: \
public BaseClass<OpFunc<E1>> \
{ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
\
public: \
static constexpr bool is_leaf = false; \
\
OpFunc(const E1& u) \
: \
u_(u) \
{} \
\
auto evaluate() const \
{ \
return BaseFunc(u_.evaluate()); \
} \
}; \
template<typename E1> \
OpFunc<E1> Func \
( \
const BaseClass<E1>& u \
) \
{ \
return OpFunc<E1>(static_cast<const E1&>(u)); \
}
#define EXPRESSION_FUNCTION2(BaseClass, Func, BaseFunc, OpFunc) \
template<typename E1, typename E2> \
class OpFunc \
: \
public BaseClass<OpFunc<E1, E2>> \
{ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
typename std::conditional<E2::is_leaf, const E2&, const E2>::type v_; \
\
public: \
static constexpr bool is_leaf = false; \
\
OpFunc(const E1& u, const E2& v) \
: \
u_(u), v_(v) \
{} \
auto evaluate() const \
{ \
return BaseFunc(u_.evaluate(), v_.evaluate()); \
} \
}; \
template<typename E1, typename E2> \
OpFunc<E1, E2> Func \
( \
const BaseClass<E1>& u, \
const BaseClass<E2>& v \
) \
{ \
return OpFunc<E1, E2> \
( \
static_cast<const E1&>(u), \
static_cast<const E2&>(v) \
); \
}
#define EXPRESSION_OPERATOR(BaseClass, Op, BaseOp, OpFunc) \
template<typename E1, typename E2> \
class OpFunc \
: \
public BaseClass \
< \
OpFunc<E1, E2> \
> \
{ \
/* cref if leaf, copy otherwise */ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
typename std::conditional<E2::is_leaf, const E2&, const E2>::type v_; \
\
public: \
static constexpr bool is_leaf = false; \
\
OpFunc(const E1& u, const E2& v) \
: \
u_(u), v_(v) \
{} \
auto evaluate() const \
{ \
return u_.evaluate() BaseOp v_.evaluate(); \
} \
}; \
template<typename E1, typename E2> \
OpFunc<E1, E2> \
operator Op \
( \
BaseClass<E1> const& u, \
BaseClass<E2> const& v \
) \
{ \
return OpFunc<E1, E2> \
( \
static_cast<const E1&>(u), \
static_cast<const E2&>(v) \
); \
}
// Do '-' separately until we work out macro expansion...
template<typename E1>
class g_negate
:
public GenericExpression
<
g_negate<E1>
>
{
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_;
public:
static constexpr bool is_leaf = false;
g_negate(const E1& u)
:
u_(u)
{}
auto evaluate() const
{
return -u_.evaluate();
}
};
template<typename E1>
g_negate<E1> operator-
(
const GenericExpression<E1>& u
)
{
return g_negate<E1>(static_cast<const E1&>(u));
}
EXPRESSION_FUNCTION1(GenericExpression, sqr, Foam::sqr, g_sqr)
EXPRESSION_FUNCTION1(GenericExpression, sqrt, Foam::sqrt, g_sqrt)
EXPRESSION_FUNCTION1(GenericExpression, magSqr, Foam::magSqr, g_magSqr)
EXPRESSION_FUNCTION1(GenericExpression, symm, Foam::symm, g_symm)
EXPRESSION_FUNCTION1(GenericExpression, pow2, Foam::pow2, g_pow2)
EXPRESSION_FUNCTION1(GenericExpression, pow3, Foam::pow3, g_pow3)
EXPRESSION_FUNCTION1(GenericExpression, pow4, Foam::pow4, g_pow4)
EXPRESSION_FUNCTION1(GenericExpression, operator~, Foam::operator~, g_compl)
//TBD. Parse problem
//EXPRESSION_FUNCTION1(GenericExpression, operator!, Foam::operator!, g_not)
#undef EXPRESSION_FUNCTION1
EXPRESSION_FUNCTION2(GenericExpression, operator+, Foam::operator+, g_add);
EXPRESSION_FUNCTION2(GenericExpression, operator-, Foam::operator-, g_subtract);
EXPRESSION_FUNCTION2(GenericExpression, operator*, Foam::operator*, g_multiply);
EXPRESSION_FUNCTION2(GenericExpression, operator/, Foam::operator/, g_divide);
#undef EXPRESSION_FUNCTION2
EXPRESSION_OPERATOR(GenericExpression, ||, ||, g_or)
EXPRESSION_OPERATOR(GenericExpression, &&, &&, g_and)
EXPRESSION_OPERATOR(GenericExpression, &, &, g_bitand)
EXPRESSION_OPERATOR(GenericExpression, |, |, g_bitor)
EXPRESSION_OPERATOR(GenericExpression, ^, ^, g_xor)
#undef EXPRESSION_OPERATOR
} // End namespace Expression
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 M. Janssens
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::boolExpression
Description
Expression templates for bool
SourceFiles
boolExpression.H
\*---------------------------------------------------------------------------*/
#ifndef Foam_boolExpression_H
#define Foam_boolExpression_H
#include "GenericExpression.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Expression
{
/*---------------------------------------------------------------------------*\
Namespace Expression Declarations
\*---------------------------------------------------------------------------*/
// Wrap of non-const bool
// ~~~~~~~~~~~~~~~~~~~~~~
class boolWrap
:
public GenericExpression<boolWrap>
{
bool elems_;
public:
static constexpr bool is_leaf = false; //true;
//- Construct from components
boolWrap(const bool elems)
:
elems_(elems)
{}
// Construct from GenericExpression, forcing its evaluation.
template<typename E>
boolWrap
(
const GenericExpression<E>& expr
)
:
elems_(expr.evaluate())
{}
auto evaluate() const
{
return elems_;
}
template<typename E>
auto evaluate
(
const GenericExpression<E>& expr
)
{
elems_ = expr.evaluate();
return elems_;
}
//- Assignment
template<typename E>
void operator=
(
const GenericExpression<E>& expr
)
{
elems_ = expr.evaluate();
}
};
// Wrap of const bool
// ~~~~~~~~~~~~~~~~~~
class boolConstWrap
:
public GenericExpression<boolConstWrap>
{
const bool elems_;
public:
// ! Store as copy (since holds reference)
static constexpr bool is_leaf = false;
// construct from components
boolConstWrap(const bool elems)
:
elems_(elems)
{}
auto evaluate() const
{
return elems_;
}
};
} // End namespace Expression
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 M. Janssens
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Namespace
Foam::dimensionSetExpression
Description
Expression templates for dimensionSet
SourceFiles
dimensionSetExpression.H
\*---------------------------------------------------------------------------*/
#ifndef Foam_dimensionSetExpression_H
#define Foam_dimensionSetExpression_H
#include "GenericExpression.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Expression
{
/*---------------------------------------------------------------------------*\
Namespace Expression Declarations
\*---------------------------------------------------------------------------*/
// Wrap of non-const reference to dimensionSet
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class dimensionSetRefWrap
:
public GenericExpression<dimensionSetRefWrap>
{
dimensionSet& elems_;
public:
static constexpr bool is_leaf = false; //true;
//- Construct from components
dimensionSetRefWrap(dimensionSet& elems)
:
elems_(elems)
{}
// Construct from GenericExpression, forcing its evaluation.
template<typename E>
dimensionSetRefWrap
(
dimensionSet& elems,
const GenericExpression<E>& expr
)
:
elems_(elems)
{
elems_ = expr.evaluate();
}
auto evaluate() const
{
return elems_;
}
template<typename E>
auto& evaluate
(
const GenericExpression<E>& expr
)
{
elems_ = expr.evaluate();
return elems_;
}
//- Assignment
template<typename E>
void operator=
(
const GenericExpression<E>& expr
)
{
elems_ = expr.evaluate();
}
};
// Wrap of const reference to dimensionSet
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class dimensionSetConstRefWrap
:
public GenericExpression<dimensionSetConstRefWrap>
{
const dimensionSet& elems_;
public:
// ! Store as copy (since holds reference)
static constexpr bool is_leaf = false;
// construct from components
dimensionSetConstRefWrap(const dimensionSet& elems)
:
elems_(elems)
{}
auto evaluate() const
{
return elems_;
}
};
} // End namespace Expression
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -582,6 +582,37 @@ public:
friend Ostream& operator<< <Type> friend Ostream& operator<< <Type>
(Ostream&, const tmp<Field<Type>>&); (Ostream&, const tmp<Field<Type>>&);
// Expression templates
//- Construct from value expression
template<typename E>
explicit Field
(
const Expression::ListExpression
<
E,
typename E::value_type
>& expr
)
{
expr.evaluate(*this);
}
//- Assign values from expression
template<typename E>
void operator=
(
const Expression::ListExpression
<
E,
typename E::value_type
>& expr
)
{
expr.evaluate(*this);
}
}; };

View File

@ -1675,6 +1675,124 @@ Foam::Ostream& Foam::operator<<
} }
// * * * * * * * * * * * * * Expression Templates * * * * * * * * * * * * * //
template<class Type, template<class> class PatchField, class GeoMesh>
template<typename E>
Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
(
const IOobject& io,
const Mesh& mesh,
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
:
Internal(io, mesh, expr.dimensions(), false),
timeIndex_(this->time().timeIndex()),
boundaryField_(mesh.boundary(), *this, PatchField<Type>::calculatedType())
{
DebugInFunction
<< "Creating from expression " << nl << this->info() << endl;
bool hasRead = readIfPresent();
if (!hasRead)
{
expr.evaluate(*this);
}
}
template<class Type, template<class> class PatchField, class GeoMesh>
template<typename E>
Foam::GeometricField<Type, PatchField, GeoMesh>::GeometricField
(
const word& name,
const Mesh& mesh,
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
:
Internal
(
IOobject
(
name,
mesh.time().timeName(),
mesh.thisDb()
),
mesh,
expr.dimensions(),
false
),
timeIndex_(this->time().timeIndex()),
boundaryField_(mesh.boundary(), *this, PatchField<Type>::calculatedType())
{
DebugInFunction
<< "Creating from expression " << nl << this->info() << endl;
expr.evaluate(*this);
}
template<class Type, template<class> class PatchField, class GeoMesh>
Foam::Expression::GeometricFieldConstRefWrap
<
Foam::GeometricField<Type, PatchField, GeoMesh>
>
Foam::GeometricField<Type, PatchField, GeoMesh>::expr() const
{
return Expression::GeometricFieldConstRefWrap<this_type>(*this);
}
template<class Type, template<class> class PatchField, class GeoMesh>
template<typename E>
void Foam::GeometricField<Type, PatchField, GeoMesh>::operator=
(
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
{
Expression::GeometricFieldRefWrap<this_type>(*this, expr);
}
template<class Type, template<class> class PatchField, class GeoMesh>
template<typename E>
void Foam::GeometricField<Type, PatchField, GeoMesh>::operator==
(
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
{
expr.evaluate(*this, true);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#undef checkField #undef checkField

View File

@ -42,6 +42,7 @@ SourceFiles
#define Foam_GeometricField_H #define Foam_GeometricField_H
#include "GeometricBoundaryField.H" #include "GeometricBoundaryField.H"
#include "GeometricFieldExpression.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -1142,6 +1143,79 @@ public:
{ {
return this->clamp_range(lo.value(), hi.value()); return this->clamp_range(lo.value(), hi.value());
} }
// Expression templates
//- Have unique tag
using is_GeometricField = void;
//- Construct from IOobject and value expression. Supports
// read_if_present
template<typename E>
GeometricField
(
const IOobject& io,
const Mesh& mesh,
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
);
//- Construct from name, mesh and value expression.
template<typename E>
GeometricField
(
const word& name,
const Mesh& mesh,
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
);
//- Wrap value as expression
typename Expression::GeometricFieldConstRefWrap
<
this_type
> expr() const;
//- Assign values from expression
template<typename E>
void operator=
(
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
);
//- Assign values from expression. Override asssignable.
template<typename E>
void operator==
(
const Expression::GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
);
}; };

View File

@ -59,8 +59,17 @@ See also
namespace Foam namespace Foam
{ {
namespace Expression
{
template<class GeoField> class GeometricFieldConstTmpWrap;
template<class T> class ListConstTmpWrap;
}
// Forward Declarations // Forward Declarations
template<class T> class refPtr; template<class T> class refPtr;
template<class T> class tmp;
template<class Type, template<class> class PatchField, class GeoMesh>
class GeometricField;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class tmp Declaration Class tmp Declaration
@ -352,6 +361,33 @@ public:
// \deprecated(2020-07) - use bool operator // \deprecated(2020-07) - use bool operator
FOAM_DEPRECATED_FOR(2020-07, "bool operator") FOAM_DEPRECATED_FOR(2020-07, "bool operator")
bool empty() const noexcept { return !ptr_; } bool empty() const noexcept { return !ptr_; }
// Expression templates
//- Wrap value as expression
auto expr() const
{
// Add 'using is_GeometricField = void' to GeometricField
// Add 'using is_List = void' to List
if constexpr
(
std::is_void_v<typename T::is_GeometricField>
)
{
return Expression::GeometricFieldConstTmpWrap<T>(*this);
}
else //if constexpr (std::is_void_v<T::is_List>)
{
return Expression::ListConstTmpWrap<T>(*this);
}
//else
//{
// //static_assert("XXX",YYY);
// return;
//}
}
}; };

View File

@ -131,7 +131,7 @@ inline Foam::tmp<T>::tmp(const tmp<T>& rhs)
if (ptr_) if (ptr_)
{ {
ptr_->refCount::operator++(); ptr_->refCount::operator++();
this->checkUseCount(); //this->checkUseCount();
} }
else else
{ {
@ -162,7 +162,7 @@ inline Foam::tmp<T>::tmp(const tmp<T>& rhs, bool reuse)
else else
{ {
ptr_->refCount::operator++(); ptr_->refCount::operator++();
this->checkUseCount(); //this->checkUseCount();
} }
} }
else else

View File

@ -855,7 +855,7 @@ bool Foam::UPstream::finishedRequest(const label i)
// This allows MPI to progress behind the scenes if it wishes. // This allows MPI to progress behind the scenes if it wishes.
int flag = 0; int flag = 0;
if (i < 0 || i >= PstreamGlobals::outstandingRequests_.size()) if (i >= 0 && i < PstreamGlobals::outstandingRequests_.size())
{ {
auto& request = PstreamGlobals::outstandingRequests_[i]; auto& request = PstreamGlobals::outstandingRequests_[i];

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,2025 OpenCFD Ltd. Copyright (C) 2016-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -189,23 +189,6 @@ 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
@ -313,17 +296,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2019 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,40 +191,6 @@ 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

@ -218,9 +218,11 @@ tmp<vectorField> atmBoundaryLayer::U(const vectorField& pCf) const
const scalar groundMin = zDir() & ppMin_; const scalar groundMin = zDir() & ppMin_;
// (YGCJ:Table 1, RH:Eq. 6, HW:Eq. 5) // (YGCJ:Table 1, RH:Eq. 6, HW:Eq. 5)
scalarField zEff(max((zDir() & pCf) - groundMin - d + z0, z0));
scalarField Un scalarField Un
( (
(Ustar(z0)/kappa_)*log(((zDir() & pCf) - groundMin - d + z0)/z0) (Ustar(z0)/kappa_)*log(zEff/z0)
); );
return flowDir()*Un; return flowDir()*Un;
@ -235,9 +237,9 @@ tmp<scalarField> atmBoundaryLayer::k(const vectorField& pCf) const
const scalar groundMin = zDir() & ppMin_; const scalar groundMin = zDir() & ppMin_;
// (YGCJ:Eq. 21; RH:Eq. 7, HW:Eq. 6 when C1=0 and C2=1) // (YGCJ:Eq. 21; RH:Eq. 7, HW:Eq. 6 when C1=0 and C2=1)
return scalarField zEff(max((zDir() & pCf) - groundMin - d + z0, z0));
sqr(Ustar(z0))/sqrt(Cmu_)
*sqrt(C1_*log(((zDir() & pCf) - groundMin - d + z0)/z0) + C2_); return sqr(Ustar(z0))/sqrt(Cmu_)*sqrt(C1_*log(zEff/z0) + C2_);
} }
@ -249,9 +251,9 @@ tmp<scalarField> atmBoundaryLayer::epsilon(const vectorField& pCf) const
const scalar groundMin = zDir() & ppMin_; const scalar groundMin = zDir() & ppMin_;
// (YGCJ:Eq. 22; RH:Eq. 8, HW:Eq. 7 when C1=0 and C2=1) // (YGCJ:Eq. 22; RH:Eq. 8, HW:Eq. 7 when C1=0 and C2=1)
return scalarField zEff(max((zDir() & pCf) - groundMin - d + z0, z0));
pow3(Ustar(z0))/(kappa_*((zDir() & pCf) - groundMin - d + z0))
*sqrt(C1_*log(((zDir() & pCf) - groundMin - d + z0)/z0) + C2_); return pow3(Ustar(z0))/(kappa_*zEff)*sqrt(C1_*log(zEff/z0) + C2_);
} }
@ -263,7 +265,9 @@ tmp<scalarField> atmBoundaryLayer::omega(const vectorField& pCf) const
const scalar groundMin = zDir() & ppMin_; const scalar groundMin = zDir() & ppMin_;
// (YGJ:Eq. 13) // (YGJ:Eq. 13)
return Ustar(z0)/(kappa_*sqrt(Cmu_)*((zDir() & pCf) - groundMin - d + z0)); scalarField zEff(max((zDir() & pCf) - groundMin - d + z0, z0));
return Ustar(z0)/(kappa_*sqrt(Cmu_)*zEff);
} }

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,2025 OpenCFD Ltd. Copyright (C) 2019-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -242,23 +242,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -287,35 +287,6 @@ 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,23 +186,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,35 +191,6 @@ 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,23 +197,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -248,35 +248,6 @@ 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,23 +229,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2019-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -278,35 +278,6 @@ 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==

File diff suppressed because it is too large Load Diff

View File

@ -227,15 +227,9 @@ 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;
} }
@ -246,15 +240,9 @@ 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;
} }
@ -272,15 +260,9 @@ 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
( (
@ -289,15 +271,9 @@ 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;
@ -507,7 +483,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -518,20 +494,14 @@ 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_,
recvRequests_,
sendBufs_, sendBufs_,
recvBufs_, recvRequests_,
recvBufs_
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
} }
@ -577,15 +547,12 @@ 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())
{ {
@ -641,7 +608,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -652,20 +619,14 @@ 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_,
recvRequests_,
scalarSendBufs_, scalarSendBufs_,
scalarRecvBufs_, recvRequests_,
scalarRecvBufs_
sendRequests1_,
recvRequests1_,
scalarSendBufs1_,
scalarRecvBufs1_
); );
} }
@ -720,14 +681,11 @@ 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
{ {
@ -780,7 +738,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -791,20 +749,14 @@ 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_,
recvRequests_,
sendBufs_, sendBufs_,
recvBufs_, recvRequests_,
recvBufs_
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
@ -846,14 +798,11 @@ 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,28 +102,6 @@ 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,15 +207,9 @@ 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;
} }
@ -226,15 +220,9 @@ 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;
} }
@ -252,15 +240,9 @@ 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
( (
@ -269,15 +251,9 @@ 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;
@ -343,18 +319,9 @@ Foam::cyclicAMIFvPatchField<Type>::getNeighbourField
template<class Type> template<class Type>
bool Foam::cyclicAMIFvPatchField<Type>::cacheNeighbourField() const bool Foam::cyclicAMIFvPatchField<Type>::cacheNeighbourField()
{ {
// const auto& AMI = this->ownerAMI(); return (FieldBase::localBoundaryConsistency() != 0);
// if (AMI.cacheActive())
// {
// return false;
// }
// else
{
return (FieldBase::localBoundaryConsistency() != 0);
}
} }
@ -383,12 +350,11 @@ Foam::cyclicAMIFvPatchField<Type>::getPatchNeighbourField
} }
const auto& fvp = this->patch(); const auto& fvp = this->patch();
const auto& mesh = fvp.boundaryMesh().mesh();
if if
( (
patchNeighbourFieldPtr_ patchNeighbourFieldPtr_
&& !mesh.upToDatePoints(this->internalField()) && !fvp.boundaryMesh().mesh().upToDatePoints(this->internalField())
) )
{ {
//DebugPout //DebugPout
@ -452,8 +418,7 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::cyclicAMIFvPatchField<Type>::patchNeighbourField() const Foam::cyclicAMIFvPatchField<Type>::patchNeighbourField() const
{ {
// checkCommunicator = true return this->getPatchNeighbourField(true); // checkCommunicator = true
return this->getPatchNeighbourField(true);
} }
@ -526,7 +491,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -537,20 +502,14 @@ 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_,
recvRequests_,
sendBufs_, sendBufs_,
recvBufs_, recvRequests_,
recvBufs_
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
} }
@ -603,15 +562,12 @@ 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())
{ {
@ -662,7 +618,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -673,20 +629,14 @@ 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_,
recvRequests_,
scalarSendBufs_, scalarSendBufs_,
scalarRecvBufs_, recvRequests_,
scalarRecvBufs_
sendRequests1_,
recvRequests1_,
scalarSendBufs1_,
scalarRecvBufs1_
); );
} }
@ -741,14 +691,11 @@ 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
{ {
@ -810,7 +757,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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -821,20 +768,14 @@ 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_,
recvRequests_,
sendBufs_, sendBufs_,
recvBufs_, recvRequests_,
recvBufs_
sendRequests1_,
recvRequests1_,
sendBufs1_,
recvBufs1_
); );
} }
@ -888,14 +829,11 @@ 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
{ {
@ -980,7 +918,7 @@ void Foam::cyclicAMIFvPatchField<Type>::manipulateMatrix
} }
// Set internalCoeffs and boundaryCoeffs in the assembly matrix // Set internalCoeffs and boundaryCoeffs in the assembly matrix
// on cyclicAMI patches to be used in the individual matrix by // on clyclicAMI 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,28 +113,6 @@ 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_;
@ -156,7 +134,7 @@ class cyclicAMIFvPatchField
virtual bool all_ready() const; virtual bool all_ready() const;
//- Use neighbour field caching //- Use neighbour field caching
bool cacheNeighbourField() const; static bool cacheNeighbourField();
//- 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,23 +209,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -191,45 +191,6 @@ 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,23 +207,6 @@ 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,45 +210,6 @@ 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

@ -1,4 +1,4 @@
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | \\ / O peration |
@ -36,23 +36,18 @@ License
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type, class Stencil> template<class Type, class Stencil>
Foam::tmp void Foam::fv::LeastSquaresGrad<Type, Stencil>::calcGrad
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::LeastSquaresGrad<Type, Stencil>::calcGrad
( (
const GeometricField<Type, fvPatchField, volMesh>& vtf, GeometricField
const word& name <
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& lsGrad,
const GeometricField<Type, fvPatchField, volMesh>& vtf
) const ) const
{ {
typedef typename outerProduct<vector, Type>::type GradType; typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vtf.mesh(); const fvMesh& mesh = vtf.mesh();
@ -62,24 +57,7 @@ Foam::fv::LeastSquaresGrad<Type, Stencil>::calcGrad
mesh mesh
); );
tmp<GradFieldType> tlsGrad lsGrad = dimensioned<GradType>(vtf.dimensions()/dimLength, Zero);
(
new GradFieldType
(
IOobject
(
name,
vtf.instance(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensioned<GradType>(vtf.dimensions()/dimLength, Zero),
fvPatchFieldBase::extrapolatedCalculatedType()
)
);
GradFieldType& lsGrad = tlsGrad.ref();
Field<GradType>& lsGradIf = lsGrad; Field<GradType>& lsGradIf = lsGrad;
const extendedCentredCellToCellStencil& stencil = lsv.stencil(); const extendedCentredCellToCellStencil& stencil = lsv.stencil();
@ -131,6 +109,50 @@ Foam::fv::LeastSquaresGrad<Type, Stencil>::calcGrad
// Correct the boundary conditions // Correct the boundary conditions
lsGrad.correctBoundaryConditions(); lsGrad.correctBoundaryConditions();
gaussGrad<Type>::correctBoundaryConditions(vtf, lsGrad); gaussGrad<Type>::correctBoundaryConditions(vtf, lsGrad);
}
template<class Type, class Stencil>
Foam::tmp
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::LeastSquaresGrad<Type, Stencil>::calcGrad
(
const GeometricField<Type, fvPatchField, volMesh>& vtf,
const word& name
) const
{
typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vtf.mesh();
tmp<GradFieldType> tlsGrad
(
new GradFieldType
(
IOobject
(
name,
vtf.instance(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
vtf.dimensions()/dimLength,
fvPatchFieldBase::extrapolatedCalculatedType()
)
);
GradFieldType& lsGrad = tlsGrad.ref();
calcGrad(lsGrad, vtf);
return tlsGrad; return tlsGrad;
} }

View File

@ -132,6 +132,14 @@ public:
const GeometricField<Type, fvPatchField, volMesh>& vsf, const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name const word& name
) const; ) const;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
}; };

View File

@ -38,19 +38,21 @@ License
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type> template<class Type>
Foam::tmp void Foam::fv::fourthGrad<Type>::calcGrad
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::fourthGrad<Type>::calcGrad
( (
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& fGrad,
const GeometricField<Type, fvPatchField, volMesh>& vsf, const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name const GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& secondfGrad
) const ) const
{ {
// The fourth-order gradient is calculated in two passes. First, // The fourth-order gradient is calculated in two passes. First,
@ -59,37 +61,11 @@ Foam::fv::fourthGrad<Type>::calcGrad
// gradient to complete the accuracy. // gradient to complete the accuracy.
typedef typename outerProduct<vector, Type>::type GradType; typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vsf.mesh(); const fvMesh& mesh = vsf.mesh();
// Assemble the second-order least-square gradient // Initialise to gradient
// Calculate the second-order least-square gradient fGrad = secondfGrad;
tmp<GradFieldType> tsecondfGrad
= leastSquaresGrad<Type>(mesh).grad
(
vsf,
"leastSquaresGrad(" + vsf.name() + ")"
);
const GradFieldType& secondfGrad =
tsecondfGrad();
tmp<GradFieldType> tfGrad
(
new GradFieldType
(
IOobject
(
name,
vsf.instance(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
secondfGrad
)
);
GradFieldType& fGrad = tfGrad.ref();
const vectorField& C = mesh.C(); const vectorField& C = mesh.C();
@ -158,9 +134,102 @@ Foam::fv::fourthGrad<Type>::calcGrad
fGrad.correctBoundaryConditions(); fGrad.correctBoundaryConditions();
gaussGrad<Type>::correctBoundaryConditions(vsf, fGrad); gaussGrad<Type>::correctBoundaryConditions(vsf, fGrad);
}
template<class Type>
Foam::tmp
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::fourthGrad<Type>::calcGrad
(
const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name
) const
{
// The fourth-order gradient is calculated in two passes. First,
// the standard least-square gradient is assembled. Then, the
// fourth-order correction is added to the second-order accurate
// gradient to complete the accuracy.
typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vsf.mesh();
// Assemble the second-order least-square gradient
// Calculate the second-order least-square gradient
tmp<GradFieldType> tsecondfGrad
= leastSquaresGrad<Type>(mesh).grad
(
vsf,
"leastSquaresGrad(" + vsf.name() + ")"
);
const GradFieldType& secondfGrad = tsecondfGrad();
tmp<GradFieldType> tfGrad
(
new GradFieldType
(
IOobject
(
name,
vsf.instance(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
vsf.dimensions()/dimLength,
fvPatchFieldBase::extrapolatedCalculatedType()
)
);
calcGrad(tfGrad.ref(), vsf, secondfGrad);
return tfGrad; return tfGrad;
} }
template<class Type>
void Foam::fv::fourthGrad<Type>::calcGrad
(
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& fGrad,
const GeometricField<Type, fvPatchField, volMesh>& vsf
) const
{
// The fourth-order gradient is calculated in two passes. First,
// the standard least-square gradient is assembled. Then, the
// fourth-order correction is added to the second-order accurate
// gradient to complete the accuracy.
typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vsf.mesh();
// Assemble the second-order least-square gradient
// Calculate the second-order least-square gradient
tmp<GradFieldType> tsecondfGrad
= leastSquaresGrad<Type>(mesh).grad
(
vsf,
"leastSquaresGrad(" + vsf.name() + ")"
);
calcGrad(fGrad, vsf, tsecondfGrad());
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -99,6 +99,32 @@ public:
const GeometricField<Type, fvPatchField, volMesh>& vsf, const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name const word& name
) const; ) const;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
//- Helper : calculate the grad of the given field into supplied field
void calcGrad
(
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& fGrad,
const GeometricField<Type, fvPatchField, volMesh>& vsf,
const GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& secondfGrad
) const;
}; };

View File

@ -140,6 +140,67 @@ Foam::fv::gaussGrad<Type>::calcGrad
} }
template<class Type>
void Foam::fv::gaussGrad<Type>::calcGrad
(
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& gGrad,
const GeometricField<Type, fvPatchField, volMesh>& vsf
) const
{
typedef typename outerProduct<vector, Type>::type GradType;
DebugPout<< "gaussGrad<Type>::calcGrad on " << vsf.name()
<< " into " << gGrad.name() << endl;
const fvMesh& mesh = vsf.mesh();
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
const vectorField& Sf = mesh.Sf();
const auto tssf(tinterpScheme_().interpolate(vsf));
const auto& ssf = tssf();
gGrad = dimensioned<GradType>(vsf.dimensions()/dimLength, Zero);
Field<GradType>& igGrad = gGrad;
const Field<Type>& issf = ssf;
forAll(owner, facei)
{
const GradType Sfssf = Sf[facei]*issf[facei];
igGrad[owner[facei]] += Sfssf;
igGrad[neighbour[facei]] -= Sfssf;
}
forAll(mesh.boundary(), patchi)
{
const labelUList& pFaceCells =
mesh.boundary()[patchi].faceCells();
const vectorField& pSf = mesh.Sf().boundaryField()[patchi];
const fvsPatchField<Type>& pssf = ssf.boundaryField()[patchi];
forAll(mesh.boundary()[patchi], facei)
{
igGrad[pFaceCells[facei]] += pSf[facei]*pssf[facei];
}
}
igGrad /= mesh.V();
gGrad.correctBoundaryConditions();
correctBoundaryConditions(vsf, gGrad);
}
template<class Type> template<class Type>
void Foam::fv::gaussGrad<Type>::correctBoundaryConditions void Foam::fv::gaussGrad<Type>::correctBoundaryConditions
( (

View File

@ -145,6 +145,14 @@ public:
const word& name const word& name
) const; ) const;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
//- Correct the boundary values of the gradient using the patchField //- Correct the boundary values of the gradient using the patchField
//- snGrad functions //- snGrad functions
static void correctBoundaryConditions static void correctBoundaryConditions

View File

@ -96,7 +96,7 @@ Foam::fv::gradScheme<Type>::grad
GradFieldType* pgGrad = GradFieldType* pgGrad =
mesh().objectRegistry::template getObjectPtr<GradFieldType>(name); mesh().objectRegistry::template getObjectPtr<GradFieldType>(name);
if (!this->mesh().cache(name) || this->mesh().changing()) if (!this->mesh().cache(name) || this->mesh().topoChanging())
{ {
// Delete any old occurrences to avoid double registration // Delete any old occurrences to avoid double registration
if (pgGrad && pgGrad->ownedByRegistry()) if (pgGrad && pgGrad->ownedByRegistry())
@ -119,17 +119,14 @@ Foam::fv::gradScheme<Type>::grad
} }
else else
{ {
if (pgGrad->upToDate(vsf)) if (pgGrad->upToDate(vsf) && this->mesh().upToDatePoints(*pgGrad))
{ {
solution::cachePrintMessage("Reusing", name, vsf); solution::cachePrintMessage("Reusing", name, vsf);
} }
else else
{ {
solution::cachePrintMessage("Updating", name, vsf); solution::cachePrintMessage("Updating", name, vsf);
delete pgGrad; calcGrad(*pgGrad, vsf);
pgGrad = calcGrad(vsf, name).ptr();
regIOobject::store(pgGrad);
} }
} }
@ -180,4 +177,23 @@ Foam::fv::gradScheme<Type>::grad
} }
template<class Type>
void Foam::fv::gradScheme<Type>::calcGrad
(
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& result,
const GeometricField<Type, fvPatchField, volMesh>& vsf
) const
{
DebugPout<< "gradScheme<Type>::calcGrad on " << vsf.name()
<< " into " << result.name() << endl;
result = calcGrad(vsf, result.name());
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -142,6 +142,14 @@ public:
const word& name const word& name
) const = 0; ) const = 0;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
//- Calculate and return the grad of the given field //- Calculate and return the grad of the given field
//- which may have been cached //- which may have been cached
tmp tmp

View File

@ -62,40 +62,25 @@ void Foam::fv::cellLimitedGrad<Type, Limiter>::limitGradient
template<class Type, class Limiter> template<class Type, class Limiter>
Foam::tmp void Foam::fv::cellLimitedGrad<Type, Limiter>::calcGrad
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::cellLimitedGrad<Type, Limiter>::calcGrad
( (
const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name
) const
{
const fvMesh& mesh = vsf.mesh();
tmp
<
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>
> tGrad = basicGradScheme_().calcGrad(vsf, name);
if (k_ < SMALL)
{
return tGrad;
}
GeometricField GeometricField
< <
typename outerProduct<vector, Type>::type, typename outerProduct<vector, Type>::type,
fvPatchField, fvPatchField,
volMesh volMesh
>& g = tGrad.ref(); >& g,
const GeometricField<Type, fvPatchField, volMesh>& vsf
) const
{
const fvMesh& mesh = vsf.mesh();
basicGradScheme_().calcGrad(g, vsf);
if (k_ < SMALL)
{
return;
}
const labelUList& owner = mesh.owner(); const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour(); const labelUList& neighbour = mesh.neighbour();
@ -227,6 +212,49 @@ Foam::fv::cellLimitedGrad<Type, Limiter>::calcGrad
limitGradient(limiter, g); limitGradient(limiter, g);
g.correctBoundaryConditions(); g.correctBoundaryConditions();
gaussGrad<Type>::correctBoundaryConditions(vsf, g); gaussGrad<Type>::correctBoundaryConditions(vsf, g);
}
template<class Type, class Limiter>
Foam::tmp
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::cellLimitedGrad<Type, Limiter>::calcGrad
(
const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name
) const
{
typedef typename outerProduct<vector, Type>::type GradType;
typedef GeometricField<GradType, fvPatchField, volMesh> GradFieldType;
const fvMesh& mesh = vsf.mesh();
tmp<GradFieldType> tGrad
(
new GradFieldType
(
IOobject
(
name,
vsf.instance(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
vsf.dimensions()/dimLength,
fvPatchFieldBase::extrapolatedCalculatedType()
)
);
calcGrad(tGrad.ref(), vsf);
return tGrad; return tGrad;
} }

View File

@ -150,6 +150,14 @@ public:
const GeometricField<Type, fvPatchField, volMesh>& vsf, const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name const word& name
) const; ) const;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
}; };

View File

@ -2984,6 +2984,77 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const fvMatrix<Type>& fvm)
} }
// * * * * * * * * * * * * * Expression Templates * * * * * * * * * * * * * //
template<class Type>
template<typename E>
Foam::fvMatrix<Type>::fvMatrix
(
const GeometricField<Type, fvPatchField, volMesh>& psi,
const Expression::fvMatrixExpression
<
E,
typename E::DiagExpr,
typename E::UpperExpr,
typename E::LowerExpr,
typename E::FaceFluxExpr,
typename E::SourceExpr
>& expr
)
:
lduMatrix(psi.mesh()),
psi_(psi),
useImplicit_(false),
lduAssemblyName_(),
nMatrix_(0),
dimensions_(expr.dimensions()),
source_(psi.size(), Zero),
internalCoeffs_(psi.mesh().boundary().size()),
boundaryCoeffs_(psi.mesh().boundary().size())
{
DebugInFunction
<< "Constructing fvMatrix<Type> from expression for field "
<< psi_.name() << endl;
checkImplicit();
// Fill in diag,upper,lower etc.
expr.evaluate(*this);
auto& psiRef = this->psi(0);
const label currentStatePsi = psiRef.eventNo();
psiRef.boundaryFieldRef().updateCoeffs();
psiRef.eventNo() = currentStatePsi;
}
template<class Type>
Foam::Expression::fvMatrixConstRefWrap<Foam::fvMatrix<Type>>
Foam::fvMatrix<Type>::expr() const
{
return Expression::fvMatrixConstRefWrap<Foam::fvMatrix<Type>>(*this);
}
template<class Type>
template<typename E>
void Foam::fvMatrix<Type>::operator=
(
const Expression::fvMatrixExpression
<
E,
typename E::DiagExpr,
typename E::UpperExpr,
typename E::LowerExpr,
typename E::FaceFluxExpr,
typename E::SourceExpr
>& expr
)
{
expr.evaluate(*this);
}
// * * * * * * * * * * * * * * * * Solvers * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Solvers * * * * * * * * * * * * * * * * * //
#include "fvMatrixSolve.C" #include "fvMatrixSolve.C"

View File

@ -53,6 +53,8 @@ SourceFiles
#include "lduPrimitiveMeshAssembly.H" #include "lduPrimitiveMeshAssembly.H"
#include "lduMesh.H" #include "lduMesh.H"
#include "fvMatrixExpression.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam namespace Foam
@ -741,6 +743,47 @@ public:
Ostream&, Ostream&,
const fvMatrix<Type>& const fvMatrix<Type>&
); );
// Expression templates
//- Construct given a field to solve for and expressions for
//- all the components
template<typename E>
fvMatrix
(
const GeometricField<Type, fvPatchField, volMesh>& psi,
const Expression::fvMatrixExpression
<
E,
typename E::DiagExpr,
typename E::UpperExpr,
typename E::LowerExpr,
typename E::FaceFluxExpr,
typename E::SourceExpr
>& expr
);
//- Wrap value as expression
typename Expression::fvMatrixConstRefWrap
<
fvMatrix<Type>
> expr() const;
//- Assign values from expression
template<typename E>
void operator=
(
const Expression::fvMatrixExpression
<
E,
typename E::DiagExpr,
typename E::UpperExpr,
typename E::LowerExpr,
typename E::FaceFluxExpr,
typename E::SourceExpr
>& expr
);
}; };

View File

@ -220,14 +220,9 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
labelRange& recvRequests,
PtrList<List<Type>>& sendBuffers, PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers, labelRange& recvRequests,
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
@ -237,14 +232,9 @@ public:
( (
fld, fld,
sendRequests, sendRequests,
recvRequests,
sendBuffers, sendBuffers,
recvBuffers, recvRequests,
recvBuffers
sendRequests1,
recvRequests1,
sendBuffers1,
recvBuffers1
); );
} }
@ -253,9 +243,7 @@ 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
@ -263,8 +251,6 @@ public:
localFld, localFld,
requests, requests,
recvBuffers, recvBuffers,
requests1,
recvBuffers1,
UList<Type>() UList<Type>()
); );
} }

View File

@ -226,6 +226,94 @@ Foam::fv::fusedGaussGrad<Type>::calcGrad
} }
template<class Type>
void Foam::fv::fusedGaussGrad<Type>::calcGrad
(
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& gGrad,
const GeometricField<Type, fvPatchField, volMesh>& vf
) const
{
typedef typename outerProduct<vector, Type>::type GradType;
const fvMesh& mesh = vf.mesh();
DebugPout<< "fusedGaussGrad<Type>::calcGrad on " << vf.name()
<< " into " << gGrad.name() << endl;
gGrad = dimensioned<GradType>(vf.dimensions()/dimLength, Zero);
if (this->tinterpScheme_().corrected())
{
const auto tfaceCorr(this->tinterpScheme_().correction(vf));
auto& faceCorr = tfaceCorr();
DebugPout<< "fusedGaussGrad<Type>::calcGrad corrected interpScheme "
<< this->tinterpScheme_().type() << endl;
const auto interpolate = [&]
(
const vector& area,
const scalar lambda,
const Type& ownVal,
const Type& neiVal,
const Type& correction
) -> GradType
{
return area*((lambda*(ownVal - neiVal) + neiVal) + correction);
};
fvc::surfaceSum
(
this->tinterpScheme_().weights(vf),
vf,
faceCorr,
interpolate,
gGrad,
false
);
}
else
{
DebugPout<< "fusedGaussGrad<Type>::calcGrad uncorrected interpScheme "
<< this->tinterpScheme_().type() << endl;
const auto interpolate = [&]
(
const vector& area,
const scalar lambda,
const Type& ownVal,
const Type& neiVal
) -> GradType
{
return area*(lambda*(ownVal - neiVal) + neiVal);
};
fvc::surfaceSum
(
tinterpScheme_().weights(vf),
vf,
interpolate,
gGrad,
false
);
}
gGrad.primitiveFieldRef() /= mesh.V();
gGrad.correctBoundaryConditions();
correctBoundaryConditions(vf, gGrad);
}
template<class Type> template<class Type>
template<class GradType> template<class GradType>
void Foam::fv::fusedGaussGrad<Type>::correctBoundaryConditions void Foam::fv::fusedGaussGrad<Type>::correctBoundaryConditions

View File

@ -145,6 +145,14 @@ public:
const word& name const word& name
) const; ) const;
//- Calculate the grad of the given field into supplied field
virtual void calcGrad
(
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>& res,
const GeometricField<Type, fvPatchField, volMesh>&
) const;
//- Correct the boundary values of the gradient using the patchField //- Correct the boundary values of the gradient using the patchField
//- snGrad functions //- snGrad functions
template<class GradType> template<class GradType>

View File

@ -45,6 +45,87 @@ namespace fv
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type, class GType>
template<class E1, class E2>
void fusedGaussLaplacianScheme<Type, GType>::fvmCorrection
(
fvMatrix<Type>& fvm,
const dimensionSet& gammaDim,
const E1& gammaMagSf,
const E2& corr
)
{
typedef GeometricField<Type, fvsPatchField, surfaceMesh> surfaceType;
const auto& vf = fvm.psi();
const fvMesh& mesh = vf.mesh();
const auto V = mesh.V().expr();
if (mesh.fluxRequired(vf.name()))
{
fvm.faceFluxCorrectionPtr() = std::make_unique<surfaceType>
(
IOobject
(
"faceFluxCorr",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
gammaDim
*mesh.magSf().dimensions()
*corr.data().dimensions()
);
auto& faceFluxCorr = *fvm.faceFluxCorrectionPtr();
faceFluxCorr = corr*gammaMagSf;
fvm.source() =
fvm.source().expr()
- (
fvc::div
(
faceFluxCorr
)().primitiveField().expr()
*V
);
}
else
{
surfaceType faceFluxCorr
(
IOobject
(
"faceFluxCorr",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
mesh,
gammaDim
*mesh.magSf().dimensions()
*corr.data().dimensions()
);
faceFluxCorr = corr*gammaMagSf;
fvm.source() =
fvm.source().expr()
- (
fvc::div
(
faceFluxCorr
)().primitiveField().expr()
*V
);
}
}
template<class Type, class GType> template<class Type, class GType>
tmp<fvMatrix<Type>> tmp<fvMatrix<Type>>
fusedGaussLaplacianScheme<Type, GType>::fvmLaplacianUncorrected fusedGaussLaplacianScheme<Type, GType>::fvmLaplacianUncorrected

View File

@ -65,6 +65,17 @@ class fusedGaussLaplacianScheme
{ {
// Private Member Functions // Private Member Functions
//- Helper for calculate source correction. Partially expression
// templated. Move to fvMatrixExpression.H?
template<class E1, class E2>
static void fvmCorrection
(
fvMatrix<Type>& fvm,
const dimensionSet& gammaDim,
const E1& gammaMagSf,
const E2& corr
);
//- See gaussLaplacianScheme //- See gaussLaplacianScheme
tmp<GeometricField<Type, fvsPatchField, surfaceMesh>> gammaSnGradCorr tmp<GeometricField<Type, fvsPatchField, surfaceMesh>> gammaSnGradCorr
( (
@ -198,6 +209,8 @@ defineFvmLaplacianScalarGamma(sphericalTensor);
defineFvmLaplacianScalarGamma(symmTensor); defineFvmLaplacianScalarGamma(symmTensor);
defineFvmLaplacianScalarGamma(tensor); defineFvmLaplacianScalarGamma(tensor);
#undef defineFvmLaplacianScalarGamma
// Unweighted laplacian // Unweighted laplacian
template<> template<>
tmp<GeometricField<scalar, fvPatchField, volMesh>> tmp<GeometricField<scalar, fvPatchField, volMesh>>
@ -227,20 +240,6 @@ fusedGaussLaplacianScheme<vector, scalar>::fvcLaplacian
const GeometricField<scalar, fvPatchField, volMesh>&, const GeometricField<scalar, fvPatchField, volMesh>&,
const GeometricField<vector, fvPatchField, volMesh>& const GeometricField<vector, fvPatchField, volMesh>&
); );
template<>
tmp<fvMatrix<scalar>>
fusedGaussLaplacianScheme<scalar, scalar>::fvmLaplacian
(
const GeometricField<scalar, fvPatchField, volMesh>&,
const GeometricField<scalar, fvPatchField, volMesh>&
);
template<>
tmp<fvMatrix<vector>>
fusedGaussLaplacianScheme<vector, scalar>::fvmLaplacian
(
const GeometricField<scalar, fvPatchField, volMesh>&,
const GeometricField<vector, fvPatchField, volMesh>&
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -28,6 +28,7 @@ License
#include "fusedGaussLaplacianScheme.H" #include "fusedGaussLaplacianScheme.H"
#include "fvMesh.H" #include "fvMesh.H"
#include "fvMatrixExpression.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -40,61 +41,81 @@ Foam::tmp<Foam::fvMatrix<Foam::Type>> \
Foam::fv::fusedGaussLaplacianScheme<Foam::Type, Foam::scalar>:: \ Foam::fv::fusedGaussLaplacianScheme<Foam::Type, Foam::scalar>:: \
fvmLaplacian \ fvmLaplacian \
( \ ( \
const GeometricField<scalar, fvsPatchField, surfaceMesh>& gamma, \ const GeometricField<scalar, fvPatchField, volMesh>& gamma, \
const GeometricField<Type, fvPatchField, volMesh>& vf \ const GeometricField<Type, fvPatchField, volMesh>& vf \
) \ ) \
{ \ { \
DebugPout<< "fusedGaussLaplacianScheme::fvmLaplacian on " << vf.name() \ DebugPout<< "fusedGaussLaplacianScheme::fvmLaplacian on " << vf.name() \
<< " with scalar gamma " << gamma.name() << endl; \ << " with scalar gamma " << gamma.name() << " and ET" << endl; \
\ \
const fvMesh& mesh = this->mesh(); \ const fvMesh& mesh = this->mesh(); \
\ \
GeometricField<scalar, fvsPatchField, surfaceMesh> gammaMagSf \ const auto weights = this->tinterpGammaScheme_().weights(gamma).expr(); \
( \ const auto gammaMagSf = \
gamma*mesh.magSf() \ Expression::interpolate(gamma.expr(), weights, mesh) \
); \ * mesh.magSf().expr(); \
/* For compatibility with linearInterpolate : avoid orientation. TBD. */ \
const_cast<orientedType&>(gammaMagSf.oriented()).setOriented(false); \
const auto deltaCoeffs = this->tsnGradScheme_().deltaCoeffs(vf).expr(); \
\ \
tmp<fvMatrix<Type>> tfvm = fvmLaplacianUncorrected \ tmp<fvMatrix<Type>> tfvm \
( \ ( \
gammaMagSf, \ new fvMatrix<Type> \
this->tsnGradScheme_().deltaCoeffs(vf), \ ( \
vf \ vf, \
gamma.dimensions()*mesh.magSf().dimensions()*vf.dimensions() \
) \
); \ ); \
fvMatrix<Type>& fvm = tfvm.ref(); \ fvMatrix<Type>& fvm = tfvm.ref(); \
\ \
Expression::fvmLaplacianUncorrected(fvm, gammaMagSf, deltaCoeffs); \
\
if (this->tsnGradScheme_().corrected()) \ if (this->tsnGradScheme_().corrected()) \
{ \ { \
if (mesh.fluxRequired(vf.name())) \ const auto corr(this->tsnGradScheme_().correction(vf).expr()); \
{ \ fvmCorrection(fvm, gamma.dimensions(), gammaMagSf, corr); \
fvm.faceFluxCorrectionPtr() = std::make_unique \
< \
GeometricField<Type, fvsPatchField, surfaceMesh> \
> \
( \
gammaMagSf*this->tsnGradScheme_().correction(vf) \
); \
\
fvm.source() -= \
mesh.V()* \
fvc::div \
( \
*fvm.faceFluxCorrectionPtr() \
)().primitiveField(); \
} \
else \
{ \
fvm.source() -= \
mesh.V()* \
fvc::div \
( \
gammaMagSf*this->tsnGradScheme_().correction(vf) \
)().primitiveField(); \
} \
} \ } \
\ \
return tfvm; \ return tfvm; \
} \ } \
\ \
template<> \
Foam::tmp<Foam::fvMatrix<Foam::Type>> \
Foam::fv::fusedGaussLaplacianScheme<Foam::Type, Foam::scalar>:: \
fvmLaplacian \
( \
const GeometricField<scalar, fvsPatchField, surfaceMesh>& gamma, \
const GeometricField<Type, fvPatchField, volMesh>& vf \
) \
{ \
DebugPout<< "fusedGaussLaplacianScheme::fvmLaplacian on " << vf.name() \
<< " with interpolated gamma " << gamma.name() << " and ET" << endl; \
\
const fvMesh& mesh = this->mesh(); \
\
const auto gammaMagSf = gamma.expr()* mesh.magSf().expr(); \
const auto deltaCoeffs = this->tsnGradScheme_().deltaCoeffs(vf).expr(); \
\
tmp<fvMatrix<Type>> tfvm \
( \
new fvMatrix<Type> \
( \
vf, \
gamma.dimensions()*mesh.magSf().dimensions()*vf.dimensions() \
) \
); \
fvMatrix<Type>& fvm = tfvm.ref(); \
\
Expression::fvmLaplacianUncorrected(fvm, gammaMagSf, deltaCoeffs); \
\
if (this->tsnGradScheme_().corrected()) \
{ \
const auto corr(this->tsnGradScheme_().correction(vf).expr()); \
fvmCorrection(fvm, gamma.dimensions(), gammaMagSf, corr); \
} \
\
return tfvm; \
} \
\ \
template<> \ template<> \
Foam::tmp<Foam::GeometricField<Foam::Type, Foam::fvPatchField, Foam::volMesh>> \ Foam::tmp<Foam::GeometricField<Foam::Type, Foam::fvPatchField, Foam::volMesh>> \
@ -500,38 +521,6 @@ Foam::fv::fusedGaussLaplacianScheme<Foam::vector, Foam::scalar>::fvcLaplacian
} }
template<>
Foam::tmp<Foam::fvMatrix<Foam::scalar>>
Foam::fv::fusedGaussLaplacianScheme<Foam::scalar, Foam::scalar>::fvmLaplacian
(
const GeometricField<scalar, fvPatchField, volMesh>& gamma,
const GeometricField<scalar, fvPatchField, volMesh>& vf
)
{
// TBD
DebugPout
<< "fusedGaussLaplacianScheme<scalar, scalar>::fvmLaplacian"
<< " on " << vf.name() << " with gamma " << gamma.name() << endl;
return fvmLaplacian(this->tinterpGammaScheme_().interpolate(gamma)(), vf);
}
template<>
Foam::tmp<Foam::fvMatrix<Foam::vector>>
Foam::fv::fusedGaussLaplacianScheme<Foam::vector, Foam::scalar>::fvmLaplacian
(
const GeometricField<scalar, fvPatchField, volMesh>& gamma,
const GeometricField<vector, fvPatchField, volMesh>& vf
)
{
// TBD
DebugPout
<< "fusedGaussLaplacianScheme<vector, scalar>::fvmLaplacian"
<< " on " << vf.name() << " with gamma " << gamma.name() << endl;
return fvmLaplacian(this->tinterpGammaScheme_().interpolate(gamma)(), vf);
}
template<> template<>
Foam::tmp Foam::tmp
< <

View File

@ -251,23 +251,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2018-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -443,41 +443,6 @@ 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

@ -1,651 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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

@ -1,388 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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

@ -1,63 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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,26 +61,11 @@ 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(const primitivePatch &patch) const Foam::AMIInterpolation::createTree
(
const primitivePatch& patch
) const
{ {
treeBoundBox bb(patch.points(), patch.meshPoints()); treeBoundBox bb(patch.points(), patch.meshPoints());
bb.inflate(0.01); bb.inflate(0.01);
@ -715,8 +700,7 @@ Foam::AMIInterpolation::AMIInterpolation
tgtWeightsSum_(), tgtWeightsSum_(),
tgtCentroids_(), tgtCentroids_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false), upToDate_(false)
cache_(dict)
{} {}
@ -746,8 +730,7 @@ Foam::AMIInterpolation::AMIInterpolation
tgtCentroids_(), tgtCentroids_(),
tgtPatchPts_(), tgtPatchPts_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false), upToDate_(false)
cache_()
{} {}
@ -760,7 +743,7 @@ Foam::AMIInterpolation::AMIInterpolation
: :
requireMatch_(fineAMI.requireMatch_), requireMatch_(fineAMI.requireMatch_),
reverseTarget_(fineAMI.reverseTarget_), reverseTarget_(fineAMI.reverseTarget_),
lowWeightCorrection_(-1.0), // Deactivated? lowWeightCorrection_(-1.0),
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_(),
@ -776,17 +759,16 @@ Foam::AMIInterpolation::AMIInterpolation
tgtWeightsSum_(), tgtWeightsSum_(),
tgtPatchPts_(), tgtPatchPts_(),
tgtMapPtr_(nullptr), tgtMapPtr_(nullptr),
upToDate_(false), upToDate_(false)
cache_(fineAMI.cache(), fineAMI, sourceRestrictAddressing, targetRestrictAddressing)
{ {
const label sourceCoarseSize = label sourceCoarseSize =
( (
sourceRestrictAddressing.size() sourceRestrictAddressing.size()
? max(sourceRestrictAddressing)+1 ? max(sourceRestrictAddressing)+1
: 0 : 0
); );
const label neighbourCoarseSize = label neighbourCoarseSize =
( (
targetRestrictAddressing.size() targetRestrictAddressing.size()
? max(targetRestrictAddressing)+1 ? max(targetRestrictAddressing)+1
@ -913,15 +895,14 @@ 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_(ami.srcMapPtr_.clone()), srcMapPtr_(nullptr),
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_(ami.tgtMapPtr_.clone()), tgtMapPtr_(nullptr),
upToDate_(ami.upToDate_), upToDate_(false)
cache_(ami.cache_)
{} {}
@ -949,9 +930,7 @@ 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?
@ -1382,6 +1361,7 @@ const
} }
else if (ray.distance() < nearest.distance()) else if (ray.distance() < nearest.distance())
{ {
nearest = ray; nearest = ray;
nearestFacei = srcFacei; nearestFacei = srcFacei;
} }
@ -1559,8 +1539,6 @@ void Foam::AMIInterpolation::write(Ostream& os) const
{ {
os.writeEntry("lowWeightCorrection", lowWeightCorrection_); os.writeEntry("lowWeightCorrection", lowWeightCorrection_);
} }
cache_.write(os);
} }
@ -1586,8 +1564,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2016-2024 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,7 +78,6 @@ 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
@ -87,10 +86,6 @@ 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:
@ -150,6 +145,7 @@ protected:
autoPtr<mapDistribute> srcMapPtr_; autoPtr<mapDistribute> srcMapPtr_;
// Target patch // Target patch
//- Target face areas //- Target face areas
@ -177,13 +173,9 @@ 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
@ -220,10 +212,10 @@ protected:
// Access // Access
//- Return the original src patch with optionally updated points //- Return the orginal src patch with optionally updated points
inline const primitivePatch& srcPatch0() const; inline const primitivePatch& srcPatch0() const;
//- Return the original tgt patch with optionally updated points //- Return the orginal tgt patch with optionally updated points
inline const primitivePatch& tgtPatch0() const; inline const primitivePatch& tgtPatch0() const;
@ -248,6 +240,27 @@ 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
@ -353,26 +366,6 @@ 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?
@ -386,10 +379,6 @@ 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;
@ -422,8 +411,6 @@ 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
@ -544,8 +531,7 @@ public:
// Low-level // Low-level
//- Weighted sum of contributions. Note: cop operates on //- Weighted sum of contributions
//- single Type only.
template<class Type, class CombineOp> template<class Type, class CombineOp>
static void weightedSum static void weightedSum
( (
@ -559,35 +545,20 @@ public:
const UList<Type>& defaultValues const UList<Type>& defaultValues
); );
//- Weighted sum of contributions (includes caching+interp) //- Weighted sum of contributions
//- (for primitive types only)
template<class Type> template<class Type>
void weightedSum void weightedSum
( (
const bool toSource, const bool interpolateToSource,
const UList<Type>& fld, const UList<Type>& fld,
List<Type>& result, List<Type>& result,
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const; ) const;
//- Weighted sum of (potentially distributed) contributions //- Interpolate from target to source with supplied op
//- 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 interpolateToTarget void interpolateToSource
( (
const UList<Type>& fld, const UList<Type>& fld,
const CombineOp& cop, const CombineOp& cop,
@ -595,10 +566,10 @@ public:
const UList<Type>& defaultValues = UList<Type>::null() const UList<Type>& defaultValues = UList<Type>::null()
) const; ) const;
//- Interpolate from target to source with supplied op //- 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,
@ -700,12 +671,6 @@ 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,12 +123,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2015-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -83,19 +83,18 @@ void Foam::AMIInterpolation::weightedSum
template<class Type> template<class Type>
void Foam::AMIInterpolation::weightedSum void Foam::AMIInterpolation::weightedSum
( (
const bool toSource, const bool interpolateToSource,
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_,
(toSource ? srcAddress_ : tgtAddress_), (interpolateToSource ? srcAddress_ : tgtAddress_),
(toSource ? srcWeights_ : tgtWeights_), (interpolateToSource ? srcWeights_ : tgtWeights_),
(toSource ? srcWeightsSum_ : tgtWeightsSum_), (interpolateToSource ? srcWeightsSum_ : tgtWeightsSum_),
fld, fld,
multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()), multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()),
result, result,
@ -104,223 +103,6 @@ void Foam::AMIInterpolation::weightedSum
} }
template<class Type, class CombineOp, class InterpolateOp>
void Foam::AMIInterpolation::interpolate
(
const bool toSource,
const UList<Type>& fld,
const CombineOp& cop,
const InterpolateOp& iop,
List<Type>& result,
const UList<Type>& defaultValues
) const
{
// 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)
// 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
<< "Supplied field size is not equal to "
<< (toSource ? "target" : "source") << " patch size" << nl
<< " source patch = " << srcAddr.size() << nl
<< " target patch = " << tgtAddr.size() << nl
<< " supplied field = " << fld.size()
<< abort(FatalError);
}
else if
(
(lowWeightCorrection_ > 0) && (defVals.size() != srcAddr.size())
)
{
FatalErrorInFunction
<< "Employing default values when sum of weights falls below "
<< lowWeightCorrection_
<< " but number of default values is not equal to "
<< (toSource ? "source" : "target") << " patch size" << nl
<< " default values = " << defVals.size() << nl
<< " source patch = " << srcAddr.size() << nl
<< abort(FatalError);
}
};
// Work space for if distributed
List<Type> work;
List<Type> result0;
if (cache_.index0() != -1)
{
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)
{
return;
}
work.resize_nocopy(map.constructSize());
SubList<Type>(work, fld.size()) = fld; // deep copy
map.distribute(work);
}
// if constexpr (is_contiguous_scalar<Type>::value)
// {
// result0 = Zero;
// }
weightedSum
(
lowWeightCorrection_,
srcAddress,
srcWeights,
srcWeightsSum,
(distributed() ? work : fld),
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> template<class Type, class CombineOp>
void Foam::AMIInterpolation::interpolateToTarget void Foam::AMIInterpolation::interpolateToTarget
( (
@ -330,31 +112,58 @@ void Foam::AMIInterpolation::interpolateToTarget
const UList<Type>& defaultValues const UList<Type>& defaultValues
) const ) const
{ {
// In-place interpolation
addProfiling(ami, "AMIInterpolation::interpolateToTarget"); addProfiling(ami, "AMIInterpolation::interpolateToTarget");
// Wrap lerp operator to operate inplace if (fld.size() != srcAddress_.size())
auto iop = [&] {
FatalErrorInFunction
<< "Supplied field size is not equal to source patch size" << nl
<< " source patch = " << srcAddress_.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< " supplied field = " << fld.size()
<< abort(FatalError);
}
else if
( (
Type& res, (lowWeightCorrection_ > 0)
const label i, && (defaultValues.size() != tgtAddress_.size())
const label ia,
const Type& a,
const label ib,
const Type& b,
const scalar w
) )
{ {
res = lerp(a, b, w); FatalErrorInFunction
}; << "Employing default values when sum of weights falls below "
<< lowWeightCorrection_
<< " but supplied default field size is not equal to target "
<< "patch size" << nl
<< " default values = " << defaultValues.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< abort(FatalError);
}
interpolate result.setSize(tgtAddress_.size());
List<Type> work;
if (distributed() && srcMapPtr_)
{
const mapDistribute& map = srcMapPtr_();
if (map.comm() == -1)
{
return;
}
work.resize_nocopy(map.constructSize());
SubList<Type>(work, fld.size()) = fld; // deep copy
map.distribute(work);
}
weightedSum
( (
false, // interpolate to target lowWeightCorrection_,
fld, tgtAddress_,
tgtWeights_,
tgtWeightsSum_,
(distributed() ? work : fld),
cop, cop,
iop,
result, result,
defaultValues defaultValues
); );
@ -370,32 +179,58 @@ 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");
// Wrap lerp operator to operate inplace if (fld.size() != tgtAddress_.size())
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
( (
Type& res, (lowWeightCorrection_ > 0)
const label i, && (defaultValues.size() != srcAddress_.size())
const label ia,
const Type& a,
const label ib,
const Type& b,
const scalar w
) )
{ {
res = lerp(a, b, w); FatalErrorInFunction
}; << "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;
interpolate if (distributed() && tgtMapPtr_)
{
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
( (
true, // toSource, lowWeightCorrection_,
fld, srcAddress_,
srcWeights_,
srcWeightsSum_,
(distributed() ? work : fld),
cop, cop,
iop,
result, result,
defaultValues defaultValues
); );

View File

@ -67,7 +67,9 @@ 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);
@ -87,7 +89,9 @@ 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_()
{} {}
@ -100,7 +104,9 @@ 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_()
{} {}
@ -114,7 +120,9 @@ 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);
@ -134,15 +142,9 @@ 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
( (
@ -151,15 +153,9 @@ 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;
@ -214,9 +210,15 @@ 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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -224,63 +226,22 @@ void Foam::cyclicACMIGAMGInterfaceField::initInterfaceMatrixUpdate
<< abort(FatalError); << abort(FatalError);
} }
const auto& cache = AMI.cache(); // Assume that sends are also OK
sendRequests_.clear();
if (cache.index0() == -1 && cache.index1() == -1) // Insert send/receive requests (non-blocking). See e.g.
{ // cyclicAMIPolyPatchTemplates.C
const auto& map = const label oldWarnComm = UPstream::commWarn(AMI.comm());
( map.send
cyclicACMIInterface_.owner() (
? AMI.tgtMap() pnf,
: AMI.srcMap() sendRequests_,
); scalarSendBufs_,
recvRequests_,
// Insert send/receive requests (non-blocking). See e.g. scalarRecvBufs_,
// cyclicAMIPolyPatchTemplates.C 19462+cyclicACMIInterface_.index() // unique offset + patch index
const label oldWarnComm = UPstream::commWarn(AMI.comm()); );
map.send UPstream::commWarn(oldWarnComm);
(
pnf,
sendRequests_,
scalarSendBufs_,
recvRequests_,
scalarRecvBufs_,
19462+cyclicACMIInterface_.index() // unique offset + patch index
);
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);
@ -299,8 +260,6 @@ 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 =
@ -310,122 +269,48 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
: cyclicACMIInterface_.neighbPatch().AMI() : cyclicACMIInterface_.neighbPatch().AMI()
); );
const auto& cache = AMI.cache(); DebugPout<< "cyclicACMIGAMGInterfaceField::updateInterfaceMatrix() :"
<< " 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 = cyclicACMIInterface_.owner()
( ? AMI.tgtMap()
cyclicACMIInterface_.owner() : AMI.srcMap()
? AMI.tgtMap() );
: AMI.srcMap()
);
// Receive (= copy) data from buffers into work. TBD: receive directly // Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work. // into slices of work.
solveScalarField work; solveScalarField work;
map.receive map.receive
( (
recvRequests_, recvRequests_,
scalarRecvBufs_, scalarRecvBufs_,
work, work,
19462+cyclicACMIInterface_.index() // unique offset + patch index 19462+cyclicACMIInterface_.index() // unique offset + patch index
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
solveScalarField pnf(faceCells.size(), Zero); solveScalarField pnf(faceCells.size(), Zero);
AMI.weightedSum AMI.weightedSum
( (
cyclicACMIInterface_.owner(), cyclicACMIInterface_.owner(),
work, work,
pnf, // result pnf, // result
solveScalarField::null() solveScalarField::null()
); );
// 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(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 else
{ {
@ -433,73 +318,23 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
const labelUList& nbrFaceCells = const labelUList& nbrFaceCells =
lduAddr.patchAddr(cyclicACMIInterface_.neighbPatchID()); lduAddr.patchAddr(cyclicACMIInterface_.neighbPatchID());
solveScalarField work(psiInternal, nbrFaceCells); solveScalarField pnf(psiInternal, nbrFaceCells);
// Transform according to the transformation tensors // Transform according to the transformation tensors
transformCoupleField(work, cmpt); transformCoupleField(pnf, cmpt);
if (cache.index0() == -1 && cache.index1() == -1) if (cyclicACMIInterface_.owner())
{ {
solveScalarField pnf(faceCells.size(), Zero); pnf = AMI.interpolateToSource(pnf);
AMI.weightedSum
(
cyclicACMIInterface_.owner(),
work,
pnf, // result
solveScalarField::null()
);
const labelUList& faceCells = lduAddr.patchAddr(patchId);
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
else else
{ {
cache.setDirection(cyclicACMIInterface_.owner()); pnf = AMI.interpolateToTarget(pnf);
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);
}
} }
const labelUList& faceCells = lduAddr.patchAddr(patchId);
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
} }
this->updatedMatrix(true); this->updatedMatrix(true);

View File

@ -83,20 +83,6 @@ 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,7 +67,9 @@ 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);
@ -87,7 +89,9 @@ 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_()
{} {}
@ -100,7 +104,9 @@ 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_()
{} {}
@ -114,7 +120,9 @@ 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);
@ -134,15 +142,9 @@ 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
( (
@ -151,15 +153,9 @@ 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;
@ -187,6 +183,7 @@ 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() :"
@ -214,8 +211,15 @@ 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() || !recvRequests1_.empty()) if (!recvRequests_.empty())
{ {
FatalErrorInFunction FatalErrorInFunction
<< "Outstanding recv request(s) on patch " << "Outstanding recv request(s) on patch "
@ -223,63 +227,22 @@ void Foam::cyclicAMIGAMGInterfaceField::initInterfaceMatrixUpdate
<< abort(FatalError); << abort(FatalError);
} }
const auto& cache = AMI.cache(); // Assume that sends are also OK
sendRequests_.clear();
if (cache.index0() == -1 && cache.index1() == -1) // Insert send/receive requests (non-blocking). See e.g.
{ // cyclicAMIPolyPatchTemplates.C
const auto& map = const label oldWarnComm = UPstream::commWarn(AMI.comm());
( map.send
cyclicAMIInterface_.owner() (
? AMI.tgtMap() pnf,
: AMI.srcMap() sendRequests_,
); scalarSendBufs_,
recvRequests_,
// Insert send/receive requests (non-blocking). See e.g. scalarRecvBufs_,
// cyclicAMIPolyPatchTemplates.C 19462+cyclicAMIInterface_.index() // unique offset + patch index
const label oldWarnComm = UPstream::commWarn(AMI.comm()); );
map.send UPstream::commWarn(oldWarnComm);
(
pnf,
sendRequests_,
scalarSendBufs_,
recvRequests_,
scalarRecvBufs_,
19462+cyclicAMIInterface_.index() // unique offset + patch index
);
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);
@ -298,8 +261,6 @@ 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 =
@ -323,12 +284,6 @@ 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)
@ -338,118 +293,38 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
<< exit(FatalError); << exit(FatalError);
} }
if (cache.index0() == -1 && cache.index1() == -1) const auto& map =
{ (
const auto& map = cyclicAMIInterface_.owner()
( ? AMI.tgtMap()
cyclicAMIInterface_.owner() : AMI.srcMap()
? AMI.tgtMap() );
: AMI.srcMap()
);
// Receive (= copy) data from buffers into work. TBD: receive directly // Receive (= copy) data from buffers into work. TBD: receive directly
// into slices of work. // into slices of work.
solveScalarField work; solveScalarField work;
map.receive map.receive
( (
recvRequests_, recvRequests_,
scalarRecvBufs_, scalarRecvBufs_,
work, work,
19462+cyclicAMIInterface_.index() // unique offset + patch index 19462+cyclicAMIInterface_.index() // unique offset + patch index
); );
// Receive requests all handled by last function call // Receive requests all handled by last function call
recvRequests_.clear(); recvRequests_.clear();
solveScalarField pnf(faceCells.size(), Zero); solveScalarField pnf(faceCells.size(), Zero);
AMI.weightedSum AMI.weightedSum
( (
cyclicAMIInterface_.owner(), cyclicAMIInterface_.owner(),
work, work,
pnf, // result pnf, // result
defaultValues defaultValues
); );
// 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());
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 else
{ {
@ -462,68 +337,17 @@ 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()); solveScalarField pnf(faceCells.size(), Zero);
AMI.weightedSum
(
cyclicAMIInterface_.owner(),
work,
pnf, // result
defaultValues
);
if (cache.index0() == -1 && cache.index1() == -1) // Add result using coefficients
{ this->addToInternalField(result, !add, faceCells, coeffs, pnf);
pnf = Zero;
AMI.weightedSum
(
cyclicAMIInterface_.owner(),
work,
pnf, // result
defaultValues
);
// Add result using coefficients
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,21 +83,6 @@ 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,46 +381,6 @@ 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());
@ -472,7 +432,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(), srcPoints); meshTools::writeOBJ(osO, this->localFaces(), localPoints());
} }
// Construct/apply AMI interpolation to determine addressing and weights // Construct/apply AMI interpolation to determine addressing and weights
@ -486,8 +446,6 @@ 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 across AMI //- Particle displacement fraction accross AMI
const scalar fraction_; const scalar fraction_;
@ -166,9 +166,6 @@ 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
@ -523,14 +520,9 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
labelRange& recvRequests,
PtrList<List<Type>>& sendBuffers, PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const; ) const;
template<class Type> template<class Type>
@ -538,14 +530,9 @@ public:
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
labelRange& recvRequests,
PtrList<List<Type>>& sendBuffers, PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers, labelRange& recvRequests,
PtrList<List<Type>>& recvBuffers
labelRange& sendRequests1,
labelRange& recvRequests1,
PtrList<List<Type>>& sendBuffers1,
PtrList<List<Type>>& recvBuffers1
) const; ) const;
template<class Type> template<class Type>
@ -554,8 +541,6 @@ 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,7 +63,6 @@ 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());
} }
@ -131,7 +130,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() != 0 && defaultValues.size() == size()) if (defaultValues.size() == size())
{ {
// Transform default values into cylindrical coords (using // Transform default values into cylindrical coords (using
// *this faceCentres) // *this faceCentres)
@ -177,77 +176,27 @@ void Foam::cyclicAMIPolyPatch::initInterpolateUntransformed
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
labelRange& recvRequests,
PtrList<List<Type>>& sendBuffers, PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers, labelRange& recvRequests,
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(); const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap());
if (cache.index0() == -1 && cache.index1() == -1) // Insert send/receive requests (non-blocking)
{ map.send
// No caching (
fld,
const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap()); sendRequests,
sendBuffers,
// Insert send/receive requests (non-blocking) recvRequests,
map.send recvBuffers,
( 3894+this->index() // unique offset + patch index
fld, );
sendRequests,
sendBuffers,
recvRequests,
recvBuffers,
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
);
}
}
} }
} }
@ -257,14 +206,9 @@ void Foam::cyclicAMIPolyPatch::initInterpolate
( (
const Field<Type>& fld, const Field<Type>& fld,
labelRange& sendRequests, labelRange& sendRequests,
labelRange& recvRequests,
PtrList<List<Type>>& sendBuffers, PtrList<List<Type>>& sendBuffers,
PtrList<List<Type>>& recvBuffers, labelRange& recvRequests,
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());
@ -277,50 +221,46 @@ 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)
{ {
// Only creates the co-ord system if using periodic AMI cs.reset(cylindricalCS());
// - convert to cylindrical coordinate system
auto cs = cylindricalCS();
if (cs)
{
Field<Type> localFld(fld.size());
const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
const tensorField nbrT(cs().R(nbrPp.faceCentres()));
Foam::invTransform(localFld, nbrT, fld);
initInterpolateUntransformed
(
localFld,
sendRequests,
recvRequests,
sendBuffers,
recvBuffers,
sendRequests1,
recvRequests1,
sendBuffers1,
recvBuffers1
);
return;
}
} }
initInterpolateUntransformed if (!cs)
( {
fld, initInterpolateUntransformed
sendRequests, (
recvRequests, fld,
sendBuffers, sendRequests,
recvBuffers, sendBuffers,
recvRequests,
recvBuffers
);
}
else if constexpr (transform_supported)
{
const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
sendRequests1, Field<Type> localFld(fld.size());
recvRequests1,
sendBuffers1, // Transform to cylindrical coords
recvBuffers1 {
); const tensorField nbrT(cs().R(nbrPp.faceCentres()));
Foam::invTransform(localFld, nbrT, fld);
}
initInterpolateUntransformed
(
localFld,
sendRequests,
sendBuffers,
recvRequests,
recvBuffers
);
}
} }
@ -330,21 +270,14 @@ 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)
@ -352,157 +285,71 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
return tresult; return tresult;
} }
if (cache.index0() == -1 && cache.index1() == -1) const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap());
{
// No caching
const auto& map = (owner() ? AMI.tgtMap() : AMI.srcMap());
// Receive (= copy) data from buffers into work. TBD: receive // Receive (= copy) data from buffers into work. TBD: receive directly
// directly into slices of work. // into slices of work.
map.receive map.receive
( (
requests, requests,
recvBuffers, recvBuffers,
work, work,
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>;
// Rotate fields (vector and non-spherical tensors) for periodic AMI [[maybe_unused]]
tensorField ownTransform; autoPtr<coordSystem::cylindrical> cs;
Field<Type> localDeflt;
// Rotate fields (vector and non-spherical tensors)
if constexpr (transform_supported) if constexpr (transform_supported)
{ {
// Only creates the co-ord system if using periodic AMI cs.reset(cylindricalCS());
// - convert to cylindrical coordinate system
auto cs = cylindricalCS();
if (cs)
{
ownTransform = cs().R(this->faceCentres());
localDeflt = defaultValues;
if (defaultValues.size() == size())
{
// Transform default values into cylindrical coords (using
// *this faceCentres)
// We get in UList (why? Copied from cyclicAMI). Convert to
// Field so we can use transformField routines.
const SubField<Type> defaultSubFld(defaultValues);
const Field<Type>& defaultFld(defaultSubFld);
Foam::invTransform(localDeflt, ownTransform, defaultFld);
}
}
} }
const auto& localDefaultValues = if (!cs)
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(),
localDefaultValues defaultValues
);
}
else if constexpr (transform_supported)
{
const tensorField ownT(cs().R(this->faceCentres()));
Field<Type> localDeflt(defaultValues.size());
if (defaultValues.size() == size())
{
// Transform default values into cylindrical coords (using
// *this faceCentres)
// We get in UList (why? Copied from cyclicAMI). Convert to
// Field so we can use transformField routines.
const SubField<Type> defaultSubFld(defaultValues);
const Field<Type>& defaultFld(defaultSubFld);
Foam::invTransform(localDeflt, ownT, defaultFld);
}
AMI.weightedSum
(
owner(),
fld,
tresult.ref(),
localDeflt
); );
// Transform back // Transform back
if (ownTransform.size()) Foam::transform(tresult.ref(), ownT, tresult());
{
Foam::transform(tresult.ref(), ownTransform, 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()) return tresult;
{
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;
}
} }

View File

@ -281,7 +281,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2018-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -95,102 +95,6 @@ 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()
);
}
}
};
} }
@ -880,43 +784,18 @@ 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())
{ {
const List<Type> defVals 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
{ {
AMI.interpolate cycPatch.interpolate(sendInfo, cmb, receiveInfo);
(
cycPatch.owner(),
sendInfo,
cmb,
interp,
receiveInfo,
UList<Type>::null() // no default values needed
);
} }
} }

View File

@ -197,23 +197,6 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -249,31 +249,6 @@ 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,16 +76,6 @@ 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.
@ -216,41 +206,10 @@ 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,2025 OpenCFD Ltd. Copyright (C) 2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -35,12 +35,21 @@ 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
@ -74,26 +83,6 @@ 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()
@ -271,58 +260,6 @@ 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,23 +196,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2019-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -199,38 +199,6 @@ 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,23 +174,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2015-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -173,35 +173,6 @@ 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,23 +200,6 @@ 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-2025 OpenCFD Ltd. Copyright (C) 2017-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -205,35 +205,6 @@ 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

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2020-2023 OpenCFD Ltd. Copyright (C) 2020-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -26,9 +26,9 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "dynamicContactAngleForce.H" #include "dynamicContactAngleForce.H"
#include "addToRunTimeSelectionTable.H"
#include "Function1.H" #include "Function1.H"
#include "distributionModel.H" #include "distributionModel.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -59,6 +59,7 @@ dynamicContactAngleForce::dynamicContactAngleForce
) )
: :
contactAngleForce(typeName, film, dict), contactAngleForce(typeName, film, dict),
thetaPtr_(nullptr),
U_vs_thetaPtr_ U_vs_thetaPtr_
( (
Function1<scalar>::NewIfPresent Function1<scalar>::NewIfPresent
@ -80,46 +81,56 @@ dynamicContactAngleForce::dynamicContactAngleForce
) )
), ),
rndGen_(label(0)), rndGen_(label(0)),
distribution_ distributionPtr_(nullptr)
(
distributionModel::New
(
coeffDict_.subDict("distribution"),
rndGen_
)
)
{ {
if (U_vs_thetaPtr_ && T_vs_thetaPtr_) if (U_vs_thetaPtr_ && T_vs_thetaPtr_)
{ {
FatalIOErrorInFunction(dict) FatalIOErrorInFunction(dict)
<< "Entries Utheta and Ttheta could not be used together" << "Only one of Utheta or Ttheta should be provided; "
<< "both inputs cannot be used together."
<< abort(FatalIOError); << abort(FatalIOError);
} }
thetaPtr_.emplace
(
IOobject
(
IOobject::scopedName(typeName, "theta"),
film.regionMesh().time().timeName(),
film.regionMesh().thisDb(),
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
film.regionMesh(),
dimensionedScalar(dimless, Zero)
);
if (coeffDict_.findEntry("distribution"))
{
distributionPtr_ = distributionModel::New
(
coeffDict_.subDict("distribution"),
rndGen_
);
}
} }
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
dynamicContactAngleForce::~dynamicContactAngleForce()
{} // distributionModel was forward declared
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
tmp<areaScalarField> dynamicContactAngleForce::theta() const tmp<areaScalarField> dynamicContactAngleForce::theta() const
{ {
auto ttheta = tmp<areaScalarField>::New areaScalarField& theta = thetaPtr_.ref();
(
IOobject
(
IOobject::scopedName(typeName, "theta"),
film().regionMesh().time().timeName(),
film().regionMesh().thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
film().regionMesh(),
dimensionedScalar(dimless, Zero)
);
areaScalarField& theta = ttheta.ref();
scalarField& thetai = theta.ref(); scalarField& thetai = theta.ref();
if (U_vs_thetaPtr_) if (U_vs_thetaPtr_)
{ {
// Initialize with the function of film speed // Initialize with the function of film speed
@ -136,13 +147,16 @@ tmp<areaScalarField> dynamicContactAngleForce::theta() const
thetai = T_vs_thetaPtr_->value(T()); thetai = T_vs_thetaPtr_->value(T());
} }
// Add the stochastic perturbation if (distributionPtr_)
forAll(thetai, facei)
{ {
thetai[facei] += distribution_->sample(); // Add the stochastic perturbation
forAll(thetai, facei)
{
thetai[facei] += distributionPtr_->sample();
}
} }
return ttheta; return thetaPtr_();
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2020-2022 OpenCFD Ltd. Copyright (C) 2020-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -112,6 +112,9 @@ class dynamicContactAngleForce
{ {
// Private Data // Private Data
//- Contact-angle field in degrees
mutable autoPtr<areaScalarField> thetaPtr_;
//- Contact angle as a function of film speed //- Contact angle as a function of film speed
autoPtr<Function1<scalar>> U_vs_thetaPtr_; autoPtr<Function1<scalar>> U_vs_thetaPtr_;
@ -121,17 +124,8 @@ class dynamicContactAngleForce
//- Random number generator //- Random number generator
Random rndGen_; Random rndGen_;
//- Parcel size PDF model //- Stochastic perturbation model for contact angle
const autoPtr<distributionModel> distribution_; autoPtr<distributionModel> distributionPtr_;
// Private Member Functions
//- No copy construct
dynamicContactAngleForce(const dynamicContactAngleForce&) = delete;
//- No copy assignment
void operator=(const dynamicContactAngleForce&) = delete;
protected: protected:
@ -148,7 +142,7 @@ public:
// Constructors // Constructors
//- Construct from surface film model //- Construct from surface film model and dictionary
dynamicContactAngleForce dynamicContactAngleForce
( (
liquidFilmBase& film, liquidFilmBase& film,
@ -157,7 +151,7 @@ public:
//- Destructor //- Destructor
virtual ~dynamicContactAngleForce() = default; virtual ~dynamicContactAngleForce();
}; };

View File

@ -788,14 +788,9 @@ 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
{ {
@ -820,13 +815,9 @@ 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
{ {

View File

@ -19,4 +19,12 @@ sed "s/GAUSS/fusedGauss/g" system/fvSchemes.template > system/fvSchemes
runParallel -s fusedGauss $(getApplication) runParallel -s fusedGauss $(getApplication)
echo "Updating fvSolution to cache gradients"
sed 's/GRADIENT/"grad(.*)"/g' system/fvSolution.template > system/fvSolution
runParallel -s fusedGaussCached $(getApplication)
# Restore
cp system/fvSolution.template system/fvSolution
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------

View File

@ -16,6 +16,15 @@ FoamFile
libs (fusedFiniteVolume); libs (fusedFiniteVolume);
/*
DebugSwitches
{
fusedGauss 1;
Gauss 1;
solution 1;
}
*/
application simpleFoam; application simpleFoam;
startFrom startTime; startFrom startTime;

View File

@ -55,5 +55,11 @@ relaxationFactors
} }
} }
cache
{
// Cache all grads
GRADIENT;
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,65 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2506 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
p
{
solver GAMG;
tolerance 1e-06;
relTol 0.1;
smoother GaussSeidel;
}
"(U|k|epsilon|omega|f|v2)"
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-05;
relTol 0.1;
}
}
SIMPLE
{
nNonOrthogonalCorrectors 0;
consistent yes;
residualControl
{
p 1e-2;
U 1e-3;
"(k|epsilon|omega|f|v2)" 1e-3;
}
}
relaxationFactors
{
equations
{
U 0.9; // 0.9 is more stable but 0.95 more convergent
".*" 0.9; // 0.9 is more stable but 0.95 more convergent
}
}
cache
{
// Cache all grads
GRADIENT;
}
// ************************************************************************* //