Compare commits

..

14 Commits

Author SHA1 Message Date
413c91d873 WIP: ENH: evapotranspirationHeatTransfer: New atmospheric-model fvOption
WIP: The units of the main governing eq are inconsistent - see EP1950

Applies sources on temperature ('T' - incompressible)
or energy ('h'/'e' - compressible) equation to incorporate
evapotranspiration heat-transfer effects from the specified
plant canopy. Heat transfer is usually calculated based on
empirical relations between plants and solar radiation.

Two submodels to incorporate heat transfer effects
- 'tree': specified tree canopy - uses empirical relations between solar
radiation and evapotranspiration.
- 'grass': specified grass canopy - uses Pemnan-Monteith Equation model.
2024-04-05 13:56:20 +01:00
f6539e4d52 ENH: treeTurbulence: new atmospheric-model fvOption
Applies sources on 'k' and either 'epsilon' or 'omega'
to incorporate effects of trees on atmospheric boundary layer.
2024-03-22 10:25:11 +00:00
68e36946fd BUG: externalWallHeatFluxTemperature: prevent FPE in mixedEnergy condition (fixes #3123) 2024-03-21 16:36:22 +00:00
c6ecf3113a COMP: syncTools: move attribute 2024-03-20 09:32:43 +00:00
46e1b00c34 ENH: handle sub-mesh connectivity by subsetting of adjacency matrix
- in renumberMesh replace calculation of a subMesh connectivity
  with calculation of the full mesh connectivity followed by subsetting
  of the full adjacency matrix. This should reduce the overall number of
  operations. (MR !669)
2024-03-19 14:09:22 +01:00
a431e0fe9a ENH: additional parRun selection/protection on syncTools
- allow more control over using parallel communication or not.
2024-03-18 20:59:21 +01:00
6d69506294 STYLE: adjust comments and iterator de-reference
STYLE: replace PackedListCore.H with in-file definition
2024-03-18 20:59:21 +01:00
77ec7ab679 Merge branch 'feature-topoSet-with-zone' into 'develop'
topoSet: allow use of 'zone' instead 'set', 'zones' instead of 'sets' in all set sources

See merge request Development/openfoam!674
2024-03-18 19:58:07 +00:00
6692ecfbbc topoSet: allow use of 'zone' instead 'set', 'zones' instead of 'sets' in all set sources 2024-03-18 19:58:06 +00:00
3ef892b980 Merge branch 'feature-topoSet' into 'develop'
Feature topo set

See merge request Development/openfoam!668
2024-03-18 16:13:52 +00:00
a7d6f2720f ENH: add for geometric transformation properties for topoSet
- added solidBodyMotionFunctions to topoSet which allows things like
  moving cellSet selection for fvOptions etc.

COMP: relocate solidBodyMotionFunctions to meshTools

Co-authored-by: Kutalmis Bercin <>
2024-03-18 16:50:16 +01:00
4a0a63999e BUG: cyclicAMI: start without 'value'. Fixes #3119 2024-03-18 12:14:36 +00:00
b1eb3e8746 BUG: fileHandler: disable parallel side effects. Fixes #3105 2024-03-18 11:54:40 +00:00
bc03a538cf ENH: mapDistribute: improved error message 2024-03-18 10:44:54 +00:00
172 changed files with 5110 additions and 2008 deletions

View File

@ -145,6 +145,7 @@ Usage
#include "hexRef8Data.H"
#include "regionProperties.H"
#include "polyMeshTools.H"
#include "subsetAdjacency.H"
using namespace Foam;
@ -194,21 +195,56 @@ tmp<volScalarField> createScalarField
}
// Calculate band of matrix
label getBand(const labelList& owner, const labelList& neighbour)
// Calculate band of mesh
// label getBand(const labelUList& owner, const labelUList& neighbour)
// {
// label bandwidth = 0;
//
// forAll(neighbour, facei)
// {
// const label width = neighbour[facei] - owner[facei];
//
// if (bandwidth < width)
// {
// bandwidth = width;
// }
// }
// return bandwidth;
// }
// Calculate band and profile of matrix. Profile is scalar to avoid overflow
Tuple2<label, scalar> getBand
(
const CompactListList<label>& mat
)
{
label band = 0;
Tuple2<label, scalar> metrics(0, 0);
forAll(neighbour, facei)
auto& bandwidth = metrics.first();
auto& profile = metrics.second();
forAll(mat, celli)
{
label diff = neighbour[facei] - owner[facei];
const auto& neighbours = mat[celli];
if (diff > band)
const label nNbr = neighbours.size();
if (nNbr)
{
band = diff;
// Max distance
const label width = (neighbours[nNbr-1] - celli);
if (bandwidth < width)
{
bandwidth = width;
}
profile += scalar(width);
}
}
return band;
return metrics;
}
@ -217,27 +253,35 @@ void getBand
(
const bool calculateIntersect,
const label nCells,
const labelList& owner,
const labelList& neighbour,
const labelUList& owner,
const labelUList& neighbour,
label& bandwidth,
scalar& profile, // scalar to avoid overflow
scalar& sumSqrIntersect // scalar to avoid overflow
)
{
labelList cellBandwidth(nCells, Foam::zero{});
scalarField nIntersect(nCells, Foam::zero{});
bandwidth = 0;
forAll(neighbour, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
const label own = owner[facei];
const label nei = neighbour[facei];
// Note: mag not necessary for correct (upper-triangular) ordering.
label diff = nei-own;
cellBandwidth[nei] = max(cellBandwidth[nei], diff);
}
const label width = nei - own;
bandwidth = max(cellBandwidth);
if (cellBandwidth[nei] < width)
{
cellBandwidth[nei] = width;
if (bandwidth < width)
{
bandwidth = width;
}
}
}
// Do not use field algebra because of conversion label to scalar
profile = 0;
@ -246,14 +290,16 @@ void getBand
profile += scalar(width);
}
sumSqrIntersect = 0.0;
sumSqrIntersect = 0;
if (calculateIntersect)
{
scalarField nIntersect(nCells, Foam::zero{});
forAll(nIntersect, celli)
{
for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
{
nIntersect[colI] += 1.0;
nIntersect[colI] += scalar(1);
}
}
@ -675,9 +721,8 @@ CompactListList<label> regionRenumber
forAll(regionCellOrder, regioni)
{
// Info<< " region " << regioni
// << " starts at " << regionCellOrder.localStart(regioni)
// << nl;
// Info<< " region " << regioni << " starts at "
// << regionCellOrder.localStart(regioni) << nl;
// No parallel communication
const bool oldParRun = UPstream::parRun(false);
@ -703,27 +748,42 @@ CompactListList<label> regionRenumber
{
timer.resetTimeIncrement();
// Create adjacency matrix of the full mesh and subset subsequently.
// This is more efficient than creating adjacency matrices of
// sub-meshes.
// No parallel communication
const bool oldParRun = UPstream::parRun(false);
// The local connectivity of the full (non-subsetted) mesh
CompactListList<label> meshCellCells;
globalMeshData::calcCellCells(mesh, meshCellCells);
UPstream::parRun(oldParRun); // Restore parallel state
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
// For the respective subMesh selections
bitSet subsetCells(mesh.nCells());
forAll(regionCellOrder, regioni)
{
// Info<< " region " << regioni
// << " starts at " << regionCellOrder.localStart(regioni)
// << nl;
// Info<< " region " << regioni << " starts at "
// << regionCellOrder.localStart(regioni) << nl;
subsetCells = false;
subsetCells.set(regionCellOrder[regioni]);
// Connectivity of local sub-mesh
labelList cellMap;
CompactListList<label> subCellCells =
subsetAdjacency(subsetCells, meshCellCells, cellMap);
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
// No parallel communication
const bool oldParRun = UPstream::parRun(false);
// Connectivity of local sub-mesh
CompactListList<label> cellCells;
labelList cellMap = globalMeshData::calcCellCells
(
mesh,
regionCellOrder[regioni],
cellCells
);
timings[TimingType::CELL_CELLS] += timer.timeIncrement();
labelList subCellOrder = method.renumber(cellCells);
labelList subCellOrder = method.renumber(subCellCells);
UPstream::parRun(oldParRun); // Restore parallel state
@ -835,10 +895,10 @@ int main(int argc, char *argv[])
const bool dryrun = args.dryRun();
const bool readDict = args.found("dict");
const bool doFrontWidth = args.found("frontWidth");
const bool doDecompose = args.found("decompose");
const bool overwrite = args.found("overwrite");
const bool doFields = !args.found("no-fields");
const bool doDecompose = args.found("decompose");
const bool doFrontWidth = args.found("frontWidth") && !doDecompose;
word renumberMethodName;
args.readIfPresent("renumber-method", renumberMethodName);
@ -846,8 +906,7 @@ int main(int argc, char *argv[])
if (doDecompose && UPstream::parRun())
{
FatalErrorIn(args.executable())
<< "Cannot use -decompose option in parallel"
<< " ... giving up" << nl
<< "Cannot use -decompose option in parallel ... giving up" << nl
<< exit(FatalError);
}
@ -908,21 +967,21 @@ int main(int argc, char *argv[])
reduce(band, maxOp<label>());
reduce(profile, sumOp<scalar>());
reduce(sumSqrIntersect, sumOp<scalar>());
scalar rmsFrontwidth = Foam::sqrt
(
sumSqrIntersect/mesh.globalData().nTotalCells()
);
Info<< "Mesh " << mesh.name()
<< " size: " << mesh.globalData().nTotalCells() << nl
<< "Before renumbering :" << nl
<< "Before renumbering" << nl
<< " band : " << band << nl
<< " profile : " << profile << nl;
if (doFrontWidth)
{
reduce(sumSqrIntersect, sumOp<scalar>());
scalar rmsFrontwidth = Foam::sqrt
(
sumSqrIntersect/mesh.globalData().nTotalCells()
);
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
}
@ -1091,10 +1150,7 @@ int main(int argc, char *argv[])
);
// List of objects read from time directory
// List of stored objects to clear from mesh
IOobjectList objects;
// List of stored objects to clear from mesh (after reading)
DynamicList<regIOobject*> storedObjects;
if (!dryrun && doFields)
@ -1103,55 +1159,60 @@ int main(int argc, char *argv[])
timer.resetTimeIncrement();
objects = IOobjectList(mesh, runTime.timeName());
IOobjectList objects(mesh, runTime.timeName());
storedObjects.reserve(objects.size());
const predicates::always nameMatcher;
// Read GeometricFields
#undef ReadFields
#define ReadFields(FieldType) \
#undef doLocalCode
#define doLocalCode(FieldType) \
readFields<FieldType>(mesh, objects, nameMatcher, storedObjects);
// Read volume fields
ReadFields(volScalarField);
ReadFields(volVectorField);
ReadFields(volSphericalTensorField);
ReadFields(volSymmTensorField);
ReadFields(volTensorField);
doLocalCode(volScalarField);
doLocalCode(volVectorField);
doLocalCode(volSphericalTensorField);
doLocalCode(volSymmTensorField);
doLocalCode(volTensorField);
// Read internal fields
ReadFields(volScalarField::Internal);
ReadFields(volVectorField::Internal);
ReadFields(volSphericalTensorField::Internal);
ReadFields(volSymmTensorField::Internal);
ReadFields(volTensorField::Internal);
doLocalCode(volScalarField::Internal);
doLocalCode(volVectorField::Internal);
doLocalCode(volSphericalTensorField::Internal);
doLocalCode(volSymmTensorField::Internal);
doLocalCode(volTensorField::Internal);
// Read surface fields
ReadFields(surfaceScalarField);
ReadFields(surfaceVectorField);
ReadFields(surfaceSphericalTensorField);
ReadFields(surfaceSymmTensorField);
ReadFields(surfaceTensorField);
doLocalCode(surfaceScalarField);
doLocalCode(surfaceVectorField);
doLocalCode(surfaceSphericalTensorField);
doLocalCode(surfaceSymmTensorField);
doLocalCode(surfaceTensorField);
// Read point fields
const pointMesh& pMesh = pointMesh::New(mesh);
#undef ReadPointFields
#define ReadPointFields(FieldType) \
#undef doLocalCode
#define doLocalCode(FieldType) \
readFields<FieldType>(pMesh, objects, nameMatcher, storedObjects);
ReadPointFields(pointScalarField);
ReadPointFields(pointVectorField);
ReadPointFields(pointSphericalTensorField);
ReadPointFields(pointSymmTensorField);
ReadPointFields(pointTensorField);
doLocalCode(pointScalarField);
doLocalCode(pointVectorField);
doLocalCode(pointSphericalTensorField);
doLocalCode(pointSymmTensorField);
doLocalCode(pointTensorField);
#undef ReadFields
#undef ReadPointFields
#undef doLocalCode
timings[TimingType::READ_FIELDS] += timer.timeIncrement();
// Write loaded fields when mesh.write() is called
for (auto* fldptr : storedObjects)
{
fldptr->writeOpt(IOobject::AUTO_WRITE);
}
}
@ -1224,7 +1285,13 @@ int main(int argc, char *argv[])
CompactListList<label> regionCellOrder =
regionRenumber(renumberPtr(), mesh, cellToRegion);
regionRenumber
(
renumberPtr(),
mesh,
cellToRegion,
decomposePtr().nDomains()
);
cellOrder = regionCellOrder.values();
@ -1586,19 +1653,25 @@ int main(int argc, char *argv[])
);
reduce(band, maxOp<label>());
reduce(profile, sumOp<scalar>());
reduce(sumSqrIntersect, sumOp<scalar>());
scalar rmsFrontwidth = Foam::sqrt
(
sumSqrIntersect/mesh.globalData().nTotalCells()
);
Info<< "After renumbering";
if (doDecompose)
{
Info<< " [values are misleading with -decompose option]";
}
Info<< "After renumbering :" << nl
Info<< nl
<< " band : " << band << nl
<< " profile : " << profile << nl;
if (doFrontWidth)
{
reduce(sumSqrIntersect, sumOp<scalar>());
scalar rmsFrontwidth = Foam::sqrt
(
sumSqrIntersect/mesh.globalData().nTotalCells()
);
Info<< " rms frontwidth : " << rmsFrontwidth << nl;
}

View File

@ -0,0 +1,168 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Description
Subsetting of an adjacency matrix (as CompactListList).
Can be relocated elsewhere.
\*---------------------------------------------------------------------------*/
#include "CompactListList.H"
#include "bitSet.H"
#include "ListOps.H"
#include "Map.H"
namespace Foam
{
// Perform a subset of the adjacency matrix
CompactListList<label> subsetAdjacency
(
const bitSet& select, // could also be labelHashSet
const CompactListList<label>& input,
labelList& subMap
)
{
// Corresponds to cellMap etc (the original selection)
subMap = select.sortedToc();
// Ensure that the subMap corresponds to a valid subset
{
label validSize = 0;
const label nTotal = input.size();
forAllReverse(subMap, i)
{
if (subMap[i] < nTotal)
{
validSize = i + 1;
break;
}
}
subMap.resize(validSize);
}
// Assumed to be sparse - use Map for reverse lookup
const Map<label> reverseMap(invertToMap(subMap));
// Pass 1: determine the selected sub-sizes
labelList sizes(subMap.size(), Foam::zero{});
forAll(subMap, idx)
{
for (const label nbr : input[subMap[idx]])
{
if
(
select.test(nbr)
&& reverseMap.contains(nbr) // extra consistency (paranoid)
)
{
++sizes[idx];
}
}
}
CompactListList<label> output(sizes);
// Reuse sizes as output offset into output.values()
sizes = labelList::subList(output.offsets(), output.size());
labelList& values = output.values();
// Pass 2: extract sub-adjacent matrix
label newNbr = -1;
forAll(subMap, idx)
{
for (const label nbr : input[subMap[idx]])
{
if
(
select.test(nbr)
&& (newNbr = reverseMap.lookup(nbr, -1)) >= 0
)
{
values[sizes[idx]++] = newNbr;
}
}
}
return output;
}
// Perform a subset of the adjacency matrix
CompactListList<label> subsetAdjacency
(
const labelRange& slice,
const CompactListList<label>& input,
labelList& subMap
)
{
// Ensure that the selection corresponds to a valid subset
const labelRange select = slice.subset0(input.size());
// Corresponds to cellMap etc (the original selection)
subMap = Foam::identity(select);
// Pass 1: determine the selected sub-sizes
labelList sizes(subMap.size(), Foam::zero{});
forAll(subMap, idx)
{
for (const label nbr : input[subMap[idx]])
{
if (select.contains(nbr))
{
++sizes[idx];
}
}
}
CompactListList<label> output(sizes);
// Reuse sizes as output offset into output.values()
sizes = labelList::subList(output.offsets(), output.size());
labelList& values = output.values();
// Pass 2: extract sub-adjacent matrix
const label localOffset = select.start();
forAll(subMap, idx)
{
for (const label nbr : input[subMap[idx]])
{
if (select.contains(nbr))
{
values[sizes[idx]++] = nbr - localOffset;
}
}
}
return output;
}
} // End namespace Foam
// ************************************************************************* //

View File

@ -83,8 +83,9 @@ See also
Foam::DynamicList
SourceFiles
PackedListI.H
PackedList.C
PackedListCore.C
PackedListI.H
PackedListIO.C
\*---------------------------------------------------------------------------*/
@ -92,11 +93,11 @@ SourceFiles
#ifndef Foam_PackedList_H
#define Foam_PackedList_H
#include "className.H"
#include "BitOps.H"
#include "labelList.H"
#include "IndirectListBase.H"
#include "InfoProxy.H"
#include "PackedListCore.H"
#include <type_traits>
@ -119,6 +120,23 @@ template<unsigned Width>
Ostream& operator<<(Ostream& os, const InfoProxy<PackedList<Width>>& info);
/*---------------------------------------------------------------------------*\
Class Detail::PackedListCore Declaration
\*---------------------------------------------------------------------------*/
namespace Detail
{
//- Template-invariant parts for PackedList
struct PackedListCore
{
//- Define template name
ClassNameNoDebug("PackedList");
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class PackedList Declaration
\*---------------------------------------------------------------------------*/

View File

@ -25,7 +25,7 @@ License
\*---------------------------------------------------------------------------*/
#include "PackedListCore.H"
#include "PackedList.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //

View File

@ -1,69 +1 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::Detail::PackedListCore
Description
Implementation of template-invariant details for Foam::PackedList
SourceFiles
PackedListCore.C
\*---------------------------------------------------------------------------*/
#ifndef PackedListCore_H
#define PackedListCore_H
#include "className.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::PackedListCore Declaration
\*---------------------------------------------------------------------------*/
//- Template-invariant parts for PackedList
struct PackedListCore
{
//- Define template name
ClassNameNoDebug("PackedList");
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Detail
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
#warning File removed - left for old dependency check only

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017 OpenFOAM Foundation
Copyright (C) 2020-2023 OpenCFD Ltd.
Copyright (C) 2020-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -716,6 +716,14 @@ bool Foam::fileOperations::uncollatedFileOperation::read
const bool oldMasterOnly = regIOobject::masterOnlyReading;
regIOobject::masterOnlyReading = masterOnly;
const bool oldParRun = UPstream::parRun();
if (masterOnly)
{
// Reading on master only.
// Avoid side effects from io.readStream below.
UPstream::parRun(false);
}
// Read file
ok = io.readData(io.readStream(typeName));
io.close();
@ -723,6 +731,7 @@ bool Foam::fileOperations::uncollatedFileOperation::read
// Restore flags
io.globalObject(oldGlobal);
regIOobject::masterOnlyReading = oldMasterOnly;
UPstream::parRun(oldParRun);
if (debug)
{

View File

@ -84,7 +84,10 @@ static void calcCellCellsImpl
globalNeighbour[bfacei] = val;
}
}
syncTools::swapBoundaryFaceList(mesh, globalNeighbour);
// Swap boundary neighbour information:
// - cyclics and (optionally) processor
syncTools::swapBoundaryFaceList(mesh, globalNeighbour, parallel);
// Count number of faces (internal + coupled)

View File

@ -349,7 +349,10 @@ void Foam::mapDistributeBase::receive
{
FatalErrorInFunction
<< "From processor " << proci
<< " : unallocated receive field" << nl
<< " : unallocated receive field."
<< " Expected size " << map.size()
<< " on comm " << comm
<< " with procs " << UPstream::nProcs(comm) << nl
<< exit(FatalError);
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,34 +34,34 @@ void Foam::syncTools::swapBoundaryCellPositions
(
const polyMesh& mesh,
const UList<point>& cellData,
List<point>& neighbourCellData
List<point>& neighbourCellData,
const bool parRun
)
{
if (cellData.size() != mesh.nCells())
{
FatalErrorInFunction
<< "Number of cell values " << cellData.size()
<< " is not equal to the number of cells in the mesh "
<< mesh.nCells() << abort(FatalError);
<< "Number of values " << cellData.size()
<< " != number of cells " << mesh.nCells() << nl
<< abort(FatalError);
}
const polyBoundaryMesh& patches = mesh.boundaryMesh();
neighbourCellData.resize(mesh.nBoundaryFaces());
for (const polyPatch& pp : patches)
for (const polyPatch& pp : mesh.boundaryMesh())
{
label bFacei = pp.start()-mesh.nInternalFaces();
const auto& faceCells = pp.faceCells();
const labelUList& faceCells = pp.faceCells();
for (const label celli : faceCells)
{
neighbourCellData[bFacei] = cellData[celli];
++bFacei;
}
// ie, boundarySlice() = patchInternalList()
SubList<point>
(
neighbourCellData,
faceCells.size(),
pp.offset()
) = UIndirectList<point>(cellData, faceCells);
}
syncTools::swapBoundaryFacePositions(mesh, neighbourCellData);
syncTools::swapBoundaryFacePositions(mesh, neighbourCellData, parRun);
}
@ -127,9 +127,7 @@ Foam::bitSet Foam::syncTools::getMasterFaces(const polyMesh& mesh)
{
bitSet isMaster(mesh.nFaces(), true);
const polyBoundaryMesh& patches = mesh.boundaryMesh();
for (const polyPatch& pp : patches)
for (const polyPatch& pp : mesh.boundaryMesh())
{
if (pp.coupled())
{
@ -151,9 +149,7 @@ Foam::bitSet Foam::syncTools::getInternalOrMasterFaces
{
bitSet isMaster(mesh.nFaces(), true);
const polyBoundaryMesh& patches = mesh.boundaryMesh();
for (const polyPatch& pp : patches)
for (const polyPatch& pp : mesh.boundaryMesh())
{
if (pp.coupled())
{
@ -179,9 +175,7 @@ Foam::bitSet Foam::syncTools::getInternalOrCoupledFaces
{
bitSet isMaster(mesh.nFaces(), true);
const polyBoundaryMesh& patches = mesh.boundaryMesh();
for (const polyPatch& pp : patches)
for (const polyPatch& pp : mesh.boundaryMesh())
{
if (!pp.coupled())
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2021 OpenCFD Ltd.
Copyright (C) 2015-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -69,6 +69,7 @@ class syncTools
// Private Member Functions
//- Combine val with existing value in pointValues map at given index
// No communication
template<class T, class CombineOp>
static void combine
(
@ -79,6 +80,7 @@ class syncTools
);
//- Combine val with existing value in edgeValues at edge index
// No communication
template<class T, class CombineOp>
static void combine
(
@ -95,6 +97,7 @@ public:
// Preferably use specialisations below.
//- Synchronize values on selected points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp>
static void syncPointMap
(
@ -105,6 +108,7 @@ public:
);
//- Synchronize values on selected edges.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp>
static void syncEdgeMap
(
@ -115,6 +119,7 @@ public:
);
//- Synchronize values on all mesh points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp>
static void syncPointList
(
@ -126,6 +131,7 @@ public:
);
//- Synchronize values on selected mesh points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp>
static void syncPointList
(
@ -138,6 +144,7 @@ public:
);
//- Synchronize values on all mesh edges.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp, class FlipOp>
static void syncEdgeList
(
@ -150,11 +157,12 @@ public:
);
//- Synchronize values on selected mesh edges.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp, class TransformOp, class FlipOp>
static void syncEdgeList
(
const polyMesh& mesh,
const labelList& meshEdges,
const labelUList& meshEdges,
List<T>& edgeValues,
const CombineOp& cop,
const T& nullValue,
@ -170,6 +178,7 @@ public:
UList<T>& faceValues,
const CombineOp& cop,
const TransformOp& top,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
@ -177,6 +186,7 @@ public:
// Synchronise point-wise data
//- Synchronize values on all mesh points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncPointList
(
@ -197,6 +207,7 @@ public:
}
//- Synchronize locations on all mesh points.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncPointPositions
(
@ -217,11 +228,12 @@ public:
}
//- Synchronize values on selected mesh points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncPointList
(
const polyMesh& mesh,
const labelList& meshPoints,
const labelUList& meshPoints,
List<T>& pointValues,
const CombineOp& cop,
const T& nullValue
@ -239,11 +251,12 @@ public:
}
//- Synchronize locations on selected mesh points.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncPointPositions
(
const polyMesh& mesh,
const labelList& meshPoints,
const labelUList& meshPoints,
List<point>& positions,
const CombineOp& cop,
const point& nullValue
@ -264,6 +277,7 @@ public:
// Synchronise edge-wise data
//- Synchronize values on all mesh edges.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncEdgeList
(
@ -285,6 +299,7 @@ public:
}
//- Synchronize locations on all mesh edges.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncEdgePositions
(
@ -306,11 +321,12 @@ public:
}
//- Synchronize values on selected mesh edges.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncEdgeList
(
const polyMesh& mesh,
const labelList& meshEdges,
const labelUList& meshEdges,
List<T>& edgeValues,
const CombineOp& cop,
const T& nullValue
@ -329,11 +345,12 @@ public:
}
//- Synchronize locations on selected mesh edges.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncEdgePositions
(
const polyMesh& mesh,
const labelList& meshEdges,
const labelUList& meshEdges,
List<point>& positions,
const CombineOp& cop,
const point& nullValue
@ -397,7 +414,9 @@ public:
(
const polyMesh& mesh,
UList<T>& faceValues,
const CombineOp& cop
const CombineOp& cop,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
SubList<T> bndValues
@ -412,7 +431,8 @@ public:
mesh,
bndValues,
cop,
mapDistribute::transform()
mapDistribute::transform(),
parRun
);
}
@ -422,7 +442,9 @@ public:
(
const polyMesh& mesh,
UList<point>& positions,
const CombineOp& cop
const CombineOp& cop,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
SubList<point> bndValues
@ -436,7 +458,8 @@ public:
mesh,
bndValues,
cop,
mapDistribute::transformPosition()
mapDistribute::transformPosition(),
parRun
);
}
@ -445,7 +468,9 @@ public:
static void swapBoundaryFaceList
(
const polyMesh& mesh,
UList<T>& faceValues
UList<T>& faceValues,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
syncBoundaryFaceList
@ -453,7 +478,8 @@ public:
mesh,
faceValues,
eqOp<T>(),
mapDistribute::transform()
mapDistribute::transform(),
parRun
);
}
@ -461,7 +487,9 @@ public:
static void swapBoundaryFacePositions
(
const polyMesh& mesh,
UList<point>& positions
UList<point>& positions,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
syncBoundaryFaceList
@ -469,7 +497,8 @@ public:
mesh,
positions,
eqOp<point>(),
mapDistribute::transformPosition()
mapDistribute::transformPosition(),
parRun
);
}
@ -478,7 +507,9 @@ public:
static void swapFaceList
(
const polyMesh& mesh,
UList<T>& faceValues
UList<T>& faceValues,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
SubList<T> bndValues
@ -492,31 +523,71 @@ public:
mesh,
bndValues,
eqOp<T>(),
mapDistribute::transform()
mapDistribute::transform(),
parRun
);
}
//- Swap to obtain neighbour cell values for all boundary faces
//- Extract and swap to obtain neighbour cell values
//- for all boundary faces
template<class T>
static void swapBoundaryCellList
(
const polyMesh& mesh,
const UList<T>& cellData,
List<T>& neighbourCellData
List<T>& neighbourCellData,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
//- Swap to obtain neighbour cell positions for all boundary faces
//- Extract and swap to obtain neighbour cell positions
//- for all boundary faces
static void swapBoundaryCellPositions
(
const polyMesh& mesh,
const UList<point>& cellData,
List<point>& neighbourCellData
List<point>& neighbourCellData,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
//- Return neighbour cell values for all boundary faces
//- by swapping via boundary faces
template<class T>
FOAM_NODISCARD static List<T> swapBoundaryCellList
(
const polyMesh& mesh,
const UList<T>& cellData,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
List<T> nbrCellData;
swapBoundaryCellList(mesh, cellData, nbrCellData, parRun);
return nbrCellData;
}
//- Return neighbour cell positions for all boundary faces
//- by swapping via boundary faces
FOAM_NODISCARD static List<point> swapBoundaryCellPositions
(
const polyMesh& mesh,
const UList<point>& cellData,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
)
{
List<point> nbrCellData;
swapBoundaryCellPositions(mesh, cellData, nbrCellData, parRun);
return nbrCellData;
}
// Sparse versions
//- Synchronize values on selected points.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncPointMap
(
@ -535,6 +606,7 @@ public:
}
//- Synchronize locations on selected points.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncPointPositions
(
@ -552,9 +624,10 @@ public:
);
}
//- Synchronize values on selected edges. Edges are represented
// by the two vertices that make it up so global edges never get
// constructed.
//- Synchronize values on selected edges.
//- Edges are represented by the two vertices that make it up
//- so global edges never get constructed.
// Communication if UPstream::parRun() == true.
template<class T, class CombineOp>
static void syncEdgeMap
(
@ -573,6 +646,7 @@ public:
}
//- Synchronize locations on selected edges.
// Communication if UPstream::parRun() == true.
template<class CombineOp>
static void syncEdgePositions
(
@ -601,7 +675,7 @@ public:
// offset when accessing values.
// \param faceValues The face values to synchronize
// \param cop The combine operation
// \param parRun True if this is a parallel simulation
// \param parRun Allow parallel communication
template<unsigned Width, class CombineOp>
static void syncFaceList
(
@ -619,6 +693,7 @@ public:
const polyMesh& mesh,
PackedList<Width>& faceValues,
const CombineOp& cop,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
@ -629,6 +704,7 @@ public:
const polyMesh& mesh,
PackedList<Width>& faceValues,
const CombineOp& cop,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
@ -637,7 +713,9 @@ public:
static void swapFaceList
(
const polyMesh& mesh,
PackedList<Width>& faceValues
PackedList<Width>& faceValues,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
//- Swap coupled boundary face values. Uses eqOp
@ -645,7 +723,9 @@ public:
static void swapBoundaryFaceList
(
const polyMesh& mesh,
PackedList<Width>& faceValues
PackedList<Width>& faceValues,
//! Allow parallel communication
const bool parRun = UPstream::parRun()
);
template<unsigned Width, class CombineOp>

View File

@ -79,6 +79,8 @@ void Foam::syncTools::combine
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class T, class CombineOp, class TransformOp>
void Foam::syncTools::syncPointMap
(
@ -488,7 +490,7 @@ void Foam::syncTools::syncEdgeMap
forAllConstIters(nbrPatchInfo, nbrIter)
{
const edge& e = nbrIter.key();
const edge meshEdge(meshPts[e[0]], meshPts[e[1]]);
const edge meshEdge(meshPts, e);
combine
(
@ -535,7 +537,7 @@ void Foam::syncTools::syncEdgeMap
{
const edge& e0 = edgesA[twoEdges[0]];
const edge meshEdge0(meshPtsA[e0[0]], meshPtsA[e0[1]]);
const edge meshEdge0(meshPtsA, e0);
const auto iter = edgeValues.cfind(meshEdge0);
@ -546,7 +548,7 @@ void Foam::syncTools::syncEdgeMap
}
{
const edge& e1 = edgesB[twoEdges[1]];
const edge meshEdge1(meshPtsB[e1[0]], meshPtsB[e1[1]]);
const edge meshEdge1(meshPtsB, e1);
const auto iter = edgeValues.cfind(meshEdge1);
@ -573,7 +575,7 @@ void Foam::syncTools::syncEdgeMap
if (half1Fnd.good())
{
const edge& e0 = edgesA[twoEdges[0]];
const edge meshEdge0(meshPtsA[e0[0]], meshPtsA[e0[1]]);
const edge meshEdge0(meshPtsA, e0);
combine
(
@ -589,7 +591,7 @@ void Foam::syncTools::syncEdgeMap
if (half0Fnd.good())
{
const edge& e1 = edgesB[twoEdges[1]];
const edge meshEdge1(meshPtsB[e1[0]], meshPtsB[e1[1]]);
const edge meshEdge1(meshPtsB, e1);
combine
(
@ -749,8 +751,8 @@ void Foam::syncTools::syncPointList
{
FatalErrorInFunction
<< "Number of values " << pointValues.size()
<< " is not equal to the number of points in the mesh "
<< mesh.nPoints() << abort(FatalError);
<< " != number of points " << mesh.nPoints() << nl
<< abort(FatalError);
}
mesh.globalData().syncPointData(pointValues, cop, top);
@ -772,8 +774,8 @@ void Foam::syncTools::syncPointList
{
FatalErrorInFunction
<< "Number of values " << pointValues.size()
<< " is not equal to the number of meshPoints "
<< meshPoints.size() << abort(FatalError);
<< " != number of meshPoints " << meshPoints.size() << nl
<< abort(FatalError);
}
const globalMeshData& gd = mesh.globalData();
const indirectPrimitivePatch& cpp = gd.coupledPatch();
@ -829,8 +831,8 @@ void Foam::syncTools::syncEdgeList
{
FatalErrorInFunction
<< "Number of values " << edgeValues.size()
<< " is not equal to the number of edges in the mesh "
<< mesh.nEdges() << abort(FatalError);
<< " != number of edges " << mesh.nEdges() << nl
<< abort(FatalError);
}
const edgeList& edges = mesh.edges();
@ -915,7 +917,7 @@ template<class T, class CombineOp, class TransformOp, class FlipOp>
void Foam::syncTools::syncEdgeList
(
const polyMesh& mesh,
const labelList& meshEdges,
const labelUList& meshEdges,
List<T>& edgeValues,
const CombineOp& cop,
const T& nullValue,
@ -927,8 +929,8 @@ void Foam::syncTools::syncEdgeList
{
FatalErrorInFunction
<< "Number of values " << edgeValues.size()
<< " is not equal to the number of meshEdges "
<< meshEdges.size() << abort(FatalError);
<< " != number of meshEdges " << meshEdges.size() << nl
<< abort(FatalError);
}
const edgeList& edges = mesh.edges();
const globalMeshData& gd = mesh.globalData();
@ -946,7 +948,7 @@ void Foam::syncTools::syncEdgeList
const auto iter = mpm.cfind(meshEdgei);
if (iter.good())
{
const label cppEdgei = iter();
const label cppEdgei = iter.val();
const edge& cppE = cppEdges[cppEdgei];
const edge& meshE = edges[meshEdgei];
@ -992,7 +994,7 @@ void Foam::syncTools::syncEdgeList
const auto iter = mpm.cfind(meshEdgei);
if (iter.good())
{
label cppEdgei = iter();
label cppEdgei = iter.val();
const edge& cppE = cppEdges[cppEdgei];
const edge& meshE = edges[meshEdgei];
@ -1029,14 +1031,13 @@ void Foam::syncTools::syncBoundaryFaceList
{
FatalErrorInFunction
<< "Number of values " << faceValues.size()
<< " is not equal to the number of boundary faces in the mesh "
<< mesh.nBoundaryFaces() << nl
<< " != number of boundary faces " << mesh.nBoundaryFaces() << nl
<< abort(FatalError);
}
const polyBoundaryMesh& patches = mesh.boundaryMesh();
if (parRun)
if (parRun && UPstream::parRun())
{
// Avoid mesh.globalData() - possible race condition
@ -1104,7 +1105,7 @@ void Foam::syncTools::syncBoundaryFaceList
}
// Wait for all comms to finish
Pstream::waitRequests(startRequest);
UPstream::waitRequests(startRequest);
// Combine with existing data
for (const polyPatch& pp : patches)
@ -1274,20 +1275,20 @@ void Foam::syncTools::syncFaceList
{
FatalErrorInFunction
<< "Number of values " << faceValues.size()
<< " is not equal to the number of "
<< " != number of "
<< (isBoundaryOnly ? "boundary" : "mesh") << " faces "
<< ((mesh.nFaces() - boundaryOffset)) << nl
<< (mesh.nFaces() - boundaryOffset) << nl
<< abort(FatalError);
}
const polyBoundaryMesh& patches = mesh.boundaryMesh();
if (parRun)
if (parRun && UPstream::parRun())
{
const label startRequest = UPstream::nRequests();
// Receive buffers
PtrList<PackedList<Width>> recvInfos(patches.size());
PtrList<PackedList<Width>> recvBufs(patches.size());
// Set up reads
for (const polyPatch& pp : patches)
@ -1298,23 +1299,21 @@ void Foam::syncTools::syncFaceList
{
const auto& procPatch = *ppp;
const label patchi = pp.index();
const label patchSize = pp.size();
recvInfos.set(patchi, new PackedList<Width>(patchSize));
PackedList<Width>& recvInfo = recvInfos[patchi];
auto& recvbuf = recvBufs.emplace_set(patchi, pp.size());
UIPstream::read
(
UPstream::commsTypes::nonBlocking,
procPatch.neighbProcNo(),
recvInfo.data_bytes(),
recvInfo.size_bytes()
recvbuf.data_bytes(),
recvbuf.size_bytes()
);
}
}
// Send buffers
PtrList<PackedList<Width>> sendInfos(patches.size());
PtrList<PackedList<Width>> sendBufs(patches.size());
// Set up writes
for (const polyPatch& pp : patches)
@ -1326,24 +1325,16 @@ void Foam::syncTools::syncFaceList
const auto& procPatch = *ppp;
const label patchi = pp.index();
const labelRange range
(
pp.start()-boundaryOffset,
pp.size()
);
sendInfos.set
(
patchi,
new PackedList<Width>(faceValues, range)
);
PackedList<Width>& sendInfo = sendInfos[patchi];
const labelRange range(pp.start()-boundaryOffset, pp.size());
auto& sendbuf = sendBufs.emplace_set(patchi, faceValues, range);
UOPstream::write
(
UPstream::commsTypes::nonBlocking,
procPatch.neighbProcNo(),
sendInfo.cdata_bytes(),
sendInfo.size_bytes()
sendbuf.cdata_bytes(),
sendbuf.size_bytes()
);
}
}
@ -1361,13 +1352,13 @@ void Foam::syncTools::syncFaceList
const label patchi = pp.index();
const label patchSize = pp.size();
const PackedList<Width>& recvInfo = recvInfos[patchi];
const auto& recvbuf = recvBufs[patchi];
// Combine (bitwise)
label bFacei = pp.start()-boundaryOffset;
for (label i = 0; i < patchSize; ++i)
{
unsigned int recvVal = recvInfo[i];
unsigned int recvVal = recvbuf[i];
unsigned int faceVal = faceValues[bFacei];
cop(faceVal, recvVal);
@ -1420,15 +1411,16 @@ void Foam::syncTools::swapBoundaryCellList
(
const polyMesh& mesh,
const UList<T>& cellData,
List<T>& neighbourCellData
List<T>& neighbourCellData,
const bool parRun
)
{
if (cellData.size() != mesh.nCells())
{
FatalErrorInFunction
<< "Number of cell values " << cellData.size()
<< " is not equal to the number of cells in the mesh "
<< mesh.nCells() << abort(FatalError);
<< " != number of cells " << mesh.nCells() << nl
<< abort(FatalError);
}
const polyBoundaryMesh& patches = mesh.boundaryMesh();
@ -1437,15 +1429,18 @@ void Foam::syncTools::swapBoundaryCellList
for (const polyPatch& pp : patches)
{
label bFacei = pp.offset();
const auto& faceCells = pp.faceCells();
for (const label celli : pp.faceCells())
{
neighbourCellData[bFacei] = cellData[celli];
++bFacei;
}
// ie, boundarySlice() = patchInternalList()
SubList<T>
(
neighbourCellData,
faceCells.size(),
pp.offset()
) = UIndirectList<T>(cellData, faceCells);
}
syncTools::swapBoundaryFaceList(mesh, neighbourCellData);
syncTools::swapBoundaryFaceList(mesh, neighbourCellData, parRun);
}
@ -1479,10 +1474,17 @@ template<unsigned Width>
void Foam::syncTools::swapFaceList
(
const polyMesh& mesh,
PackedList<Width>& faceValues
PackedList<Width>& faceValues,
const bool parRun
)
{
syncFaceList(mesh, faceValues, eqOp<unsigned int>());
syncFaceList
(
mesh,
faceValues,
eqOp<unsigned int>(),
parRun
);
}
@ -1490,10 +1492,17 @@ template<unsigned Width>
void Foam::syncTools::swapBoundaryFaceList
(
const polyMesh& mesh,
PackedList<Width>& faceValues
PackedList<Width>& faceValues,
const bool parRun
)
{
syncBoundaryFaceList(mesh, faceValues, eqOp<unsigned int>());
syncBoundaryFaceList
(
mesh,
faceValues,
eqOp<unsigned int>(),
parRun
);
}
@ -1510,8 +1519,8 @@ void Foam::syncTools::syncPointList
{
FatalErrorInFunction
<< "Number of values " << pointValues.size()
<< " is not equal to the number of points in the mesh "
<< mesh.nPoints() << abort(FatalError);
<< " != number of points " << mesh.nPoints() << nl
<< abort(FatalError);
}
const globalMeshData& gd = mesh.globalData();
@ -1553,8 +1562,8 @@ void Foam::syncTools::syncEdgeList
{
FatalErrorInFunction
<< "Number of values " << edgeValues.size()
<< " is not equal to the number of edges in the mesh "
<< mesh.nEdges() << abort(FatalError);
<< " != number of edges " << mesh.nEdges() << nl
<< abort(FatalError);
}
const globalMeshData& gd = mesh.globalData();

View File

@ -96,7 +96,7 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
{
map.insert(id, zonei);
}
else if (fnd() != zonei)
else if (fnd.val() != zonei)
{
// Multiple zones for same id
@ -112,7 +112,7 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
: static_cast<const labelList&>(zn)
)
{
maxIndex = max(maxIndex, id);
maxIndex = Foam::max(maxIndex, id);
}
}
additionalMapPtr_.reset(new labelListList(maxIndex+1));
@ -135,7 +135,7 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
if (zones.size())
{
stableSort(zones);
Foam::stableSort(zones);
const label zonei = map[id];
const label index = findLower(zones, zonei);
if (index == -1)
@ -426,11 +426,11 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::whichZones
) const
{
zones.clear();
const auto fnd = zoneMap().find(objectIndex);
const auto fnd = zoneMap().cfind(objectIndex);
if (fnd)
{
// Add main element
zones.push_back(fnd());
zones.push_back(fnd.val());
if (additionalMapPtr_)
{
const auto& additionalMap = *additionalMapPtr_;
@ -967,7 +967,7 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkParallelSync
const bool report
) const
{
if (!Pstream::parRun())
if (!UPstream::parRun())
{
return false;
}
@ -1025,7 +1025,7 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkParallelSync
{
hasError = true;
if (debug || (report && Pstream::master()))
if (debug || (report && UPstream::master()))
{
Info<< " ***Zone " << zn.name()
<< " of type " << zn.type()

View File

@ -194,9 +194,8 @@ public:
// If object does not belong to any zones, return -1
label whichZone(const label objectIndex) const;
//- Given a global object index, return (in argument) the zones it is
// in. Returns number of zones (0 if object does not belong to any
// zones)
//- Given a global object index, return (in argument) its zones.
// Returns number of zones (0 if object does not belong to any zones)
label whichZones
(
const label objectIndex,

View File

@ -33,7 +33,15 @@ fvOptions/atmPlantCanopyTurbSource/atmPlantCanopyTurbSource.C
fvOptions/atmPlantCanopyUSource/atmPlantCanopyUSource.C
fvOptions/atmPlantCanopyTSource/atmPlantCanopyTSource.C
fvOptions/atmNutSource/atmNutSource.C
fvOptions/treeTurbulence/treeTurbulence.C
etht = fvOptions/evapotranspirationHeatTransfer
ethtModels = $(etht)/evapotranspirationHeatTransferModels
$(etht)/evapotranspirationHeatTransfer.C
$(ethtModels)/evapotranspirationHeatTransferModel/evapotranspirationHeatTransferModel.C
$(ethtModels)/evapotranspirationHeatTransferModel/evapotranspirationHeatTransferModelNew.C
$(ethtModels)/tree/tree.C
$(ethtModels)/grass/grass.C
/* functionObjects */
functionObjects/ObukhovLength/ObukhovLength.C

View File

@ -8,6 +8,7 @@ EXE_INC = \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/solidThermo/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/radiation/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
-I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
@ -18,6 +19,7 @@ LIB_LIBS = \
-lfvOptions \
-lmeshTools \
-lsurfMesh \
-lradiationModels \
-lfluidThermophysicalModels \
-lsolidThermo \
-lturbulenceModels \

View File

@ -0,0 +1,172 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "evapotranspirationHeatTransfer.H"
#include "evapotranspirationHeatTransferModel.H"
#include "fvMesh.H"
#include "fvMatrix.H"
#include "basicThermo.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
defineTypeNameAndDebug(evapotranspirationHeatTransfer, 0);
addToRunTimeSelectionTable
(
option,
evapotranspirationHeatTransfer,
dictionary
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fv::evapotranspirationHeatTransfer::evapotranspirationHeatTransfer
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
)
:
fv::cellSetOption(sourceName, modelType, dict, mesh),
ethtModelPtr_()
{
// Set the field name to that of the energy
// field from which the temperature is obtained
const auto& thermo = mesh_.lookupObject<basicThermo>(basicThermo::dictName);
fieldNames_.resize(1, thermo.he().name());
fv::option::resetApplied();
Info<< " Applying evapotranspirationHeatTransfer to: " << fieldNames_[0]
<< endl;
read(dict);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fv::evapotranspirationHeatTransfer::~evapotranspirationHeatTransfer()
{} // evapotranspirationHeatTransferModel was forward declared
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::fv::evapotranspirationHeatTransfer::addSup
(
fvScalarMatrix& eqn,
const label fieldi
)
{
if (this->V() < VSMALL)
{
return;
}
const scalar V = this->V();
const scalarField& Vcells = mesh_.V();
const volScalarField& he = eqn.psi();
scalarField& heSource = eqn.source();
// Calculate evapotranspiration heat transfer rate per volume [J/s/m^3]
const scalarField Q(ethtModelPtr_->Q(cells_)/V);
if (he.dimensions() == dimEnergy/dimMass)
{
forAll(cells_, i)
{
const label celli = cells_[i];
heSource[celli] += Q[i]*Vcells[celli];
}
}
else if (he.dimensions() == dimTemperature)
{
const auto& thermo =
mesh_.lookupObject<basicThermo>(basicThermo::dictName);
// Calculate density*heat capacity at constant pressure/volume
const volScalarField rhoCpv(thermo.rho()*thermo.Cpv());
// heSource [K m^3/s] = [J/s/m^3] * m^3 / [kg/m^3] / [J/kg/K]
forAll(cells_, i)
{
const label celli = cells_[i];
heSource[celli] += Q[i]*Vcells[celli]*rhoCpv[i];
}
}
}
void Foam::fv::evapotranspirationHeatTransfer::addSup
(
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
)
{
addSup(eqn, fieldi);
}
bool Foam::fv::evapotranspirationHeatTransfer::read(const dictionary& dict)
{
if (!fv::cellSetOption::read(dict))
{
return false;
}
if (selectionMode_ != selectionModeType::smCellZone)
{
FatalIOErrorInFunction(dict)
<< "evapotranspirationHeatTransfer requires "
<< selectionModeTypeNames_[selectionModeType::smCellZone]
<< exit(FatalIOError);
}
ethtModelPtr_.reset
(
evapotranspirationHeatTransferModel::New(dict, mesh_)
);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,183 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::fv::evapotranspirationHeatTransfer
Description
Applies sources on temperature (\c T - incompressible)
or energy (\c h/e - compressible) equation to incorporate
evapotranspiration heat-transfer effects from the specified
plant canopy. Heat transfer is usually calculated based on
empirical relations between plants and solar radiation.
Usage
Example by using \c constant/fvOptions:
\verbatim
evapotranspirationHeatTransfer1
{
// Mandatory entries
type evapotranspirationHeatTransfer;
model <word>;
// Model-specific entries
...
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: evapotranspirationHeatTransfer | word | yes | -
model | Name of heat-transfer model | word | yes | -
\endtable
Options for the \c model entry:
\verbatim
tree | Regression-based heat-transfer model for trees
grass | Heat-transfer model for grass
\endverbatim
The inherited entries are elaborated in:
- \link fvOption.H \endlink
- \link cellSetOption.H \endlink
Note
- Evapotranspiration mass transfer is not modelled.
SourceFiles
evapotranspirationHeatTransfer.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_fv_evapotranspirationHeatTransfer_H
#define Foam_fv_evapotranspirationHeatTransfer_H
#include "cellSetOption.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class evapotranspirationHeatTransferModel;
namespace fv
{
/*---------------------------------------------------------------------------*\
Class evapotranspirationHeatTransfer Declaration
\*---------------------------------------------------------------------------*/
class evapotranspirationHeatTransfer
:
public fv::cellSetOption
{
// Private Data
//- Runtime-selectable evapotranspiration heat transfer model
autoPtr<evapotranspirationHeatTransferModel> ethtModelPtr_;
public:
//- Runtime type information
TypeName("evapotranspirationHeatTransfer");
// Constructors
//- Construct from explicit source name and mesh
evapotranspirationHeatTransfer
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
evapotranspirationHeatTransfer(const evapotranspirationHeatTransfer&) =
delete;
//- No copy assignment
void operator=(const evapotranspirationHeatTransfer&) = delete;
//- Destructor
virtual ~evapotranspirationHeatTransfer();
// Member Functions
//- Add explicit contribution to energy equation
//- for incompressible flow computations
virtual void addSup
(
fvScalarMatrix& eqn,
const label fieldi
);
//- Add explicit contribution to energy equation
//- for compressible flow computations
virtual void addSup
(
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
);
//- Add explicit contribution to energy equation
//- for multiphase flow computations
virtual void addSup
(
const volScalarField& alpha,
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
)
{
NotImplemented;
}
//- Read dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,196 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "evapotranspirationHeatTransferModel.H"
#include "radiationModel.H"
#include "solarLoadBase.H"
#include "fvMesh.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(evapotranspirationHeatTransferModel, 0);
defineRunTimeSelectionTable
(
evapotranspirationHeatTransferModel,
dictionary
);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
Foam::volScalarField& Foam::evapotranspirationHeatTransferModel::getOrReadField
(
const word& fieldName
) const
{
auto* ptr = mesh_.getObjectPtr<volScalarField>(fieldName);
if (!ptr)
{
ptr = new volScalarField
(
IOobject
(
fieldName,
mesh_.time().timeName(),
mesh_,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh_
);
mesh_.objectRegistry::store(ptr);
}
return *ptr;
}
Foam::scalar Foam::evapotranspirationHeatTransferModel::q() const
{
// Retrieve solar-load information
const auto& base =
mesh().lookupObject<radiation::solarLoadBase>("solarLoadBase");
const solarCalculator& solar = base.solarCalculatorRef();
// Retrieve internal & boundary faces directly hit by solar rays
const faceShading& shade = base.faceShadingRef();
const labelList& hitFacesId = shade.rayStartFaces();
// Retrieve face zone information
const faceZone& zone = mesh_.faceZones()[faceZoneId_];
const vectorField& faceNormals = zone().faceNormals();
const scalarField& faceAreas = zone().magFaceAreas();
// Retrieve direct solar load [W/m^2]
const vector directSolarRad(solar.directSolarRad()*solar.direction());
// Identify zone faces within mesh
bitSet isZoneFace(mesh_.nFaces());
isZoneFace.set(zone);
// Calculate area-averaged incident solar load
// Assuming hit faces are updated by solarLoad
scalar q = 0;
scalar totalFaceArea = 0;
for (const label facei : hitFacesId)
{
if (isZoneFace[facei])
{
const label localFacei = zone.whichFace(facei);
const vector& faceNormal = faceNormals[localFacei];
const scalar faceArea = faceAreas[localFacei];
const scalar qIncident = directSolarRad & faceNormal;
q += qIncident*faceArea;
totalFaceArea += faceArea;
}
}
reduce(q, sumOp<scalar>());
reduce(totalFaceArea, sumOp<scalar>());
q /= totalFaceArea;
// Sum diffusive solar loads
switch(solar.sunLoadModel())
{
case solarCalculator::mSunLoadFairWeatherConditions:
case solarCalculator::mSunLoadTheoreticalMaximum:
{
// Calculate diffusive radiance
// contribution from sky and ground
tmp<scalarField> tdiffuseSolarRad =
solar.diffuseSolarRad(faceNormals);
const scalarField& diffuseSolarRad = tdiffuseSolarRad.cref();
// Calculate area-averaged diffusive solar load
scalar meanDiffuseSolarRad = 0;
forAll(faceAreas, i)
{
meanDiffuseSolarRad += diffuseSolarRad[i]*faceAreas[i];
}
meanDiffuseSolarRad /= totalFaceArea;
q += meanDiffuseSolarRad;
}
break;
case solarCalculator::mSunLoadConstant:
case solarCalculator::mSunLoadTimeDependent:
{
q += solar.diffuseSolarRad();
}
break;
}
return q;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::evapotranspirationHeatTransferModel::evapotranspirationHeatTransferModel
(
const dictionary& dict,
const fvMesh& mesh
)
:
mesh_(mesh)
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::evapotranspirationHeatTransferModel::read(const dictionary& dict)
{
faceZoneId_ = mesh_.faceZones().findZoneID(dict.get<word>("faceZone"));
if (faceZoneId_ < 0)
{
const word faceZoneName(mesh_.faceZones()[faceZoneId_].name());
FatalIOErrorInFunction(dict)
<< type() << ' ' << typeName << ": "
<< " No matching face zone: " << faceZoneName << nl
<< " Known face zones: "
<< flatOutput(mesh_.faceZones().names()) << nl
<< exit(FatalIOError);
return false;
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,180 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::evapotranspirationHeatTransferModel
Description
Base class for evapotranspiration models
to handle general evapotranspiration characteristics.
SourceFiles
evapotranspirationHeatTransferModel.C
evapotranspirationHeatTransferModelNew.C
evapotranspirationHeatTransferModelTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_evapotranspirationHeatTransferModel_H
#define Foam_evapotranspirationHeatTransferModel_H
#include "dictionary.H"
#include "HashSet.H"
#include "volFields.H"
#include "runTimeSelectionTables.H"
#include "OFstream.H"
#include "coordinateSystem.H"
#include "writeFile.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class fvMesh;
/*---------------------------------------------------------------------------*\
Class evapotranspirationHeatTransferModel Declaration
\*---------------------------------------------------------------------------*/
class evapotranspirationHeatTransferModel
{
// Private Data
//- Reference to the mesh
const fvMesh& mesh_;
//- Identifier of specified face zone
label faceZoneId_;
protected:
// Protected Member Functions
//- Return requested field from the object registry
//- or read+register the field to the object registry
volScalarField& getOrReadField(const word& fieldName) const;
//- Area-averaged heat flux due to short-wave
//- solar rays on face zone [W/m^2]
// Short-wave: direct and diffusive solar rays
scalar q() const;
public:
//- Runtime type information
TypeName("evapotranspirationHeatTransferModel");
// Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
evapotranspirationHeatTransferModel,
dictionary,
(
const dictionary& dict,
const fvMesh& mesh
),
(dict, mesh)
);
// Selectors
//- Return a reference to the selected evapotranspiration model
static autoPtr<evapotranspirationHeatTransferModel> New
(
const dictionary& dict,
const fvMesh& mesh
);
// Constructors
//- Construct from components
evapotranspirationHeatTransferModel
(
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
evapotranspirationHeatTransferModel
(
const evapotranspirationHeatTransferModel&
) = delete;
//- No copy assignment
void operator=(const evapotranspirationHeatTransferModel&) = delete;
//- Destructor
virtual ~evapotranspirationHeatTransferModel() = default;
// Member Functions
// Access
//- Return const reference to the mesh
const fvMesh& mesh() const noexcept
{
return mesh_;
}
//- Return the face-zone identifier
label faceZoneId() const noexcept
{
return faceZoneId_;
}
// Evaluation
//- Return heat-transfer rate for speficied cells [J/s]
virtual tmp<scalarField> Q(const labelList& cells) const = 0;
// I-O
//- Read the dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,34 +25,38 @@ License
\*---------------------------------------------------------------------------*/
#ifndef AMIFieldOps_H
#define AMIFieldOps_H
#include "evapotranspirationHeatTransferModel.H"
#include "fvMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "ops.H"
#include "AMIFieldOp.H"
#include "AMIMultiplyWeightedOp.H"
#include "LowWeightCorrection.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
Foam::autoPtr<Foam::evapotranspirationHeatTransferModel>
Foam::evapotranspirationHeatTransferModel::New
(
const dictionary& dict,
const fvMesh& mesh
)
{
word modelType(dict.get<word>("model"));
template<class Type>
using AMIMaxOp = AMIFieldOp<Type, maxEqOp<Type>>;
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
template<class Type>
using AMIMinOp = AMIFieldOp<Type, minEqOp<Type>>;
if (!cstrIter.found())
{
FatalIOErrorInLookup
(
dict,
"model",
modelType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
template<class Type>
using AMICorrectedMultiplyWeightedOp =
LowWeightCorrection<AMIMultiplyWeightedOp<Type>, plusEqOp<Type>>;
return autoPtr<evapotranspirationHeatTransferModel>
(
cstrIter()(dict, mesh)
);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
// ************************************************************************* //

View File

@ -0,0 +1,418 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "grass.H"
#include "basicThermo.H"
#include "fluidThermo.H"
#include "turbulentTransportModel.H"
#include "turbulentFluidThermoModel.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace evapotranspirationHeatTransferModels
{
defineTypeNameAndDebug(grass, 0);
addToRunTimeSelectionTable
(
evapotranspirationHeatTransferModel,
grass,
dictionary
);
}
}
const Foam::Enum
<
Foam::evapotranspirationHeatTransferModels::grass::soilHeatFluxType
>
Foam::evapotranspirationHeatTransferModels::grass::soilHeatFluxTypeNames
({
{
soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION,
"proportionalToSolarRadiation"
},
{ soilHeatFluxType::BOUNDARY, "boundary" }
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::tmp<Foam::scalarField>
Foam::evapotranspirationHeatTransferModels::grass::E(const labelList& cells)
const
{
const scalar q = this->q();
const scalar G = this->G(cells);
const scalar Delta = this->Delta();
const scalar D = this->D();
const scalar ra = this->ra();
const scalar rs = this->rs();
const scalar gamma = this->gamma();
// (BSG:Eq. 11)
const scalar E =
(Delta*(q - G) + rho_*Cp_*D/ra)/(Delta + gamma*(1 + rs/ra));
return tmp<scalarField>::New(cells.size(), E);
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::Delta() const
{
// (BSG:Eq. 15), (APR:Eq. 13) - note 0.6108 -> 610.8 due to kPa -> Pa
const scalar Ta = Tref_ + 237.3;
return 4098*(610.8*exp(17.27*Tref_/Ta))/sqr(Ta);
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::D() const
{
// (BSG:Eq. 16)
const scalar RHref = RHptr_->value(mesh().time().timeOutputValue());
return (1 - RHref)*pSat();
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::pSat() const
{
// (BSG:Eq. 17; Arden Buck equation)
const scalar p1 = (1.0007 + 3.46e-8*pAtm_)*611.21;
return p1*exp((18.678 - Tref_/234.5)*Tref_/(Tref_ + 257.14));
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::gamma() const
{
// (APR:Eq. 8)
return Cp_*pAtm_/(epsilon_*lambda());
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::lambda() const
{
// (BSG:Eq. 12)
const scalar T1 = Tref_ + 273.15;
const scalar T2 = Tref_ + 239.24;
return 1.91846e6*sqr(T1/T2);
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::ra() const
{
// (APR:Eq. 4), (BSG:Eq. 14)
const scalar log1 = log((zRefU_ - d_*h_)/(zom_*h_));
const scalar log2 = log((zRefH_ - d_*h_)/(zoh_*h_));
return log1*log2/(sqr(kappa_)*uRef_);
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::rs() const
{
// (BSG:Eq. 13), (APR:Eq. 5; reduced form in p. 4-5)
return ri_/(scalar(12)*h_);
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::S
(
const labelList& cells
) const
{
// Mark fvOption cells within mesh
bitSet isZoneCell(mesh().nCells());
isZoneCell.set(cells);
scalar S = 0;
// Select cells next to specified patches
// Sum patch area that is covered by fvOption cells
for (const label patchi : patchSet_)
{
const scalarField& s = mesh().magSf().boundaryField()[patchi];
const polyPatch& pp = mesh().boundaryMesh()[patchi];
const labelList& faceCells = pp.faceCells();
forAll(faceCells, i)
{
const bool isCovered = isZoneCell[faceCells[i]];
if (isCovered)
{
S += s[i];
}
}
}
reduce(S, sumOp<scalar>());
if (mag(S) < SMALL)
{
FatalErrorInFunction
<< "Area coverage of grass cannot be zero. "
<< "Check whether cellZone has any boundary faces."
<< exit(FatalError);
}
return S;
}
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::G
(
const labelList& cells
) const
{
switch (soilHeatFluxMethod_)
{
case soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION:
{
return Csoil_*q();
}
case soilHeatFluxType::BOUNDARY:
{
// Retrieve heat flux through patches
tmp<FieldField<Field, scalar>> tqBf = this->qBf();
const FieldField<Field, scalar>& qBf = tqBf.cref();
// Mark fvOption cells within mesh
bitSet isZoneCell(mesh().nCells());
isZoneCell.set(cells);
scalar G = 0;
for (const label patchi : patchSet_)
{
const scalarField& s = mesh().magSf().boundaryField()[patchi];
const scalarField& qfld = qBf[patchi];
const polyPatch& pp = mesh().boundaryMesh()[patchi];
const labelList& faceCells = pp.faceCells();
forAll(faceCells, i)
{
const bool isCovered = isZoneCell[faceCells[i]];
if (isCovered)
{
G += qfld[i]*s[i];
}
}
}
reduce(G, sumOp<scalar>());
return G/area_;
}
}
return -1;
}
Foam::tmp<Foam::FieldField<Foam::Field, Foam::scalar>>
Foam::evapotranspirationHeatTransferModels::grass::qBf() const
{
const auto& T = mesh().lookupObject<volScalarField>(TName_);
const volScalarField::Boundary& Tbf = T.boundaryField();
auto tq = tmp<FieldField<Field, scalar>>::New(Tbf.size());
auto& q = tq.ref();
forAll(q, patchi)
{
q.set(patchi, new Field<scalar>(Tbf[patchi].size(), Zero));
}
typedef compressible::turbulenceModel cmpTurbModel;
if (mesh().foundObject<cmpTurbModel>(cmpTurbModel::propertiesName))
{
const auto& turb =
mesh().lookupObject<cmpTurbModel>(cmpTurbModel::propertiesName);
// Note: calling he(p,T) instead of he()
const volScalarField he(turb.transport().he(turb.transport().p(), T));
const volScalarField::Boundary& hebf = he.boundaryField();
const volScalarField alphaEff(turb.alphaEff());
const volScalarField::Boundary& alphaEffbf = alphaEff.boundaryField();
for (const label patchi : patchSet_)
{
q[patchi] = alphaEffbf[patchi]*hebf[patchi].snGrad();
}
}
else if (mesh().foundObject<fluidThermo>(fluidThermo::dictName))
{
const auto& thermo =
mesh().lookupObject<fluidThermo>(fluidThermo::dictName);
// Note: calling he(p,T) instead of he()
const volScalarField he(thermo.he(thermo.p(), T));
const volScalarField::Boundary& hebf = he.boundaryField();
const volScalarField& alpha(thermo.alpha());
const volScalarField::Boundary& alphabf = alpha.boundaryField();
for (const label patchi : patchSet_)
{
q[patchi] = alphabf[patchi]*hebf[patchi].snGrad();
}
}
else
{
FatalErrorInFunction
<< "Unable to find a valid thermo model to evaluate q. " << nl
<< "Database contents are: " << mesh().objectRegistry::sortedToc()
<< exit(FatalError);
}
// No radiative heat flux contribution is present
return tq;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::evapotranspirationHeatTransferModels::grass::grass
(
const dictionary& dict,
const fvMesh& mesh
)
:
evapotranspirationHeatTransferModel(dict, mesh),
soilHeatFluxMethod_
(
soilHeatFluxTypeNames.getOrDefault
(
"soilHeatFluxMethod",
dict,
soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION
)
),
Tptr_(nullptr),
RHptr_(nullptr),
area_(-1),
Csoil_(),
rho_(),
Cp_(),
epsilon_(),
h_(),
kappa_(),
uRef_(),
zRefU_(),
zRefH_(),
zom_(),
zoh_(),
d_(),
ri_(),
pAtm_(),
Tref_(0),
TName_(),
patchSet_()
{
Info<< " Activating evapotranspiration heat transfer model: "
<< typeName << endl;
read(dict);
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp<Foam::scalarField>
Foam::evapotranspirationHeatTransferModels::grass::Q
(
const labelList& cells
) const
{
if (area_ == -1)
{
area_ = S(cells);
}
Tref_ = Tptr_->value(mesh().time().timeOutputValue());
return E(cells)*area_;
}
bool Foam::evapotranspirationHeatTransferModels::grass::read
(
const dictionary& dict
)
{
if (!evapotranspirationHeatTransferModel::read(dict))
{
return false;
}
Tptr_.reset(Function1<scalar>::New("Tref", dict, &mesh()));
RHptr_.reset(Function1<scalar>::New("RHref", dict, &mesh()));
area_ = -1;
const auto range = scalarMinMax::ge(SMALL);
Csoil_ = dict.getCheckOrDefault<scalar>("Csoil", 0.1, range);
rho_ = dict.getCheckOrDefault<scalar>("rho", 1.225, range);
Cp_ = dict.getCheckOrDefault<scalar>("Cp", 1013.0, range);
epsilon_ = dict.getCheckOrDefault<scalar>("epsilon", 0.622, range);
h_ = dict.getCheckOrDefault<scalar>("h", 0.1, range);
kappa_ = dict.getCheckOrDefault<scalar>("kappa", 0.41, range);
uRef_ = dict.getCheckOrDefault<scalar>("uRef", 2, range);
zRefU_ = dict.getCheckOrDefault<scalar>("zRefU", 10, range);
zRefH_ = dict.getCheckOrDefault<scalar>("zRefH", 10, range);
zom_ = dict.getCheckOrDefault<scalar>("zom", 0.123, range);
zoh_ = dict.getCheckOrDefault<scalar>("zoh", 0.0123, range);
d_ = dict.getCheckOrDefault<scalar>("d", 2.0/3.0, range);
ri_ = dict.getCheckOrDefault<scalar>("ri", 100, range);
pAtm_ = dict.getCheckOrDefault<scalar>("pAtm", 101.325, range);
TName_ = dict.getOrDefault<word>("T", "T");
if (soilHeatFluxMethod_ == soilHeatFluxType::BOUNDARY)
{
patchSet_ =
mesh().boundaryMesh().patchSet(dict.get<wordRes>("patches"));
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,342 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::evapotranspirationHeatTransferModels::grass
Description
Applies sources on temperature (\c T - incompressible) or energy
(\c h/e - compressible) equation to incorporate evapotranspiration
heat-transfer effects from the specified grass canopy.
The model is based on Pemnan-Monteith Equation model.
Sources applied to either of the below, if exist:
\verbatim
T | Temperature [K]
e | Internal energy [m^2/s^2]
h | Enthalphy [m^2/s^2]
\endverbatim
Required fields:
\verbatim
T | Temperature [K]
e | Internal energy [m^2/s^2]
h | Enthalphy [m^2/s^2]
LAD | Leaf area density [m^2/m^3]
\endverbatim
References:
\verbatim
Governing equations (tag:BSG):
Brozovsky, J., Simonsen, A., & Gaitani, N. (2021).
Validation of a CFD model for the evaluation of urban
microclimate at high latitudes: A case study in Trondheim, Norway.
Building and Environment, 205, 108175.
DOI:10.1016/j.buildenv.2021.108175
Governing equations (tag:APR):
Allen, R. G., Pereira, L. S., Raes, D., & Smith, M. (1998).
Crop evapotranspiration-Guidelines for computing crop
water requirements-FAO Irrigation and drainage paper 56.
Fao, Rome, 300(9), D05109.
\endverbatim
Usage
Example by using \c constant/fvOptions:
\verbatim
evapotranspirationHeatTransfer1
{
// Inherited entries
...
// Mandatory entries
model grass;
Tref <Function1<scalar>>;
RHref <Function1<scalar>>;
// Conditional entries
// when soilHeatFluxMethod == boundary
patches <wordRes>;
// Optional entries
soilHeatFluxMethod <word>;
Csoil <scalar>;
rho <scalar>;
Cp <scalar>;
epsilon <scalar>;
h <scalar>;
kappa <scalar>;
uRef <scalar>;
zRefU <scalar>;
zRefH <scalar>;
zom <scalar>;
zoh <scalar>;
d <scalar>;
ri <scalar>;
pAtm <scalar>;
T <word>;
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
model | Model name: grass | word | yes | -
Tref | Reference weather station air temperature [Celsius] <!--
--> | Function1\<scalar\> | yes | -
RHref | Reference weather station relative humidity [%] <!--
--> | Function1\<scalar\> | yes | -
patches | Names of ground patches | wordRes | yes | -
soilHeatFluxMethod | Method to calculate soil heat flux - see below <!--
--> | word | no | -
Csoil | Proportionality constant of soil heat-flux wrt <!--
--> solar radiation | scalar | no | 0.1
rho | Mean air density at constant pressure [kg/m^3] <!--
--> | scalar | no | 1.225
Cp | Specific heat at constant pressure [J/kg/C] <!--
--> | scalar | no | 1013.0
epsilon | Molecular-weight ratio of water vapour/dry air [-] <!--
--> | scalar | no | 0.622
h | Height of grass layer [m] | scalar | no | 0.1
kappa | Von Karman constant [-] | scalar | no | 0.41
uRef | Reference velocity magnitude [m/s] | scalar | no | 2.0
zRefU | Height of wind speed measurements [m] | scalar | no | 10.0
zRefH | Height of humidity measurements [m] | scalar | no | 10.0
zom | Roughness length governing momentum transfer coefficient <!--
--> [-] | scalar | no | 0.123
zoh | Roughness length governing transfer of heat and vapour <!--
--> coefficient [-] | scalar | no | 0.0123
d | Zero plane displacement height coefficient [-] <!--
--> | scalar | no | 0.666
ri | Bulk stomata resistance of leaf [s/m] | scalar | no | 100.0
pAtm | Atmospheric pressure [kPa] | scalar | no | 101.325
T | Name of temperature field | word | no | T
\endtable
Options for the \c soilHeatFluxMethod entry:
\verbatim
proportionalToSolarRadiation | Estimate from solar load
boundary | Obtain soil heat flux from boundary
\endverbatim
The inherited entries are elaborated in:
- \link evapotranspirationHeatTransfer.H \endlink
- \link evapotranspirationHeatTransferModel.H \endlink
SourceFiles
grass.C
grassTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_evapotranspirationHeatTransferModels_grass_H
#define Foam_evapotranspirationHeatTransferModels_grass_H
#include "evapotranspirationHeatTransferModel.H"
#include "Function1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace evapotranspirationHeatTransferModels
{
/*---------------------------------------------------------------------------*\
Class grass Declaration
\*---------------------------------------------------------------------------*/
class grass
:
public evapotranspirationHeatTransferModel
{
// Private Enumerations
//- Options for the soil heat flux
enum soilHeatFluxType : char
{
PROPORTIONAL_TO_SOLAR_RADIATION = 0, //!< "Estimate from solar load"
BOUNDARY, //!< "Obtain soil heat flux from boundary"
};
//- Names for soilHeatFluxType
static const Enum<soilHeatFluxType> soilHeatFluxTypeNames;
// Private Data
//- Soil heat-flux calculation method
enum soilHeatFluxType soilHeatFluxMethod_;
//- Reference weather station air temperature [Celsius]
autoPtr<Function1<scalar>> Tptr_;
//- Reference weather station relative humidity [%]
autoPtr<Function1<scalar>> RHptr_;
//- Area coverage of grass [m^2]
mutable scalar area_;
//- Proportionality constant of soil heat-flux wrt solar radiation [-]
scalar Csoil_;
//- Mean air density at constant pressure [kg/m^3]
scalar rho_;
//- Specific heat at constant pressure [J/kg/C]
scalar Cp_;
//- Molecular-weight ratio of water vapour/dry air [-]
scalar epsilon_;
//- Height of grass layer [m]
scalar h_;
//- Von Karman constant [-]
scalar kappa_;
//- Reference velocity magnitude [m/s]
scalar uRef_;
//- Height of wind speed measurements [m]
scalar zRefU_;
//- Height of humidity measurements [m]
scalar zRefH_;
//- Roughness length governing momentum transfer coefficient [-]
scalar zom_;
//- Roughness length governing transfer of heat and vapour coeff [-]
scalar zoh_;
//- Zero plane displacement height coefficient [-]
scalar d_;
//- Bulk stomata resistance of leaf [s/m]
scalar ri_;
//- Atmospheric pressure [kPa]
scalar pAtm_;
//- Cached reference weather station air temperature [Celsius]
mutable scalar Tref_;
//- Name of temperature field
word TName_;
//- List of patches to calculate boundary heat flux
labelHashSet patchSet_;
// Private Member Functions
//- Return evapotranspiration heat flux through grass layer [W/m^2]
tmp<scalarField> E(const labelList& cells) const;
//- Return slope of the relation between
//- vapour pressure-temperature [Pa/K]
scalar Delta() const;
//- Return atmospheric vapour pressure deficit [Pa]
scalar D() const;
//- Return saturated vapour pressure over water [Pa]
scalar pSat() const;
//- Return psychrometric constant [kPa/K]
scalar gamma() const;
//- Return specific latent heat of vaporisation [MJ/kg]
scalar lambda() const;
//- Return bulk aerodynamic resistance [Pa]
scalar ra() const;
//- Return bulk surface resistance [Pa]
scalar rs() const;
//- Return area coverage of grass [m^2]
scalar S(const labelList& cells) const;
//- Return area-averaged heat flux through ground [W/m^2]
scalar G(const labelList& cells) const;
//- Return heat-flux boundary fields
tmp<FieldField<Field, scalar>> qBf() const;
public:
//- Runtime type information
TypeName("grass");
// Constructors
//- Construct from components
grass
(
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
grass(const grass&) = delete;
//- No copy assignment
void operator=(const grass&) = delete;
//- Destructor
virtual ~grass() = default;
// Member Functions
// Evaluation
//- Return heat-transfer rate for speficied cells [J/s]
virtual tmp<scalarField> Q(const labelList& cells) const;
// I-O
//- Read the dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace evapotranspirationHeatTransferModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "tree.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace evapotranspirationHeatTransferModels
{
defineTypeNameAndDebug(tree, 0);
addToRunTimeSelectionTable
(
evapotranspirationHeatTransferModel,
tree,
dictionary
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::scalar Foam::evapotranspirationHeatTransferModels::tree::Et() const
{
return a_*q() + b_;
}
Foam::tmp<Foam::scalarField>
Foam::evapotranspirationHeatTransferModels::tree::leafArea
(
const labelList& cells
) const
{
const volScalarField& LAD = getOrReadField(LADname_);
const scalarField& V = mesh().V();
auto tleafArea = tmp<scalarField>::New(cells.size(), Zero);
auto& leafArea = tleafArea.ref();
forAll(cells, i)
{
const label celli = cells[i];
leafArea[i] = LAD[celli]*V[celli];
}
return tleafArea;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::evapotranspirationHeatTransferModels::tree::tree
(
const dictionary& dict,
const fvMesh& mesh
)
:
evapotranspirationHeatTransferModel(dict, mesh),
a_(),
b_(),
lambda_(),
LADname_()
{
Info<< " Activating evapotranspiration heat transfer model: "
<< typeName << endl;
read(dict);
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp<Foam::scalarField>
Foam::evapotranspirationHeatTransferModels::tree::Q
(
const labelList& cells
) const
{
// Convert units from [MJ g/hr] to [J kg/s]
static const scalar unitConverter = scalar(1000)/scalar(3600);
return unitConverter*lambda_*Et()*leafArea(cells);
}
bool Foam::evapotranspirationHeatTransferModels::tree::read
(
const dictionary& dict
)
{
if (!evapotranspirationHeatTransferModel::read(dict))
{
return false;
}
const auto range = scalarMinMax::ge(SMALL);
a_ = dict.getOrDefault<scalar>("a", 0.3622);
b_ = dict.getOrDefault<scalar>("b", 60.758);
lambda_ = dict.getCheckOrDefault<scalar>("lambda", 2.44, range);
LADname_ = dict.getOrDefault<word>("LAD", "LAD");
(void) getOrReadField(LADname_);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::evapotranspirationHeatTransferModels::tree
Description
Applies sources on temperature (\c T - incompressible) or energy
(\c h/e - compressible) equation to incorporate evapotranspiration
heat-transfer effects from the specified tree canopy.
The heat-transfer is calculated based on the following relations.
The heat transfer is given by the first equation and the
evapotranspiration is calculated linearly proportional to absorbed
solar radiation (direct and diffusive) with the empirical relation
shown in the second equation below.
\f[
Q = \lambda E_t \frac{1000}{3600} \int_{cellZone} LAD \, dV
\f]
where
\vartable
Q | Heat transfer from tree crown [W]
\lambda | Specific latent heat of vaporisation [MJ/kg]
E_t | Area-averaged evapotranspiration [g/m^2/hr]
LAD | Leaf area density [m^2/m^3]
V | Volume [m^3]
\endvartable
with
\f[
E_t = a R_n + b
\f]
where
\vartable
R_n | Heat flux through tree crown [W/m^2]
a | Linear-regression coefficient - slope parameter [g/W/hr]
b | Linear-regression coefficient - intercept parameter [g/m^2/hr]
\endvartable
Sources applied to either of the below, if exist:
\verbatim
T | Temperature [K]
e | Internal energy [m^2/s^2]
h | Enthalphy [m^2/s^2]
\endverbatim
Required fields:
\verbatim
T | Temperature [K]
e | Internal energy [m^2/s^2]
h | Enthalphy [m^2/s^2]
LAD | Leaf area density [m^2/m^3]
\endverbatim
Usage
Example by using \c constant/fvOptions:
\verbatim
evapotranspirationHeatTransfer1
{
// Inherited entries
...
// Mandatory entries
model tree;
// Optional entries
a <scalar>;
b <scalar>;
lambda <scalar>;
LAD <word>;
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
model | Model name: tree | word | yes | -
a | Linear-regression coefficient - slope parameter [g/W/hr] | scalar <!--
--> | no | 0.3622
b | Linear-regression coefficient - intercept parameter [g/m^2/hr] <!--
--> | scalar | no | 60.758
lambda | Specific latent heat of vaporisation [MJ/kg] | scalar <!--
--> | no | 2.44
LAD | Name of leaf-area density field | word | no | LAD
\endtable
The inherited entries are elaborated in:
- \link evapotranspirationHeatTransfer.H \endlink
- \link evapotranspirationHeatTransferModel.H \endlink
SourceFiles
tree.C
treeTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_evapotranspirationHeatTransferModels_tree_H
#define Foam_evapotranspirationHeatTransferModels_tree_H
#include "evapotranspirationHeatTransferModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace evapotranspirationHeatTransferModels
{
/*---------------------------------------------------------------------------*\
Class tree Declaration
\*---------------------------------------------------------------------------*/
class tree
:
public evapotranspirationHeatTransferModel
{
// Private Data
//- Linear-regression coefficient - slope parameter [g/W/hr]
scalar a_;
//- Linear-regression coefficient - intercept parameter [g/m^2/hr]
scalar b_;
//- Specific latent heat of vaporisation [MJ/kg]
scalar lambda_;
//- Name of leaf-area density field
word LADname_;
// Private Member Functions
//- Return area-averaged transpiration [g/m^2/hr]
// Calculated from empirical regressions with heat flux
scalar Et() const;
//- Return volume weighted leaf area density (LAD) [m^2]
// LAD [m^2/m^3]: one-sided area of leaves per unit volume
tmp<scalarField> leafArea(const labelList& cells) const;
public:
//- Runtime type information
TypeName("tree");
// Constructors
//- Construct from components
tree
(
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
tree(const tree&) = delete;
//- No copy assignment
void operator=(const tree&) = delete;
//- Destructor
virtual ~tree() = default;
// Member Functions
// Evaluation
//- Return heat-transfer rate for speficied cells [J/s]
virtual tmp<scalarField> Q(const labelList& cells) const;
// I-O
//- Read the dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace evapotranspirationHeatTransferModels
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,234 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "treeTurbulence.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
defineTypeNameAndDebug(treeTurbulence, 0);
addToRunTimeSelectionTable(option, treeTurbulence, dictionary);
}
}
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
Foam::volScalarField& Foam::fv::treeTurbulence::getOrReadField
(
const word& fieldName
) const
{
auto* ptr = mesh_.getObjectPtr<volScalarField>(fieldName);
if (!ptr)
{
ptr = new volScalarField
(
IOobject
(
fieldName,
mesh_.time().timeName(),
mesh_,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh_
);
mesh_.objectRegistry::store(ptr);
}
return *ptr;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fv::treeTurbulence::treeTurbulence
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
)
:
fv::cellSetOption(sourceName, modelType, dict, mesh),
isEpsilon_(true),
betaP_(),
betaD_(),
Ceps1_(),
Ceps2_(),
betaStar_(),
CdName_(),
LADname_()
{
read(dict);
const auto* turbPtr = mesh_.findObject<turbulenceModel>
(
turbulenceModel::propertiesName
);
if (!turbPtr)
{
FatalErrorInFunction
<< "Unable to find a turbulence model."
<< abort(FatalError);
}
fieldNames_.resize(2);
tmp<volScalarField> tepsilon = turbPtr->epsilon();
tmp<volScalarField> tomega = turbPtr->omega();
if (!tepsilon.isTmp())
{
fieldNames_[0] = tepsilon().name();
}
else if (!tomega.isTmp())
{
isEpsilon_ = false;
fieldNames_[0] = tomega().name();
}
else
{
FatalErrorInFunction
<< "Unable to find epsilon or omega field." << nl
<< abort(FatalError);
}
fieldNames_[1] = turbPtr->k()().name();
fv::option::resetApplied();
Log << " Applying treeTurbulence to: "
<< fieldNames_[0] << " and " << fieldNames_[1]
<< endl;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::fv::treeTurbulence::addSup
(
fvScalarMatrix& eqn,
const label fieldi
)
{
if (fieldi == 1)
{
kSource(geometricOneField(), geometricOneField(), eqn, fieldi);
return;
}
if (isEpsilon_)
{
epsilonSource(geometricOneField(), geometricOneField(), eqn, fieldi);
}
else
{
omegaSource(geometricOneField(), geometricOneField(), eqn, fieldi);
}
}
void Foam::fv::treeTurbulence::addSup
(
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
)
{
if (fieldi == 1)
{
kSource(geometricOneField(), rho, eqn, fieldi);
return;
}
if (isEpsilon_)
{
epsilonSource(geometricOneField(), rho, eqn, fieldi);
}
else
{
omegaSource(geometricOneField(), rho, eqn, fieldi);
}
}
void Foam::fv::treeTurbulence::addSup
(
const volScalarField& alpha,
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
)
{
if (fieldi == 1)
{
kSource(alpha, rho, eqn, fieldi);
return;
}
if (isEpsilon_)
{
epsilonSource(alpha, rho, eqn, fieldi);
}
else
{
omegaSource(alpha, rho, eqn, fieldi);
}
}
bool Foam::fv::treeTurbulence::read(const dictionary& dict)
{
if (!fv::cellSetOption::read(dict))
{
return false;
}
betaP_ = dict.getOrDefault<scalar>("betaP", 1.0);
betaD_ = dict.getOrDefault<scalar>("betaD", 4.0);
Ceps1_ = dict.getOrDefault<scalar>("Ceps1", 0.9);
Ceps2_ = dict.getOrDefault<scalar>("Ceps2", 0.9);
betaStar_ = dict.getOrDefault<scalar>("betaStar", 0.09);
CdName_ = dict.getOrDefault<word>("Cd", "Cd");
LADname_ = dict.getOrDefault<word>("LAD", "LAD");
(void) getOrReadField(CdName_);
(void) getOrReadField(LADname_);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,262 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::fv::treeTurbulence
Group
grpFvOptionsSources
Description
Applies sources on \c k and either \c epsilon or \c omega
to incorporate effects of trees on atmospheric boundary layer.
Corrections applied to:
\verbatim
k | Turbulent kinetic energy [m^2/s^2]
\endverbatim
Corrections applied to either of the below, if exist:
\verbatim
epsilon | Turbulent kinetic energy dissipation rate [m^2/s^3]
omega | Specific dissipation rate [1/s]
\endverbatim
Required fields:
\verbatim
k | Turbulent kinetic energy [m^2/s^2]
Cd | Canopy drag coefficient [-]
LAD | Leaf area density [m^2/m^3]
epsilon | Turbulent kinetic energy dissipation rate [m^2/s^3]
omega | Specific dissipation rate [1/s]
\endverbatim
References:
\verbatim
Governing equations (tag:BSG):
Brozovsky, J., Simonsen, A., & Gaitani, N. (2021).
Validation of a CFD model for the evaluation of urban microclimate
at high latitudes: A case study in Trondheim, Norway.
Building and Environment, 205, 108175.
DOI:10.1016/j.buildenv.2021.108175
\endverbatim
Usage
Example by using \c constant/fvOptions:
\verbatim
treeTurbulence1
{
// Mandatory entries
type treeTurbulence;
// Optional entries
Cd <word>;
LAD <word>;
betaP <scalar>;
betaD <scalar>;
Ceps1 <scalar>;
Ceps2 <scalar>;
betaStar <scalar>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: treeTurbulence | word | yes | -
Cd | Name of operand canopy drag coefficient field | word | no | Cd
LAD | Name of operand leaf area density field | word | no | LAD
betaP | Model coefficient | scalar | no | 1.0
betaD | Model coefficient | scalar | no | 4.0
Ceps1 | Model coefficient | scalar | no | 0.9
Ceps2 | Model coefficient | scalar | no | 0.9
betaStar | Model coefficient | scalar | no | 0.09
\endtable
The inherited entries are elaborated in:
- \link fvOption.H \endlink
- \link cellSetOption.H \endlink
SourceFiles
treeTurbulence.C
treeTurbulenceTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef fv_treeTurbulence_H
#define fv_treeTurbulence_H
#include "cellSetOption.H"
#include "turbulentTransportModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
/*---------------------------------------------------------------------------*\
Class treeTurbulence Declaration
\*---------------------------------------------------------------------------*/
class treeTurbulence
:
public fv::cellSetOption
{
// Private Data
//- Internal flag to determine the working field is epsilon or omega
bool isEpsilon_;
// Model coefficients
scalar betaP_;
scalar betaD_;
scalar Ceps1_;
scalar Ceps2_;
scalar betaStar_;
//- Name of operand canopy drag coefficient field
word CdName_;
//- Name of operand leaf area density field
word LADname_;
// Private Member Functions
//- Return requested field from the object registry
//- or read+register the field to the object registry
volScalarField& getOrReadField(const word& fieldName) const;
//- Apply sources to turbulent kinetic energy
template<class AlphaFieldType, class RhoFieldType>
void kSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const;
//- Apply sources to turbulent kinetic energy dissipation rate
template<class AlphaFieldType, class RhoFieldType>
void epsilonSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const;
//- Apply sources to specific dissipation rate
template<class AlphaFieldType, class RhoFieldType>
void omegaSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const;
public:
//- Runtime type information
TypeName("treeTurbulence");
// Constructors
//- Construct from explicit source name and mesh
treeTurbulence
(
const word& sourceName,
const word& modelType,
const dictionary& dict,
const fvMesh& mesh
);
//- No copy construct
treeTurbulence(const treeTurbulence&) = delete;
//- No copy assignment
void operator=(const treeTurbulence&) = delete;
// Member Functions
//- Add explicit contribution to epsilon or omega equation
//- for incompressible flow computations
virtual void addSup
(
fvScalarMatrix& eqn,
const label fieldi
);
//- Add explicit contribution to epsilon or omega equation
//- for compressible flow computations
virtual void addSup
(
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
);
//- Add explicit contribution to epsilon or omega equation
//- for multiphase flow computations
virtual void addSup
(
const volScalarField& alpha,
const volScalarField& rho,
fvScalarMatrix& eqn,
const label fieldi
);
//- Read source dictionary
virtual bool read(const dictionary& dict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "treeTurbulenceTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "treeTurbulence.H"
#include "volFields.H"
#include "fvmSup.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class AlphaFieldType, class RhoFieldType>
void Foam::fv::treeTurbulence::kSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const
{
const auto* turbPtr = mesh_.findObject<turbulenceModel>
(
turbulenceModel::propertiesName
);
const volScalarField& k = turbPtr->k();
const volVectorField& U = turbPtr->U();
const volScalarField magU(mag(U));
const volScalarField& Cd = getOrReadField(CdName_);
const volScalarField& LAD = getOrReadField(LADname_);
// (BSG:Eq. 8)
eqn +=
alpha*rho*LAD*Cd*betaP_*pow3(magU)
- fvm::Sp(alpha*rho*LAD*Cd*betaD_*magU, k);
}
template<class AlphaFieldType, class RhoFieldType>
void Foam::fv::treeTurbulence::epsilonSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const
{
const auto* turbPtr = mesh_.findObject<turbulenceModel>
(
turbulenceModel::propertiesName
);
const volScalarField& epsilon = turbPtr->epsilon();
const volScalarField& k = turbPtr->k();
const volVectorField& U = turbPtr->U();
const volScalarField magU(mag(U));
const volScalarField& Cd = getOrReadField(CdName_);
const volScalarField& LAD = getOrReadField(LADname_);
// (BSG:Eq. 9)
eqn +=
fvm::Sp
(
alpha*rho*LAD*Cd*(Ceps1_*betaP_/k*pow3(magU) - Ceps2_*betaD_*magU),
epsilon
);
}
template<class AlphaFieldType, class RhoFieldType>
void Foam::fv::treeTurbulence::omegaSource
(
const AlphaFieldType& alpha,
const RhoFieldType& rho,
fvScalarMatrix& eqn,
const label fieldi
) const
{
const auto* turbPtr = mesh_.findObject<turbulenceModel>
(
turbulenceModel::propertiesName
);
const volScalarField& omega = turbPtr->omega();
const volScalarField& k = turbPtr->k();
const volVectorField& U = turbPtr->U();
const volScalarField magU(mag(U));
const volScalarField& Cd = getOrReadField(CdName_);
const volScalarField& LAD = getOrReadField(LADname_);
// (derived from BSG:Eq. 9 by assuming epsilon = betaStar*omega*k)
eqn +=
fvm::Sp
(
alpha*rho*LAD*Cd*betaStar_
*(Ceps1_*betaP_*pow3(magU) - Ceps2_*betaD_*k*magU),
omega
);
}
// ************************************************************************* //

View File

@ -109,19 +109,6 @@ motionSolvers/displacement/solidBody/solidBodyMotionSolver.C
motionSolvers/displacement/solidBody/multiSolidBodyMotionSolver.C
motionSolvers/displacement/codedPoints0/codedPoints0MotionSolver.C
solidBodyMotionFunctions = motionSolvers/displacement/solidBody/solidBodyMotionFunctions
$(solidBodyMotionFunctions)/solidBodyMotionFunction/solidBodyMotionFunction.C
$(solidBodyMotionFunctions)/solidBodyMotionFunction/solidBodyMotionFunctionNew.C
$(solidBodyMotionFunctions)/SDA/SDA.C
$(solidBodyMotionFunctions)/tabulated6DoFMotion/tabulated6DoFMotion.C
$(solidBodyMotionFunctions)/linearMotion/linearMotion.C
$(solidBodyMotionFunctions)/drivenLinearMotion/drivenLinearMotion.C
$(solidBodyMotionFunctions)/rotatingMotion/rotatingMotion.C
$(solidBodyMotionFunctions)/axisRotationMotion/axisRotationMotion.C
$(solidBodyMotionFunctions)/multiMotion/multiMotion.C
$(solidBodyMotionFunctions)/oscillatingLinearMotion/oscillatingLinearMotion.C
$(solidBodyMotionFunctions)/oscillatingRotatingMotion/oscillatingRotatingMotion.C
motionSolvers/displacement/solidBody/pointPatchFields/derived/solidBodyMotionDisplacement/solidBodyMotionDisplacementPointPatchVectorField.C
createShellMesh/createShellMesh.C

View File

@ -2817,7 +2817,7 @@ void Foam::polyMeshAdder::add
if (newNei < newOwn)
{
std::swap(newOwn, newNei);
newFace = newFace.reverseFace();
newFace.flip();
flipFaceFlux = !flipFaceFlux;
for (bool& flip : flips)
{

View File

@ -109,7 +109,21 @@ Foam::cyclicACMIFvPatchField<Type>::cyclicACMIFvPatchField
<< exit(FatalIOError);
}
// Tricky: avoid call to evaluate without call to initEvaluate.
// For now just disable the localConsistency to make it use the
// old logic (ultimately calls the fully self contained
// patchNeighbourField)
int& consistency =
GeometricField<Type, fvPatchField, volMesh>::
Boundary::localConsistency;
const int oldConsistency = consistency;
consistency = 0;
this->evaluate(Pstream::commsTypes::blocking);
consistency = oldConsistency;
}
}

View File

@ -44,7 +44,6 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
cyclicAMILduInterfaceField(),
coupledFvPatchField<Type>(p, iF),
cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
lowWeightOption_(lowWeightCorrectionBase::option::ASSIGN),
patchNeighbourFieldPtr_(nullptr)
{}
@ -60,15 +59,6 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
cyclicAMILduInterfaceField(),
coupledFvPatchField<Type>(p, iF, dict, IOobjectOption::NO_READ),
cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p, dict)),
lowWeightOption_
(
lowWeightCorrectionBase::optionNames_.getOrDefault
(
"lowWeightOption",
dict,
lowWeightCorrectionBase::option::ASSIGN
)
),
patchNeighbourFieldPtr_(nullptr)
{
if (!isA<cyclicAMIFvPatch>(p))
@ -102,7 +92,21 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
{
if (this->coupled())
{
// Tricky: avoid call to evaluate without call to initEvaluate.
// For now just disable the localConsistency to make it use the
// old logic (ultimately calls the fully self contained
// patchNeighbourField)
int& consistency =
GeometricField<Type, fvPatchField, volMesh>::
Boundary::localConsistency;
const int oldConsistency = consistency;
consistency = 0;
this->evaluate(UPstream::commsTypes::nonBlocking);
consistency = oldConsistency;
}
else
{
@ -124,7 +128,6 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
cyclicAMILduInterfaceField(),
coupledFvPatchField<Type>(ptf, p, iF, mapper),
cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
lowWeightOption_(ptf.lowWeightOption_),
patchNeighbourFieldPtr_(nullptr)
{
//if (ptf.patchNeighbourFieldPtr_ && cacheNeighbourField())
@ -163,7 +166,6 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
cyclicAMILduInterfaceField(),
coupledFvPatchField<Type>(ptf),
cyclicAMIPatch_(ptf.cyclicAMIPatch_),
lowWeightOption_(ptf.lowWeightOption_),
patchNeighbourFieldPtr_(nullptr)
{
if (debug && !ptf.all_ready())
@ -185,7 +187,6 @@ Foam::cyclicAMIFvPatchField<Type>::cyclicAMIFvPatchField
cyclicAMILduInterfaceField(),
coupledFvPatchField<Type>(ptf, iF),
cyclicAMIPatch_(ptf.cyclicAMIPatch_),
lowWeightOption_(ptf.lowWeightOption_),
patchNeighbourFieldPtr_(nullptr)
{
if (debug && !ptf.all_ready())
@ -311,8 +312,7 @@ Foam::cyclicAMIFvPatchField<Type>::patchNeighbourField
defaultValues = Field<Type>(iField, cyclicAMIPatch_.faceCells());
}
tmp<Field<Type>> tpnf =
cyclicAMIPatch_.interpolate(pnf, defaultValues, lowWeightOption_);
tmp<Field<Type>> tpnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
if (doTransform())
{
@ -540,8 +540,7 @@ void Foam::cyclicAMIFvPatchField<Type>::evaluate
Field<Type>::null(), // Not used for distributed
recvRequests_,
recvBufs_,
defaultValues,
lowWeightOption_
defaultValues
).ptr()
);
@ -667,8 +666,7 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
solveScalarField::null(), // Not used for distributed
recvRequests_,
scalarRecvBufs_,
defaultValues,
lowWeightOption_
defaultValues
);
// Receive requests all handled by last function call
@ -690,7 +688,7 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
// Transform according to the transformation tensors
transformCoupleField(pnf, cmpt);
pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues, lowWeightOption_);
pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
}
// Multiply the field by coefficients and add into the result
@ -802,8 +800,7 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
Field<Type>::null(), // Not used for distributed
recvRequests_,
recvBufs_,
defaultValues,
lowWeightOption_
defaultValues
);
// Receive requests all handled by last function call
@ -825,7 +822,7 @@ void Foam::cyclicAMIFvPatchField<Type>::updateInterfaceMatrix
defaultValues = Field<Type>(psiInternal, faceCells);
}
pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues, lowWeightOption_);
pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
}
// Multiply the field by coefficients and add into the result
@ -1011,12 +1008,6 @@ void Foam::cyclicAMIFvPatchField<Type>::write(Ostream& os) const
{
patchNeighbourFieldPtr_->writeEntry("neighbourValue", os);
}
os.writeEntry
(
"lowWeightOption",
lowWeightCorrectionBase::optionNames_[lowWeightOption_]
);
}

View File

@ -71,7 +71,6 @@ SourceFiles
#include "cyclicAMIFvPatch.H"
#include "coupledFvPatchField.H"
#include "cyclicAMILduInterfaceField.H"
#include "lowWeightCorrectionBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -93,10 +92,6 @@ class cyclicAMIFvPatchField
//- Local reference cast into the cyclic patch
const cyclicAMIFvPatch& cyclicAMIPatch_;
//- Low weight correction mode
// Default: assign (same as v2312 and earlier)
lowWeightCorrectionBase::option lowWeightOption_;
// Sending and receiving (distributed AMI)

View File

@ -29,7 +29,6 @@ License
#include "addToRunTimeSelectionTable.H"
#include "faceAreaWeightAMI.H"
#include "turbulentDFSEMInletFvPatchVectorField.H"
#include "AMIFieldOps.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -83,8 +82,14 @@ void Foam::turbulentDigitalFilterInletFvPatchField<Type>::mapL
}
// Map two-point correlations (integral scales)
AMIMultiplyWeightedOp<Type> cop(AMIPtr_(), true);
AMIPtr_->interpolate(sourceFld, cop, fld, UList<Type>::null());
plusEqOp<Type> cop;
AMIPtr_->interpolateToSource
(
sourceFld,
multiplyWeightedOp<Type, plusEqOp<Type>>(cop),
fld,
UList<Type>::null()
);
// Map forward-stepwise method correlations if requested
if (L_.fsm())

View File

@ -100,19 +100,12 @@ void Foam::cyclicACMIFvPatch::makeWeights(scalarField& w) const
// These deltas are of the cyclic part alone - they are
// not affected by the amount of overlap with the nonOverlapPatch
scalarField nbrDeltas;
const auto& AMI = owner() ? this->AMI() : nbrPatch.AMI();
// Multiply-weighted op - no low weight correction
auto cop = AMIMultiplyWeightedOp<scalar>(AMI, owner());
AMI.interpolate
scalarField nbrDeltas
(
(nbrPatch.nf() & nbrPatch.coupledFvPatch::delta())(),
cop,
nbrDeltas,
UList<scalar>()
interpolate
(
nbrPatch.nf() & nbrPatch.coupledFvPatch::delta()
)
);
const scalar tol = cyclicACMIPolyPatch::tolerance();
@ -251,35 +244,31 @@ Foam::tmp<Foam::vectorField> Foam::cyclicACMIFvPatch::delta() const
const vectorField patchD(coupledFvPatch::delta());
const auto& AMI = owner() ? this->AMI() : nbrPatch.AMI();
// Multiply-weighted op - no low weight correction
auto cop = AMIMultiplyWeightedOp<vector>(AMI, owner());
vectorField nbrPatchD;
AMI.interpolate
(
nbrPatch.coupledFvPatch::delta()(),
cop,
nbrPatchD,
UList<vector>()
);
// Do the transformation if necessary
if (!parallel())
{
transform(nbrPatchD, forwardT()[0], nbrPatchD);
}
vectorField nbrPatchD(interpolate(nbrPatch.coupledFvPatch::delta()));
auto tpdv = tmp<vectorField>::New(patchD.size());
vectorField& pdv = tpdv.ref();
forAll(patchD, facei)
// do the transformation if necessary
if (parallel())
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - dni;
pdv[facei] = ddi - dni;
forAll(patchD, facei)
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - dni;
}
}
else
{
forAll(patchD, facei)
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - transform(forwardT()[0], dni);
}
}
return tpdv;

View File

@ -251,7 +251,7 @@ public:
localFld,
requests,
recvBuffers,
UList<Type>::null()
UList<Type>()
);
}

View File

@ -97,50 +97,32 @@ void Foam::cyclicAMIFvPatch::makeWeights(scalarField& w) const
{
const cyclicAMIFvPatch& nbrPatch = neighbFvPatch();
const auto& AMI = owner() ? this->AMI() : nbrPatch.AMI();
const scalarField deltas(nf() & coupledFvPatch::delta());
auto tnbrDeltas = tmp<scalarField>::New();
tmp<scalarField> tnbrDeltas;
if (applyLowWeightCorrection())
{
// Use 'assign' correction for geometric interpolation
auto cop = AMICorrectedMultiplyWeightedOp<scalar>
(
AMI,
owner(),
lowWeightCorrectionBase::option::ASSIGN
);
// Faces with invalid interpolation weights converted to one-sided
AMI.interpolate
(
(nbrPatch.nf() & nbrPatch.coupledFvPatch::delta())(),
cop,
tnbrDeltas.ref(),
scalarList(this->size(), 1.0)
);
tnbrDeltas =
interpolate
(
nbrPatch.nf() & nbrPatch.coupledFvPatch::delta(),
scalarField(this->size(), 1.0)
);
}
else
{
// Multiply-weighted op - no low weight correction
auto cop = AMIMultiplyWeightedOp<scalar>(AMI, owner());
AMI.interpolate
(
(nbrPatch.nf() & nbrPatch.coupledFvPatch::delta())(),
cop,
tnbrDeltas.ref(),
UList<scalar>::null()
);
tnbrDeltas =
interpolate(nbrPatch.nf() & nbrPatch.coupledFvPatch::delta());
}
const scalarField& nbrDeltas = tnbrDeltas();
const scalarField deltas(nf() & coupledFvPatch::delta());
forAll(deltas, facei)
{
// Note use of mag
scalar di = mag(deltas[facei]);
scalar dni = mag(nbrDeltas[facei]);
w[facei] = dni/(di + dni);
}
}
@ -180,58 +162,46 @@ Foam::tmp<Foam::vectorField> Foam::cyclicAMIFvPatch::delta() const
{
const vectorField patchD(coupledFvPatch::delta());
const auto& AMI = owner() ? this->AMI() : nbrPatch.AMI();
auto tnbrPatchD = tmp<vectorField>::New();
tmp<vectorField> tnbrPatchD;
if (applyLowWeightCorrection())
{
// Use 'assign' correction for geometric interpolation
auto cop = AMICorrectedMultiplyWeightedOp<vector>
(
AMI,
owner(),
lowWeightCorrectionBase::option::ASSIGN
);
// Faces with invalid interpolation weights converted to one-sided
AMI.interpolate
(
nbrPatch.coupledFvPatch::delta()(),
cop,
tnbrPatchD.ref(),
vectorField(this->size(), Zero)
);
tnbrPatchD =
interpolate
(
nbrPatch.coupledFvPatch::delta(),
vectorField(this->size(), Zero)
);
}
else
{
// Multiply-weighted op - no low weight correction
auto cop = AMIMultiplyWeightedOp<vector>(AMI, owner());
AMI.interpolate
(
nbrPatch.coupledFvPatch::delta()(),
cop,
tnbrPatchD.ref(),
UList<vector>::null()
);
tnbrPatchD = interpolate(nbrPatch.coupledFvPatch::delta());
}
vectorField& nbrPatchD = tnbrPatchD.ref();
// Do the transformation if necessary
if (!parallel())
{
transform(nbrPatchD, forwardT()[0], nbrPatchD);
}
const vectorField& nbrPatchD = tnbrPatchD();
auto tpdv = tmp<vectorField>::New(patchD.size());
vectorField& pdv = tpdv.ref();
forAll(patchD, facei)
// do the transformation if necessary
if (parallel())
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - dni;
forAll(patchD, facei)
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - dni;
}
}
else
{
forAll(patchD, facei)
{
const vector& ddi = patchD[facei];
const vector& dni = nbrPatchD[facei];
pdv[facei] = ddi - transform(forwardT()[0], dni);
}
}
return tpdv;

View File

@ -217,34 +217,20 @@ public:
tmp<Field<Type>> interpolate
(
const Field<Type>& fld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>()
) const
{
return cyclicAMIPolyPatch_.interpolate
(
fld,
defaultValues,
lwOption
);
return cyclicAMIPolyPatch_.interpolate(fld, defaultValues);
}
template<class Type>
tmp<Field<Type>> interpolate
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>()
) const
{
return cyclicAMIPolyPatch_.interpolate
(
tFld,
defaultValues,
lwOption
);
return cyclicAMIPolyPatch_.interpolate(tFld, defaultValues);
}

View File

@ -1,114 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::AMIFieldOP
Description
General template for AMI field operations
\*---------------------------------------------------------------------------*/
#ifndef AMIFieldOp_H
#define AMIFieldOp_H
#include "AMIFieldOpBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class AMIFieldOp Declaration
\*---------------------------------------------------------------------------*/
template<class Type, class CombineOp>
class AMIFieldOp
:
public AMIFieldOpBase
{
// Private Data
//- Combine operator, e.g. plusEqOp<Type>()
// Note: must be null-constructed
CombineOp cop_;
public:
typedef Type value_type;
//- Constructor
AMIFieldOp(const AMIInterpolation& ami, bool toSource)
:
AMIFieldOpBase(ami, toSource),
cop_()
{}
//- Destructor
~AMIFieldOp() = default;
//- Apply the op
// Note: does not use default values
void operator()
(
List<value_type>& result,
const UList<value_type>& fld,
const UList<value_type>& /* unused defaultValues */
) const
{
const auto& address = this->address();
forAll(result, facei)
{
const labelList& faceSlots = address[facei];
forAll(faceSlots, i)
{
if (i == 0)
{
result[facei] = fld[faceSlots[i]];
}
else
{
cop_(result[facei], fld[faceSlots[i]]);
}
}
}
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,105 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::AMIFieldOpBase
Description
Base class for AMI field operations
\*---------------------------------------------------------------------------*/
#ifndef AMIFieldOpsBase_H
#define AMIFieldOpsBase_H
#include "AMIInterpolation.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class AMIFieldOpBase Declaration
\*---------------------------------------------------------------------------*/
class AMIFieldOpBase
{
protected:
//- Reference to the AMI
const AMIInterpolation& ami_;
//- Interpolation to source; false=interpolate to target
const bool toSource_;
public:
//- Constructor
AMIFieldOpBase(const AMIInterpolation& ami, const bool toSource)
:
ami_(ami),
toSource_(toSource)
{}
// Member Functions
//- Return the 'toSource' flag
bool toSource() const
{
return toSource_;
}
//- Return the AMI addressing
const labelListList& address() const
{
return toSource_ ? ami_.srcAddress() : ami_.tgtAddress();
}
//- Return the AMI weights
const scalarListList& weights() const
{
return toSource_ ? ami_.srcWeights() : ami_.tgtWeights();
}
//- Return the AMI sum of weights
const scalarList& weightsSum() const
{
return toSource_ ? ami_.srcWeightsSum() : ami_.tgtWeightsSum();
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,112 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef AMIMultiplyWeightedOp_H
#define AMIMultiplyWeightedOp_H
#include "AMIFieldOpBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class AMIMultiplyWeightedOp Declaration
\*---------------------------------------------------------------------------*/
template<class Type, class CombineOp = plusEqOp<Type>>
class AMIMultiplyWeightedOp
:
public AMIFieldOpBase
{
// Private Data
//- Combine operator, e.g. plusEqOp<Type>()
// Note: must be null-constructed
CombineOp cop_;
public:
typedef Type value_type;
//- Constructor
AMIMultiplyWeightedOp
(
const AMIInterpolation& ami,
const bool toSource
)
:
AMIFieldOpBase(ami, toSource),
cop_()
{}
//- Multiply-weighted op
// Note: does not use default values
void operator()
(
List<value_type>& result,
const UList<value_type>& fld,
const UList<value_type>& /* unused defaultValues */
) const
{
const auto& address = this->address();
const auto& weights = this->weights();
forAll(result, facei)
{
const labelList& faceSlots = address[facei];
const scalarList& faceWeights = weights[facei];
forAll(faceSlots, i)
{
if (i == 0)
{
result[facei] = faceWeights[i]*fld[faceSlots[i]];
}
else
{
cop_(result[facei], faceWeights[i]*fld[faceSlots[i]]);
}
}
}
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,176 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::LowWeightCorrection
Description
Wrapper around the AMI field op
\*---------------------------------------------------------------------------*/
#ifndef LowWeightCorrection_H
#define LowWeightCorrection_H
#include "lowWeightCorrectionBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class LowWeightCorrection Declaration
\*---------------------------------------------------------------------------*/
template<class AMIOpType, class CombineOp>
class LowWeightCorrection
:
public lowWeightCorrectionBase,
public AMIOpType
{
typedef typename AMIOpType::value_type value_type;
public:
//- Constructor
LowWeightCorrection
(
const AMIInterpolation& ami,
const bool toSource,
const lowWeightCorrectionBase::option& opt =
lowWeightCorrectionBase::option::NONE
)
:
lowWeightCorrectionBase(opt),
AMIOpType(ami, toSource)
{}
// Member Functions
//- Helper function to ensure default value field is valid
bool validDefaults(const UList<value_type>& defaultValues) const
{
const auto& ami = AMIOpType::ami_;
if (ami.lowWeightCorrection() > 0)
{
const auto& weightsSum = this->weightsSum();
if (defaultValues.size() != weightsSum.size())
{
FatalErrorInFunction
<< "Employing default values when sum of weights "
<< "falls below " << ami.lowWeightCorrection()
<< " but number of default values is not equal to "
<< "addressing size" << nl
<< " default values size = "
<< defaultValues.size() << nl
<< " addressing size = "
<< weightsSum.size() << nl
<< abort(FatalError);
}
return true;
}
return false;
}
//- Correction operator
void operator()
(
List<value_type>& result,
const UList<value_type>& fld,
const UList<value_type>& defaultValues
) const
{
// Apply AMI interpolator
AMIOpType::operator()(result, fld, UList<value_type>::null());
if (!validDefaults(defaultValues)) return;
switch (opt_)
{
case option::NONE:
{
break;
}
case option::ASSIGN:
{
const auto& ami = AMIOpType::ami_;
const auto& weightsSum = this->weightsSum();
forAll(result, facei)
{
if (weightsSum[facei] < ami.lowWeightCorrection())
{
// Assign default value
result[facei] = defaultValues[facei];
}
}
break;
}
case option::BLEND:
{
const auto& ami = AMIOpType::ami_;
const auto& weightsSum = this->weightsSum();
forAll(result, facei)
{
if (weightsSum[facei] < ami.lowWeightCorrection())
{
// Already have 'weightSum' contribution in result
// - blend 'missing' contribution into result
const scalar w = min(1, max(0, weightsSum[facei]));
result[facei] += (1 - w)*defaultValues[facei];
}
}
break;
}
default:
{
FatalErrorInFunction
<< "Unhandled enumeration " << static_cast<int>(opt_)
<< abort(FatalError);
}
}
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,49 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "lowWeightCorrectionBase.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::Enum<Foam::lowWeightCorrectionBase::option>
Foam::lowWeightCorrectionBase::optionNames_
({
{ option::NONE, "none" },
{ option::ASSIGN, "assign" },
{ option::BLEND, "blend" },
});
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::lowWeightCorrectionBase::lowWeightCorrectionBase(const option& opt)
:
opt_(opt)
{}
// ************************************************************************* //

View File

@ -1,90 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::lowWeightCorrectionBase
Description
Base class for AMI low weight corrections
\*---------------------------------------------------------------------------*/
#ifndef lowWeightCorrectionBase_H
#define lowWeightCorrectionBase_H
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class lowWeightCorrectionBase Declaration
\*---------------------------------------------------------------------------*/
class lowWeightCorrectionBase
{
public:
enum class option
{
NONE,
ASSIGN,
BLEND
};
static const Enum<option> optionNames_;
protected:
// Protected Data
//- Option
option opt_;
public:
//- Constructors
lowWeightCorrectionBase(const option& opt = option::NONE);
//- Destructor
~lowWeightCorrectionBase() = default;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1123,36 +1123,6 @@ void Foam::AMIInterpolation::normaliseWeights
}
void Foam::AMIInterpolation::removeSourceConnection(const label facei)
{
if (facei < 0 || facei > srcAddress_.size())
{
FatalErrorInFunction
<< "Face index " << facei << " out of bonds"
<< abort(FatalError);
}
srcWeightsSum_[facei] = 0;
srcWeights_[facei].clear();
srcAddress_[facei].clear();
}
void Foam::AMIInterpolation::removeTargetConnection(const label facei)
{
if (facei < 0 || facei > tgtAddress_.size())
{
FatalErrorInFunction
<< "Face index " << facei << " out of bonds"
<< abort(FatalError);
}
tgtWeightsSum_[facei] = 0;
tgtWeights_[facei].clear();
tgtAddress_[facei].clear();
}
Foam::label Foam::AMIInterpolation::srcPointFace
(
const primitivePatch& srcPatch,

View File

@ -61,7 +61,7 @@ SourceFiles
#include "indexedOctree.H"
#include "treeDataPrimitivePatch.H"
#include "runTimeSelectionTables.H"
#include "lowWeightCorrectionBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -512,21 +512,39 @@ public:
//- Normalise the weights
void normaliseWeights(const bool conformal, const bool output);
//- Remove source face connection
void removeSourceConnection(const label facei);
//- Remove target face connection
void removeTargetConnection(const label facei);
// Evaluation
// Low-level
//- Interpolate with supplied op to combine existing value
//- with remote value and weight
//- Weighted sum of contributions
template<class Type, class CombineOp>
void interpolate
static void weightedSum
(
const scalar lowWeightCorrection,
const labelListList& allSlots,
const scalarListList& allWeights,
const scalarField& weightsSum,
const UList<Type>& fld,
const CombineOp& cop,
List<Type>& result,
const UList<Type>& defaultValues
);
//- Weighted sum of contributions
template<class Type>
void weightedSum
(
const bool interpolateToSource,
const UList<Type>& fld,
List<Type>& result,
const UList<Type>& defaultValues
) const;
//- Interpolate from target to source with supplied op
//- to combine existing value with remote value and weight
template<class Type, class CombineOp>
void interpolateToSource
(
const UList<Type>& fld,
const CombineOp& cop,
@ -534,18 +552,48 @@ public:
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate with supplied op
//- Interpolate from source to target with supplied op
//- to combine existing value with remote value and weight
template<class Type, class CombineOp>
void interpolateToTarget
(
const UList<Type>& fld,
const CombineOp& cop,
List<Type>& result,
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from target to source with supplied op
template<class Type, class CombineOp>
tmp<Field<Type>> interpolate
tmp<Field<Type>> interpolateToSource
(
const Field<Type>& fld,
const CombineOp& cop,
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate with supplied op
//- Interpolate from target tmp field to source with supplied op
template<class Type, class CombineOp>
tmp<Field<Type>> interpolate
tmp<Field<Type>> interpolateToSource
(
const tmp<Field<Type>>& tFld,
const CombineOp& cop,
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from source to target with supplied op
template<class Type, class CombineOp>
tmp<Field<Type>> interpolateToTarget
(
const Field<Type>& fld,
const CombineOp& cop,
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from source tmp field to target with supplied op
template<class Type, class CombineOp>
tmp<Field<Type>> interpolateToTarget
(
const tmp<Field<Type>>& tFld,
const CombineOp& cop,
@ -557,9 +605,7 @@ public:
tmp<Field<Type>> interpolateToSource
(
const Field<Type>& fld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from target tmp field
@ -567,9 +613,7 @@ public:
tmp<Field<Type>> interpolateToSource
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from source to target
@ -577,9 +621,7 @@ public:
tmp<Field<Type>> interpolateToTarget
(
const Field<Type>& fld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>::null()
) const;
//- Interpolate from source tmp field
@ -587,9 +629,7 @@ public:
tmp<Field<Type>> interpolateToTarget
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues = UList<Type>::null(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>::null()
) const;

View File

@ -28,12 +28,83 @@ License
#include "profiling.H"
#include "mapDistribute.H"
#include "AMIFieldOps.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type, class CombineOp>
void Foam::AMIInterpolation::interpolate
void Foam::AMIInterpolation::weightedSum
(
const scalar lowWeightCorrection,
const labelListList& allSlots,
const scalarListList& allWeights,
const scalarField& weightsSum,
const UList<Type>& fld,
const CombineOp& cop,
List<Type>& result,
const UList<Type>& defaultValues
)
{
if (lowWeightCorrection > 0)
{
forAll(result, facei)
{
if (weightsSum[facei] < lowWeightCorrection)
{
result[facei] = defaultValues[facei];
}
else
{
const labelList& slots = allSlots[facei];
const scalarList& weights = allWeights[facei];
forAll(slots, i)
{
cop(result[facei], facei, fld[slots[i]], weights[i]);
}
}
}
}
else
{
forAll(result, facei)
{
const labelList& slots = allSlots[facei];
const scalarList& weights = allWeights[facei];
forAll(slots, i)
{
cop(result[facei], facei, fld[slots[i]], weights[i]);
}
}
}
}
template<class Type>
void Foam::AMIInterpolation::weightedSum
(
const bool interpolateToSource,
const UList<Type>& fld,
List<Type>& result,
const UList<Type>& defaultValues
) const
{
weightedSum
(
lowWeightCorrection_,
(interpolateToSource ? srcAddress_ : tgtAddress_),
(interpolateToSource ? srcWeights_ : tgtWeights_),
(interpolateToSource ? srcWeightsSum_ : tgtWeightsSum_),
fld,
multiplyWeightedOp<Type, plusEqOp<Type>>(plusEqOp<Type>()),
result,
defaultValues
);
}
template<class Type, class CombineOp>
void Foam::AMIInterpolation::interpolateToTarget
(
const UList<Type>& fld,
const CombineOp& cop,
@ -41,67 +112,182 @@ void Foam::AMIInterpolation::interpolate
const UList<Type>& defaultValues
) const
{
addProfiling(ami, "AMIInterpolation::interpolate");
addProfiling(ami, "AMIInterpolation::interpolateToTarget");
label inSize = cop.toSource() ? tgtAddress_.size() : srcAddress_.size();
if (fld.size() != inSize)
if (fld.size() != srcAddress_.size())
{
FatalErrorInFunction
<< "Supplied field size is not equal to expected field size ("
<< inSize << ")" << nl
<< "Supplied field size is not equal to source patch size" << nl
<< " source patch = " << srcAddress_.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< " supplied field = " << fld.size()
<< abort(FatalError);
}
else if
(
(lowWeightCorrection_ > 0)
&& (defaultValues.size() != tgtAddress_.size())
)
{
FatalErrorInFunction
<< "Employing default values when sum of weights falls below "
<< lowWeightCorrection_
<< " but supplied default field size is not equal to target "
<< "patch size" << nl
<< " default values = " << defaultValues.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< abort(FatalError);
}
label outSize = cop.toSource() ? srcAddress_.size() : tgtAddress_.size();
result.resize_nocopy(outSize);
result.setSize(tgtAddress_.size());
List<Type> work;
if (distributed())
{
const auto& map = cop.toSource() ? tgtMapPtr_() : srcMapPtr_();
List<Type> work = fld; // deep copy
const mapDistribute& map = srcMapPtr_();
work = fld; // deep copy
map.distribute(work);
}
// Apply interpolation
cop(result, work, defaultValues);
}
else
{
// Apply interpolation
cop(result, fld, defaultValues);
}
weightedSum
(
lowWeightCorrection_,
tgtAddress_,
tgtWeights_,
tgtWeightsSum_,
(distributed() ? work : fld),
cop,
result,
defaultValues
);
}
template<class Type, class CombineOp>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolate
void Foam::AMIInterpolation::interpolateToSource
(
const UList<Type>& fld,
const CombineOp& cop,
List<Type>& result,
const UList<Type>& defaultValues
) const
{
addProfiling(ami, "AMIInterpolation::interpolateToSource");
if (fld.size() != tgtAddress_.size())
{
FatalErrorInFunction
<< "Supplied field size is not equal to target patch size" << nl
<< " source patch = " << srcAddress_.size() << nl
<< " target patch = " << tgtAddress_.size() << nl
<< " supplied field = " << fld.size()
<< abort(FatalError);
}
else if
(
(lowWeightCorrection_ > 0)
&& (defaultValues.size() != srcAddress_.size())
)
{
FatalErrorInFunction
<< "Employing default values when sum of weights falls below "
<< lowWeightCorrection_
<< " but number of default values is not equal to source "
<< "patch size" << nl
<< " default values = " << defaultValues.size() << nl
<< " source patch = " << srcAddress_.size() << nl
<< abort(FatalError);
}
result.setSize(srcAddress_.size());
List<Type> work;
if (distributed())
{
const mapDistribute& map = tgtMapPtr_();
work = fld; // deep copy
map.distribute(work);
}
weightedSum
(
lowWeightCorrection_,
srcAddress_,
srcWeights_,
srcWeightsSum_,
(distributed() ? work : fld),
cop,
result,
defaultValues
);
}
template<class Type, class CombineOp>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource
(
const Field<Type>& fld,
const CombineOp& cop,
const UList<Type>& defaultValues
) const
{
auto tresult = tmp<Field<Type>>::New();
auto tresult = tmp<Field<Type>>::New(srcAddress_.size(), Zero);
interpolate(fld, cop, tresult.ref(), defaultValues);
interpolateToSource
(
fld,
multiplyWeightedOp<Type, CombineOp>(cop),
tresult.ref(),
defaultValues
);
return tresult;
}
template<class Type, class CombineOp>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolate
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource
(
const tmp<Field<Type>>& tFld,
const CombineOp& cop,
const UList<Type>& defaultValues
) const
{
return interpolate(tFld(), cop, defaultValues);
return interpolateToSource(tFld(), cop, defaultValues);
}
template<class Type, class CombineOp>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget
(
const Field<Type>& fld,
const CombineOp& cop,
const UList<Type>& defaultValues
) const
{
auto tresult = tmp<Field<Type>>::New(tgtAddress_.size(), Zero);
interpolateToTarget
(
fld,
multiplyWeightedOp<Type, CombineOp>(cop),
tresult.ref(),
defaultValues
);
return tresult;
}
template<class Type, class CombineOp>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget
(
const tmp<Field<Type>>& tFld,
const CombineOp& cop,
const UList<Type>& defaultValues
) const
{
return interpolateToTarget(tFld(), cop, defaultValues);
}
@ -109,13 +295,10 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource
(
const Field<Type>& fld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
AMICorrectedMultiplyWeightedOp<Type> cop(*this, true, lwOption);
return interpolate(fld, cop, defaultValues);
return interpolateToSource(fld, plusEqOp<Type>(), defaultValues);
}
@ -123,11 +306,10 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
return interpolateToSource(tFld(), defaultValues, lwOption);
return interpolateToSource(tFld(), plusEqOp<Type>(), defaultValues);
}
@ -135,13 +317,10 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget
(
const Field<Type>& fld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
AMICorrectedMultiplyWeightedOp<Type> cop(*this, false, lwOption);
return interpolate(fld, cop, defaultValues);
return interpolateToTarget(fld, plusEqOp<Type>(), defaultValues);
}
@ -149,11 +328,10 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
return interpolateToTarget(tFld(), defaultValues, lwOption);
return interpolateToTarget(tFld(), plusEqOp<Type>(), defaultValues);
}

View File

@ -292,15 +292,14 @@ void Foam::cyclicACMIGAMGInterfaceField::updateInterfaceMatrix
recvRequests_.clear();
solveScalarField pnf(faceCells.size(), Zero);
AMIMultiplyWeightedOp<solveScalar> cop
AMI.weightedSum
(
AMI,
cyclicACMIInterface_.owner()
cyclicACMIInterface_.owner(),
work,
pnf, // result
solveScalarField::null()
);
cop(pnf, work, solveScalarField::null());
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
}

View File

@ -306,14 +306,13 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
recvRequests_.clear();
solveScalarField pnf(faceCells.size(), Zero);
// Note: no low-weight correction
AMIMultiplyWeightedOp<solveScalar> cop
AMI.weightedSum
(
AMI,
cyclicAMIInterface_.owner()
cyclicAMIInterface_.owner(),
work,
pnf, // result
defaultValues
);
cop(pnf, work, defaultValues);
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);
@ -330,14 +329,13 @@ void Foam::cyclicAMIGAMGInterfaceField::updateInterfaceMatrix
transformCoupleField(work, cmpt);
solveScalarField pnf(faceCells.size(), Zero);
// Note: no low-weight correction
AMIMultiplyWeightedOp<solveScalar> cop
AMI.weightedSum
(
AMI,
cyclicAMIInterface_.owner()
cyclicAMIInterface_.owner(),
work,
pnf, // result
defaultValues
);
cop(pnf, work, defaultValues);
// Add result using coefficients
this->addToInternalField(result, !add, faceCells, coeffs, pnf);

View File

@ -446,54 +446,6 @@ void Foam::cyclicAMIPolyPatch::resetAMI(const UList<point>& points) const
{
AMIPtr_->checkSymmetricWeights(true);
}
// Check connectivity
if (applyLowWeightCorrection() || !AMIPtr_->requireMatch())
{
Info<< "AMI: performing connectivity checks" << endl;
const auto& C = boundaryMesh().mesh().cellCentres();
auto cosTheta =
[&](const polyPatch& p1, const polyPatch& p2, const bool toSource)
{
const auto& Cf1 = p1.faceCentres();
const auto& faceCells1 = p1.faceCells();
vectorField delta1(p1.size());
forAll(delta1, i)
{
delta1[i] = Cf1[i] - C[faceCells1[i]];
}
// Interpolate nbr delta to local (src) side using (uncorrected)
// multiply-weighted op
const AMIMultiplyWeightedOp<vector> cop(*AMIPtr_, toSource);
AMIPtr_->interpolate(delta1, cop, UList<vector>::null());
delta1.normalise();
return delta1 & p2.faceNormals();
};
const scalarField ctSrc(cosTheta(*this, nbr, true));
forAll(ctSrc, facei)
{
if (ctSrc[facei] < 0)
{
AMIPtr_->removeSourceConnection(facei);
}
}
const scalarField ctTgt(cosTheta(nbr, *this, false));
forAll(ctTgt, facei)
{
if (ctTgt[facei] < 0)
{
AMIPtr_->removeTargetConnection(facei);
}
}
}
}

View File

@ -483,9 +483,7 @@ public:
tmp<Field<Type>> interpolate
(
const Field<Type>& fld,
const UList<Type>& defaultValues = UList<Type>(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>()
) const;
//- Interpolate tmp field
@ -493,9 +491,7 @@ public:
tmp<Field<Type>> interpolate
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues = UList<Type>(),
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues = UList<Type>()
) const;
//- Interpolate without periodic
@ -503,9 +499,7 @@ public:
tmp<Field<Type>> interpolateUntransformed
(
const Field<Type>& fld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues
) const;
//- Low-level interpolate List
@ -547,9 +541,7 @@ public:
const Field<Type>& localFld,
const labelRange& requests, // The receive requests
const PtrList<List<Type>>& recvBuffers,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption =
lowWeightCorrectionBase::option::ASSIGN
const UList<Type>& defaultValues
) const;

View File

@ -26,30 +26,22 @@ License
\*---------------------------------------------------------------------------*/
#include "AMIFieldOps.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolateUntransformed
(
const Field<Type>& fld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
if (owner())
{
return AMI().interpolateToSource(fld, defaultValues, lwOption);
return AMI().interpolateToSource(fld, defaultValues);
}
else
{
return neighbPatch().AMI().interpolateToTarget
(
fld,
defaultValues,
lwOption
);
return neighbPatch().AMI().interpolateToTarget(fld, defaultValues);
}
}
@ -58,8 +50,7 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
(
const Field<Type>& fld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
autoPtr<coordSystem::cylindrical> cs;
@ -74,7 +65,7 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
if (!cs)
{
return interpolateUntransformed(fld, defaultValues, lwOption);
return interpolateUntransformed(fld, defaultValues);
}
else
{
@ -150,7 +141,7 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
return Foam::transform
(
ownT,
interpolateUntransformed(localFld, localDeflt, lwOption)
interpolateUntransformed(localFld, localDeflt)
);
}
}
@ -160,11 +151,10 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
(
const tmp<Field<Type>>& tFld,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
return interpolate(tFld(), defaultValues, lwOption);
return interpolate(tFld(), defaultValues);
}
@ -255,8 +245,7 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
const Field<Type>& localFld,
const labelRange& requests,
const PtrList<List<Type>>& recvBuffers,
const UList<Type>& defaultValues,
const lowWeightCorrectionBase::option& lwOption
const UList<Type>& defaultValues
) const
{
const auto& AMI = (owner() ? this->AMI() : neighbPatch().AMI());
@ -283,9 +272,13 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
if (!cs)
{
AMICorrectedMultiplyWeightedOp<Type> cop(AMI, owner(), lwOption);
cop(tresult.ref(), fld, defaultValues);
AMI.weightedSum
(
owner(),
fld,
tresult.ref(),
defaultValues
);
}
else
{
@ -303,8 +296,13 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
Foam::invTransform(localDeflt, ownT, defaultFld);
}
AMICorrectedMultiplyWeightedOp<Type> cop(AMI, owner(), lwOption);
cop(tresult.ref(), fld, defaultValues);
AMI.weightedSum
(
owner(),
fld,
tresult.ref(),
localDeflt
);
// Transform back
Foam::transform(tresult.ref(), ownT, tresult());
@ -358,7 +356,26 @@ void Foam::cyclicAMIPolyPatch::interpolate
}
// Do actual AMI interpolation
AMI().interpolate(fld, cop, result, defaultValues);
if (owner())
{
AMI().interpolateToSource
(
fld,
cop,
result,
localDeflt
);
}
else
{
neighbPatch().AMI().interpolateToTarget
(
fld,
cop,
result,
localDeflt
);
}
// Transform back. Result is now at *this
Foam::transform(result, ownT, result);
@ -366,7 +383,26 @@ void Foam::cyclicAMIPolyPatch::interpolate
else
*/
{
AMI().interpolate(fld, cop, result, defaultValues);
if (owner())
{
AMI().interpolateToSource
(
fld,
cop,
result,
defaultValues
);
}
else
{
neighbPatch().AMI().interpolateToTarget
(
fld,
cop,
result,
defaultValues
);
}
}
}

View File

@ -276,7 +276,6 @@ processorLOD/cellBox/cellBox.C
processorLOD/faceBox/faceBox.C
AMI=AMIInterpolation
$(AMI)/AMIInterpolation/AMIFieldOps/lowWeightCorrectionBase.C
$(AMI)/AMIInterpolation/AMIInterpolation.C
$(AMI)/AMIInterpolation/AMIInterpolationNew.C
$(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C
@ -355,4 +354,18 @@ tetOverlapVolume/tetOverlapVolume.C
triangulatedPatch/triangulatedPatch.C
solidBodyMotion = solidBodyMotionFunctions
$(solidBodyMotion)/solidBodyMotionFunction/solidBodyMotionFunction.C
$(solidBodyMotion)/solidBodyMotionFunction/solidBodyMotionFunctionNew.C
$(solidBodyMotion)/SDA/SDA.C
$(solidBodyMotion)/tabulated6DoFMotion/tabulated6DoFMotion.C
$(solidBodyMotion)/linearMotion/linearMotion.C
$(solidBodyMotion)/drivenLinearMotion/drivenLinearMotion.C
$(solidBodyMotion)/rotatingMotion/rotatingMotion.C
$(solidBodyMotion)/axisRotationMotion/axisRotationMotion.C
$(solidBodyMotion)/multiMotion/multiMotion.C
$(solidBodyMotion)/oscillatingLinearMotion/oscillatingLinearMotion.C
$(solidBodyMotion)/oscillatingRotatingMotion/oscillatingRotatingMotion.C
LIB = $(FOAM_LIBBIN)/libmeshTools

View File

@ -1,7 +1,6 @@
EXE_INC = \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/surfMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude
-I$(LIB_SRC)/surfMesh/lnInclude
LIB_LIBS = \
-lfileFormats \

View File

@ -38,7 +38,6 @@ License
#include "typeInfo.H"
#include "SubField.H"
#include "globalMeshData.H"
#include "AMIFieldOps.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -96,73 +95,6 @@ namespace Foam
}
}
};
// Combine operator for AMIInterpolation
template<class Type, class TrackingData>
class combineField
:
public AMIFieldOpBase
{
// Private Data
FaceCellWave<Type, TrackingData>& solver_;
const cyclicAMIPolyPatch& patch_;
public:
combineField
(
FaceCellWave<Type, TrackingData>& solver,
const cyclicAMIPolyPatch& patch
)
:
AMIFieldOpBase(patch.AMI(), patch.owner()),
solver_(solver),
patch_(patch)
{}
void operator()
(
List<Type>& result,
const UList<Type>& fld,
const UList<Type>& /* unused defaultValues */
) const
{
const auto& allSlots = address();
forAll(result, facei)
{
const labelList& slots = allSlots[facei];
for (const label sloti : slots)
{
if (fld[sloti].valid(solver_.data()))
{
label meshFacei = -1;
if (patch_.owner())
{
meshFacei = patch_.start() + facei;
}
else
{
meshFacei =
patch_.neighbPatch().start() + facei;
}
result[facei].updateFace
(
solver_.mesh(),
meshFacei,
fld[sloti],
solver_.propagationTol(),
solver_.data()
);
}
}
}
}
};
}
@ -850,7 +782,7 @@ void Foam::FaceCellWave<Type, TrackingData>::handleAMICyclicPatches()
}
// Transfer sendInfo to cycPatch
combineField<Type, TrackingData> cmb(*this, cycPatch);
combine<Type, TrackingData> cmb(*this, cycPatch);
if (cycPatch.applyLowWeightCorrection())
{

View File

@ -26,9 +26,6 @@ License
\*---------------------------------------------------------------------------*/
#include "AMIFieldOps.H"
template<class Type>
void Foam::mappedPatchBase::distribute(List<Type>& lst) const
{
@ -123,9 +120,7 @@ void Foam::mappedPatchBase::distribute
const label oldWarnComm = UPstream::commWarn(myComm);
const label oldWorldComm = UPstream::commWorld(myComm);
const auto op = AMIFieldOp<Type, CombineOp>(interp, cop, true);
lst = interp.interpolate(Field<Type>(std::move(lst)), op);
lst = interp.interpolateToSource(Field<Type>(std::move(lst)), cop);
UPstream::commWarn(oldWarnComm);
UPstream::commWorld(oldWorldComm);
@ -211,9 +206,7 @@ void Foam::mappedPatchBase::reverseDistribute
const label oldWarnComm = UPstream::commWarn(myComm);
const label oldWorldComm = UPstream::commWorld(myComm);
const auto op = AMIFieldOp<Type, CombineOp>(interp, false);
lst = interp.interpolate(Field<Type>(std::move(lst)), op);
lst = interp.interpolateToTarget(Field<Type>(std::move(lst)), cop);
UPstream::commWarn(oldWarnComm);
UPstream::commWorld(oldWorldComm);

View File

@ -39,12 +39,12 @@ Description
SourceFiles
solidBodyMotionFunction.C
dynamicFvMeshNew.C
solidBodyMotionFunctionNew.C
\*---------------------------------------------------------------------------*/
#ifndef solidBodyMotionFunction_H
#define solidBodyMotionFunction_H
#ifndef Foam_solidBodyMotionFunction_H
#define Foam_solidBodyMotionFunction_H
#include "Time.H"
#include "dictionary.H"
@ -101,7 +101,7 @@ public:
// Constructors
//- Construct from the SBMFCoeffs dictionary and Time
//- Construct from the coefficients dictionary and Time
solidBodyMotionFunction
(
const dictionary& SBMFCoeffs,
@ -114,10 +114,28 @@ public:
// Selectors
//- Select constructed from the SBMFCoeffs dictionary and Time
//- Construct and dispatch motionType with dictionary and Time.
// Returns nullptr if motionType is empty
static autoPtr<solidBodyMotionFunction> New
(
const dictionary& SBMFCoeffs,
const word& motionType,
const dictionary& dict,
const Time& runTime
);
//- Select "solidBodyMotionFunction" type from dictionary
//- and create with Time.
static autoPtr<solidBodyMotionFunction> New
(
const dictionary& dict,
const Time& runTime
);
//- Select "solidBodyMotionFunction" type (if present) from dictionary
//- and create with Time.
static autoPtr<solidBodyMotionFunction> NewIfPresent
(
const dictionary& dict,
const Time& runTime
);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019-2021 OpenCFD Ltd.
Copyright (C) 2019-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,15 +30,18 @@ License
// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::solidBodyMotionFunction> Foam::solidBodyMotionFunction::New
Foam::autoPtr<Foam::solidBodyMotionFunction>
Foam::solidBodyMotionFunction::New
(
const word& motionType,
const dictionary& dict,
const Time& runTime
)
{
const word motionType(dict.get<word>("solidBodyMotionFunction"));
Info<< "Selecting solid-body motion function " << motionType << endl;
if (motionType.empty())
{
return nullptr;
}
auto* ctorPtr = dictionaryConstructorTable(motionType);
@ -53,8 +56,45 @@ Foam::autoPtr<Foam::solidBodyMotionFunction> Foam::solidBodyMotionFunction::New
) << exit(FatalIOError);
}
Info<< "Selecting solid-body motion function " << motionType << endl;
return autoPtr<solidBodyMotionFunction>(ctorPtr(dict, runTime));
}
Foam::autoPtr<Foam::solidBodyMotionFunction>
Foam::solidBodyMotionFunction::New
(
const dictionary& dict,
const Time& runTime
)
{
return New
(
dict.get<word>("solidBodyMotionFunction", keyType::LITERAL),
dict,
runTime
);
}
Foam::autoPtr<Foam::solidBodyMotionFunction>
Foam::solidBodyMotionFunction::NewIfPresent
(
const dictionary& dict,
const Time& runTime
)
{
word motionType;
dict.readIfPresent("solidBodyMotionFunction", motionType, keyType::LITERAL);
if (motionType.empty())
{
return nullptr;
}
return New(motionType, dict, runTime);
}
// ************************************************************************* //

View File

@ -90,10 +90,10 @@ Foam::boundaryToCell::boundaryToCell(const polyMesh& mesh)
Foam::boundaryToCell::boundaryToCell
(
const polyMesh& mesh,
const dictionary&
const dictionary& dict
)
:
topoSetCellSource(mesh)
topoSetCellSource(mesh, dict)
{}

View File

@ -92,7 +92,8 @@ static void readBoxDim(const dictionary& dict, treeBoundBox& bb)
void Foam::boxToCell::combine(topoSet& set, const bool add) const
{
const pointField& ctrs = mesh_.cellCentres();
const tmp<pointField> tctrs(this->transform(mesh_.cellCentres()));
const pointField& ctrs = tctrs();
forAll(ctrs, elemi)
{
@ -138,7 +139,7 @@ Foam::boxToCell::boxToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
bbs_()
{
// Accept 'boxes', 'box' or 'min/max'

View File

@ -50,7 +50,7 @@ Usage
source boxToCell;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
boxes

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -60,7 +60,8 @@ Foam::cellToCell::cellToCell
)
:
topoSetCellSource(mesh),
names_(one{}, setName)
names_(Foam::one{}, setName),
isZone_(false)
{}
@ -70,16 +71,10 @@ Foam::cellToCell::cellToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
names_()
{
// Look for 'sets' or 'set'
if (!dict.readIfPresent("sets", names_))
{
names_.resize(1);
dict.readEntry("set", names_.front());
}
}
topoSetCellSource(mesh, dict),
names_(),
isZone_(topoSetSource::readNames(dict, names_))
{}
Foam::cellToCell::cellToCell
@ -89,7 +84,8 @@ Foam::cellToCell::cellToCell
)
:
topoSetCellSource(mesh),
names_(one{}, word(checkIs(is)))
names_(Foam::one{}, word(checkIs(is))),
isZone_(false)
{}
@ -105,30 +101,44 @@ void Foam::cellToCell::applyToSet
{
if (verbose_)
{
Info<< " Adding all elements of cell sets: "
Info<< " Adding all elements of cell "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}
for (const word& setName : names_)
{
cellSet loadedSet(mesh_, setName);
set.addSet(loadedSet);
if (isZone_)
{
set.addSet(mesh_.cellZones()[setName]);
}
else
{
cellSet loadedSet(mesh_, setName);
set.addSet(loadedSet);
}
}
}
else if (action == topoSetSource::SUBTRACT)
{
if (verbose_)
{
Info<< " Removing all elements of cell sets: "
Info<< " Removing all elements of cell "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}
for (const word& setName : names_)
{
cellSet loadedSet(mesh_, setName);
set.subtractSet(loadedSet);
if (isZone_)
{
set.subtractSet(mesh_.cellZones()[setName]);
}
else
{
cellSet loadedSet(mesh_, setName);
set.subtractSet(loadedSet);
}
}
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,7 +28,8 @@ Class
Foam::cellToCell
Description
A \c topoSetCellSource to select all the cells from given \c cellSet(s).
A \c topoSetCellSource to select all the cells from given \c cellSet(s)
or \c cellZone(s).
Operands:
\table
@ -50,7 +51,7 @@ Usage
source cellToCell;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
sets
@ -61,7 +62,18 @@ Usage
);
// Option-2
set <cellSetName>;
zones
(
<cellZoneName0>
<cellZoneName1>
...
);
// Option-3
set <cellSetName>;
// Option-4
zone <cellZoneName>;
}
\endverbatim
@ -81,17 +93,15 @@ Usage
subtract | Remove selected cells from this cellSet
\endverbatim
Options for the conditional mandatory entries:
Options for the conditional mandatory entries (in order of precedence):
\verbatim
Entry | Description | Type | Req'd | Dflt
sets | Names of input cellSets | wordList | cond'l | -
zones | Names of input cellZones | wordList | cond'l | -
set | Name of input cellSet | word | cond'l | -
zone | Name of input cellZone | word | cond'l | -
\endverbatim
Note
The order of precedence among the conditional mandatory entries from the
highest to the lowest is \c sets, and \c set.
See also
- Foam::topoSetSource
- Foam::topoSetCellSource
@ -101,8 +111,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef cellToCell_H
#define cellToCell_H
#ifndef Foam_cellToCell_H
#define Foam_cellToCell_H
#include "topoSetCellSource.H"
@ -124,9 +134,12 @@ class cellToCell
//- Add usage string
static addToUsageTable usage_;
//- Names of sets to use
//- Names of sets or zones to use
wordList names_;
//- Is name a set or a zone
const bool isZone_;
public:

View File

@ -69,7 +69,8 @@ void Foam::clipPlaneToCell::combine(topoSet& set, const bool add) const
{
// Cell centres above the plane
const pointField& ctrs = mesh_.cellCentres();
const tmp<pointField> tctrs(this->transform(mesh_.cellCentres()));
const pointField& ctrs = tctrs();
forAll(ctrs, elemi)
{
@ -102,12 +103,9 @@ Foam::clipPlaneToCell::clipPlaneToCell
const dictionary& dict
)
:
clipPlaneToCell
(
mesh,
dict.get<vector>("point"),
dict.get<vector>("normal")
)
topoSetCellSource(mesh, dict),
point_(dict.get<vector>("point")),
normal_(dict.get<vector>("normal"))
{}

View File

@ -68,7 +68,8 @@ Foam::topoSetSource::addToUsageTable Foam::cylinderToCell::usage_
void Foam::cylinderToCell::combine(topoSet& set, const bool add) const
{
const pointField& ctrs = mesh_.cellCentres();
const tmp<pointField> tctrs(this->transform(mesh_.cellCentres()));
const pointField& ctrs = tctrs();
const vector axis = (point2_ - point1_);
const scalar magAxis2 = magSqr(axis);
@ -127,12 +128,12 @@ Foam::cylinderToCell::cylinderToCell
const dictionary& dict
)
:
cylinderToCell
topoSetCellSource(mesh, dict),
point1_(dict.getCompat<point>("point1", {{"p1", -2112}})),
point2_(dict.getCompat<point>("point2", {{"p2", -2112}})),
radius_(dict.getCompat<scalar>("radius", {{"outerRadius", -2112}})),
innerRadius_
(
mesh,
dict.getCompat<point>("point1", {{"p1", -2112}}),
dict.getCompat<point>("point2", {{"p2", -2112}}),
dict.getCompat<scalar>("radius", {{"outerRadius", -2112}}),
dict.getCheckOrDefault<scalar>("innerRadius", 0, scalarMinMax::ge(0))
)
{}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -66,18 +66,14 @@ Foam::faceToCell::faceActionNames_
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::faceToCell::combine
template<class Selector>
void Foam::faceToCell::combineImpl
(
topoSet& set,
const bool add,
const word& setName
const Selector& faceLabels
) const
{
// Load the set
faceSet loadedSet(mesh_, setName);
const labelHashSet& faceLabels = loadedSet;
// Handle owner/neighbour/any selection
for (const label facei : faceLabels)
{
@ -104,7 +100,7 @@ void Foam::faceToCell::combine
{
// Count number of selected faces per cell.
Map<label> facesPerCell(loadedSet.size());
Map<label> facesPerCell(faceLabels.size());
for (const label facei : faceLabels)
{
@ -134,6 +130,31 @@ void Foam::faceToCell::combine
}
void Foam::faceToCell::combine
(
topoSet& set,
const bool add,
const word& setName
) const
{
if (isZone_)
{
const labelList& faceLabels = mesh_.faceZones()[setName];
combineImpl(set, add, faceLabels);
}
else
{
// Load the set
faceSet loadedSet(mesh_, setName);
const labelHashSet& faceLabels = loadedSet;
combineImpl(set, add, faceLabels);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::faceToCell::faceToCell
@ -144,7 +165,8 @@ Foam::faceToCell::faceToCell
)
:
topoSetCellSource(mesh),
names_(one{}, setName),
names_(Foam::one{}, setName),
isZone_(false),
option_(option)
{}
@ -155,17 +177,11 @@ Foam::faceToCell::faceToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
names_(),
isZone_(topoSetSource::readNames(dict, names_)),
option_(faceActionNames_.get("option", dict))
{
// Look for 'sets' or 'set'
if (!dict.readIfPresent("sets", names_))
{
names_.resize(1);
dict.readEntry("set", names_.front());
}
}
{}
Foam::faceToCell::faceToCell
@ -175,7 +191,8 @@ Foam::faceToCell::faceToCell
)
:
topoSetCellSource(mesh),
names_(one{}, word(checkIs(is))),
names_(Foam::one{}, word(checkIs(is))),
isZone_(false),
option_(faceActionNames_.read(checkIs(is)))
{}
@ -192,8 +209,9 @@ void Foam::faceToCell::applyToSet
{
if (verbose_)
{
Info<< " Adding cells according to face sets: "
<< flatOutput(names_) << endl;
Info<< " Adding cells according to face "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}
for (const word& setName : names_)
@ -205,8 +223,9 @@ void Foam::faceToCell::applyToSet
{
if (verbose_)
{
Info<< " Removing cells according to face sets: "
<< flatOutput(names_) << endl;
Info<< " Removing cells according to face "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}
for (const word& setName : names_)

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -53,7 +53,7 @@ Usage
option <option>;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
sets
@ -64,7 +64,18 @@ Usage
);
// Option-2
zones
(
<faceZoneName0>
<faceZoneName1>
...
);
// Option-3
set <faceSetName>;
// Option-4
zone <faceZoneName>;
}
\endverbatim
@ -93,17 +104,15 @@ Usage
neighbour | Cells that are neighbour of given faces
\endverbatim
Options for the conditional mandatory entries:
Options for the conditional mandatory entries (in order of precedence):
\verbatim
Entry | Description | Type | Req'd | Dflt
sets | Names of input faceSets | wordList | cond'l | -
zones | Names of input faceZones | wordList | cond'l | -
set | Name of input faceSet | word | cond'l | -
zone | Name of input faceZone | word | cond'l | -
\endverbatim
Note
The order of precedence among the conditional mandatory entries from the
highest to the lowest is \c sets, and \c set.
See also
- Foam::topoSetSource
- Foam::topoSetCellSource
@ -114,8 +123,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef faceToCell_H
#define faceToCell_H
#ifndef Foam_faceToCell_H
#define Foam_faceToCell_H
#include "topoSetCellSource.H"
#include "Enum.H"
@ -153,15 +162,27 @@ private:
//- Add usage string
static addToUsageTable usage_;
//- Names of sets to use
//- Names of sets or zones to use
wordList names_;
//- Is name a set or a zone
const bool isZone_;
//- Option
faceAction option_;
// Private Member Functions
//- Depending on face to cell option add to or delete from cellSet.
template<class Selector>
void combineImpl
(
topoSet& set,
const bool add,
const Selector& faceLabels
) const;
//- Depending on face to cell option add to or delete from cellSet.
void combine(topoSet& set, const bool add, const word& setName) const;

View File

@ -214,7 +214,7 @@ Foam::faceZoneToCell::faceZoneToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
zoneMatcher_(),
option_(faceActionNames_.get("option", dict))
{

View File

@ -52,7 +52,7 @@ Usage
option <option>;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
zones
@ -63,7 +63,7 @@ Usage
);
// Option-2
set <faceZoneName>;
zone <faceZoneName>;
}
\endverbatim

View File

@ -148,13 +148,10 @@ Foam::fieldToCell::fieldToCell
const dictionary& dict
)
:
fieldToCell
(
mesh,
dict.get<word>("field"),
dict.get<scalar>("min"),
dict.get<scalar>("max")
)
topoSetCellSource(mesh, dict),
fieldName_(dict.get<word>("field")),
min_(dict.get<scalar>("min")),
max_(dict.get<scalar>("max"))
{}

View File

@ -198,7 +198,8 @@ Foam::haloToCell::haloToCell
const dictionary& dict
)
:
haloToCell(mesh, dict.getOrDefault<label>("steps", 1))
topoSetCellSource(mesh, dict),
steps_(dict.getOrDefault<label>("steps", 1))
{}

View File

@ -94,7 +94,8 @@ Foam::labelToCell::labelToCell
const dictionary& dict
)
:
labelToCell(mesh, dict.get<labelList>("value"))
topoSetCellSource(mesh, dict),
labels_(dict.get<labelList>("value"))
{}

View File

@ -74,6 +74,7 @@ void Foam::nbrToCell::combine(topoSet& set, const bool add) const
}
const cellList& cells = mesh().cells();
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
boolList isCoupled(mesh_.nBoundaryFaces(), false);
@ -136,7 +137,8 @@ Foam::nbrToCell::nbrToCell
const dictionary& dict
)
:
nbrToCell(mesh, dict.getCheck<label>("neighbours", labelMinMax::ge(1)))
topoSetCellSource(mesh, dict),
minNbrs_(dict.getCheck<label>("neighbours", labelMinMax::ge(1)))
{}

View File

@ -127,11 +127,8 @@ Foam::nearestToCell::nearestToCell
const dictionary& dict
)
:
nearestToCell
(
mesh,
dict.get<pointField>("points")
)
topoSetCellSource(mesh, dict),
points_(dict.get<pointField>("points"))
{}

View File

@ -125,7 +125,7 @@ Foam::patchToCell::patchToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
selectedPatches_()
{
// Look for 'patches' and 'patch', but accept 'name' as well

View File

@ -48,7 +48,7 @@ Usage
source patchToCell;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
patches

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -64,18 +64,14 @@ Foam::pointToCell::pointActionNames_
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::pointToCell::combine
template<class Selector>
void Foam::pointToCell::combineImpl
(
topoSet& set,
const bool add,
const word& setName
const Selector& pointLabels
) const
{
// Load the set
pointSet loadedSet(mesh_, setName);
const labelHashSet& pointLabels = loadedSet;
// Handle any selection
if (option_ == ANY)
{
@ -114,6 +110,31 @@ void Foam::pointToCell::combine
}
void Foam::pointToCell::combine
(
topoSet& set,
const bool add,
const word& setName
) const
{
if (isZone_)
{
const labelList& pointLabels = mesh_.pointZones()[setName];
combineImpl(set, add, pointLabels);
}
else
{
// Load the set
pointSet loadedSet(mesh_, setName);
const labelHashSet& pointLabels = loadedSet;
combineImpl(set, add, pointLabels);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pointToCell::pointToCell
@ -124,7 +145,8 @@ Foam::pointToCell::pointToCell
)
:
topoSetCellSource(mesh),
names_(one{}, setName),
names_(Foam::one{}, setName),
isZone_(false),
option_(option)
{}
@ -135,17 +157,11 @@ Foam::pointToCell::pointToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
names_(),
isZone_(topoSetSource::readNames(dict, names_)),
option_(pointActionNames_.get("option", dict))
{
// Look for 'sets' or 'set'
if (!dict.readIfPresent("sets", names_))
{
names_.resize(1);
dict.readEntry("set", names_.front());
}
}
{}
Foam::pointToCell::pointToCell
@ -155,7 +171,8 @@ Foam::pointToCell::pointToCell
)
:
topoSetCellSource(mesh),
names_(one{}, word(checkIs(is))),
names_(Foam::one{}, word(checkIs(is))),
isZone_(false),
option_(pointActionNames_.read(checkIs(is)))
{}
@ -172,7 +189,8 @@ void Foam::pointToCell::applyToSet
{
if (verbose_)
{
Info<< " Adding cells according to point sets: "
Info<< " Adding cells according to point "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}
@ -185,7 +203,8 @@ void Foam::pointToCell::applyToSet
{
if (verbose_)
{
Info<< " Removing cells according to point sets: "
Info<< " Removing cells according to point "
<< (isZone_ ? "zones: " : "sets: ")
<< flatOutput(names_) << nl;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -52,7 +52,7 @@ Usage
option <option>;
// Conditional mandatory entries
// Select either of the below
// Select one of the below
// Option-1
sets
@ -62,8 +62,19 @@ Usage
...
);
// Option-2
set <pointSetName>;
// Option-3
zones
(
<pointZoneName0>
<pointZoneName1>
...
);
// Option-3
set <pointSetName>;
// Option-4
zone <pointZoneName>;
}
\endverbatim
@ -90,17 +101,15 @@ Usage
edge | Cells using an edge with both points in pointSet
\endverbatim
Options for the conditional mandatory entries:
Options for the conditional mandatory entries (in order of precedence):
\verbatim
Entry | Description | Type | Req'd | Dflt
sets | Names of input pointSets | wordList | cond'l | -
zones | Names of input pointZones | wordList | cond'l | -
set | Name of input pointSet | word | cond'l | -
zone | Name of input pointZone | word | cond'l | -
\endverbatim
Note
The order of precedence among the conditional mandatory entries from the
highest to the lowest is \c sets, and \c set.
See also
- Foam::topoSetSource
- Foam::topoSetCellSource
@ -110,8 +119,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef pointToCell_H
#define pointToCell_H
#ifndef Foam_pointToCell_H
#define Foam_pointToCell_H
#include "topoSetCellSource.H"
#include "Enum.H"
@ -148,15 +157,27 @@ private:
static const Enum<pointAction> pointActionNames_;
//- Names of sets to use
//- Names of sets or zones to use
wordList names_;
//- Is name a set or a zone
const bool isZone_;
//- Selection type
pointAction option_;
// Private Member Functions
//- Depending on point to cell option add to or delete from cellSet.
template<class Selector>
void combineImpl
(
topoSet& set,
const bool add,
const Selector& pointLabels
) const;
//- Depending on point-to-cell option add to or delete from cellSet.
void combine(topoSet& set, const bool add, const word& setName) const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2020 OpenCFD Ltd.
Copyright (C) 2015-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -346,18 +346,33 @@ void Foam::regionToCell::combine(topoSet& set, const bool add) const
// Note: wip. Select cells first
boolList selectedCell(mesh_.nCells(), true);
if (setName_.size() && setName_ != "none")
if (!setName_.empty() && setName_ != "none")
{
Info<< " Loading subset " << setName_
<< " to delimit search region."
<< endl;
cellSet subSet(mesh_, setName_);
selectedCell = false;
for (const label celli : subSet)
if (isZone_)
{
selectedCell[celli] = true;
Info<< " Using cellZone " << setName_
<< " to delimit search region."
<< endl;
selectedCell = false;
for (const label celli : mesh_.cellZones()[setName_])
{
selectedCell[celli] = true;
}
}
else
{
Info<< " Loading cellSet " << setName_
<< " to delimit search region."
<< endl;
cellSet subSet(mesh_, setName_);
selectedCell = false;
for (const label celli : subSet)
{
selectedCell[celli] = true;
}
}
}
@ -392,6 +407,7 @@ Foam::regionToCell::regionToCell
:
topoSetCellSource(mesh),
setName_(setName),
isZone_(false),
insidePoints_(insidePoints),
nErode_(nErode)
{}
@ -403,14 +419,25 @@ Foam::regionToCell::regionToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
setName_(dict.getOrDefault<word>("set", "none")),
topoSetCellSource(mesh, dict),
setName_(),
isZone_(false),
insidePoints_
(
dict.getCompat<pointField>("insidePoints", {{ "insidePoint", 0 }})
),
nErode_(dict.getCheckOrDefault<label>("nErode", 0, labelMinMax::ge(0)))
{}
{
// A single set or zone only!
if (dict.readIfPresent("set", setName_))
{
isZone_ = false;
}
else if (dict.readIfPresent("zone", setName_))
{
isZone_ = true;
}
}
Foam::regionToCell::regionToCell
@ -421,6 +448,7 @@ Foam::regionToCell::regionToCell
:
topoSetCellSource(mesh),
setName_(checkIs(is)),
isZone_(false),
insidePoints_(checkIs(is)),
nErode_(readLabel(checkIs(is)))
{}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2012 OpenFOAM Foundation
Copyright (C) 2018-2020 OpenCFD Ltd.
Copyright (C) 2018-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -59,6 +59,7 @@ Usage
// Optional entries
set <cellSetName>;
zone <cellZoneName>;
nErode <label>;
}
\endverbatim
@ -93,8 +94,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef regionToCell_H
#define regionToCell_H
#ifndef Foam_regionToCell_H
#define Foam_regionToCell_H
#include "topoSetCellSource.H"
#include "boolList.H"
@ -119,8 +120,11 @@ class regionToCell
//- Add usage string
static addToUsageTable usage_;
//- Name of cellSet to keep to
const word setName_;
//- Name of cellSet or cellZone to keep to
word setName_;
//- Is name a set or a zone
bool isZone_;
//- Coordinate(s) that is inside connected region
const pointField insidePoints_;

View File

@ -96,7 +96,8 @@ void Foam::rotatedBoxToCell::combine(topoSet& set, const bool add) const
// Check whether cell centre is inside all faces of box.
const pointField& ctrs = mesh_.cellCentres();
const tmp<pointField> tctrs(this->transform(mesh_.cellCentres()));
const pointField& ctrs = tctrs();
forAll(ctrs, celli)
{
@ -146,14 +147,11 @@ Foam::rotatedBoxToCell::rotatedBoxToCell
const dictionary& dict
)
:
rotatedBoxToCell
(
mesh,
dict.get<point>("origin"),
dict.get<vector>("i"),
dict.get<vector>("j"),
dict.get<vector>("k")
)
topoSetCellSource(mesh, dict),
origin_(dict.get<point>("origin")),
i_(dict.get<vector>("i")),
j_(dict.get<vector>("j")),
k_(dict.get<vector>("k"))
{}

View File

@ -102,9 +102,13 @@ void Foam::searchableSurfaceToCell::combine(topoSet& set, const bool add) const
{
return;
}
const pointField& ctrs = mesh_.cellCentres();
const tmp<pointField> tctrs(this->transform(mesh_.cellCentres()));
const pointField& ctrs = tctrs();
const searchableSurface& s = *surf_;
// Cell centres within the enclosing volumes
List<volumeType> volTypes;
@ -130,7 +134,7 @@ Foam::searchableSurfaceToCell::searchableSurfaceToCell
const dictionary& dict
)
:
topoSetCellSource(mesh),
topoSetCellSource(mesh, dict),
surf_
(
searchableSurface::New

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