[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
navier_stokes.cpp
1 #include <cmath>
2 #include <vector>
3 #include <complex> // for the jacobian
4 #include <boost/preprocessor/seq/for_each.hpp>
5 #include <deal.II/lac/identity_matrix.h>
6 
7 #include "ADTypes.hpp"
8 
9 #include "physics.h"
10 #include "euler.h"
11 #include "navier_stokes.h"
12 
13 namespace PHiLiP {
14 namespace Physics {
15 
16 template <int dim, int nspecies, int nstate, typename real>
18  const Parameters::AllParameters *const parameters_input,
19  const double ref_length,
20  const double gamma_gas,
21  const double mach_inf,
22  const double angle_of_attack,
23  const double side_slip_angle,
24  const double prandtl_number,
25  const double reynolds_number_inf,
26  const bool use_constant_viscosity,
27  const double constant_viscosity,
28  const double temperature_inf,
29  const double isothermal_wall_temperature,
30  const thermal_boundary_condition_enum thermal_boundary_condition_type,
31  std::shared_ptr< ManufacturedSolutionFunction<dim,nspecies,real> > manufactured_solution_function,
32  const two_point_num_flux_enum two_point_num_flux_type,
33  const bool has_nonzero_physical_source)
34  : Euler<dim,nspecies,nstate,real>(parameters_input,
35  ref_length,
36  gamma_gas,
37  mach_inf,
38  angle_of_attack,
39  side_slip_angle,
40  manufactured_solution_function,
41  two_point_num_flux_type,
42  true, //has_nonzero_diffusion = true
43  has_nonzero_physical_source) //has_nonzero_physical_source = false
44  , viscosity_coefficient_inf(1.0) // Nondimensional - Free stream values
45  , use_constant_viscosity(use_constant_viscosity)
46  , constant_viscosity(constant_viscosity) // Nondimensional - Free stream values
47  , prandtl_number(prandtl_number)
48  , reynolds_number_inf(reynolds_number_inf)
49  , isothermal_wall_temperature(isothermal_wall_temperature) // Nondimensional - Free stream values
50  , thermal_boundary_condition_type(thermal_boundary_condition_type)
51  , sutherlands_temperature(110.4) // Sutherland's temperature. Units: [K]
52  , freestream_temperature(temperature_inf) // Freestream temperature. Units: [K]
53  , temperature_ratio(sutherlands_temperature/freestream_temperature)
54 {
55  static_assert(nstate==dim+2, "Physics::NavierStokes() should be created with nstate=dim+2");
56  // Nothing to do here so far
57 }
58 
59 template <int dim, int nspecies, int nstate, typename real>
60 template<typename real2>
61 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
63  const std::array<real2,nstate> &primitive_soln,
64  const std::array<dealii::Tensor<1,dim,real2>,nstate> &primitive_soln_gradient) const
65 {
66  const real2 density = primitive_soln[0];
67  const real2 temperature = this->template compute_temperature<real2>(primitive_soln); // from Euler
68 
69  dealii::Tensor<1,dim,real2> temperature_gradient;
70  for (int d=0; d<dim; d++) {
71  temperature_gradient[d] = (this->gam*this->mach_inf_sqr*primitive_soln_gradient[nstate-1][d] - temperature*primitive_soln_gradient[0][d])/density;
72  }
73  return temperature_gradient;
74 }
75 
76 template <int dim, int nspecies, int nstate, typename real>
77 template<typename real2>
78 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
80  const std::array<real2,nstate> &conservative_soln,
81  const dealii::Tensor<1,dim,real2> &normal_vector) const
82 {
83  // extract velocities
84  const dealii::Tensor<1,dim,real2> velocities = this->template compute_velocities<real2>(conservative_soln);// from Euler
85  // compute normal velocity
86  real2 normal_velocity = 0.0;
87  for(int d=0;d<dim;++d){
88  normal_velocity += velocities[d]*normal_vector[d];
89  }
90  // compute wall parallel velocities
91  dealii::Tensor<1,dim,real2> velocities_parallel_to_wall;
92  for(int d=0;d<dim;++d){
93  velocities_parallel_to_wall[d] = velocities[d] - normal_velocity*normal_vector[d];
94  }
95  return velocities_parallel_to_wall;
96 }
97 
98 template <int dim, int nspecies, int nstate, typename real>
99 template<typename real2>
100 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
102  const std::array<real2,nstate> &conservative_soln,
103  const dealii::Tensor<1,dim,real2> &normal_vector) const
104 {
105  // compute wall parallel velocities
106  const dealii::Tensor<1,dim,real2> velocities_parallel_to_wall = compute_velocities_parallel_to_wall(conservative_soln,normal_vector);
107  // compute tangent vector
108  const dealii::Tensor<1,dim,real2> tangent_vector = compute_wall_tangent_vector_from_velocities_parallel_to_wall(velocities_parallel_to_wall);
109  return tangent_vector;
110 }
111 
112 template <int dim, int nspecies, int nstate, typename real>
113 template<typename real2>
114 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
116  const dealii::Tensor<1,dim,real2> &velocities_parallel_to_wall) const
117 {
118  // get magnitude
119  real2 magnitude = 0.0;
120  for(int d=0;d<dim;++d){
121  magnitude += velocities_parallel_to_wall[d]*velocities_parallel_to_wall[d];
122  }
123  magnitude = pow(magnitude,0.5);
124  // compute tangent vector
125  dealii::Tensor<1,dim,real2> tangent_vector;
126  for(int d=0;d<dim;++d){
127  tangent_vector[d] = velocities_parallel_to_wall[d]/magnitude;
128  }
129  return tangent_vector;
130 }
131 
132 template <int dim, int nspecies, int nstate, typename real>
133 template<typename real2>
136  const std::array<real2,nstate> &conservative_soln,
137  const std::array<dealii::Tensor<1,dim,real2>,nstate> &conservative_soln_gradient,
138  const dealii::Tensor<1,dim,real2> &normal_vector) const
139 {
140  // Computes the non-dimensional wall shear stress
141  // - get primitive solution, gradient, and velocities gradient
142  const std::array<real2,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real2>(conservative_soln); // from Euler
143  const std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient
144  = this->template convert_conservative_gradient_to_primitive_gradient_templated<real2>(conservative_soln,conservative_soln_gradient);
145 
146  /* NOTE: The following commented code has been left here as it includes different
147  expressions for computing this quantity which may be helpful to someone
148  in future work
149  */
150  // const dealii::Tensor<2,dim,real2> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real2>(primitive_soln_gradient);
151  /*
152  // - compute normal velocity gradient
153  dealii::Tensor<1,dim,real2> velocity_normal_to_wall_gradient;
154  for(int dspace=0;dspace<dim;++dspace){
155  velocity_normal_to_wall_gradient[dspace] = 0.0;
156  for(int dvel=0;dvel<dim;++dvel){
157  velocity_normal_to_wall_gradient[dspace] += velocities_gradient[dvel][dspace]*normal_vector[dvel];
158  }
159  }
160  // - compute wall parallel velocities gradient
161  dealii::Tensor<2,dim,real2> velocities_parallel_to_wall_gradient;
162  for(int dspace=0;dspace<dim;++dspace){
163  for(int dvel=0;dvel<dim;++dvel){
164  velocities_parallel_to_wall_gradient[dvel][dspace] = velocities_gradient[dvel][dspace] - velocity_normal_to_wall_gradient[dspace]*normal_vector[dvel];
165  }
166  }
167  // - compute wall parallel velocity gradient
168  dealii::Tensor<1,dim,real2> velocity_parallel_to_wall_gradient;
169  for(int dspace=0;dspace<dim;++dspace){
170  real2 magnitude = 0.0;
171  for(int dvel=0;dvel<dim;++dvel){
172  magnitude += velocities_parallel_to_wall_gradient[dvel][dspace]*velocities_parallel_to_wall_gradient[dvel][dspace];
173  }
174  velocity_parallel_to_wall_gradient[dspace] = pow(magnitude,0.5);
175  }
176  */
177  /*
178  // - compute wall parallel velocity gradient in the direction normal to the wall
179  real2 velocity_gradient_of_parallel_velocity_in_the_direction_normal_to_wall = 0.0;
180  for(int d=0;d<dim;++d){
181  velocity_gradient_of_parallel_velocity_in_the_direction_normal_to_wall += velocities_gradient[0][d]*normal_vector[d]; // for channel flow (simplest case, x-velocity is the wall parallel velocity)
182  // velocity_gradient_of_parallel_velocity_in_the_direction_normal_to_wall += velocity_parallel_to_wall_gradient[d]*normal_vector[d];
183  }
184  // Reference: https://www.cfd-online.com/Wiki/Wall_shear_stress
185  const real2 scaled_viscosity_coefficient = compute_scaled_viscosity_coefficient<real2>(primitive_soln);
186  const real2 wall_shear_stress = scaled_viscosity_coefficient*velocity_gradient_of_parallel_velocity_in_the_direction_normal_to_wall;
187  */
188  // For 3D flow over curved walls, reference: https://www.cfd-online.com/Forums/main/11103-calculate-y-u-how-get-wall-shear-stress.html#post41614
189  // const dealii::Tensor<1,dim,real2> tangent_vector = compute_wall_tangent_vector<real2>(conservative_soln,normal_vector);
190  const dealii::Tensor<2,dim,real2> viscous_stress_tensor = compute_viscous_stress_tensor<real2>(primitive_soln,primitive_soln_gradient);
191  // real2 wall_shear_stress = 0.0;
192  // for(int i=0;i<dim;++i){
193  // real2 val = 0.0;
194  // for(int j=0;j<dim;++j){
195  // val += viscous_stress_tensor[i][j]*tangent_vector[j];
196  // }
197  // wall_shear_stress += val*val;
198  // }
199  // wall_shear_stress = pow(wall_shear_stress,0.5);
200 
201  /*// build tangential operator (can be used to get the surface tangential component of some vector)
202  dealii::Tensor<2,dim,real2> tangential_operator;
203  for(int i=0;i<dim;++i){
204  for(int j=0;j<dim;++j){
205  tangential_operator[i][j] = 0.0; // initialize
206  if(j==i) tangential_operator[i][j] = 1.0;
207  tangential_operator[i][j] -= normal_vector[j]*normal_vector[i];
208  }
209  }*/
210  // viscous stress tensor times normal vector (contains all components on the surface associated with the normal vector)
211  dealii::Tensor<1,dim,real2> viscous_stress_tensor_times_normal_vector;
212  for(int i=0;i<dim;++i){
213  viscous_stress_tensor_times_normal_vector[i] = 0.0;
214  for(int j=0;j<dim;++j){
215  viscous_stress_tensor_times_normal_vector[i] += viscous_stress_tensor[i][j]*normal_vector[j];
216  }
217  }
218  /*// components tangent to the surface
219  dealii::Tensor<1,dim,real2> viscous_stress_tensor_times_tangent_vector;
220  for(int i=0;i<dim;++i){
221  viscous_stress_tensor_times_tangent_vector[i] = 0.0;
222  for(int j=0;j<dim;++j){
223  viscous_stress_tensor_times_tangent_vector[i] += tangential_operator[i][j]*viscous_stress_tensor_times_normal_vector[j];
224  }
225  }*/
226  // compute magnitude
227  real2 wall_shear_stress = 0.0;
228  for(int i=0;i<dim;++i){
229  // wall_shear_stress += viscous_stress_tensor_times_tangent_vector[i]*viscous_stress_tensor_times_tangent_vector[i];
230  wall_shear_stress += viscous_stress_tensor_times_normal_vector[i]*viscous_stress_tensor_times_normal_vector[i];
231  }
232  wall_shear_stress = pow(wall_shear_stress,0.5);
233 
234 
235  return wall_shear_stress;
236 }
237 
238 template <int dim, int nspecies, int nstate, typename real>
239 template<typename real2>
241 ::compute_viscosity_coefficient (const std::array<real2,nstate> &primitive_soln) const
242 {
243  // Use either Sutherland's law or constant viscosity
244  real2 viscosity_coefficient;
245  if(use_constant_viscosity){
246  viscosity_coefficient = 1.0*constant_viscosity;
247  } else {
248  viscosity_coefficient = compute_viscosity_coefficient_sutherlands_law<real2>(primitive_soln);
249  }
250 
251  return viscosity_coefficient;
252 }
253 
254 template <int dim, int nspecies, int nstate, typename real>
255 template<typename real2>
258 {
259  // Use either Sutherland's law or constant viscosity
260  real2 viscosity_coefficient;
261  if(use_constant_viscosity){
262  viscosity_coefficient = 1.0*constant_viscosity;
263  } else {
264  viscosity_coefficient = compute_viscosity_coefficient_sutherlands_law_from_temperature<real2>(temperature);
265  }
266 
267  return viscosity_coefficient;
268 }
269 
270 template <int dim, int nspecies, int nstate, typename real>
271 template<typename real2>
273 ::compute_viscosity_coefficient_sutherlands_law (const std::array<real2,nstate> &primitive_soln) const
274 {
275  /* Nondimensionalized viscosity coefficient, \mu^{*}
276  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.16)
277  *
278  * Based on Sutherland's law for viscosity
279  * * Reference: Sutherland, W. (1893), "The viscosity of gases and molecular force", Philosophical Magazine, S. 5, 36, pp. 507-531 (1893)
280  * * Values: https://www.cfd-online.com/Wiki/Sutherland%27s_law
281  */
282 
283  const real2 temperature = this->template compute_temperature<real2>(primitive_soln); // from Euler
284 
285  const real2 viscosity_coefficient = compute_viscosity_coefficient_sutherlands_law_from_temperature<real2>(temperature);
286 
287  return viscosity_coefficient;
288 }
289 
290 template <int dim, int nspecies, int nstate, typename real>
291 template<typename real2>
294 {
295  /* Nondimensionalized viscosity coefficient, \mu^{*}
296  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.16)
297  *
298  * Based on Sutherland's law for viscosity
299  * * Reference: Sutherland, W. (1893), "The viscosity of gases and molecular force", Philosophical Magazine, S. 5, 36, pp. 507-531 (1893)
300  * * Values: https://www.cfd-online.com/Wiki/Sutherland%27s_law
301  */
302  const real2 viscosity_coefficient = ((1.0 + temperature_ratio)/(temperature + temperature_ratio))*pow(temperature,1.5);
303 
304  return viscosity_coefficient;
305 }
306 
307 template <int dim, int nspecies, int nstate, typename real>
308 template<typename real2>
310 ::scale_viscosity_coefficient (const real2 viscosity_coefficient) const
311 {
312  /* Scaled nondimensionalized viscosity coefficient, $\hat{\mu}^{*}$
313  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.14)
314  */
315  const real2 scaled_viscosity_coefficient = viscosity_coefficient/reynolds_number_inf;
316 
317  return scaled_viscosity_coefficient;
318 }
319 
320 template <int dim, int nspecies, int nstate, typename real>
321 template<typename real2>
323 ::compute_scaled_viscosity_coefficient (const std::array<real2,nstate> &primitive_soln) const
324 {
325  /* Scaled nondimensionalized viscosity coefficient, $\hat{\mu}^{*}$
326  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.14)
327  */
328  const real2 viscosity_coefficient = compute_viscosity_coefficient<real2>(primitive_soln);
329  const real2 scaled_viscosity_coefficient = scale_viscosity_coefficient(viscosity_coefficient);
330 
331  return scaled_viscosity_coefficient;
332 }
333 
334 template <int dim, int nspecies, int nstate, typename real>
335 template<typename real2>
337 ::compute_scaled_heat_conductivity_given_scaled_viscosity_coefficient_and_prandtl_number (const real2 scaled_viscosity_coefficient, const double prandtl_number_input) const
338 {
339  /* Scaled nondimensionalized heat conductivity, $\hat{\kappa}^{*}$, given the scaled viscosity coefficient
340  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.13)
341  */
342  const real2 scaled_heat_conductivity = scaled_viscosity_coefficient/(this->gamm1*this->mach_inf_sqr*prandtl_number_input);
343 
344  return scaled_heat_conductivity;
345 }
346 
347 template <int dim, int nspecies, int nstate, typename real>
348 template<typename real2>
350 ::compute_scaled_heat_conductivity (const std::array<real2,nstate> &primitive_soln) const
351 {
352  /* Scaled nondimensionalized heat conductivity, $\hat{\kappa}^{*}$
353  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.13)
354  */
355  const real2 scaled_viscosity_coefficient = compute_scaled_viscosity_coefficient<real2>(primitive_soln);
356 
357  const real2 scaled_heat_conductivity = compute_scaled_heat_conductivity_given_scaled_viscosity_coefficient_and_prandtl_number(scaled_viscosity_coefficient,prandtl_number);
358 
359  return scaled_heat_conductivity;
360 }
361 
362 template <int dim, int nspecies, int nstate, typename real>
363 template<typename real2>
364 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
366  const std::array<real2,nstate> &primitive_soln,
367  const std::array<dealii::Tensor<1,dim,real2>,nstate> &primitive_soln_gradient) const
368 {
369  /* Nondimensionalized heat flux, $\bm{q}^{*}$
370  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.13)
371  */
372  const real2 scaled_heat_conductivity = compute_scaled_heat_conductivity<real2>(primitive_soln);
373  const dealii::Tensor<1,dim,real2> temperature_gradient = compute_temperature_gradient<real2>(primitive_soln, primitive_soln_gradient);
374  // Compute the heat flux
375  const dealii::Tensor<1,dim,real2> heat_flux = compute_heat_flux_given_scaled_heat_conductivity_and_temperature_gradient<real2>(scaled_heat_conductivity,temperature_gradient);
376  return heat_flux;
377 }
378 
379 template <int dim, int nspecies, int nstate, typename real>
380 template<typename real2>
381 dealii::Tensor<1,dim,real2> NavierStokes<dim,nspecies,nstate,real>
383  const real2 scaled_heat_conductivity,
384  const dealii::Tensor<1,dim,real2> &temperature_gradient) const
385 {
386  /* Nondimensionalized heat flux, $\bm{q}^{*}$
387  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.13)
388  */
389  dealii::Tensor<1,dim,real2> heat_flux;
390  for (int d=0; d<dim; d++) {
391  heat_flux[d] = -scaled_heat_conductivity*temperature_gradient[d];
392  }
393  return heat_flux;
394 }
395 
396 template <int dim, int nspecies, int nstate, typename real>
397 template<typename real2>
398 dealii::Tensor<1,3,real2> NavierStokes<dim,nspecies,nstate,real>
400  const std::array<real2,nstate> &conservative_soln,
401  const std::array<dealii::Tensor<1,dim,real2>,nstate> &conservative_soln_gradient) const
402 {
403  // Compute the vorticity
404  dealii::Tensor<1,3,real2> vorticity;
405  for(int d=0; d<3; ++d) {
406  vorticity[d] = 0.0;
407  }
408  if constexpr(dim>1) {
409  // Get velocity gradient
410  const std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real2>(conservative_soln, conservative_soln_gradient);
411  const dealii::Tensor<2,dim,real2> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real2>(primitive_soln_gradient);
412  if constexpr(dim==2) {
413  // vorticity exists only in z-component
414  vorticity[2] = velocities_gradient[1][0] - velocities_gradient[0][1]; // z-component
415  }
416  if constexpr(dim==3) {
417  vorticity[0] = velocities_gradient[2][1] - velocities_gradient[1][2]; // x-component
418  vorticity[1] = velocities_gradient[0][2] - velocities_gradient[2][0]; // y-component
419  vorticity[2] = velocities_gradient[1][0] - velocities_gradient[0][1]; // z-component
420  }
421  }
422  return vorticity;
423 }
424 
425 template <int dim, int nspecies, int nstate, typename real>
428  const std::array<real,nstate> &conservative_soln,
429  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
430 {
431  // Compute the vorticity
432  dealii::Tensor<1,3,real> vorticity = compute_vorticity(conservative_soln, conservative_soln_gradient);
433  // Compute vorticity magnitude squared
434  real vorticity_magnitude_sqr = 0.0;
435  for(int d=0; d<3; ++d) {
436  vorticity_magnitude_sqr += vorticity[d]*vorticity[d];
437  }
438  return vorticity_magnitude_sqr;
439 }
440 
441 template <int dim, int nspecies, int nstate, typename real>
444  const std::array<real,nstate> &conservative_soln,
445  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
446 {
447  real vorticity_magnitude_sqr = compute_vorticity_magnitude_sqr(conservative_soln, conservative_soln_gradient);
448  real vorticity_magnitude = sqrt(vorticity_magnitude_sqr);
449  return vorticity_magnitude;
450 }
451 
452 template <int dim, int nspecies, int nstate, typename real>
455  const std::array<real,nstate> &conservative_soln,
456  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
457 {
458  // Reference: Jeong J, Hussain F. On the identification of a vortex. Journal of Fluid Mechanics. 1995;285:69-94. doi:10.1017/S0022112095000462
459  // -- Equation (2)
460  // Compute the second invariant (i.e. Q-criterion)
461  real second_invariant = 0.0;
462  if constexpr(dim>1) {
463  // Get velocity gradient
464  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln, conservative_soln_gradient);
465  const dealii::Tensor<2,dim,real> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real>(primitive_soln_gradient);
466  // Get symmetric strain rate tensor, S_{i,j}
467  const dealii::Tensor<2,dim,real> strain_rate_tensor_symmetric = compute_strain_rate_tensor<real>(velocities_gradient);
468  // Compute anti-symmetric strain rate tensor, \Omega_{i,j}
469  dealii::Tensor<2,dim,real> strain_rate_tensor_antisymmetric;
470  for (int d1=0; d1<dim; d1++) {
471  for (int d2=0; d2<dim; d2++) {
472  strain_rate_tensor_antisymmetric[d1][d2] = 0.5*(velocities_gradient[d1][d2] - velocities_gradient[d2][d1]);
473  }
474  }
475  second_invariant = 0.5*(get_tensor_magnitude_sqr(strain_rate_tensor_antisymmetric) - get_tensor_magnitude_sqr(strain_rate_tensor_symmetric));
476  }
477  return second_invariant;
478 }
479 
480 template <int dim, int nspecies, int nstate, typename real>
483  const std::array<real,nstate> &conservative_soln,
484  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
485 {
486  // Compute enstrophy
487  const real density = conservative_soln[0];
488  real enstrophy = 0.5*density*compute_vorticity_magnitude_sqr(conservative_soln, conservative_soln_gradient);
489  return enstrophy;
490 }
491 
492 template <int dim, int nspecies, int nstate, typename real>
495  const std::array<real,nstate> &conservative_soln,
496  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
497 {
498  // Compute incompressible enstrophy
499  real enstrophy = 0.5*compute_vorticity_magnitude_sqr(conservative_soln, conservative_soln_gradient);
500  return enstrophy;
501 }
502 
503 template <int dim, int nspecies, int nstate, typename real>
506  const std::array<real,nstate> &/*conservative_soln*/,
507  const std::array<dealii::Tensor<1,dim,real>,3> &vorticity_gradient) const
508 {
509  // Compute vorticity gradient magnitude squared
510  real vorticity_gradient_magnitude_sqr = 0.0;
511  for(int istate=0; istate<3; ++istate) {
512  for(int d=0; d<dim; ++d) {
513  vorticity_gradient_magnitude_sqr += vorticity_gradient[istate][d]*vorticity_gradient[istate][d];
514  }
515  }
516  // Compute incompressible palinstrophy
517  const real palinstrophy = 0.5*vorticity_gradient_magnitude_sqr;
518  return palinstrophy;
519 }
520 
521 template <int dim, int nspecies, int nstate, typename real>
524  const real integrated_enstrophy) const
525 {
526  real dissipation_rate = 2.0*integrated_enstrophy/(this->reynolds_number_inf);
527  return dissipation_rate;
528 }
529 
530 template <int dim, int nspecies, int nstate, typename real>
533  const std::array<real,nstate> &conservative_soln,
534  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
535 {
536  // Get pressure
537  const real pressure = this->template compute_pressure_templated<real>(conservative_soln);
538 
539  // Compute the pressure dilatation
540  real pressure_dilatation = compute_dilatation(conservative_soln,conservative_soln_gradient);
541  pressure_dilatation *= pressure;
542 
543  return pressure_dilatation;
544 }
545 
546 template <int dim, int nspecies, int nstate, typename real>
549  const std::array<real,nstate> &conservative_soln,
550  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
551 {
552  // Get velocity gradient
553  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln, conservative_soln_gradient);
554  const dealii::Tensor<2,dim,real> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real>(primitive_soln_gradient);
555 
556  // Compute the dilatation
557  real dilatation = 0.0;
558  for(int d=0; d<dim; ++d) {
559  dilatation += velocities_gradient[d][d]; // divergence
560  }
561 
562  return dilatation;
563 }
564 
565 template <int dim, int nspecies, int nstate, typename real>
568  const std::array<real,nstate> &/*conservative_soln*/,
569  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
570 {
571  // Get density gradient
572  dealii::Tensor<1,dim,real> density_gradient;
573  for (int d=0; d<dim; d++) {
574  density_gradient[d] = conservative_soln_gradient[0][d];
575  }
576  // compute magnitude
577  real density_gradient_magnitude = 0.0;
578  for (int d=0; d<dim; d++) {
579  density_gradient_magnitude += density_gradient[d]*density_gradient[d];
580  }
581  density_gradient_magnitude = sqrt(density_gradient_magnitude);
582  return density_gradient_magnitude;
583 }
584 
585 template <int dim, int nspecies, int nstate, typename real>
586 dealii::Tensor<2,dim,real> NavierStokes<dim,nspecies,nstate,real>
588  const std::array<real,nstate> &conservative_soln,
589  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
590 {
591  return compute_strain_rate_tensor_from_conservative_templated<real>(conservative_soln,conservative_soln_gradient);
592 }
593 
594 template <int dim, int nspecies, int nstate, typename real>
595 template<typename real2>
596 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
598  const std::array<real2,nstate> &conservative_soln,
599  const std::array<dealii::Tensor<1,dim,real2>,nstate> &conservative_soln_gradient) const
600 {
601  // Get velocity gradient
602  const std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real2>(conservative_soln, conservative_soln_gradient);
603  const dealii::Tensor<2,dim,real2> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real2>(primitive_soln_gradient);
604 
605  // Strain rate tensor, S_{i,j}
606  const dealii::Tensor<2,dim,real2> strain_rate_tensor = compute_strain_rate_tensor<real2>(velocities_gradient);
607  return strain_rate_tensor;
608 }
609 
610 template <int dim, int nspecies, int nstate, typename real>
611 dealii::Tensor<2,dim,real> NavierStokes<dim,nspecies,nstate,real>
613  const std::array<real,nstate> &conservative_soln,
614  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
615 {
616  // Get velocity gradient
617  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln, conservative_soln_gradient);
618  const dealii::Tensor<2,dim,real> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real>(primitive_soln_gradient);
619 
620  // Strain rate tensor, S_{i,j}
621  const dealii::Tensor<2,dim,real> strain_rate_tensor = compute_strain_rate_tensor<real>(velocities_gradient);
622 
623  // Compute divergence of velocity
624  real vel_divergence = 0.0;
625  for(int d1=0; d1<dim; ++d1) {
626  vel_divergence += velocities_gradient[d1][d1];
627  }
628 
629  // Compute the deviatoric strain rate tensor
630  dealii::Tensor<2,dim,real> deviatoric_strain_rate_tensor;
631  for(int d1=0; d1<dim; ++d1) {
632  for(int d2=0; d2<dim; ++d2) {
633  deviatoric_strain_rate_tensor[d1][d2] = strain_rate_tensor[d1][d2];
634  }
635  deviatoric_strain_rate_tensor[d1][d1] -= (1.0/3.0)*vel_divergence;
636  }
637  return deviatoric_strain_rate_tensor;
638 }
639 
640 template <int dim, int nspecies, int nstate, typename real>
643  const dealii::Tensor<2,dim,real> &tensor) const
644 {
645  real tensor_magnitude_sqr = 0.0;
646  for (int i=0; i<dim; ++i) {
647  for (int j=0; j<dim; ++j) {
648  tensor_magnitude_sqr += tensor[i][j]*tensor[i][j];
649  }
650  }
651  return tensor_magnitude_sqr;
652 }
653 
654 template <int dim, int nspecies, int nstate, typename real>
657  const dealii::Tensor<2,dim,real> &tensor) const
658 {
659  return sqrt(get_tensor_magnitude_sqr(tensor));
660 }
661 
662 template <int dim, int nspecies, int nstate, typename real>
665  const std::array<real,nstate> &conservative_soln,
666  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
667 {
668  // Compute the deviatoric strain rate tensor
669  const dealii::Tensor<2,dim,real> deviatoric_strain_rate_tensor = compute_deviatoric_strain_rate_tensor(conservative_soln,conservative_soln_gradient);
670  // Get magnitude squared
671  real deviatoric_strain_rate_tensor_magnitude_sqr = get_tensor_magnitude_sqr(deviatoric_strain_rate_tensor);
672 
673  // Compute viscosity coefficient
674  const std::array<real,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(conservative_soln); // from Euler
675  const real viscosity_coefficient = compute_viscosity_coefficient (primitive_soln);
676 
677  return (viscosity_coefficient*deviatoric_strain_rate_tensor_magnitude_sqr);
678 }
679 
680 template <int dim, int nspecies, int nstate, typename real>
683  const real integrated_viscosity_times_deviatoric_strain_rate_tensor_magnitude_sqr) const
684 {
685  real dissipation_rate = 2.0*integrated_viscosity_times_deviatoric_strain_rate_tensor_magnitude_sqr/(this->reynolds_number_inf);
686  return dissipation_rate;
687 }
688 
689 template <int dim, int nspecies, int nstate, typename real>
690 template<typename real2>
691 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
693  const std::array<dealii::Tensor<1,dim,real2>,nstate> &primitive_soln_gradient) const
694 {
695  dealii::Tensor<2,dim,real2> velocities_gradient;
696  for (int d1=0; d1<dim; d1++) {
697  for (int d2=0; d2<dim; d2++) {
698  velocities_gradient[d1][d2] = primitive_soln_gradient[1+d1][d2];
699  }
700  }
701  return velocities_gradient;
702 }
703 
704 template <int dim, int nspecies, int nstate, typename real>
705 template<typename real2>
706 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
708  const dealii::Tensor<2,dim,real2> &vel_gradient) const
709 {
710  // Strain rate tensor, S_{i,j}
711  dealii::Tensor<2,dim,real2> strain_rate_tensor;
712  for (int d1=0; d1<dim; d1++) {
713  for (int d2=0; d2<dim; d2++) {
714  // rate of strain (deformation) tensor:
715  strain_rate_tensor[d1][d2] = 0.5*(vel_gradient[d1][d2] + vel_gradient[d2][d1]);
716  }
717  }
718  return strain_rate_tensor;
719 }
720 
721 template <int dim, int nspecies, int nstate, typename real>
724  const std::array<real,nstate> &conservative_soln,
725  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
726 {
727  // Get velocity gradient
728  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln, conservative_soln_gradient);
729  const dealii::Tensor<2,dim,real> velocities_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real>(primitive_soln_gradient);
730 
731  // Compute the strain rate tensor
732  const dealii::Tensor<2,dim,real> strain_rate_tensor = compute_strain_rate_tensor(velocities_gradient);
733  // Get magnitude squared
734  real strain_rate_tensor_magnitude_sqr = get_tensor_magnitude_sqr(strain_rate_tensor);
735 
736  // Compute viscosity coefficient
737  const std::array<real,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(conservative_soln); // from Euler
738  const real viscosity_coefficient = compute_viscosity_coefficient (primitive_soln);
739 
740  return (viscosity_coefficient*strain_rate_tensor_magnitude_sqr);
741 }
742 
743 template <int dim, int nspecies, int nstate, typename real>
746  const real integrated_viscosity_times_strain_rate_tensor_magnitude_sqr) const
747 {
748  real dissipation_rate = 2.0*integrated_viscosity_times_strain_rate_tensor_magnitude_sqr/(this->reynolds_number_inf);
749  return dissipation_rate;
750 }
751 
752 template <int dim, int nspecies, int nstate, typename real>
753 template<typename real2>
754 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
756  const real2 scaled_viscosity_coefficient,
757  const dealii::Tensor<2,dim,real2> &strain_rate_tensor) const
758 {
759  /* Nondimensionalized viscous stress tensor, $\bm{\tau}^{*}$
760  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.12)
761  */
762 
763  // Divergence of velocity
764  // -- Initialize
765  real2 vel_divergence; // complex initializes it as 0+0i
766  if(std::is_same<real2,real>::value){
767  vel_divergence = 0.0;
768  }
769  // -- Obtain from trace of strain rate tensor
770  for (int d=0; d<dim; d++) {
771  vel_divergence += strain_rate_tensor[d][d];
772  }
773 
774  // Viscous stress tensor, \tau_{i,j}
775  dealii::Tensor<2,dim,real2> viscous_stress_tensor;
776  const real2 scaled_2nd_viscosity_coefficient = (-2.0/3.0)*scaled_viscosity_coefficient; // Stokes' hypothesis
777  for (int d1=0; d1<dim; d1++) {
778  for (int d2=0; d2<dim; d2++) {
779  viscous_stress_tensor[d1][d2] = 2.0*scaled_viscosity_coefficient*strain_rate_tensor[d1][d2];
780  }
781  viscous_stress_tensor[d1][d1] += scaled_2nd_viscosity_coefficient*vel_divergence;
782  }
783  return viscous_stress_tensor;
784 }
785 
786 template <int dim, int nspecies, int nstate, typename real>
787 dealii::Tensor<2,dim,real> NavierStokes<dim,nspecies,nstate,real>
789  const std::array<real,nstate> &conservative_soln,
790  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
791 {
792  return compute_viscous_stress_tensor_from_conservative_templated<real>(conservative_soln,conservative_soln_gradient);
793 }
794 
795 template <int dim, int nspecies, int nstate, typename real>
796 template<typename real2>
797 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
799  const std::array<real2,nstate> &conservative_soln,
800  const std::array<dealii::Tensor<1,dim,real2>,nstate> &conservative_soln_gradient) const
801 {
802  // Step 1: Primitive solution
803  const std::array<real2,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real2>(conservative_soln); // from Euler
804 
805  // Step 2: Gradient of primitive solution
806  const std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real2>(conservative_soln, conservative_soln_gradient);
807 
808  // Viscous stress tensor, \tau_{i,j}
809  const dealii::Tensor<2,dim,real2> viscous_stress_tensor = compute_viscous_stress_tensor<real2>(primitive_soln,primitive_soln_gradient);
810 
811  return viscous_stress_tensor;
812 }
813 
814 template <int dim, int nspecies, int nstate, typename real>
815 template<typename real2>
816 dealii::Tensor<2,dim,real2> NavierStokes<dim,nspecies,nstate,real>
818  const std::array<real2,nstate> &primitive_soln,
819  const std::array<dealii::Tensor<1,dim,real2>,nstate> &primitive_soln_gradient) const
820 {
821  /* Nondimensionalized viscous stress tensor, $\bm{\tau}^{*}$
822  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.12)
823  */
824  const dealii::Tensor<2,dim,real2> vel_gradient = extract_velocities_gradient_from_primitive_solution_gradient<real2>(primitive_soln_gradient);
825  const dealii::Tensor<2,dim,real2> strain_rate_tensor = compute_strain_rate_tensor<real2>(vel_gradient);
826  const real2 scaled_viscosity_coefficient = compute_scaled_viscosity_coefficient<real2>(primitive_soln);
827 
828  // Viscous stress tensor, \tau_{i,j}
829  const dealii::Tensor<2,dim,real2> viscous_stress_tensor
830  = compute_viscous_stress_tensor_via_scaled_viscosity_and_strain_rate_tensor<real2>(scaled_viscosity_coefficient,strain_rate_tensor);
831 
832  return viscous_stress_tensor;
833 }
834 
835 template <int dim, int nspecies, int nstate, typename real>
836 dealii::Tensor<2,dim,real> NavierStokes<dim,nspecies,nstate,real>
838  const std::array<real,nstate> &conservative_soln) const
839 {
840  const dealii::Tensor<1,dim,real> vel = this->template compute_velocities<real>(conservative_soln);
841  dealii::Tensor<2,dim,real> matrix_L;
842  for (int i=0; i<dim; i++) {
843  for (int j=0; j<dim; j++) {
844  matrix_L[i][j] = vel[i]*vel[j];
845  }
846  }
847  return matrix_L;
848 }
849 
850 template <int dim, int nspecies, int nstate, typename real>
851 dealii::Tensor<2,dim,real> NavierStokes<dim,nspecies,nstate,real>
853  const std::array<real,nstate> &conservative_soln,
854  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
855 {
856  dealii::Tensor<2,dim,real> matrix_M;
857 
858  // Strain rate tensor, S_{i,j}
859  const dealii::Tensor<2,dim,real> strain_rate_tensor = compute_strain_rate_tensor_from_conservative(conservative_soln, conservative_soln_gradient);
860  // -- Magnitude: same magnitude calculation as Smagorinsky model with the sqrt(2) factor, see Lilly 1991
861  const real strain_rate_tensor_magnitude = sqrt(2.0*get_tensor_magnitude_sqr(strain_rate_tensor));
862 
863  // Compute divergence of velocity
864  real strain_rate_tensor_trace = 0.0;
865  for(int i=0; i<dim; ++i) {
866  strain_rate_tensor_trace += strain_rate_tensor[i][i];
867  }
868 
869  // Compute the deviatoric strain rate tensor
870  dealii::Tensor<2,dim,real> deviatoric_strain_rate_tensor;
871  for(int i=0; i<dim; ++i) {
872  for(int j=0; j<dim; ++j) {
873  matrix_M[i][j] = strain_rate_tensor_magnitude*strain_rate_tensor[i][j];
874  }
875  matrix_M[i][i] -= strain_rate_tensor_magnitude*(1.0/3.0)*strain_rate_tensor_trace;
876  }
877  return matrix_M;
878 }
879 
880 //----------------------------------------------------------------
881 template <int dim, int nspecies, int nstate, typename real>
884  const dealii::Tensor<2,dim,real> &tensor1,
885  const dealii::Tensor<2,dim,real> &tensor2) const
886 {
887  real tensor_product_magnitude_sqr = 0.0;
888  for (int i=0; i<dim; ++i) {
889  for (int j=0; j<dim; ++j) {
890  tensor_product_magnitude_sqr += tensor1[i][j]*tensor2[i][j];
891  }
892  }
893  return tensor_product_magnitude_sqr;
894 }
895 
896 template <int dim, int nspecies, int nstate, typename real>
897 std::array<dealii::Tensor<1,dim,real>,nstate> NavierStokes<dim,nspecies,nstate,real>
899  const std::array<real,nstate> &conservative_soln,
900  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient) const
901 {
902  /* Nondimensionalized viscous flux (i.e. dissipative flux)
903  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.12.1-4.12.4)
904  */
905  std::array<dealii::Tensor<1,dim,real>,nstate> viscous_flux = dissipative_flux_templated<real>(conservative_soln, solution_gradient);
906  return viscous_flux;
907 }
908 
909 template <int dim, int nspecies, int nstate, typename real>
910 dealii::Tensor<1,dim,real> NavierStokes<dim,nspecies,nstate,real>
912  const std::array<real,nstate> &primitive_soln,
913  const dealii::Tensor<1,dim,real> &temperature_gradient) const
914 {
915  /* Gradient of the scaled nondimensionalized viscosity coefficient
916  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.14.14 and 4.14.17)
917  */
918  const real temperature = this->compute_temperature(primitive_soln); // from Euler
919  const real scaled_viscosity_coefficient = compute_scaled_viscosity_coefficient(primitive_soln);
920 
921  // Eq.(4.14.17)
922  real dmudT = 0.5*(scaled_viscosity_coefficient/(temperature + temperature_ratio))*(1.0 + 3.0*temperature_ratio/temperature);
923 
924  // Gradient (dmudX) from dmudT and dTdX
925  dealii::Tensor<1,dim,real> scaled_viscosity_coefficient_gradient;
926  for (int d=0; d<dim; d++) {
927  scaled_viscosity_coefficient_gradient[d] = dmudT*temperature_gradient[d];
928  }
929 
930  return scaled_viscosity_coefficient_gradient;
931 }
932 
933 // Returns the value from a CoDiPack or Sacado variable.
934 template<typename real>
935 double getValue(const real &x) {
936  if constexpr(std::is_same<real,double>::value) {
937  return x;
938  }
939  else if constexpr(std::is_same<real,FadType>::value) {
940  return x.val(); // sacado
941  }
942  else if constexpr(std::is_same<real,FadFadType>::value) {
943  return x.val().val(); // sacado
944  }
945  else if constexpr(std::is_same<real,RadType>::value) {
946  return x.value(); // CoDiPack
947  }
948  else if(std::is_same<real,RadFadType>::value) {
949  return x.value().value(); // CoDiPack
950  }
951 }
952 
953 template <int dim, int nspecies, int nstate, typename real>
954 dealii::Tensor<2,nstate,real> NavierStokes<dim,nspecies,nstate,real>
956  const std::array<real,nstate> &conservative_soln,
957  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient,
958  const dealii::Tensor<1,dim,real> &normal) const
959 {
960  using adtype = FadType;
961 
962  // Initialize AD objects
963  std::array<adtype,nstate> AD_conservative_soln;
964  std::array<dealii::Tensor<1,dim,adtype>,nstate> AD_solution_gradient;
965  for (int s=0; s<nstate; s++) {
966  adtype ADvar(nstate, s, getValue<real>(conservative_soln[s])); // create AD variable
967  AD_conservative_soln[s] = ADvar;
968  for (int d=0;d<dim;d++) {
969  AD_solution_gradient[s][d] = getValue<real>(solution_gradient[s][d]);
970  }
971  }
972 
973  // Compute AD dissipative flux
974  std::array<dealii::Tensor<1,dim,adtype>,nstate> AD_dissipative_flux = dissipative_flux_templated<adtype>(AD_conservative_soln, AD_solution_gradient);
975 
976  // Assemble the directional Jacobian
977  dealii::Tensor<2,nstate,real> jacobian;
978  for (int sp=0; sp<nstate; sp++) {
979  // for each perturbed state (sp) variable
980  for (int s=0; s<nstate; s++) {
981  jacobian[s][sp] = 0.0;
982  for (int d=0;d<dim;d++) {
983  // Compute directional jacobian
984  jacobian[s][sp] += AD_dissipative_flux[s][d].dx(sp)*normal[d];
985  }
986  }
987  }
988  return jacobian;
989 }
990 
991 template <int dim, int nspecies, int nstate, typename real>
992 dealii::Tensor<2,nstate,real> NavierStokes<dim,nspecies,nstate,real>
994  const std::array<real,nstate> &conservative_soln,
995  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient,
996  const dealii::Tensor<1,dim,real> &normal,
997  const int d_gradient) const
998 {
999  using adtype = FadType;
1000 
1001  // Initialize AD objects
1002  std::array<adtype,nstate> AD_conservative_soln;
1003  std::array<dealii::Tensor<1,dim,adtype>,nstate> AD_solution_gradient;
1004  for (int s=0; s<nstate; s++) {
1005  AD_conservative_soln[s] = getValue<real>(conservative_soln[s]);
1006  for (int d=0;d<dim;d++) {
1007  if(d == d_gradient){
1008  adtype ADvar(nstate, s, getValue<real>(solution_gradient[s][d])); // create AD variable
1009  AD_solution_gradient[s][d] = ADvar;
1010  }
1011  else {
1012  AD_solution_gradient[s][d] = getValue<real>(solution_gradient[s][d]);
1013  }
1014  }
1015  }
1016 
1017  // Compute AD dissipative flux
1018  std::array<dealii::Tensor<1,dim,adtype>,nstate> AD_dissipative_flux = dissipative_flux_templated<adtype>(AD_conservative_soln, AD_solution_gradient);
1019 
1020  // Assemble the directional Jacobian
1021  dealii::Tensor<2,nstate,real> jacobian;
1022  for (int sp=0; sp<nstate; sp++) {
1023  // for each perturbed state (sp) variable
1024  for (int s=0; s<nstate; s++) {
1025  jacobian[s][sp] = 0.0;
1026  for (int d=0;d<dim;d++) {
1027  // Compute directional jacobian
1028  jacobian[s][sp] += AD_dissipative_flux[s][d].dx(sp)*normal[d];
1029  }
1030  }
1031  }
1032  return jacobian;
1033 }
1034 
1035 template <int dim, int nspecies, int nstate, typename real>
1036 std::array<real,nstate> NavierStokes<dim,nspecies,nstate,real>
1038  const dealii::Point<dim,real> &pos) const
1039 {
1040  // Get Manufactured Solution values
1041  const std::array<real,nstate> manufactured_solution = this->get_manufactured_solution_value(pos); // from Euler
1042 
1043  // Get Manufactured Solution gradient
1044  const std::array<dealii::Tensor<1,dim,real>,nstate> manufactured_solution_gradient = this->get_manufactured_solution_gradient(pos); // from Euler
1045 
1046  // Get Manufactured Solution hessian
1047  std::array<dealii::SymmetricTensor<2,dim,real>,nstate> manufactured_solution_hessian;
1048  for (int s=0; s<nstate; s++) {
1049  dealii::SymmetricTensor<2,dim,real> hessian = this->manufactured_solution_function->hessian(pos,s);
1050  for (int dr=0;dr<dim;dr++) {
1051  for (int dc=0;dc<dim;dc++) {
1052  manufactured_solution_hessian[s][dr][dc] = hessian[dr][dc];
1053  }
1054  }
1055  }
1056 
1057  // First term -- wrt to the conservative variables
1058  // This is similar, should simply provide this function a flux_directional_jacobian() -- could restructure later
1059  dealii::Tensor<1,nstate,real> dissipative_flux_divergence;
1060  for (int d=0;d<dim;d++) {
1061  dealii::Tensor<1,dim,real> normal;
1062  normal[d] = 1.0;
1063  const dealii::Tensor<2,nstate,real> jacobian = dissipative_flux_directional_jacobian(manufactured_solution, manufactured_solution_gradient, normal);
1064 
1065  // get the directional jacobian wrt gradient
1066  std::array<dealii::Tensor<2,nstate,real>,dim> jacobian_wrt_gradient;
1067  for (int d_gradient=0;d_gradient<dim;d_gradient++) {
1068 
1069  // get the directional jacobian wrt gradient component (x,y,z)
1070  const dealii::Tensor<2,nstate,real> jacobian_wrt_gradient_component = dissipative_flux_directional_jacobian_wrt_gradient_component(manufactured_solution, manufactured_solution_gradient, normal, d_gradient);
1071 
1072  // store each component in jacobian_wrt_gradient -- could do this in the function used above
1073  for (int sr = 0; sr < nstate; ++sr) {
1074  for (int sc = 0; sc < nstate; ++sc) {
1075  jacobian_wrt_gradient[d_gradient][sr][sc] = jacobian_wrt_gradient_component[sr][sc];
1076  }
1077  }
1078  }
1079  for (int sr = 0; sr < nstate; ++sr) {
1080  real jac_grad_row = 0.0;
1081  for (int sc = 0; sc < nstate; ++sc) {
1082  jac_grad_row += jacobian[sr][sc]*manufactured_solution_gradient[sc][d];
1083  // Second term -- wrt to the gradient of conservative variables
1084  // -- add the contribution of each gradient component (e.g. x,y,z for dim==3)
1085  for (int d_gradient=0;d_gradient<dim;d_gradient++) {
1086  jac_grad_row += jacobian_wrt_gradient[d_gradient][sr][sc]*manufactured_solution_hessian[sc][d_gradient][d]; // symmetric so d indexing works both ways
1087  }
1088  }
1089  dissipative_flux_divergence[sr] += jac_grad_row;
1090  }
1091  }
1092  std::array<real,nstate> dissipative_source_term;
1093  for (int s=0; s<nstate; s++) {
1094  dissipative_source_term[s] = dissipative_flux_divergence[s];
1095  }
1096 
1097  return dissipative_source_term;
1098 }
1099 
1100 template <int dim, int nspecies, int nstate, typename real>
1101 std::array<real,nstate> NavierStokes<dim,nspecies,nstate,real>
1103  const dealii::Point<dim,real> &pos,
1104  const std::array<real,nstate> &/*conservative_soln*/,
1105  const real /*current_time*/) const
1106 {
1107  // will probably have to change this line: -- modify so we only need to provide a jacobian
1108  const std::array<real,nstate> conv_source_term = this->convective_source_term(pos);
1109  const std::array<real,nstate> diss_source_term = dissipative_source_term(pos);
1110  std::array<real,nstate> source_term;
1111  for (int s=0; s<nstate; s++)
1112  {
1113  source_term[s] = conv_source_term[s] + diss_source_term[s];
1114  }
1115  return source_term;
1116 }
1117 
1118 template <int dim, int nspecies, int nstate, typename real>
1119 dealii::Tensor<2,nstate,real> NavierStokes<dim,nspecies,nstate,real>
1121  std::array<real,nstate> &conservative_soln,
1122  const dealii::Tensor<1,dim,real> &normal) const
1123 {
1124  using adtype = FadType;
1125 
1126  // Initialize AD objects
1127  std::array<adtype,nstate> AD_conservative_soln;
1128  for (int s=0; s<nstate; s++) {
1129  adtype ADvar(nstate, s, getValue<real>(conservative_soln[s])); // create AD variable
1130  AD_conservative_soln[s] = ADvar;
1131  }
1132 
1133  // Compute AD convective flux
1134  // -- taken exactly from euler.cpp:
1135  std::array<dealii::Tensor<1,dim,adtype>,nstate> AD_conv_flux;
1136  const adtype density = AD_conservative_soln[0];
1137  const adtype pressure = this->template compute_pressure_templated<adtype>(AD_conservative_soln);
1138  const dealii::Tensor<1,dim,adtype> vel = this->template compute_velocities<adtype>(AD_conservative_soln);
1139  const adtype specific_total_energy = AD_conservative_soln[nstate-1]/AD_conservative_soln[0];
1140  const adtype specific_total_enthalpy = specific_total_energy + pressure/density;
1141  for (int flux_dim=0; flux_dim<dim; ++flux_dim) {
1142  // Density equation
1143  AD_conv_flux[0][flux_dim] = AD_conservative_soln[1+flux_dim];
1144  // Momentum equation
1145  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
1146  AD_conv_flux[1+velocity_dim][flux_dim] = density*vel[flux_dim]*vel[velocity_dim];
1147  }
1148  AD_conv_flux[1+flux_dim][flux_dim] += pressure; // Add diagonal of pressure
1149  // Energy equation
1150  AD_conv_flux[nstate-1][flux_dim] = density*vel[flux_dim]*specific_total_enthalpy;
1151  }
1152  // -- end of computing the AD convective flux
1153 
1154  // Assemble the directional Jacobian
1155  dealii::Tensor<2,nstate,real> jacobian;
1156  for (int sp=0; sp<nstate; sp++) {
1157  // for each perturbed state (sp) variable
1158  for (int s=0; s<nstate; s++) {
1159  jacobian[s][sp] = 0.0;
1160  for (int d=0;d<dim;d++) {
1161  // Compute directional jacobian
1162  jacobian[s][sp] += AD_conv_flux[s][d].dx(sp)*normal[d];
1163  }
1164  }
1165  }
1166  return jacobian;
1167 }
1168 
1169 template <int dim, int nspecies, int nstate, typename real>
1172  std::array<real,nstate> &conservative_soln) const
1173 {
1174  using adtype = FadType;
1175 
1176  // Step 1: Primitive solution
1177  const std::array<real,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(conservative_soln); // from Euler
1178 
1179  // Step 2: Compute temperature
1180  real temperature = this->template compute_temperature<real>(primitive_soln); // from Euler
1181 
1182  // Initialize AD objects
1183  adtype AD_temperature(1, 0, getValue<real>(temperature));
1184 
1185  // Compute the AD scaled viscosity coefficient
1186  adtype viscosity_coefficient = ((1.0 + temperature_ratio)/(AD_temperature + temperature_ratio))*pow(AD_temperature,1.5);
1187  adtype scaled_viscosity_coefficient = viscosity_coefficient/reynolds_number_inf;
1188 
1189  // Get the derivative from AD
1190  real dmudT = scaled_viscosity_coefficient.dx(0);
1191 
1192  return dmudT;
1193 }
1194 
1195 template <int dim, int nspecies, int nstate, typename real>
1196 template<typename real2>
1197 std::array<dealii::Tensor<1,dim,real2>,nstate> NavierStokes<dim,nspecies,nstate,real>
1199  const std::array<real2,nstate> &conservative_soln,
1200  const std::array<dealii::Tensor<1,dim,real2>,nstate> &solution_gradient) const
1201 {
1202  /* Nondimensionalized viscous flux (i.e. dissipative flux)
1203  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.12.1-4.12.4)
1204  */
1205 
1206  // Step 1: Primitive solution
1207  const std::array<real2,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real2>(conservative_soln); // from Euler
1208 
1209  // Step 2: Gradient of primitive solution
1210  const std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real2>(conservative_soln, solution_gradient);
1211 
1212  // Step 3: Viscous stress tensor, Velocities, Heat flux
1213  const dealii::Tensor<2,dim,real2> viscous_stress_tensor = compute_viscous_stress_tensor<real2>(primitive_soln, primitive_soln_gradient);
1214  const dealii::Tensor<1,dim,real2> vel = this->template extract_velocities_from_primitive<real2>(primitive_soln); // from Euler
1215  const dealii::Tensor<1,dim,real2> heat_flux = compute_heat_flux<real2>(primitive_soln, primitive_soln_gradient);
1216 
1217  // Step 4: Construct viscous flux; Note: sign corresponds to LHS
1218  const std::array<dealii::Tensor<1,dim,real2>,nstate> viscous_flux = dissipative_flux_given_velocities_viscous_stress_tensor_and_heat_flux<real2>(vel,viscous_stress_tensor,heat_flux);
1219  return viscous_flux;
1220 }
1221 
1222 template <int dim, int nspecies, int nstate, typename real>
1223 std::array<real,nstate> NavierStokes<dim,nspecies,nstate,real>
1225  const std::array<real,nstate> &solution,
1226  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient,
1227  const std::array<real,nstate> &filtered_solution,
1228  const std::array<dealii::Tensor<1,dim,real>,nstate> &filtered_solution_gradient,
1229  const bool on_boundary,
1230  const dealii::types::global_dof_index cell_index,
1231  const dealii::Tensor<1,dim,real> &normal,
1232  const int boundary_type)
1233 {
1234  std::array<real,nstate> dissipative_flux_dot_normal;
1235  // Associated thermal boundary condition
1236  if((on_boundary && (thermal_boundary_condition_type == thermal_boundary_condition_enum::adiabatic))
1237  && (boundary_type == 1001)) {
1238 
1240  // adiabatic boundary
1241  // --> Modify viscous flux such that normal_vector dot gradient of temperature must be zero
1242  dissipative_flux_dot_normal = this->dissipative_flux_dot_normal_on_adiabatic_boundary (
1243  solution,
1244  solution_gradient,
1245  filtered_solution,
1246  filtered_solution_gradient,
1247  cell_index,
1248  normal);
1249  } else {
1250  // if not on boundary and for all other types of boundary conditions (including isothermal) --> no change to dissipative flux
1251  // no change to dissipative flux for BCs that do not impose a condition on the gradient at the boundary
1252  std::array<dealii::Tensor<1,dim,real>,nstate> dissipative_flux;
1253  dissipative_flux = dissipative_flux_templated<real>(solution,solution_gradient);
1254  // compute the dot product with the normal vector
1255  dissipative_flux_dot_normal.fill(0.0); // initialize
1256  for (int s=0; s<nstate; s++) {
1257  for (int d=0; d<dim; ++d) {
1258  dissipative_flux_dot_normal[s] += dissipative_flux[s][d] * normal[d];//compute dot product
1259  }
1260  }
1261  }
1262 
1263  return dissipative_flux_dot_normal;
1264 }
1265 
1266 template <int dim, int nspecies, int nstate, typename real>
1267 std::array<real,nstate> NavierStokes<dim,nspecies,nstate,real>
1269  const std::array<real,nstate> &solution,
1270  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient,
1271  const std::array<real,nstate> &/*filtered_solution*/,
1272  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*filtered_solution_gradient*/,
1273  const dealii::types::global_dof_index /*cell_index*/,
1274  const dealii::Tensor<1,dim,real> &normal)
1275 {
1276  std::array<real,nstate> dissipative_flux_dot_normal;
1277 
1279  // adiabatic boundary
1280  // --> Modify viscous flux such that normal_vector dot gradient of temperature must be zero
1281 
1282  // REFERENCES:
1283  /* (1) Masatsuka 2018 "I do like CFD", p.148, eq.(4.12.1-4.12.4)
1284  * (2) For the boundary condition case, refer to the equation above equation 458 of the following paper:
1285  * Hartmann, Ralf. "Numerical analysis of higher order discontinuous Galerkin finite element methods." (2008): 1-107.
1286  */
1287 
1288  // Step 1: Primitive solution
1289  const std::array<real,nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(solution); // from Euler
1290 
1291  // Step 2: Gradient of primitive solution
1292  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(solution, solution_gradient);
1293 
1294  // Step 3: Viscous stress tensor, Velocities, Heat flux
1295  const dealii::Tensor<2,dim,real> viscous_stress_tensor = compute_viscous_stress_tensor<real>(primitive_soln, primitive_soln_gradient);
1296  const dealii::Tensor<1,dim,real> vel = this->template extract_velocities_from_primitive<real>(primitive_soln); // from Euler
1297  /* ---> Impose adiabatic boundary condition by modifying the heat flux. */
1298  dealii::Tensor<1,dim,real> heat_flux;
1299  for (int flux_dim=0; flux_dim<dim; ++flux_dim) {
1300  // set the heat flux to zero since we want the normal dot gradient of temperature to be zero for an adiabatic boundary
1301  heat_flux[flux_dim] = 0.0;
1302  }
1303 
1304  // Step 4: Construct viscous flux; Note: sign corresponds to LHS
1305  std::array<dealii::Tensor<1,dim,real>,nstate> dissipative_flux;
1306  dissipative_flux = dissipative_flux_given_velocities_viscous_stress_tensor_and_heat_flux<real>(vel,viscous_stress_tensor,heat_flux);
1307 
1308  // compute the dot product with the normal vector
1309  dissipative_flux_dot_normal.fill(0.0); // initialize
1310  for (int s=0; s<nstate; s++) {
1311  for (int d=0; d<dim; ++d) {
1312  dissipative_flux_dot_normal[s] += dissipative_flux[s][d] * normal[d];//compute dot product
1313  }
1314  }
1315 
1316  return dissipative_flux_dot_normal;
1317 }
1318 
1319 template <int dim, int nspecies, int nstate, typename real>
1320 template<typename real2>
1321 std::array<dealii::Tensor<1,dim,real2>,nstate> NavierStokes<dim,nspecies,nstate,real>
1323  const dealii::Tensor<1,dim,real2> &vel,
1324  const dealii::Tensor<2,dim,real2> &viscous_stress_tensor,
1325  const dealii::Tensor<1,dim,real2> &heat_flux) const
1326 {
1327  /* Nondimensionalized viscous flux (i.e. dissipative flux)
1328  * Reference: Masatsuka 2018 "I do like CFD", p.148, eq.(4.12.1-4.12.4)
1329  */
1330 
1331  /* Construct viscous flux given velocities, viscous stress tensor,
1332  * and heat flux; Note: sign corresponds to LHS
1333  */
1334  std::array<dealii::Tensor<1,dim,real2>,nstate> viscous_flux;
1335  for (int flux_dim=0; flux_dim<dim; ++flux_dim) {
1336  // Density equation
1337  viscous_flux[0][flux_dim] = 0.0;
1338  // Momentum equation
1339  for (int stress_dim=0; stress_dim<dim; ++stress_dim){
1340  viscous_flux[1+stress_dim][flux_dim] = -viscous_stress_tensor[stress_dim][flux_dim];
1341  }
1342  // Energy equation
1343  viscous_flux[nstate-1][flux_dim] = 0.0;
1344  for (int stress_dim=0; stress_dim<dim; ++stress_dim){
1345  viscous_flux[nstate-1][flux_dim] -= vel[stress_dim]*viscous_stress_tensor[flux_dim][stress_dim];
1346  }
1347  viscous_flux[nstate-1][flux_dim] += heat_flux[flux_dim];
1348  }
1349  return viscous_flux;
1350 }
1351 
1352 template <int dim, int nspecies, int nstate, typename real>
1355  const int boundary_type,
1356  const dealii::Point<dim, real> &pos,
1357  const dealii::Tensor<1,dim,real> &normal_int,
1358  const std::array<real,nstate> &soln_int,
1359  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1360  const std::array<real,nstate> &/*filtered_soln_int*/,
1361  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*filtered_soln_grad_int*/,
1362  std::array<real,nstate> &soln_bc,
1363  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1364 {
1365  if (boundary_type == 1000) {
1366  // Manufactured solution boundary condition
1367  boundary_manufactured_solution (pos, normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1368  }
1369  else if (boundary_type == 1001) {
1370  // Wall boundary condition
1371  boundary_wall_viscous_flux (normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1372  }
1373  else if (boundary_type == 1004) {
1374  // Riemann-based farfield boundary condition
1375  this->boundary_riemann (normal_int, soln_int, soln_bc);
1376  }
1377  else if (boundary_type == 1005) {
1378  // Simple farfield boundary condition
1379  this->boundary_farfield(soln_bc);
1380  }
1381  else if (boundary_type == 1006)
1382  {
1383  /* Reference: Brian Vermeire's thesis 2014 Equations 3.72-3.73
1384  For slip wall boundary conditions, we require that the
1385  viscous fluxes across the boundary are negligible.
1386  To do this, we can simply project the solution vector
1387  and the gradient from the interior point onto the boundary.
1388  This effectively eliminates the penalty term at the
1389  boundary for both the gradient and flux terms.
1390  */
1391  for (int istate=0; istate<nstate; ++istate) {
1392  soln_bc[istate] = soln_int[istate];
1393  soln_grad_bc[istate] = soln_grad_int[istate];
1394  }
1395  }
1396  else {
1397  this->pcout << "Invalid boundary_type: " << boundary_type <<" not implemented for viscous flows."<<std::endl;
1398  std::abort();
1399  }
1400 }
1401 
1402 template <int dim, int nspecies, int nstate, typename real>
1405  const dealii::Tensor<1,dim,real> &/*normal_int*/,
1406  const std::array<real,nstate> &soln_int,
1407  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1408  std::array<real,nstate> &soln_bc,
1409  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1410 {
1412 
1413  // No-slip wall boundary conditions
1414  // Reference: Page 48 of Julien Brillon's thesis available at https://escholarship.mcgill.ca/concern/theses/h989r903p
1415 
1416  // Apply boundary conditions:
1417  // -- solution at boundary
1418  soln_bc[0] = soln_int[0];
1419  soln_bc[nstate-1] = soln_int[nstate-1];
1420  for (int d=0; d<dim; ++d) {
1421  soln_bc[1+d] = -soln_int[1+d];
1422  }
1423  // -- gradient of solution at boundary
1424  for (int istate=0; istate<nstate; ++istate) {
1425  soln_grad_bc[istate] = soln_grad_int[istate];
1426  }
1427  // If adiabatic wall, set gradient to zero
1428  if(thermal_boundary_condition_type == thermal_boundary_condition_enum::adiabatic){
1429  soln_grad_bc[nstate-1] = 0.0;
1430  }
1431  // If isothermal wall, set temperature at exterior such that the average is the isothermal wall temperature
1432  if(thermal_boundary_condition_type == thermal_boundary_condition_enum::isothermal){
1433  // Step 1: Primitive solutions
1434  const std::array<real,nstate> primitive_soln_int = this->template convert_conservative_to_primitive_templated<real>(soln_int); // from Euler
1435  std::array<real,nstate> primitive_soln_ext = this->template convert_conservative_to_primitive_templated<real>(soln_bc); // from Euler
1436  const real temperature_int = this->template compute_temperature<real>(primitive_soln_int);
1437  const real temperature_ext = 2.0*this->isothermal_wall_temperature - temperature_int;
1438  // override the pressure based on the temperature
1439  primitive_soln_ext[nstate-1] = this->compute_pressure_from_density_temperature(primitive_soln_ext[0],temperature_ext);
1440  // set the equivalent total energy
1441  soln_bc[nstate-1] = this->compute_total_energy(primitive_soln_ext);
1442  }
1443 }
1444 
1445 template <int dim, int nspecies, int nstate, typename real>
1448  const dealii::Point<dim, real> &pos,
1449  const dealii::Tensor<1,dim,real> &/*normal_int*/,
1450  const std::array<real,nstate> &/*soln_int*/,
1451  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*soln_grad_int*/,
1452  std::array<real,nstate> &soln_bc,
1453  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1454 {
1455  // Manufactured solution boundary condition
1456  // Note: This is consistent with Navah & Nadarajah (2018)
1457  std::array<real,nstate> boundary_values;
1458  std::array<dealii::Tensor<1,dim,real>,nstate> boundary_gradients;
1459  for (int i=0; i<nstate; i++) {
1460  boundary_values[i] = this->manufactured_solution_function->value (pos, i);
1461  boundary_gradients[i] = this->manufactured_solution_function->gradient (pos, i);
1462  }
1463  for (int istate=0; istate<nstate; istate++) {
1464  soln_bc[istate] = boundary_values[istate];
1465  // soln_grad_bc[istate] = soln_grad_int[istate]; // done in convection_diffusion.cpp
1466  soln_grad_bc[istate] = boundary_gradients[istate];
1467  }
1468 }
1469 
1470 template <int dim, int nspecies, int nstate, typename real>
1472  const dealii::Vector<double> &uh,
1473  const std::vector<dealii::Tensor<1,dim> > &duh,
1474  const std::vector<dealii::Tensor<2,dim> > &dduh,
1475  const dealii::Tensor<1,dim> &normals,
1476  const dealii::Point<dim> &evaluation_points) const
1477 {
1478  std::vector<std::string> names = post_get_names ();
1479  dealii::Vector<double> computed_quantities = PhysicsBase<dim,nspecies,nstate,real>::post_compute_derived_quantities_vector ( uh, duh, dduh, normals, evaluation_points);
1480  unsigned int current_data_index = computed_quantities.size() - 1;
1481  computed_quantities.grow_or_shrink(names.size());
1482  if constexpr (std::is_same<real,double>::value) {
1483 
1484  std::array<double, nstate> conservative_soln;
1485  for (unsigned int s=0; s<nstate; ++s) {
1486  conservative_soln[s] = uh(s);
1487  }
1488  const std::array<double, nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(conservative_soln);
1489 
1490  std::array<dealii::Tensor<1,dim,double>,nstate> conservative_soln_gradient;
1491  for (unsigned int s=0; s<nstate; ++s) {
1492  for (unsigned int d=0; d<dim; ++d) {
1493  conservative_soln_gradient[s][d] = duh[s][d];
1494  }
1495  }
1496 
1497  // Density
1498  computed_quantities(++current_data_index) = primitive_soln[0];
1499  // Velocities
1500  for (unsigned int d=0; d<dim; ++d) {
1501  computed_quantities(++current_data_index) = primitive_soln[1+d];
1502  }
1503  // Momentum
1504  for (unsigned int d=0; d<dim; ++d) {
1505  computed_quantities(++current_data_index) = conservative_soln[1+d];
1506  }
1507  // Total Energy
1508  computed_quantities(++current_data_index) = conservative_soln[nstate-1];
1509  // Pressure
1510  computed_quantities(++current_data_index) = primitive_soln[nstate-1];
1511  // Pressure coefficient
1512  computed_quantities(++current_data_index) = (primitive_soln[nstate-1] - this->pressure_inf) / this->dynamic_pressure_inf;
1513  // Temperature
1514  computed_quantities(++current_data_index) = this->template compute_temperature<real>(primitive_soln);
1515  // Entropy generation
1516  computed_quantities(++current_data_index) = this->compute_entropy_measure(conservative_soln) - this->entropy_inf;
1517  // Mach Number
1518  computed_quantities(++current_data_index) = this->compute_mach_number(conservative_soln);
1519  if constexpr(dim==3) {
1520  // Vorticity
1521  dealii::Tensor<1,3,double> vorticity = compute_vorticity<double>(conservative_soln,conservative_soln_gradient);
1522  for (unsigned int d=0; d<3; ++d) {
1523  computed_quantities(++current_data_index) = vorticity[d];
1524  }
1525  }
1526  // Vorticity magnitude
1527  computed_quantities(++current_data_index) = compute_vorticity_magnitude(conservative_soln,conservative_soln_gradient);
1528  // Enstrophy
1529  computed_quantities(++current_data_index) = compute_enstrophy(conservative_soln,conservative_soln_gradient);
1530  // Second-invariant Q
1531  computed_quantities(++current_data_index) = compute_second_invariant(conservative_soln,conservative_soln_gradient);
1532  // Dilatation
1533  computed_quantities(++current_data_index) = compute_dilatation(conservative_soln,conservative_soln_gradient);
1534  // Density gradient magnitude
1535  computed_quantities(++current_data_index) = compute_density_gradient_magnitude(conservative_soln,conservative_soln_gradient);
1536  // Viscous stress tensor
1537  if constexpr(dim==2) {
1538  // Vorticity
1539  dealii::Tensor<2,2,double> viscous_stress_tensor = compute_viscous_stress_tensor_from_conservative_templated<double>(conservative_soln,conservative_soln_gradient);
1540  //First line of viscous stress tensor
1541  for (unsigned int d=0; d<2; ++d) {
1542  computed_quantities(++current_data_index) = viscous_stress_tensor[0][d];
1543  }
1544  //Second line of viscous stress tensor
1545  for (unsigned int d=0; d<2; ++d) {
1546  computed_quantities(++current_data_index) = viscous_stress_tensor[1][d];
1547  }
1548  }
1549  else if constexpr(dim==3) {
1550  // Calculate primitive solution gradient
1551  const std::array<dealii::Tensor<1,dim,real>,nstate> primitive_soln_gradient = this->template convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln, conservative_soln_gradient);
1552  // Viscous stress tensor
1553  dealii::Tensor<2,3,double> viscous_stress_tensor = compute_viscous_stress_tensor<real>(primitive_soln,primitive_soln_gradient);
1554  //First line of viscous stress tensor
1555  for (unsigned int d=0; d<3; ++d) {
1556  computed_quantities(++current_data_index) = viscous_stress_tensor[0][d];
1557  }
1558  //Second line of viscous stress tensor
1559  for (unsigned int d=0; d<3; ++d) {
1560  computed_quantities(++current_data_index) = viscous_stress_tensor[1][d];
1561  }
1562  //Third line of viscous stress tensor
1563  for (unsigned int d=0; d<3; ++d) {
1564  computed_quantities(++current_data_index) = viscous_stress_tensor[2][d];
1565  }
1566  }
1567  //Viscosity coefficient
1568  computed_quantities(++current_data_index) = compute_viscosity_coefficient<real>(primitive_soln);
1569 
1570  }
1571  if (computed_quantities.size()-1 != current_data_index) {
1572  this->pcout << " Did not assign a value to all the data. Missing " << computed_quantities.size() - current_data_index << " variables."
1573  << " If you added a new output variable, make sure the names and DataComponentInterpretation match the above. "
1574  << std::endl;
1575  }
1576 
1577  return computed_quantities;
1578 }
1579 
1580 template <int dim, int nspecies, int nstate, typename real>
1581 std::vector<dealii::DataComponentInterpretation::DataComponentInterpretation> NavierStokes<dim,nspecies,nstate,real>
1583 {
1584  namespace DCI = dealii::DataComponentInterpretation;
1585  std::vector<DCI::DataComponentInterpretation> interpretation = PhysicsBase<dim,nspecies,nstate,real>::post_get_data_component_interpretation (); // state variables
1586  interpretation.push_back (DCI::component_is_scalar); // Density
1587  for (unsigned int d=0; d<dim; ++d) {
1588  interpretation.push_back (DCI::component_is_part_of_vector); // Velocity
1589  }
1590  for (unsigned int d=0; d<dim; ++d) {
1591  interpretation.push_back (DCI::component_is_part_of_vector); // Momentum
1592  }
1593  interpretation.push_back (DCI::component_is_scalar); // Total Energy
1594  interpretation.push_back (DCI::component_is_scalar); // Pressure
1595  interpretation.push_back (DCI::component_is_scalar); // Pressure coefficient
1596  interpretation.push_back (DCI::component_is_scalar); // Temperature
1597  interpretation.push_back (DCI::component_is_scalar); // Entropy generation
1598  interpretation.push_back (DCI::component_is_scalar); // Mach number
1599  if constexpr(dim==3) {
1600  for (unsigned int d=0; d<3; ++d) {
1601  interpretation.push_back (DCI::component_is_part_of_vector); // Vorticity
1602  }
1603  }
1604  interpretation.push_back (DCI::component_is_scalar); // Vorticity magnitude
1605  interpretation.push_back (DCI::component_is_scalar); // Enstrophy
1606  interpretation.push_back (DCI::component_is_scalar); // Second-invariant Q
1607  interpretation.push_back (DCI::component_is_scalar); // Dilatation
1608  interpretation.push_back (DCI::component_is_scalar); // Density gradient magnitude
1609  if constexpr(dim==2) {
1610  for (unsigned int d=0; d<dim; ++d) {
1611  interpretation.push_back (DCI::component_is_part_of_vector); // First line of viscous Stress Tensor
1612  }
1613  for (unsigned int d=0; d<dim; ++d) {
1614  interpretation.push_back (DCI::component_is_part_of_vector); // Second line of viscous Stress Tensor
1615  }
1616  }
1617  else if constexpr(dim==3) {
1618  for (unsigned int d=0; d<dim; ++d) {
1619  interpretation.push_back (DCI::component_is_part_of_vector); // First line of viscous Stress Tensor
1620  }
1621  for (unsigned int d=0; d<dim; ++d) {
1622  interpretation.push_back (DCI::component_is_part_of_vector); // Second line of viscous Stress Tensor
1623  }
1624  for (unsigned int d=0; d<dim; ++d) {
1625  interpretation.push_back (DCI::component_is_part_of_vector); // Third line of viscous Stress Tensor
1626  }
1627  }
1628  interpretation.push_back (DCI::component_is_scalar); // Viscosity
1629 
1630  std::vector<std::string> names = post_get_names();
1631  if (names.size() != interpretation.size()) {
1632  this->pcout << "Number of DataComponentInterpretation is not the same as number of names for output file" << std::endl;
1633  }
1634  return interpretation;
1635 }
1636 
1637 
1638 template <int dim, int nspecies, int nstate, typename real>
1639 std::vector<std::string> NavierStokes<dim,nspecies,nstate,real>
1641 {
1642  std::vector<std::string> names = PhysicsBase<dim,nspecies,nstate,real>::post_get_names ();
1643  names.push_back ("density");
1644  for (unsigned int d=0; d<dim; ++d) {
1645  names.push_back ("velocity");
1646  }
1647  for (unsigned int d=0; d<dim; ++d) {
1648  names.push_back ("momentum");
1649  }
1650  names.push_back ("total_energy");
1651  names.push_back ("pressure");
1652  names.push_back ("pressure_coefficient");
1653  names.push_back ("temperature");
1654 
1655  names.push_back ("entropy_generation");
1656  names.push_back ("mach_number");
1657  if constexpr(dim==3) {
1658  for (unsigned int d=0; d<3; ++d) {
1659  names.push_back ("vorticity");
1660  }
1661  }
1662  names.push_back ("vorticity_magnitude");
1663  names.push_back ("enstrophy");
1664  names.push_back ("second_invariant_Q");
1665  names.push_back ("dilatation");
1666  names.push_back ("density_gradient_magnitude");
1667  if constexpr(dim==2) {
1668  // First line of viscous Stress Tensor
1669  for (unsigned int d=0; d<dim; ++d) {
1670  names.push_back ("du_viscous_stress_tensor");
1671  }
1672  // Second line of viscous Stress Tensor
1673  for (unsigned int d=0; d<dim; ++d) {
1674  names.push_back ("dv_viscous_stress_tensor");
1675  }
1676  }
1677  else if constexpr(dim==3) {
1678  // First line of viscous Stress Tensor
1679  for (unsigned int d=0; d<dim; ++d) {
1680  names.push_back ("du_viscous_stress_tensor");
1681  }
1682  // Second line of viscous Stress Tensor
1683  for (unsigned int d=0; d<dim; ++d) {
1684  names.push_back ("dv_viscous_stress_tensor");
1685  }
1686  // Third line of viscous Stress Tensor
1687  for (unsigned int d=0; d<dim; ++d) {
1688  names.push_back ("dz_viscous_stress_tensor");
1689  }
1690  }
1691  names.push_back ("viscosity_coefficient");
1692  return names;
1693 }
1694 
1695 template <int dim, int nspecies, int nstate, typename real>
1696 dealii::UpdateFlags NavierStokes<dim,nspecies,nstate,real>
1698 {
1699  //return update_values | update_gradients;
1700  return dealii::update_values
1701  | dealii::update_quadrature_points
1702  | dealii::update_gradients
1703  ;
1704 }
1705 
1706 template <int dim, int nspecies, int nstate, typename real>
1708  const Parameters::AllParameters *const parameters_input,
1709  const double ref_length,
1710  const double gamma_gas,
1711  const double mach_inf,
1712  const double angle_of_attack,
1713  const double side_slip_angle,
1714  const double prandtl_number,
1715  const double reynolds_number_inf,
1716  const bool use_constant_viscosity,
1717  const double constant_viscosity,
1718  const double reynolds_number_based_on_friction_velocity,
1719  const double half_channel_height,
1720  const double temperature_inf,
1721  const double isothermal_wall_temperature,
1722  const thermal_boundary_condition_enum thermal_boundary_condition_type,
1723  std::shared_ptr< ManufacturedSolutionFunction<dim,nspecies,real> > manufactured_solution_function,
1724  const two_point_num_flux_enum two_point_num_flux_type)
1725  : NavierStokes<dim,nspecies,nstate,real>(
1726  parameters_input,
1727  ref_length,
1728  gamma_gas,
1729  mach_inf,
1730  angle_of_attack,
1731  side_slip_angle,
1732  prandtl_number,
1733  reynolds_number_inf,
1734  use_constant_viscosity,
1735  constant_viscosity,
1736  temperature_inf,
1737  isothermal_wall_temperature,
1738  thermal_boundary_condition_type,
1739  manufactured_solution_function,
1740  two_point_num_flux_type,
1741  true) //has_nonzero_physical_source = true
1742  , x_momentum_constant_source_term(pow((1.0/half_channel_height),3.0)*pow((reynolds_number_based_on_friction_velocity/this->reynolds_number_inf),2.0))
1743 {
1744  static_assert(nstate==dim+2, "Physics::NavierStokes_ChannelFlowConstantSourceTerm() should be created with nstate=dim+2");
1745  // Nothing to do here so far
1746 }
1747 
1748 template <int dim, int nspecies, int nstate, typename real>
1751  const dealii::Point<dim,real> &/*pos*/,
1752  const std::array<real,nstate> &solution,
1753  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*solution_gradient*/,
1754  const dealii::types::global_dof_index /*cell_index*/) const
1755 {
1756  std::array<real,nstate> physical_source;
1757  for (int i=0; i<nstate; i++) {
1758  physical_source[i] = 0;
1759  }
1760  physical_source[1] = this->x_momentum_constant_source_term; // x-momentum
1761  const dealii::Tensor<1,dim,real> vel = this->template compute_velocities<real>(solution);
1762  physical_source[nstate-1] = vel[0]*physical_source[1];
1763 
1764  return physical_source;
1765 }
1766 
1767 template <int dim, int nspecies, int nstate, typename real>
1769  const Parameters::AllParameters *const parameters_input,
1770  const double ref_length,
1771  const double gamma_gas,
1772  const double mach_inf,
1773  const double angle_of_attack,
1774  const double side_slip_angle,
1775  const double prandtl_number,
1776  const double reynolds_number_inf,
1777  const bool use_constant_viscosity,
1778  const double constant_viscosity,
1779  const double reynolds_number_based_on_friction_velocity,
1780  const double half_channel_height,
1781  const double distance_from_wall_for_wall_model_input_velocity,
1782  const double temperature_inf,
1783  const double isothermal_wall_temperature,
1787  : NavierStokes_ChannelFlowConstantSourceTerm<dim,nspecies,nstate,real>(
1788  parameters_input,
1789  ref_length,
1790  gamma_gas,
1791  mach_inf,
1792  angle_of_attack,
1793  side_slip_angle,
1794  prandtl_number,
1795  reynolds_number_inf,
1796  use_constant_viscosity,
1797  constant_viscosity,
1798  reynolds_number_based_on_friction_velocity,
1799  half_channel_height,
1800  temperature_inf,
1801  isothermal_wall_temperature,
1802  thermal_boundary_condition_type,
1804  two_point_num_flux_type)
1805  , distance_from_wall_for_wall_model_input_velocity(distance_from_wall_for_wall_model_input_velocity)
1806  , wall_model_look_up_table(std::unique_ptr<WallModelLookUpTable<real>>())
1807 {
1808  static_assert(nstate==dim+2, "Physics::NavierStokes_ChannelFlowConstantSourceTerm_WallModel() should be created with nstate=dim+2");
1809  // Nothing to do here so far
1810 }
1811 
1812 template <int dim, int nspecies, int nstate, typename real>
1815  const std::array<real,nstate> &conservative_soln,
1816  const dealii::Tensor<1,dim,real> &normal_vector) const
1817 {
1818  // Get the wall parallel velocities; equivalent Frere thesis eq.(2.40)
1819  const dealii::Tensor<1,dim,real> velocities_parallel_to_wall = this->template compute_velocities_parallel_to_wall<real>(conservative_soln,normal_vector);
1820 
1821  // Get wall tangent vector; equivalent Frere thesis eq.(2.40)
1822  const dealii::Tensor<1,dim,real> wall_tangent_vector = this->template compute_wall_tangent_vector_from_velocities_parallel_to_wall<real>(velocities_parallel_to_wall);
1823 
1824  // Get wall parallel velocity component; Frere thesis eq.(2.41)
1825  real velocity_parallel_to_wall = 0.0;
1826  for (int d=0; d<dim; ++d) {
1827  velocity_parallel_to_wall += velocities_parallel_to_wall[d]*wall_tangent_vector[d];
1828  }
1829  return velocity_parallel_to_wall;
1830 }
1831 
1832 template <int dim, int nspecies, int nstate, typename real>
1835  const std::array<real,nstate> &solution,
1836  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*solution_gradient*/,
1837  const std::array<real,nstate> &/*filtered_solution*/,
1838  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*filtered_solution_gradient*/,
1839  const dealii::types::global_dof_index /*cell_index*/,
1840  const dealii::Tensor<1,dim,real> &normal)
1841 {
1842  /* Input variable 'solution' is actually solution at the wall element opposing face.
1843  This means that for a channel flow with a uniform grid, this is solution is
1844  at a distance dy = domain_length_y/(number_of_elements_y_direction) from the wall.
1845  */
1846 
1847  // Get the wall parallel velocities; equivalent Frere thesis eq.(2.40)
1848  const dealii::Tensor<1,dim,real> velocities_parallel_to_wall = this->template compute_velocities_parallel_to_wall<real>(solution,normal);
1849 
1850  // Get wall tangent vector; equivalent Frere thesis eq.(2.40)
1851  const dealii::Tensor<1,dim,real> wall_tangent_vector = this->template compute_wall_tangent_vector_from_velocities_parallel_to_wall<real>(velocities_parallel_to_wall);
1852 
1853  // Get wall parallel velocity component; Frere thesis eq.(2.41)
1854  real velocity_parallel_to_wall = 0.0;
1855  for (int d=0; d<dim; ++d) {
1856  velocity_parallel_to_wall += velocities_parallel_to_wall[d]*wall_tangent_vector[d];
1857  }
1858 
1859  // Get wall shear stress magnitude from wall model
1860  const std::array<real, nstate> primitive_soln = this->template convert_conservative_to_primitive_templated<real>(solution);
1861  const real viscosity_coefficient = this->template compute_viscosity_coefficient<real>(primitive_soln);
1862  const real density = solution[0];
1863  const real wall_shear_stress_magnitude =
1864  this->wall_model_look_up_table->get_wall_shear_stress_magnitude(
1865  velocity_parallel_to_wall,
1867  viscosity_coefficient,
1868  density,
1869  this->reynolds_number_inf);
1870 
1871  // Compute the dissipative flux dot normal vector; Frere thesis eq.(2.39)
1872  std::array<real,nstate> dissipative_flux_dot_normal;
1873  dissipative_flux_dot_normal.fill(0.0); // initialize
1874  for (int d=0; d<dim; ++d) {
1875  dissipative_flux_dot_normal[1+d] += wall_shear_stress_magnitude * wall_tangent_vector[d]; // Frere thesis eq.(2.39)
1876  }
1878 }
1879 
1880 template <typename real>
1882 {
1883  // Do nothing
1884 }
1885 
1886 template <typename real>
1889  const real wall_parallel_velocity,
1890  const real distance,
1891  const real viscosity_coefficient,
1892  const real density,
1893  const double reynolds_number_inf) const
1894 {
1895  const real u_parallel_plus_y_plus = reynolds_number_inf*density*distance*wall_parallel_velocity/viscosity_coefficient;
1896  const real y_plus = this->interpolate(u_parallel_plus_y_plus,true);
1897  const real wall_friction_velocity = y_plus*viscosity_coefficient/(density*distance*reynolds_number_inf);
1898  const real wall_shear_stress = density*wall_friction_velocity*wall_friction_velocity;
1899  return wall_shear_stress;
1900 }
1901 
1902 template <typename real>
1904 interpolate(const real x, const bool extrapolate) const
1905 {
1906  int i = 0; // find left end of interval for interpolation
1907  if ( x >= xData[NUMBER_OF_SAMPLE_POINTS - 2] ) // special case: beyond right end
1908  {
1909  i = NUMBER_OF_SAMPLE_POINTS - 2;
1910  }
1911  else
1912  {
1913  while ( x > xData[i+1] ) i++;
1914  }
1915  real xL = xData[i], yL = yData[i], xR = xData[i+1], yR = yData[i+1]; // points on either side (unless beyond ends)
1916  if ( !extrapolate ) // if beyond ends of array and not extrapolating
1917  {
1918  if ( x < xL ) yR = yL;
1919  if ( x > xR ) yL = yR;
1920  }
1921 
1922  real dydx = ( yR - yL ) / ( xR - xL ); // gradient
1923 
1924  return yL + dydx * ( x - xL ); // linear interpolation
1925 }
1926 
1927 #if PHILIP_SPECIES==1
1928  // Define a sequence of possible types
1929  #define POSSIBLE_TYPES (double)(FadType)(RadType)(FadFadType)(RadFadType)
1930  // Define a macro to instantiate NavierStokes and NavierStokes functions for a specific type
1931  #define INSTANTIATE_TYPES(r, data, type) \
1932  template class NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >; \
1933  template class NavierStokes_ChannelFlowConstantSourceTerm < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >; \
1934  template class NavierStokes_ChannelFlowConstantSourceTerm_WallModel < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >; \
1935  template class WallModelLookUpTable<type>; \
1936  template type NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_scaled_viscosity_coefficient< type >(const std::array<type,PHILIP_DIM+2> &primitive_soln) const; \
1937  template dealii::Tensor<2,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::extract_velocities_gradient_from_primitive_solution_gradient< type > (const std::array<dealii::Tensor<1,PHILIP_DIM, type >,PHILIP_DIM+2> &primitive_soln_gradient) const; \
1938  template std::array<dealii::Tensor<1,PHILIP_DIM, type >,PHILIP_DIM+2> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::dissipative_flux_given_velocities_viscous_stress_tensor_and_heat_flux<type>(const dealii::Tensor<1,PHILIP_DIM, type> &vel, const dealii::Tensor<2,PHILIP_DIM,type> &viscous_stress_tensor, const dealii::Tensor<1,PHILIP_DIM, type> &heat_flux) const; \
1939  template dealii::Tensor<2,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_strain_rate_tensor< type > (const dealii::Tensor<2,PHILIP_DIM,type > &vel_gradient) const; \
1940  template dealii::Tensor<2,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type>::compute_strain_rate_tensor_from_conservative_templated<type>(const std::array<type,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM,type>,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1941  template dealii::Tensor<2,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_viscous_stress_tensor_via_scaled_viscosity_and_strain_rate_tensor< type > (const type scaled_viscosity_coefficient, const dealii::Tensor<2,PHILIP_DIM,type> &strain_rate_tensor) const; \
1942  template dealii::Tensor<2,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_viscous_stress_tensor_from_conservative_templated<type>(const std::array<type,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM,type>,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1943  template dealii::Tensor<1,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_heat_flux_given_scaled_heat_conductivity_and_temperature_gradient< type > (const type scaled_heat_conductivity, const dealii::Tensor<1,PHILIP_DIM, type> &temperature_gradient) const; \
1944  template type NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_scaled_heat_conductivity_given_scaled_viscosity_coefficient_and_prandtl_number< type > (const type scaled_viscosity_coefficient, const double prandtl_number_input) const; \
1945  template dealii::Tensor<1,PHILIP_DIM, type > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_temperature_gradient< type >(const std::array< type ,PHILIP_DIM+2> &primitive_soln, const std::array<dealii::Tensor<1,PHILIP_DIM, type >,PHILIP_DIM+2> &primitive_soln_gradient) const; \
1946  template type NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_viscosity_coefficient< type >(const std::array< type ,PHILIP_DIM+2> &primitive_soln) const; \
1947  template type NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type>::compute_viscosity_coefficient_from_temperature< type >(const type temperature) const; \
1948  template dealii::Tensor<1,3,type > NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_vorticity< type >(const std::array<type ,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM, type >,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1949  template type NavierStokes<PHILIP_DIM,PHILIP_SPECIES,PHILIP_DIM+2,type>::compute_wall_shear_stress<type>(const std::array<type,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM,type>,PHILIP_DIM+2> &conservative_soln_gradient, const dealii::Tensor<1,PHILIP_DIM,type> &normal_vector) const; \
1950  template type NavierStokes<PHILIP_DIM,PHILIP_SPECIES,PHILIP_DIM+2,type>::scale_viscosity_coefficient<type> (const type viscosity_coefficient) const;
1951  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_TYPES, _, POSSIBLE_TYPES)
1952 
1953 // -- -- instantiate all the real types with real2 = FadType for automatic differentiation in classes derived from LargeEddySimulationBase
1954  #undef POSSIBLE_TYPES
1955  #define POSSIBLE_TYPES (double)(RadType)(FadFadType)(RadFadType)
1956  // Define a macro to instantiate NavierStokes and NavierStokes functions for a specific type
1957  #define INSTANTIATE_FADTYPES(r, data, type) \
1958  template dealii::Tensor<2,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::extract_velocities_gradient_from_primitive_solution_gradient<FadType> (const std::array<dealii::Tensor<1,PHILIP_DIM, FadType>,PHILIP_DIM+2> &primitive_soln_gradient) const; \
1959  template std::array<dealii::Tensor<1,PHILIP_DIM, FadType>,PHILIP_DIM+2> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type>::dissipative_flux_given_velocities_viscous_stress_tensor_and_heat_flux<FadType>(const dealii::Tensor<1,PHILIP_DIM, FadType> &vel, const dealii::Tensor<2,PHILIP_DIM, FadType> &viscous_stress_tensor, const dealii::Tensor<1,PHILIP_DIM, FadType> &heat_flux) const; \
1960  template dealii::Tensor<2,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_strain_rate_tensor<FadType> (const dealii::Tensor<2,PHILIP_DIM, FadType> &vel_gradient) const; \
1961  template dealii::Tensor<2,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2, type>::compute_strain_rate_tensor_from_conservative_templated<FadType>(const std::array<FadType,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM,FadType>,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1962  template dealii::Tensor<2,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_viscous_stress_tensor_via_scaled_viscosity_and_strain_rate_tensor<FadType> (const FadType scaled_viscosity_coefficient, const dealii::Tensor<2,PHILIP_DIM, FadType> &strain_rate_tensor) const; \
1963  template dealii::Tensor<2,PHILIP_DIM, FadType > NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_viscous_stress_tensor_from_conservative_templated<FadType>(const std::array<FadType,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM,FadType>,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1964  template dealii::Tensor<1,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_heat_flux_given_scaled_heat_conductivity_and_temperature_gradient<FadType> (const FadType scaled_heat_conductivity, const dealii::Tensor<1,PHILIP_DIM, FadType> &temperature_gradient) const; \
1965  template FadType NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_scaled_heat_conductivity_given_scaled_viscosity_coefficient_and_prandtl_number<FadType> (const FadType scaled_viscosity_coefficient, const double prandtl_number_input) const; \
1966  template dealii::Tensor<1,PHILIP_DIM, FadType> NavierStokes<PHILIP_DIM, PHILIP_SPECIES,PHILIP_DIM+2,type >::compute_temperature_gradient<FadType>(const std::array<FadType,PHILIP_DIM+2> &primitive_soln, const std::array<dealii::Tensor<1,PHILIP_DIM, FadType>,PHILIP_DIM+2> &primitive_soln_gradient) const; \
1967  template FadType NavierStokes<PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_viscosity_coefficient< FadType >(const std::array<FadType,PHILIP_DIM+2> &primitive_soln) const; \
1968  template FadType NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_viscosity_coefficient_from_temperature< FadType >(const FadType temperature) const; \
1969  template dealii::Tensor<1,3,FadType> NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_vorticity< FadType >(const std::array<FadType,PHILIP_DIM+2> &conservative_soln, const std::array<dealii::Tensor<1,PHILIP_DIM, FadType>,PHILIP_DIM+2> &conservative_soln_gradient) const; \
1970  template FadType NavierStokes < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_scaled_viscosity_coefficient< FadType >(const std::array<FadType ,PHILIP_DIM+2> &primitive_soln) const;
1971  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_FADTYPES, _, POSSIBLE_TYPES)
1972 //==============================================================================
1973 #else
1975 #endif
1976 } // Physics namespace
1977 } // PHiLiP namespace
std::array< real, nstate > dissipative_flux_dot_normal(const std::array< real, nstate > &solution, const std::array< dealii::Tensor< 1, dim, real >, nstate > &solution_gradient, const std::array< real, nstate > &filtered_solution, const std::array< dealii::Tensor< 1, dim, real >, nstate > &filtered_solution_gradient, const bool on_boundary, const dealii::types::global_dof_index cell_index, const dealii::Tensor< 1, dim, real > &normal, const int boundary_type) override
const thermal_boundary_condition_enum thermal_boundary_condition_type
Thermal boundary condition type (adiabatic or isothermal)
Definition: navier_stokes.h:60
const double angle_of_attack
Angle of attack.
Definition: euler.h:119
const double constant_viscosity
Nondimensionalized constant viscosity.
Definition: navier_stokes.h:52
Sacado::Fad::DFad< double > FadType
Sacado AD type for first derivatives.
Definition: ADTypes.hpp:11
const double mach_inf
Farfield Mach number.
Definition: euler.h:114
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
std::array< real, nstate > physical_source_term(const dealii::Point< dim, real > &pos, const std::array< real, nstate > &solution, const std::array< dealii::Tensor< 1, dim, real >, nstate > &solution_gradient, const dealii::types::global_dof_index cell_index) const override
Physical source term for turbulent channel flow case.
const two_point_num_flux_enum two_point_num_flux_type
Two point numerical flux type (for split form)
Definition: euler.h:129
Manufactured solution used for grid studies to check convergence orders.
Files for the baseline physics.
Definition: ADTypes.hpp:10
Wall Model Look up table.
real get_velocity_component_parallel_to_wall_from_solution_and_normal_vector(const std::array< real, nstate > &conservative_soln, const dealii::Tensor< 1, dim, real > &normal_vector) const
Returns the velocoty component parallel to the wall from the solution and normal vector.
std::array< real, nstate > dissipative_flux_dot_normal_on_adiabatic_boundary(const std::array< real, nstate > &solution, const std::array< dealii::Tensor< 1, dim, real >, nstate > &solution_gradient, const std::array< real, nstate > &filtered_solution, const std::array< dealii::Tensor< 1, dim, real >, nstate > &filtered_solution_gradient, const dealii::types::global_dof_index cell_index, const dealii::Tensor< 1, dim, real > &normal) override
std::shared_ptr< ManufacturedSolutionFunction< dim, nspecies, real > > manufactured_solution_function
Manufactured solution function.
Definition: physics.h:71
NavierStokes_ChannelFlowConstantSourceTerm_WallModel(const Parameters::AllParameters *const parameters_input, const double ref_length, const double gamma_gas, const double mach_inf, const double angle_of_attack, const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, const bool use_constant_viscosity, const double constant_viscosity, const double reynolds_number_based_on_friction_velocity, const double half_channel_height, const double distance_from_wall_for_wall_model_input_velocity, const double temperature_inf=273.15, const double isothermal_wall_temperature=1.0, const thermal_boundary_condition_enum thermal_boundary_condition_type=thermal_boundary_condition_enum::adiabatic, std::shared_ptr< ManufacturedSolutionFunction< dim, nspecies, real > > manufactured_solution_function=nullptr, const two_point_num_flux_enum two_point_num_flux_type=two_point_num_flux_enum::KG)
Constructor.
Main parameter class that contains the various other sub-parameter classes.
const double distance_from_wall_for_wall_model_input_velocity
Distance from wall for wall model input velocity.
NavierStokes(const Parameters::AllParameters *const parameters_input, const double ref_length, const double gamma_gas, const double mach_inf, const double angle_of_attack, const double side_slip_angle, const double prandtl_number, const double reynolds_number_inf, const bool use_constant_viscosity, const double constant_viscosity, const double temperature_inf=273.15, const double isothermal_wall_temperature=1.0, const thermal_boundary_condition_enum thermal_boundary_condition_type=thermal_boundary_condition_enum::adiabatic, std::shared_ptr< ManufacturedSolutionFunction< dim, nspecies, real > > manufactured_solution_function=nullptr, const two_point_num_flux_enum two_point_num_flux_type=two_point_num_flux_enum::KG, const bool has_nonzero_physical_source=false)
Constructor.
TwoPointNumericalFlux
Two point numerical flux type for split form.
const double isothermal_wall_temperature
Nondimensionalized isothermal wall temperature.
Definition: navier_stokes.h:58
const double side_slip_angle
Sideslip angle.
Definition: euler.h:123
Euler equations. Derived from PhysicsBase.
Definition: euler.h:78
const double x_momentum_constant_source_term
Nondimensional constant source term for x-momentum.
double temperature_inf
Non-dimensionalized temperature* at infinity. Should equal 1/density*(inf)
Definition: euler.h:130
const double reynolds_number_inf
Farfield (free stream) Reynolds number.
Definition: navier_stokes.h:56
const bool use_constant_viscosity
Flag to use constant viscosity instead of Sutherland&#39;s law of viscosity.
Definition: navier_stokes.h:50
const double ref_length
Reference length.
Definition: euler.h:105
const double prandtl_number
Prandtl number.
Definition: navier_stokes.h:54
real interpolate(const real x, const bool extrapolate) const
Destructor.
ThermalBoundaryCondition
Types of thermal boundary conditions available.
std::unique_ptr< WallModelLookUpTable< real > > wall_model_look_up_table
Pointer to wall model look-up table object.
Navier-Stokes equations. Derived from Euler for the convective terms, which is derived from PhysicsBa...
Definition: navier_stokes.h:12
real get_wall_shear_stress_magnitude(const real wall_parallel_velocity, const real distance, const real viscosity_coefficient, const real density, const double reynolds_number_inf) const
Returns the wall shear stress magnitude calculated from the wall model.
Navier-Stokes equations with constant physical source term for the turbulent channel flow case...