Compare commits

..

9 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
155 changed files with 9928 additions and 4395 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

@ -49,7 +49,8 @@ int main(int argc, char *argv[])
Info<< "mesh 0: " << mesh.sortedNames() << nl; Info<< "mesh 0: " << mesh.sortedNames() << nl;
auto& reg = const_cast<faMeshesRegistry&>(faMeshesRegistry::New(mesh)); faMeshesRegistry& reg =
const_cast<faMeshesRegistry&>(faMeshesRegistry::New(mesh));
// faMeshesRegistry faReg = faMeshesRegistry(mesh); // faMeshesRegistry faReg = faMeshesRegistry(mesh);

View File

@ -1,3 +1,3 @@
foamToEnsight-check.cxx foamToEnsight-check.C
EXE = $(FOAM_USER_APPBIN)/foamToEnsight-check EXE = $(FOAM_USER_APPBIN)/foamToEnsight-check

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2022-2025 OpenCFD Ltd. Copyright (C) 2022-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -203,7 +203,6 @@ int main(int argc, char *argv[])
argList::addVerboseOption(); argList::addVerboseOption();
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addBoolOption argList::addBoolOption
( (
@ -252,14 +251,6 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region // Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#include "createNamedMeshes.H" #include "createNamedMeshes.H"
@ -268,8 +259,8 @@ int main(int argc, char *argv[])
/// #include "createMeshAccounting.H" /// #include "createMeshAccounting.H"
PtrList<ensightMesh> ensightMeshes(regionNames.size()); PtrList<ensightMesh> ensightMeshes(regionNames.size());
List<PtrList<faMesh>> meshesFa(regionNames.size()); PtrList<faMesh> meshesFa(regionNames.size());
List<PtrList<ensightFaMesh>> ensightMeshesFa(regionNames.size()); PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
forAll(regionNames, regioni) forAll(regionNames, regioni)
{ {
@ -282,32 +273,21 @@ int main(int argc, char *argv[])
); );
ensightMeshes[regioni].verbose(optVerbose); ensightMeshes[regioni].verbose(optVerbose);
if (!doFiniteArea)
if (doFiniteArea)
{ {
continue; autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
}
meshesFa[regioni].resize_null(areaRegionNames.size());
ensightMeshesFa[regioni].resize_null(areaRegionNames.size());
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
forAll(areaRegionNames, areai)
{
const word& areaName = areaRegionNames[areai];
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(areaName, mesh));
if (faMeshPtr) if (faMeshPtr)
{ {
meshesFa[regioni].set(areai, std::move(faMeshPtr)); meshesFa.set(regioni, std::move(faMeshPtr));
ensightMeshesFa[regioni].set ensightMeshesFa.set
( (
areai, regioni,
new ensightFaMesh(meshesFa[regioni][areai]) new ensightFaMesh(meshesFa[regioni])
); );
ensightMeshesFa[regioni][areai].verbose(optVerbose); ensightMeshesFa[regioni].verbose(optVerbose);
} }
} }
} }
@ -315,7 +295,7 @@ int main(int argc, char *argv[])
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
if (UPstream::master()) if (Pstream::master())
{ {
Info<< "Checking " << timeDirs.size() << " time steps" << nl; Info<< "Checking " << timeDirs.size() << " time steps" << nl;
} }
@ -337,20 +317,17 @@ int main(int argc, char *argv[])
auto& ensMesh = ensightMeshes[regioni]; auto& ensMesh = ensightMeshes[regioni];
// Finite-area (can be missing) // Finite-area (can be missing)
auto& ensFaMeshes = ensightMeshesFa[regioni]; auto* ensFaMeshPtr = ensightMeshesFa.get(regioni);
if (moving) if (moving)
{ {
ensMesh.expire(); ensMesh.expire();
ensMesh.correct(); ensMesh.correct();
forAll(areaRegionNames, areai) if (ensFaMeshPtr)
{ {
if (auto* ensFaMeshPtr = ensFaMeshes.get(areai)) ensFaMeshPtr->expire();
{ ensFaMeshPtr->correct();
ensFaMeshPtr->expire();
ensFaMeshPtr->correct();
}
} }
} }
@ -363,15 +340,9 @@ int main(int argc, char *argv[])
printInfo(ensMesh, optVerbose); printInfo(ensMesh, optVerbose);
// finite-area if (ensFaMeshPtr)
forAll(areaRegionNames, areai)
{ {
auto* ensFaMeshPtr = ensFaMeshes.get(areai); printInfo(*ensFaMeshPtr, optVerbose);
if (ensFaMeshPtr)
{
printInfo(*ensFaMeshPtr, optVerbose);
}
} }
} }
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2021-2025 OpenCFD Ltd. Copyright (C) 2021-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,7 +28,7 @@ Application
makeFaMesh makeFaMesh
Description Description
Check a finite-area mesh Check a finiteArea mesh
Original Authors Original Authors
Zeljko Tukovic, FAMENA Zeljko Tukovic, FAMENA
@ -39,7 +39,6 @@ Original Authors
#include "Time.H" #include "Time.H"
#include "argList.H" #include "argList.H"
#include "faMesh.H" #include "faMesh.H"
#include "faMeshTools.H"
#include "polyMesh.H" #include "polyMesh.H"
#include "areaFaMesh.H" #include "areaFaMesh.H"
#include "edgeFaMesh.H" #include "edgeFaMesh.H"
@ -48,7 +47,7 @@ Original Authors
#include "processorFaPatch.H" #include "processorFaPatch.H"
#include "foamVtkIndPatchWriter.H" #include "foamVtkIndPatchWriter.H"
#include "foamVtkLineWriter.H" #include "foamVtkLineWriter.H"
#include "regionProperties.H" #include "faMeshTools.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -60,7 +59,7 @@ int main(int argc, char *argv[])
{ {
argList::addNote argList::addNote
( (
"Check a finite-area mesh" "Check a finiteArea mesh"
); );
argList::addBoolOption argList::addBoolOption
@ -78,15 +77,9 @@ int main(int argc, char *argv[])
); );
#include "addRegionOption.H" #include "addRegionOption.H"
#include "addAllFaRegionOptions.H" #include "addFaRegionOption.H"
#include "setRootCase.H" #include "setRootCase.H"
#include "createTime.H" #include "createTime.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
// ------------------------------------------------------------------------
#include "createNamedPolyMesh.H" #include "createNamedPolyMesh.H"
int geometryOrder(1); int geometryOrder(1);
@ -98,41 +91,16 @@ int main(int argc, char *argv[])
faMesh::geometryOrder(geometryOrder); faMesh::geometryOrder(geometryOrder);
} }
for (const word& areaName : areaRegionNames) #include "createNamedFaMesh.H"
Info<< "Time = " << runTime.timeName() << nl << endl;
// Mesh information (verbose)
faMeshTools::printMeshChecks(aMesh);
if (args.found("write-vtk"))
{ {
Info<< "Create faMesh"; #include "faMeshWriteVTK.H"
if (!polyMesh::regionName(areaName).empty())
{
Info<< " [" << areaName << "]";
}
Info<< " for time = " << runTime.timeName() << nl;
autoPtr<faMesh> faMeshPtr(faMesh::TryNew(areaName, mesh));
if (!faMeshPtr)
{
Info<< " ...failed to create area-mesh";
if (!polyMesh::regionName(areaName).empty())
{
Info<< " [" << areaName << "]";
}
Info<< endl;
continue;
}
else
{
Info<< endl;
}
const auto& aMesh = faMeshPtr();
// Mesh information (verbose)
faMeshTools::printMeshChecks(aMesh);
if (args.found("write-vtk"))
{
#include "faMeshWriteVTK.H"
}
} }
Info<< "\nEnd\n" << endl; Info<< "\nEnd\n" << endl;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021-2025 OpenCFD Ltd. Copyright (C) 2021-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,16 +15,6 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
// The base name for output files
word vtkBaseFileName(aMesh.regionName());
if (polyMesh::regionName(vtkBaseFileName).empty())
{
vtkBaseFileName = "finiteArea";
}
Info<< nl;
Info<< "Write faMesh in vtk format:" << nl;
{ {
// finiteArea - faces // finiteArea - faces
vtk::uindirectPatchWriter writer vtk::uindirectPatchWriter writer
@ -33,7 +23,7 @@ Info<< "Write faMesh in vtk format:" << nl;
// vtk::formatType::INLINE_ASCII, // vtk::formatType::INLINE_ASCII,
fileName fileName
( (
aMesh.time().globalPath() / vtkBaseFileName aMesh.time().globalPath() / "finiteArea"
) )
); );
@ -42,7 +32,7 @@ Info<< "Write faMesh in vtk format:" << nl;
globalIndex procAddr(aMesh.nFaces()); globalIndex procAddr(aMesh.nFaces());
labelList cellIDs; labelList cellIDs;
if (UPstream::master()) if (Pstream::master())
{ {
cellIDs.resize(procAddr.totalSize()); cellIDs.resize(procAddr.totalSize());
for (const labelRange& range : procAddr.ranges()) for (const labelRange& range : procAddr.ranges())
@ -63,7 +53,8 @@ Info<< "Write faMesh in vtk format:" << nl;
writer.beginPointData(1); writer.beginPointData(1);
writer.write("normal", aMesh.pointAreaNormals()); writer.write("normal", aMesh.pointAreaNormals());
Info<< " " << writer.output().name() << nl; Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
} }
{ {
@ -75,7 +66,7 @@ Info<< "Write faMesh in vtk format:" << nl;
// vtk::formatType::INLINE_ASCII, // vtk::formatType::INLINE_ASCII,
fileName fileName
( (
aMesh.time().globalPath() / (vtkBaseFileName + "-edges") aMesh.time().globalPath() / "finiteArea-edges"
) )
); );
@ -97,7 +88,8 @@ Info<< "Write faMesh in vtk format:" << nl;
writer.beginPointData(1); writer.beginPointData(1);
writer.write("normal", aMesh.pointAreaNormals()); writer.write("normal", aMesh.pointAreaNormals());
Info<< " " << writer.output().name() << nl; Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
} }
{ {
@ -116,7 +108,7 @@ Info<< "Write faMesh in vtk format:" << nl;
// vtk::formatType::INLINE_ASCII, // vtk::formatType::INLINE_ASCII,
fileName fileName
( (
aMesh.time().globalPath() / (vtkBaseFileName + "-edgesCentres") aMesh.time().globalPath() / "finiteArea-edgesCentres"
) )
); );
@ -142,7 +134,8 @@ Info<< "Write faMesh in vtk format:" << nl;
writer.write("normal", fld); writer.write("normal", fld);
} }
Info<< " " << writer.output().name() << nl; Info<< nl
<< "Wrote faMesh in vtk format: " << writer.output().name() << nl;
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2023-2025 OpenCFD Ltd. Copyright (C) 2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,7 +15,7 @@ Description
Input Input
mesh (polyMesh) mesh (polyMesh)
meshDefDict (system/finite-area/faMeshDefinition) meshDefDict (system/faMeshDefintion)
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -25,16 +25,13 @@ Input
const polyBoundaryMesh& pbm = mesh.boundaryMesh(); const polyBoundaryMesh& pbm = mesh.boundaryMesh();
labelList patchIDs; wordRes polyPatchNames;
meshDefDict.readIfPresent("polyMeshPatches", polyPatchNames);
if const labelList patchIDs
( (
wordRes select; pbm.indices(polyPatchNames, true) // useGroups
meshDefDict.readIfPresent("polyMeshPatches", select) );
)
{
patchIDs = pbm.indices(select, true); // useGroups
}
label nFaceLabels = 0; label nFaceLabels = 0;
for (const label patchi : patchIDs) for (const label patchi : patchIDs)

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021-2025 OpenCFD Ltd. Copyright (C) 2021-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -13,18 +13,6 @@ License
Description Description
Search for the appropriate faMeshDefinition dictionary... Search for the appropriate faMeshDefinition dictionary...
Expects to find a faMeshDefinition file in a location specified
by the command-line option, or one of the standard locations.
For default area region (region0):
(1) system/finite-area/faMeshDefinition
(2) system/faMeshDefinition [legacy location - v2312 and earlier]
For a named area region:
(1) system/finite-area/<area-name>/faMeshDefinition
(2) system/finite-area/faMeshDefinition.<area-name>
[symmetric with faOptions]
Required Classes Required Classes
- Foam::polyMesh - Foam::polyMesh
- Foam::IOdictionary - Foam::IOdictionary
@ -36,185 +24,81 @@ Required Variables
- runTime [Time] - runTime [Time]
Provided Variables Provided Variables
- faMeshDefinitionPtr [autoPtr<IOdictionary>] - meshDefDict [IOdictionary]
- meshDictPtr [autoPtr<IOdictionary>]
If the dictionary cannot be found, exits with an error message or
reports a warning (dry-run mode)
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
const word dictName("faMeshDefinition"); const word dictName("faMeshDefinition");
autoPtr<IOdictionary> faMeshDefinitionPtr; autoPtr<IOdictionary> meshDictPtr;
{ {
// Exit unless dry-run? fileName dictPath;
const bool exitOnFailure = (!args.dryRun()); const word& regionDir = Foam::polyMesh::regionName(regionName);
const word& areaRegionDir = Foam::polyMesh::regionName(areaRegionName);
const word& regionDir = polyMesh::regionName(regionName); if (args.readIfPresent("dict", dictPath))
const word& areaRegionDir = polyMesh::regionName(areaRegionName);
// Canonical location
fileName dictPath
(
runTime.system()/regionDir
/ faMesh::prefix()/areaRegionDir/dictName
);
// Dictionary specified on the command-line ...
const bool specified = args.readIfPresent("dict", dictPath);
if (specified)
{ {
// Dictionary specified on the command-line ...
if (isDir(dictPath)) if (isDir(dictPath))
{ {
dictPath /= dictName; dictPath /= dictName;
} }
} }
else if
(
// Dictionary under system/faMeshDefinition ?
// (v2312 and earlier)
areaRegionDir.empty()
&& exists
(
runTime.path()/runTime.caseSystem()
/ regionDir/faMesh::meshSubDir/dictName
)
)
{
// Dictionary present directly in system/ (v2312 and earlier)
dictPath = runTime.system()/regionDir/dictName;
}
else
{
// Use system/finite-area/ directory, with region qualifications
dictPath =
(
runTime.system()/regionDir
/ faMesh::prefix()/areaRegionDir/dictName
);
}
IOobject meshDictIO IOobject meshDictIO
( (
dictPath, dictPath,
runTime, runTime,
IOobjectOption::MUST_READ, IOobject::MUST_READ,
IOobjectOption::NO_WRITE, IOobject::NO_WRITE,
IOobjectOption::NO_REGISTER, IOobject::NO_REGISTER,
true // is globalObject true // is globalObject
); );
refPtr<IOobject> meshDictIOPtr; if (!meshDictIO.typeHeaderOk<IOdictionary>(true))
bool foundIOobject = meshDictIO.typeHeaderOk<IOdictionary>(true);
// For reporting any alternative locations
dictPath.clear();
if (!foundIOobject && !specified)
{ {
if (!areaRegionDir.empty()) FatalErrorInFunction
{ << meshDictIO.objectPath() << nl
// Alternative location << exit(FatalError);
// - system/finite-area/faMeshDefinition.<area-name>
dictPath =
(
runTime.system()/regionDir
/ faMesh::prefix()/IOobject::groupName(dictName, areaRegionDir)
);
}
else
{
// legacy location (v2312 and earlier)
// - system/faMeshDefinition
dictPath = runTime.system()/regionDir/dictName;
}
if (!dictPath.empty())
{
auto ioptr = autoPtr<IOobject>::New
(
dictPath,
runTime,
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER,
true // is globalObject
);
foundIOobject =
(
ioptr && ioptr->typeHeaderOk<IOdictionary>(true)
);
if (foundIOobject)
{
// Use if found
meshDictIOPtr = std::move(ioptr);
}
// Generally retain dictPath for error messages,
// but don't mention the really old legacy location
if (areaRegionDir.empty())
{
dictPath.clear();
}
}
} }
// Alternative location or regular location? Info<< "Creating faMesh from definition: "
if (!meshDictIOPtr) << meshDictIO.objectRelPath() << endl;
{
meshDictIOPtr.cref(meshDictIO);
}
const auto& io = meshDictIOPtr();
meshDictPtr = autoPtr<IOdictionary>::New(meshDictIO);
// Handle final success or failure
if (foundIOobject)
{
Info<< "----------------" << nl
<< "Using area-mesh definition";
if (!areaRegionDir.empty())
{
Info<< " [" << areaRegionName << "]";
}
Info<< nl
<< " " << io.objectRelPath() << nl << endl;
faMeshDefinitionPtr = autoPtr<IOdictionary>::New(io);
}
else
{
// Failure
if (exitOnFailure)
{
auto& err =
FatalErrorInFunction
<< "Did not find area-mesh definition";
if (!areaRegionDir.empty())
{
err<< " [" << areaRegionName << "]";
}
err << nl
<< " " << io.objectRelPath() << nl;
if (!dictPath.empty())
{
err << " " << dictPath << nl;
}
FatalError<< exit(FatalError);
}
else
{
// dry-run: warning
auto& err =
Warning << nl
<< "----------------" << nl
<< "Did not find area-mesh definition";
if (!areaRegionDir.empty())
{
err << " [" << areaRegionName << "]";
}
err << nl
<< " " << io.objectRelPath() << nl;
if (!dictPath.empty())
{
err << " " << dictPath << nl;
}
}
}
} }
IOdictionary& meshDefDict = *meshDictPtr;
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2021-2025 OpenCFD Ltd. Copyright (C) 2021-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -40,6 +40,7 @@ Original Authors
#include "Time.H" #include "Time.H"
#include "argList.H" #include "argList.H"
#include "OSspecific.H"
#include "faMesh.H" #include "faMesh.H"
#include "faMeshTools.H" #include "faMeshTools.H"
#include "IOdictionary.H" #include "IOdictionary.H"
@ -52,7 +53,6 @@ Original Authors
#include "PtrListOps.H" #include "PtrListOps.H"
#include "foamVtkLineWriter.H" #include "foamVtkLineWriter.H"
#include "foamVtkIndPatchWriter.H" #include "foamVtkIndPatchWriter.H"
#include "regionProperties.H"
#include "syncTools.H" #include "syncTools.H"
#include "OBJstream.H" #include "OBJstream.H"
@ -104,14 +104,12 @@ int main(int argc, char *argv[])
); );
#include "addRegionOption.H" #include "addRegionOption.H"
#include "addAllFaRegionOptions.H" #include "addFaRegionOption.H"
#include "setRootCase.H" #include "setRootCase.H"
#include "createTime.H" #include "createTime.H"
#include "createNamedPolyMesh.H" #include "createNamedPolyMesh.H"
// Handle -all-area-regions, -area-regions, -area-region #include "getFaRegionOption.H"
#include "getAllFaRegionOptions.H"
const bool doDecompose = !args.found("no-decompose"); const bool doDecompose = !args.found("no-decompose");
const bool doDecompFields = !args.found("no-fields"); const bool doDecompFields = !args.found("no-fields");
@ -125,83 +123,56 @@ int main(int argc, char *argv[])
Info<< "Skip decompose of finiteArea fields" << nl; Info<< "Skip decompose of finiteArea fields" << nl;
} }
// ------------------------------------------------------------------------ // Reading faMeshDefinition dictionary
#include "findMeshDefinitionDict.H"
for (const word& areaRegionName : areaRegionNames) // Inject/overwrite name for optional 'empty' patch
word patchName;
if (args.readIfPresent("empty-patch", patchName))
{ {
// Reading faMeshDefinition dictionary meshDefDict.add("emptyPatch", patchName, true);
#include "findMeshDefinitionDict.H" }
if (!faMeshDefinitionPtr) // Preliminary checks
{ #include "checkPatchTopology.H"
if (args.dryRun())
{
break;
}
else
{
FatalErrorInFunction
<< "Did not find area-mesh definition"<< nl
<< exit(FatalError);
}
}
auto& meshDefDict = (*faMeshDefinitionPtr); Info << "Create areaMesh";
if (!Foam::polyMesh::regionName(areaRegionName).empty())
{
Foam::Info << ' ' << areaRegionName;
}
Info << " for polyMesh at time = " << runTime.timeName() << nl;
// Create
faMesh aMesh(areaRegionName, mesh, meshDefDict);
// Inject/overwrite name for optional 'empty' patch // Mesh information (less verbose)
if (word name; args.readIfPresent("empty-patch", name)) faMeshTools::printMeshChecks(aMesh, 0);
{
meshDefDict.add("emptyPatch", name, true);
}
// Preliminary checks if (args.found("write-edges-obj"))
#include "checkPatchTopology.H" {
#include "faMeshWriteEdgesOBJ.H"
}
Info<< "Create area-mesh"; if (args.found("write-vtk"))
if (!polyMesh::regionName(areaRegionName).empty()) {
{ #include "faMeshWriteVTK.H"
Info<< " [" << areaRegionName << "]"; }
}
Info<< " with polyMesh at time = " << runTime.timeName() << nl;
// Create if (args.dryRun())
faMesh aMesh(areaRegionName, mesh, meshDefDict); {
Info<< "\ndry-run: not writing mesh or decomposing fields\n" << nl;
}
else
{
// More precision (for points data)
IOstream::minPrecision(10);
// Mesh information (less verbose) Info<< nl << "Write finite area mesh." << nl;
faMeshTools::printMeshChecks(aMesh, 0); aMesh.write();
if (args.found("write-edges-obj")) Info<< endl;
{ #include "decomposeFaFields.H"
#include "faMeshWriteEdgesOBJ.H"
}
if (args.found("write-vtk"))
{
#include "faMeshWriteVTK.H"
}
if (args.dryRun())
{
Info<< "\ndry-run: not writing mesh or decomposing fields\n" << nl;
}
else
{
// More precision (for points data)
IOstream::minPrecision(10);
Info<< nl << "Write finite area mesh";
if (const word& name = aMesh.regionName(); !name.empty())
{
Info<< " [" << name << "]";
}
Info<< nl;
aMesh.write();
Info<< endl;
#include "decomposeFaFields.H"
}
} }
Info<< "\nEnd\n" << endl; Info<< "\nEnd\n" << endl;

View File

@ -334,7 +334,6 @@ int main(int argc, char *argv[])
); );
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addDryRunOption argList::addDryRunOption
( (
@ -443,6 +442,7 @@ int main(int argc, char *argv[])
bool decomposeFieldsOnly = args.found("fields"); bool decomposeFieldsOnly = args.found("fields");
bool forceOverwrite = args.found("force"); bool forceOverwrite = args.found("force");
// Set time from database // Set time from database
#include "createTime.H" #include "createTime.H"
@ -491,17 +491,9 @@ int main(int argc, char *argv[])
decompDictFile = runTime.globalPath()/decompDictFile; decompDictFile = runTime.globalPath()/decompDictFile;
} }
// Handle -allRegions, -regions, -region // Get region names
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
const bool optRegions = const bool optRegions =
(regionNames.size() != 1 || regionNames[0] != polyMesh::defaultRegion); (regionNames.size() != 1 || regionNames[0] != polyMesh::defaultRegion);
@ -821,76 +813,56 @@ int main(int argc, char *argv[])
// Field objects at this time // Field objects at this time
IOobjectList objects; IOobjectList objects;
IOobjectList faObjects;
// faMesh fields - can have multiple finite-area per volume
HashTable<IOobjectList> faObjects;
if (doDecompFields) if (doDecompFields)
{ {
// List of volume mesh objects for this instance // List of volume mesh objects for this instance
objects = IOobjectList(mesh, runTime.timeName()); objects = IOobjectList(mesh, runTime.timeName());
// List of area mesh objects (assuming single region)
faObjects = IOobjectList
(
mesh.time(),
runTime.timeName(),
faMesh::dbDir(mesh, word::null),
IOobjectOption::NO_REGISTER
);
// Ignore generated fields: (cellDist) // Ignore generated fields: (cellDist)
objects.remove("cellDist"); objects.remove("cellDist");
// Lists of finite-area fields
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
// The finite-area objects for this area region
IOobjectList objs
(
faMesh::Registry(mesh),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
} }
// Finite area handling // Finite area handling
// - all area regions use the same volume decomposition autoPtr<faMeshDecomposition> faMeshDecompPtr;
HashPtrTable<faMeshDecomposition> faMeshDecompHashes;
if (doFiniteArea) if (doFiniteArea)
{ {
const word boundaryInst = const word boundaryInst =
mesh.time().findInstance(mesh.meshDir(), "boundary"); mesh.time().findInstance(mesh.meshDir(), "boundary");
for (const word& areaName : areaRegionNames) IOobject io
{ (
IOobject io "faBoundary",
( boundaryInst,
"faBoundary", faMesh::meshDir(mesh, word::null),
boundaryInst, mesh.time(),
faMesh::meshDir(mesh, areaName), IOobject::READ_IF_PRESENT,
mesh.time(), IOobject::NO_WRITE,
IOobject::READ_IF_PRESENT, IOobject::NO_REGISTER
IOobject::NO_WRITE, );
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true)) if (io.typeHeaderOk<faBoundaryMesh>(true))
{ {
// Always based on the volume decomposition! // Always based on the volume decomposition!
faMeshDecompHashes.set faMeshDecompPtr.reset
(
new faMeshDecomposition
( (
areaName, mesh,
autoPtr<faMeshDecomposition>::New mesh.nProcs(),
( mesh.model()
areaName, )
mesh, );
mesh.nProcs(),
mesh.model()
)
);
}
} }
} }
@ -1094,7 +1066,7 @@ int main(int argc, char *argv[])
processorDb.setTime(runTime); processorDb.setTime(runTime);
// Read the mesh // read the mesh
if (!procMeshList.set(proci)) if (!procMeshList.set(proci))
{ {
procMeshList.set procMeshList.set
@ -1301,15 +1273,12 @@ int main(int argc, char *argv[])
} }
// Finite-area mesh and field decomposition // Finite area mesh and field decomposition
for (auto& iter : faMeshDecompHashes.sorted()) if (faMeshDecompPtr)
{ {
const word& areaName = iter.key(); Info<< "\nFinite area mesh decomposition" << endl;
faMeshDecomposition& aMesh = *(iter.val()); faMeshDecomposition& aMesh = faMeshDecompPtr();
Info<< "\nFinite area mesh decomposition: "
<< areaName << endl;
aMesh.decomposeMesh(); aMesh.decomposeMesh();
aMesh.writeDecomposition(); aMesh.writeDecomposition();
@ -1320,13 +1289,9 @@ int main(int argc, char *argv[])
faFieldDecomposer::fieldsCache areaFieldCache; faFieldDecomposer::fieldsCache areaFieldCache;
if if (doDecompFields)
(
const auto objs = faObjects.cfind(areaName);
doDecompFields && objs.good()
)
{ {
areaFieldCache.readAllFields(aMesh, objs.val()); areaFieldCache.readAllFields(aMesh, faObjects);
} }
const label nAreaFields = areaFieldCache.size(); const label nAreaFields = areaFieldCache.size();
@ -1357,7 +1322,7 @@ int main(int argc, char *argv[])
processorDb.setTime(runTime); processorDb.setTime(runTime);
// Read the volume mesh // Read the mesh
fvMesh procFvMesh fvMesh procFvMesh
( (
IOobject IOobject
@ -1368,7 +1333,7 @@ int main(int argc, char *argv[])
) )
); );
faMesh procMesh(areaName, procFvMesh); faMesh procMesh(procFvMesh);
// // Does not work. HJ, 15/Aug/2017 // // Does not work. HJ, 15/Aug/2017
// const labelIOList& faceProcAddressing = // const labelIOList& faceProcAddressing =
@ -1427,11 +1392,7 @@ int main(int argc, char *argv[])
boundaryProcAddressing boundaryProcAddressing
); );
areaFieldCache.decomposeAllFields areaFieldCache.decomposeAllFields(fieldDecomposer);
(
fieldDecomposer,
args.verbose() // report
);
} }
} }
} }

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.
@ -91,7 +91,6 @@ int main(int argc, char *argv[])
argList::noParallel(); argList::noParallel();
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addVerboseOption(); argList::addVerboseOption();
argList::addOption argList::addOption
@ -202,17 +201,9 @@ int main(int argc, char *argv[])
const bool newTimes = args.found("newTimes"); const bool newTimes = args.found("newTimes");
// Handle -allRegions, -regions, -region // Get region names
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// Determine the processor count // Determine the processor count
label nProcs{0}; label nProcs{0};
@ -400,30 +391,19 @@ int main(int argc, char *argv[])
IOobjectOption::NO_REGISTER IOobjectOption::NO_REGISTER
); );
// The finite-area fields (multiple finite-area per volume) IOobjectList faObjects;
HashTable<IOobjectList> faObjects;
if (doFiniteArea && doFields) if (doFiniteArea && doFields)
{ {
// Lists of finite-area fields - scan on processor0 // List of area mesh objects (assuming single region)
faObjects.reserve(areaRegionNames.size()); // - scan on processor0
faObjects = IOobjectList
for (const word& areaName : areaRegionNames) (
{ procMeshes.meshes()[0],
// The finite-area objects for this area region databases[0].timeName(),
IOobjectList objs faMesh::dbDir(word::null), // local relative to mesh
( IOobjectOption::NO_REGISTER
procMeshes.meshes()[0], );
databases[0].timeName(),
faMesh::dbDir(areaName), // local relative to mesh
IOobjectOption::NO_REGISTER
);
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
} }
if (doFields) if (doFields)
@ -573,60 +553,42 @@ int main(int argc, char *argv[])
} }
// Reconstruct any finite-area fields // If there are any FA fields, reconstruct them
if (doFiniteArea)
if (!doFiniteArea)
{ {
bool hadFaFields = false;
for (const word& areaName : areaRegionNames)
{
const auto objs = faObjects.cfind(areaName);
if (!objs.good())
{
continue;
}
const auto& faObjs = objs.val();
if
(
!faObjs.count(fieldTypes::is_area)
&& !faObjs.count<edgeScalarField>()
)
{
continue;
}
hadFaFields = true;
Info<< "Reconstructing finite-area fields ["
<< polyMesh::regionName(areaName)
<< "]" << nl << endl;
const faMesh aMesh(areaName, mesh);
processorFaMeshes procFaMeshes
(
procMeshes.meshes(),
areaName
);
faFieldReconstructor reconstructor
(
aMesh,
procFaMeshes.meshes(),
procFaMeshes.edgeProcAddressing(),
procFaMeshes.faceProcAddressing(),
procFaMeshes.boundaryProcAddressing()
);
reconstructor.reconstructAllFields(faObjs);
}
if (!hadFaFields)
{
Info << "No finite-area fields" << nl << endl;
}
} }
else if
(
faObjects.count<areaScalarField>()
|| faObjects.count<areaVectorField>()
|| faObjects.count<areaSphericalTensorField>()
|| faObjects.count<areaSymmTensorField>()
|| faObjects.count<areaTensorField>()
|| faObjects.count<edgeScalarField>()
)
{
Info << "Reconstructing FA fields" << nl << endl;
faMesh aMesh(mesh);
processorFaMeshes procFaMeshes(procMeshes.meshes());
faFieldReconstructor reconstructor
(
aMesh,
procFaMeshes.meshes(),
procFaMeshes.edgeProcAddressing(),
procFaMeshes.faceProcAddressing(),
procFaMeshes.boundaryProcAddressing()
);
reconstructor.reconstructAllFields(faObjects);
}
else
{
Info << "No FA fields" << nl << endl;
}
if (doReconstructSets) if (doReconstructSets)
{ {

View File

@ -119,10 +119,17 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh(); const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
DynamicList<label> masterFaces(masterMesh.nBoundaryFaces()); DynamicList<label> masterFaces
(
masterMesh.nFaces()
- masterMesh.nInternalFaces()
);
for (const polyPatch& pp : masterPatches)
forAll(masterPatches, patchi)
{ {
const polyPatch& pp = masterPatches[patchi];
if (isA<processorPolyPatch>(pp)) if (isA<processorPolyPatch>(pp))
{ {
for for
@ -132,8 +139,11 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
proci++ proci++
) )
{ {
const string toProcString("to" + Foam::name(proci)); const string toProcString("to" + name(proci));
if (pp.name().ends_with(toProcString)) if (
pp.name().rfind(toProcString)
== (pp.name().size()-toProcString.size())
)
{ {
label meshFacei = pp.start(); label meshFacei = pp.start();
forAll(pp, i) forAll(pp, i)
@ -146,6 +156,7 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
} }
} }
masterFaces.shrink();
// Pick up all patches on meshToAdd ending in "procBoundaryDDDtoYYY" // Pick up all patches on meshToAdd ending in "procBoundaryDDDtoYYY"
@ -153,10 +164,16 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh(); const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
DynamicList<label> addFaces(meshToAdd.nBoundaryFaces()); DynamicList<label> addFaces
(
meshToAdd.nFaces()
- meshToAdd.nInternalFaces()
);
for (const polyPatch& pp : addPatches) forAll(addPatches, patchi)
{ {
const polyPatch& pp = addPatches[patchi];
if (isA<processorPolyPatch>(pp)) if (isA<processorPolyPatch>(pp))
{ {
bool isConnected = false; bool isConnected = false;
@ -198,6 +215,7 @@ autoPtr<faceCoupleInfo> determineCoupledFaces
} }
} }
} }
addFaces.shrink();
return autoPtr<faceCoupleInfo>::New return autoPtr<faceCoupleInfo>::New
( (
@ -484,14 +502,15 @@ void writeMaps
Info<< " pointProcAddressing" << endl; Info<< " pointProcAddressing" << endl;
ioAddr.rename("pointProcAddressing"); ioAddr.rename("pointProcAddressing");
labelIOList::writeContents(ioAddr, pointProcAddressing); IOList<label>::writeContents(ioAddr, pointProcAddressing);
// From processor face to reconstructed mesh face // From processor face to reconstructed mesh face
// - add turning index to faceProcAddressing. Info<< " faceProcAddressing" << endl;
// See reconstructPar for meaning of turning index. ioAddr.rename("faceProcAddressing");
labelIOList faceProcAddr(ioAddr, faceProcAddressing);
labelList faceProcAddr(faceProcAddressing);
// Now add turning index to faceProcAddressing.
// See reconstructPar for meaning of turning index.
forAll(faceProcAddr, procFacei) forAll(faceProcAddr, procFacei)
{ {
const label masterFacei = faceProcAddr[procFacei]; const label masterFacei = faceProcAddr[procFacei];
@ -526,21 +545,19 @@ void writeMaps
} }
} }
Info<< " faceProcAddressing" << endl; faceProcAddr.write();
ioAddr.rename("faceProcAddressing");
labelIOList::writeContents(ioAddr, faceProcAddr);
faceProcAddr.clear();
// From processor cell to reconstructed mesh cell // From processor cell to reconstructed mesh cell
Info<< " cellProcAddressing" << endl; Info<< " cellProcAddressing" << endl;
ioAddr.rename("cellProcAddressing"); ioAddr.rename("cellProcAddressing");
labelIOList::writeContents(ioAddr, cellProcAddressing); IOList<label>::writeContents(ioAddr, cellProcAddressing);
// From processor patch to reconstructed mesh patch // From processor patch to reconstructed mesh patch
Info<< " boundaryProcAddressing" << endl; Info<< " boundaryProcAddressing" << endl;
ioAddr.rename("boundaryProcAddressing"); ioAddr.rename("boundaryProcAddressing");
labelIOList::writeContents(ioAddr, boundProcAddressing); IOList<label>::writeContents(ioAddr, boundProcAddressing);
Info<< endl; Info<< endl;
} }
@ -628,8 +645,7 @@ void sortFaEdgeMapping
{ {
// From faMeshReconstructor.C - edge shuffling on patches // From faMeshReconstructor.C - edge shuffling on patches
Map<label> remapGlobal; Map<label> remapGlobal(2*onePatch.nEdges());
remapGlobal.reserve(onePatch.nEdges());
for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei) for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei)
{ {
remapGlobal.insert(edgei, remapGlobal.size()); remapGlobal.insert(edgei, remapGlobal.size());
@ -763,11 +779,6 @@ int main(int argc, char *argv[])
); );
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
// Prevent volume fields [with regionFaModels] from incidental
// triggering finite-area
regionModels::allowFaModels(false);
// Prevent volume BCs from triggering finite-area // Prevent volume BCs from triggering finite-area
regionModels::allowFaModels(false); regionModels::allowFaModels(false);
@ -830,17 +841,9 @@ int main(int argc, char *argv[])
} }
} }
// Handle -allRegions, -regions, -region // Get region names
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// Determine the processor count // Determine the processor count
label nProcs{0}; label nProcs{0};
@ -932,8 +935,7 @@ int main(int argc, char *argv[])
polyMesh::meshDir(regionName), polyMesh::meshDir(regionName),
databases[0], databases[0],
IOobject::NO_READ, IOobject::NO_READ,
IOobject::NO_WRITE, IOobject::NO_WRITE
IOobject::NO_REGISTER
); );
// Problem: faceCompactIOList recognises both 'faceList' and // Problem: faceCompactIOList recognises both 'faceList' and
@ -1403,12 +1405,8 @@ int main(int argc, char *argv[])
// Read finite-area // Read finite-area
// For each named area region that exists create a HashTable PtrList<faMesh> procFaMeshes(databases.size());
// entry that will contain the PtrList for all processors
PtrList<polyMesh> procMeshes(databases.size()); PtrList<polyMesh> procMeshes(databases.size());
HashTable<PtrList<faMesh>> procAreaRegionMeshes;
procAreaRegionMeshes.reserve(areaRegionNames.size());
forAll(databases, proci) forAll(databases, proci)
{ {
@ -1416,16 +1414,20 @@ int main(int argc, char *argv[])
<< "Read processor mesh: " << "Read processor mesh: "
<< (databases[proci].caseName()/regionDir) << endl; << (databases[proci].caseName()/regionDir) << endl;
const polyMesh& procMesh = procMeshes.emplace procMeshes.set
( (
proci, proci,
IOobject new polyMesh
( (
regionName, IOobject
databases[proci].timeName(), (
databases[proci] regionName,
databases[proci].timeName(),
databases[proci]
)
) )
); );
const polyMesh& procMesh = procMeshes[proci];
writeMaps writeMaps
( (
@ -1448,67 +1450,38 @@ int main(int argc, char *argv[])
"boundary" "boundary"
); );
for (const word& areaName : areaRegionNames) IOobject io
(
"faBoundary",
boundaryInst,
faMesh::meshDir(procMesh, word::null),
procMesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
{ {
IOobject io // Always based on the volume decomposition!
( procFaMeshes.set(proci, new faMesh(procMesh));
"faBoundary",
boundaryInst,
faMesh::meshDir(procMesh, areaName),
procMesh.time(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
if (io.typeHeaderOk<faBoundaryMesh>(true))
{
// Always based on the volume decomposition!
auto& procFaMeshes = procAreaRegionMeshes(areaName);
procFaMeshes.resize(databases.size());
procFaMeshes.set
(
proci,
new faMesh(areaName, procMesh)
);
}
} }
} }
} }
// A finite-area mapping exists if procFaMeshes was filled // Finite-area mapping
doFiniteArea = false;
// Re-read reconstructed polyMesh. Note: could probably be avoided forAll(procFaMeshes, proci)
// by merging into loops above.
refPtr<polyMesh> masterPolyMeshPtr;
if (!procAreaRegionMeshes.empty())
{ {
masterPolyMeshPtr.reset if (procFaMeshes.set(proci))
( {
new polyMesh doFiniteArea = true;
( }
IOobject
(
regionName,
runTime.timeName(),
runTime
),
true
)
);
} }
// Process any finite-area meshes if (doFiniteArea)
for (const auto& iter : procAreaRegionMeshes.csorted())
{ {
const auto& areaName = iter.key();
const auto& procFaMeshes = iter.val();
const polyMesh& masterMesh = masterPolyMeshPtr();
// Addressing from processor to reconstructed case // Addressing from processor to reconstructed case
labelListList faFaceProcAddressing(nProcs); labelListList faFaceProcAddressing(nProcs);
labelListList faEdgeProcAddressing(nProcs); labelListList faEdgeProcAddressing(nProcs);
@ -1526,10 +1499,32 @@ int main(int argc, char *argv[])
faBoundProcAddressing[proci] = identity(bm.size()); faBoundProcAddressing[proci] = identity(bm.size());
// Mark processor patches // Mark processor patches
faBoundProcAddressing[proci].slice(bm.nNonProcessor()) = -1; for
(
label patchi = bm.nNonProcessor();
patchi < bm.size();
++patchi
)
{
faBoundProcAddressing[proci][patchi] = -1;
}
} }
// Re-read reconstructed polyMesh. Note: could probably be avoided
// by merging into loops above.
const polyMesh masterMesh
(
IOobject
(
regionName,
runTime.timeName(),
runTime
),
true
);
// faceProcAddressing // faceProcAddressing
// ~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~
@ -1564,13 +1559,13 @@ int main(int argc, char *argv[])
// Construct without patches // Construct without patches
faMesh masterFaMesh faMesh masterFaMesh
( (
areaName,
masterMesh, masterMesh,
std::move(masterFaceLabels), std::move(masterFaceLabels),
io io
); );
const auto& masterPatch = masterFaMesh.patch(); const uindirectPrimitivePatch& masterPatch =
masterFaMesh.patch();
// pointProcAddressing // pointProcAddressing
@ -1582,7 +1577,7 @@ int main(int argc, char *argv[])
const auto& procPatch = procFaMeshes[proci].patch(); const auto& procPatch = procFaMeshes[proci].patch();
const auto& mp = procPatch.meshPoints(); const auto& mp = procPatch.meshPoints();
auto& pointAddr = faPointProcAddressing[proci]; labelList& pointAddr = faPointProcAddressing[proci];
pointAddr.resize_nocopy(mp.size()); pointAddr.resize_nocopy(mp.size());
forAll(mp, i) forAll(mp, i)
@ -1631,7 +1626,8 @@ int main(int argc, char *argv[])
label nPatches = 0; label nPatches = 0;
forAll(completePatches, patchi) forAll(completePatches, patchi)
{ {
const auto& patchEdgeLabels = singlePatchEdgeLabels[patchi]; const labelList& patchEdgeLabels =
singlePatchEdgeLabels[patchi];
const faPatch& fap = procMesh0.boundary()[patchi]; const faPatch& fap = procMesh0.boundary()[patchi];
@ -1662,11 +1658,11 @@ int main(int argc, char *argv[])
// Serial mesh - no parallel communication // Serial mesh - no parallel communication
const bool oldParRun = UPstream::parRun(false); const bool oldParRun = Pstream::parRun(false);
masterFaMesh.addFaPatches(completePatches); masterFaMesh.addFaPatches(completePatches);
UPstream::parRun(oldParRun); // Restore parallel state Pstream::parRun(oldParRun); // Restore parallel state
// Write mesh & individual addressing // Write mesh & individual addressing

View File

@ -33,266 +33,99 @@ License
#include "decomposedBlockData.H" #include "decomposedBlockData.H"
#include "IFstream.H" #include "IFstream.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
// Trimmed-down version of lookupAndCacheProcessorsPath bool Foam::checkFileExistence(const fileName& fName)
// with Foam::exists() check. No caching.
// Check for two conditions:
// - file has to exist
// - if collated the entry has to exist inside the file
// Note: bypass fileOperation::filePath(IOobject&) since has problems
// with going to a different number of processors
// (in collated format). Use file-based searching instead
namespace Foam
{ {
// Trimmed-down version of lookupAndCacheProcessorsPath
// with Foam::exists() check. No caching.
// If indeed collated format: // Check for two conditions:
// Collect block-number in individual filenames // - file has to exist
// (might differ on different processors) // - if collated the entry has to exist inside the file
static bool checkFileExistenceCollated
( // Note: bypass fileOperation::filePath(IOobject&) since has problems
const Foam::fileOperation& handler, // with going to a different number of processors
const Foam::fileName& fName // (in collated format). Use file-based searching instead
)
{ const auto& handler = Foam::fileHandler();
// using namespace Foam; typedef fileOperation::procRangeType procRangeType;
fileName path, pDir, local;
procRangeType group;
label numProcs;
const label proci =
fileOperation::splitProcessorPath
(fName, path, pDir, local, group, numProcs);
bool found = false; bool found = false;
if (proci != -1)
{ {
const label handlerComm = handler.comm(); // Read all directories to see any beginning with processor
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const label globalProci = UPstream::myProcNo(UPstream::worldComm); const fileNameList dirEntries
const label handlerProci = UPstream::myProcNo(handlerComm);
const label nHandlerProcs = UPstream::nProcs(handlerComm);
// Determine my local block number
label myBlockNumber = -1;
{
fileOperation::procRangeType group;
label proci = fileOperation::detectProcessorPath(fName, group);
if (proci == -1 && group.empty())
{
// 'processorsXXX' format so contains all ranks
// according to worldComm
myBlockNumber = globalProci;
}
else
{
// 'processorsXXX_n-m' format so check for relative rank
myBlockNumber = handlerProci;
}
}
// Since we are streaming anyhow, could also pack as tuple:
// Tuple2<fileName, label>
// Collect file names on master of local communicator
const fileNameList fNames
( (
Pstream::listGatherValues handler.readDir(path, fileName::Type::DIRECTORY)
(
fName,
handlerComm,
UPstream::msgType()
)
); );
// Collect block numbers on master of local communicator // Extract info from processorN or processorsNN
const labelList myBlockNumbers // - highest processor number
( // - directory+offset containing data for proci
Pstream::listGatherValues
(
myBlockNumber,
handlerComm,
UPstream::msgType()
)
);
// Determine for all whether the filename exists in the collated file. // label nProcs = 0;
boolList allFound; for (const fileName& dirN : dirEntries)
if (UPstream::master(handlerComm))
{ {
allFound.resize(nHandlerProcs, false); // Analyse directory name
label rNum(-1);
const label readProci =
fileOperation::detectProcessorPath(dirN, group, &rNum);
// Store nBlocks and index of file that was used for nBlocks if (proci == readProci)
label nBlocks = -1;
label blockRanki = -1;
forAll(fNames, ranki)
{ {
if // Found "processorN"
( if (Foam::exists(path/dirN/local))
blockRanki == -1
|| (fNames[ranki] != fNames[blockRanki])
)
{ {
blockRanki = ranki; found = true;
IFstream is(fNames[ranki]); break;
nBlocks = decomposedBlockData::getNumBlocks(is);
} }
}
else if (rNum != -1)
{
// "processorsNN" or "processorsNN_start-end"
if (group.empty())
{
// "processorsNN"
if (proci < rNum && Foam::exists(path/dirN/local))
{
found = true;
break;
}
}
else if (group.contains(proci))
{
// "processorsNN_start-end"
// - save the local proc offset
allFound[ranki] = (myBlockNumbers[ranki] < nBlocks); if (Foam::exists(path/dirN/local))
{
found = true;
break;
}
}
} }
} }
}
// Scatter using the handler communicator if (!found)
found = Pstream::listScatterValues {
( found = Foam::exists(fName);
allFound,
handlerComm,
UPstream::msgType()
);
} }
return found; return found;
} }
} // End namespace
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
Foam::bitSet Foam::haveProcessorFile
(
const word& name, // eg "faces"
const fileName& instance, // eg "constant"
const fileName& local, // eg, polyMesh
const Time& runTime,
const bool verbose
)
{
const auto& handler = Foam::fileHandler();
const fileName fName
(
handler.filePath(runTime.path()/instance/local/name)
);
bool found = handler.isFile(fName);
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{
// Test for collated format.
// Note: can test only world-master. Since even host-collated will have
// same file format type for all processors
if (UPstream::master(UPstream::worldComm))
{
const bool oldParRun = UPstream::parRun(false);
if (IFstream is(fName); is.good())
{
IOobject io(name, instance, local, runTime);
io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io);
}
UPstream::parRun(oldParRun);
}
Pstream::broadcast(isCollated, UPstream::worldComm);
}
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Globally consistent information about who has the file
bitSet haveFileOnProc = bitSet::allGather(found, UPstream::worldComm);
if (verbose)
{
Info<< "Per processor availability of \""
<< name << "\" file in " << instance/local << nl
<< " " << flatOutput(haveFileOnProc) << nl << endl;
}
return haveFileOnProc;
}
Foam::boolList Foam::haveMeshFile
(
const word& name, // eg "faces"
const fileName& instance, // eg "constant"
const fileName& local, // eg, polyMesh
const Time& runTime,
const bool verbose
)
{
const auto& handler = Foam::fileHandler();
const fileName fName
(
handler.filePath(runTime.path()/instance/local/name)
);
bool found = handler.isFile(fName);
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{
// Test for collated format.
// Note: can test only world-master. Since even host-collated will have
// same file format type for all processors
if (UPstream::master(UPstream::worldComm))
{
const bool oldParRun = UPstream::parRun(false);
if (IFstream is(fName); is.good())
{
IOobject io(name, instance, local, runTime);
io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io);
}
UPstream::parRun(oldParRun);
}
Pstream::broadcast(isCollated, UPstream::worldComm);
}
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Globally consistent information about who has a mesh
boolList haveFileOnProc
(
UPstream::allGatherValues<bool>(found, UPstream::worldComm)
);
if (verbose)
{
Info<< "Per processor availability of \""
<< name << "\" file in " << instance/local << nl
<< " " << flatOutput(haveFileOnProc) << nl << endl;
}
return haveFileOnProc;
}
Foam::boolList Foam::haveMeshFile Foam::boolList Foam::haveMeshFile
( (
@ -302,49 +135,143 @@ Foam::boolList Foam::haveMeshFile
const bool verbose const bool verbose
) )
{ {
#if 0
// Simple directory scanning - too fragile
bool found = checkFileExistence(runTime.path()/meshPath/meshFile);
#else
// Trimmed-down version of lookupAndCacheProcessorsPath
// with Foam::exists() check. No caching.
// Check for two conditions:
// - file has to exist
// - if collated the entry has to exist inside the file
// Note: bypass fileOperation::filePath(IOobject&) since has problems
// with going to a different number of processors
// (in collated format). Use file-based searching instead
const auto& handler = Foam::fileHandler(); const auto& handler = Foam::fileHandler();
typedef fileOperation::procRangeType procRangeType;
const fileName fName const fileName fName
( (
handler.filePath(runTime.path()/meshPath/meshFile) handler.filePath(runTime.path()/meshPath/meshFile)
); );
bool found = handler.isFile(fName); bool found = handler.isFile(fName);
if (returnReduceAnd(found)) // worldComm
// Assume non-collated (as fallback value).
// If everyone claims to have the file, use master to verify if
// collated is involved.
bool isCollated = false;
if (returnReduceAnd(found, UPstream::worldComm))
{ {
// Test for collated format. // Bit tricky: avoid having all slaves open file since this involves
// reading it on master and broadcasting it. This fails if file > 2G.
// So instead only read on master
bool isCollated = false;
// Note: can test only world-master. Since even host-collated will have // Note: can test only world-master. Since even host-collated will have
// same file format type for all processors // same file format type for all processors
if (UPstream::master(UPstream::worldComm)) if (UPstream::master(UPstream::worldComm))
{ {
const bool oldParRun = UPstream::parRun(false); const bool oldParRun = UPstream::parRun(false);
if (IFstream is(fName); is.good()) IFstream is(fName);
if (is.good())
{ {
IOobject io(meshFile, meshPath, runTime); IOobject io(meshFile, meshPath, runTime);
io.readHeader(is); io.readHeader(is);
isCollated = decomposedBlockData::isCollatedType(io); isCollated = decomposedBlockData::isCollatedType(io);
} }
UPstream::parRun(oldParRun); UPstream::parRun(oldParRun);
} }
Pstream::broadcast(isCollated, UPstream::worldComm); Pstream::broadcast(isCollated); //UPstream::worldComm
}
// For collated, check that the corresponding blocks exist
if (isCollated)
{
found = checkFileExistenceCollated(handler, fName);
}
// Collect block-number in individual filenames (might differ
// on different processors)
if (isCollated)
{
const label nProcs = UPstream::nProcs(fileHandler().comm());
const label myProcNo = UPstream::myProcNo(fileHandler().comm());
// Collect file names on master of local communicator
const fileNameList fNames
(
Pstream::listGatherValues
(
fName,
fileHandler().comm(),
UPstream::msgType()
)
);
// Collect local block number
label myBlockNumber = -1;
{
procRangeType group;
label proci = fileOperation::detectProcessorPath(fName, group);
if (proci == -1 && group.empty())
{
// 'processorsXXX' format so contains all ranks
// according to worldComm
myBlockNumber = UPstream::myProcNo(UPstream::worldComm);
}
else
{
// 'processorsXXX_n-m' format so check for the
// relative rank
myBlockNumber = myProcNo;
}
}
const labelList myBlockNumbers
(
Pstream::listGatherValues
(
myBlockNumber,
fileHandler().comm(),
UPstream::msgType()
)
);
// Determine for all whether the filename exists in the collated
// file.
boolList allFound(nProcs, false);
if (UPstream::master(fileHandler().comm()))
{
// Store nBlocks and index of file that was used for nBlocks
label nBlocks = -1;
label blockRanki = -1;
forAll(fNames, ranki)
{
if
(
blockRanki == -1
|| (fNames[ranki] != fNames[blockRanki])
)
{
blockRanki = ranki;
IFstream is(fNames[ranki]);
nBlocks = decomposedBlockData::getNumBlocks(is);
}
allFound[ranki] = (myBlockNumbers[ranki] < nBlocks);
}
}
found = Pstream::listScatterValues
(
allFound,
fileHandler().comm(),
UPstream::msgType()
);
}
}
#endif
// Globally consistent information about who has a mesh // Globally consistent information about who has a mesh
boolList haveFileOnProc boolList haveFileOnProc

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2012 OpenFOAM Foundation Copyright (C) 2012 OpenFOAM Foundation
Copyright (C) 2022-2025 OpenCFD Ltd. Copyright (C) 2022-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -48,32 +48,15 @@ namespace Foam
// Forward Declarations // Forward Declarations
class faMesh; class faMesh;
//- Check for availability of specified file (on all ranks) //- Check for availability of given file
bitSet haveProcessorFile bool checkFileExistence(const fileName& fName);
(
const word& name, // eg, "faces"
const fileName& instance, // eg, "constant"
const fileName& local, // eg, "polyMesh"
const Time& runTime,
const bool verbose = true
);
//- Check for availability of specified file (on all ranks) //- Check for availability of specified mesh file (default: "faces")
boolList haveMeshFile
(
const word& name, // eg, "faces"
const fileName& instance, // eg, "constant"
const fileName& local, // eg, "polyMesh"
const Time& runTime,
const bool verbose = true
);
//- Check for availability of specified mesh file
boolList haveMeshFile boolList haveMeshFile
( (
const Time& runTime, const Time& runTime,
const fileName& meshPath, const fileName& meshPath,
const word& meshFile, const word& meshFile = "faces",
const bool verbose = true const bool verbose = true
); );
@ -92,7 +75,7 @@ void masterMeshInstance
fileName& pointsInstance fileName& pointsInstance
); );
} // End namespace Foam }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -21,59 +21,44 @@ Requires
// Initially all possible objects that are available at the final time // Initially all possible objects that are available at the final time
List<wordHashSet> availableRegionObjectNames(meshes.size()); List<wordHashSet> availableRegionObjectNames(meshes.size());
List<HashTable<wordHashSet>> availableFaRegionObjectNames(meshes.size()); List<wordHashSet> availableFaRegionObjectNames(meshes.size());
forAll(meshes, regioni) forAll(meshes, regioni)
{ {
const auto& mesh = meshes[regioni]; const auto& mesh = meshes[regioni];
IOobjectList objects; IOobjectList objects;
HashTable<IOobjectList> faObjects; IOobjectList faObjects;
if (doConvertFields && !timeDirs.empty()) if (doConvertFields && !timeDirs.empty())
{ {
// const word& checkTimeDir = timeDirs.back().name();
// List of volume mesh objects for this instance // List of volume mesh objects for this instance
objects = IOobjectList(mesh, timeDirs.back().name()); objects = IOobjectList(mesh, timeDirs.back().name());
// List of area mesh objects (assuming single region)
faObjects = IOobjectList
(
mesh.time(),
timeDirs.back().name(),
faMesh::dbDir(mesh, word::null),
IOobjectOption::NO_REGISTER
);
if (fieldSelector) if (fieldSelector)
{ {
objects.filterObjects(fieldSelector); objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector);
} }
// Remove "*_0" restart fields // Remove "*_0" restart fields
objects.prune_0(); objects.prune_0();
faObjects.prune_0();
if (!doPointValues) if (!doPointValues)
{ {
// Prune point fields if disabled // Prune point fields if disabled
objects.filterClasses(Foam::fieldTypes::is_point, true); objects.filterClasses(Foam::fieldTypes::is_point, true);
} }
// The finite-area regions and their fields for this volume region
// and instance
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
IOobjectList objs
(
faMesh::Registry(mesh),
timeDirs.back().name(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objs.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objs.prune_0();
faObjects(areaName) = std::move(objs);
}
} }
// Volume fields // Volume fields
@ -93,29 +78,20 @@ forAll(meshes, regioni)
} }
// Area fields // Area fields
for (const word& areaName : areaRegionNames) if (!faObjects.empty())
{ {
wordList objectNames; wordList objectNames(faObjects.sortedNames());
if (const auto iter = faObjects.cfind(areaName); iter.good()) // Check availability for all times... (assuming single region)
{ checkData
objectNames = iter.val().sortedNames();
// Check availability for all times...
checkData
(
faMesh::Registry(mesh),
timeDirs,
objectNames,
polyMesh::regionName(areaName)
);
}
availableFaRegionObjectNames[regioni].emplace_set
( (
areaName, mesh.time(),
std::move(objectNames) timeDirs,
objectNames,
faMesh::dbDir(mesh, word::null)
); );
availableFaRegionObjectNames[regioni] = objectNames;
} }
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021-2025 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -15,14 +15,12 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
// Cases and meshes per volume region
PtrList<ensightCase> ensightCases(regionNames.size()); PtrList<ensightCase> ensightCases(regionNames.size());
PtrList<ensightMesh> ensightMeshes(regionNames.size()); PtrList<ensightMesh> ensightMeshes(regionNames.size());
// Per volume region can have multiple finite-area regions PtrList<faMesh> meshesFa(regionNames.size());
List<PtrDynList<faMesh>> meshesFa(regionNames.size()); PtrList<ensightCase> ensightCasesFa(regionNames.size());
List<PtrDynList<ensightCase>> ensightCasesFa(regionNames.size()); PtrList<ensightFaMesh> ensightMeshesFa(regionNames.size());
List<PtrDynList<ensightFaMesh>> ensightMeshesFa(regionNames.size());
{ {
forAll(regionNames, regioni) forAll(regionNames, regioni)
@ -47,7 +45,6 @@ List<PtrDynList<ensightFaMesh>> ensightMeshesFa(regionNames.size());
} }
} }
// Volume mesh
ensightMeshes.set ensightMeshes.set
( (
regioni, regioni,
@ -62,59 +59,32 @@ List<PtrDynList<ensightFaMesh>> ensightMeshesFa(regionNames.size());
new ensightCase(ensCasePath, ensCaseName, caseOpts) new ensightCase(ensCasePath, ensCaseName, caseOpts)
); );
if (!doFiniteArea) if (doFiniteArea)
{ {
continue; autoPtr<faMesh> faMeshPtr(faMesh::TryNew(mesh));
}
// Note: not every volume region is guaranteed to have
// any or all area region(s)
meshesFa[regioni].reserve_exact(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
auto faMeshPtr = faMesh::TryNew(areaName, mesh);
if (faMeshPtr) if (faMeshPtr)
{ {
meshesFa[regioni].push_back(std::move(faMeshPtr)); ensightCasesFa.set
}
}
// Setup the ensight components
const label nAreas = meshesFa[regioni].size();
ensightCasesFa[regioni].reserve_exact(nAreas);
ensightMeshesFa[regioni].reserve_exact(nAreas);
for (const faMesh& areaMesh : meshesFa[regioni])
{
// Use regionName() - automatically filters for defaultRegion
const word& areaName = areaMesh.regionName();
if (areaName.empty())
{
// single-region
ensightCasesFa[regioni].emplace_back
( (
ensCasePath/"finite-area", regioni,
"finite-area", new ensightCase
caseOpts (
ensCasePath/"finite-area",
"finite-area",
caseOpts
)
); );
}
else
{
// multi-region
ensightCasesFa[regioni].emplace_back
(
ensCasePath/"finite-area"/areaName,
areaName,
caseOpts
);
}
auto& ensFaMesh = ensightMeshesFa[regioni].emplace_back(areaMesh); meshesFa.set(regioni, std::move(faMeshPtr));
ensFaMesh.verbose(optVerbose);
ensightMeshesFa.set
(
regioni,
new ensightFaMesh(meshesFa[regioni])
);
ensightMeshesFa[regioni].verbose(optVerbose);
}
} }
} }
} }

View File

@ -124,7 +124,6 @@ Usage
#include "OFstream.H" #include "OFstream.H"
#include "Pstream.H" #include "Pstream.H"
#include "HashOps.H" #include "HashOps.H"
#include "PtrDynList.H"
#include "regionProperties.H" #include "regionProperties.H"
#include "fvc.H" #include "fvc.H"
@ -173,7 +172,6 @@ int main(int argc, char *argv[])
argList::addVerboseOption(); argList::addVerboseOption();
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addBoolOption argList::addBoolOption
( (
@ -441,14 +439,6 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region // Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Directory management // Directory management
@ -528,32 +518,29 @@ int main(int argc, char *argv[])
polyMesh::readUpdateState meshState = mesh.readUpdate(); polyMesh::readUpdateState meshState = mesh.readUpdate();
const bool moving = (meshState != polyMesh::UNCHANGED); const bool moving = (meshState != polyMesh::UNCHANGED);
// Ensight (fvMesh) // Ensight
auto& ensCase = ensightCases[regioni]; auto& ensCase = ensightCases[regioni];
auto& ensMesh = ensightMeshes[regioni]; auto& ensMesh = ensightMeshes[regioni];
// Finite-area (can be missing)
auto* ensFaCasePtr = ensightCasesFa.get(regioni);
auto* ensFaMeshPtr = ensightMeshesFa.get(regioni);
ensCase.setTime(timeDirs[timei], timeIndex); ensCase.setTime(timeDirs[timei], timeIndex);
if (ensFaCasePtr)
// Finite-area (optional)
// Accounting exists for each volume region but may be empty
auto& ensFaCases = ensightCasesFa[regioni];
auto& ensFaMeshes = ensightMeshesFa[regioni];
for (auto& ensFaCase : ensFaCases)
{ {
ensFaCase.setTime(timeDirs[timei], timeIndex); ensFaCasePtr->setTime(timeDirs[timei], timeIndex);
} }
// Movement
if (moving) if (moving)
{ {
ensMesh.expire(); ensMesh.expire();
ensMesh.correct(); ensMesh.correct();
for (auto& ensFaMesh : ensFaMeshes) if (ensFaMeshPtr)
{ {
ensFaMesh.expire(); ensFaMeshPtr->expire();
ensFaMesh.correct(); ensFaMeshPtr->correct();
} }
} }
@ -568,19 +555,15 @@ int main(int argc, char *argv[])
} }
// finite-area // finite-area
forAll(ensFaMeshes, areai) if (ensFaCasePtr && ensFaMeshPtr)
{ {
const auto& ensFaCase = ensFaCases[areai];
const auto& ensFaMesh = ensFaMeshes[areai];
autoPtr<ensightGeoFile> os = autoPtr<ensightGeoFile> os =
ensFaCase.newGeometry(hasMovingMesh); ensFaCasePtr->newGeometry(hasMovingMesh);
ensFaMesh.write(os.ref()); ensFaMeshPtr->write(os.ref());
} }
} }
// Objects at this time // Objects at this time
IOobjectList objects(mesh, runTime.timeName()); IOobjectList objects(mesh, runTime.timeName());
@ -592,37 +575,23 @@ int main(int argc, char *argv[])
// Volume, internal, point fields // Volume, internal, point fields
#include "convertVolumeFields.H" #include "convertVolumeFields.H"
// finite-area // The finite-area objects at this time
forAll(ensFaMeshes, areai) IOobjectList faObjects;
if (ensFaMeshPtr)
{ {
auto* ensFaCasePtr = ensFaCases.get(areai); faObjects =
auto* ensFaMeshPtr = ensFaMeshes.get(areai); IOobjectList(ensFaMeshPtr->mesh(), runTime.timeName());
// The finite-area region objects at this time faObjects.filterObjects
IOobjectList faObjects; (
availableFaRegionObjectNames[regioni]
if (ensFaMeshPtr) );
{
const word& areaName = ensFaMeshPtr->mesh().name();
faObjects = IOobjectList
(
faMesh::Registry(mesh),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
faObjects.filterObjects
(
availableFaRegionObjectNames[regioni](areaName)
);
}
// The finiteArea fields
#include "convertAreaFields.H"
} }
// The finiteArea fields
#include "convertAreaFields.H"
// Lagrangian fields // Lagrangian fields
#include "convertLagrangian.H" #include "convertLagrangian.H"
} }
@ -635,13 +604,14 @@ int main(int argc, char *argv[])
// Write cases // Write cases
forAll(ensightCases, regioni) forAll(ensightCases, regioni)
{ {
// finite-volume
ensightCases[regioni].write(); ensightCases[regioni].write();
}
// Finite-area (if any) forAll(ensightCasesFa, regioni)
for (const auto& ensFaCase : ensightCasesFa[regioni]) {
if (ensightCasesFa.set(regioni))
{ {
ensFaCase.write(); ensightCasesFa[regioni].write();
} }
} }

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.
@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "readFields.H" #include "readFields.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
@ -41,30 +42,26 @@ Foam::label Foam::checkData
wordHashSet goodFields; wordHashSet goodFields;
IOobject io
(
"any-name", // placeholder
"constant", // placeholder
local,
obr,
IOobjectOption::NO_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
for (const word& fieldName : objectNames) for (const word& fieldName : objectNames)
{ {
// In case prune_0() not previously used... // // If prune_0() not previously used...
if (fieldName.ends_with("_0")) continue; // if (objectNames.ends_with("_0")) continue;
bool good = false; bool good = false;
for (const instant& inst : timeDirs) for (const instant& inst : timeDirs)
{ {
io.resetHeader(fieldName); good =
io.instance() = inst.name(); IOobject
(
good = io.typeHeaderOk<regIOobject>(false, false); fieldName,
inst.name(),
local,
obr,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
).typeHeaderOk<volScalarField>(false, false);
if (!good) if (!good)
{ {

View File

@ -22,66 +22,24 @@ Description
// //
// No subsetting! // No subsetting!
if (doFiniteArea && !areaRegionNames.empty()) if (doFiniteArea)
{ {
using reportFields = foamToVtkReportFields; using reportFields = foamToVtkReportFields;
// The (region) polyMesh being used. No subsetting possible autoPtr<faMesh> faMeshPtr;
const auto& basePolyMesh = meshProxy.baseMesh();
for (const word& areaName : areaRegionNames) const label nAreaFields = faObjects.count(Foam::fieldTypes::is_area);
if (nAreaFields || withMeshIds)
{ {
const bool isDefaultRegion(polyMesh::regionName(areaName).empty()); faMeshPtr = faMesh::TryNew(meshProxy.baseMesh());
}
// CAUTION if (faMeshPtr && (nAreaFields || withMeshIds))
// If we want to have constant access to the HashTable: {
// const faMesh& areaMesh = faMeshPtr();
// (SEGFAULT)
// const auto& faObjs = faObjects.lookup(areaName, IOobjectList());
//
// Use an empty fallback to avoid binding to a temporary:
//
// const IOobjectList emptyObjectList;
// const auto& faObjs = faObjects.lookup(areaName, emptyObjectList);
// Since we do not need the area fields afterwards, reportFields::area(Info, faObjects);
// just move them out from the HashTable
IOobjectList faObjs;
if (auto iter = faObjects.find(areaName); iter.good())
{
faObjs = std::move(iter.val());
}
const label nAreaFields = faObjs.count(Foam::fieldTypes::is_area);
autoPtr<faMesh> faMeshPtr;
if (nAreaFields || withMeshIds)
{
faMeshPtr = faMesh::TryNew(areaName, basePolyMesh);
}
if (!faMeshPtr)
{
if (!isDefaultRegion)
{
// Report any area region specified but missing
// - silently ignore region0
Info<< "No area-mesh [" << polyMesh::regionName(areaName)
<< "] on volume-region ["
<< basePolyMesh.regionName() << "]" << endl;
}
continue;
}
const auto& areaMesh = faMeshPtr();
Info<< "Using area-mesh [" << polyMesh::regionName(areaName)
<< "] on volume-region ["
<< basePolyMesh.regionName() << "]" << endl;
reportFields::area(Info, faObjs);
const auto& pp = faMeshPtr->patch(); const auto& pp = faMeshPtr->patch();
@ -91,12 +49,7 @@ if (doFiniteArea && !areaRegionNames.empty())
writeOpts, writeOpts,
( (
outputDir/regionDir/"finite-area" outputDir/regionDir/"finite-area"
/ ( / "finiteArea" + timeDesc
isDefaultRegion
? fileName("finiteArea")
: fileName(areaName/areaName)
)
+ timeDesc
), ),
UPstream::parRun() UPstream::parRun()
); );
@ -143,7 +96,7 @@ if (doFiniteArea && !areaRegionNames.empty())
( (
writer, writer,
areaMesh, areaMesh,
faObjs, faObjects,
true // syncPar true // syncPar
); );

View File

@ -135,13 +135,13 @@ Note
#include "emptyPolyPatch.H" #include "emptyPolyPatch.H"
#include "volPointInterpolation.H" #include "volPointInterpolation.H"
#include "faceZoneMesh.H" #include "faceZoneMesh.H"
#include "faMesh.H"
#include "areaFields.H" #include "areaFields.H"
#include "fvMeshSubsetProxy.H" #include "fvMeshSubsetProxy.H"
#include "faceSet.H" #include "faceSet.H"
#include "pointSet.H" #include "pointSet.H"
#include "HashOps.H" #include "HashOps.H"
#include "regionProperties.H" #include "regionProperties.H"
#include "stringListOps.H" // For stringListOps::findMatching()
#include "Cloud.H" #include "Cloud.H"
#include "readFields.H" #include "readFields.H"
@ -434,7 +434,6 @@ int main(int argc, char *argv[])
argList::addOptionCompat("one-boundary", {"allPatches", 1806}); argList::addOptionCompat("one-boundary", {"allPatches", 1806});
#include "addAllRegionOptions.H" #include "addAllRegionOptions.H"
#include "addAllFaRegionOptions.H"
argList::addOption argList::addOption
( (
@ -631,16 +630,6 @@ int main(int argc, char *argv[])
// Handle -allRegions, -regions, -region // Handle -allRegions, -regions, -region
#include "getAllRegionOptions.H" #include "getAllRegionOptions.H"
// Handle -all-area-regions, -area-regions, -area-region
#include "getAllFaRegionOptions.H"
if (!doFiniteArea)
{
areaRegionNames.clear(); // For consistency
}
// ------------------------------------------------------------------------
// Names for sets and zones // Names for sets and zones
word cellSelectionName; word cellSelectionName;
word faceSetName; word faceSetName;
@ -788,11 +777,8 @@ int main(int argc, char *argv[])
} }
} }
// fvMesh fields
IOobjectList objects; IOobjectList objects;
IOobjectList faObjects;
// faMesh fields (multiple finite-area regions per volume region)
HashTable<IOobjectList> faObjects;
if (doConvertFields) if (doConvertFields)
{ {
@ -800,51 +786,33 @@ int main(int argc, char *argv[])
objects = objects =
IOobjectList(meshProxy.baseMesh(), runTime.timeName()); IOobjectList(meshProxy.baseMesh(), runTime.timeName());
// List of area mesh objects (assuming single region)
faObjects =
IOobjectList
(
runTime,
runTime.timeName(),
faMesh::dbDir(meshProxy.baseMesh(), word::null),
IOobjectOption::NO_REGISTER
);
if (fieldSelector) if (fieldSelector)
{ {
objects.filterObjects(fieldSelector); objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector);
} }
// Remove "*_0" restart fields // Remove "*_0" restart fields
objects.prune_0(); objects.prune_0();
faObjects.prune_0();
if (!doPointValues) if (!doPointValues)
{ {
// Prune point fields if disabled // Prune point fields if disabled
objects.filterClasses(Foam::fieldTypes::is_point, true); objects.filterClasses(Foam::fieldTypes::is_point, true);
} }
// Lists of finite-area fields
faObjects.reserve(areaRegionNames.size());
for (const word& areaName : areaRegionNames)
{
// The finite-area objects for given area region.
// Add as method to faMeshesRegistry?
IOobjectList objs
(
faMesh::Registry(meshProxy.baseMesh()),
runTime.timeName(),
polyMesh::regionName(areaName),
IOobjectOption::NO_REGISTER
);
if (fieldSelector)
{
objs.filterObjects(fieldSelector);
}
// Remove "*_0" restart fields
objs.prune_0();
if (!objs.empty())
{
faObjects.emplace_set(areaName, std::move(objs));
}
}
} }
if (processorFieldsOnly) if (processorFieldsOnly)
{ {
// Processor-patches only and continue // Processor-patches only and continue

View File

@ -1,10 +1,10 @@
EXE_INC = \ EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/finiteArea/lnInclude -I$(LIB_SRC)/finiteArea/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \ EXE_LIBS = \
-lmeshTools \
-lfiniteVolume \ -lfiniteVolume \
-lfiniteArea \ -lfiniteArea \
-lmeshTools \
-lgenericPatchFields -lgenericPatchFields

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2022-2025 OpenCFD Ltd. Copyright (C) 2022-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -47,7 +47,6 @@ Description
#include "areaFields.H" #include "areaFields.H"
#include "coupledFvPatch.H" #include "coupledFvPatch.H"
#include "coupledFaPatch.H" #include "coupledFaPatch.H"
#include "regionProperties.H"
using namespace Foam; using namespace Foam;
@ -87,18 +86,17 @@ bool consumeUnusedType(const fieldDescription& fieldDesc, Istream& is)
//? typedef GeometricField<Type, faePatchField, areaMesh> fieldType3; //? typedef GeometricField<Type, faePatchField, areaMesh> fieldType3;
//? typedef GeometricField<Type, fvsPatchField, volMesh> fieldType4; //? typedef GeometricField<Type, fvsPatchField, volMesh> fieldType4;
const bool isExpectedType if
( (
fieldDesc.type() == fieldType1::typeName fieldDesc.type() == fieldType1::typeName
|| fieldDesc.type() == fieldType2::typeName || fieldDesc.type() == fieldType2::typeName
); )
if (isExpectedType)
{ {
(void) pTraits<Type>(is); (void) pTraits<Type>(is);
return true;
} }
return isExpectedType; return false;
} }
@ -124,18 +122,13 @@ bool setCellFieldType
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const fvMesh& mesh, const fvMesh& mesh,
const labelUList& selectedCells, const labelList& selectedCells,
Istream& is Istream& is
) )
{ {
typedef GeometricField<Type, fvPatchField, volMesh> fieldType; typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
const bool isExpectedType if (fieldDesc.type() != fieldType::typeName)
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{ {
return false; return false;
} }
@ -150,9 +143,7 @@ bool setCellFieldType
fieldDesc.name(), fieldDesc.name(),
mesh.thisDb().time().timeName(), mesh.thisDb().time().timeName(),
mesh.thisDb(), mesh.thisDb(),
IOobjectOption::MUST_READ, IOobject::MUST_READ
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
); );
bool found = fieldHeader.typeHeaderOk<fieldType>(true); bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -160,8 +151,13 @@ bool setCellFieldType
if (!found) if (!found)
{ {
// Fallback to "constant" directory // Fallback to "constant" directory
fieldHeader.resetHeader(); fieldHeader = IOobject
fieldHeader.instance() = mesh.thisDb().time().constant(); (
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
found = fieldHeader.typeHeaderOk<fieldType>(true); found = fieldHeader.typeHeaderOk<fieldType>(true);
} }
@ -175,7 +171,7 @@ bool setCellFieldType
fieldType field(fieldHeader, mesh, false); fieldType field(fieldHeader, mesh, false);
if (isNull(selectedCells) || (selectedCells.size() == field.size())) if (isNull(selectedCells) || selectedCells.size() == field.size())
{ {
field.primitiveFieldRef() = fieldValue; field.primitiveFieldRef() = fieldValue;
} }
@ -208,7 +204,7 @@ bool setCellFieldType
<< "Field " << fieldDesc.name() << " not found" << endl; << "Field " << fieldDesc.name() << " not found" << endl;
} }
return isExpectedType; return true;
} }
@ -220,18 +216,13 @@ bool setAreaFieldType
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const faMesh& mesh, const faMesh& mesh,
const labelUList& selectedFaces, const labelList& selectedFaces,
Istream& is Istream& is
) )
{ {
typedef GeometricField<Type, faPatchField, areaMesh> fieldType; typedef GeometricField<Type, faPatchField, areaMesh> fieldType;
const bool isExpectedType if (fieldDesc.type() != fieldType::typeName)
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{ {
return false; return false;
} }
@ -246,9 +237,7 @@ bool setAreaFieldType
fieldDesc.name(), fieldDesc.name(),
mesh.thisDb().time().timeName(), mesh.thisDb().time().timeName(),
mesh.thisDb(), mesh.thisDb(),
IOobjectOption::MUST_READ, IOobject::MUST_READ
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
); );
bool found = fieldHeader.typeHeaderOk<fieldType>(true); bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -256,8 +245,13 @@ bool setAreaFieldType
if (!found) if (!found)
{ {
// Fallback to "constant" directory // Fallback to "constant" directory
fieldHeader.resetHeader(); fieldHeader = IOobject
fieldHeader.instance() = mesh.thisDb().time().constant(), (
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
found = fieldHeader.typeHeaderOk<fieldType>(true); found = fieldHeader.typeHeaderOk<fieldType>(true);
} }
@ -298,7 +292,7 @@ bool setAreaFieldType
<< "Field " << fieldDesc.name() << " not found" << endl; << "Field " << fieldDesc.name() << " not found" << endl;
} }
return isExpectedType; return true;
} }
@ -310,18 +304,13 @@ bool setFaceFieldType
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const fvMesh& mesh, const fvMesh& mesh,
const labelUList& selectedFaces, const labelList& selectedFaces,
Istream& is Istream& is
) )
{ {
typedef GeometricField<Type, fvPatchField, volMesh> fieldType; typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
const bool isExpectedType if (fieldDesc.type() != fieldType::typeName)
(
fieldDesc.type() == fieldType::typeName
);
if (!isExpectedType)
{ {
return false; return false;
} }
@ -336,9 +325,7 @@ bool setFaceFieldType
fieldDesc.name(), fieldDesc.name(),
mesh.thisDb().time().timeName(), mesh.thisDb().time().timeName(),
mesh.thisDb(), mesh.thisDb(),
IOobjectOption::MUST_READ, IOobject::MUST_READ
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
); );
bool found = fieldHeader.typeHeaderOk<fieldType>(true); bool found = fieldHeader.typeHeaderOk<fieldType>(true);
@ -346,8 +333,13 @@ bool setFaceFieldType
if (!found) if (!found)
{ {
// Fallback to "constant" directory // Fallback to "constant" directory
fieldHeader.resetHeader(); fieldHeader = IOobject
fieldHeader.instance() = mesh.thisDb().time().constant(); (
fieldDesc.name(),
mesh.thisDb().time().constant(),
mesh.thisDb(),
IOobject::MUST_READ
);
found = fieldHeader.typeHeaderOk<fieldType>(true); found = fieldHeader.typeHeaderOk<fieldType>(true);
} }
@ -363,14 +355,15 @@ bool setFaceFieldType
// Create flat list of selected faces and their value. // Create flat list of selected faces and their value.
Field<Type> allBoundaryValues(mesh.nBoundaryFaces()); Field<Type> allBoundaryValues(mesh.nBoundaryFaces());
for (const auto& pfld : field.boundaryField()) forAll(field.boundaryField(), patchi)
{ {
SubField<Type> SubField<Type>
( (
allBoundaryValues, allBoundaryValues,
pfld.size(), field.boundaryField()[patchi].size(),
pfld.patch().offset() field.boundaryField()[patchi].patch().start()
) = pfld; - mesh.nInternalFaces()
) = field.boundaryField()[patchi];
} }
// Override // Override
@ -431,7 +424,8 @@ bool setFaceFieldType
( (
allBoundaryValues, allBoundaryValues,
fieldBf[patchi].size(), fieldBf[patchi].size(),
fieldBf[patchi].patch().offset() fieldBf[patchi].patch().start()
- mesh.nInternalFaces()
); );
} }
} }
@ -451,7 +445,7 @@ bool setFaceFieldType
<< "Field " << fieldDesc.name() << " not found" << endl; << "Field " << fieldDesc.name() << " not found" << endl;
} }
return isExpectedType; return true;
} }
@ -466,7 +460,7 @@ struct setCellField
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const fvMesh& m, const fvMesh& m,
const labelUList& selectedCells, const labelList& selectedCells,
Istream& is Istream& is
) )
{ {
@ -483,11 +477,11 @@ struct setCellField
class iNew class iNew
{ {
const fvMesh& mesh_; const fvMesh& mesh_;
const labelUList& selected_; const labelList& selected_;
public: public:
iNew(const fvMesh& mesh, const labelUList& selectedCells) noexcept iNew(const fvMesh& mesh, const labelList& selectedCells)
: :
mesh_(mesh), mesh_(mesh),
selected_(selectedCells) selected_(selectedCells)
@ -534,7 +528,7 @@ struct setFaceField
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const fvMesh& m, const fvMesh& m,
const labelUList& selectedFaces, const labelList& selectedFaces,
Istream& is Istream& is
) )
{ {
@ -551,11 +545,11 @@ struct setFaceField
class iNew class iNew
{ {
const fvMesh& mesh_; const fvMesh& mesh_;
const labelUList& selected_; const labelList& selected_;
public: public:
iNew(const fvMesh& mesh, const labelUList& selectedFaces) noexcept iNew(const fvMesh& mesh, const labelList& selectedFaces)
: :
mesh_(mesh), mesh_(mesh),
selected_(selectedFaces) selected_(selectedFaces)
@ -602,7 +596,7 @@ struct setAreaField
( (
const fieldDescription& fieldDesc, const fieldDescription& fieldDesc,
const faMesh& m, const faMesh& m,
const labelUList& selectedFaces, const labelList& selectedFaces,
Istream& is Istream& is
) )
{ {
@ -619,11 +613,11 @@ struct setAreaField
class iNew class iNew
{ {
const faMesh& mesh_; const faMesh& mesh_;
const labelUList& selected_; const labelList& selected_;
public: public:
iNew(const faMesh& mesh, const labelUList& selectedFaces) noexcept iNew(const faMesh& mesh, const labelList& selectedFaces)
: :
mesh_(mesh), mesh_(mesh),
selected_(selectedFaces) selected_(selectedFaces)
@ -681,7 +675,6 @@ int main(int argc, char *argv[])
); );
#include "addRegionOption.H" #include "addRegionOption.H"
#include "addAllFaRegionOptions.H"
// ------------------------- // -------------------------
@ -693,59 +686,15 @@ int main(int argc, char *argv[])
#include "createNamedMesh.H" #include "createNamedMesh.H"
// Handle -all-area-regions, -area-regions, -area-region autoPtr<faMesh> faMeshPtr;
#include "getAllFaRegionOptions.H"
if (args.found("no-finite-area")) if (!args.found("no-finite-area"))
{ {
areaRegionNames.clear(); // For consistency faMeshPtr = faMesh::TryNew(mesh);
} }
if (faMeshPtr)
// ------------------------------------------------------------------------
PtrList<faMesh> faMeshes;
// Setup all area meshes on this region
if (!areaRegionNames.empty()) // ie, !args.found("no-finite-area")
{ {
faMeshes.resize(areaRegionNames.size()); Info<< "Detected finite-area mesh" << nl;
label nGoodRegions(0);
for (const word& areaName : areaRegionNames)
{
autoPtr<faMesh> faMeshPtr = faMesh::TryNew(areaName, mesh);
if (faMeshPtr)
{
faMeshes.set(nGoodRegions++, std::move(faMeshPtr));
}
}
faMeshes.resize(nGoodRegions);
}
if (faMeshes.size() == 1)
{
Info<< "Using finite-area mesh";
if
(
const word& name = polyMesh::regionName(faMeshes[0].name());
!name.empty()
)
{
Info<< " [" << name << "]";
}
Info<< nl;
}
else if (faMeshes.size() > 1)
{
Info<< "Detected finite-area meshes:";
for (const faMesh& areaMesh : faMeshes)
{
Info<< " [" << areaMesh.name() << "]";
}
Info<< nl;
} }
const word dictName("setFieldsDict"); const word dictName("setFieldsDict");
@ -763,45 +712,37 @@ int main(int argc, char *argv[])
// Default field values // Default field values
if
(
const auto* eptr
= setFieldsDict.findEntry("defaultFieldValues", keyType::LITERAL)
)
{ {
ITstream& is = eptr->stream(); const entry* eptr =
setFieldsDict.findEntry("defaultFieldValues", keyType::LITERAL);
Info<< "Setting volume field default values" << endl; if (eptr)
PtrList<setCellField> defaultFieldValues
(
is,
setCellField::iNew(mesh, labelList::null())
);
for (const faMesh& areaMesh : faMeshes)
{ {
Info<< "Setting area field default values"; ITstream& is = eptr->stream();
if Info<< "Setting volume field default values" << endl;
(
const word& name = polyMesh::regionName(areaMesh.name());
!name.empty()
)
{
Info<< " [" << name << "]";
}
Info<< endl;
is.rewind(); PtrList<setCellField> defaultFieldValues
PtrList<setAreaField> defaultAreaFieldValues
( (
is, is,
setAreaField::iNew(areaMesh, labelList::null()) setCellField::iNew(mesh, labelList::null())
); );
if (faMeshPtr)
{
const faMesh& areaMesh = faMeshPtr();
is.rewind();
Info<< "Setting area field default values" << endl;
PtrList<setAreaField> defaultFieldValues
(
is,
setAreaField::iNew(areaMesh, labelList::null())
);
}
Info<< endl;
} }
Info<< endl;
} }
@ -827,15 +768,11 @@ int main(int argc, char *argv[])
labelList selectedCells(subset.sortedToc()); labelList selectedCells(subset.sortedToc());
{ Info<< " Selected "
FixedList<label, 2> stats; << returnReduce(selectedCells.size(), sumOp<label>())
stats[0] = selectedCells.size(); << '/'
stats[1] = mesh.nCells(); << returnReduce(mesh.nCells(), sumOp<label>())
reduce(stats, sumOp<label>()); << " cells" << nl;
Info<< " Selected " << stats[0] << '/' << stats[1]
<< " cells" << nl;
}
ITstream& is = region.dict().lookup("fieldValues"); ITstream& is = region.dict().lookup("fieldValues");
@ -869,8 +806,10 @@ int main(int argc, char *argv[])
setFaceField::iNew(mesh, selectedFaces) setFaceField::iNew(mesh, selectedFaces)
); );
for (const faMesh& areaMesh : faMeshes) if (faMeshPtr)
{ {
const faMesh& areaMesh = faMeshPtr();
const labelUList& faceLabels = areaMesh.faceLabels(); const labelUList& faceLabels = areaMesh.faceLabels();
// Transcribe from mesh faces to finite-area addressing // Transcribe from mesh faces to finite-area addressing
@ -889,15 +828,11 @@ int main(int argc, char *argv[])
} }
areaFaces.resize(nUsed); areaFaces.resize(nUsed);
{ Info<< " Selected "
FixedList<label, 2> stats; << returnReduce(areaFaces.size(), sumOp<label>())
stats[0] = areaFaces.size(); << '/'
stats[1] = faceLabels.size(); << returnReduce(faceLabels.size(), sumOp<label>())
reduce(stats, sumOp<label>()); << " area faces" << nl;
Info<< " Selected " << stats[0] << '/' << stats[1]
<< " area faces for " << areaMesh.name() << endl;
}
is.rewind(); is.rewind();

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

@ -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

@ -9,7 +9,7 @@ faceSetOption/faceSetOption.C
derivedSources=sources/derived derivedSources=sources/derived
$(derivedSources)/externalHeatFluxSource/externalHeatFluxSource.C $(derivedSources)/externalHeatFluxSource/externalHeatFluxSource.C
$(derivedSources)/jouleHeatingSource/jouleHeatingSource.cxx $(derivedSources)/jouleHeatingSource/jouleHeatingSource.C
$(derivedSources)/contactHeatFluxSource/contactHeatFluxSource.C $(derivedSources)/contactHeatFluxSource/contactHeatFluxSource.C
$(derivedSources)/externalFileSource/externalFileSource.C $(derivedSources)/externalFileSource/externalFileSource.C

View File

@ -81,33 +81,6 @@ Foam::fa::option::option
active_(dict.getOrDefault("active", true)), active_(dict.getOrDefault("active", true)),
log(true) log(true)
{ {
// Suffix hint for variable names
if
(
coeffs_.readIfPresent("suffixing", suffixHint_)
|| dict.readIfPresent("suffixing", suffixHint_)
)
{
Switch sw = Switch::find(suffixHint_);
if (sw.good())
{
if (!sw) // No suffix
{
suffixHint_.clear();
}
}
else if (suffixHint_ == "default")
{
sw = true;
}
if (sw) // Default suffix
{
suffixHint_ = '_' + regionName_;
}
}
if (dict.readIfPresent("area", areaName_)) if (dict.readIfPresent("area", areaName_))
{ {
if (!sameRegionNames(areaName_, defaultAreaName)) if (!sameRegionNames(areaName_, defaultAreaName))
@ -122,14 +95,9 @@ Foam::fa::option::option
} }
} }
Log << incrIndent << indent << "Source: " << name_; Log << incrIndent << indent << "Source: " << name_
<< " [" << polyMesh::regionName(areaName_) << ']' << endl
if (!polyMesh::regionName(areaName_).empty()) << decrIndent;
{
Log<< " [" << areaName_ << ']';
}
Info<< decrIndent << endl;
} }
@ -149,20 +117,13 @@ Foam::autoPtr<Foam::fa::option> Foam::fa::option::New
coeffs.readIfPresent("area", areaName); coeffs.readIfPresent("area", areaName);
Info<< indent Info<< indent
<< "Selecting finite-area option, type " << modelType; << "Selecting finite-area option, type " << modelType
<< " [" << polyMesh::regionName(areaName) << ']';
if (sameRegionNames(areaName, defaultAreaName)) if (!sameRegionNames(areaName, defaultAreaName))
{ {
if (!polyMesh::regionName(areaName).empty()) Info<< " != " << defaultAreaName << nl;
{
Info<< " [" << areaName << ']';
}
} }
else
{
Info<< " [" << areaName << "] != [" << defaultAreaName << ']';
}
Info<< endl; Info<< endl;
mesh.time().libs().open mesh.time().libs().open

View File

@ -65,13 +65,10 @@ Usage
--> the selected faOption settings | dictionary | no | - --> the selected faOption settings | dictionary | no | -
active | Flag to (de)activate faOption | bool | no | true active | Flag to (de)activate faOption | bool | no | true
log | Flag to log faOption-related info | bool | no | true log | Flag to log faOption-related info | bool | no | true
suffixing | Suffix hint for option variables | word | no | -
\endtable \endtable
Note Note
- Source/sink options are to be added to the right-hand side of equations. - Source/sink options are to be added to the right-hand side of equations.
- Suffixing (true|false|none|default|...) currently selects between
no suffix and ('_'+region).
SourceFiles SourceFiles
faOption.C faOption.C
@ -139,9 +136,6 @@ protected:
//- The model region name (finite-area) //- The model region name (finite-area)
word regionName_; word regionName_;
//- Suffix hint for variable names (default: "")
word suffixHint_;
// Protected Member Functions // Protected Member Functions
@ -279,7 +273,7 @@ public:
//- The source name //- The source name
const word& name() const noexcept { return name_; } const word& name() const noexcept { return name_; }
//- Return const access to the volume mesh //- Return const access to the mesh database
const fvMesh& mesh() const noexcept { return mesh_; } const fvMesh& mesh() const noexcept { return mesh_; }
//- Return dictionary //- Return dictionary
@ -310,18 +304,6 @@ public:
inline bool active(bool on) noexcept; inline bool active(bool on) noexcept;
// Helper Functions
//- The suffix hint when generating variable names
const word& suffixHint() const noexcept { return suffixHint_; }
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const char* base) const;
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const std::string& base) const;
// Checks // Checks
//- Is the source active? //- Is the source active?

View File

@ -61,18 +61,4 @@ inline const Foam::volSurfaceMapping& Foam::fa::option::vsm() const
} }
inline Foam::word
Foam::fa::option::suffixed(const char* base) const
{
return word(base + suffixHint_);
}
inline Foam::word
Foam::fa::option::suffixed(const std::string& base) const
{
return word(base + suffixHint_);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -27,6 +27,7 @@ License
#include "faOptions.H" #include "faOptions.H"
#include "faMesh.H" #include "faMesh.H"
#include "faMeshesRegistry.H"
#include "Time.H" #include "Time.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -67,7 +68,7 @@ Foam::IOobject createIOobject
lookupName, lookupName,
mesh.time().constant(), mesh.time().constant(),
// located under finite-area // located under finite-area
faMesh::Registry(mesh), faMeshesRegistry::New(mesh).thisDb(),
IOobjectOption::MUST_READ, IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE, IOobjectOption::NO_WRITE,
IOobjectOption::REGISTER IOobjectOption::REGISTER
@ -187,7 +188,11 @@ Foam::fa::options& Foam::fa::options::New
); );
// Registered under finite-area? // Registered under finite-area?
auto* ptr = faMesh::Registry(mesh).getObjectPtr<fa::options>(lookupName); auto* ptr =
faMeshesRegistry::New(mesh).thisDb().getObjectPtr<fa::options>
(
lookupName
);
if (!ptr && polyMesh::regionName(defaultAreaName).empty()) if (!ptr && polyMesh::regionName(defaultAreaName).empty())
{ {

View File

@ -30,6 +30,7 @@ License
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
#include "volFields.H" #include "volFields.H"
#include "famSup.H" #include "famSup.H"
#include "zeroGradientFaPatchFields.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
@ -56,10 +57,13 @@ Foam::fa::contactHeatFluxSource::contactHeatFluxSource
: :
fa::faceSetOption(sourceName, modelType, dict, mesh, defaultAreaName), fa::faceSetOption(sourceName, modelType, dict, mesh, defaultAreaName),
TName_(dict.getOrDefault<word>("T", "T")), TName_(dict.getOrDefault<word>("T", "T")),
TprimaryName_(dict.getOrDefault<word>("Tprimary", "T")), TprimaryName_(dict.get<word>("Tprimary")),
Tprimary_(mesh_.lookupObject<volScalarField>(TprimaryName_)), Tprimary_(mesh_.lookupObject<volScalarField>(TprimaryName_)),
thicknessLayers_(),
kappaLayers_(),
contactRes_(0), contactRes_(0),
curTimeIndex_(-1) curTimeIndex_(-1),
coupling_()
{ {
fieldNames_.resize(1, TName_); fieldNames_.resize(1, TName_);
@ -127,30 +131,30 @@ void Foam::fa::contactHeatFluxSource::addSup
const label fieldi const label fieldi
) )
{ {
if (!isActive()) if (isActive())
{ {
return; DebugInfo
} << name() << ": applying source to "
<< eqn.psi().name() << endl;
DebugInfo<< name() << ": applying source to " << eqn.psi().name() << endl; if (curTimeIndex_ != mesh().time().timeIndex())
{
tmp<DimensionedField<scalar, areaMesh>> htcw(htc());
if (curTimeIndex_ != mesh().time().timeIndex()) // Wall temperature - mapped from primary field to finite-area
{ auto Twall = DimensionedField<scalar, areaMesh>::New
tmp<DimensionedField<scalar, areaMesh>> htcw(htc()); (
"Tw_" + option::name(),
regionMesh(),
dimensionedScalar(dimTemperature, Zero)
);
// Wall temperature - mapped from primary field to finite-area vsm().mapInternalToSurface<scalar>(Tprimary_, Twall.ref().field());
auto Twall = DimensionedField<scalar, areaMesh>::New
(
"Tw_" + option::name(),
regionMesh(),
dimensionedScalar(dimTemperature, Zero)
);
vsm().mapInternalToSurface<scalar>(Tprimary_, Twall.ref().field()); eqn += -fam::Sp(htcw(), eqn.psi()) + htcw()*Twall;
eqn += -fam::Sp(htcw(), eqn.psi()) + htcw()*Twall; curTimeIndex_ = mesh().time().timeIndex();
}
curTimeIndex_ = mesh().time().timeIndex();
} }
} }
@ -186,14 +190,8 @@ bool Foam::fa::contactHeatFluxSource::read(const dictionary& dict)
const labelList& patches = regionMesh().whichPolyPatches(); const labelList& patches = regionMesh().whichPolyPatches();
if (patches.empty()) coupling_.clear();
{ coupling_.resize(patches.empty() ? 0 : (patches.last()+1));
coupling_.clear();
}
else
{
coupling_.resize_null(patches.back()+1);
}
for (const label patchi : patches) for (const label patchi : patches)
{ {

View File

@ -40,8 +40,6 @@ Usage
{ {
// Mandatory entries (unmodifiable) // Mandatory entries (unmodifiable)
type contactHeatFluxSource; type contactHeatFluxSource;
// Optional entries (unmodifiable)
Tprimary <TprimaryFieldName>; Tprimary <TprimaryFieldName>;
// Optional entries (runtime modifiable) // Optional entries (runtime modifiable)
@ -62,19 +60,12 @@ Usage
\table \table
Property | Description | Type | Reqd | Dflt Property | Description | Type | Reqd | Dflt
type | Type name: contactHeatFluxSource | word | yes | - type | Type name: contactHeatFluxSource | word | yes | -
Tprimary | Name of primary temperature field | word | yes | -
T | Name of operand temperature field | word | no | T T | Name of operand temperature field | word | no | T
Tprimary | Name of primary temperature field | word | no | T
thicknessLayers | List of thicknesses of layers | scalarList | no | - thicknessLayers | List of thicknesses of layers | scalarList | no | -
kappaLayers | List of conductivities of layers | scalarList | cndtnl | - kappaLayers | List of conductivities of layers | scalarList | cndtnl | -
\endtable \endtable
Fields/variables used:
\table
Property | Description | Type | Deflt
T | Temperature | shell | T
Tprimary | Temperature | volume | T
\endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
- \link faOption.H \endlink - \link faOption.H \endlink
- \link faceSetOption.H \endlink - \link faceSetOption.H \endlink
@ -133,13 +124,13 @@ class contactHeatFluxSource
// Private Data // Private Data
//- Name of shell temperature field (default: "T") //- Name of temperature field
word TName_; word TName_;
//- Name of volume temperature field (default: "T") //- Name of primary temperature field
const word TprimaryName_; word TprimaryName_;
//- Primary (volume) region temperature //- Primary region temperature
const volScalarField& Tprimary_; const volScalarField& Tprimary_;
//- Thickness of layers //- Thickness of layers

View File

@ -72,6 +72,10 @@ Foam::fa::externalHeatFluxSource::externalHeatFluxSource
fa::faceSetOption(sourceName, modelType, dict, m, defaultAreaName), fa::faceSetOption(sourceName, modelType, dict, m, defaultAreaName),
mode_(operationModeNames.get("mode", dict)), mode_(operationModeNames.get("mode", dict)),
TName_(dict.getOrDefault<word>("T", "T")), TName_(dict.getOrDefault<word>("T", "T")),
Q_(nullptr),
q_(nullptr),
h_(nullptr),
Ta_(nullptr),
emissivity_(dict.getOrDefault<scalar>("emissivity", 0)) emissivity_(dict.getOrDefault<scalar>("emissivity", 0))
{ {
fieldNames_.resize(1, TName_); fieldNames_.resize(1, TName_);
@ -201,11 +205,6 @@ bool Foam::fa::externalHeatFluxSource::read(const dictionary& dict)
mode_ = operationModeNames.get("mode", dict); mode_ = operationModeNames.get("mode", dict);
Q_.reset(nullptr);
q_.reset(nullptr);
h_.reset(nullptr);
Ta_.reset(nullptr);
switch (mode_) switch (mode_)
{ {
case fixedPower: case fixedPower:

View File

@ -103,7 +103,7 @@ Usage
\verbatim \verbatim
power | Use fixed power (supply Q) power | Use fixed power (supply Q)
flux | Use fixed heat flux (supply q) flux | Use fixed heat flux (supply q)
coefficient | Use fixes heat transfer coefficient (supply h and Ta) coefficient | Use fixes heat transfer coefficient (supply h and T)
\endverbatim \endverbatim
See also See also
@ -159,7 +159,7 @@ private:
//- Operation mode //- Operation mode
operationMode mode_; operationMode mode_;
//- Name of shell temperature field (default: "T") //- Name of temperature field
word TName_; word TName_;
//- Heat power [W] //- Heat power [W]
@ -174,7 +174,7 @@ private:
//- Ambient temperature [K] //- Ambient temperature [K]
autoPtr<Function1<scalar>> Ta_; autoPtr<Function1<scalar>> Ta_;
//- Surface emissivity for radiative transfer to ambient (default: 0) //- Optional surface emissivity for radiative transfer to ambient
scalar emissivity_; scalar emissivity_;

View File

@ -42,12 +42,6 @@ namespace fa
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "jouleHeatingSourceImpl.cxx"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fa::jouleHeatingSource::jouleHeatingSource Foam::fa::jouleHeatingSource::jouleHeatingSource
@ -65,7 +59,7 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
( (
IOobject IOobject
( (
suffixed(IOobject::scopedName(typeName, "V")), IOobject::scopedName(typeName, "V_" + regionName_),
regionMesh().thisDb().time().timeName(), regionMesh().thisDb().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::MUST_READ, IOobject::MUST_READ,
@ -74,6 +68,8 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
), ),
regionMesh() regionMesh()
), ),
scalarSigmaVsTPtr_(nullptr),
tensorSigmaVsTPtr_(nullptr),
curTimeIndex_(-1), curTimeIndex_(-1),
nIter_(1), nIter_(1),
anisotropicElectricalConductivity_(false) anisotropicElectricalConductivity_(false)
@ -82,8 +78,6 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
fa::option::resetApplied(); fa::option::resetApplied();
read(dict);
if (anisotropicElectricalConductivity_) if (anisotropicElectricalConductivity_)
{ {
Info<< " Using tensor electrical conductivity" << endl; Info<< " Using tensor electrical conductivity" << endl;
@ -96,6 +90,8 @@ Foam::fa::jouleHeatingSource::jouleHeatingSource
initialiseSigma(coeffs_, scalarSigmaVsTPtr_); initialiseSigma(coeffs_, scalarSigmaVsTPtr_);
} }
read(dict);
} }
@ -109,14 +105,12 @@ void Foam::fa::jouleHeatingSource::addSup
const label fieldi const label fieldi
) )
{ {
if (!isActive()) if (isActive())
{ {
return; DebugInfo
} << name() << ": applying source to "
<< eqn.psi().name() << endl;
DebugInfo<< name() << ": applying source to " << eqn.psi().name() << endl;
{
if (curTimeIndex_ != mesh().time().timeIndex()) if (curTimeIndex_ != mesh().time().timeIndex())
{ {
for (label i = 0; i < nIter_; ++i) for (label i = 0; i < nIter_; ++i)
@ -124,7 +118,8 @@ void Foam::fa::jouleHeatingSource::addSup
if (anisotropicElectricalConductivity_) if (anisotropicElectricalConductivity_)
{ {
// Update sigma as a function of T if required // Update sigma as a function of T if required
const auto& sigma = updateSigma(tensorSigmaVsTPtr_); const areaTensorField& sigma =
updateSigma(tensorSigmaVsTPtr_);
// Solve the electrical potential equation // Solve the electrical potential equation
faScalarMatrix VEqn(fam::laplacian(h*sigma, V_)); faScalarMatrix VEqn(fam::laplacian(h*sigma, V_));
@ -134,7 +129,8 @@ void Foam::fa::jouleHeatingSource::addSup
else else
{ {
// Update sigma as a function of T if required // Update sigma as a function of T if required
const auto& sigma = updateSigma(scalarSigmaVsTPtr_); const areaScalarField& sigma =
updateSigma(scalarSigmaVsTPtr_);
// Solve the electrical potential equation // Solve the electrical potential equation
faScalarMatrix VEqn(fam::laplacian(h*sigma, V_)); faScalarMatrix VEqn(fam::laplacian(h*sigma, V_));
@ -149,7 +145,7 @@ void Foam::fa::jouleHeatingSource::addSup
// Add the Joule heating contribution // Add the Joule heating contribution
const word sigmaName const word sigmaName
( (
IOobject::scopedName(typeName, "sigma") + suffixHint() IOobject::scopedName(typeName, "sigma_" + regionName_)
); );
areaVectorField gradV("gradV", fac::grad(V_)); areaVectorField gradV("gradV", fac::grad(V_));
@ -166,13 +162,15 @@ void Foam::fa::jouleHeatingSource::addSup
if (anisotropicElectricalConductivity_) if (anisotropicElectricalConductivity_)
{ {
const auto& sigma = obr.lookupObject<areaTensorField>(sigmaName); const auto& sigma =
obr.lookupObject<areaTensorField>(sigmaName);
tsource = (h*sigma & gradV) & gradV; tsource = (h*sigma & gradV) & gradV;
} }
else else
{ {
const auto& sigma = obr.lookupObject<areaScalarField>(sigmaName); const auto& sigma =
obr.lookupObject<areaScalarField>(sigmaName);
tsource = (h*sigma*gradV) & gradV; tsource = (h*sigma*gradV) & gradV;
} }

View File

@ -115,30 +115,23 @@ Usage
- \link faceSetOption.H \endlink - \link faceSetOption.H \endlink
Note Note
If the \c sigma entry is present, the electrical conductivity is specified - \c anisotropicElectricalConductivity=true enables
as a function of temperature using a \c Function1 type, otherwise anisotropic (tensorial) electrical conductivity.
the \c sigma field will be read from file. - \c anisotropicElectricalConductivity=false enables
When the \c anisotropicElectricalConductivity flag is set to \c true, isotropic (scalar) electrical conductivity.
\c sigma should be specified as a \em tensor quantity instead of as - The electrical conductivity can be specified using either:
an isotropic \em scalar quantity. - If the \c sigma entry is present the electrical conductivity is specified
as a function of temperature using a \c Function1 type.
BREAKING Naming changes from 2056 and earlier for the fields: - If not present the \c sigma field will be read from file.
\table - If the \c anisotropicElectricalConductivity flag is set to \c true,
Field | Scoped names | Scoped names (old) \c sigma should be specified as a tensor quantity.
V | \<scope\>:V (suffix) | \<scope\>:V_ + regionName
sigma | \<scope\>:sigma (suffix) | \<scope\>:sigma_ + regionName
\endtable
It is possible to replicate the older naming by specifying
the \c suffixing to ('_' + regionName).
See also See also
- Foam::Function1 - Foam::Function1
- Foam::fv::jouleHeatingSource
SourceFiles SourceFiles
jouleHeatingSource.cxx jouleHeatingSource.C
jouleHeatingSourceImpl.cxx jouleHeatingSourceTemplates.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -195,13 +188,13 @@ class jouleHeatingSource
void initialiseSigma void initialiseSigma
( (
const dictionary& dict, const dictionary& dict,
autoPtr<Function1<Type>>& sigmaFunctionPtr autoPtr<Function1<Type>>& sigmaVsTPtr
); );
//- Update the electrical conductivity field //- Update the electrical conductivity field
template<class Type> template<class Type>
const GeometricField<Type, faPatchField, areaMesh>& const GeometricField<Type, faPatchField, areaMesh>&
updateSigma(const autoPtr<Function1<Type>>& sigmaFunctionPtr) const; updateSigma(const autoPtr<Function1<Type>>& sigmaVsTPtr) const;
public: public:
@ -236,22 +229,22 @@ public:
// Member Functions // Member Functions
// Evaluation // Evaluation
//- Add explicit contribution to energy equation //- Add explicit contribution to compressible momentum equation
virtual void addSup virtual void addSup
( (
const areaScalarField& h, const areaScalarField& h,
const areaScalarField& rho, const areaScalarField& rho,
faMatrix<scalar>& eqn, faMatrix<scalar>& eqn,
const label fieldi const label fieldi
); );
// IO // IO
//- Read source dictionary //- Read source dictionary
virtual bool read(const dictionary& dict); virtual bool read(const dictionary& dict);
}; };
@ -262,6 +255,12 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "jouleHeatingSourceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2025 OpenCFD Ltd. Copyright (C) 2019-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -33,21 +33,16 @@ template<class Type>
void Foam::fa::jouleHeatingSource::initialiseSigma void Foam::fa::jouleHeatingSource::initialiseSigma
( (
const dictionary& dict, const dictionary& dict,
autoPtr<Function1<Type>>& sigmaFunctionPtr autoPtr<Function1<Type>>& sigmaVsTPtr
) )
{ {
typedef GeometricField<Type, faPatchField, areaMesh> FieldType; typedef GeometricField<Type, faPatchField, areaMesh> FieldType;
const word sigmaName
(
IOobject::scopedName(typeName, "sigma") + suffixHint()
);
auto& obr = regionMesh().thisDb(); auto& obr = regionMesh().thisDb();
IOobject io IOobject io
( (
sigmaName, IOobject::scopedName(typeName, "sigma_" + regionName_),
obr.time().timeName(), obr.time().timeName(),
obr, obr,
IOobject::NO_READ, IOobject::NO_READ,
@ -57,11 +52,11 @@ void Foam::fa::jouleHeatingSource::initialiseSigma
autoPtr<FieldType> tsigma; autoPtr<FieldType> tsigma;
// Is sigma defined using a Function1 type? if (dict.found("sigma"))
sigmaFunctionPtr = Function1<Type>::NewIfPresent("sigma", dict, &mesh_);
if (sigmaFunctionPtr)
{ {
// Sigma to be defined using a Function1 type
sigmaVsTPtr = Function1<Type>::New("sigma", dict, &mesh_);
tsigma.reset tsigma.reset
( (
new FieldType new FieldType
@ -94,34 +89,31 @@ template<class Type>
const Foam::GeometricField<Type, Foam::faPatchField, Foam::areaMesh>& const Foam::GeometricField<Type, Foam::faPatchField, Foam::areaMesh>&
Foam::fa::jouleHeatingSource::updateSigma Foam::fa::jouleHeatingSource::updateSigma
( (
const autoPtr<Function1<Type>>& sigmaFunctionPtr const autoPtr<Function1<Type>>& sigmaVsTPtr
) const ) const
{ {
typedef GeometricField<Type, faPatchField, areaMesh> FieldType; typedef GeometricField<Type, faPatchField, areaMesh> FieldType;
const word sigmaName
(
IOobject::scopedName(typeName, "sigma") + suffixHint()
);
const auto& obr = regionMesh().thisDb(); const auto& obr = regionMesh().thisDb();
auto& sigma = obr.lookupObjectRef<FieldType>(sigmaName); auto& sigma =
obr.lookupObjectRef<FieldType>
(
IOobject::scopedName(typeName, "sigma_" + regionName_)
);
if (!sigmaFunctionPtr) if (!sigmaVsTPtr)
{ {
// Electrical conductivity field, sigma, was specified by the user // Electrical conductivity field, sigma, was specified by the user
return sigma; return sigma;
} }
const auto& sigmaFunction = sigmaFunctionPtr();
const auto& T = obr.lookupObject<areaScalarField>(TName_); const auto& T = obr.lookupObject<areaScalarField>(TName_);
// Internal field // Internal field
forAll(sigma, i) forAll(sigma, i)
{ {
sigma[i] = sigmaFunction.value(T[i]); sigma[i] = sigmaVsTPtr->value(T[i]);
} }
@ -135,7 +127,7 @@ Foam::fa::jouleHeatingSource::updateSigma
const scalarField& Tbf = T.boundaryField()[patchi]; const scalarField& Tbf = T.boundaryField()[patchi];
forAll(pf, facei) forAll(pf, facei)
{ {
pf[facei] = sigmaFunction.value(Tbf[facei]); pf[facei] = sigmaVsTPtr->value(Tbf[facei]);
} }
} }
} }

View File

@ -28,7 +28,6 @@ License
#include "faMesh.H" #include "faMesh.H"
#include "faMeshBoundaryHalo.H" #include "faMeshBoundaryHalo.H"
#include "faMeshesRegistry.H"
#include "faGlobalMeshData.H" #include "faGlobalMeshData.H"
#include "Time.H" #include "Time.H"
#include "polyMesh.H" #include "polyMesh.H"
@ -160,12 +159,6 @@ const Foam::objectRegistry* Foam::faMesh::registry(const polyMesh& pMesh)
// return obr.cfindObject<objectRegistry>(faMesh::prefix()); // return obr.cfindObject<objectRegistry>(faMesh::prefix());
// } // }
// Forwarding
const Foam::objectRegistry& Foam::faMesh::Registry(const polyMesh& pMesh)
{
return faMeshesRegistry::Registry(pMesh);
}
const Foam::faMesh& Foam::faMesh::mesh const Foam::faMesh& Foam::faMesh::mesh
( (

View File

@ -751,14 +751,10 @@ public:
// Database // Database
//- Find the singleton parent registry (on the polyMesh) //- The parent registry containing all finite-area meshes
//- that contains all objects related to finite-area. //- on the polyMesh.
static const objectRegistry* registry(const polyMesh& pMesh); static const objectRegistry* registry(const polyMesh& pMesh);
//- Return the singleton parent registry (on the polyMesh)
//- that contains all objects related to finite-area.
static const objectRegistry& Registry(const polyMesh& pMesh);
//- The single-region finite-area region on the polyMesh. //- The single-region finite-area region on the polyMesh.
//- Uses lookupObject semantics - Fatal if non-existent //- Uses lookupObject semantics - Fatal if non-existent
static const faMesh& mesh(const polyMesh& pMesh); static const faMesh& mesh(const polyMesh& pMesh);

View File

@ -27,8 +27,8 @@ License
#include "faMesh.H" #include "faMesh.H"
#include "faMeshesRegistry.H" #include "faMeshesRegistry.H"
#include "polyMesh.H"
#include "Time.H" #include "Time.H"
#include "polyMesh.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -43,7 +43,6 @@ Foam::faMeshRegistry::faMeshRegistry
IOobject IOobject
( (
(areaName.empty() ? polyMesh::defaultRegion : areaName), (areaName.empty() ? polyMesh::defaultRegion : areaName),
mesh.thisDb().time().timeName(),
faMeshesRegistry::New(mesh).thisDb(), faMeshesRegistry::New(mesh).thisDb(),
IOobjectOption::NO_READ, IOobjectOption::NO_READ,
IOobjectOption::AUTO_WRITE, IOobjectOption::AUTO_WRITE,

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2023-2025 OpenCFD Ltd. Copyright (C) 2023-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -86,8 +86,6 @@ bool Foam::faMeshesRegistry::writeObject
const bool writeOnProc const bool writeOnProc
) const ) const
{ {
// Could also restrict to faMesh only...
//
// for (const faMesh& m : objects_.csorted<faMesh>()) // for (const faMesh& m : objects_.csorted<faMesh>())
// { // {
// m.write(writeOnProc); // m.write(writeOnProc);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2023-2025 OpenCFD Ltd. Copyright (C) 2023-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -144,34 +144,14 @@ public:
explicit faMeshesRegistry(const polyMesh& mesh); explicit faMeshesRegistry(const polyMesh& mesh);
// Factory Methods
//- Return the registry of objects on the singleton.
// Same as New(mesh).thisDb()
FOAM_NO_DANGLING_REFERENCE //< Reference stored in registry
static const objectRegistry& Registry(const polyMesh& mesh)
{
return MeshObject_type::New(mesh).thisDb();
}
// Database // Database
// It redirects to the private objects but uses some //- Return the object registry
// objectRegistry method naming
//- The registry of the objects
const objectRegistry& thisDb() const noexcept const objectRegistry& thisDb() const noexcept
{ {
return objects_; return objects_;
} }
//- Local relative to time
const fileName& dbDir() const
{
return objects_.dbDir();
}
//- The polyMesh reference //- The polyMesh reference
const polyMesh& mesh() const noexcept const polyMesh& mesh() const noexcept
{ {

File diff suppressed because it is too large Load Diff

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

@ -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

@ -14,7 +14,7 @@ $(derivedSources)/buoyancyEnergy/buoyancyEnergy.C
$(derivedSources)/buoyancyForce/buoyancyForce.C $(derivedSources)/buoyancyForce/buoyancyForce.C
$(derivedSources)/directionalPressureGradientExplicitSource/directionalPressureGradientExplicitSource.C $(derivedSources)/directionalPressureGradientExplicitSource/directionalPressureGradientExplicitSource.C
$(derivedSources)/explicitPorositySource/explicitPorositySource.C $(derivedSources)/explicitPorositySource/explicitPorositySource.C
$(derivedSources)/jouleHeatingSource/jouleHeatingSource.cxx $(derivedSources)/jouleHeatingSource/jouleHeatingSource.C
$(derivedSources)/meanVelocityForce/meanVelocityForce.C $(derivedSources)/meanVelocityForce/meanVelocityForce.C
$(derivedSources)/meanVelocityForce/patchMeanVelocityForce/patchMeanVelocityForce.C $(derivedSources)/meanVelocityForce/patchMeanVelocityForce/patchMeanVelocityForce.C
$(derivedSources)/multiphaseStabilizedTurbulence/multiphaseStabilizedTurbulence.C $(derivedSources)/multiphaseStabilizedTurbulence/multiphaseStabilizedTurbulence.C

View File

@ -29,6 +29,7 @@ License
#include "fvMatrices.H" #include "fvMatrices.H"
#include "fvmLaplacian.H" #include "fvmLaplacian.H"
#include "fvcGrad.H" #include "fvcGrad.H"
#include "zeroGradientFvPatchField.H"
#include "basicThermo.H" #include "basicThermo.H"
#include "addToRunTimeSelectionTable.H" #include "addToRunTimeSelectionTable.H"
@ -44,12 +45,6 @@ namespace fv
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "jouleHeatingSourceImpl.cxx"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::tmp<Foam::volSymmTensorField> Foam::tmp<Foam::volSymmTensorField>
@ -120,8 +115,11 @@ Foam::fv::jouleHeatingSource::jouleHeatingSource
), ),
mesh mesh
), ),
curTimeIndex_(-1), anisotropicElectricalConductivity_(false),
anisotropicElectricalConductivity_(false) scalarSigmaVsTPtr_(nullptr),
vectorSigmaVsTPtr_(nullptr),
csysPtr_(nullptr),
curTimeIndex_(-1)
{ {
// Set the field name to that of the energy // Set the field name to that of the energy
// field from which the temperature is obtained // field from which the temperature is obtained
@ -164,7 +162,7 @@ void Foam::fv::jouleHeatingSource::addSup
else else
{ {
// Update sigma as a function of T if required // Update sigma as a function of T if required
const auto& sigma = updateSigma(scalarSigmaVsTPtr_); const volScalarField& sigma = updateSigma(scalarSigmaVsTPtr_);
// Solve the electrical potential equation // Solve the electrical potential equation
fvScalarMatrix VEqn(fvm::laplacian(sigma, V_)); fvScalarMatrix VEqn(fvm::laplacian(sigma, V_));
@ -228,7 +226,7 @@ bool Foam::fv::jouleHeatingSource::read(const dictionary& dict)
initialiseSigma(coeffs_, scalarSigmaVsTPtr_); initialiseSigma(coeffs_, scalarSigmaVsTPtr_);
csysPtr_.reset(nullptr); // Do not need coordinate system csysPtr_.clear(); // Do not need coordinate system
} }
return true; return true;

View File

@ -137,28 +137,25 @@ Note
anisotropic (vectorial) electrical conductivity. anisotropic (vectorial) electrical conductivity.
- \c anisotropicElectricalConductivity=false enables - \c anisotropicElectricalConductivity=false enables
isotropic (scalar) electrical conductivity. isotropic (scalar) electrical conductivity.
- The electrical conductivity can be specified using either:
The electrical conductivity can be specified using either:
- If the \c sigma entry is present the electrical conductivity is specified - If the \c sigma entry is present the electrical conductivity is specified
as a function of temperature using a \c Function1 type. as a function of temperature using a \c Function1 type.
- If not present the \c sigma field will be read from file. - If not present the \c sigma field will be read from file.
- If the \c anisotropicElectricalConductivity flag is set to \c true, - If the \c anisotropicElectricalConductivity flag is set to \c true,
\c sigma should be specified as a vector quantity. \c sigma should be specified as a vector quantity.
.
See also See also
- Foam::Function1 - Foam::Function1
- Foam::coordSystem - Foam::coordSystem
- Foam::fa::jouleHeatingSource
SourceFiles SourceFiles
jouleHeatingSource.cxx jouleHeatingSource.C
jouleHeatingSourceImpl.cxx jouleHeatingSourceTemplates.C
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef Foam_fv_jouleHeatingSource_H #ifndef fv_jouleHeatingSource_H
#define Foam_fv_jouleHeatingSource_H #define fv_jouleHeatingSource_H
#include "fvOption.H" #include "fvOption.H"
#include "Function1.H" #include "Function1.H"
@ -188,6 +185,9 @@ class jouleHeatingSource
//- Electrical potential field / [V] //- Electrical potential field / [V]
volScalarField V_; volScalarField V_;
//- Flag to indicate that the electrical conductivity is anisotropic
bool anisotropicElectricalConductivity_;
//- Electrical conductivity as a scalar function of temperature //- Electrical conductivity as a scalar function of temperature
autoPtr<Function1<scalar>> scalarSigmaVsTPtr_; autoPtr<Function1<scalar>> scalarSigmaVsTPtr_;
@ -200,9 +200,6 @@ class jouleHeatingSource
//- Current time index (used for updating) //- Current time index (used for updating)
label curTimeIndex_; label curTimeIndex_;
//- Flag to indicate that the electrical conductivity is anisotropic
bool anisotropicElectricalConductivity_;
// Private Member Functions // Private Member Functions
@ -217,13 +214,13 @@ class jouleHeatingSource
void initialiseSigma void initialiseSigma
( (
const dictionary& dict, const dictionary& dict,
autoPtr<Function1<Type>>& sigmaFunctionPtr autoPtr<Function1<Type>>& sigmaVsTPtr
); );
//- Update the electrical conductivity field //- Update the electrical conductivity field
template<class Type> template<class Type>
const GeometricField<Type, fvPatchField, volMesh>& const GeometricField<Type, fvPatchField, volMesh>&
updateSigma(const autoPtr<Function1<Type>>& sigmaFunctionPtr) const; updateSigma(const autoPtr<Function1<Type>>& sigmaVsTPtr) const;
public: public:
@ -256,21 +253,21 @@ public:
// Member Functions // Member Functions
// Evaluation // Evaluation
//- Add explicit contribution to energy equation //- Add explicit contribution to compressible momentum equation
virtual void addSup virtual void addSup
( (
const volScalarField& rho, const volScalarField& rho,
fvMatrix<scalar>& eqn, fvMatrix<scalar>& eqn,
const label fieldi const label fieldi
); );
// IO // IO
//- Read source dictionary //- Read source dictionary
virtual bool read(const dictionary& dict); virtual bool read(const dictionary& dict);
}; };
@ -281,6 +278,12 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "jouleHeatingSourceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
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.
@ -27,25 +27,18 @@ License
#include "emptyFvPatchField.H" #include "emptyFvPatchField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type> template<class Type>
void Foam::fv::jouleHeatingSource::initialiseSigma void Foam::fv::jouleHeatingSource::initialiseSigma
( (
const dictionary& dict, const dictionary& dict,
autoPtr<Function1<Type>>& sigmaFunctionPtr autoPtr<Function1<Type>>& sigmaVsTPtr
) )
{ {
typedef GeometricField<Type, fvPatchField, volMesh> FieldType; typedef GeometricField<Type, fvPatchField, volMesh> FieldType;
const word sigmaName
(
IOobject::scopedName(typeName, "sigma")
);
IOobject io IOobject io
( (
sigmaName, IOobject::scopedName(typeName, "sigma"),
mesh_.time().timeName(), mesh_.time().timeName(),
mesh_.thisDb(), mesh_.thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -55,11 +48,11 @@ void Foam::fv::jouleHeatingSource::initialiseSigma
autoPtr<FieldType> tsigma; autoPtr<FieldType> tsigma;
// Is sigma defined using a Function1 ? if (dict.found("sigma"))
sigmaFunctionPtr = Function1<Type>::NewIfPresent("sigma", dict, &mesh_);
if (sigmaFunctionPtr)
{ {
// Sigma to be defined using a Function1 type
sigmaVsTPtr = Function1<Type>::New("sigma", dict, &mesh_);
tsigma.reset tsigma.reset
( (
new FieldType new FieldType
@ -92,32 +85,28 @@ template<class Type>
const Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>& const Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>&
Foam::fv::jouleHeatingSource::updateSigma Foam::fv::jouleHeatingSource::updateSigma
( (
const autoPtr<Function1<Type>>& sigmaFunctionPtr const autoPtr<Function1<Type>>& sigmaVsTPtr
) const ) const
{ {
typedef GeometricField<Type, fvPatchField, volMesh> FieldType; typedef GeometricField<Type, fvPatchField, volMesh> FieldType;
const word sigmaName auto& sigma = mesh_.lookupObjectRef<FieldType>
( (
IOobject::scopedName(typeName, "sigma") IOobject::scopedName(typeName, "sigma")
); );
auto& sigma = mesh_.lookupObjectRef<FieldType>(sigmaName); if (!sigmaVsTPtr)
if (!sigmaFunctionPtr)
{ {
// Electrical conductivity field, sigma, was specified by the user // Electrical conductivity field, sigma, was specified by the user
return sigma; return sigma;
} }
const auto& sigmaFunction = sigmaFunctionPtr();
const auto& T = mesh_.lookupObject<volScalarField>(TName_); const auto& T = mesh_.lookupObject<volScalarField>(TName_);
// Internal field // Internal field
forAll(sigma, i) forAll(sigma, i)
{ {
sigma[i] = sigmaFunction.value(T[i]); sigma[i] = sigmaVsTPtr->value(T[i]);
} }
@ -131,7 +120,7 @@ Foam::fv::jouleHeatingSource::updateSigma
const scalarField& Tbf = T.boundaryField()[patchi]; const scalarField& Tbf = T.boundaryField()[patchi];
forAll(pf, facei) forAll(pf, facei)
{ {
pf[facei] = sigmaFunction.value(Tbf[facei]); pf[facei] = sigmaVsTPtr->value(Tbf[facei]);
} }
} }
} }

View File

@ -480,7 +480,6 @@ void Foam::faMeshReconstructor::createMesh()
( (
new faMesh new faMesh
( (
procMesh_.name(),
*serialVolMesh_, *serialVolMesh_,
identity(singlePatchFaces_.size()) // faceLabels identity(singlePatchFaces_.size()) // faceLabels
) )

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2019-2025 OpenCFD Ltd. Copyright (C) 2019-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -144,23 +144,11 @@ KirchhoffShell::KirchhoffShell
) )
: :
vibrationShellModel(modelType, mesh, dict), vibrationShellModel(modelType, mesh, dict),
h_
(
IOobject
(
dict.getOrDefault<word>("h", suffixed("hs")),
regionMesh().time().timeName(),
regionMesh().thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
regionMesh()
),
ps_ ps_
( (
IOobject IOobject
( (
dict.getOrDefault<word>("ps", suffixed("ps")), "ps_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::READ_IF_PRESENT, IOobject::READ_IF_PRESENT,
@ -169,11 +157,23 @@ KirchhoffShell::KirchhoffShell
regionMesh(), regionMesh(),
dimensionedScalar(dimPressure, Zero) dimensionedScalar(dimPressure, Zero)
), ),
h_
(
IOobject
(
"h_" + regionName_,
regionMesh().time().timeName(),
regionMesh().thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
regionMesh()
),
laplaceW_ laplaceW_
( (
IOobject IOobject
( (
suffixed("laplaceW"), "laplaceW_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -186,7 +186,7 @@ KirchhoffShell::KirchhoffShell
( (
IOobject IOobject
( (
suffixed("laplace2W"), "laplace2W_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -199,7 +199,7 @@ KirchhoffShell::KirchhoffShell
( (
IOobject IOobject
( (
suffixed("w0"), "w0_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -212,7 +212,7 @@ KirchhoffShell::KirchhoffShell
( (
IOobject IOobject
( (
suffixed("w00"), "w00_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -225,7 +225,7 @@ KirchhoffShell::KirchhoffShell
( (
IOobject IOobject
( (
suffixed("laplaceW0"), "laplaceW0_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -238,7 +238,7 @@ KirchhoffShell::KirchhoffShell
( (
IOobject IOobject
( (
suffixed("laplace2W0"), "laplace2W0_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,
@ -256,7 +256,6 @@ KirchhoffShell::KirchhoffShell
init(dict); init(dict);
} }
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void KirchhoffShell::preEvolveRegion() void KirchhoffShell::preEvolveRegion()

View File

@ -24,7 +24,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class Class
Foam::regionModels::KirchhoffShell (Foam::regionFaModels) Foam::regionFaModels::KirchhoffShell
Description Description
Vibration-shell finite-area model. Vibration-shell finite-area model.
@ -51,25 +51,9 @@ Usage
\table \table
Property | Description | Type | Reqd | Deflt Property | Description | Type | Reqd | Deflt
vibrationShellModel | Type name: KirchhoffShell | word | yes | - vibrationShellModel | Type name: KirchhoffShell | word | yes | -
f0 | Damping coefficient [1/s] | scalar | yes | - f0 | Damping coefficient [1/s] | scalar | yes | -
f1 | Damping coefficient [1/s] | scalar | yes | - f1 | Damping coefficient [1/s] | scalar | yes | -
f2 | Damping coefficient [1/s] | scalar | yes | - f2 | Damping coefficient [1/s] | scalar | yes | -
h | Name of thickness field | word | no | hs (suffix)
ps | Name of pressure field | word | no | ps (suffix)
\endtable
Fields/variables used:
\table
Property | Description | Type | Deflt
h | Thickness | shell | hs (suffix)
ps | Pressure on shell | shell | ps (suffix)
\endtable
Naming changes from 2056 and earlier:
\table
Keyword | Description | Keyword (old) | Deflt (old)
h | Thickness (shell) | - | "h_" + regionName
ps | Pressure (shell) | - | "ps_" + regionName
\endtable \endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
@ -106,12 +90,12 @@ class KirchhoffShell
// Source term fields // Source term fields
//- Shell thickness [m]
areaScalarField h_;
//- External surface source [Pa] //- External surface source [Pa]
const areaScalarField ps_; const areaScalarField ps_;
//- Thickness [m]
areaScalarField h_;
//- Laplace of the displacement //- Laplace of the displacement
areaScalarField laplaceW_; areaScalarField laplaceW_;

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

@ -27,6 +27,7 @@ License
#include "regionFaModel.H" #include "regionFaModel.H"
#include "faMesh.H" #include "faMesh.H"
#include "faMeshesRegistry.H"
#include "Time.H" #include "Time.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -73,7 +74,7 @@ Foam::IOobject createModelIOobject
( (
objName, objName,
mesh.time().constant(), mesh.time().constant(),
faMesh::Registry(mesh), faMeshesRegistry::New(mesh).thisDb(),
IOobjectOption::NO_READ, IOobjectOption::NO_READ,
IOobjectOption::NO_WRITE, IOobjectOption::NO_WRITE,
IOobjectOption::REGISTER IOobjectOption::REGISTER
@ -140,71 +141,12 @@ Foam::IOobject createPropertiesIOobject
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
void Foam::regionModels::regionFaModel::constructMeshObjects void Foam::regionModels::regionFaModel::constructMeshObjects()
(
// Just for error reference
const dictionary& dict
)
{ {
regionMeshPtr_.reset(nullptr);
#if 1
regionMeshPtr_.reset regionMeshPtr_.reset
( (
new faMesh(areaName_, primaryMesh_) new faMesh(areaName_, primaryMesh_)
); );
#else
// With try/catch and error messages
// DIY
// regionMeshPtr_ = faMesh::TryNew(areaName_, primaryMesh_);
// More heavy handed, but gives a better chance of locating
// the source of the error.
{
const bool oldThrowingError = FatalError.throwing(true);
const bool oldThrowingIOerr = FatalIOError.throwing(true);
try
{
regionMeshPtr_.reset
(
new faMesh(areaName_, primaryMesh_)
);
}
catch (const Foam::error& err)
{
Warning << err << nl << endl;
// Trickery to get original message
err.write(Warning, false);
}
catch (const Foam::IOerror& err)
{
Warning << err << nl << endl;
// Trickery to get original message
err.write(Warning, false);
}
FatalError.throwing(oldThrowingError);
FatalIOError.throwing(oldThrowingIOerr);
}
if (!regionMeshPtr_)
{
FatalError
<< "Failed to create finite-area mesh [" << areaName_
<< "] for model: "<< modelName_ << nl
<< "A common cause is an incorrect or"
" missing 'area' entry in the setup" << nl
<< ">>>>" << nl
<< dict.relativeName() << dict << "<<<<" << endl
<< exit(FatalError);
}
#endif
} }
@ -292,35 +234,7 @@ Foam::regionModels::regionFaModel::regionFaModel
regionName_(dict.get<word>("region")), regionName_(dict.get<word>("region")),
coeffs_(dict.subOrEmptyDict(modelName + "Coeffs")) coeffs_(dict.subOrEmptyDict(modelName + "Coeffs"))
{ {
// Suffix hint for variable names constructMeshObjects();
if
(
coeffs_.readIfPresent("suffixing", suffixHint_)
|| dict.readIfPresent("suffixing", suffixHint_)
)
{
Switch sw = Switch::find(suffixHint_);
if (sw.good())
{
if (!sw) // No suffix
{
suffixHint_.clear();
}
}
else if (suffixHint_ == "default")
{
// Use default suffix
sw = true;
}
if (sw) // Default suffix
{
suffixHint_ = '_' + regionName_;
}
}
constructMeshObjects(dict);
initialise(); initialise();
if (readFields) if (readFields)
@ -336,14 +250,9 @@ void Foam::regionModels::regionFaModel::evolve()
{ {
if (active_) if (active_)
{ {
Info<< "\nEvolving " << modelName_ Info<< "\nEvolving " << modelName_ << " for region "
<< " for region " << regionMesh().name(); << regionMesh().name() << " : "
<< polyMesh::regionName(areaName_) << endl;
if (!polyMesh::regionName(areaName_).empty())
{
Info<< " [" << areaName_ << "]";
}
Info<< endl;
preEvolveRegion(); preEvolveRegion();
@ -356,7 +265,7 @@ void Foam::regionModels::regionFaModel::evolve()
{ {
Info<< incrIndent; Info<< incrIndent;
info(); info();
Info<< decrIndent << endl; Info<< endl << decrIndent;
} }
} }
} }

View File

@ -57,20 +57,9 @@ Usage
region | Name of operand region | word | yes | - region | Name of operand region | word | yes | -
area | Name of the finite-area mesh | word | no | region0 area | Name of the finite-area mesh | word | no | region0
active | Flag to activate the model | bool | yes | - active | Flag to activate the model | bool | yes | -
suffixing | Suffix hint for model variables | word | no | -
infoOutput | Flag to activate information output | bool | no | false infoOutput | Flag to activate information output | bool | no | false
\endtable \endtable
Note
The \c suffixing parameter is a hint that individual models may use
when automatically generating variable names internally. For example,
a model \em may provide ("T" + suffixing) and ("q" + suffixing)
as its default names temperature and flux fields, respectively.
If the user specifies \c suffixing = "_foo", those \em default names
would then become "T_foo" and "q_foo", respectively.
Suffixing (true|false|none|default|...) currently selects between
no suffix and ('_'+region).
SourceFiles SourceFiles
regionFaModelI.H regionFaModelI.H
regionFaModel.C regionFaModel.C
@ -101,7 +90,7 @@ class regionFaModel
// Private Member Functions // Private Member Functions
//- Construct region mesh and fields //- Construct region mesh and fields
void constructMeshObjects(const dictionary&); void constructMeshObjects();
//- Initialise the region //- Initialise the region
void initialise(); void initialise();
@ -129,21 +118,18 @@ protected:
//- Model name //- Model name
const word modelName_; const word modelName_;
//- Suffix hint for automatic model variable names (default: "") //- The finite-area mesh name
word suffixHint_;
//- The finite-area mesh name (default: region0)
word areaName_; word areaName_;
//- Region name //- Region name
word regionName_; word regionName_;
//- Model coefficients dictionary
dictionary coeffs_;
//- Pointer to the region mesh database //- Pointer to the region mesh database
autoPtr<faMesh> regionMeshPtr_; autoPtr<faMesh> regionMeshPtr_;
//- Model coefficients dictionary
dictionary coeffs_;
//- Dictionary of output properties //- Dictionary of output properties
autoPtr<IOdictionary> outputPropertiesPtr_; autoPtr<IOdictionary> outputPropertiesPtr_;
@ -238,15 +224,6 @@ public:
//- Return mapping between surface and volume fields //- Return mapping between surface and volume fields
const volSurfaceMapping& vsm() const; const volSurfaceMapping& vsm() const;
//- The suffix hint for automatic model variable names
const word& suffixHint() const noexcept { return suffixHint_; }
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const char* base) const;
//- Return the concatenation of \p base and the suffix hint
inline word suffixed(const std::string& base) const;
// Evolution // Evolution

View File

@ -27,7 +27,7 @@ License
#include "regionFaModel.H" #include "regionFaModel.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
inline const Foam::faMesh& Foam::regionModels::regionFaModel::regionMesh() const inline const Foam::faMesh& Foam::regionModels::regionFaModel::regionMesh() const
{ {
@ -106,18 +106,4 @@ inline bool Foam::regionModels::regionFaModel::isRegionPatch
} }
inline Foam::word
Foam::regionModels::regionFaModel::suffixed(const char* base) const
{
return word(base + suffixHint_);
}
inline Foam::word
Foam::regionModels::regionFaModel::suffixed(const std::string& base) const
{
return word(base + suffixHint_);
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -123,29 +123,14 @@ thermalShell::thermalShell
) )
: :
thermalShellModel(modelType, mesh, dict), thermalShellModel(modelType, mesh, dict),
hName_(dict.getOrDefault<word>("h", suffixed("hs"))),
qsName_(dict.getOrDefault<word>("qs", suffixed("qs"))),
qrName_(dict.getOrDefault<word>("qr", "none")),
nNonOrthCorr_(1), nNonOrthCorr_(1),
// Only need/want thermal solid properties // Only need/want thermal solid properties
thermo_(dict.subDict("thermo"), solidProperties::THERMAL), thermo_(dict.subDict("thermo"), solidProperties::THERMAL),
h_
(
IOobject
(
hName_,
regionMesh().time().timeName(),
regionMesh().thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
regionMesh()
),
qs_ qs_
( (
IOobject IOobject
( (
qsName_, "qs_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::READ_IF_PRESENT, IOobject::READ_IF_PRESENT,
@ -154,6 +139,19 @@ thermalShell::thermalShell
regionMesh(), regionMesh(),
dimensionedScalar(dimPower/dimArea, Zero) dimensionedScalar(dimPower/dimArea, Zero)
), ),
h_
(
IOobject
(
"h_" + regionName_,
regionMesh().time().timeName(),
regionMesh().thisDb(),
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
regionMesh()
),
qrName_(dict.getOrDefault<word>("qr", "none")),
thickness_(dict.getOrDefault<scalar>("thickness", 0)) thickness_(dict.getOrDefault<scalar>("thickness", 0))
{ {
init(dict); init(dict);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
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.
@ -56,28 +56,11 @@ Usage
where the entries mean: where the entries mean:
\table \table
Property | Description | Type | Reqd | Deflt Property | Description | Type | Reqd | Deflt
thermalShellModel | Type name: thermalShell | word | yes | - thermalShellModel | Type name: thermalShell | word | yes | -
h | Name of thickness field | word | no | hs (suffix) thermo | Solid thermal properties | dictionary | yes | -
qs | Name of source field | word | no | qs (suffix) qr | Name of radiative heat flux field | word | no | none
qr | Name of radiative heat flux field | word | no | none thickness | Uniform film thickness [m] | scalar | choice | -
thermo | Solid thermal properties | dict | yes | -
thickness | Uniform shell thickness [m] | scalar | choice | -
\endtable
Fields/variables used:
\table
Property | Description | Type | Deflt
h | Thickness | shell | hs (suffix)
qs | Source field | shell | qs (suffix)
qr | Radiative heat flux field | volume | none
\endtable
Note the following naming changes from 2056 and earlier:
\table
Keyword | Description | Keyword (old) | Deflt (old)
h | Temperature (volume) | h | "h_" + regionName
qs | Temperature (shell) | qs | "qs_" + regionName
\endtable \endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
@ -85,6 +68,7 @@ Usage
SourceFiles SourceFiles
thermalShell.C thermalShell.C
thermalShellI.H
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -124,38 +108,31 @@ protected:
// Protected Data // Protected Data
//- Name of shell thickness [height] field (default: "hs" + suffix) // Solution parameters
const word hName_;
//- Name of surface energy source (default: "qs" + suffix) //- Number of non orthogonal correctors
const word qsName_; label nNonOrthCorr_;
//- Name of (volume) radiative flux field (default: none)
const word qrName_;
// Solution Parameters // Thermo properties
//- Number of non orthogonal correctors //- Solid properties
label nNonOrthCorr_; solidProperties thermo_;
// Thermo properties // Source term fields
//- Solid properties //- External surface energy source [J/m2/s]
solidProperties thermo_; areaScalarField qs_;
//- Film thickness [m]
areaScalarField h_;
// Source term fields //- Name of the primary region radiative flux
const word qrName_;
//- Shell thickness field [m] //- Uniform film thickness [m]
areaScalarField h_; scalar thickness_;
//- External surface energy source [J/m2/s]
areaScalarField qs_;
//- Uniform shell thickness [m]
scalar thickness_;
// Protected Member Functions // Protected Member Functions
@ -197,7 +174,7 @@ public:
// Fields // Fields
//- Return the shell specific heat capacity [J/kg/K] //- Return the film specific heat capacity [J/kg/K]
const tmp<areaScalarField> Cp() const; const tmp<areaScalarField> Cp() const;
//- Return density [kg/m3] //- Return density [kg/m3]

View File

@ -50,14 +50,13 @@ thermalShellModel::thermalShellModel
) )
: :
regionFaModel(mesh, "thermalShell", modelType, dict, true), regionFaModel(mesh, "thermalShell", modelType, dict, true),
TName_(dict.getOrDefault<word>("T", suffixed("Ts"))), TName_(dict.get<word>("T")),
TprimaryName_(dict.getOrDefault<word>("Tprimary", "T")), Tp_(mesh.lookupObject<volScalarField>(TName_)),
Tp_(mesh.lookupObject<volScalarField>(TprimaryName_)),
T_ T_
( (
IOobject IOobject
( (
TName_, "Ts_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::MUST_READ, IOobject::MUST_READ,
@ -72,8 +71,8 @@ thermalShellModel::thermalShellModel
{ {
if (faOptions_.optionList::empty()) if (faOptions_.optionList::empty())
{ {
Info<< "No finite-area options present for area:" Info<< "No finite area options present for area : "
<< regionFaModel::areaName() << endl; << polyMesh::regionName(regionFaModel::areaName()) << endl;
} }
} }

View File

@ -24,7 +24,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class Class
Foam::regionModels::thermalShellModel Foam::regionModels::thermalShellModels::thermalShellModel
Description Description
Intermediate class for thermal-shell finite-area models. Intermediate class for thermal-shell finite-area models.
@ -34,12 +34,12 @@ Usage
\verbatim \verbatim
<patchName> <patchName>
{ {
// Mandatory entries
T <word>;
// Optional entries // Optional entries
thermalShellModel <word>; thermalShellModel <word>;
T <word>;
Tprimary <word>;
// Inherited entries // Inherited entries
... ...
} }
@ -47,27 +47,12 @@ Usage
where the entries mean: where the entries mean:
\table \table
Property | Description | Type | Reqd | Deflt Property | Description | Type | Reqd | Deflt
T | Name of operand temperature field | word | no | Ts (suffix) T | Name of operand temperature field | word | yes | -
Tprimary | Name of primary temperature field | word | no | T thermalShellModel | Name of thermal-shell model <!--
thermalShellModel | Name of thermalShellModel thermal-shell model <!--
--> | word | choice | - --> | word | choice | -
\endtable \endtable
Fields/variables used:
\table
Property | Description | Type | Deflt
T | Temperature | shell | Ts (suffix)
Tprimary | Temperature | volume | T
\endtable
\b BREAKING Naming changes from 2056 and earlier:
\table
Keyword | Description | Keyword (old) | Deflt (old)
T | Temperature (shell) | - | "Ts_" + regionName
Tprimary | Temperature (volume) | T | -
\endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
- \link regionFaModel.H \endlink - \link regionFaModel.H \endlink
@ -104,11 +89,8 @@ protected:
// Protected Data // Protected Data
//- Name of shell temperature field (default: "Ts" + suffix) //- Name of the temperature field
const word TName_; word TName_;
//- Name of volume temperature field (default: "T")
const word TprimaryName_;
//- Primary (volume) region temperature //- Primary (volume) region temperature
const volScalarField& Tp_; const volScalarField& Tp_;

View File

@ -53,7 +53,7 @@ vibrationShellModel::vibrationShellModel
( (
IOobject IOobject
( (
dict.getOrDefault<word>("ws", suffixed("ws")), "ws_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::MUST_READ, IOobject::MUST_READ,
@ -65,7 +65,7 @@ vibrationShellModel::vibrationShellModel
( (
IOobject IOobject
( (
dict.getOrDefault<word>("as", suffixed("as")), "as_" + regionName_,
regionMesh().time().timeName(), regionMesh().time().timeName(),
regionMesh().thisDb(), regionMesh().thisDb(),
IOobject::NO_READ, IOobject::NO_READ,

View File

@ -24,7 +24,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class Class
Foam::regionModels::vibrationShellModel Foam::regionModels::thermalShellModels::vibrationShellModel
Description Description
Intermediate class for vibration-shell finite-area models. Intermediate class for vibration-shell finite-area models.
@ -52,19 +52,9 @@ Usage
\table \table
Property | Description | Type | Reqd | Deflt Property | Description | Type | Reqd | Deflt
vibrationShellModel | Name of vibration-shell model | word | yes | - vibrationShellModel | Name of vibration-shell model | word | yes | -
p | Name of primary pressure field | word | yes | - p | Name of the coupled field in the primary <!--
solid | Solid properties | dict | yes | - --> region | word | yes | -
as | Name of shell acceleration field | word | no | as (suffix) solid | Solid properties | dictionary | yes | -
ps | Name of pressure (source) on shell | word | no | ps (suffix)
ws | Name of shell displacement field | word | no | ws (suffix)
\endtable
Naming changes from 2056 and earlier:
\table
Keyword | Description | Keyword (old) | Deflt (old)
as | Acceleration (shell) | - | "as_" + regionName
ps | Pressure on shell | - | "ps_" + regionName
ws | Displacement (shell) | - | "ws_" + regionName
\endtable \endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
@ -103,19 +93,19 @@ protected:
// Protected Data // Protected Data
//- Shell displacement [m] //- Shell displacement
areaScalarField w_; areaScalarField w_;
//- Shell acceleration [m/s2] //- Shell acceleration
areaScalarField a_; areaScalarField a_;
//- Solid properties //- Solid properties
solidProperties solid_; solidProperties solid_;
//- Name of primary region acoustic pressure field //- Name of the coupled field in the primary region
word pName_; word pName_;
//- Primary region acoustic pressure [Pa] //- Primary region acoustic pressure
const volScalarField& pa_; const volScalarField& pa_;
//- Reference to faOptions //- Reference to faOptions
@ -177,26 +167,26 @@ public:
// Member Functions // Member Functions
//- Return the primary region presssure //- Return primary region pa
const volScalarField& pa() const noexcept { return pa_; } const volScalarField& pa() const noexcept { return pa_; }
//- Return the shell displacement //- Return shell displacement
const areaScalarField& w() const noexcept { return w_; } const areaScalarField& w() const noexcept { return w_; }
//- Return the shell acceleration //- Return shell acceleration
const areaScalarField& a() const noexcept { return a_; } const areaScalarField& a() const noexcept { return a_; }
//- Return faOptions //- Return faOptions
Foam::fa::options& faOptions() noexcept { return faOptions_; } Foam::fa::options& faOptions() noexcept { return faOptions_; }
//- Return solid properties //- Return solid properties
const solidProperties& solid() const noexcept { return solid_; } const solidProperties& solid() const noexcept { return solid_; }
// Evolution // Evolution
//- Pre-evolve region //- Pre-evolve region
virtual void preEvolveRegion(); virtual void preEvolveRegion();
}; };

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class areaScalarField; class areaScalarField;
object hs; object h_ceilingShell;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -10,7 +10,7 @@ FoamFile
version 2.0; version 2.0;
format ascii; format ascii;
class areaScalarField; class areaScalarField;
object ws; object wS;
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -41,7 +41,7 @@ boundaryField
nu 0.22; nu 0.22;
} }
region vibration; region vibrationShell;
vibrationShellModel KirchhoffShell; vibrationShellModel KirchhoffShell;
f0 0.04; f0 0.04;

View File

@ -17,13 +17,12 @@ FoamFile
pressure pressure
{ {
type externalFileSource; type externalFileSource;
//fieldName ws_shell; fieldName ws_vibrationShell;
fieldName ws;
tableName p; tableName p;
active true; active true;
timeStart 0.001; timeStart 0.001;
duration 0.03; duration 0.03;
region vibration; region vibrationShell;
selectionMode all; selectionMode all;
sampleFormat ensight; sampleFormat ensight;

Some files were not shown because too many files have changed in this diff Show More