filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.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) 2013-2017 OpenFOAM Foundation
9  Copyright (C) 2019-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
31 #include "mappedPatchBase.H"
32 
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 
41 filmPyrolysisRadiativeCoupledMixedFvPatchScalarField::filmModel() const
42 {
43  typedef filmModelType ModelType;
44 
45  const UPtrList<const ModelType> models
46  (
47  db().time().csorted<ModelType>()
48  );
49 
50  for (const ModelType& mdl : models)
51  {
52  if (mdl.regionMesh().name() == filmRegionName_)
53  {
54  return mdl;
55  }
56  }
57 
58  DynamicList<word> modelNames(models.size());
59  for (const ModelType& mdl : models)
60  {
61  modelNames.push_back(mdl.regionMesh().name());
62  }
63 
65  << "Unable to locate film region " << filmRegionName_
66  << ". Available regions include: " << modelNames
67  << abort(FatalError);
68 
69  return models.front(); // Failure
70 }
71 
72 
75 filmPyrolysisRadiativeCoupledMixedFvPatchScalarField::pyrModel() const
76 {
77  typedef pyrolysisModelType ModelType;
78 
79  const UPtrList<const ModelType> models
80  (
81  db().time().csorted<ModelType>()
82  );
83 
84  for (const ModelType& mdl : models)
85  {
86  if (mdl.regionMesh().name() == pyrolysisRegionName_)
87  {
88  return mdl;
89  }
90  }
91 
92  DynamicList<word> modelNames(models.size());
93  for (const ModelType& mdl : models)
94  {
95  modelNames.push_back(mdl.regionMesh().name());
96  }
97 
99  << "Unable to locate pyrolysis region " << pyrolysisRegionName_
100  << ". Available regions include: " << modelNames
101  << abort(FatalError);
102 
103  return models.front(); // Failure
104 }
105 
106 
107 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
108 
111 (
112  const fvPatch& p,
114 )
115 :
116  mixedFvPatchScalarField(p, iF),
117  temperatureCoupledBase(patch()), // default method (fluidThermo)
118  filmRegionName_("surfaceFilmProperties"),
119  pyrolysisRegionName_("pyrolysisProperties"),
120  TnbrName_("undefined-Tnbr"),
121  qrName_("undefined-qr"),
122  convectiveScaling_(1.0),
123  filmDeltaDry_(0.0),
124  filmDeltaWet_(0.0)
125 {
126  this->refValue() = 0.0;
127  this->refGrad() = 0.0;
128  this->valueFraction() = 1.0;
129 }
130 
131 
134 (
136  const fvPatch& p,
138  const fvPatchFieldMapper& mapper
139 )
140 :
141  mixedFvPatchScalarField(psf, p, iF, mapper),
143  filmRegionName_(psf.filmRegionName_),
144  pyrolysisRegionName_(psf.pyrolysisRegionName_),
145  TnbrName_(psf.TnbrName_),
146  qrName_(psf.qrName_),
147  convectiveScaling_(psf.convectiveScaling_),
148  filmDeltaDry_(psf.filmDeltaDry_),
149  filmDeltaWet_(psf.filmDeltaWet_)
150 {}
151 
152 
155 (
156  const fvPatch& p,
158  const dictionary& dict
159 )
160 :
161  mixedFvPatchScalarField(p, iF),
163  filmRegionName_
164  (
165  dict.getOrDefault<word>("filmRegion", "surfaceFilmProperties")
166  ),
167  pyrolysisRegionName_
168  (
169  dict.getOrDefault<word>("pyrolysisRegion", "pyrolysisProperties")
170  ),
171  TnbrName_(dict.lookup("Tnbr")),
172  qrName_(dict.lookup("qr")),
173  convectiveScaling_(dict.getOrDefault<scalar>("convectiveScaling", 1)),
174  filmDeltaDry_(dict.get<scalar>("filmDeltaDry")),
175  filmDeltaWet_(dict.get<scalar>("filmDeltaWet"))
176 {
177  if (!isA<mappedPatchBase>(this->patch().patch()))
178  {
180  << "' not type '" << mappedPatchBase::typeName << "'"
181  << "\n for patch " << p.name()
182  << " of field " << internalField().name()
183  << " in file " << internalField().objectPath()
184  << exit(FatalError);
185  }
186 
187  this->readValueEntry(dict, IOobjectOption::MUST_READ);
188 
189  if (this->readMixedEntries(dict))
190  {
191  // Full restart
192  }
193  else
194  {
195  // Start from user entered data. Assume fixedValue.
196  refValue() = *this;
197  refGrad() = 0.0;
198  valueFraction() = 1.0;
199  }
200 }
201 
202 
205 (
206  const filmPyrolysisRadiativeCoupledMixedFvPatchScalarField& psf,
207  const DimensionedField<scalar, volMesh>& iF
208 )
209 :
210  mixedFvPatchScalarField(psf, iF),
211  temperatureCoupledBase(patch(), psf),
212  filmRegionName_(psf.filmRegionName_),
213  pyrolysisRegionName_(psf.pyrolysisRegionName_),
214  TnbrName_(psf.TnbrName_),
215  qrName_(psf.qrName_),
216  convectiveScaling_(psf.convectiveScaling_),
217  filmDeltaDry_(psf.filmDeltaDry_),
218  filmDeltaWet_(psf.filmDeltaWet_)
219 {}
220 
221 
222 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
223 
225 (
226  const fvPatchFieldMapper& mapper
227 )
228 {
229  mixedFvPatchScalarField::autoMap(mapper);
231 }
232 
233 
235 (
236  const fvPatchField<scalar>& ptf,
237  const labelList& addr
238 )
239 {
240  mixedFvPatchScalarField::rmap(ptf, addr);
242  const auto& fpptf = refCast<const myType>(ptf);
243 
244  temperatureCoupledBase::rmap(fpptf, addr);
245 }
246 
247 
249 {
250  if (updated())
251  {
252  return;
253  }
254 
255  // Get the coupling information from the mappedPatchBase
256  const auto& mpp = refCast<const mappedPatchBase>(patch().patch());
257 
258  const label patchi = patch().index();
259  const label nbrPatchi = mpp.samplePolyPatch().index();
260  const polyMesh& mesh = patch().boundaryMesh().mesh();
261  const polyMesh& nbrMesh = mpp.sampleMesh();
262  const fvPatch& nbrPatch =
263  refCast<const fvMesh>(nbrMesh).boundary()[nbrPatchi];
264 
265  scalarField intFld(patchInternalField());
266 
267  const auto& nbrField =
268  refCast<const myType>
269  (
270  nbrPatch.lookupPatchField<volScalarField>(TnbrName_)
271  );
272 
273  // Swap to obtain full local values of neighbour internal field
274  scalarField nbrIntFld(nbrField.patchInternalField());
275  mpp.distribute(nbrIntFld);
276 
277  scalarField& Tp = *this;
278 
279  const scalarField K(this->kappa(*this));
280  const scalarField nbrK(nbrField.kappa(*this));
281 
282  // Swap to obtain full local values of neighbour K*delta
283  scalarField KDeltaNbr(nbrK*nbrPatch.deltaCoeffs());
284  mpp.distribute(KDeltaNbr);
285 
286  const scalarField myKDelta(K*patch().deltaCoeffs());
287 
288  scalarList Tfilm(patch().size(), Zero);
289  scalarList htcwfilm(patch().size(), Zero);
290  scalarList filmDelta(patch().size(), Zero);
291 
292  const pyrolysisModelType& pyrolysis = pyrModel();
293  const filmModelType& film = filmModel();
294 
295  // Obtain Rad heat (qr)
296  scalarField qr(patch().size(), Zero);
297 
298  label coupledPatchi = -1;
299  label filmPatchi = -1;
300  if (pyrolysisRegionName_ == mesh.name())
301  {
302  // Working on the pyrolysis mesh
303 
304  coupledPatchi = patchi;
305  if (qrName_ != "none")
306  {
307  qr = nbrPatch.lookupPatchField<volScalarField>(qrName_);
308  mpp.distribute(qr);
309  }
310 
311  filmPatchi = pyrolysis.nbrCoupledPatchID(film, coupledPatchi);
312 
313  const scalarField htcw(film.htcw().h()().boundaryField()[filmPatchi]);
314 
315  // Obtain htcw
316  htcwfilm =
317  pyrolysis.mapRegionPatchField
318  (
319  film,
320  coupledPatchi,
321  filmPatchi,
322  htcw,
323  true
324  );
325 
326  // Obtain Tfilm at the boundary through Ts.
327  // NOTE: Tf is not good as at the boundary it will retrieve Tp
328  const scalarField Ts(film.Ts().boundaryField()[filmPatchi]);
329  Tfilm =
330  pyrolysis.mapRegionPatchField
331  (
332  film,
333  coupledPatchi,
334  filmPatchi,
335  Ts,
336  true
337  );
338 
339  // Obtain delta
340  filmDelta =
341  pyrolysis.mapRegionPatchField<scalar>
342  (
343  film,
344  "deltaf",
345  coupledPatchi,
346  true
347  );
348  }
349  else if (pyrolysis.primaryMesh().name() == mesh.name())
350  {
351  // Working on the primary mesh
352 
353  coupledPatchi = nbrPatch.index();
354  if (qrName_ != "none")
355  {
356  qr = patch().lookupPatchField<volScalarField>(qrName_);
357  }
358 
359  filmPatchi = pyrolysis.nbrCoupledPatchID(film, coupledPatchi);
360 
361  htcwfilm = film.htcw().h()().boundaryField()[filmPatchi];
362  film.toPrimary(filmPatchi, htcwfilm);
363 
364  // Obtain Tfilm at the boundary through Ts.
365  // NOTE: Tf is not good as at the boundary it will retrieve Tp
366  Tfilm = film.Ts().boundaryField()[filmPatchi];
367  film.toPrimary(filmPatchi, Tfilm);
368 
369  filmDelta = film.delta().boundaryField()[filmPatchi];
370  film.toPrimary(filmPatchi, filmDelta);
371  }
372  else
373  {
375  << type() << " condition is intended to be applied to either the "
376  << "primary or pyrolysis regions only"
377  << exit(FatalError);
378  }
379 
380  // Estimate wetness of the film (1: wet , 0: dry)
381  const scalarField ratio
382  (
383  min
384  (
385  max
386  (
387  (filmDelta - filmDeltaDry_)/(filmDeltaWet_ - filmDeltaDry_),
388  scalar(0)
389  ),
390  scalar(1)
391  )
392  );
393 
394  const scalarField qConv(ratio*htcwfilm*(Tfilm - Tp)*convectiveScaling_);
395  const scalarField qRad((1.0 - ratio)*qr);
396  const scalarField alpha(KDeltaNbr - (qRad + qConv)/Tp);
397 
398  valueFraction() = alpha/(alpha + (1.0 - ratio)*myKDelta);
399  refValue() = ratio*Tfilm + (1.0 - ratio)*(KDeltaNbr*nbrIntFld)/alpha;
400 
401  mixedFvPatchScalarField::updateCoeffs();
402 
403  if (debug)
404  {
405  scalar Qc = gSum(qConv*patch().magSf());
406  scalar qr = gSum(qRad*patch().magSf());
407  scalar Qt = gSum((qConv + qRad)*patch().magSf());
408 
409  Info<< mesh.name() << ':'
410  << patch().name() << ':'
411  << this->internalField().name() << " <- "
412  << nbrMesh.name() << ':'
413  << nbrPatch.name() << ':'
414  << this->internalField().name() << " :" << nl
415  << " convective heat[W] : " << Qc << nl
416  << " radiative heat [W] : " << qr << nl
417  << " total heat [W] : " << Qt << nl
418  << " wall temperature "
419  << " min:" << gMin(*this)
420  << " max:" << gMax(*this)
421  << " avg:" << gAverage(*this)
422  << endl;
423  }
424 }
425 
426 
428 (
429  Ostream& os
430 ) const
431 {
433  os.writeEntryIfDifferent<word>
434  (
435  "filmRegion",
436  "surfaceFilmProperties",
437  filmRegionName_
438  );
439  os.writeEntryIfDifferent<word>
440  (
441  "pyrolysisRegion",
442  "pyrolysisProperties",
443  pyrolysisRegionName_
444  );
445  os.writeEntry("Tnbr", TnbrName_);
446  os.writeEntry("qr", qrName_);
447  os.writeEntry("convectiveScaling", convectiveScaling_);
448  os.writeEntry("filmDeltaDry", filmDeltaDry_);
449  os.writeEntry("filmDeltaWet", filmDeltaWet_);
451 }
452 
453 
454 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
455 
457 (
459  filmPyrolysisRadiativeCoupledMixedFvPatchScalarField
460 );
461 
462 
463 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
464 
465 } // End namespace Foam
466 
467 
468 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
faceListList boundary
virtual void rmap(const fvPatchField< scalar > &, const labelList &)
Reverse map the given fvPatchField onto this fvPatchField.
Mixed boundary condition for temperature, to be used in the flow and pyrolysis regions when a film re...
dictionary dict
virtual void autoMap(const fvPatchFieldMapper &)
Map (and resize as needed) from self given a mapping object.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
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:598
Type gMin(const FieldField< Field, Type > &f)
tmp< scalarField > K() const
Get corresponding K field.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
virtual tmp< scalarField > kappa(const scalarField &Tp) const
Given patch temperature calculate corresponding K field.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
virtual tmp< scalarField > alpha(const scalarField &Tp) const
Given patch temperature calculate corresponding alphaEff field.
virtual void rmap(const fvPatchField< scalar > &, const labelList &)=0
Reverse map the given fvPatchField onto this fvPatchField.
virtual void autoMap(const fvPatchFieldMapper &)=0
Map (and resize as needed) from self given a mapping object.
void write(Ostream &os) const
Write.
Lookup type of boundary radiation properties.
Definition: lookup.H:57
CGAL::Exact_predicates_exact_constructions_kernel K
filmPyrolysisRadiativeCoupledMixedFvPatchScalarField(const fvPatch &, const DimensionedField< scalar, volMesh > &)
Construct from patch and internal field.
Macros for easy insertion into run-time selection tables.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:81
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
dynamicFvMesh & mesh
Type gSum(const FieldField< Field, Type > &f)
fvPatchField< scalar > fvPatchScalarField
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
A FieldMapper for finite-volume patch fields.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
int debug
Static debugging option.
Type gMax(const FieldField< Field, Type > &f)
OBJstream os(runTime.globalPath()/outputName)
virtual void updateCoeffs()
Update the coefficients associated with the patch field.
Common functions used in temperature coupled boundaries.
Type gAverage(const FieldField< Field, Type > &f)
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Definition: areaFieldsFwd.H:42
const std::string patch
OpenFOAM patch number as a std::string.
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual void write(Ostream &) const
Write.
volScalarField & p
makePatchTypeField(fvPatchScalarField, atmBoundaryLayerInletEpsilonFvPatchScalarField)
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127