energyTransport.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2017-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "energyTransport.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 namespace functionObjects
38 {
39  defineTypeNameAndDebug(energyTransport, 0);
40 
42  (
43  functionObject,
44  energyTransport,
45  dictionary
46  );
47 }
48 }
49 
50 
51 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52 
53 Foam::volScalarField& Foam::functionObjects::energyTransport::transportedField()
54 {
55  if (!foundObject<volScalarField>(fieldName_))
56  {
57  auto tfldPtr = tmp<volScalarField>::New
58  (
59  IOobject
60  (
61  fieldName_,
62  mesh_.time().timeName(),
63  mesh_,
67  ),
68  mesh_
69  );
70  store(fieldName_, tfldPtr);
71  }
72 
73  return lookupObjectRef<volScalarField>(fieldName_);
74 }
75 
76 
78 Foam::functionObjects::energyTransport::kappaEff() const
79 {
80  // Incompressible
81  {
82  typedef incompressible::turbulenceModel turbType;
83 
84  const turbType* turbPtr = findObject<turbType>
85  (
87  );
88 
89  if (turbPtr)
90  {
91  return volScalarField::New
92  (
93  "kappaEff",
95  (
96  kappa() + Cp()*turbPtr->nut()*rho()/Prt_
97  )
98  );
99  }
100  }
101 
103  << "Turbulence model not found" << exit(FatalError);
104 
105  return nullptr;
106 }
107 
108 
110 Foam::functionObjects::energyTransport::rho() const
111 {
113  (
114  "trho",
116  mesh_,
117  rho_
118  );
119 
120  if (phases_.size())
121  {
122  trho.ref() = lookupObject<volScalarField>(rhoName_);
123  }
124  return trho;
125 }
126 
127 
129 Foam::functionObjects::energyTransport::Cp() const
130 {
131  if (phases_.size())
132  {
133  tmp<volScalarField> tCp(phases_[0]*Cps_[0]);
134 
135  for (label i = 1; i < phases_.size(); i++)
136  {
137  tCp.ref() += phases_[i]*Cps_[i];
138  }
139  return tCp;
140  }
141 
142  return volScalarField::New
143  (
144  "tCp",
146  mesh_,
147  Cp_
148  );
149 }
150 
151 
153 Foam::functionObjects::energyTransport::kappa() const
154 {
155  if (phases_.size())
156  {
157  tmp<volScalarField> tkappa(phases_[0]*kappas_[0]);
158 
159  for (label i = 1; i < phases_.size(); i++)
160  {
161  tkappa.ref() += phases_[i]*kappas_[i];
162  }
163  return tkappa;
164  }
165 
166  return volScalarField::New
167  (
168  "tkappa",
170  mesh_,
171  kappa_
172  );
173 }
174 
175 
176 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
177 
179 (
180  const word& name,
181  const Time& runTime,
182  const dictionary& dict
183 )
184 :
186  rhoCp_
187  (
188  IOobject
189  (
190  "rhoCp",
191  mesh_.time().timeName(),
192  mesh_,
193  IOobject::NO_READ,
194  IOobject::NO_WRITE,
195  IOobject::NO_REGISTER
196  ),
197  mesh_,
199  ),
200  fvOptions_(mesh_),
201  multiphaseThermo_(dict.subOrEmptyDict("phaseThermos")),
202  Cp_("Cp", dimEnergy/dimMass/dimTemperature, 0, dict),
203  kappa_
204  (
205  "kappa",
207  0,
208  dict
209  ),
210  rho_("rhoInf", dimDensity, 0, dict),
211  Prt_("Prt", dimless, 1, dict),
212  fieldName_(dict.getOrDefault<word>("field", "T")),
213  schemesField_("unknown-schemesField"),
214  phiName_(dict.getOrDefault<word>("phi", "phi")),
215  rhoName_(dict.getOrDefault<word>("rho", "rho")),
216  tol_(1),
217  nCorr_(0)
218 {
219  read(dict);
220 
221  // If the flow is multiphase
222  if (!multiphaseThermo_.empty())
223  {
224  Cps_.setSize(multiphaseThermo_.size());
225  kappas_.setSize(Cps_.size());
226  phaseNames_.setSize(Cps_.size());
227 
228  label phasei = 0;
229  forAllConstIters(multiphaseThermo_, iter)
230  {
231  const word& key = iter().keyword();
232 
233  const dictionary* subDictPtr = multiphaseThermo_.findDict(key);
234 
235  if (!subDictPtr)
236  {
238  << "Found non-dictionary entry " << iter()
239  << " in top-level dictionary " << multiphaseThermo_
240  << exit(FatalError);
241  }
242 
243  const dictionary& dict = *subDictPtr;
244 
245  phaseNames_[phasei] = key;
246 
247  Cps_.set
248  (
249  phasei,
251  (
252  "Cp",
254  dict
255  )
256  );
257 
258  kappas_.set
259  (
260  phasei,
261  new dimensionedScalar //[J/m/s/K]
262  (
263  "kappa",
265  dict
266  )
267  );
268 
269  ++phasei;
270  }
271 
272  phases_.setSize(phaseNames_.size());
273  forAll(phaseNames_, i)
274  {
275  phases_.set
276  (
277  i,
278  mesh_.getObjectPtr<volScalarField>(phaseNames_[i])
279  );
280  }
281 
282  rhoCp_ = rho()*Cp();
283  rhoCp_.oldTime();
284  }
285  else
286  {
287  if (Cp_.value() == 0.0 || kappa_.value() == 0.0)
288  {
290  << " Multiphase thermo dictionary not found and Cp/kappa "
291  << " for single phase are zero. Please entry either"
292  << exit(FatalError);
293  }
294 
295  }
296 
297  // Force creation of transported field so any BCs using it can
298  // look it up
299  volScalarField& s = transportedField();
300  s.correctBoundaryConditions();
301 }
302 
303 
304 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
305 
307 {
309  {
310  return false;
311  }
312 
313  dict.readIfPresent("phi", phiName_);
314  dict.readIfPresent("rho", rhoName_);
315 
316  schemesField_ = dict.getOrDefault("schemesField", fieldName_);
317 
318  dict.readIfPresent("nCorr", nCorr_);
319  dict.readIfPresent("tolerance", tol_);
320 
321  if (dict.found("fvOptions"))
322  {
323  fvOptions_.reset(dict.subDict("fvOptions"));
324  }
325 
326  return true;
327 }
328 
329 
331 {
332  volScalarField& s = transportedField();
333 
334  Log << type() << " execute: " << s.name() << endl;
335 
336  const surfaceScalarField& phi =
337  mesh_.lookupObject<surfaceScalarField>(phiName_);
338 
339  // Calculate the diffusivity
340  const volScalarField kappaEff("kappaEff", this->kappaEff());
341 
342  word divScheme("div(phi," + schemesField_ + ")");
343  word laplacianScheme
344  (
345  "laplacian(kappaEff," + schemesField_ + ")"
346  );
347 
348  // Set under-relaxation coeff
349  scalar relaxCoeff = 0;
350  mesh_.relaxEquation(schemesField_, relaxCoeff);
351 
352  // Convergence monitor parameters
353  bool converged = false;
354  int iter = 0;
355 
356  if (phi.dimensions() == dimMass/dimTime)
357  {
358  rhoCp_ = rho()*Cp();
360 
361  for (int i = 0; i <= nCorr_; ++i)
362  {
363  fvScalarMatrix sEqn
364  (
365  fvm::ddt(rhoCp_, s)
366  + fvm::div(rhoCpPhi, s, divScheme)
367  - fvm::Sp(fvc::ddt(rhoCp_) + fvc::div(rhoCpPhi), s)
368  - fvm::laplacian(kappaEff, s, laplacianScheme)
369  ==
370  fvOptions_(rhoCp_, s)
371  );
372 
373  sEqn.relax(relaxCoeff);
374 
375  fvOptions_.constrain(sEqn);
376 
377  ++iter;
378  converged = (sEqn.solve(schemesField_).initialResidual() < tol_);
379  if (converged) break;
380  }
381  }
382  else if (phi.dimensions() == dimVolume/dimTime)
383  {
384  dimensionedScalar rhoCp(rho_*Cp_);
385 
386  const surfaceScalarField CpPhi(rhoCp*phi);
387 
388  auto trhoCp = volScalarField::New
389  (
390  "trhoCp",
392  mesh_,
393  rhoCp
394  );
395 
396  for (int i = 0; i <= nCorr_; ++i)
397  {
398  fvScalarMatrix sEqn
399  (
400  fvm::ddt(rhoCp, s)
401  + fvm::div(CpPhi, s, divScheme)
402  - fvm::laplacian(kappaEff, s, laplacianScheme)
403  ==
404  fvOptions_(trhoCp.ref(), s)
405  );
406 
407  sEqn.relax(relaxCoeff);
408 
409  fvOptions_.constrain(sEqn);
410 
411  ++iter;
412  converged = (sEqn.solve(schemesField_).initialResidual() < tol_);
413  if (converged) break;
414  }
415  }
416  else
417  {
419  << "Incompatible dimensions for phi: " << phi.dimensions() << nl
420  << "Dimensions should be " << dimMass/dimTime << " or "
422  }
423 
424  if (converged)
425  {
426  Log << type() << ": " << name() << ": "
427  << s.name() << " is converged." << nl
428  << tab << "initial-residual tolerance: " << tol_ << nl
429  << tab << "outer iteration: " << iter << nl;
430  }
432  Log << endl;
433 
434  return true;
435 }
436 
437 
439 {
440  return true;
441 }
442 
443 
444 // ************************************************************************* //
const Type & value() const noexcept
Return const reference to value.
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
defineTypeNameAndDebug(ObukhovLength, 0)
fvMatrix< scalar > fvScalarMatrix
Definition: fvMatricesFwd.H:37
const GeometricField< Type, PatchField, GeoMesh > & oldTime() const
Return old time field.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
label phasei
Definition: pEqn.H:27
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
const tmp< volScalarField > & tCp
Definition: EEqn.H:4
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:42
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
engineTime & runTime
virtual bool read(const dictionary &)
Read the energyTransport data.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
tmp< volScalarField > trho
virtual bool execute()
Calculate the energyTransport.
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
virtual bool write()
Do nothing.
IncompressibleTurbulenceModel< transportModel > turbulenceModel
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
kappaEff
Definition: TEqn.H:10
const dimensionedScalar kappa
Coulomb constant: default SI units: [N.m2/C2].
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
const surfaceScalarField rhoCpPhi(fvc::interpolate(fluid.Cp()) *rhoPhi)
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
tmp< GeometricField< Type, fvPatchField, volMesh > > ddt(const dimensioned< Type > dt, const fvMesh &mesh)
Definition: fvcDdt.C:40
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
word timeName
Definition: getTimeIndex.H:3
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:801
const dimensionSet dimVolume(pow3(dimLength))
Definition: dimensionSets.H:58
void setSize(const label n)
Alias for resize()
Definition: List.H:325
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
static const word propertiesName
Default name of the turbulence properties dictionary.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Type * getObjectPtr(const word &name, const bool recursive=false) const
Return non-const pointer to the object of the given Type, using a const-cast to have it behave like a...
const dimensionSet dimTemperature(0, 0, 0, 1, 0, 0, 0)
Definition: dimensionSets.H:52
tmp< fvMatrix< Type > > ddt(const GeometricField< Type, fvPatchField, volMesh > &vf)
Definition: fvmDdt.C:41
bool store(word &fieldName, const tmp< ObjectType > &tfield, bool cacheable=false)
Store the field in the (sub) objectRegistry under the given name.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
A special matrix type and solver, designed for finite volume solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: fvPatchField.H:64
energyTransport(const word &name, const Time &runTime, const dictionary &dict)
Construct from Time and dictionary.
auto key(const Type &t) -> std::enable_if_t< std::is_enum_v< Type >, std::underlying_type_t< Type > >
Definition: foamGltfBase.H:103
zeroField Sp(const Foam::zero, const GeometricField< Type, fvPatchField, volMesh > &)
A no-op source.
rhoCp
Definition: TEqn.H:3
static tmp< GeometricField< scalar, fvPatchField, volMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=fvPatchField< scalar >::calculatedType())
Return tmp field (NO_READ, NO_WRITE) from name, mesh, dimensions and patch type. [Takes current timeN...
SolverPerformance< Type > solve(const dictionary &)
Solve returning the solution statistics.
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
tmp< fvMatrix< Type > > div(const surfaceScalarField &flux, const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmDiv.C:41
const volScalarField & Cp
Definition: EEqn.H:7
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
void relax(const scalar alpha)
Relax matrix (for steady-state solution).
Definition: fvMatrix.C:1094
const dimensionSet dimEnergy
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
const dimensionSet dimDensity
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:41
#define Log
Definition: PDRblock.C:28
Automatically write from objectRegistry::writeObject()
const dimensionSet dimTime(0, 0, 1, 0, 0, 0, 0)
Definition: dimensionSets.H:51
virtual bool read(const dictionary &dict)
Read optional controls.
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
const dimensionSet dimMass(1, 0, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:49
A class for managing temporary objects.
Definition: HashPtrTable.H:50
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
Request registration (bool: true)
const fvMesh & mesh_
Reference to the fvMesh.
Do not request registration (bool: false)
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and it is a dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127