Loading...
Searching...
No Matches
SemiImplicitSource.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) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2020-2022 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
29#include "SemiImplicitSource.H"
30#include "fvMesh.H"
31#include "fvMatrices.H"
32#include "fvmSup.H"
33#include "Constant.H"
34#include "Tuple2.H"
35
36// * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * * //
37
38template<class Type>
39const Foam::Enum
40<
42>
44({
45 { volumeModeType::vmAbsolute, "absolute" },
46 { volumeModeType::vmSpecific, "specific" },
47});
48
49
50// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
51
52template<class Type>
53void Foam::fv::SemiImplicitSource<Type>::setFieldCoeffs
54(
55 const dictionary& dict,
56 const word& keyExplicit,
57 const word& keyImplicit
58)
59{
60 label count = dict.size();
61
62 fieldNames_.resize_nocopy(count);
63
64 Su_.clear();
65 Sp_.clear();
66 Su_.reserve(count);
67 Sp_.reserve(count);
68
69 driverSu_.clear();
70 driverSp_.clear();
71 driverSu_.reserve(count);
72 driverSp_.reserve(count);
73
74 valueExprSu_.clear();
75 valueExprSp_.clear();
76 valueExprSu_.reserve(count);
77 valueExprSp_.reserve(count);
78
79 fv::option::resetApplied();
80
81 word modelType;
82 Tuple2<Type, scalar> sourceRates;
83
84 count = 0;
85
86 for (const entry& dEntry : dict)
87 {
88 const word& fieldName = dEntry.keyword();
89 bool ok = false;
90
91 if (dEntry.isDict())
92 {
93 const dictionary& subDict = dEntry.dict();
94
95 const entry* eptr;
96
97 if
98 (
99 (eptr = subDict.findEntry(keyExplicit, keyType::LITERAL))
100 != nullptr
101 )
102 {
103 ok = true;
104
105 if
106 (
107 eptr->isDict()
108 && eptr->dict().readEntry("type", modelType, keyType::LITERAL)
109 && (modelType == "exprField")
110 )
111 {
112 const dictionary& exprDict = eptr->dict();
113
114 valueExprSu_.emplace_set(fieldName);
115 valueExprSu_[fieldName].readEntry("expression", exprDict);
116
117 driverSu_.set
118 (
119 fieldName,
120 new expressions::volumeExprDriver(mesh_, exprDict)
121 );
122 }
123 else
124 {
125 Su_.set
126 (
127 fieldName,
128 Function1<Type>::New(keyExplicit, subDict, &mesh_)
129 );
130 }
131 }
132
133 if
134 (
135 (eptr = subDict.findEntry(keyImplicit, keyType::LITERAL))
136 != nullptr
137 )
138 {
139 ok = true;
140
141 if
142 (
143 eptr->isDict()
144 && eptr->dict().readEntry("type", modelType, keyType::LITERAL)
145 && (modelType == "exprField")
146 )
147 {
148 const dictionary& exprDict = eptr->dict();
149
150 valueExprSp_.emplace_set(fieldName);
151 valueExprSp_[fieldName].readEntry("expression", exprDict);
152
153 driverSp_.set
154 (
155 fieldName,
156 new expressions::volumeExprDriver(mesh_, exprDict)
157 );
158 }
159 else
160 {
161 Sp_.set
162 (
163 fieldName,
164 Function1<scalar>::New(keyImplicit, subDict, &mesh_)
165 );
166 }
167 }
168 }
169 else
170 {
171 // Non-dictionary form
172
173 dEntry.readEntry(sourceRates);
174
175 ok = true;
176
177 Su_.set
178 (
179 fieldName,
180 new Function1Types::Constant<Type>
181 (
182 keyExplicit,
183 sourceRates.first()
184 )
185 );
186 Sp_.set
187 (
188 fieldName,
189 new Function1Types::Constant<scalar>
190 (
191 keyImplicit,
192 sourceRates.second()
193 )
194 );
195 }
196
197 if (!ok)
198 {
200 << "Require at least one of "
201 << keyExplicit << '/' << keyImplicit << " entries for "
202 << "field: " << fieldName << endl
203 << exit(FatalIOError);
204 }
205
206 fieldNames_[count] = fieldName;
207 ++count;
209}
210
211
212// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
213
214template<class Type>
216(
217 const word& name,
218 const word& modelType,
219 const dictionary& dict,
220 const fvMesh& mesh
221)
222:
223 fv::cellSetOption(name, modelType, dict, mesh),
224 volumeMode_(vmAbsolute),
225 VDash_(1)
226{
228}
229
230
231// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
232
233template<class Type>
235(
236 fvMatrix<Type>& eqn,
237 const label fieldi
239{
240 return this->addSup(volScalarField::null(), eqn, fieldi);
241}
242
243
244template<class Type>
246(
247 const volScalarField& rho,
248 fvMatrix<Type>& eqn,
249 const label fieldi
250)
251{
252 if (debug)
253 {
254 Info<< "SemiImplicitSource<" << pTraits<Type>::typeName
255 << ">::addSup for source " << name_ << endl;
256 }
257
259
260 // Note: field name may deviate from psi name
261 const word& fieldName = fieldNames_[fieldi];
262
263 const scalar tmVal = mesh_.time().timeOutputValue();
264
265 const dimensionSet SuDims(eqn.dimensions()/dimVolume);
266 const dimensionSet SpDims(SuDims/psi.dimensions());
267
268 // Explicit source
269 {
270 const auto iter1 = valueExprSu_.cfind(fieldName);
271 const auto iter2 = Su_.cfind(fieldName);
272
274
275 if (iter1.good())
276 {
277 const auto& valueExpr = iter1.val();
278
279 typedef
281 ExprResultType;
282
283 if (debug)
284 {
285 Info<< "Explicit expression source:" << nl
286 << ">>>>" << nl
287 << valueExpr.c_str() << nl
288 << "<<<<" << nl;
289 }
290
291 auto& driver = *(driverSu_[fieldName]);
292
293 driver.clearVariables();
294
295 if (notNull(rho))
296 {
297 driver.addContextObject("rho", &rho);
298 }
299
300 // Switch dimension checking off
301 const bool oldDimChecking = dimensionSet::checking(false);
302
303 driver.parse(valueExpr);
304
305 // Restore dimension checking
306 dimensionSet::checking(oldDimChecking);
307
308 const ExprResultType* ptr =
309 driver.template isResultType<ExprResultType>();
310
311 if (!ptr)
312 {
314 << "Expression for Su " << fieldName
315 << " evaluated to <" << driver.resultType()
316 << "> but expected <" << ExprResultType::typeName
317 << ">" << endl
318 << exit(FatalError);
319 }
320 else if (ptr->size() != mesh_.nCells())
321 {
323 << "Expression for Su " << fieldName
324 << " evaluated to " << ptr->size()
325 << " instead of " << mesh_.nCells() << " values" << endl
326 << exit(FatalError);
327 }
328
329 if (notNull(rho))
330 {
331 driver.removeContextObject(&rho);
332 }
333
334 const Field<Type>& exprFld = ptr->primitiveField();
335
337 (
338 name_ + fieldName + "Su",
340 mesh_,
341 dimensioned<Type>(SuDims, Zero)
342 );
343
344 if (this->useSubMesh())
345 {
346 for (const label celli : cells_)
347 {
348 tsu.ref()[celli] = exprFld[celli]/VDash_;
349 }
350 }
351 else
352 {
353 tsu.ref().field() = exprFld;
354
355 if (!equal(VDash_, 1))
356 {
357 tsu.ref().field() /= VDash_;
358 }
359 }
360 }
361 else if (iter2.good() && iter2.val()->good())
362 {
363 const dimensioned<Type> SuValue
364 (
365 "Su",
366 SuDims,
367 iter2.val()->value(tmVal)/VDash_
368 );
369
370 if (mag(SuValue.value()) <= ROOTVSMALL)
371 {
372 // No-op
373 }
374 else if (this->useSubMesh())
375 {
377 (
378 name_ + fieldName + "Su",
380 mesh_,
381 dimensioned<Type>(SuDims, Zero)
382 );
383 UIndirectList<Type>(tsu.ref(), cells_) = SuValue.value();
384 }
385 else
386 {
387 eqn += SuValue;
388 }
389 }
390
391 if (tsu.valid())
392 {
393 eqn += tsu;
394 }
395 }
396
397
398 // Implicit source
399 {
400 const auto iter1 = valueExprSp_.cfind(fieldName);
401 const auto iter2 = Sp_.cfind(fieldName);
402
403 tmp<DimensionedField<scalar, volMesh>> tsp;
404
405 if (iter1.good())
406 {
407 const auto& valueExpr = iter1.val();
408
409 typedef volScalarField ExprResultType;
410
411 if (debug)
412 {
413 Info<< "Implicit expression source:" << nl
414 << ">>>>" << nl
415 << valueExpr.c_str() << nl
416 << "<<<<" << nl;
417 }
418
419 auto& driver = *(driverSp_[fieldName]);
420
421 driver.clearVariables();
422
423 if (notNull(rho))
424 {
425 driver.addContextObject("rho", &rho);
426 }
427
428 // Switch dimension checking off
429 const bool oldDimChecking = dimensionSet::checking(false);
430
431 driver.parse(valueExpr);
432
433 // Restore dimension checking
434 dimensionSet::checking(oldDimChecking);
435
436 const ExprResultType* ptr =
437 driver.template isResultType<ExprResultType>();
438
439 if (!ptr)
440 {
442 << "Expression for Sp " << fieldName
443 << " evaluated to <" << driver.resultType()
444 << "> but expected <" << ExprResultType::typeName
445 << ">" << endl
446 << exit(FatalError);
447 }
448 else if (ptr->size() != mesh_.nCells())
449 {
451 << "Expression for Sp " << fieldName
452 << " evaluated to " << ptr->size()
453 << " instead of " << mesh_.nCells() << " values" << endl
454 << exit(FatalError);
455 }
456
457 if (notNull(rho))
458 {
459 driver.removeContextObject(&rho);
460 }
461
462 const Field<scalar>& exprFld = ptr->primitiveField();
463
465 (
466 name_ + fieldName + "Sp",
468 mesh_,
469 dimensioned<scalar>(SpDims, Zero)
470 );
471
472 if (this->useSubMesh())
473 {
474 for (const label celli : cells_)
475 {
476 tsp.ref()[celli] = exprFld[celli]/VDash_;
477 }
478 }
479 else
480 {
481 tsp.ref().field() = exprFld;
482
483 if (!equal(VDash_, 1))
484 {
485 tsp.ref().field() /= VDash_;
486 }
487 }
488 }
489 else if (iter2.good() && iter2.val()->good())
490 {
491 const dimensioned<scalar> SpValue
492 (
493 "Sp",
494 SpDims,
495 iter2.val()->value(tmVal)/VDash_
496 );
497
498 if (mag(SpValue.value()) <= ROOTVSMALL)
499 {
500 // No-op
501 }
502 else if (this->useSubMesh())
503 {
505 (
506 name_ + fieldName + "Sp",
508 mesh_,
509 dimensioned<scalar>(SpDims, Zero)
510 );
511 UIndirectList<scalar>(tsp.ref(), cells_) = SpValue.value();
512 }
513 else
514 {
515 eqn += fvm::SuSp(SpValue, psi);
516 }
517 }
518
519 if (tsp.valid())
520 {
521 eqn += fvm::SuSp(tsp, psi);
522 }
523 }
524}
525
526
527template<class Type>
529{
530 VDash_ = 1;
531
533 {
534 volumeMode_ = volumeModeTypeNames_.get("volumeMode", coeffs_);
535
536 // Set volume normalisation
537 if (volumeMode_ == vmAbsolute)
538 {
539 VDash_ = V_;
540 }
541
542 // Compatibility (2112 and earlier)
543 const dictionary* injectDict =
544 coeffs_.findDict("injectionRateSuSp", keyType::LITERAL);
545
546 if (injectDict)
547 {
548 setFieldCoeffs
549 (
550 *injectDict,
551 "Su", // Su = explicit
552 "Sp" // Sp = implicit
553 );
554 }
555 else
556 {
557 setFieldCoeffs
558 (
559 coeffs_.subDict("sources", keyType::LITERAL),
560 "explicit",
561 "implicit"
562 );
563 }
564
565 return true;
566 }
567
568 return false;
569}
570
571
572// ************************************************************************* //
static tmp< DimensionedField< Type, GeoMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const Field< Type > &iField)
Return tmp field (NO_READ, NO_WRITE) from name, mesh, dimensions, copy of internal field....
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition Enum.H:57
Generic templated field type that is much like a Foam::List except that it is expected to hold numeri...
Definition Field.H:172
Generic GeometricField class.
@ NO_REGISTER
Do not request registration (bool: false).
A List with indirect addressing. Like IndirectList but does not store addressing.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
Dimension set for the base types, which can be used to implement rigorous dimension checking for alge...
static bool checking() noexcept
True if dimension checking is enabled (the usual default).
Generic dimensioned Type class.
const Type & value() const noexcept
Return const reference to value.
A special matrix type and solver, designed for finite volume solutions of scalar equations....
Definition fvMatrix.H:118
const dimensionSet & dimensions() const noexcept
Definition fvMatrix.H:530
const GeometricField< Type, fvPatchField, volMesh > & psi(const label i=0) const
Return psi.
Definition fvMatrix.H:487
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
virtual void addSup(fvMatrix< Type > &eqn, const label fieldi)
Add explicit contribution to incompressible equation.
static const Enum< volumeModeType > volumeModeTypeNames_
Names for volumeModeType.
virtual bool read(const dictionary &dict)
Read source dictionary.
SemiImplicitSource(const word &name, const word &modelType, const dictionary &dict, const fvMesh &mesh)
Construct from components.
volumeModeType
Options for the volume mode type.
labelList cells_
Set of cells to apply source to.
virtual bool read(const dictionary &dict)
Read source dictionary.
cellSetOption(const word &name, const word &modelType, const dictionary &dict, const fvMesh &mesh)
Construct from components.
scalar V_
Sum of cell volumes.
bool useSubMesh() const noexcept
True if sub-selection should be used.
const word & name() const noexcept
Return const access to the source name.
Definition fvOptionI.H:24
const fvMesh & mesh_
Reference to the mesh database.
Definition fvOption.H:142
wordList fieldNames_
Field names to apply source to - populated by derived models.
Definition fvOption.H:157
dictionary coeffs_
Dictionary containing source coefficients.
Definition fvOption.H:152
const fvMesh & mesh() const noexcept
Return const access to the mesh database.
Definition fvOptionI.H:30
const word name_
Source name.
Definition fvOption.H:132
@ LITERAL
String literal.
Definition keyType.H:82
A traits class, which is primarily used for primitives and vector-space.
Definition pTraits.H:64
A class for managing temporary objects.
Definition tmp.H:75
bool valid() const noexcept
Identical to good(), or bool operator.
Definition tmp.H:481
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition tmpI.H:235
A class for handling words, derived from Foam::string.
Definition word.H:66
const volScalarField & psi
dynamicFvMesh & mesh
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition error.H:629
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
A special matrix type and solver, designed for finite volume solutions of scalar equations.
Calculate the finiteVolume matrix for implicit and explicit sources.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for finite-volume.
zeroField SuSp(const Foam::zero, const GeometricField< Type, fvPatchField, volMesh > &)
A no-op source.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition label.H:180
messageStream Info
Information stream (stdout output on master, null elsewhere).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
const dimensionSet dimVolume(pow3(dimLength))
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
bool notNull(const T *ptr) noexcept
True if ptr is not a pointer (of type T) to the nullObject.
Definition nullObject.H:267
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict