1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "advectiveFvPatchField.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "fvPatchFieldMapper.H"
30 #include "volFields.H"
31 #include "EulerDdtScheme.H"
32 #include "CrankNicholsonDdtScheme.H"
33 #include "backwardDdtScheme.H"
34 #include "steadyStateDdtScheme.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
44 advectiveFvPatchField<Type>::advectiveFvPatchField
47 const DimensionedField<Type, volMesh>& iF
50 mixedFvPatchField<Type>(p, iF),
53 fieldInf_(pTraits<Type>::zero),
56 correctSupercritical_(false)
58 this->refValue() = pTraits<Type>::zero;
59 this->refGrad() = pTraits<Type>::zero;
60 this->valueFraction() = 0.0;
65 advectiveFvPatchField<Type>::advectiveFvPatchField
68 const DimensionedField<Type, volMesh>& iF,
69 const dictionary& dict
72 mixedFvPatchField<Type>(p, iF),
73 phiName_(dict.lookupOrDefault<word>("phi", "phi")),
74 rhoName_(dict.lookupOrDefault<word>("rho", "rho")),
75 fieldInf_(pTraits<Type>::zero),
77 inletOutlet_(dict.lookup("inletOutlet")),
78 correctSupercritical_(dict.lookup("correctSupercritical"))
80 if (dict.found("value"))
82 fvPatchField<Type>::operator=
84 Field<Type>("value", dict, p.size())
89 fvPatchField<Type>::operator=(this->patchInternalField());
92 this->refValue() = *this;
93 this->refGrad() = pTraits<Type>::zero;
94 this->valueFraction() = 0.0;
96 if (dict.readIfPresent("lInf", lInf_))
98 dict.lookup("fieldInf") >> fieldInf_;
104 "advectiveFvPatchField<Type>::"
105 "advectiveFvPatchField"
106 "(const fvPatch&, const Field<Type>&, const dictionary&)",
108 ) << "unphysical lInf specified (lInf < 0)\n"
109 << " on patch " << this->patch().name()
110 << " of field " << this->dimensionedInternalField().name()
111 << " in file " << this->dimensionedInternalField().objectPath()
112 << exit(FatalIOError);
119 advectiveFvPatchField<Type>::advectiveFvPatchField
121 const advectiveFvPatchField& ptf,
123 const DimensionedField<Type, volMesh>& iF,
124 const fvPatchFieldMapper& mapper
127 mixedFvPatchField<Type>(ptf, p, iF, mapper),
128 phiName_(ptf.phiName_),
129 rhoName_(ptf.rhoName_),
130 fieldInf_(ptf.fieldInf_),
132 inletOutlet_(ptf.inletOutlet_),
133 correctSupercritical_(ptf.correctSupercritical_)
138 advectiveFvPatchField<Type>::advectiveFvPatchField
140 const advectiveFvPatchField& ptpsf
143 mixedFvPatchField<Type>(ptpsf),
144 phiName_(ptpsf.phiName_),
145 rhoName_(ptpsf.rhoName_),
146 fieldInf_(ptpsf.fieldInf_),
148 inletOutlet_(ptpsf.inletOutlet_),
149 correctSupercritical_(ptpsf.correctSupercritical_)
154 advectiveFvPatchField<Type>::advectiveFvPatchField
156 const advectiveFvPatchField& ptpsf,
157 const DimensionedField<Type, volMesh>& iF
160 mixedFvPatchField<Type>(ptpsf, iF),
161 phiName_(ptpsf.phiName_),
162 rhoName_(ptpsf.rhoName_),
163 fieldInf_(ptpsf.fieldInf_),
165 inletOutlet_(ptpsf.inletOutlet_),
166 correctSupercritical_(ptpsf.correctSupercritical_)
170 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
173 tmp<scalarField> advectiveFvPatchField<Type>::advectionSpeed() const
175 const surfaceScalarField& phi =
176 this->db().objectRegistry::lookupObject<surfaceScalarField>(phiName_);
178 fvsPatchField<scalar> phip = this->patch().lookupPatchField
181 reinterpret_cast<const surfaceScalarField*>(0),
182 reinterpret_cast<const scalar*>(0)
185 if (phi.dimensions() == dimDensity*dimVelocity*dimArea)
187 const fvPatchScalarField& rhop = this->patch().lookupPatchField
190 reinterpret_cast<const volScalarField*>(0),
191 reinterpret_cast<const scalar*>(0)
194 return phip/(rhop*this->patch().magSf());
198 return phip/this->patch().magSf();
204 tmp<scalarField> advectiveFvPatchField<Type>::supercritical() const
206 // In base class, the condition is never supercritical
207 return tmp<scalarField>(new scalarField(this->size(), scalar(0)));
212 void advectiveFvPatchField<Type>::updateCoeffs()
219 const GeometricField<Type, fvPatchField, volMesh>& field =
220 this->db().objectRegistry::
221 lookupObject<GeometricField<Type, fvPatchField, volMesh> >
223 this->dimensionedInternalField().name()
228 this->dimensionedInternalField().mesh().ddtScheme(field.name())
231 // Calculate the advection speed of the field wave
232 // If the wave is incoming set the speed to 0.
233 scalarField w = Foam::max(advectionSpeed(), scalar(0));
236 scalarField deltaT(this->size(), this->db().time().deltaT().value());
238 // For steady-state, calculate formal deltaT from the
239 // under-relaxation factor
240 if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
242 // Get under-relaxation factor
244 // this->dimensionedInternalField().mesh().relaxationFactor
249 // deltaT = urf/(1 - urf)*1/(w*this->patch().deltaCoeffs() + SMALL);
251 // Set delta t for Co = 1
252 deltaT = 1/(w*this->patch().deltaCoeffs() + SMALL);
255 // Calculate the field wave coefficient alpha (See notes)
256 scalarField alpha = w*deltaT*this->patch().deltaCoeffs();
258 label patchi = this->patch().index();
260 // Non-reflecting outflow boundary
261 // If lInf_ defined setup relaxation to the value fieldInf_.
265 // Calculate the field relaxation coefficient k (See notes)
266 scalarField k = w*deltaT/lInf_;
270 ddtScheme == fv::EulerDdtScheme<Type>::typeName
271 || ddtScheme == fv::CrankNicholsonDdtScheme<Type>::typeName
276 field.oldTime().boundaryField()[patchi] + k*fieldInf_
279 this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
281 else if (ddtScheme == fv::backwardDdtScheme<Type>::typeName)
285 2.0*field.oldTime().boundaryField()[patchi]
286 - 0.5*field.oldTime().oldTime().boundaryField()[patchi]
290 this->valueFraction() = (1.5 + k)/(1.5 + alpha + k);
292 else if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
296 field.prevIter().boundaryField()[patchi] + k*fieldInf_
299 this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
305 "advectiveFvPatchField<Type>::updateCoeffs()"
306 ) << " Unsupported temporal differencing scheme : "
308 << "\n on patch " << this->patch().name()
309 << " of field " << this->dimensionedInternalField().name()
310 << " in file " << this->dimensionedInternalField().objectPath()
318 ddtScheme == fv::EulerDdtScheme<Type>::typeName
319 || ddtScheme == fv::CrankNicholsonDdtScheme<Type>::typeName
322 this->refValue() = field.oldTime().boundaryField()[patchi];
324 this->valueFraction() = 1.0/(1.0 + alpha);
326 else if (ddtScheme == fv::backwardDdtScheme<Type>::typeName)
330 2.0*field.oldTime().boundaryField()[patchi]
331 - 0.5*field.oldTime().oldTime().boundaryField()[patchi]
334 this->valueFraction() = 1.5/(1.5 + alpha);
336 else if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
338 this->refValue() = field.prevIter().boundaryField()[patchi];
340 this->valueFraction() = 1.0/(1.0 + alpha);
346 "advectiveFvPatchField<Type>::updateCoeffs()"
347 ) << " Unsupported temporal differencing scheme : "
349 << "\n on patch " << this->patch().name()
350 << " of field " << this->dimensionedInternalField().name()
351 << " in file " << this->dimensionedInternalField().objectPath()
356 // Get access to flux field
357 fvsPatchField<scalar> phip = this->patch().lookupPatchField
360 reinterpret_cast<const surfaceScalarField*>(NULL),
361 reinterpret_cast<const scalar*>(NULL)
364 // Treatment for supercritical inlet or outlet. HJ, 28/Oct/2009
365 // If the flow is faster than critical speed, the boundary condition
366 // needs to behave as zero gradient at outflow and fixed value at inflow.
367 // This is the case when eg. a wave-transmissive pressure outlet
368 // becomes supersonic. Face selection for supercritical outlet is
369 // done through a supercritical() virtual function: return 1 if
370 // flow is supercritical and zero otherwise
371 if (correctSupercritical_)
373 this->valueFraction() =
375 // If the flow is going out
376 // - set zero gradient for supercritical; otherwise use current
379 (scalar(1) - this->supercritical())
380 + this->supercritical()*this->valueFraction()
382 // If the flow is going in
383 // - set fixed value for supercritical; otherwise use current
386 this->supercritical()
387 + (scalar(1) - this->supercritical())*this->valueFraction()
392 // If the flow is going out
393 // - for supercritical, the value does not matter. use fieldInf_
394 // - for subcritical, use current value
397 this->supercritical()*fieldInf_
398 + (scalar(1) - this->supercritical())*this->refValue()
400 // If the flow is going in
401 // - for supercritical use fieldInf_
404 this->supercritical()*fieldInf_
405 + (scalar(1) - this->supercritical())*this->refValue()
409 // Inlet-outlet treatment at the boundary. HJ, 28/Oct/2009
410 // If the flux is outgoing, the normal condition is used
411 // if the flux is incoming, incoming value is set to fieldInf_
412 // (value = fieldInf, valueFraction = 1)
415 this->refValue() = pos(phip)*this->refValue() + neg(phip)*fieldInf_;
416 this->refGrad() = pTraits<Type>::zero;
417 this->valueFraction() = pos(phip)*this->valueFraction() + neg(phip);
420 mixedFvPatchField<Type>::updateCoeffs();
425 void advectiveFvPatchField<Type>::write(Ostream& os) const
427 fvPatchField<Type>::write(os);
429 if (phiName_ != "phi")
431 os.writeKeyword("phi") << phiName_ << token::END_STATEMENT << nl;
433 if (rhoName_ != "rho")
435 os.writeKeyword("rho") << rhoName_ << token::END_STATEMENT << nl;
440 os.writeKeyword("fieldInf") << fieldInf_
441 << token::END_STATEMENT << nl;
442 os.writeKeyword("lInf") << lInf_
443 << token::END_STATEMENT << endl;
446 os.writeKeyword("inletOutlet") << inletOutlet_
447 << token::END_STATEMENT << nl;
449 os.writeKeyword("correctSupercritical") << correctSupercritical_
450 << token::END_STATEMENT << nl;
452 this->writeEntry("value", os);
456 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
458 } // End namespace Foam
460 // ************************************************************************* //