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.
This commit is contained in:
Kutalmis Bercin
2025-10-16 16:44:06 +01:00
parent 29813b0e96
commit 460f1478be
4 changed files with 467 additions and 2 deletions

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
// ************************************************************************* //