GRINS-0.8.0
reacting_low_mach_navier_stokes_stab_base.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // GRINS - General Reacting Incompressible Navier-Stokes
5 //
6 // Copyright (C) 2014-2017 Paul T. Bauman, Roy H. Stogner
7 // Copyright (C) 2010-2013 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 
26 // This class
28 
29 // GRINS
30 #include "grins/assembly_context.h"
32 
33 namespace GRINS
34 {
35 
36  template<typename Mixture, typename Evaluator>
38  ( const std::string& physics_name,const GetPot& input,libMesh::UniquePtr<Mixture> & gas_mix )
39  : ReactingLowMachNavierStokesBase<Mixture>(physics_name,input,gas_mix),
40  _stab_helper( physics_name+"StabHelper", input )
41  {}
42 
43  template<typename Mixture, typename Evaluator>
45  {
46  // First call base class
48 
49  // We need pressure derivatives
50  context.get_element_fe(this->_press_var.p())->get_dphi();
51 
52  // We also need second derivatives, so initialize those.
53  context.get_element_fe(this->_flow_vars.u())->get_d2phi();
54  context.get_element_fe(this->_temp_vars.T())->get_d2phi();
55  }
56 
57  template<typename Mixture, typename Evaluator>
59  unsigned int qp,
60  libMesh::Real& RP_s,
61  libMesh::RealGradient& RM_s,
62  libMesh::Real& RE_s,
63  std::vector<libMesh::Real>& Rs_s )
64  {
65  Rs_s.resize(this->n_species(),0.0);
66 
67  // Grab r-coordinate for axisymmetric terms
68  // We're assuming all variables are using the same quadrature rule
69  libMesh::Real r = (context.get_element_fe(this->_flow_vars.u())->get_xyz())[qp](0);
70 
71  libMesh::RealGradient grad_p = context.interior_gradient(this->_press_var.p(), qp);
72 
73  libMesh::RealGradient grad_u = context.interior_gradient(this->_flow_vars.u(), qp);
74 
75  libMesh::RealGradient U( context.interior_value(this->_flow_vars.u(), qp) );
76  libMesh::Real divU = grad_u(0);
77 
78  if( this->_is_axisymmetric )
79  divU += U(0)/r;
80 
81  if(this->_flow_vars.dim() > 1)
82  {
83  U(1) = context.interior_value(this->_flow_vars.v(), qp);
84  divU += (context.interior_gradient(this->_flow_vars.v(), qp))(1);
85  }
86  if(this->_flow_vars.dim() == 3)
87  {
88  U(2) = context.interior_value(this->_flow_vars.w(), qp);
89  divU += (context.interior_gradient(this->_flow_vars.w(), qp))(2);
90  }
91 
92  // We don't add axisymmetric terms here since we don't directly use hess_{u,v}
93  // axisymmetric terms are built into divGradU, etc. functions below
94  libMesh::RealTensor hess_u = context.interior_hessian(this->_flow_vars.u(), qp);
95  libMesh::RealTensor hess_v = context.interior_hessian(this->_flow_vars.v(), qp);
96 
97  libMesh::Real T = context.interior_value(this->_temp_vars.T(), qp);
98 
99  libMesh::Gradient grad_T = context.interior_gradient(this->_temp_vars.T(), qp);
100  libMesh::Tensor hess_T = context.interior_hessian(this->_temp_vars.T(), qp);
101 
102  libMesh::Real hess_T_term = hess_T(0,0) + hess_T(1,1);
103 #if LIBMESH_DIM > 2
104  hess_T_term += hess_T(2,2);
105 #endif
106  // Add axisymmetric terms, if needed
107  if( this->_is_axisymmetric )
108  hess_T_term += grad_T(0)/r;
109 
110  std::vector<libMesh::Real> ws(this->n_species());
111  std::vector<libMesh::RealGradient> grad_ws(this->n_species());
112  std::vector<libMesh::RealTensor> hess_ws(this->n_species());
113  for(unsigned int s=0; s < this->_n_species; s++ )
114  {
115  ws[s] = context.interior_value(this->_species_vars.species(s), qp);
116  grad_ws[s] = context.interior_gradient(this->_species_vars.species(s), qp);
117  hess_ws[s] = context.interior_hessian(this->_species_vars.species(s), qp);
118  }
119 
120  Evaluator gas_evaluator( *(this->_gas_mixture) );
121  const libMesh::Real R_mix = gas_evaluator.R_mix(ws);
122  const libMesh::Real p0 = this->get_p0_steady(context,qp);
123  libMesh::Real rho = this->rho(T, p0, R_mix );
124  libMesh::Real cp = gas_evaluator.cp(T,p0,ws);
125  libMesh::Real M = gas_evaluator.M_mix( ws );
126 
127  std::vector<libMesh::Real> D( this->n_species() );
128  libMesh::Real mu, k;
129 
130  gas_evaluator.mu_and_k_and_D( T, rho, cp, ws, mu, k, D );
131 
132 
133  // grad_rho = drho_dT*gradT + \sum_s drho_dws*grad_ws
134  const libMesh::Real drho_dT = -p0/(R_mix*T*T);
135  libMesh::RealGradient grad_rho = drho_dT*grad_T;
136  for(unsigned int s=0; s < this->_n_species; s++ )
137  {
138  libMesh::Real Ms = gas_evaluator.M(s);
139  libMesh::Real R_uni = Constants::R_universal/1000.0; /* J/kmol-K --> J/mol-K */
140 
141  // drho_dws = -p0/(T*R_mix*R_mix)*dR_dws
142  // dR_dws = R_uni*d_dws(1/M)
143  // d_dws(1/M) = d_dws(\sum_s w_s/Ms) = 1/Ms
144  const libMesh::Real drho_dws = -p0/(R_mix*R_mix*T)*R_uni/Ms;
145  grad_rho += drho_dws*grad_ws[s];
146  }
147 
148  libMesh::RealGradient rhoUdotGradU;
149  libMesh::RealGradient divGradU;
150  libMesh::RealGradient divGradUT;
151  libMesh::RealGradient divdivU;
152 
153  if( this->_flow_vars.dim() == 1 )
154  {
155  rhoUdotGradU = rho*_stab_helper.UdotGradU( U, grad_u );
156 
157  divGradU = _stab_helper.div_GradU( hess_u );
158  divGradUT = _stab_helper.div_GradU_T( hess_u );
159  divdivU = _stab_helper.div_divU_I( hess_u );
160  }
161  else if( this->_flow_vars.dim() == 2 )
162  {
163  libMesh::RealGradient grad_v = context.interior_gradient(this->_flow_vars.v(), qp);
164 
165  rhoUdotGradU = rho*_stab_helper.UdotGradU( U, grad_u, grad_v );
166 
167  // Call axisymmetric versions if we are doing an axisymmetric run
168  if( this->_is_axisymmetric )
169  {
170  divGradU = _stab_helper.div_GradU_axi( r, U, grad_u, grad_v, hess_u, hess_v );
171  divGradUT = _stab_helper.div_GradU_T_axi( r, U, grad_u, hess_u, hess_v );
172  divdivU = _stab_helper.div_divU_I_axi( r, U, grad_u, hess_u, hess_v );
173  }
174  else
175  {
176  divGradU = _stab_helper.div_GradU( hess_u, hess_v );
177  divGradUT = _stab_helper.div_GradU_T( hess_u, hess_v );
178  divdivU = _stab_helper.div_divU_I( hess_u, hess_v );
179  }
180  }
181  else
182  {
183  libMesh::RealGradient grad_v = context.interior_gradient(this->_flow_vars.v(), qp);
184  libMesh::RealTensor hess_v = context.interior_hessian(this->_flow_vars.v(), qp);
185 
186  libMesh::RealGradient grad_w = context.interior_gradient(this->_flow_vars.w(), qp);
187  libMesh::RealTensor hess_w = context.interior_hessian(this->_flow_vars.w(), qp);
188 
189  rhoUdotGradU = rho*_stab_helper.UdotGradU( U, grad_u, grad_v, grad_w );
190 
191  divGradU = _stab_helper.div_GradU( hess_u, hess_v, hess_w );
192  divGradUT = _stab_helper.div_GradU_T( hess_u, hess_v, hess_w );
193  divdivU = _stab_helper.div_divU_I( hess_u, hess_v, hess_w );
194  }
195 
196 
197 
198  // Terms if we have vicosity derivatives w.r.t. temp.
199  /*
200  if( this->_mu.deriv(T) != 0.0 )
201  {
202  libMesh::Gradient gradTgradu( grad_T*grad_u, grad_T*grad_v );
203 
204  libMesh::Gradient gradTgraduT( grad_T(0)*grad_u(0) + grad_T(1)*grad_u(1),
205  grad_T(0)*grad_v(0) + grad_T(1)*grad_v(1) );
206 
207  libMesh::Real divU = grad_u(0) + grad_v(1);
208 
209  libMesh::Gradient gradTdivU( grad_T(0)*divU, grad_T(1)*divU );
210 
211  if(this->_flow_vars.dim() == 3)
212  {
213  libMesh::Gradient grad_w = context.interior_gradient(this->_flow_vars.w(), qp);
214 
215  gradTgradu(2) = grad_T*grad_w;
216 
217  gradTgraduT(0) += grad_T(2)*grad_u(2);
218  gradTgraduT(1) += grad_T(2)*grad_v(2);
219  gradTgraduT(2) = grad_T(0)*grad_w(0) + grad_T(1)*grad_w(1) + grad_T(2)*grad_w(2);
220 
221  divU += grad_w(2);
222  gradTdivU(0) += grad_T(0)*grad_w(2);
223  gradTdivU(1) += grad_T(1)*grad_w(2);
224  gradTdivU(2) += grad_T(2)*divU;
225  }
226 
227  divT += this->_mu.deriv(T)*( gradTgradu + gradTgraduT - 2.0/3.0*gradTdivU );
228  }
229  */
230 
231  // Axisymmetric terms already built in
232  libMesh::RealGradient div_stress = mu*(divGradU + divGradUT - 2.0/3.0*divdivU);
233 
234  std::vector<libMesh::Real> omega_dot(this->n_species());
235  gas_evaluator.omega_dot(T,rho,ws,omega_dot);
236 
237  libMesh::Real chem_term = 0.0;
238  libMesh::Gradient mass_term(0.0,0.0,0.0);
239  for(unsigned int s=0; s < this->_n_species; s++ )
240  {
241  // Start accumulating chemistry term for energy residual
242  libMesh::Real h_s=gas_evaluator.h_s(T,s);
243  chem_term += h_s*omega_dot[s];
244 
245  /* Accumulate mass term for continuity residual
246  mass_term = grad_M/M */
247  mass_term += grad_ws[s]/this->_gas_mixture->M(s);
248 
249  libMesh::Real hess_s_term = hess_ws[s](0,0) + hess_ws[s](1,1);
250 #if LIBMESH_DIM > 2
251  hess_s_term += hess_ws[s](2,2);
252 #endif
253  // Add axisymmetric terms, if needed
254  if( this->_is_axisymmetric )
255  hess_s_term += grad_ws[s](0)/r;
256 
257  // Species residual
260  Rs_s[s] = rho*U*grad_ws[s] - rho*D[s]*hess_s_term - grad_rho*D[s]*grad_ws[s]
261  - omega_dot[s];
262  }
263  mass_term *= M;
264 
265  // Continuity residual
266  RP_s = divU - (U*grad_T)/T - U*mass_term;
267 
268  // Momentum residual
269  RM_s = rhoUdotGradU + grad_p - div_stress - rho*(this->_g);
270 
271  // Energy residual
272  // - this->_k.deriv(T)*(grad_T*grad_T)
273  RE_s = rho*U*cp*grad_T - k*(hess_T_term) + chem_term;
274 
275  return;
276  }
277 
278  template<typename Mixture, typename Evaluator>
280  unsigned int qp,
281  libMesh::Real& RP_t,
282  libMesh::RealGradient& RM_t,
283  libMesh::Real& RE_t,
284  std::vector<libMesh::Real>& Rs_t )
285  {
286  libMesh::Real T = context.interior_value( this->_temp_vars.T(), qp );
287 
288  std::vector<libMesh::Real> ws(this->n_species());
289  for(unsigned int s=0; s < this->_n_species; s++ )
290  {
291  ws[s] = context.interior_value(this->_species_vars.species(s), qp);
292  }
293 
294  Evaluator gas_evaluator( *(this->_gas_mixture) );
295  const libMesh::Real R_mix = gas_evaluator.R_mix(ws);
296  const libMesh::Real p0 = this->get_p0_transient(context,qp);
297  const libMesh::Real rho = this->rho(T, p0, R_mix);
298  const libMesh::Real cp = gas_evaluator.cp(T,p0,ws);
299  const libMesh::Real M = gas_evaluator.M_mix( ws );
300 
301  // M_dot = -M^2 \sum_s w_dot[s]/Ms
302  libMesh::Real M_dot = 0.0;
303  std::vector<libMesh::Real> ws_dot(this->n_species());
304  for(unsigned int s=0; s < this->n_species(); s++)
305  {
306  context.interior_rate(this->_species_vars.species(s), qp, ws_dot[s]);
307 
308  // Start accumulating M_dot
309  M_dot += ws_dot[s]/this->_gas_mixture->M(s);
310  }
311  libMesh::Real M_dot_over_M = M_dot*(-M);
312 
313  libMesh::RealGradient u_dot;
314  context.interior_rate(this->_flow_vars.u(), qp, u_dot(0));
315  if(this->_flow_vars.dim() > 1)
316  context.interior_rate(this->_flow_vars.v(), qp, u_dot(1));
317  if(this->_flow_vars.dim() == 3)
318  context.interior_rate(this->_flow_vars.w(), qp, u_dot(2));
319 
320  libMesh::Real T_dot;
321  context.interior_rate(this->_temp_vars.T(), qp, T_dot);
322 
323  RP_t = -T_dot/T + M_dot_over_M;
324  RM_t = rho*u_dot;
325  RE_t = rho*cp*T_dot;
326  for(unsigned int s=0; s < this->n_species(); s++)
327  {
328  Rs_t[s] = rho*ws_dot[s];
329  }
330 
331  return;
332  }
333 
334 } // namespace GRINS
const libMesh::Real R_universal
Universal Gas Constant, R, [J/(kmol-K)].
GRINS namespace.
virtual void init_context(AssemblyContext &context)
Initialize context for added physics variables.
void compute_res_steady(AssemblyContext &context, unsigned int qp, libMesh::Real &RP_s, libMesh::RealGradient &RM_s, libMesh::Real &RE_s, std::vector< libMesh::Real > &Rs_s)
void compute_res_transient(AssemblyContext &context, unsigned int qp, libMesh::Real &RP_t, libMesh::RealGradient &RM_t, libMesh::Real &RE_t, std::vector< libMesh::Real > &Rs_t)
virtual void init_context(AssemblyContext &context)
Initialize context for added physics variables.

Generated on Tue Dec 19 2017 12:47:28 for GRINS-0.8.0 by  doxygen 1.8.9.1