Nektar++
RedlichKwongEoS.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: RedlichKwongEoS.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Redlich-Kwong equation of state
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include "RedlichKwongEoS.h"
36 
37 using namespace std;
38 
39 namespace Nektar
40 {
41 
42 std::string RedlichKwongEoS::className =
44  "RedlichKwong", RedlichKwongEoS::create,
45  "Redlich-Kwong equation of state.");
46 
47 RedlichKwongEoS::RedlichKwongEoS(
49  : EquationOfState(pSession)
50 {
51  pSession->LoadParameter("Tcrit", m_Tc);
52  pSession->LoadParameter("Pcrit", m_Pc);
53 
54  m_a = 0.42748 * m_gasConstant * m_gasConstant * m_Tc * m_Tc / m_Pc;
55  m_b = 0.08664 * m_gasConstant * m_Tc / m_Pc;
56 }
57 
59  const NekDouble &e)
60 {
61  // First we need to evaluate the log term
62  // ln[1 + b*rho]
63  NekDouble logTerm = LogTerm(rho);
64 
65  // The temperature can be expressed as an equation in the form
66  // (T^1/2)^3 + A* T^1/2 + B = 0, which we solve iteratively
67  NekDouble A, B;
68 
69  A = -e * (m_gamma - 1) / m_gasConstant;
70  B = -3.0 * m_a / (2.0 * m_b * m_gasConstant) * (m_gamma - 1) * sqrt(m_Tc) *
71  logTerm;
72 
73  // Use ideal gas solution as starting guess for iteration
74  NekDouble sqrtT = sqrt(e * (m_gamma - 1) / m_gasConstant);
75  // Newton-Raphson iteration to find T^(1/2)
76  NekDouble tol = 1e-6;
77  NekDouble maxIter = 100;
78  NekDouble residual = 1;
79  NekDouble f, df;
80  unsigned int cnt = 0;
81  while (abs(residual) > tol && cnt < maxIter)
82  {
83  f = sqrtT * sqrtT * sqrtT + A * sqrtT + B;
84  df = 3 * sqrtT * sqrtT + A;
85  residual = f / df;
86  sqrtT -= residual;
87  ++cnt;
88  }
89  if (cnt == maxIter)
90  {
91  cout << "Newton-Raphson in RedlichKwongEoS::v_GetTemperature did not "
92  "converge in "
93  << maxIter << " iterations (residual = " << residual << ")"
94  << endl;
95  }
96 
97  // Calculate the temperature
98  return sqrtT * sqrtT;
99 }
100 
102  const NekDouble &e)
103 {
104  NekDouble T = GetTemperature(rho, e);
105 
106  NekDouble p = m_gasConstant * T / (1.0 / rho - m_b) -
107  m_a * Alpha(T) / (1.0 / (rho * rho) + m_b / rho);
108 
109  return p;
110 }
111 
113  const NekDouble &e)
114 {
115  NekDouble T = GetTemperature(rho, e);
116  NekDouble logTerm = LogTerm(rho);
117  // Entropy for an ideal gas
118  NekDouble sIg =
119  m_gasConstant / (m_gamma - 1) * log(T) - m_gasConstant * log(rho);
120 
121  NekDouble deltaS = m_gasConstant * log(1 - m_b * rho);
122  deltaS -= m_a * Alpha(T) * logTerm / (2 * m_b * T);
123 
124  return sIg + deltaS;
125 }
126 
128  const NekDouble &e)
129 {
130  NekDouble T = GetTemperature(rho, e);
131  NekDouble alpha = Alpha(T);
132  NekDouble dPde = GetDPDe_rho(rho, e);
133 
134  // Calculate dPdrho_T
135  NekDouble dPdrho_T =
136  m_gasConstant * T / ((1.0 - m_b * rho) * (1.0 - m_b * rho)) -
137  m_a * alpha * rho * (m_b * rho + 2) /
138  ((1 + m_b * rho) * (1 + m_b * rho));
139 
140  // Calculate dedrho_T
141  NekDouble dedrho_T = -3 * m_a * alpha / (2 * (1 + m_b * rho));
142 
143  // The result is dPdrho_e = dPdrho_T - dPde_rho * dedrho_T
144  return dPdrho_T - dPde * dedrho_T;
145 }
146 
148  const NekDouble &e)
149 {
150  NekDouble T = GetTemperature(rho, e);
151  NekDouble alpha = Alpha(T);
152  NekDouble logTerm = LogTerm(rho);
153 
154  // First calculate the denominator 1/rho^2 + 2*b/rho - b^2
155  // and sqrt(Alpha) = 1+f_w*(1-sqrt(Tr))
156  NekDouble denom = 1.0 / (rho * rho) + m_b / rho;
157 
158  // Compute cv = dedT_rho
159  NekDouble cv = m_gasConstant / (m_gamma - 1) +
160  3 * m_a * alpha * logTerm / (4 * m_b * T);
161 
162  // Now we obtain dPdT_rho
163  NekDouble dPdT =
164  m_gasConstant / (1.0 / rho - m_b) + m_a * alpha / (denom * 2 * T);
165 
166  // The result is dPde_rho = dPdT_rho / cv
167  return dPdT / cv;
168 }
169 
171  const NekDouble &p)
172 {
173  NekDouble logTerm = LogTerm(rho);
174  // First calculate the temperature, which can be expressed as
175  // (T^1/2)^3 + A* T^1/2 + B = 0
176  NekDouble A, B;
177 
178  A = -p * (1.0 / rho - m_b) / m_gasConstant;
179  B = -m_a * sqrt(m_Tc) * (1.0 / rho - m_b) /
180  (1.0 / (rho * rho) + m_b / rho) / m_gasConstant;
181 
182  // Use ideal gas solution as starting guess for iteration
183  NekDouble sqrtT = sqrt(p / (rho * (m_gamma - 1)));
184  // Newton-Raphson iteration to find T^(1/2)
185  NekDouble tol = 1e-6;
186  NekDouble maxIter = 100;
187  NekDouble residual = 1;
188  NekDouble f, df;
189  unsigned int cnt = 0;
190  while (abs(residual) > tol && cnt < maxIter)
191  {
192  f = sqrtT * sqrtT * sqrtT + A * sqrtT + B;
193  df = 3 * sqrtT * sqrtT + A;
194  residual = f / df;
195  sqrtT -= residual;
196  ++cnt;
197  }
198  if (cnt == maxIter)
199  {
200  cout << "Newton-Raphson in RedlichKwongEoS::v_GetEFromRhoP did not "
201  "converge in "
202  << maxIter << " iterations (residual = " << residual << ")"
203  << endl;
204  }
205 
206  // Calculate T
207  NekDouble T = sqrtT * sqrtT;
208 
209  // Calculate internal energy
210  return m_gasConstant * T / (m_gamma - 1) -
211  3 * m_a * Alpha(T) / (2 * m_b) * logTerm;
212 }
213 
215  const NekDouble &T)
216 {
217  // First solve for the compressibility factor Z using the cubic equation
218  // Z^3 + k1 * Z^2 + k2 * Z + k3 = 0
219  // for RedlichKwong:
220  // k1 = -1.0, k2 = A - B - B^2, k3 = -AB
221  // where A = a*alpha(T)*P/(RT)^2, B = bP/(RT)
222  NekDouble A = m_a * Alpha(T) * p / (m_gasConstant * m_gasConstant * T * T);
223  NekDouble B = m_b * p / (m_gasConstant * T);
224 
225  NekDouble k1 = -1.0;
226  NekDouble k2 = A - B - B * B;
227  NekDouble k3 = -A * B;
228 
229  // Use ideal gas (Z=1) as starting guess for iteration
230  NekDouble Z = 1.0;
231  // Newton-Raphson iteration to find Z
232  NekDouble tol = 1e-6;
233  NekDouble maxIter = 100;
234  NekDouble residual = 1;
235  NekDouble f, df;
236  unsigned int cnt = 0;
237  while (abs(residual) > tol && cnt < maxIter)
238  {
239  f = Z * Z * Z + k1 * Z * Z + k2 * Z + k3;
240  df = 3 * Z * Z + 2 * k1 * Z + k2;
241  residual = f / df;
242  Z -= residual;
243  ++cnt;
244  }
245  if (cnt == maxIter)
246  {
247  cout << "Newton-Raphson in RedlichKwongEoS::v_GetRhoFromPT did not "
248  "converge in "
249  << maxIter << " iterations (residual = " << residual << ")"
250  << endl;
251  }
252 
253  // Now calculate rho = p/(ZRT)
254  return p / (Z * m_gasConstant * T);
255 }
256 
258 {
259  return 1.0 / sqrt(T / m_Tc);
260 }
261 
263 {
264  return log(1 + m_b * rho);
265 }
266 }
virtual NekDouble v_GetTemperature(const NekDouble &rho, const NekDouble &e)
virtual NekDouble v_GetDPDrho_e(const NekDouble &rho, const NekDouble &e)
virtual NekDouble v_GetEFromRhoP(const NekDouble &rho, const NekDouble &p)
NekDouble GetDPDe_rho(const NekDouble &rho, const NekDouble &e)
Calculate the partial derivative of P(rho,e) with respect to e.
Encapsulates equations of state allowing us to obtain thermodynamic properties: most relations are in...
STL namespace.
NekDouble Alpha(const NekDouble &T)
EquationOfStateFactory & GetEquationOfStateFactory()
Declaration of the equation of state factory singleton.
virtual NekDouble v_GetRhoFromPT(const NekDouble &rho, const NekDouble &p)
double NekDouble
NekDouble GetTemperature(const NekDouble &rho, const NekDouble &e)
Calculate the temperature.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
virtual NekDouble v_GetDPDe_rho(const NekDouble &rho, const NekDouble &e)
NekDouble LogTerm(const NekDouble &rho)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
virtual NekDouble v_GetEntropy(const NekDouble &rho, const NekDouble &e)
virtual NekDouble v_GetPressure(const NekDouble &rho, const NekDouble &e)