1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "advectiveFvPatchField.H"
27 #include "addToRunTimeSelectionTable.H"
28 #include "fvPatchFieldMapper.H"
29 #include "volFields.H"
30 #include "EulerDdtScheme.H"
31 #include "CrankNicolsonDdtScheme.H"
32 #include "backwardDdtScheme.H"
33 #include "steadyStateDdtScheme.H"
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
43 advectiveFvPatchField<Type>::advectiveFvPatchField
46 const DimensionedField<Type, volMesh>& iF
49 mixedFvPatchField<Type>(p, iF),
52 fieldInf_(pTraits<Type>::zero),
55 correctSupercritical_(false)
57 this->refValue() = pTraits<Type>::zero;
58 this->refGrad() = pTraits<Type>::zero;
59 this->valueFraction() = 0.0;
64 advectiveFvPatchField<Type>::advectiveFvPatchField
67 const DimensionedField<Type, volMesh>& iF,
68 const dictionary& dict
71 mixedFvPatchField<Type>(p, iF),
72 phiName_(dict.lookupOrDefault<word>("phi", "phi")),
73 rhoName_(dict.lookupOrDefault<word>("rho", "rho")),
74 fieldInf_(pTraits<Type>::zero),
76 inletOutlet_(dict.lookup("inletOutlet")),
77 correctSupercritical_(dict.lookup("correctSupercritical"))
79 if (dict.found("value"))
81 fvPatchField<Type>::operator=
83 Field<Type>("value", dict, p.size())
88 fvPatchField<Type>::operator=(this->patchInternalField());
91 this->refValue() = *this;
92 this->refGrad() = pTraits<Type>::zero;
93 this->valueFraction() = 0.0;
95 if (dict.readIfPresent("lInf", lInf_))
97 dict.lookup("fieldInf") >> fieldInf_;
103 "advectiveFvPatchField<Type>::"
104 "advectiveFvPatchField"
105 "(const fvPatch&, const Field<Type>&, const dictionary&)",
107 ) << "unphysical lInf specified (lInf < 0)\n"
108 << " on patch " << this->patch().name()
109 << " of field " << this->dimensionedInternalField().name()
110 << " in file " << this->dimensionedInternalField().objectPath()
111 << exit(FatalIOError);
118 advectiveFvPatchField<Type>::advectiveFvPatchField
120 const advectiveFvPatchField& ptf,
122 const DimensionedField<Type, volMesh>& iF,
123 const fvPatchFieldMapper& mapper
126 mixedFvPatchField<Type>(ptf, p, iF, mapper),
127 phiName_(ptf.phiName_),
128 rhoName_(ptf.rhoName_),
129 fieldInf_(ptf.fieldInf_),
131 inletOutlet_(ptf.inletOutlet_),
132 correctSupercritical_(ptf.correctSupercritical_)
137 advectiveFvPatchField<Type>::advectiveFvPatchField
139 const advectiveFvPatchField& ptpsf
142 mixedFvPatchField<Type>(ptpsf),
143 phiName_(ptpsf.phiName_),
144 rhoName_(ptpsf.rhoName_),
145 fieldInf_(ptpsf.fieldInf_),
147 inletOutlet_(ptpsf.inletOutlet_),
148 correctSupercritical_(ptpsf.correctSupercritical_)
153 advectiveFvPatchField<Type>::advectiveFvPatchField
155 const advectiveFvPatchField& ptpsf,
156 const DimensionedField<Type, volMesh>& iF
159 mixedFvPatchField<Type>(ptpsf, iF),
160 phiName_(ptpsf.phiName_),
161 rhoName_(ptpsf.rhoName_),
162 fieldInf_(ptpsf.fieldInf_),
164 inletOutlet_(ptpsf.inletOutlet_),
165 correctSupercritical_(ptpsf.correctSupercritical_)
169 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
172 tmp<scalarField> advectiveFvPatchField<Type>::advectionSpeed() const
174 const surfaceScalarField& phi =
175 this->db().objectRegistry::template lookupObject<surfaceScalarField>
180 fvsPatchField<scalar> phip = this->lookupPatchField
183 reinterpret_cast<const surfaceScalarField*>(0),
184 reinterpret_cast<const scalar*>(0)
187 if (phi.dimensions() == dimDensity*dimVelocity*dimArea)
189 const fvPatchScalarField& rhop = this->lookupPatchField
192 reinterpret_cast<const volScalarField*>(0),
193 reinterpret_cast<const scalar*>(0)
196 return phip/(rhop*this->patch().magSf());
200 return phip/this->patch().magSf();
206 tmp<scalarField> advectiveFvPatchField<Type>::supercritical() const
208 // In base class, the condition is never supercritical
209 return tmp<scalarField>(new scalarField(this->size(), scalar(0)));
214 void advectiveFvPatchField<Type>::updateCoeffs()
221 const GeometricField<Type, fvPatchField, volMesh>& field =
222 this->db().objectRegistry::template
223 lookupObject<GeometricField<Type, fvPatchField, volMesh> >
225 this->dimensionedInternalField().name()
230 this->dimensionedInternalField().mesh().schemesDict().ddtScheme
236 // Calculate the advection speed of the field wave
237 // If the wave is incoming set the speed to 0.
238 scalarField w = Foam::max(advectionSpeed(), scalar(0));
241 scalarField deltaT(this->size(), this->db().time().deltaT().value());
243 // For steady-state, calculate formal deltaT from the
244 // under-relaxation factor
245 if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
247 // Get under-relaxation factor
249 // this->dimensionedInternalField().mesh().relaxationFactor
254 // deltaT = urf/(1 - urf)*1/(w*this->patch().deltaCoeffs() + SMALL);
256 // Set delta t for Co = 1
257 deltaT = 1/(w*this->patch().deltaCoeffs() + SMALL);
260 // Calculate the field wave coefficient alpha (See notes)
261 scalarField alpha = w*deltaT*this->patch().deltaCoeffs();
263 label patchi = this->patch().index();
265 // Non-reflecting outflow boundary
266 // If lInf_ defined setup relaxation to the value fieldInf_.
270 // Calculate the field relaxation coefficient k (See notes)
271 scalarField k = w*deltaT/lInf_;
275 ddtScheme == fv::EulerDdtScheme<Type>::typeName
276 || ddtScheme == fv::CrankNicolsonDdtScheme<Type>::typeName
281 field.oldTime().boundaryField()[patchi] + k*fieldInf_
284 this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
286 else if (ddtScheme == fv::backwardDdtScheme<Type>::typeName)
290 2.0*field.oldTime().boundaryField()[patchi]
291 - 0.5*field.oldTime().oldTime().boundaryField()[patchi]
295 this->valueFraction() = (1.5 + k)/(1.5 + alpha + k);
297 else if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
301 field.prevIter().boundaryField()[patchi] + k*fieldInf_
304 this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
310 "advectiveFvPatchField<Type>::updateCoeffs()"
311 ) << " Unsupported temporal differencing scheme : "
313 << "\n on patch " << this->patch().name()
314 << " of field " << this->dimensionedInternalField().name()
315 << " in file " << this->dimensionedInternalField().objectPath()
323 ddtScheme == fv::EulerDdtScheme<Type>::typeName
324 || ddtScheme == fv::CrankNicolsonDdtScheme<Type>::typeName
327 this->refValue() = field.oldTime().boundaryField()[patchi];
329 this->valueFraction() = 1.0/(1.0 + alpha);
331 else if (ddtScheme == fv::backwardDdtScheme<Type>::typeName)
335 2.0*field.oldTime().boundaryField()[patchi]
336 - 0.5*field.oldTime().oldTime().boundaryField()[patchi]
339 this->valueFraction() = 1.5/(1.5 + alpha);
341 else if (ddtScheme == fv::steadyStateDdtScheme<Type>::typeName)
343 this->refValue() = field.prevIter().boundaryField()[patchi];
345 this->valueFraction() = 1.0/(1.0 + alpha);
351 "advectiveFvPatchField<Type>::updateCoeffs()"
352 ) << " Unsupported temporal differencing scheme : "
354 << "\n on patch " << this->patch().name()
355 << " of field " << this->dimensionedInternalField().name()
356 << " in file " << this->dimensionedInternalField().objectPath()
361 // Get access to flux field
362 fvsPatchField<scalar> phip = this->lookupPatchField
365 reinterpret_cast<const surfaceScalarField*>(NULL),
366 reinterpret_cast<const scalar*>(NULL)
369 // Treatment for supercritical inlet or outlet. HJ, 28/Oct/2009
370 // If the flow is faster than critical speed, the boundary condition
371 // needs to behave as zero gradient at outflow and fixed value at inflow.
372 // This is the case when eg. a wave-transmissive pressure outlet
373 // becomes supersonic. Face selection for supercritical outlet is
374 // done through a supercritical() virtual function: return 1 if
375 // flow is supercritical and zero otherwise
376 if (correctSupercritical_)
378 this->valueFraction() =
380 // If the flow is going out
381 // - set zero gradient for supercritical; otherwise use current
384 (scalar(1) - this->supercritical())
385 + this->supercritical()*this->valueFraction()
387 // If the flow is going in
388 // - set fixed value for supercritical; otherwise use current
391 this->supercritical()
392 + (scalar(1) - this->supercritical())*this->valueFraction()
397 // If the flow is going out
398 // - for supercritical, the value does not matter. use fieldInf_
399 // - for subcritical, use current value
402 this->supercritical()*fieldInf_
403 + (scalar(1) - this->supercritical())*this->refValue()
405 // If the flow is going in
406 // - for supercritical use fieldInf_
409 this->supercritical()*fieldInf_
410 + (scalar(1) - this->supercritical())*this->refValue()
414 // Inlet-outlet treatment at the boundary. HJ, 28/Oct/2009
415 // If the flux is outgoing, the normal condition is used
416 // if the flux is incoming, incoming value is set to fieldInf_
417 // (value = fieldInf, valueFraction = 1)
420 this->refValue() = pos(phip)*this->refValue() + neg(phip)*fieldInf_;
421 this->refGrad() = pTraits<Type>::zero;
422 this->valueFraction() = pos(phip)*this->valueFraction() + neg(phip);
425 mixedFvPatchField<Type>::updateCoeffs();
430 void advectiveFvPatchField<Type>::write(Ostream& os) const
432 fvPatchField<Type>::write(os);
434 this->writeEntryIfDifferent(os, "phi", word("phi"), phiName_);
435 this->writeEntryIfDifferent(os, "rho", word("rho"), rhoName_);
439 os.writeKeyword("fieldInf") << fieldInf_
440 << token::END_STATEMENT << nl;
441 os.writeKeyword("lInf") << lInf_
442 << token::END_STATEMENT << endl;
445 os.writeKeyword("inletOutlet") << inletOutlet_
446 << token::END_STATEMENT << nl;
448 os.writeKeyword("correctSupercritical") << correctSupercritical_
449 << token::END_STATEMENT << nl;
451 this->writeEntry("value", os);
455 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
457 } // End namespace Foam
459 // ************************************************************************* //