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 "supersonicFreestreamFvPatchVectorField.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "fvPatchFieldMapper.H"
30 #include "volFields.H"
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
39 supersonicFreestreamFvPatchVectorField::supersonicFreestreamFvPatchVectorField
42 const DimensionedField<vector, volMesh>& iF
45 mixedFvPatchVectorField(p, iF),
51 refValue() = patchInternalField();
52 refGrad() = vector::zero;
57 supersonicFreestreamFvPatchVectorField::supersonicFreestreamFvPatchVectorField
59 const supersonicFreestreamFvPatchVectorField& ptf,
61 const DimensionedField<vector, volMesh>& iF,
62 const fvPatchFieldMapper& mapper
65 mixedFvPatchVectorField(ptf, p, iF, mapper),
73 supersonicFreestreamFvPatchVectorField::supersonicFreestreamFvPatchVectorField
76 const DimensionedField<vector, volMesh>& iF,
77 const dictionary& dict
80 mixedFvPatchVectorField(p, iF),
81 UInf_(dict.lookup("UInf")),
82 pInf_(readScalar(dict.lookup("pInf"))),
83 TInf_(readScalar(dict.lookup("TInf"))),
84 gamma_(readScalar(dict.lookup("gamma")))
86 if (dict.found("value"))
88 fvPatchField<vector>::operator=
90 vectorField("value", dict, p.size())
95 fvPatchField<vector>::operator=(patchInternalField());
99 refGrad() = vector::zero;
106 "supersonicFreestreamFvPatchVectorField::"
107 "supersonicFreestreamFvPatchVectorField"
108 "(const fvPatch&, const vectorField&, const dictionary&)",
110 ) << " unphysical pInf specified (pInf <= 0.0)"
111 << "\n on patch " << this->patch().name()
112 << " of field " << this->dimensionedInternalField().name()
113 << " in file " << this->dimensionedInternalField().objectPath()
114 << exit(FatalIOError);
119 supersonicFreestreamFvPatchVectorField::supersonicFreestreamFvPatchVectorField
121 const supersonicFreestreamFvPatchVectorField& sfspvf
124 mixedFvPatchVectorField(sfspvf),
128 gamma_(sfspvf.gamma_)
132 supersonicFreestreamFvPatchVectorField::supersonicFreestreamFvPatchVectorField
134 const supersonicFreestreamFvPatchVectorField& sfspvf,
135 const DimensionedField<vector, volMesh>& iF
138 mixedFvPatchVectorField(sfspvf, iF),
142 gamma_(sfspvf.gamma_)
146 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
148 void supersonicFreestreamFvPatchVectorField::updateCoeffs()
150 if (!size() || updated())
155 const fvPatchField<scalar>& pT =
156 patch().lookupPatchField<volScalarField, scalar>("T");
158 const fvPatchField<scalar>& pp =
159 patch().lookupPatchField<volScalarField, scalar>("p");
161 const fvPatchField<scalar>& ppsi =
162 patch().lookupPatchField<volScalarField, scalar>("psi");
164 // Need R of the free-stream flow. Assume R is independent of location
165 // along patch so use face 0
166 scalar R = 1.0/(ppsi[0]*pT[0]);
168 scalar MachInf = mag(UInf_)/sqrt(gamma_*R*TInf_);
174 "supersonicFreestreamFvPatchVectorField::updateCoeffs()"
175 ) << " MachInf < 1.0, free stream must be supersonic"
176 << "\n on patch " << this->patch().name()
177 << " of field " << this->dimensionedInternalField().name()
178 << " in file " << this->dimensionedInternalField().objectPath()
182 vectorField& Up = refValue();
185 // get the near patch internal cell values
186 vectorField U = patchInternalField();
189 // Find the component of U normal to the free-stream flow and in the
190 // plane of the free-stream flow and the patch normal
192 // Direction of the free-stream flow
193 vector UInfHat = UInf_/mag(UInf_);
195 // Normal to the plane defined by the free-stream and the patch normal
196 vectorField nnInfHat = UInfHat ^ patch().nf();
198 //vectorField UnInf = U - nnInfHat*(nnInfHat & U);
199 //vectorField Un = UnInf - UInfHat*(UInfHat & UnInf);
200 //vectorField nHatInf =
201 // (Un/(mag(Un) + SMALL)) * sign(patch().nf() & Un);
203 // Normal to the free-stream in the plane defined by the free-stream
204 // and the patch normal
205 vectorField nHatInf = nnInfHat ^ UInfHat;
207 // Component of U normal to the free-stream in the plane defined by the
208 // free-stream and the patch normal
209 vectorField Un = nHatInf*(nHatInf & U);
211 // The tangential component is
212 vectorField Ut = U - Un;
214 // Calculate the Prandtl-Meyer function of the free-stream
216 sqrt((gamma_ + 1)/(gamma_ - 1))
217 *atan(sqrt((gamma_ - 1)/(gamma_ + 1)*(sqr(MachInf) - 1)))
218 - atan(sqr(MachInf) - 1);
221 // Set the patch boundary condition based on the Mach number and direction
222 // of the flow dictated by the boundary/free-stream pressure difference
226 if (pp[facei] >= pInf_) // If outflow
228 // Assume supersonic outflow and calculate the boundary velocity
232 sqrt(sqr(MachInf) - 1)
233 /(gamma_*sqr(MachInf))*mag(Ut[facei])*log(pp[facei]/pInf_);
235 Up[facei] = Ut[facei] + fpp*nHatInf[facei];
237 // Calculate the Mach number of the boundary velocity
238 scalar Mach = mag(Up[facei])/sqrt(gamma_/ppsi[facei]);
240 if (Mach <= 1) // If subsonic
242 // Zero-gradient subsonic outflow
244 Up[facei] = U[facei];
245 valueFraction()[facei] = 0;
250 // Calculate the Mach number of the boundary velocity
251 // from the boundary pressure assuming constant total pressure
252 // expansion from the free-stream
256 (2/(gamma_ - 1))*(1 + ((gamma_ - 1)/2)*sqr(MachInf))
257 *pow(pp[facei]/pInf_, (1 - gamma_)/gamma_)
261 if (Mach > 1) // If supersonic
263 // Supersonic inflow is assumed to occur according to the
264 // Prandtl-Meyer expansion process
267 sqrt((gamma_ + 1)/(gamma_ - 1))
268 *atan(sqrt((gamma_ - 1)/(gamma_ + 1)*(sqr(Mach) - 1)))
269 - atan(sqr(Mach) - 1);
271 scalar fpp = (nuMachInf - nuMachf)*mag(Ut[facei]);
273 Up[facei] = Ut[facei] + fpp*nHatInf[facei];
279 "supersonicFreestreamFvPatchVectorField::updateCoeffs()"
280 ) << "unphysical subsonic inflow has been generated"
281 << "\n on patch " << this->patch().name()
282 << " of field " << this->dimensionedInternalField().name()
284 << this->dimensionedInternalField().objectPath()
290 mixedFvPatchVectorField::updateCoeffs();
294 void supersonicFreestreamFvPatchVectorField::write(Ostream& os) const
296 fvPatchVectorField::write(os);
297 os.writeKeyword("UInf") << UInf_ << token::END_STATEMENT << nl;
298 os.writeKeyword("pInf") << pInf_ << token::END_STATEMENT << nl;
299 os.writeKeyword("TInf") << TInf_ << token::END_STATEMENT << nl;
300 os.writeKeyword("gamma") << gamma_ << token::END_STATEMENT << nl;
301 writeEntry("value", os);
305 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
310 supersonicFreestreamFvPatchVectorField
313 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
315 } // End namespace Foam
317 // ************************************************************************* //