Compare commits

..

3 Commits

Author SHA1 Message Date
460f1478be ENH: radiometerProbes: new function object to monitor radiative heat flux at internal points
The radiometer probes enable measurement of incident radiative heat flux
at arbitrary internal points within the domain, useful for radiation sensor
simulation and heat transfer analysis in participating media applications.
2025-10-23 10:15:09 +01:00
29813b0e96 ENH: probes: refactor probes framework with template-based design
- detach probe actions from data handling actions
- move common functionalities to base classes for code reuse
- add pointProberBase as abstract base for probe location handling
- implement internalPointProber for sampling at internal mesh locations
- implement patchPointProber for sampling at boundary patch locations
- introduce ProbesBase<Prober> template class for sampling framework
- refactor existing probes and patchProbes to use new template structure
- update thermoCoupleProbes to use new prober() interface
- maintain backward compatibility while enabling extensible probe types

ENH: probes: detach pointField inheritance from probes

STYLE: probes: rename lists as ids
2025-10-23 10:14:58 +01:00
6cadf3116f ENH: radiation: add access function for solverFreq variable 2025-10-15 20:45:06 +01:00
135 changed files with 4118 additions and 5618 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2025 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,6 +26,7 @@ License
\*---------------------------------------------------------------------------*/
#include "readFields.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
@ -41,30 +42,26 @@ Foam::label Foam::checkData
wordHashSet goodFields;
IOobject io
(
"any-name", // placeholder
"constant", // placeholder
local,
obr,
IOobjectOption::NO_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
);
for (const word& fieldName : objectNames)
{
// In case prune_0() not previously used...
if (fieldName.ends_with("_0")) continue;
// // If prune_0() not previously used...
// if (objectNames.ends_with("_0")) continue;
bool good = false;
for (const instant& inst : timeDirs)
{
io.resetHeader(fieldName);
io.instance() = inst.name();
good = io.typeHeaderOk<regIOobject>(false, false);
good =
IOobject
(
fieldName,
inst.name(),
local,
obr,
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
).typeHeaderOk<volScalarField>(false, false);
if (!good)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -57,6 +57,7 @@ writeDictionary/writeDictionary.C
writeObjects/writeObjects.C
thermoCoupleProbes/thermoCoupleProbes.C
radiometerProbes/radiometerProbes.C
syncObjects/syncObjects.C

View File

@ -9,7 +9,9 @@ EXE_INC = \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/ODE/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
-I$(LIB_SRC)/transportModels/compressible/lnInclude
-I$(LIB_SRC)/transportModels/compressible/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/radiation/lnInclude \
-I$(LIB_SRC)/parallel/distributed/lnInclude
LIB_LIBS = \
-lfiniteVolume \
@ -22,4 +24,6 @@ LIB_LIBS = \
-lsampling \
-lODE \
-lfluidThermophysicalModels \
-lcompressibleTransportModels
-lcompressibleTransportModels \
-lradiationModels \
-ldistributed

View File

@ -0,0 +1,260 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "radiometerProbes.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(radiometerProbes, 0);
addToRunTimeSelectionTable(functionObject, radiometerProbes, dictionary);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::functionObjects::radiometerProbes::writeFileHeader(Ostream& os)
{
const pointField& locs = probeLocations();
writeCommented(os, "Probe,Location,Normal");
os << nl;
for (label i = 0; i < szProbes_; ++i)
{
const vector& loc = locs[i];
const vector& n = n_[i];
os << '#' << ' ' << i
<< ',' << loc.x() << ',' << loc.y() << ',' << loc.z()
<< ',' << n.x() << ',' << n.y() << ',' << n.z()
<< nl;
}
os << "# Time";
for (int i = 0; i < szProbes_; ++i)
{
os << ',' << i;
}
os << endl;
writtenHeader_ = true;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::radiometerProbes::radiometerProbes
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
regionFunctionObject(name, runTime, dict),
internalProber(mesh_, dict),
writeFile(mesh_, name, typeName, dict),
dom_(mesh_.lookupObject<radiation::fvDOM>("radiationProperties")),
firstIter_(true)
{
read(dict);
}
// * * * * * * * * * * * * * * Public Member Functions * * * * * * * * * * * //
bool Foam::functionObjects::radiometerProbes::read(const dictionary& dict)
{
if
(
!(
regionFunctionObject::read(dict)
&& internalProber::read(dict)
&& writeFile::read(dict)
)
)
{
return false;
}
// Skip if the radiation model is inactive
if (!dom_.radiation())
{
WarningInFunction
<< "The radiation model is inactive."
<< "Skipping the function object " << type() << ' ' << name()
<< endl;
return false;
}
Log << type() << ':' << name() << ": read" << nl << nl;
// Probe locations are read by 'internalProber'
szProbes_ = this->size();
// If/when fvDOM is updated, the 'read' func is assumed to be executed to
// update the fvDOM properties
nRay_ = dom_.nRay();
if (!szProbes_ || !nRay_)
{
FatalIOErrorInFunction(dict)
<< "size(probe locations): " << szProbes_ << nl
<< "size(rays): " << nRay_ << nl
<< "The input size of probe locations and rays cannot be zero."
<< exit(FatalIOError);
}
// Read and check size consistency of probe normals with probe locations
dict.readEntry("probeNormals", n_);
if (n_.size() != szProbes_)
{
FatalIOErrorInFunction(dict)
<< "size(probe locations): " << szProbes_ << nl
<< "size(probe normals): " << n_.size() << nl
<< "The input size of probe locations and normals must match."
<< exit(FatalIOError);
}
n_.normalise();
// Pre-compute and cache inner product of 'n_' and 'dAve_', and 'C_'
// This simplification of calculation is valid only if I is non-negative
n_dAve_.resize(nRay_);
C_.resize(nRay_);
for (label rayi = 0; rayi < nRay_; ++rayi)
{
const vector& dAvei = dom_.IRay(rayi).dAve();
scalarList& n_dAveRay = n_dAve_[rayi];
boolList& Cray = C_[rayi];
n_dAveRay.resize(szProbes_, Zero);
Cray.resize(szProbes_, false);
for (label pi = 0; pi < szProbes_; ++pi)
{
n_dAveRay[pi] = n_[pi] & dAvei;
if (n_dAveRay[pi] < 0) // ray entering the probe
{
Cray[pi] = true;
}
}
}
qin_.resize(szProbes_);
if (writeFile::canResetFile())
{
writeFile::resetFile(typeName);
}
if (writeFile::canWriteHeader())
{
writeFileHeader(file());
}
return true;
}
bool Foam::functionObjects::radiometerProbes::execute()
{
// Skip if there is no probe to sample, or the radiation model is inactive
if (!szProbes_ || !dom_.radiation() || !shouldCalcThisStep())
{
return false;
}
Log << type() << ' ' << name() << ": execute" << nl << nl;
qin_ = Zero; // resized in 'read'
for (label rayi = 0; rayi < nRay_; ++rayi)
{
// Radiative intensity field for this ray
const volScalarField& I = dom_.IRay(rayi).I();
// Sample radiative intensity ray at probe locations
tmp<scalarField> tIp = internalProber::sample(I);
const scalarField& Ip = tIp.cref();
const scalarList& n_dAveRay = n_dAve_[rayi];
const boolList& Cray = C_[rayi];
// Add incident radiative heat flux per probe location for each ray
for (label pi = 0; pi < szProbes_; ++pi)
{
if (Cray[pi])
{
qin_[pi] += Ip[pi]*n_dAveRay[pi];
}
}
}
return true;
}
bool Foam::functionObjects::radiometerProbes::write()
{
// Skip if there is no probe to sample, or the radiation model is inactive
if (!szProbes_ || !dom_.radiation() || !shouldCalcThisStep())
{
return false;
}
Log << type() << ' ' << name() << ": write" << nl << nl;
if (UPstream::master())
{
Ostream& os = file();
os << mesh_.time().timeOutputValue();
for (label pi = 0; pi < szProbes_; ++pi)
{
os << ',' << qin_[pi];
}
os << endl;
}
firstIter_ = false;
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,200 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionObjects::radiometerProbes
Group
grpUtilitiesFunctionObjects
Description
Probes the incident radiative heat flux, qin, at arbitrary points within a
domain.
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
radiometer
{
// Mandatory entries
type radiometerProbes;
libs (utilityFunctionObjects);
probeLocations (<vectorList>);
probeNormals (<vectorList>);
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: radiometerProbes | word | yes | -
libs | Library name: utilityFunctionObjects | word | yes | -
probeLocations | Locations of probes | vectorList | yes | -
probeNormals | Normals of specified probes | vectorList | yes | -
\endtable
The inherited entries are elaborated in:
- \link regionFunctionObject.H \endlink
- \link internalProber.H \endlink
- \link writeFile.H \endlink
- \link fvDOM.H \endlink
Note
- The function object can only be used with the \c fvDOM radiation model.
- The \c solverFreq input of the \c fvDOM model has superiority over
\c executeControl and \c writeControl entries.
SourceFiles
radiometerProbes.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_functionObjects_radiometerProbes_H
#define Foam_functionObjects_radiometerProbes_H
#include "regionFunctionObject.H"
#include "internalProber.H"
#include "writeFile.H"
#include "fvDOM.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class radiometerProbes Declaration
\*---------------------------------------------------------------------------*/
class radiometerProbes
:
public regionFunctionObject,
public internalProber,
public writeFile
{
// Private Data
//- Const reference to the underlying radiation model
const radiation::fvDOM& dom_;
//- Normal vectors of the specified probes
vectorField n_;
//- Pre-computed inner product of probe normals (n_) and average
//- solid-angle direction (dAve) per radiative intensity ray
List<scalarList> n_dAve_;
//- Directional selection coefficient for radiative intensity rays
// false: ray entering the probe
// true: ray leaving the probe
List<boolList> C_;
//- Incident radiative heat flux per probe location
scalarField qin_;
//- Number of radiative intensity rays
label nRay_;
//- Number of probe locations/normals
label szProbes_;
//- Flag to identify whether the iteration is the first iteration
// Resets with a restarted simulation
bool firstIter_;
// Private Member Functions
//- Write file-header information into the output file
virtual void writeFileHeader(Ostream& os);
//- Return the flag to decide if radiation-model calculations are
//- performed, so that function object calculations can proceed
bool shouldCalcThisStep() const
{
return
firstIter_
|| (mesh_.time().timeIndex() % dom_.solverFreq() == 0);
}
public:
//- Runtime type information
TypeName("radiometerProbes");
// Generated Methods
//- No copy construct
radiometerProbes(const radiometerProbes&) = delete;
//- No copy assignment
void operator=(const radiometerProbes&) = delete;
// Constructors
//- Construct from name, Time and dictionary
radiometerProbes
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- Destructor
virtual ~radiometerProbes() = default;
// Public Member Functions
//- Read the function object settings
virtual bool read(const dictionary&);
//- Execute the function object
virtual bool execute();
//- Write to data files/fields and to streams
virtual bool write();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -76,7 +76,7 @@ Foam::functionObjects::thermoCoupleProbes::thermoCoupleProbes
}
else
{
Ttc_ = probes::sample(thermo_.T());
Ttc_ = prober().sample(thermo_.T());
}
// Note: can only create the solver once all samples have been found
@ -89,7 +89,7 @@ Foam::functionObjects::thermoCoupleProbes::thermoCoupleProbes
Foam::label Foam::functionObjects::thermoCoupleProbes::nEqns() const
{
return this->size();
return prober().size();
}
@ -108,19 +108,21 @@ void Foam::functionObjects::thermoCoupleProbes::derivatives
scalarField Cpc(y.size(), Zero);
scalarField kappac(y.size(), Zero);
const auto& p = prober();
if (radiationFieldName_ != "none")
{
G = sample(mesh_.lookupObject<volScalarField>(radiationFieldName_));
G = p.sample(mesh_.lookupObject<volScalarField>(radiationFieldName_));
}
Tc = probes::sample(thermo_.T());
Tc = p.sample(thermo_.T());
Uc = mag(this->sample(mesh_.lookupObject<volVectorField>(UName_)));
Uc = mag(p.sample(mesh_.lookupObject<volVectorField>(UName_)));
rhoc = this->sample(thermo_.rho()());
kappac = this->sample(thermo_.kappa()());
muc = this->sample(thermo_.mu()());
Cpc = this->sample(thermo_.Cp()());
rhoc = p.sample(thermo_.rho()());
kappac = p.sample(thermo_.kappa()());
muc = p.sample(thermo_.mu()());
Cpc = p.sample(thermo_.Cp()());
scalarField Re(rhoc*Uc*d_/muc);
scalarField Pr(Cpc*muc/kappac);
@ -163,7 +165,7 @@ void Foam::functionObjects::thermoCoupleProbes::jacobian
bool Foam::functionObjects::thermoCoupleProbes::write()
{
if (!pointField::empty())
if (!prober().empty())
{
(void) prepare(ACTION_WRITE);
@ -182,7 +184,7 @@ bool Foam::functionObjects::thermoCoupleProbes::write()
bool Foam::functionObjects::thermoCoupleProbes::execute()
{
if (!pointField::empty())
if (!prober().empty())
{
scalar dt = mesh_.time().deltaTValue();
scalar t = mesh_.time().value();

View File

@ -42,7 +42,8 @@ void Foam::functionObjects::thermoCoupleProbes::writeValues
os << setw(w) << timeValue;
forAll(*this, probei)
const pointField& probes = prober().probeLocations();
forAll(probes, probei)
{
// if (includeOutOfBounds_ || processor_[probei] != -1)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,6 @@
probes/probers/prober.C
probes/probers/internalProber/internalProber.C
probes/probers/patchProber/patchProber.C
probes/probes.C
probes/patchProbes.C

View File

@ -0,0 +1,453 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "Probes.H"
#include "IOmanip.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "SpanStream.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Prober>
void Foam::Probes<Prober>::createProbeFiles(const wordList& fieldNames)
{
// Open new output streams
bool needsNewFiles = false;
for (const word& fieldName : fieldNames)
{
if (!probeFilePtrs_.found(fieldName))
{
needsNewFiles = true;
break;
}
}
if (needsNewFiles && Pstream::master())
{
DebugInfo
<< "Probing fields: " << fieldNames << nl
<< "Probing locations: " << prober_.probeLocations() << nl
<< endl;
// Put in undecomposed case
// (Note: gives problems for distributed data running)
fileName probeDir
(
mesh_.time().globalPath()
/ functionObject::outputPrefix
/ name()/mesh_.regionName()
// Use startTime as the instance for output files
/ mesh_.time().timeName(mesh_.time().startTime().value())
);
probeDir.clean(); // Remove unneeded ".."
// Create directory if needed
Foam::mkDir(probeDir);
for (const word& fieldName : fieldNames)
{
if (probeFilePtrs_.found(fieldName))
{
// Safety
continue;
}
auto osPtr = autoPtr<OFstream>::New(probeDir/fieldName);
auto& os = *osPtr;
if (!os.good())
{
FatalErrorInFunction
<< "Cannot open probe output file: " << os.name() << nl
<< exit(FatalError);
}
probeFilePtrs_.insert(fieldName, osPtr);
DebugInfo<< "open probe stream: " << os.name() << endl;
const unsigned int width(IOstream::defaultPrecision() + 7);
os.setf(std::ios_base::left);
const pointField& probeLocs = prober_.probeLocations();
const labelList& processors = prober_.processors();
const labelList& patchIDList = prober_.patchIDList();
const pointField& oldPoints = prober_.oldPoints();
forAll(probeLocs, probei)
{
os << "# Probe " << probei << ' ' << probeLocs[probei];
if (processors[probei] == -1)
{
os << " # Not Found";
}
else if (probei < patchIDList.size())
{
const label patchi = patchIDList[probei];
if (patchi != -1)
{
const polyBoundaryMesh& bm = mesh_.boundaryMesh();
if
(
patchi < bm.nNonProcessor()
|| processors[probei] == Pstream::myProcNo()
)
{
os << " at patch " << bm[patchi].name();
}
os << " with a distance of "
<< mag(probeLocs[probei]-oldPoints[probei])
<< " m to the original point "
<< oldPoints[probei];
}
}
os << nl;
}
os << setw(width) << "# Time";
forAll(probeLocs, probei)
{
if (prober_.includeOutOfBounds() || processors[probei] != -1)
{
os << ' ' << setw(width) << probei;
}
}
os << endl;
}
}
}
template<class Prober>
template<class Type>
void Foam::Probes<Prober>::writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
)
{
if (Pstream::master())
{
const unsigned int width(IOstream::defaultPrecision() + 7);
OFstream& os = *probeFilePtrs_[fieldName];
os << setw(width) << timeValue;
OCharStream buf;
const bool includeOutOfBounds = prober_.includeOutOfBounds();
const labelList& procs = prober_.processors();
forAll(values, probei)
{
if (includeOutOfBounds || procs[probei] != -1)
{
buf.rewind();
buf << values[probei];
os << ' ' << setw(width) << buf.str().data();
}
}
os << endl;
}
}
template<class Prober>
template<class GeoField>
void Foam::Probes<Prober>::performAction
(
const fieldGroup<GeoField>& fieldNames,
unsigned request
)
{
for (const word& fieldName : fieldNames)
{
tmp<GeoField> tfield = getOrLoadField<GeoField>(fieldName);
if (tfield)
{
const auto& field = tfield();
const scalar timeValue = field.time().timeOutputValue();
Field<typename GeoField::value_type> values(prober_.sample(field));
this->storeResults(fieldName, values);
if (request & ACTION_WRITE)
{
this->writeValues(fieldName, values, timeValue);
}
}
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Prober>
Foam::label Foam::Probes<Prober>::prepare(unsigned request)
{
// Prefilter on selection
HashTable<wordHashSet> selected =
(
loadFromFiles_
? IOobjectList(mesh_, mesh_.time().timeName()).classes(fieldSelection_)
: mesh_.classes(fieldSelection_)
);
// Classify and count fields
label nFields = 0;
do
{
#undef doLocalCode
#define doLocalCode(InputType, Target) \
{ \
Target.clear(); /* Remove old values */ \
const auto iter = selected.cfind(InputType::typeName); \
if (iter.good()) \
{ \
/* Add new (current) values */ \
Target.append(iter.val().sortedToc()); \
nFields += Target.size(); \
} \
}
doLocalCode(volScalarField, scalarFields_);
doLocalCode(volVectorField, vectorFields_);
doLocalCode(volSphericalTensorField, sphericalTensorFields_);
doLocalCode(volSymmTensorField, symmTensorFields_);
doLocalCode(volTensorField, tensorFields_);
doLocalCode(surfaceScalarField, surfaceScalarFields_);
doLocalCode(surfaceVectorField, surfaceVectorFields_);
doLocalCode(surfaceSphericalTensorField, surfaceSphericalTensorFields_);
doLocalCode(surfaceSymmTensorField, surfaceSymmTensorFields_);
doLocalCode(surfaceTensorField, surfaceTensorFields_);
#undef doLocalCode
}
while (false);
// Adjust file streams
if (Pstream::master())
{
wordHashSet currentFields(2*nFields);
currentFields.insert(scalarFields_);
currentFields.insert(vectorFields_);
currentFields.insert(sphericalTensorFields_);
currentFields.insert(symmTensorFields_);
currentFields.insert(tensorFields_);
currentFields.insert(surfaceScalarFields_);
currentFields.insert(surfaceVectorFields_);
currentFields.insert(surfaceSphericalTensorFields_);
currentFields.insert(surfaceSymmTensorFields_);
currentFields.insert(surfaceTensorFields_);
DebugInfo
<< "Probing fields: " << currentFields << nl
<< "Probing locations: " << prober_.probeLocations() << nl
<< endl;
// Close streams for fields that no longer exist
forAllIters(probeFilePtrs_, iter)
{
if (!currentFields.erase(iter.key()))
{
DebugInfo<< "close probe stream: " << iter()->name() << endl;
probeFilePtrs_.remove(iter);
}
}
if ((request & ACTION_WRITE) && !currentFields.empty())
{
createProbeFiles(currentFields.sortedToc());
}
}
return nFields;
}
template<class Prober>
template<class GeoField>
Foam::tmp<GeoField>
Foam::Probes<Prober>::getOrLoadField(const word& fieldName) const
{
tmp<GeoField> tfield;
if (loadFromFiles_)
{
tfield.emplace
(
IOobject
(
fieldName,
mesh_.time().timeName(),
mesh_.thisDb(),
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
),
mesh_
);
}
else
{
tfield.cref(mesh_.cfindObject<GeoField>(fieldName));
}
return tfield;
}
template<class Prober>
template<class Type>
void Foam::Probes<Prober>::storeResults
(
const word& fieldName,
const Field<Type>& values
)
{
const MinMax<Type> limits(values);
const Type avgVal = average(values);
this->setResult("average(" + fieldName + ")", avgVal);
this->setResult("min(" + fieldName + ")", limits.min());
this->setResult("max(" + fieldName + ")", limits.max());
this->setResult("size(" + fieldName + ")", values.size());
if (verbose_)
{
Info<< name() << " : " << fieldName << nl
<< " avg: " << avgVal << nl
<< " min: " << limits.min() << nl
<< " max: " << limits.max() << nl << nl;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Prober>
Foam::Probes<Prober>::Probes
(
const word& name,
const Time& runTime,
const dictionary& dict,
const bool loadFromFiles,
const bool readFields
)
:
functionObjects::fvMeshFunctionObject(name, runTime, dict),
prober_(mesh_, dict),
loadFromFiles_(loadFromFiles),
onExecute_(false),
fieldSelection_()
{
if (readFields)
{
read(dict);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Prober>
bool Foam::Probes<Prober>::verbose(const bool on) noexcept
{
bool old(verbose_);
verbose_ = on;
return old;
}
template<class Prober>
bool Foam::Probes<Prober>::read(const dictionary& dict)
{
dict.readEntry("fields", fieldSelection_);
verbose_ = dict.getOrDefault("verbose", false);
onExecute_ = dict.getOrDefault("sampleOnExecute", false);
// Close old (unused) streams
prepare(ACTION_NONE);
return true;
}
template<class Prober>
bool Foam::Probes<Prober>::performAction(unsigned request)
{
if (!prober_.empty() && request && prepare(request))
{
performAction(scalarFields_, request);
performAction(vectorFields_, request);
performAction(sphericalTensorFields_, request);
performAction(symmTensorFields_, request);
performAction(tensorFields_, request);
performAction(surfaceScalarFields_, request);
performAction(surfaceVectorFields_, request);
performAction(surfaceSphericalTensorFields_, request);
performAction(surfaceSymmTensorFields_, request);
performAction(surfaceTensorFields_, request);
}
return true;
}
template<class Prober>
bool Foam::Probes<Prober>::execute()
{
if (onExecute_)
{
return performAction(ACTION_ALL & ~ACTION_WRITE);
}
return true;
}
template<class Prober>
bool Foam::Probes<Prober>::write()
{
return performAction(ACTION_ALL);
}
// ************************************************************************* //

View File

@ -0,0 +1,238 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::Probes
Description
Base class for sampling fields at specified locations and writing to file.
The locations are specified and determined in the derived class. The
sampling is done using the specified point prober class.
SourceFiles
Probes.C
ProbesTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_Probes_H
#define Foam_Probes_H
#include "fvMeshFunctionObject.H"
#include "polyMesh.H"
#include "HashPtrTable.H"
#include "OFstream.H"
#include "volFieldsFwd.H"
#include "surfaceFieldsFwd.H"
#include "prober.H"
#include "IOobjectList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class Probes Declaration
\*---------------------------------------------------------------------------*/
template<class Prober>
class Probes
:
public functionObjects::fvMeshFunctionObject
{
protected:
// Protected Data
//- The specified point prober
Prober prober_;
// Protected Classes
//- Grouping of field names by GeometricField type
template<class GeoField>
struct fieldGroup : public DynamicList<word> {};
// Data Types
//- Local control for sampling actions
enum sampleActionType : unsigned
{
ACTION_NONE = 0,
ACTION_WRITE = 0x1,
ACTION_STORE = 0x2,
ACTION_ALL = 0xF
};
// Protected Data
//- Load fields from files (not from objectRegistry)
bool loadFromFiles_;
//- Output verbosity
bool verbose_;
//- Perform sample actions on execute as well
bool onExecute_;
//- Requested names of fields to probe
wordRes fieldSelection_;
// Calculated
//- Current list of field names selected for sampling
DynamicList<word> selectedFieldNames_;
//- Categorized scalar/vector/tensor volume fields
fieldGroup<volScalarField> scalarFields_;
fieldGroup<volVectorField> vectorFields_;
fieldGroup<volSphericalTensorField> sphericalTensorFields_;
fieldGroup<volSymmTensorField> symmTensorFields_;
fieldGroup<volTensorField> tensorFields_;
//- Categorized scalar/vector/tensor surface fields
fieldGroup<surfaceScalarField> surfaceScalarFields_;
fieldGroup<surfaceVectorField> surfaceVectorFields_;
fieldGroup<surfaceSphericalTensorField> surfaceSphericalTensorFields_;
fieldGroup<surfaceSymmTensorField> surfaceSymmTensorFields_;
fieldGroup<surfaceTensorField> surfaceTensorFields_;
//- Current open files (non-empty on master only)
HashPtrTable<OFstream> probeFilePtrs_;
// Protected Member Functions
//- Classify field types, close/open file streams
// \return number of fields to sample
label prepare(unsigned request);
//- Get from registry or load from disk
template<class GeoField>
tmp<GeoField> getOrLoadField(const word& fieldName) const;
//- Store results: min/max/average/size
template<class Type>
void storeResults(const word& fieldName, const Field<Type>& values);
private:
// Private Member Functions
//- Create new streams as required
void createProbeFiles(const wordList& fieldNames);
//- Write field values
template<class Type>
void writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
);
//- Sample and store/write all applicable sampled fields
template<class GeoField>
void performAction
(
const fieldGroup<GeoField>& fieldNames, /* must be sorted */
unsigned request
);
//- Perform sampling action with store/write
bool performAction(unsigned request);
public:
// Constructors
//- Construct from Time and dictionary
Probes
(
const word& name,
const Time& runTime,
const dictionary& dict,
const bool loadFromFiles = false,
const bool readFields = true
);
//- Destructor
virtual ~Probes() = default;
// Member Functions
//- Enable/disable verbose output
// \return old value
bool verbose(const bool on) noexcept;
//- Return names of fields to probe
virtual const wordRes& fieldNames() const noexcept
{
return fieldSelection_;
}
//- Return const reference to the point prober
const Prober& prober() const noexcept { return prober_; }
//- Read the settings from the dictionary
virtual bool read(const dictionary&);
//- Sample and store result if the sampleOnExecute is enabled.
virtual bool execute();
//- Sample and write
virtual bool write();
//- Update for changes of mesh due to readUpdate
virtual void readUpdate(const polyMesh::readUpdateState state)
{}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "Probes.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,11 +27,6 @@ License
\*---------------------------------------------------------------------------*/
#include "patchProbes.H"
#include "volFields.H"
#include "IOmanip.H"
#include "mappedPatchBase.H"
#include "treeBoundBox.H"
#include "treeDataFace.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -39,7 +34,6 @@ License
namespace Foam
{
defineTypeNameAndDebug(patchProbes, 0);
addToRunTimeSelectionTable
(
functionObject,
@ -48,179 +42,6 @@ namespace Foam
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::patchProbes::findElements(const fvMesh& mesh)
{
(void)mesh.tetBasePtIs();
const polyBoundaryMesh& bm = mesh.boundaryMesh();
// All the info for nearest. Construct to miss
List<mappedPatchBase::nearInfo> nearest(this->size());
const labelList patchIDs(bm.patchSet(patchNames_).sortedToc());
label nFaces = 0;
forAll(patchIDs, i)
{
nFaces += bm[patchIDs[i]].size();
}
if (nFaces > 0)
{
// Collect mesh faces and bounding box
labelList bndFaces(nFaces);
treeBoundBox overallBb;
nFaces = 0;
forAll(patchIDs, i)
{
const polyPatch& pp = bm[patchIDs[i]];
forAll(pp, i)
{
bndFaces[nFaces++] = pp.start()+i;
const face& f = pp[i];
// Without reduction.
overallBb.add(pp.points(), f);
}
}
Random rndGen(123456);
overallBb.inflate(rndGen, 1e-4, ROOTVSMALL);
const indexedOctree<treeDataFace> boundaryTree
(
treeDataFace(mesh, bndFaces), // patch faces only
overallBb, // overall search domain
8, // maxLevel
10, // leafsize
3.0 // duplicity
);
forAll(probeLocations(), probei)
{
const auto& treeData = boundaryTree.shapes();
const point sample = probeLocations()[probei];
pointIndexHit info = boundaryTree.findNearest
(
sample,
Foam::sqr(boundaryTree.bb().mag())
);
if (!info.hit())
{
info = boundaryTree.findNearest(sample, Foam::sqr(GREAT));
}
const label facei = treeData.objectIndex(info.index());
const label patchi = bm.whichPatch(facei);
if (isA<emptyPolyPatch>(bm[patchi]))
{
WarningInFunction
<< " The sample point: " << sample
<< " belongs to " << patchi
<< " which is an empty patch. This is not permitted. "
<< " This sample will not be included "
<< endl;
}
else if (info.hit())
{
// Note: do we store the face centre or the actual nearest?
// We interpolate using the faceI only though (no
// interpolation) so it does not actually matter much, just for
// the location written to the header.
//const point& facePt = mesh.faceCentres()[faceI];
const point& facePt = info.point();
mappedPatchBase::nearInfo sampleInfo;
sampleInfo.first() = pointIndexHit(true, facePt, facei);
sampleInfo.second().first() = facePt.distSqr(sample);
sampleInfo.second().second() = Pstream::myProcNo();
nearest[probei] = sampleInfo;
}
}
}
// Find nearest - globally consistent
Pstream::listCombineReduce(nearest, mappedPatchBase::nearestEqOp());
oldPoints_.resize(this->size());
// Update actual probe locations and store old ones
forAll(nearest, samplei)
{
oldPoints_[samplei] = operator[](samplei);
operator[](samplei) = nearest[samplei].first().point();
}
if (debug)
{
InfoInFunction << nl;
forAll(nearest, samplei)
{
label proci = nearest[samplei].second().second();
label locali = nearest[samplei].first().index();
Info<< " " << samplei << " coord:"<< operator[](samplei)
<< " found on processor:" << proci
<< " in local face:" << locali
<< " with location:" << nearest[samplei].first().point()
<< endl;
}
}
// Extract any local faces to sample:
// - operator[] : actual point to sample (=nearest point on patch)
// - oldPoints_ : original provided point (might be anywhere in the mesh)
// - elementList_ : cells, not used
// - faceList_ : faces (now patch faces)
// - patchIDList_ : patch corresponding to faceList
// - processor_ : processor
elementList_.resize_nocopy(nearest.size());
elementList_ = -1;
faceList_.resize_nocopy(nearest.size());
faceList_ = -1;
processor_.resize_nocopy(nearest.size());
processor_ = -1;
patchIDList_.resize_nocopy(nearest.size());
patchIDList_ = -1;
forAll(nearest, sampleI)
{
processor_[sampleI] = nearest[sampleI].second().second();
if (nearest[sampleI].second().second() == Pstream::myProcNo())
{
// Store the face to sample
faceList_[sampleI] = nearest[sampleI].first().index();
const label facei = faceList_[sampleI];
if (facei != -1)
{
processor_[sampleI] = Pstream::myProcNo();
patchIDList_[sampleI] = bm.whichPatch(facei);
}
}
reduce(processor_[sampleI], maxOp<label>());
reduce(patchIDList_[sampleI], maxOp<label>());
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchProbes::patchProbes
@ -232,7 +53,14 @@ Foam::patchProbes::patchProbes
const bool readFields
)
:
probes(name, runTime, dict, loadFromFiles, false)
Base
(
name,
runTime,
dict,
loadFromFiles,
readFields
)
{
if (readFields)
{
@ -243,52 +71,13 @@ Foam::patchProbes::patchProbes
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::patchProbes::performAction(unsigned request)
{
if (!pointField::empty() && request && prepare(request))
{
performAction(scalarFields_, request);
performAction(vectorFields_, request);
performAction(sphericalTensorFields_, request);
performAction(symmTensorFields_, request);
performAction(tensorFields_, request);
performAction(surfaceScalarFields_, request);
performAction(surfaceVectorFields_, request);
performAction(surfaceSphericalTensorFields_, request);
performAction(surfaceSymmTensorFields_, request);
performAction(surfaceTensorFields_, request);
}
return true;
}
bool Foam::patchProbes::execute()
{
if (onExecute_)
{
return performAction(ACTION_ALL & ~ACTION_WRITE);
}
return true;
}
bool Foam::patchProbes::write()
{
return performAction(ACTION_ALL);
}
bool Foam::patchProbes::read(const dictionary& dict)
{
if (!dict.readIfPresent("patches", patchNames_))
if (!(Probes::read(dict) && prober_.read(dict)))
{
patchNames_.resize(1);
patchNames_.first() = dict.get<word>("patch");
return false;
}
return probes::read(dict);
return true;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,52 +28,71 @@ Class
Foam::patchProbes
Description
Set of locations to sample at patches
Probes the specified points on specified patches. The points get snapped
onto the nearest point on the nearest face of the specified patch, and the
sampling is actioned on the snapped locations.
Call write() to sample and write files.
- find nearest location on nearest face
- update *this with location (so header contains 'snapped' locations
- use *this as the sampling location
Example of function object specification:
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
patchProbes
{
// Mandatory entries
type patchProbes;
libs (sampling);
// Name of the directory for probe data
name patchProbes;
fields (<wordRes>);
probeLocations (<vectorList>);
patches (<wordRes>); // or patch <word>;
// Patches to sample (wildcards allowed)
patches (".*inl.*");
// Optional entries
verbose <bool>;
sampleOnExecute <bool>;
fixedLocations <bool>;
includeOutOfBounds <bool>;
interpolationScheme <word>;
// Write at same frequency as fields
writeControl writeTime;
writeInterval 1;
// Fields to be probed
fields (p U);
// Locations to probe. These get snapped onto the nearest point
// on the selected patches
probeLocations
(
( -100 0 0.01 ) // at inlet
);
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: patchProbes | word | yes | -
libs | Library name: sampling | word | yes | -
fields | Names of the fields to be probed | wordRes | yes | -
probeLocations | Locations of the probes | vectorField | yes | -
patches | Patches to sample (wildcards allowed) | wordRes | yes | -
verbose | Enable/disable verbose output | bool | no | false
sampleOnExecute | Sample on execution and store results | bool | no <!--
--> | false
fixedLocations | Do not recalculate cells if mesh moves | bool | no | true
includeOutOfBounds | Include out-of-bounds locations | bool | no | true
interpolationScheme | Scheme to obtain values at the points | word <!--
--> | no | cell
\endtable
The inherited entries are elaborated in:
- \link fvMeshFunctionObject.H \endlink
- \link Probes.H \endlink
- \link patchProber.H \endlink
- \link prober.H \endlink
Note
- The \c includeOutOfBounds filters out points that haven't been found.
Default is to include them (with value \c -VGREAT).
SourceFiles
patchProbes.C
patchProbesTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_patchProbes_H
#define Foam_patchProbes_H
#include "probes.H"
#include "Probes.H"
#include "patchProber.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -81,57 +100,17 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class patchProbes Declaration
Class patchProbes Declaration
\*---------------------------------------------------------------------------*/
class patchProbes
:
public probes
public Probes<patchProber>
{
protected:
// Private Data
// Protected Data
//- Patches to sample
wordRes patchNames_;
// Protected Member Functions
//- Find elements containing patchProbes
virtual void findElements(const fvMesh& mesh); // override
private:
// Private Member Functions
//- Write field values
template<class Type>
void writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
);
//- Sample and store/write applicable volume/surface fields
template<class GeoField>
void performAction
(
const fieldGroup<GeoField>& fieldNames, /* must be sorted */
unsigned request
);
//- Perform sampling action with store/write
bool performAction(unsigned request);
//- No copy construct
patchProbes(const patchProbes&) = delete;
//- No copy assignment
void operator=(const patchProbes&) = delete;
//- Use simpler synonym for the base type
using Base = Probes<patchProber>;
public:
@ -142,7 +121,7 @@ public:
// Constructors
//- Construct from Time and dictionary
//- Construct from name, Time and dictionary
patchProbes
(
const word& name,
@ -152,54 +131,26 @@ public:
const bool readFields = true
);
//- Destructor
virtual ~patchProbes() = default;
// Member Functions
//- Sample and store result if the sampleOnExecute is enabled.
virtual bool execute();
//- Bring Base::prober into this class's public scope.
using Base::prober;
//- Sample and write
virtual bool write();
//- Read
//- Read the settings from the dictionary
virtual bool read(const dictionary&);
// Sampling
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const VolumeField<Type>&) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sample(const SurfaceField<Type>&) const;
//- Sample a single field on all sample locations
template<class Type>
tmp<Field<Type>> sample(const word& fieldName) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sampleSurfaceField(const word& fieldName) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "patchProbesTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,188 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "internalProber.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(internalProber, 0);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::internalProber::findElements(const fvMesh& mesh)
{
DebugInfo<< "internalProber: resetting sample locations" << endl;
const pointField& probeLocations = this->probeLocations();
cellIds_.resize_nocopy(probeLocations.size());
faceIds_.resize_nocopy(probeLocations.size());
procIds_.resize_nocopy(probeLocations.size());
procIds_ = -1;
forAll(probeLocations, probei)
{
const point& location = probeLocations[probei];
const label celli = mesh.findCell(location);
cellIds_[probei] = celli;
if (celli != -1)
{
const labelList& cellFaces = mesh.cells()[celli];
const vector& cellCentre = mesh.cellCentres()[celli];
scalar minDistance = GREAT;
label minFaceID = -1;
forAll(cellFaces, i)
{
label facei = cellFaces[i];
vector dist = mesh.faceCentres()[facei] - cellCentre;
if (mag(dist) < minDistance)
{
minDistance = mag(dist);
minFaceID = facei;
}
}
faceIds_[probei] = minFaceID;
}
else
{
faceIds_[probei] = -1;
}
if (debug && (cellIds_[probei] != -1 || faceIds_[probei] != -1))
{
Pout<< "internalProber : found point " << location
<< " in cell " << cellIds_[probei]
<< " and face " << faceIds_[probei] << endl;
}
}
// Check if all probes have been found.
forAll(cellIds_, probei)
{
const point& location = probeLocations[probei];
label celli = cellIds_[probei];
label facei = faceIds_[probei];
procIds_[probei] = (celli != -1 ? Pstream::myProcNo() : -1);
// Check at least one processor with cell.
reduce(celli, maxOp<label>());
reduce(facei, maxOp<label>());
reduce(procIds_[probei], maxOp<label>());
if (celli == -1)
{
if (Pstream::master())
{
WarningInFunction
<< "Did not find location " << location
<< " in any cell. Skipping location." << endl;
}
}
else if (facei == -1)
{
if (Pstream::master())
{
WarningInFunction
<< "Did not find location " << location
<< " in any face. Skipping location." << endl;
}
}
else
{
// Make sure location not on two domains.
if (cellIds_[probei] != -1 && cellIds_[probei] != celli)
{
WarningInFunction
<< "Location " << location
<< " seems to be on multiple domains:"
<< " cell " << cellIds_[probei]
<< " on my domain " << Pstream::myProcNo()
<< " and cell " << celli << " on some other domain."
<< nl
<< "This might happen if the probe location is on"
<< " a processor patch. Change the location slightly"
<< " to prevent this." << endl;
}
if (faceIds_[probei] != -1 && faceIds_[probei] != facei)
{
WarningInFunction
<< "Location " << location
<< " seems to be on multiple domains:"
<< " cell " << faceIds_[probei]
<< " on my domain " << Pstream::myProcNo()
<< " and face " << facei << " on some other domain."
<< nl
<< "This might happen if the probe location is on"
<< " a processor patch. Change the location slightly"
<< " to prevent this." << endl;
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::internalProber::internalProber
(
const fvMesh& mesh,
const dictionary& dict
)
:
prober(mesh, dict)
{
read(dict);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::internalProber::read(const dictionary& dict)
{
if (!prober::read(dict))
{
return false;
}
// Initialise cells to sample from supplied locations
findElements(mesh_);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,140 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::internalProber
Description
A utility class for probing field values at specified point locations
within an \c fvMesh.
The \c internalProber stores a list of 3D point coordinates and
determines the corresponding mesh elements (cells or faces) that contain
these points. It provides methods to sample volume or surface fields at
the stored locations, with support for fixed or mesh-moving point
coordinates.
Features include:
- Reading probe locations and settings from a dictionary
- Support for fixed or moving locations (for dynamic mesh cases)
- Optional inclusion of points that lie outside of the mesh domain
- Selection of interpolation/sampling schemes for fixed locations
- Sampling of volume and surface fields by name or by direct reference
- Automatic update of element mapping when the mesh changes or moves
SourceFiles
internalProber.C
internalProberTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_internalProber_H
#define Foam_internalProber_H
#include "prober.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class internalProber Declaration
\*---------------------------------------------------------------------------*/
class internalProber
:
public prober
{
protected:
// Protected Member Functions
//- Find cells and faces containing probes
virtual void findElements(const fvMesh& mesh);
public:
//- Runtime type information
TypeName("internalProber");
// Constructors
//- Construct from Time and dictionary
internalProber
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~internalProber() = default;
// Member Functions
// Sampling
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const VolumeField<Type>&) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sample(const SurfaceField<Type>&) const;
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const word& fieldName) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sampleSurfaceField(const word& fieldName) const;
// I-O
//- Read the settings dictionary
virtual bool read(const dictionary&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "internalProberTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "internalProber.H"
#include "interpolation.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::internalProber::sample(const VolumeField<Type>& vField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
auto tvalues = tmp<Field<Type>>::New(Field<Type>(this->size(), unsetVal));
auto& values = tvalues.ref();
if (fixedLocations_)
{
autoPtr<interpolation<Type>> interpPtr
(
interpolation<Type>::New(samplePointScheme_, vField)
);
const pointField& probeLocations = this->probeLocations();
forAll(probeLocations, probei)
{
if (cellIds_[probei] >= 0)
{
const vector& position = probeLocations[probei];
values[probei] = interpPtr().interpolate
(
position,
cellIds_[probei],
-1
);
}
}
}
else
{
forAll(*this, probei)
{
if (cellIds_[probei] >= 0)
{
values[probei] = vField[cellIds_[probei]];
}
}
}
Pstream::listCombineReduce(values, isNotEqOp<Type>());
return tvalues;
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::internalProber::sample(const SurfaceField<Type>& sField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
auto tvalues = tmp<Field<Type>>::New(Field<Type>(this->size(), unsetVal));
auto& values = tvalues.ref();
const pointField& probeLocations = this->probeLocations();
forAll(probeLocations, probei)
{
if (faceIds_[probei] >= 0)
{
values[probei] = sField[faceIds_[probei]];
}
}
Pstream::listCombineReduce(values, isNotEqOp<Type>());
return tvalues;
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::internalProber::sample(const word& fieldName) const
{
return sample(mesh_.lookupObject<VolumeField<Type>>(fieldName));
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::internalProber::sampleSurfaceField(const word& fieldName) const
{
return sample(mesh_.lookupObject<SurfaceField<Type>>(fieldName));
}
// ************************************************************************* //

View File

@ -0,0 +1,252 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-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 "patchProber.H"
#include "mappedPatchBase.H"
#include "treeBoundBox.H"
#include "treeDataFace.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(patchProber, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::patchProber::findElements(const fvMesh& mesh)
{
(void)mesh.tetBasePtIs();
const polyBoundaryMesh& bm = mesh.boundaryMesh();
// All the info for nearest. Construct to miss
List<mappedPatchBase::nearInfo> nearest(this->size());
patchIDs_ = bm.patchSet(patchNames_).sortedToc();
label nFaces = 0;
forAll(patchIDs_, i)
{
nFaces += bm[patchIDs_[i]].size();
}
if (nFaces > 0)
{
// Collect mesh faces and bounding box
labelList bndFaces(nFaces);
treeBoundBox overallBb;
nFaces = 0;
forAll(patchIDs_, i)
{
const polyPatch& pp = bm[patchIDs_[i]];
forAll(pp, i)
{
bndFaces[nFaces++] = pp.start()+i;
const face& f = pp[i];
// Without reduction.
overallBb.add(pp.points(), f);
}
}
Random rndGen(123456);
overallBb.inflate(rndGen, 1e-4, ROOTVSMALL);
const indexedOctree<treeDataFace> boundaryTree
(
treeDataFace(mesh, bndFaces), // patch faces only
overallBb, // overall search domain
8, // maxLevel
10, // leafsize
3.0 // duplicity
);
forAll(probeLocations(), probei)
{
const auto& treeData = boundaryTree.shapes();
const point sample = probeLocations()[probei];
pointIndexHit info = boundaryTree.findNearest
(
sample,
Foam::sqr(boundaryTree.bb().mag())
);
if (!info.hit())
{
info = boundaryTree.findNearest(sample, Foam::sqr(GREAT));
}
const label facei = treeData.objectIndex(info.index());
const label patchi = bm.whichPatch(facei);
if (isA<emptyPolyPatch>(bm[patchi]))
{
WarningInFunction
<< " The sample point: " << sample
<< " belongs to " << patchi
<< " which is an empty patch. This is not permitted. "
<< " This sample will not be included "
<< endl;
}
else if (info.hit())
{
// Note: do we store the face centre or the actual nearest?
// We interpolate using the faceI only though (no
// interpolation) so it does not actually matter much, just for
// the location written to the header.
//const point& facePt = mesh.faceCentres()[faceI];
const point& facePt = info.point();
mappedPatchBase::nearInfo sampleInfo;
sampleInfo.first() = pointIndexHit(true, facePt, facei);
sampleInfo.second().first() = facePt.distSqr(sample);
sampleInfo.second().second() = Pstream::myProcNo();
nearest[probei] = sampleInfo;
}
}
}
// Find nearest - globally consistent
Pstream::listCombineReduce(nearest, mappedPatchBase::nearestEqOp());
oldPoints_.resize(this->size());
pointField& probeLocations = this->probeLocations();
// Update actual probe locations and store old ones
forAll(nearest, samplei)
{
oldPoints_[samplei] = probeLocations[samplei];
probeLocations[samplei] = nearest[samplei].first().point();
}
if (debug)
{
InfoInFunction << nl;
forAll(nearest, samplei)
{
label proci = nearest[samplei].second().second();
label locali = nearest[samplei].first().index();
Info<< " " << samplei << " coord:"<< probeLocations[samplei]
<< " found on processor:" << proci
<< " in local face:" << locali
<< " with location:" << nearest[samplei].first().point()
<< endl;
}
}
// Extract any local faces to sample:
// - operator[] : actual point to sample (=nearest point on patch)
// - oldPoints_ : original provided point (might be anywhere in the mesh)
// - cellIds_ : cells, not used
// - faceIds_ : faces (now patch faces)
// - patchIds_ : patch corresponding to faceList
// - procIds_ : processor
cellIds_.resize_nocopy(nearest.size());
cellIds_ = -1;
faceIds_.resize_nocopy(nearest.size());
faceIds_ = -1;
procIds_.resize_nocopy(nearest.size());
procIds_ = -1;
patchIds_.resize_nocopy(nearest.size());
patchIds_ = -1;
forAll(nearest, sampleI)
{
procIds_[sampleI] = nearest[sampleI].second().second();
if (nearest[sampleI].second().second() == Pstream::myProcNo())
{
// Store the face to sample
faceIds_[sampleI] = nearest[sampleI].first().index();
const label facei = faceIds_[sampleI];
if (facei != -1)
{
procIds_[sampleI] = Pstream::myProcNo();
patchIds_[sampleI] = bm.whichPatch(facei);
}
}
reduce(procIds_[sampleI], maxOp<label>());
reduce(patchIds_[sampleI], maxOp<label>());
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchProber::patchProber
(
const fvMesh& mesh,
const dictionary& dict
)
:
prober(mesh, dict)
{
read(dict);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::patchProber::read(const dictionary& dict)
{
if (!prober::read(dict))
{
return false;
}
if (!dict.readIfPresent("patches", patchNames_))
{
patchNames_.resize(1);
patchNames_.first() = dict.get<word>("patch");
}
// Initialise cells to sample from supplied locations
findElements(mesh_);
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,152 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::patchProber
Description
Utility class for probing specified points on user-selected boundary
patches. The input points are projected onto the nearest point of the
nearest face on the specified patch, ensuring sampling occurs at valid
patch locations.
The patchProber enables sampling of both volume and surface fields
at these snapped locations. Patch selection is controlled via patch names or
indices, and the class provides runtime selection and dictionary-driven
configuration.
Typical usage involves specifying patch names and probe locations in a
dictionary, after which the class manages the mapping and sampling
operations.
SourceFiles
patchProber.C
patchProberTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_patchProber_H
#define Foam_patchProber_H
#include "prober.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class patchProber Declaration
\*---------------------------------------------------------------------------*/
class patchProber
:
public prober
{
protected:
// Protected Data
//- Names of the patches to sample
wordRes patchNames_;
//- Index of the patches to sample
labelList patchIDs_;
// Protected Member Functions
//- Find elements containing patchProber
virtual void findElements(const fvMesh& mesh);
public:
//- Runtime type information
TypeName("patchProber");
// Constructors
//- Construct from Time and dictionary
patchProber
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~patchProber() = default;
// Member Functions
// Access
//- Return the index of the patches to sample
const labelList& patchIDs() const noexcept { return patchIDs_; }
// Sampling
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const VolumeField<Type>&) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sample(const SurfaceField<Type>&) const;
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const word& fieldName) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sampleSurfaceField(const word& fieldName) const;
// I-O
//- Read the settings dictionary
virtual bool read(const dictionary&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "patchProberTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,8 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,70 +25,15 @@ License
\*---------------------------------------------------------------------------*/
#include "patchProbes.H"
#include "patchProber.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
void Foam::patchProbes::writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
)
{
if (Pstream::master())
{
const unsigned int w = IOstream::defaultPrecision() + 7;
OFstream& os = *probeFilePtrs_[fieldName];
os << setw(w) << timeValue;
for (const auto& v : values)
{
os << ' ' << setw(w) << v;
}
os << endl;
}
}
template<class GeoField>
void Foam::patchProbes::performAction
(
const fieldGroup<GeoField>& fieldNames,
unsigned request
)
{
for (const word& fieldName : fieldNames)
{
tmp<GeoField> tfield = getOrLoadField<GeoField>(fieldName);
if (tfield)
{
const auto& field = tfield();
const scalar timeValue = field.time().timeOutputValue();
Field<typename GeoField::value_type> values(sample(field));
this->storeResults(fieldName, values);
if (request & ACTION_WRITE)
{
this->writeValues(fieldName, values, timeValue);
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::patchProbes::sample(const VolumeField<Type>& vField) const
Foam::patchProber::sample(const VolumeField<Type>& vField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
@ -101,7 +45,7 @@ Foam::patchProbes::sample(const VolumeField<Type>& vField) const
forAll(*this, probei)
{
label facei = faceList_[probei];
label facei = faceIds_[probei];
if (facei >= 0)
{
@ -119,7 +63,7 @@ Foam::patchProbes::sample(const VolumeField<Type>& vField) const
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::patchProbes::sample(const SurfaceField<Type>& sField) const
Foam::patchProber::sample(const SurfaceField<Type>& sField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
@ -131,7 +75,7 @@ Foam::patchProbes::sample(const SurfaceField<Type>& sField) const
forAll(*this, probei)
{
label facei = faceList_[probei];
label facei = faceIds_[probei];
if (facei >= 0)
{
@ -149,7 +93,7 @@ Foam::patchProbes::sample(const SurfaceField<Type>& sField) const
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::patchProbes::sample(const word& fieldName) const
Foam::patchProber::sample(const word& fieldName) const
{
return sample(mesh_.lookupObject<VolumeField<Type>>(fieldName));
}
@ -157,7 +101,7 @@ Foam::patchProbes::sample(const word& fieldName) const
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::patchProbes::sampleSurfaceField(const word& fieldName) const
Foam::patchProber::sampleSurfaceField(const word& fieldName) const
{
return sample(mesh_.lookupObject<SurfaceField<Type>>(fieldName));
}

View File

@ -0,0 +1,188 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "prober.H"
#include "mapPolyMesh.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(prober, 0);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::prober::prober
(
const fvMesh& mesh,
const dictionary& dict
)
:
mesh_(mesh),
samplePointScheme_("cell")
{
read(dict);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::prober::read(const dictionary& dict)
{
dict.readEntry("probeLocations", probes_);
if (probes_.empty())
{
FatalIOErrorInFunction(dict)
<< "Empty 'probeLocations' list."
<< exit(FatalIOError);
}
fixedLocations_ = dict.getOrDefault<bool>("fixedLocations", true);
includeOutOfBounds_ = dict.getOrDefault<bool>("includeOutOfBounds", true);
if (dict.readIfPresent("interpolationScheme", samplePointScheme_))
{
if (!fixedLocations_ && samplePointScheme_ != "cell")
{
WarningInFunction
<< "Only cell interpolation can be applied when "
<< "not using fixedLocations. InterpolationScheme "
<< "entry will be ignored"
<< endl;
}
}
return true;
}
void Foam::prober::updateMesh(const mapPolyMesh& mpm)
{
DebugInfo<< "probes: updateMesh" << endl;
if (&mpm.mesh() != &mesh_)
{
return;
}
if (fixedLocations_)
{
this->findElements(mesh_);
}
else
{
DebugInfo<< "probes: remapping sample locations" << endl;
// 1. Update cells
{
DynamicList<label> elems(cellIds_.size());
const labelList& reverseMap = mpm.reverseCellMap();
forAll(cellIds_, i)
{
label celli = cellIds_[i];
if (celli != -1)
{
label newCelli = reverseMap[celli];
if (newCelli == -1)
{
// cell removed
}
else if (newCelli < -1)
{
// cell merged
elems.append(-newCelli - 2);
}
else
{
// valid new cell
elems.append(newCelli);
}
}
else
{
// Keep -1 elements so the size stays the same
elems.append(-1);
}
}
cellIds_.transfer(elems);
}
// 2. Update faces
{
DynamicList<label> elems(faceIds_.size());
const labelList& reverseMap = mpm.reverseFaceMap();
for (const label facei : faceIds_)
{
if (facei != -1)
{
label newFacei = reverseMap[facei];
if (newFacei == -1)
{
// face removed
}
else if (newFacei < -1)
{
// face merged
elems.append(-newFacei - 2);
}
else
{
// valid new face
elems.append(newFacei);
}
}
else
{
// Keep -1 elements
elems.append(-1);
}
}
faceIds_.transfer(elems);
}
}
}
void Foam::prober::movePoints(const polyMesh& mesh)
{
DebugInfo<< "probes: movePoints" << endl;
if (fixedLocations_ && &mesh == &mesh_)
{
this->findElements(mesh_);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,220 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::patchProber
Description
Base class for sampling fields at specified internal and boundary locations.
SourceFiles
prober.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_prober_H
#define Foam_prober_H
#include "fvMesh.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class prober Declaration
\*---------------------------------------------------------------------------*/
class prober
{
protected:
template<class T>
struct isNotEqOp
{
void operator()(T& x, const T& y) const
{
const T unsetVal(-VGREAT*pTraits<T>::one);
if (x != unsetVal)
{
// Keep x.
// Note: should check for y != unsetVal but multiple sample cells
// already handled in read().
}
else
{
// x is not set. y might be.
x = y;
}
}
};
// Protected Data
//- Const reference to the mesh
const fvMesh& mesh_;
//- Fixed locations (default: true)
// Note: set to false for moving mesh calculations where locations
// should move with the mesh
bool fixedLocations_;
//- Include probes that were not found (default: true)
bool includeOutOfBounds_;
//- Interpolation/sample scheme to obtain values at the points
// Note: only possible when fixedLocations_ is true
word samplePointScheme_;
// Calculated
//- Probe locations
pointField probes_;
//- Cells to be probed (obtained from the locations)
labelList cellIds_;
//- Faces to be probed
labelList faceIds_;
//- Processor holding the cell or face (-1 if point not found
//- on any processor)
labelList procIds_;
//- Patch IDs on which the new probes are located
labelList patchIds_;
//- Original probes location
pointField oldPoints_;
// Protected Member Functions
//- Find cells and faces containing probes
virtual void findElements(const fvMesh& mesh) = 0;
public:
//- Runtime type information
TypeName("prober");
// Generated Methods
//- No copy construct
prober(const prober&) = delete;
//- No copy assignment
void operator=(const prober&) = delete;
// Constructors
//- Construct from Time and dictionary
prober
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~prober() = default;
// Member Functions
// Access
//- Return true if no probe locations
bool empty() const { return probes_.empty(); }
//- Return number of probe locations
label size() const { return probes_.size(); }
//- Return true if fixed locations
bool fixedLocations() const { return fixedLocations_; }
//- Return true if include out of bounds probes
bool includeOutOfBounds() const { return includeOutOfBounds_; }
//- Return the interpolation scheme to obtain values at the points
// Note: only possible when fixedLocations_ is true
const word& samplePointScheme() const { return samplePointScheme_; }
//- Return const reference to the probe locations
const pointField& probeLocations() const { return probes_; }
//- Return reference to the probe locations
pointField& probeLocations() { return probes_; }
//- Return the location of probe i
const point& probe(const label i) const { return probes_[i]; }
//- Cells to be probed (obtained from the locations)
const labelList& elements() const { return cellIds_; }
//- Return const reference to the faces to be probed
const labelList& faces() const { return faceIds_; }
//- Return const reference to the processor list
const labelList& processors() const { return procIds_; }
//- Return const reference to the patch ID list
const labelList& patchIDList() const noexcept { return patchIds_; }
//- Return const reference to the original probe locations
const pointField& oldPoints() const noexcept { return oldPoints_; }
// I-O
//- Read the settings dictionary
virtual bool read(const dictionary&);
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh&);
//- Update for changes of mesh
virtual void movePoints(const polyMesh&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2023 OpenCFD Ltd.
Copyright (C) 2015-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,12 +27,6 @@ License
\*---------------------------------------------------------------------------*/
#include "probes.H"
#include "dictionary.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "Time.H"
#include "IOmanip.H"
#include "mapPolyMesh.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -40,7 +34,6 @@ License
namespace Foam
{
defineTypeNameAndDebug(probes, 0);
addToRunTimeSelectionTable
(
functionObject,
@ -49,315 +42,6 @@ namespace Foam
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::probes::createProbeFiles(const wordList& fieldNames)
{
// Open new output streams
bool needsNewFiles = false;
for (const word& fieldName : fieldNames)
{
if (!probeFilePtrs_.found(fieldName))
{
needsNewFiles = true;
break;
}
}
if (needsNewFiles && Pstream::master())
{
DebugInfo
<< "Probing fields: " << fieldNames << nl
<< "Probing locations: " << *this << nl
<< endl;
// Put in undecomposed case
// (Note: gives problems for distributed data running)
fileName probeDir
(
mesh_.time().globalPath()
/ functionObject::outputPrefix
/ name()/mesh_.regionName()
// Use startTime as the instance for output files
/ mesh_.time().timeName(mesh_.time().startTime().value())
);
probeDir.clean(); // Remove unneeded ".."
// Create directory if needed
Foam::mkDir(probeDir);
for (const word& fieldName : fieldNames)
{
if (probeFilePtrs_.found(fieldName))
{
// Safety
continue;
}
auto osPtr = autoPtr<OFstream>::New(probeDir/fieldName);
auto& os = *osPtr;
probeFilePtrs_.insert(fieldName, osPtr);
DebugInfo<< "open probe stream: " << os.name() << endl;
const unsigned int width(IOstream::defaultPrecision() + 7);
os.setf(std::ios_base::left);
forAll(*this, probei)
{
os << "# Probe " << probei << ' ' << operator[](probei);
if (processor_[probei] == -1)
{
os << " # Not Found";
}
// Only for patchProbes
else if (probei < patchIDList_.size())
{
const label patchi = patchIDList_[probei];
if (patchi != -1)
{
const polyBoundaryMesh& bm = mesh_.boundaryMesh();
if
(
patchi < bm.nNonProcessor()
|| processor_[probei] == Pstream::myProcNo()
)
{
os << " at patch " << bm[patchi].name();
}
os << " with a distance of "
<< mag(operator[](probei)-oldPoints_[probei])
<< " m to the original point "
<< oldPoints_[probei];
}
}
os << nl;
}
os << setw(width) << "# Time";
forAll(*this, probei)
{
if (includeOutOfBounds_ || processor_[probei] != -1)
{
os << ' ' << setw(width) << probei;
}
}
os << endl;
}
}
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::probes::findElements(const fvMesh& mesh)
{
DebugInfo<< "probes: resetting sample locations" << endl;
elementList_.resize_nocopy(pointField::size());
faceList_.resize_nocopy(pointField::size());
processor_.resize_nocopy(pointField::size());
processor_ = -1;
forAll(*this, probei)
{
const point& location = (*this)[probei];
const label celli = mesh.findCell(location);
elementList_[probei] = celli;
if (celli != -1)
{
const labelList& cellFaces = mesh.cells()[celli];
const vector& cellCentre = mesh.cellCentres()[celli];
scalar minDistance = GREAT;
label minFaceID = -1;
forAll(cellFaces, i)
{
label facei = cellFaces[i];
vector dist = mesh.faceCentres()[facei] - cellCentre;
if (mag(dist) < minDistance)
{
minDistance = mag(dist);
minFaceID = facei;
}
}
faceList_[probei] = minFaceID;
}
else
{
faceList_[probei] = -1;
}
if (debug && (elementList_[probei] != -1 || faceList_[probei] != -1))
{
Pout<< "probes : found point " << location
<< " in cell " << elementList_[probei]
<< " and face " << faceList_[probei] << endl;
}
}
// Check if all probes have been found.
forAll(elementList_, probei)
{
const point& location = operator[](probei);
label celli = elementList_[probei];
label facei = faceList_[probei];
processor_[probei] = (celli != -1 ? Pstream::myProcNo() : -1);
// Check at least one processor with cell.
reduce(celli, maxOp<label>());
reduce(facei, maxOp<label>());
reduce(processor_[probei], maxOp<label>());
if (celli == -1)
{
if (Pstream::master())
{
WarningInFunction
<< "Did not find location " << location
<< " in any cell. Skipping location." << endl;
}
}
else if (facei == -1)
{
if (Pstream::master())
{
WarningInFunction
<< "Did not find location " << location
<< " in any face. Skipping location." << endl;
}
}
else
{
// Make sure location not on two domains.
if (elementList_[probei] != -1 && elementList_[probei] != celli)
{
WarningInFunction
<< "Location " << location
<< " seems to be on multiple domains:"
<< " cell " << elementList_[probei]
<< " on my domain " << Pstream::myProcNo()
<< " and cell " << celli << " on some other domain."
<< nl
<< "This might happen if the probe location is on"
<< " a processor patch. Change the location slightly"
<< " to prevent this." << endl;
}
if (faceList_[probei] != -1 && faceList_[probei] != facei)
{
WarningInFunction
<< "Location " << location
<< " seems to be on multiple domains:"
<< " cell " << faceList_[probei]
<< " on my domain " << Pstream::myProcNo()
<< " and face " << facei << " on some other domain."
<< nl
<< "This might happen if the probe location is on"
<< " a processor patch. Change the location slightly"
<< " to prevent this." << endl;
}
}
}
}
Foam::label Foam::probes::prepare(unsigned request)
{
// Prefilter on selection
HashTable<wordHashSet> selected =
(
loadFromFiles_
? IOobjectList(mesh_, mesh_.time().timeName()).classes(fieldSelection_)
: mesh_.classes(fieldSelection_)
);
// Classify and count fields
label nFields = 0;
do
{
#undef doLocalCode
#define doLocalCode(InputType, Target) \
{ \
Target.clear(); /* Remove old values */ \
const auto iter = selected.cfind(InputType::typeName); \
if (iter.good()) \
{ \
/* Add new (current) values */ \
Target.append(iter.val().sortedToc()); \
nFields += Target.size(); \
} \
}
doLocalCode(volScalarField, scalarFields_);
doLocalCode(volVectorField, vectorFields_)
doLocalCode(volSphericalTensorField, sphericalTensorFields_);
doLocalCode(volSymmTensorField, symmTensorFields_);
doLocalCode(volTensorField, tensorFields_);
doLocalCode(surfaceScalarField, surfaceScalarFields_);
doLocalCode(surfaceVectorField, surfaceVectorFields_);
doLocalCode(surfaceSphericalTensorField, surfaceSphericalTensorFields_);
doLocalCode(surfaceSymmTensorField, surfaceSymmTensorFields_);
doLocalCode(surfaceTensorField, surfaceTensorFields_);
#undef doLocalCode
}
while (false);
// Adjust file streams
if (Pstream::master())
{
wordHashSet currentFields(2*nFields);
currentFields.insert(scalarFields_);
currentFields.insert(vectorFields_);
currentFields.insert(sphericalTensorFields_);
currentFields.insert(symmTensorFields_);
currentFields.insert(tensorFields_);
currentFields.insert(surfaceScalarFields_);
currentFields.insert(surfaceVectorFields_);
currentFields.insert(surfaceSphericalTensorFields_);
currentFields.insert(surfaceSymmTensorFields_);
currentFields.insert(surfaceTensorFields_);
DebugInfo
<< "Probing fields: " << currentFields << nl
<< "Probing locations: " << *this << nl
<< endl;
// Close streams for fields that no longer exist
forAllIters(probeFilePtrs_, iter)
{
if (!currentFields.erase(iter.key()))
{
DebugInfo<< "close probe stream: " << iter()->name() << endl;
probeFilePtrs_.remove(iter);
}
}
if ((request & ACTION_WRITE) && !currentFields.empty())
{
createProbeFiles(currentFields.sortedToc());
}
}
return nFields;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::probes::probes
@ -369,15 +53,14 @@ Foam::probes::probes
const bool readFields
)
:
functionObjects::fvMeshFunctionObject(name, runTime, dict),
pointField(),
loadFromFiles_(loadFromFiles),
fixedLocations_(true),
includeOutOfBounds_(true),
verbose_(false),
onExecute_(false),
fieldSelection_(),
samplePointScheme_("cell")
Base
(
name,
runTime,
dict,
loadFromFiles,
readFields
)
{
if (readFields)
{
@ -388,184 +71,14 @@ Foam::probes::probes
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::probes::verbose(const bool on) noexcept
{
bool old(verbose_);
verbose_ = on;
return old;
}
bool Foam::probes::read(const dictionary& dict)
{
dict.readEntry("probeLocations", static_cast<pointField&>(*this));
dict.readEntry("fields", fieldSelection_);
dict.readIfPresent("fixedLocations", fixedLocations_);
dict.readIfPresent("includeOutOfBounds", includeOutOfBounds_);
verbose_ = dict.getOrDefault("verbose", false);
onExecute_ = dict.getOrDefault("sampleOnExecute", false);
if (dict.readIfPresent("interpolationScheme", samplePointScheme_))
if (!(Probes::read(dict) && prober_.read(dict)))
{
if (!fixedLocations_ && samplePointScheme_ != "cell")
{
WarningInFunction
<< "Only cell interpolation can be applied when "
<< "not using fixedLocations. InterpolationScheme "
<< "entry will be ignored"
<< endl;
}
}
// Initialise cells to sample from supplied locations
findElements(mesh_);
// Close old (ununsed) streams
prepare(ACTION_NONE);
return true;
}
bool Foam::probes::performAction(unsigned request)
{
if (!pointField::empty() && request && prepare(request))
{
performAction(scalarFields_, request);
performAction(vectorFields_, request);
performAction(sphericalTensorFields_, request);
performAction(symmTensorFields_, request);
performAction(tensorFields_, request);
performAction(surfaceScalarFields_, request);
performAction(surfaceVectorFields_, request);
performAction(surfaceSphericalTensorFields_, request);
performAction(surfaceSymmTensorFields_, request);
performAction(surfaceTensorFields_, request);
return false;
}
return true;
}
bool Foam::probes::execute()
{
if (onExecute_)
{
return performAction(ACTION_ALL & ~ACTION_WRITE);
}
return true;
}
bool Foam::probes::write()
{
return performAction(ACTION_ALL);
}
void Foam::probes::updateMesh(const mapPolyMesh& mpm)
{
DebugInfo<< "probes: updateMesh" << endl;
if (&mpm.mesh() != &mesh_)
{
return;
}
if (fixedLocations_)
{
findElements(mesh_);
}
else
{
DebugInfo<< "probes: remapping sample locations" << endl;
// 1. Update cells
{
DynamicList<label> elems(elementList_.size());
const labelList& reverseMap = mpm.reverseCellMap();
forAll(elementList_, i)
{
label celli = elementList_[i];
if (celli != -1)
{
label newCelli = reverseMap[celli];
if (newCelli == -1)
{
// cell removed
}
else if (newCelli < -1)
{
// cell merged
elems.append(-newCelli - 2);
}
else
{
// valid new cell
elems.append(newCelli);
}
}
else
{
// Keep -1 elements so the size stays the same
elems.append(-1);
}
}
elementList_.transfer(elems);
}
// 2. Update faces
{
DynamicList<label> elems(faceList_.size());
const labelList& reverseMap = mpm.reverseFaceMap();
for (const label facei : faceList_)
{
if (facei != -1)
{
label newFacei = reverseMap[facei];
if (newFacei == -1)
{
// face removed
}
else if (newFacei < -1)
{
// face merged
elems.append(-newFacei - 2);
}
else
{
// valid new face
elems.append(newFacei);
}
}
else
{
// Keep -1 elements
elems.append(-1);
}
}
faceList_.transfer(elems);
}
}
}
void Foam::probes::movePoints(const polyMesh& mesh)
{
DebugInfo<< "probes: movePoints" << endl;
if (fixedLocations_ && &mesh == &mesh_)
{
findElements(mesh_);
}
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd.
Copyright (C) 2016-2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -31,237 +31,88 @@ Group
grpUtilitiesFunctionObjects
Description
Set of locations to sample.
Function object to sample fields at specified internal-mesh locations and
write to file.
Call write() to sample and write files.
Example of function object specification:
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
probes
{
// Mandatory entries
type probes;
libs (sampling);
// Name of the directory for probe data
name probes;
fields (<wordRes>);
probeLocations (<vectorList>);
// Write at same frequency as fields
writeControl writeTime;
writeInterval 1;
// Optional entries
verbose <bool>;
sampleOnExecute <bool>;
fixedLocations <bool>;
includeOutOfBounds <bool>;
interpolationScheme <word>;
// Fields to be probed
fields (U "p.*");
// Optional: do not recalculate cells if mesh moves
fixedLocations false;
// Optional: interpolation scheme to use (default is cell)
interpolationScheme cellPoint;
probeLocations
(
( 1e-06 0 0.01 ) // at inlet
(0.21 -0.20999 0.01) // at outlet1
(0.21 0.20999 0.01) // at outlet2
(0.21 0 0.01) // at central block
);
// Optional: filter out points that haven't been found. Default
// is to include them (with value -VGREAT)
includeOutOfBounds true;
// Inherited entries
...
}
\endverbatim
Entries:
where the entries mean:
\table
Property | Description | Required | Default
type | Type-name: probes | yes |
probeLocations | Probe locations | yes |
fields | word/regex list of fields to sample | yes |
interpolationScheme | scheme to obtain values | no | cell
fixedLocations | Do not recalculate cells if mesh moves | no | true
includeOutOfBounds | Include out-of-bounds locations | no | true
sampleOnExecute | Sample on execution and store results | no | false
Property | Description | Type | Reqd | Deflt
type | Type name: probes | word | yes | -
libs | Library name: sampling | word | yes | -
fields | Names of fields to probe | wordRes | yes | -
probeLocations | Locations of probes | vectorList | yes | -
verbose | Enable/disable verbose output | bool | no | false
sampleOnExecute | Sample on execution and store results | bool | no <!--
--> | false
fixedLocations | Do not recalculate cells if mesh moves | bool | no | true
includeOutOfBounds | Include out-of-bounds locations | bool | no | true
interpolationScheme | Scheme to obtain values at the points | word <!--
--> | no | cell
\endtable
The inherited entries are elaborated in:
- \link fvMeshFunctionObject.H \endlink
- \link Probes.H \endlink
- \link internalProber.H \endlink
- \link prober.H \endlink
Note
- The \c includeOutOfBounds filters out points that haven't been found.
Default is to include them (with value \c -VGREAT).
SourceFiles
probes.C
probesTemplates.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_probes_H
#define Foam_probes_H
#include "fvMeshFunctionObject.H"
#include "HashPtrTable.H"
#include "OFstream.H"
#include "polyMesh.H"
#include "pointField.H"
#include "volFieldsFwd.H"
#include "surfaceFieldsFwd.H"
#include "surfaceMesh.H"
#include "wordRes.H"
#include "IOobjectList.H"
#include "Probes.H"
#include "internalProber.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward Declarations
class Time;
class objectRegistry;
class dictionary;
class fvMesh;
class mapPolyMesh;
/*---------------------------------------------------------------------------*\
Class probes Declaration
\*---------------------------------------------------------------------------*/
class probes
:
public functionObjects::fvMeshFunctionObject,
public pointField
public Probes<internalProber>
{
protected:
// Private Data
// Protected Classes
//- Use simpler synonym for the base type
using Base = Probes<internalProber>;
//- Grouping of field names by GeometricField type
template<class GeoField>
struct fieldGroup : public DynamicList<word> {};
// Data Types
//- Local control for sampling actions
enum sampleActionType : unsigned
{
ACTION_NONE = 0,
ACTION_WRITE = 0x1,
ACTION_STORE = 0x2,
ACTION_ALL = 0xF
};
// Protected Data
//- Load fields from files (not from objectRegistry)
bool loadFromFiles_;
//- Fixed locations (default: true)
// Note: set to false for moving mesh calculations where locations
// should move with the mesh
bool fixedLocations_;
//- Include probes that were not found (default: true)
bool includeOutOfBounds_;
//- Output verbosity
bool verbose_;
//- Perform sample actions on execute as well
bool onExecute_;
//- Requested names of fields to probe
wordRes fieldSelection_;
//- Interpolation/sample scheme to obtain values at the points
// Note: only possible when fixedLocations_ is true
word samplePointScheme_;
// Calculated
//- Current list of field names selected for sampling
DynamicList<word> selectedFieldNames_;
//- Categorized scalar/vector/tensor volume fields
fieldGroup<volScalarField> scalarFields_;
fieldGroup<volVectorField> vectorFields_;
fieldGroup<volSphericalTensorField> sphericalTensorFields_;
fieldGroup<volSymmTensorField> symmTensorFields_;
fieldGroup<volTensorField> tensorFields_;
//- Categorized scalar/vector/tensor surface fields
fieldGroup<surfaceScalarField> surfaceScalarFields_;
fieldGroup<surfaceVectorField> surfaceVectorFields_;
fieldGroup<surfaceSphericalTensorField> surfaceSphericalTensorFields_;
fieldGroup<surfaceSymmTensorField> surfaceSymmTensorFields_;
fieldGroup<surfaceTensorField> surfaceTensorFields_;
//- Cells to be probed (obtained from the locations)
labelList elementList_;
//- Faces to be probed
labelList faceList_;
//- Processor holding the cell or face (-1 if point not found
// on any processor)
labelList processor_;
//- Current open files (non-empty on master only)
HashPtrTable<OFstream> probeFilePtrs_;
//- Patch IDs on which the new probes are located (for patchProbes)
labelList patchIDList_;
//- Original probes location (only used for patchProbes)
pointField oldPoints_;
// Protected Member Functions
//- Find cells and faces containing probes
virtual void findElements(const fvMesh& mesh);
//- Classify field types, close/open file streams
// \return number of fields to sample
label prepare(unsigned request);
//- Get from registry or load from disk
template<class GeoField>
tmp<GeoField> getOrLoadField(const word& fieldName) const;
//- Store results: min/max/average/size
template<class Type>
void storeResults(const word& fieldName, const Field<Type>& values);
private:
// Private Member Functions
//- Create new streams as required
void createProbeFiles(const wordList& fieldNames);
//- Write field values
template<class Type>
void writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
);
//- Sample and store/write all applicable sampled fields
template<class GeoField>
void performAction
(
const fieldGroup<GeoField>& fieldNames, /* must be sorted */
unsigned request
);
//- Perform sampling action with store/write
bool performAction(unsigned request);
//- No copy construct
probes(const probes&) = delete;
//- No copy assignment
void operator=(const probes&) = delete;
public:
@ -288,86 +139,19 @@ public:
// Member Functions
//- Enable/disable verbose output
// \return old value
bool verbose(const bool on) noexcept;
//- Bring Base::prober into this class's public scope.
using Base::prober;
//- Return names of fields to probe
virtual const wordRes& fieldNames() const noexcept
{
return fieldSelection_;
}
//- Return locations to probe
virtual const pointField& probeLocations() const noexcept
{
return *this;
}
//- Return location for probe i
virtual const point& probe(const label i) const
{
return operator[](i);
}
//- Cells to be probed (obtained from the locations)
const labelList& elements() const noexcept
{
return elementList_;
}
//- Read the probes
//- Read the settings from the dictionary
virtual bool read(const dictionary&);
//- Sample and store result if the sampleOnExecute is enabled.
virtual bool execute();
//- Sample and write
virtual bool write();
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh&);
//- Update for changes of mesh
virtual void movePoints(const polyMesh&);
//- Update for changes of mesh due to readUpdate
virtual void readUpdate(const polyMesh::readUpdateState state)
{}
// Sampling
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const VolumeField<Type>&) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sample(const SurfaceField<Type>&) const;
//- Sample a volume field at all locations
template<class Type>
tmp<Field<Type>> sample(const word& fieldName) const;
//- Sample a surface field at all locations
template<class Type>
tmp<Field<Type>> sampleSurfaceField(const word& fieldName) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "probesTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,274 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "probes.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "IOmanip.H"
#include "interpolation.H"
#include "SpanStream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
template<class T>
struct isNotEqOp
{
void operator()(T& x, const T& y) const
{
const T unsetVal(-VGREAT*pTraits<T>::one);
if (x != unsetVal)
{
// Keep x.
// Note: should check for y != unsetVal but multiple sample cells
// already handled in read().
}
else
{
// x is not set. y might be.
x = y;
}
}
};
} // End namespace Foam
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class GeoField>
Foam::tmp<GeoField>
Foam::probes::getOrLoadField(const word& fieldName) const
{
tmp<GeoField> tfield;
if (loadFromFiles_)
{
tfield.emplace
(
IOobject
(
fieldName,
mesh_.time().timeName(),
mesh_.thisDb(),
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
),
mesh_
);
}
else
{
tfield.cref(mesh_.cfindObject<GeoField>(fieldName));
}
return tfield;
}
template<class Type>
void Foam::probes::storeResults
(
const word& fieldName,
const Field<Type>& values
)
{
const MinMax<Type> limits(values);
const Type avgVal = average(values);
this->setResult("average(" + fieldName + ")", avgVal);
this->setResult("min(" + fieldName + ")", limits.min());
this->setResult("max(" + fieldName + ")", limits.max());
this->setResult("size(" + fieldName + ")", values.size());
if (verbose_)
{
Info<< name() << " : " << fieldName << nl
<< " avg: " << avgVal << nl
<< " min: " << limits.min() << nl
<< " max: " << limits.max() << nl << nl;
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type>
void Foam::probes::writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalar timeValue
)
{
if (Pstream::master())
{
const unsigned int width(IOstream::defaultPrecision() + 7);
OFstream& os = *probeFilePtrs_[fieldName];
os << setw(width) << timeValue;
OCharStream buf;
forAll(values, probei)
{
if (includeOutOfBounds_ || processor_[probei] != -1)
{
buf.rewind();
buf << values[probei];
os << ' ' << setw(width) << buf.str().data();
}
}
os << endl;
}
}
template<class GeoField>
void Foam::probes::performAction
(
const fieldGroup<GeoField>& fieldNames,
unsigned request
)
{
for (const word& fieldName : fieldNames)
{
tmp<GeoField> tfield = getOrLoadField<GeoField>(fieldName);
if (tfield)
{
const auto& field = tfield();
const scalar timeValue = field.time().timeOutputValue();
Field<typename GeoField::value_type> values(sample(field));
this->storeResults(fieldName, values);
if (request & ACTION_WRITE)
{
this->writeValues(fieldName, values, timeValue);
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::probes::sample(const VolumeField<Type>& vField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
auto tvalues = tmp<Field<Type>>::New(Field<Type>(this->size(), unsetVal));
auto& values = tvalues.ref();
if (fixedLocations_)
{
autoPtr<interpolation<Type>> interpPtr
(
interpolation<Type>::New(samplePointScheme_, vField)
);
forAll(*this, probei)
{
if (elementList_[probei] >= 0)
{
const vector& position = operator[](probei);
values[probei] = interpPtr().interpolate
(
position,
elementList_[probei],
-1
);
}
}
}
else
{
forAll(*this, probei)
{
if (elementList_[probei] >= 0)
{
values[probei] = vField[elementList_[probei]];
}
}
}
Pstream::listCombineReduce(values, isNotEqOp<Type>());
return tvalues;
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::probes::sample(const SurfaceField<Type>& sField) const
{
const Type unsetVal(-VGREAT*pTraits<Type>::one);
auto tvalues = tmp<Field<Type>>::New(Field<Type>(this->size(), unsetVal));
auto& values = tvalues.ref();
forAll(*this, probei)
{
if (faceList_[probei] >= 0)
{
values[probei] = sField[faceList_[probei]];
}
}
Pstream::listCombineReduce(values, isNotEqOp<Type>());
return tvalues;
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::probes::sample(const word& fieldName) const
{
return sample(mesh_.lookupObject<VolumeField<Type>>(fieldName));
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::probes::sampleSurfaceField(const word& fieldName) const
{
return sample(mesh_.lookupObject<SurfaceField<Type>>(fieldName));
}
// ************************************************************************* //

View File

@ -243,6 +243,9 @@ public:
//- Return access to the temperature field
const volScalarField& T() const noexcept { return T_; }
//- Return the radiation solver frequency
label solverFreq() const noexcept { return solverFreq_; }
//- Source term component (for power of T^4)
virtual tmp<volScalarField> Rp() const = 0;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / O peration | Version: v2506 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
@ -26,9 +26,8 @@ d2dt2Schemes
gradSchemes
{
default leastSquares;
grad(ws) leastSquares;
grad(ws_shell) leastSquares;
default leastSquares;
grad(ws_vibrationShell) leastSquares;
}
divSchemes

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / O peration | Version: v2506 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
@ -16,7 +16,7 @@ FoamFile
solvers
{
"(ws|ws_.*)"
ws_vibrationShell
{
solver diagonal;
preconditioner DILU;

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object IDefault;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [ 1 0 -3 0 0 0 0 ];
internalField uniform 0;
boundaryField
{
".*"
{
type greyDiffusiveRadiation;
value uniform 0;
}
}
// ************************************************************************* //

View File

@ -1,80 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object T;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 1 0 0 0];
internalField uniform 300;
boundaryField
{
"floor.*"
{
type fixedValue;
type compressible::thermalShell;
active true;
area floor;
region lower;
thermalShellModel thermalShell;
thermo
{
// Thermal properties
rho 1000;
kappa 200;
Cp 600;
emissivity 0;
}
qr qr;
thickness 1e-3;
value uniform 700;
}
"ceiling.*"
{
type compressible::thermalShell;
active true;
area ceiling;
region upper;
thermalShellModel thermalShell;
thermo
{
// Thermal properties
rho 1000;
kappa 200;
Cp 600;
emissivity 0;
}
qr qr;
thickness 1e-3;
value uniform 300;
}
"fixedWall.*"
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -1,30 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 -1 0 0 0 0];
internalField uniform (0 0 0);
boundaryField
{
".*"
{
type noSlip;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object alphat;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -1 -1 0 0 0 0];
internalField uniform 0;
boundaryField
{
".*"
{
type compressible::alphatWallFunction;
value uniform 0;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object epsilon;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -3 0 0 0 0];
internalField uniform 0.01;
boundaryField
{
".*"
{
type epsilonWallFunction;
value uniform 0.01;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class areaScalarField;
object Ts;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 1 0 0 0];
internalField uniform 300;
boundaryField
{
"side.*"
{
type fixedValue;
value uniform 300;
}
}
// ************************************************************************* //

View File

@ -1,30 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class areaScalarField;
object hs;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 0 0 0 0 0];
internalField uniform 1e-3;
boundaryField
{
"side.*"
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class areaScalarField;
object Ts;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 1 0 0 0];
internalField uniform 300;
boundaryField
{
"side.*"
{
type fixedValue;
value uniform 300;
}
}
// ************************************************************************* //

View File

@ -1,30 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class areaScalarField;
object hs;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 1 0 0 0 0 0];
internalField uniform 1e-3;
boundaryField
{
"side.*"
{
type zeroGradient;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object k;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -2 0 0 0 0];
internalField uniform 0.1;
boundaryField
{
".*"
{
type kqRWallFunction;
value uniform 0.1;
}
}
// ************************************************************************* //

View File

@ -1,31 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object nut;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 2 -1 0 0 0 0];
internalField uniform 0;
boundaryField
{
".*"
{
type nutkWallFunction;
value uniform 0;
}
}
// ************************************************************************* //

View File

@ -1,43 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -1 -2 0 0 0 0];
internalField uniform 1e5;
boundaryField
{
"floor.*"
{
type calculated;
value $internalField;
}
"ceiling.*"
{
type calculated;
value $internalField;
}
"fixedWall.*"
{
type calculated;
value $internalField;
}
}
// ************************************************************************* //

View File

@ -1,43 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2512 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object p_rgh;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [1 -1 -2 0 0 0 0];
internalField uniform 1e5;
boundaryField
{
"floor.*"
{
type fixedFluxPressure;
value $internalField;
}
"ceiling.*"
{
type fixedFluxPressure;
value $internalField;
}
"fixedWall.*"
{
type fixedFluxPressure;
value $internalField;
}
}
// ************************************************************************* //

View File

@ -1,15 +0,0 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions
#------------------------------------------------------------------------------
cleanCase
## foamListRegions -finite-area
for region in ceiling floor
do
cleanFaMesh -region "$region"
rmdir "constant/finite-area/$region" 2>/dev/null
done
#------------------------------------------------------------------------------

View File

@ -1,12 +0,0 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
#------------------------------------------------------------------------------
./Allrun.pre
runApplication makeFaMesh -all-area-regions
runApplication $(getApplication)
#------------------------------------------------------------------------------

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