[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
euler.cpp
1 #include <cmath>
2 #include <vector>
3 #include <boost/preprocessor/seq/for_each.hpp>
4 
5 #include "ADTypes.hpp"
6 
7 #include "physics.h"
8 #include "euler.h"
9 
10 namespace PHiLiP {
11 namespace Physics {
12 
13 template <int dim, int nspecies, int nstate, typename real>
15  const Parameters::AllParameters *const parameters_input,
16  const double ref_length,
17  const double gamma_gas,
18  const double mach_inf,
19  const double angle_of_attack,
20  const double side_slip_angle,
21  std::shared_ptr< ManufacturedSolutionFunction<dim,nspecies,real> > manufactured_solution_function,
22  const two_point_num_flux_enum two_point_num_flux_type_input,
23  const bool has_nonzero_diffusion,
24  const bool has_nonzero_physical_source)
25  : PhysicsBase<dim,nspecies,nstate,real>(parameters_input, has_nonzero_diffusion,has_nonzero_physical_source,manufactured_solution_function)
26  , ref_length(ref_length)
27  , gam(gamma_gas)
28  , gamm1(gam-1.0)
29  , density_inf(1.0) // Nondimensional - Free stream values
30  , mach_inf(mach_inf)
31  , mach_inf_sqr(mach_inf*mach_inf)
32  , angle_of_attack(angle_of_attack)
33  , side_slip_angle(side_slip_angle)
34  , sound_inf(1.0/(mach_inf))
35  , pressure_inf(1.0/(gam*mach_inf_sqr))
36  , entropy_inf(pressure_inf*pow(density_inf,-gam))
37  , two_point_num_flux_type(two_point_num_flux_type_input)
38  //, internal_energy_inf(1.0/(gam*(gam-1.0)*mach_inf_sqr))
39  // Note: Eq.(3.11.18) has a typo in internal_energy_inf expression, mach_inf_sqr should be in denominator.
40 {
41  static_assert(nstate==dim+2, "Physics::Euler() should be created with nstate=dim+2");
42 
43  // Nondimensional temperature at infinity
44  temperature_inf = gam*pressure_inf/density_inf * mach_inf_sqr; // Note by JB: this can simply be set = 1
45 
46  // For now, don't allow side-slip angle
47  if (std::abs(side_slip_angle) >= 1e-14) {
48  this->pcout << "Side slip angle = " << side_slip_angle << ". Side_slip_angle must be zero. " << std::endl;
49  this->pcout << "I have not figured out the side slip angles just yet." << std::endl;
50  std::abort();
51  }
52  if(dim==1) {
53  velocities_inf[0] = 1.0;
54  } else if(dim==2) {
55  velocities_inf[0] = cos(angle_of_attack);
56  velocities_inf[1] = sin(angle_of_attack); // Maybe minus?? -- Clarify with Doug
57  } else if (dim==3) {
58  velocities_inf[0] = cos(angle_of_attack)*cos(side_slip_angle);
59  velocities_inf[1] = sin(angle_of_attack)*cos(side_slip_angle);
60  velocities_inf[2] = sin(side_slip_angle);
61  }
62 
63  assert(std::abs(velocities_inf.norm() - 1.0) < 1e-14);
64 
65  double velocity_inf_sqr = 1.0;
66  dynamic_pressure_inf = 0.5 * density_inf * velocity_inf_sqr;
67 }
68 
69 template <int dim, int nspecies, int nstate, typename real>
70 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
72  const dealii::Point<dim,real> &pos,
73  const std::array<real,nstate> &conservative_soln,
74  const real current_time,
75  const dealii::types::global_dof_index /*cell_index*/) const
76 {
77  return source_term(pos,conservative_soln,current_time);
78 }
79 
80 template <int dim, int nspecies, int nstate, typename real>
81 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
83  const dealii::Point<dim,real> &pos,
84  const std::array<real,nstate> &/*conservative_soln*/,
85  const real /*current_time*/) const
86 {
87  std::array<real,nstate> source_term = convective_source_term(pos);
88  return source_term;
89 }
90 
91 template <int dim, int nspecies, int nstate, typename real>
92 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
94  const dealii::Point<dim,real> &pos) const
95 {
96  std::array<real,nstate> manufactured_solution;
97  for (int s=0; s<nstate; s++) {
98  manufactured_solution[s] = this->manufactured_solution_function->value (pos, s);
99  if (s==0) {
100  assert(manufactured_solution[s] > 0);
101  }
102  }
103  return manufactured_solution;
104 }
105 
106 template <int dim, int nspecies, int nstate, typename real>
107 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
109  const dealii::Point<dim,real> &pos) const
110 {
111  std::vector<dealii::Tensor<1,dim,real>> manufactured_solution_gradient_dealii(nstate);
112  this->manufactured_solution_function->vector_gradient(pos,manufactured_solution_gradient_dealii);
113  std::array<dealii::Tensor<1,dim,real>,nstate> manufactured_solution_gradient;
114  for (int d=0;d<dim;d++) {
115  for (int s=0; s<nstate; s++) {
116  manufactured_solution_gradient[s][d] = manufactured_solution_gradient_dealii[s][d];
117  }
118  }
119  return manufactured_solution_gradient;
120 }
121 
122 template <int dim, int nspecies, int nstate, typename real>
123 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
125  const dealii::Point<dim,real> &pos) const
126 {
127  const std::array<real,nstate> manufactured_solution = get_manufactured_solution_value(pos);
128  const std::array<dealii::Tensor<1,dim,real>,nstate> manufactured_solution_gradient = get_manufactured_solution_gradient(pos);
129 
130  dealii::Tensor<1,nstate,real> convective_flux_divergence;
131  for (int d=0;d<dim;d++) {
132  dealii::Tensor<1,dim,real> normal;
133  normal[d] = 1.0;
134  const dealii::Tensor<2,nstate,real> jacobian = convective_flux_directional_jacobian(manufactured_solution, normal);
135 
136  //convective_flux_divergence += jacobian*manufactured_solution_gradient[d];
137  for (int sr = 0; sr < nstate; ++sr) {
138  real jac_grad_row = 0.0;
139  for (int sc = 0; sc < nstate; ++sc) {
140  jac_grad_row += jacobian[sr][sc]*manufactured_solution_gradient[sc][d];
141  }
142  convective_flux_divergence[sr] += jac_grad_row;
143  }
144  }
145  std::array<real,nstate> convective_source_term;
146  for (int s=0; s<nstate; s++) {
147  convective_source_term[s] = convective_flux_divergence[s];
148  }
149 
150  return convective_source_term;
151 }
152 
153 template <int dim, int nspecies, int nstate, typename real>
154 template<typename real2>
155 bool Euler<dim,nspecies,nstate,real>::check_positive_quantity(real2 &qty, const std::string qty_name) const {
156  using limiter_enum = Parameters::LimiterParam::LimiterType;
157  bool qty_is_positive;
158 
159  if (this->all_parameters->limiter_param.bound_preserving_limiter != limiter_enum::positivity_preservingZhang2010
160  && this->all_parameters->limiter_param.bound_preserving_limiter != limiter_enum::positivity_preservingWang2012) {
161  if (qty < 0.0) {
162  // Refer to base class for non-physical results handling
163  qty = this->template handle_non_physical_result<real2>(qty_name + " is negative.");
164  qty_is_positive = false;
165  }
166  else {
167  qty_is_positive = true;
168  }
169  } else {
170  qty_is_positive = true;
171  }
172  return qty_is_positive;
173 }
174 
175 template <int dim, int nspecies, int nstate, typename real>
176 template<typename real2>
177 inline std::array<real2,nstate> Euler<dim,nspecies,nstate,real>
178 ::convert_conservative_to_primitive_templated ( const std::array<real2,nstate> &conservative_soln ) const
179 {
180  std::array<real2, nstate> primitive_soln;
181 
182  real2 density = conservative_soln[0];
183  dealii::Tensor<1,dim,real2> vel = compute_velocities<real2>(conservative_soln);
184  real2 pressure = compute_pressure_templated<real2>(conservative_soln);
185 
186  check_positive_quantity<real2>(density, "density");
187  check_positive_quantity<real2>(pressure, "pressure");
188  primitive_soln[0] = density;
189  for (int d=0; d<dim; ++d) {
190  primitive_soln[1+d] = vel[d];
191  }
192  primitive_soln[nstate-1] = pressure;
193 
194  return primitive_soln;
195 }
196 
197 template <int dim, int nspecies, int nstate, typename real>
198 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
199 ::convert_conservative_to_primitive ( const std::array<real,nstate> &conservative_soln ) const
200 {
201  return convert_conservative_to_primitive_templated<real>(conservative_soln);
202 }
203 
204 template <int dim, int nspecies, int nstate, typename real>
205 inline std::array<real,nstate> Euler<dim,nspecies,nstate,real>
206 ::convert_primitive_to_conservative ( const std::array<real,nstate> &primitive_soln ) const
207 {
208 
209  const real density = primitive_soln[0];
210  const dealii::Tensor<1,dim,real> velocities = extract_velocities_from_primitive<real>(primitive_soln);
211 
212  std::array<real, nstate> conservative_soln;
213  conservative_soln[0] = density;
214  for (int d=0; d<dim; ++d) {
215  conservative_soln[1+d] = density*velocities[d];
216  }
217  conservative_soln[nstate-1] = compute_total_energy(primitive_soln);
218 
219  return conservative_soln;
220 }
221 
222 template <int dim, int nspecies, int nstate, typename real>
223 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
225  const std::array<real,nstate> &primitive_soln,
226  const std::array<dealii::Tensor<1,dim,real>,nstate> &primitive_soln_gradient) const
227 {
228  std::array<dealii::Tensor<1,dim,real>,nstate> conservative_soln_gradient;
229 
230  // get conservative solution
231  const std::array<real,nstate> conservative_soln = convert_primitive_to_conservative(primitive_soln);
232  // extract from primitive solution
233  const real density = primitive_soln[0];
234  const dealii::Tensor<1,dim,real> vel = extract_velocities_from_primitive<real>(primitive_soln);
235 
236  // density gradient
237  for (int d=0; d<dim; d++) {
238  conservative_soln_gradient[0][d] = primitive_soln_gradient[0][d];
239  }
240  // momentum components gradient
241  for (int d1=0; d1<dim; d1++) {
242  for (int d2=0; d2<dim; d2++) {
243  conservative_soln_gradient[1+d1][d2] = density*primitive_soln_gradient[1+d1][d2] + vel[d1]*conservative_soln_gradient[0][d2];
244  }
245  }
246  // total energy gradient
247  for (int d1=0; d1<dim; d1++) {
248  conservative_soln_gradient[nstate-1][d1] = primitive_soln_gradient[nstate-1][d1];
249  conservative_soln_gradient[nstate-1][d1] /= this->gamm1;
250  for (int d2=0; d2<dim; d2++) {
251  conservative_soln_gradient[nstate-1][d1] += 0.5*(primitive_soln[1+d2]*conservative_soln_gradient[1+d2][d1]
252  + conservative_soln[1+d2]*primitive_soln_gradient[1+d2][d1]);
253  }
254  }
255  return conservative_soln_gradient;
256 }
257 
258 template <int dim, int nspecies, int nstate, typename real>
259 template<typename real2>
260 std::array<dealii::Tensor<1,dim,real2>,nstate> Euler<dim,nspecies,nstate,real>
262  const std::array<real2,nstate> &conservative_soln,
263  const std::array<dealii::Tensor<1,dim,real2>,nstate> &conservative_soln_gradient) const
264 {
265  std::array<dealii::Tensor<1,dim,real2>,nstate> primitive_soln_gradient;
266 
267  // get primitive solution
268  const std::array<real2,nstate> primitive_soln = convert_conservative_to_primitive_templated<real2>(conservative_soln);
269  // extract from primitive solution
270  const real2 density = primitive_soln[0];
271  const dealii::Tensor<1,dim,real2> vel = extract_velocities_from_primitive<real2>(primitive_soln);
272 
273  // density gradient
274  for (int d=0; d<dim; d++) {
275  primitive_soln_gradient[0][d] = conservative_soln_gradient[0][d];
276  }
277  // velocities gradient
278  for (int d1=0; d1<dim; d1++) {
279  for (int d2=0; d2<dim; d2++) {
280  primitive_soln_gradient[1+d1][d2] = (conservative_soln_gradient[1+d1][d2] - vel[d1]*conservative_soln_gradient[0][d2])/density;
281  }
282  }
283  // pressure gradient
284  // -- formulation 1:
285  // const real2 vel2 = this->template compute_velocity_squared<real2>(vel); // from Euler
286  // for (int d1=0; d1<dim; d1++) {
287  // primitive_soln_gradient[nstate-1][d1] = conservative_soln_gradient[nstate-1][d1] - 0.5*vel2*conservative_soln_gradient[0][d1];
288  // for (int d2=0; d2<dim; d2++) {
289  // primitive_soln_gradient[nstate-1][d1] -= conservative_soln[1+d2]*primitive_soln_gradient[1+d2][d1];
290  // }
291  // primitive_soln_gradient[nstate-1][d1] *= this->gamm1;
292  // }
293  // -- formulation 2 (equivalent to formulation 1):
294  for (int d1=0; d1<dim; d1++) {
295  primitive_soln_gradient[nstate-1][d1] = conservative_soln_gradient[nstate-1][d1];
296  for (int d2=0; d2<dim; d2++) {
297  primitive_soln_gradient[nstate-1][d1] -= 0.5*(primitive_soln[1+d2]*conservative_soln_gradient[1+d2][d1]
298  + conservative_soln[1+d2]*primitive_soln_gradient[1+d2][d1]);
299  }
300  primitive_soln_gradient[nstate-1][d1] *= this->gamm1;
301  }
302  return primitive_soln_gradient;
303 }
304 
305 template <int dim, int nspecies, int nstate, typename real>
306 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
308  const std::array<real,nstate> &conservative_soln,
309  const std::array<dealii::Tensor<1,dim,real>,nstate> &conservative_soln_gradient) const
310 {
311  return convert_conservative_gradient_to_primitive_gradient_templated<real>(conservative_soln,conservative_soln_gradient);
312 }
313 
314 template <int dim, int nspecies, int nstate, typename real>
316 ::compute_gamma ( const std::array<real,nstate> &/*conservative_soln*/ ) const
317 {
318  return this->gam;
319 }
320 
321 //template <int dim, int nstate, typename real>
322 //inline dealii::Tensor<1,dim,double> Euler<dim,nstate,real>::compute_velocities_inf() const
323 //{
324 // dealii::Tensor<1,dim,double> velocities;
325 // return velocities;
326 //}
327 
328 template <int dim, int nspecies, int nstate, typename real>
329 template<typename real2>
330 inline dealii::Tensor<1,dim,real2> Euler<dim,nspecies,nstate,real>
331 ::compute_velocities ( const std::array<real2,nstate> &conservative_soln ) const
332 {
333  const real2 density = conservative_soln[0];
334  dealii::Tensor<1,dim,real2> vel;
335  for (int d=0; d<dim; ++d) { vel[d] = conservative_soln[1+d]/density; }
336  return vel;
337 }
338 
339 template <int dim, int nspecies, int nstate, typename real>
340 template <typename real2>
342 ::compute_velocity_squared ( const dealii::Tensor<1,dim,real2> &velocities ) const
343 {
344  real2 vel2 = 0.0;
345  for (int d=0; d<dim; d++) {
346  vel2 = vel2 + velocities[d]*velocities[d];
347  }
348 
349  return vel2;
350 }
351 
352 template <int dim, int nspecies, int nstate, typename real>
353 template<typename real2>
354 inline dealii::Tensor<1,dim,real2> Euler<dim,nspecies,nstate,real>
355 ::extract_velocities_from_primitive ( const std::array<real2,nstate> &primitive_soln ) const
356 {
357  dealii::Tensor<1,dim,real2> velocities;
358  for (int d=0; d<dim; d++) { velocities[d] = primitive_soln[1+d]; }
359  return velocities;
360 }
361 
362 template <int dim, int nspecies, int nstate, typename real>
364 ::compute_total_energy ( const std::array<real,nstate> &primitive_soln ) const
365 {
366  const real pressure = primitive_soln[nstate-1];
367  const real kinetic_energy = compute_kinetic_energy_from_primitive_solution(primitive_soln);
368  const real tot_energy = pressure / this->gamm1 + kinetic_energy;
369  return tot_energy;
370 }
371 
372 template <int dim, int nspecies, int nstate, typename real>
374 ::compute_kinetic_energy_from_primitive_solution ( const std::array<real,nstate> &primitive_soln ) const
375 {
376  const real density = primitive_soln[0];
377  const dealii::Tensor<1,dim,real> velocities = extract_velocities_from_primitive<real>(primitive_soln);
378  const real vel2 = compute_velocity_squared<real>(velocities);
379  const real kinetic_energy = 0.5*density*vel2;
380  return kinetic_energy;
381 }
382 
383 template <int dim, int nspecies, int nstate, typename real>
385 ::compute_incompressible_kinetic_energy_from_primitive_solution ( const std::array<real,nstate> &primitive_soln ) const
386 {
387  const dealii::Tensor<1,dim,real> velocities = extract_velocities_from_primitive<real>(primitive_soln);
388  const real vel2 = compute_velocity_squared<real>(velocities);
389  const real kinetic_energy = 0.5*vel2;
390  return kinetic_energy;
391 }
392 
393 template <int dim, int nspecies, int nstate, typename real>
395 ::compute_kinetic_energy_from_conservative_solution ( const std::array<real,nstate> &conservative_soln ) const
396 {
397  const std::array<real,nstate> primitive_soln = convert_conservative_to_primitive_templated<real>(conservative_soln);
398  const real kinetic_energy = compute_kinetic_energy_from_primitive_solution(primitive_soln);
399  return kinetic_energy;
400 }
401 
402 template <int dim, int nspecies, int nstate, typename real>
404 ::compute_incompressible_kinetic_energy_from_conservative_solution ( const std::array<real,nstate> &conservative_soln ) const
405 {
406  const std::array<real,nstate> primitive_soln = convert_conservative_to_primitive_templated<real>(conservative_soln);
407  const real kinetic_energy = compute_incompressible_kinetic_energy_from_primitive_solution(primitive_soln);
408  return kinetic_energy;
409 }
410 
411 template <int dim, int nspecies, int nstate, typename real>
413 ::compute_entropy_measure ( const std::array<real,nstate> &conservative_soln ) const
414 {
415  real density = conservative_soln[0];
416  const real pressure = compute_pressure_templated<real>(conservative_soln);
417  return compute_entropy_measure(density, pressure);
418 }
419 
420 template <int dim, int nspecies, int nstate, typename real>
422 ::compute_entropy_measure ( const real density, const real pressure ) const
423 {
424  //Copy such that we don't modify the original density that is passed
425  real density_check = density;
426  const bool density_is_positive = check_positive_quantity<real>(density_check, "density");
427  if (density_is_positive) return pressure*pow(density,-gam);
428  else return (real)this->BIG_NUMBER;
429 }
430 
431 
432 template <int dim, int nspecies, int nstate, typename real>
434 ::compute_specific_enthalpy ( const std::array<real,nstate> &conservative_soln, const real pressure ) const
435 {
436  const real density = conservative_soln[0];
437  const real total_energy = conservative_soln[nstate-1];
438  const real specific_enthalpy = (total_energy+pressure)/density;
439  return specific_enthalpy;
440 }
441 
442 template <int dim, int nspecies, int nstate, typename real>
444 ::compute_numerical_entropy_function ( const std::array<real,nstate> &conservative_soln ) const
445 {
446  const real density = conservative_soln[0];
447 
448  const real entropy = compute_entropy_templated<real>(conservative_soln);
449 
450  const real numerical_entropy_function = - density * entropy;
451 
452  return numerical_entropy_function;
453 }
454 
455 template <int dim, int nspecies, int nstate, typename real>
456 template<typename real2>
458 ::compute_temperature ( const std::array<real2,nstate> &primitive_soln ) const
459 {
460  const real2 density = primitive_soln[0];
461  const real2 pressure = primitive_soln[nstate-1];
462  const real2 temperature = gam*mach_inf_sqr*(pressure/density);
463  return temperature;
464 }
465 
466 template <int dim, int nspecies, int nstate, typename real>
468 ::compute_density_from_pressure_temperature ( const real pressure, const real temperature ) const
469 {
470  const real density = gam*mach_inf_sqr*(pressure/temperature);
471  return density;
472 }
473 
474 template <int dim, int nspecies, int nstate, typename real>
476 ::compute_temperature_from_density_pressure ( const real density, const real pressure ) const
477 {
478  const real temperature = gam*mach_inf_sqr*(pressure/density);
479  return temperature;
480 }
481 
482 template <int dim, int nspecies, int nstate, typename real>
484 ::compute_pressure_from_density_temperature ( const real density, const real temperature ) const
485 {
486  const real pressure = density*temperature/(gam*mach_inf_sqr);
487  return pressure;
488 }
489 
490 template <int dim, int nspecies, int nstate, typename real>
491 template<typename real2>
493 ::compute_pressure_templated ( const std::array<real2,nstate> &conservative_soln ) const
494 {
495  const real2 density = conservative_soln[0];
496 
497  const real2 tot_energy = conservative_soln[nstate-1];
498 
499  const dealii::Tensor<1,dim,real2> vel = compute_velocities<real2>(conservative_soln);
500 
501  const real2 vel2 = compute_velocity_squared<real2>(vel);
502  real2 pressure = gamm1*(tot_energy - 0.5*density*vel2);
503 
504  check_positive_quantity<real2>(pressure, "pressure");
505  return pressure;
506 }
507 
508 template <int dim, int nspecies, int nstate, typename real>
510 ::compute_pressure ( const std::array<real,nstate> &conservative_soln ) const
511 {
512  return compute_pressure_templated<real>(conservative_soln);
513 }
514 
515 template <int dim, int nspecies, int nstate, typename real>
516 template<typename real2>
518 ::compute_entropy_templated ( const std::array<real2,nstate> &conservative_soln ) const
519 {
520  real2 density = conservative_soln[0];
521  real2 pressure = compute_pressure_templated<real2>(conservative_soln);
522  const bool density_is_positive = check_positive_quantity(density, "density");
523  const bool pressure_is_positive = check_positive_quantity(pressure, "pressure");
524  if (density_is_positive && pressure_is_positive) {
525  real2 entropy = pressure * pow(density, -gam);
526  entropy = log(entropy);
527  return entropy;
528  } else {
529  this->pcout << "WARNING: Entropy is not defined because " << std::endl
530  << " pressure * pow(density, -gam) < 0 ." << std::endl
531  << " Setting entropy = BIG_NUMBER." << std::endl;
532  this->pcout << "Aborting..." << std::endl;
533  std::abort();
534  return (real2)this->BIG_NUMBER;
535  }
536 
537 }
538 
539 template <int dim, int nspecies, int nstate, typename real>
541 ::compute_entropy ( const std::array<real,nstate> &conservative_soln ) const
542 {
543  return compute_entropy_templated<real>(conservative_soln);
544 }
545 
546 template <int dim, int nspecies, int nstate, typename real>
548 ::compute_sound ( const std::array<real,nstate> &conservative_soln ) const
549 {
550  real density = conservative_soln[0];
551  check_positive_quantity<real>(density, "density");
552  const real pressure = compute_pressure_templated<real>(conservative_soln);
553  const real sound = sqrt(pressure*gam/density);
554  return sound;
555 }
556 
557 template <int dim, int nspecies, int nstate, typename real>
559 ::compute_sound ( const real density, const real pressure ) const
560 {
561  //assert(density > 0);
562  const real sound = sqrt(pressure*gam/density);
563  return sound;
564 }
565 
566 template <int dim, int nspecies, int nstate, typename real>
568 ::compute_mach_number ( const std::array<real,nstate> &conservative_soln ) const
569 {
570  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
571  const real velocity = sqrt(compute_velocity_squared<real>(vel));
572  const real sound = compute_sound (conservative_soln);
573  const real mach_number = velocity/sound;
574  return mach_number;
575 }
576 
577 // Split form functions:
578 
579 template <int dim, int nspecies, int nstate, typename real>
580 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim, nspecies, nstate, real>
581 ::convective_numerical_split_flux(const std::array<real,nstate> &conservative_soln1,
582  const std::array<real,nstate> &conservative_soln2) const
583 {
584  std::array<dealii::Tensor<1,dim,real>,nstate> conv_num_split_flux;
585  if(two_point_num_flux_type == two_point_num_flux_enum::KG) {
586  conv_num_split_flux = convective_numerical_split_flux_kennedy_gruber(conservative_soln1, conservative_soln2);
587  } else if(two_point_num_flux_type == two_point_num_flux_enum::IR) {
588  conv_num_split_flux = convective_numerical_split_flux_ismail_roe(conservative_soln1, conservative_soln2);
589  } else if(two_point_num_flux_type == two_point_num_flux_enum::CH) {
590  conv_num_split_flux = convective_numerical_split_flux_chandrashekar(conservative_soln1, conservative_soln2);
591  } else if(two_point_num_flux_type == two_point_num_flux_enum::Ra) {
592  conv_num_split_flux = convective_numerical_split_flux_ranocha(conservative_soln1, conservative_soln2);
593  }
594 
595  return conv_num_split_flux;
596 }
597 
598 template <int dim, int nspecies, int nstate, typename real>
599 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim, nspecies, nstate, real>
600 ::convective_numerical_split_flux_kennedy_gruber(const std::array<real,nstate> &conservative_soln1,
601  const std::array<real,nstate> &conservative_soln2) const
602 {
603  std::array<dealii::Tensor<1,dim,real>,nstate> conv_num_split_flux;
604  const real mean_density = compute_mean_density(conservative_soln1, conservative_soln2);
605  const real mean_pressure = compute_mean_pressure(conservative_soln1, conservative_soln2);
606  const dealii::Tensor<1,dim,real> mean_velocities = compute_mean_velocities(conservative_soln1,conservative_soln2);
607  const real mean_specific_total_energy = compute_mean_specific_total_energy(conservative_soln1, conservative_soln2);
608 
609  for (int flux_dim = 0; flux_dim < dim; ++flux_dim)
610  {
611  // Density equation
612  conv_num_split_flux[0][flux_dim] = mean_density * mean_velocities[flux_dim];
613  // Momentum equation
614  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
615  conv_num_split_flux[1+velocity_dim][flux_dim] = mean_density*mean_velocities[flux_dim]*mean_velocities[velocity_dim];
616  }
617  conv_num_split_flux[1+flux_dim][flux_dim] += mean_pressure; // Add diagonal of pressure
618  // Energy equation
619  conv_num_split_flux[nstate-1][flux_dim] = mean_density*mean_velocities[flux_dim]*mean_specific_total_energy + mean_pressure * mean_velocities[flux_dim];
620  }
621 
622  return conv_num_split_flux;
623 }
624 
625 template <int dim, int nspecies, int nstate, typename real>
626 std::array<real,nstate> Euler<dim, nspecies, nstate, real>
627 ::compute_ismail_roe_parameter_vector_from_primitive(const std::array<real,nstate> &primitive_soln) const
628 {
629  // Ismail-Roe parameter vector; Eq (3.14) [Gassner, Winters, and Kopriva, 2016, SBP]
630  std::array<real,nstate> ismail_roe_parameter_vector;
631  ismail_roe_parameter_vector[0] = sqrt(primitive_soln[0]/primitive_soln[nstate-1]);
632  for(int d=0; d<dim; ++d){
633  ismail_roe_parameter_vector[1+d] = ismail_roe_parameter_vector[0]*primitive_soln[1+d];
634  }
635  ismail_roe_parameter_vector[nstate-1] = sqrt(primitive_soln[0]*primitive_soln[nstate-1]);
636 
637  return ismail_roe_parameter_vector;
638 }
639 
640 template <int dim, int nspecies, int nstate, typename real>
642 ::compute_ismail_roe_logarithmic_mean(const real val1, const real val2) const
643 {
644  // See Appendix B [Ismail and Roe, 2009, Entropy-Consistent Euler Flux Functions II]
645  // -- Numerically stable algorithm for computing the logarithmic mean
646  const real zeta = val1/val2;
647  const real f = (zeta-1.0)/(zeta+1.0);
648  const real u = f*f;
649 
650  real F;
651  if(u<1.0e-2){ F = 1.0 + u/3.0 + u*u/5.0 + u*u*u/7.0; }
652  else {
653  F = log(zeta)/2.0/f;
654  }
655 
656  const real log_mean_val = (val1+val2)/(2.0*F);
657 
658  return log_mean_val;
659 }
660 
661 template <int dim, int nspecies, int nstate, typename real>
662 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim, nspecies, nstate, real>
663 ::convective_numerical_split_flux_ismail_roe(const std::array<real,nstate> &conservative_soln1,
664  const std::array<real,nstate> &conservative_soln2) const
665 {
666  // Get Ismail Roe parameter vectors
667  const std::array<real,nstate> parameter_vector1 = compute_ismail_roe_parameter_vector_from_primitive(
668  convert_conservative_to_primitive_templated<real>(conservative_soln1));
669  const std::array<real,nstate> parameter_vector2 = compute_ismail_roe_parameter_vector_from_primitive(
670  convert_conservative_to_primitive_templated<real>(conservative_soln2));
671 
672  // Compute mean (average) parameter vector
673  std::array<real,nstate> avg_parameter_vector;
674  for(int s=0; s<nstate; ++s){
675  avg_parameter_vector[s] = 0.5*(parameter_vector1[s] + parameter_vector2[s]);
676  }
677 
678  // Compute logarithmic mean parameter vector
679  std::array<real,nstate> log_mean_parameter_vector;
680  for(int s=0; s<nstate; ++s){
681  log_mean_parameter_vector[s] = compute_ismail_roe_logarithmic_mean(parameter_vector1[s], parameter_vector2[s]);
682  }
683 
684  // Compute Ismail Roe mean primitive variables; Eq (3.15) [Gassner, Winters, and Kopriva, 2016, SBP]
685  std::array<real,dim> mean_velocities;
686  const real mean_density = avg_parameter_vector[0]*log_mean_parameter_vector[nstate-1];
687  for(int d=0; d<dim; ++d){
688  mean_velocities[d] = avg_parameter_vector[1+d]/avg_parameter_vector[0];
689  }
690  const real mean_pressure = avg_parameter_vector[nstate-1]/avg_parameter_vector[0];
691  // -- enthalpy
692  real mean_enthalpy = (gam+1.0)*(log_mean_parameter_vector[nstate-1]/log_mean_parameter_vector[0]) + gamm1*mean_pressure;
693  mean_enthalpy /= 2.0*gam;
694  mean_enthalpy *= gam/(mean_density*gamm1);
695  // -- get sum of mean velocities squared
696  real mean_velocities_sqr_sum = 0.0;
697  for(int d=0; d<dim; ++d){
698  mean_velocities_sqr_sum += mean_velocities[d]*mean_velocities[d];
699  }
700  // -- add to enthalpy
701  mean_enthalpy += 0.5*mean_velocities_sqr_sum;
702 
703  // Compute Ismail Roe convective numerical split flux
704  std::array<dealii::Tensor<1,dim,real>,nstate> conv_num_split_flux;
705  for (int flux_dim = 0; flux_dim < dim; ++flux_dim)
706  {
707  // Density equation
708  conv_num_split_flux[0][flux_dim] = mean_density * mean_velocities[flux_dim];
709  // Momentum equation
710  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
711  conv_num_split_flux[1+velocity_dim][flux_dim] = mean_density*mean_velocities[flux_dim]*mean_velocities[velocity_dim];
712  }
713  conv_num_split_flux[1+flux_dim][flux_dim] += mean_pressure; // Add diagonal of pressure
714  // Energy equation
715  conv_num_split_flux[nstate-1][flux_dim] = mean_density*mean_velocities[flux_dim]*mean_enthalpy;
716  }
717 
718  return conv_num_split_flux;
719 }
720 
721 template <int dim, int nspecies, int nstate, typename real>
722 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim, nspecies, nstate, real>
723 ::convective_numerical_split_flux_chandrashekar(const std::array<real,nstate> &conservative_soln1,
724  const std::array<real,nstate> &conservative_soln2) const
725 {
726 
727  std::array<dealii::Tensor<1,dim,real>,nstate> conv_num_split_flux;
728  const real rho_log = compute_ismail_roe_logarithmic_mean(conservative_soln1[0], conservative_soln2[0]);
729  const real pressure1 = compute_pressure_templated<real>(conservative_soln1);
730  const real pressure2 = compute_pressure_templated<real>(conservative_soln2);
731 
732  const real beta1 = conservative_soln1[0]/(2.0*pressure1);
733  const real beta2 = conservative_soln2[0]/(2.0*pressure2);
734 
735  const real beta_log = compute_ismail_roe_logarithmic_mean(beta1, beta2);
736  const dealii::Tensor<1,dim,real> vel1 = compute_velocities<real>(conservative_soln1);
737  const dealii::Tensor<1,dim,real> vel2 = compute_velocities<real>(conservative_soln2);
738 
739  const real pressure_hat = 0.5*(conservative_soln1[0] + conservative_soln2[0])/(2.0*0.5*(beta1+beta2));
740 
741  dealii::Tensor<1,dim,real> vel_avg;
742  real vel_square_avg = 0.0;;
743  for(int idim=0; idim<dim; idim++){
744  vel_avg[idim] = 0.5*(vel1[idim]+vel2[idim]);
745  vel_square_avg += (0.5 *(vel1[idim]+vel2[idim])) * (0.5 *(vel1[idim]+vel2[idim]));
746  }
747 
748  real enthalpy_hat = 1.0/(2.0*beta_log*gamm1) + vel_square_avg + pressure_hat/rho_log;
749 
750  for(int idim=0; idim<dim; idim++){
751  enthalpy_hat -= 0.5*(0.5*(vel1[idim]*vel1[idim] + vel2[idim]*vel2[idim]));
752  }
753 
754  for(int flux_dim=0; flux_dim<dim; flux_dim++){
755  // Density equation
756  conv_num_split_flux[0][flux_dim] = rho_log * vel_avg[flux_dim];
757  // Momentum equation
758  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
759  conv_num_split_flux[1+velocity_dim][flux_dim] = rho_log*vel_avg[flux_dim]*vel_avg[velocity_dim];
760  }
761  conv_num_split_flux[1+flux_dim][flux_dim] += pressure_hat; // Add diagonal of pressure
762 
763  // Energy equation
764  conv_num_split_flux[nstate-1][flux_dim] = rho_log * vel_avg[flux_dim] * enthalpy_hat;
765  }
766 
767  return conv_num_split_flux;
768 }
769 
770 template <int dim, int nspecies, int nstate, typename real>
771 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim, nspecies, nstate, real>
772 ::convective_numerical_split_flux_ranocha(const std::array<real,nstate> &conservative_soln1,
773  const std::array<real,nstate> &conservative_soln2) const
774 {
775 
776  std::array<dealii::Tensor<1,dim,real>,nstate> conv_num_split_flux;
777  const real rho_log = compute_ismail_roe_logarithmic_mean(conservative_soln1[0], conservative_soln2[0]);
778  const real pressure1 = compute_pressure_templated<real>(conservative_soln1);
779  const real pressure2 = compute_pressure_templated<real>(conservative_soln2);
780 
781  const real beta1 = conservative_soln1[0]/(pressure1);
782  const real beta2 = conservative_soln2[0]/(pressure2);
783 
784  const real beta_log = compute_ismail_roe_logarithmic_mean(beta1, beta2);
785  const dealii::Tensor<1,dim,real> vel1 = compute_velocities<real>(conservative_soln1);
786  const dealii::Tensor<1,dim,real> vel2 = compute_velocities<real>(conservative_soln2);
787 
788  const real pressure_hat = 0.5*(pressure1+pressure2);
789 
790  dealii::Tensor<1,dim,real> vel_avg;
791  real vel_square_avg = 0.0;;
792  for(int idim=0; idim<dim; idim++){
793  vel_avg[idim] = 0.5*(vel1[idim]+vel2[idim]);
794  vel_square_avg += (0.5 *(vel1[idim]+vel2[idim])) * (0.5 *(vel1[idim]+vel2[idim]));
795  }
796 
797  real enthalpy_hat = 1.0/(beta_log*gamm1) + vel_square_avg + 2.0*pressure_hat/rho_log;
798 
799  for(int idim=0; idim<dim; idim++){
800  enthalpy_hat -= 0.5*(0.5*(vel1[idim]*vel1[idim] + vel2[idim]*vel2[idim]));
801  }
802 
803  for(int flux_dim=0; flux_dim<dim; flux_dim++){
804  // Density equation
805  conv_num_split_flux[0][flux_dim] = rho_log * vel_avg[flux_dim];
806  // Momentum equation
807  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
808  conv_num_split_flux[1+velocity_dim][flux_dim] = rho_log*vel_avg[flux_dim]*vel_avg[velocity_dim];
809  }
810  conv_num_split_flux[1+flux_dim][flux_dim] += pressure_hat; // Add diagonal of pressure
811 
812  // Energy equation
813  conv_num_split_flux[nstate-1][flux_dim] = rho_log * vel_avg[flux_dim] * enthalpy_hat;
814  conv_num_split_flux[nstate-1][flux_dim] -= ( 0.5 *(pressure1*vel1[flux_dim] + pressure2*vel2[flux_dim]));
815  }
816 
817  return conv_num_split_flux;
818 
819 }
820 
821 template <int dim, int nspecies, int nstate, typename real>
822 std::array<real,nstate> Euler<dim, nspecies, nstate, real>
824  const std::array<real,nstate> &conservative_soln) const
825 {
826  std::array<real,nstate> entropy_var;
827  const real density = conservative_soln[0];
828  const real pressure = compute_pressure_templated<real>(conservative_soln);
829 
830  const real entropy = compute_entropy_templated<real>(conservative_soln);
831 
832  const real rho_theta = pressure / gamm1;
833 
834  entropy_var[0] = (rho_theta *(gam + 1.0 - entropy) - conservative_soln[nstate-1])/rho_theta;
835  for(int idim=0; idim<dim; idim++){
836  entropy_var[idim+1] = conservative_soln[idim+1] / rho_theta;
837  }
838  entropy_var[nstate-1] = - density / rho_theta;
839 
840  return entropy_var;
841 }
842 
843 template <int dim, int nspecies, int nstate, typename real>
844 std::array<real,nstate> Euler<dim, nspecies, nstate, real>
846  const std::array<real,nstate> &entropy_var) const
847 {
848  //Eq. 119 and 120 from Chan, Jesse. "On discretely entropy conservative and entropy stable discontinuous Galerkin methods." Journal of Computational Physics 362 (2018): 346-374.
849  //Extrapolated for 3D
850  std::array<real,nstate> conservative_var;
851  real entropy_var_vel_squared = 0.0;
852  for(int idim=0; idim<dim; idim++){
853  entropy_var_vel_squared += entropy_var[idim + 1] * entropy_var[idim + 1];
854  }
855  const real entropy = gam - entropy_var[0] + 0.5 * entropy_var_vel_squared / entropy_var[nstate-1];
856  const real rho_theta = pow( (gamm1/ pow(- entropy_var[nstate-1], gam)), 1.0 /gamm1)
857  * exp( - entropy / gamm1);
858 
859  conservative_var[0] = - rho_theta * entropy_var[nstate-1];
860  for(int idim=0; idim<dim; idim++){
861  conservative_var[idim+1] = rho_theta * entropy_var[idim+1];
862  }
863  conservative_var[nstate-1] = rho_theta * (1.0 - 0.5 * entropy_var_vel_squared / entropy_var[nstate-1]);
864  return conservative_var;
865 }
866 
867 template <int dim, int nspecies, int nstate, typename real>
868 std::array<real,nstate> Euler<dim, nspecies, nstate, real>
870  const std::array<real,nstate> &conservative_soln) const
871 {
872  std::array<real,nstate> kin_energy_var;
873  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
874  const real vel2 = compute_velocity_squared<real>(vel);
875 
876  kin_energy_var[0] = - 0.5 * vel2;
877  for(int idim=0; idim<dim; idim++){
878  kin_energy_var[idim+1] = vel[idim];
879  }
880  kin_energy_var[nstate-1] = 0;
881 
882  return kin_energy_var;
883 }
884 
885 template <int dim, int nspecies, int nstate, typename real>
887 compute_mean_density(const std::array<real,nstate> &conservative_soln1,
888  const std::array<real,nstate> &conservative_soln2) const
889 {
890  return (conservative_soln1[0] + conservative_soln2[0])/2.;
891 }
892 
893 template <int dim, int nspecies, int nstate, typename real>
895 compute_mean_pressure(const std::array<real,nstate> &conservative_soln1,
896  const std::array<real,nstate> &conservative_soln2) const
897 {
898  real pressure_1 = compute_pressure_templated<real>(conservative_soln1);
899  real pressure_2 = compute_pressure_templated<real>(conservative_soln2);
900  return (pressure_1 + pressure_2)/2.;
901 }
902 
903 template <int dim, int nspecies, int nstate, typename real>
904 inline dealii::Tensor<1,dim,real> Euler<dim,nspecies,nstate,real>::
905 compute_mean_velocities(const std::array<real,nstate> &conservative_soln1,
906  const std::array<real,nstate> &conservative_soln2) const
907 {
908  dealii::Tensor<1,dim,real> vel_1 = compute_velocities<real>(conservative_soln1);
909  dealii::Tensor<1,dim,real> vel_2 = compute_velocities<real>(conservative_soln2);
910  dealii::Tensor<1,dim,real> mean_vel;
911  for (int d=0; d<dim; ++d) {
912  mean_vel[d] = 0.5*(vel_1[d]+vel_2[d]);
913  }
914  return mean_vel;
915 }
916 
917 template <int dim, int nspecies, int nstate, typename real>
919 compute_mean_specific_total_energy(const std::array<real,nstate> &conservative_soln1,
920  const std::array<real,nstate> &conservative_soln2) const
921 {
922  return ((conservative_soln1[nstate-1]/conservative_soln1[0]) + (conservative_soln2[nstate-1]/conservative_soln2[0]))/2.;
923 }
924 
925 
926 template <int dim, int nspecies, int nstate, typename real>
927 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
928 ::convective_flux (const std::array<real,nstate> &conservative_soln) const
929 {
930  std::array<dealii::Tensor<1,dim,real>,nstate> conv_flux;
931  const real density = conservative_soln[0];
932  const real pressure = compute_pressure_templated<real>(conservative_soln);
933  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
934  const real specific_total_energy = conservative_soln[nstate-1]/conservative_soln[0];
935  const real specific_total_enthalpy = specific_total_energy + pressure/density;
936 
937  for (int flux_dim=0; flux_dim<dim; ++flux_dim) {
938  // Density equation
939  conv_flux[0][flux_dim] = conservative_soln[1+flux_dim];
940  // Momentum equation
941  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
942  conv_flux[1+velocity_dim][flux_dim] = density*vel[flux_dim]*vel[velocity_dim];
943  }
944  conv_flux[1+flux_dim][flux_dim] += pressure; // Add diagonal of pressure
945  // Energy equation
946  conv_flux[nstate-1][flux_dim] = density*vel[flux_dim]*specific_total_enthalpy;
947  }
948  return conv_flux;
949 }
950 
951 template <int dim, int nspecies, int nstate, typename real>
952 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
953 ::convective_normal_flux (const std::array<real,nstate> &conservative_soln, const dealii::Tensor<1,dim,real> &normal) const
954 {
955  std::array<real, nstate> conv_normal_flux;
956  const real density = conservative_soln[0];
957  const real pressure = compute_pressure_templated<real>(conservative_soln);
958  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
959  real normal_vel = 0.0;
960  for (int d=0; d<dim; ++d) {
961  normal_vel += vel[d]*normal[d];
962  }
963  const real total_energy = conservative_soln[nstate-1];
964  const real specific_total_enthalpy = (total_energy + pressure) / density;
965 
966  const real rhoV = density*normal_vel;
967  // Density equation
968  conv_normal_flux[0] = rhoV;
969  // Momentum equation
970  for (int velocity_dim=0; velocity_dim<dim; ++velocity_dim){
971  conv_normal_flux[1+velocity_dim] = rhoV*vel[velocity_dim] + normal[velocity_dim] * pressure;
972  }
973  // Energy equation
974  conv_normal_flux[nstate-1] = rhoV*specific_total_enthalpy;
975  return conv_normal_flux;
976 }
977 
978 template <int dim, int nspecies, int nstate, typename real>
979 dealii::Tensor<2,nstate,real> Euler<dim,nspecies,nstate,real>
981  const std::array<real,nstate> &conservative_soln,
982  const dealii::Tensor<1,dim,real> &normal) const
983 {
984  // See Blazek (year?) Appendix A.9 p. 429-430
985  // For Blazek (2001), see Appendix A.7 p. 419-420
986  // Alternatively, see Masatsuka 2018 "I do like CFD", p.77, eq.(3.6.8)
987  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
988  real vel_normal = 0.0;
989  for (int d=0;d<dim;d++) { vel_normal += vel[d] * normal[d]; }
990 
991  const real vel2 = compute_velocity_squared<real>(vel);
992  const real phi = 0.5*gamm1 * vel2;
993 
994  const real density = conservative_soln[0];
995  const real tot_energy = conservative_soln[nstate-1];
996  const real E = tot_energy / density;
997  const real a1 = gam*E-phi;
998  const real a2 = gam-1.0;
999  const real a3 = gam-2.0;
1000 
1001  dealii::Tensor<2,nstate,real> jacobian;
1002  for (int d=0; d<dim; ++d) {
1003  jacobian[0][1+d] = normal[d];
1004  }
1005  for (int row_dim=0; row_dim<dim; ++row_dim) {
1006  jacobian[1+row_dim][0] = normal[row_dim]*phi - vel[row_dim] * vel_normal;
1007  for (int col_dim=0; col_dim<dim; ++col_dim){
1008  if (row_dim == col_dim) {
1009  jacobian[1+row_dim][1+col_dim] = vel_normal - a3*normal[row_dim]*vel[row_dim];
1010  } else {
1011  jacobian[1+row_dim][1+col_dim] = normal[col_dim]*vel[row_dim] - a2*normal[row_dim]*vel[col_dim];
1012  }
1013  }
1014  jacobian[1+row_dim][nstate-1] = normal[row_dim]*a2;
1015  }
1016  jacobian[nstate-1][0] = vel_normal*(phi-a1);
1017  for (int d=0; d<dim; ++d){
1018  jacobian[nstate-1][1+d] = normal[d]*a1 - a2*vel[d]*vel_normal;
1019  }
1020  jacobian[nstate-1][nstate-1] = gam*vel_normal;
1021 
1022  return jacobian;
1023 }
1024 
1025 template <int dim, int nspecies, int nstate, typename real>
1026 std::array<real,nstate> Euler<dim,nspecies,nstate,real>
1028  const std::array<real,nstate> &conservative_soln,
1029  const dealii::Tensor<1,dim,real> &normal) const
1030 {
1031  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
1032  std::array<real,nstate> eig;
1033  real vel_dot_n = 0.0;
1034  for (int d=0;d<dim;++d) { vel_dot_n += vel[d]*normal[d]; };
1035  for (int i=0; i<nstate; i++) {
1036  eig[i] = vel_dot_n;
1037  //eig[i] = advection_speed*normal;
1038 
1039  //eig[i] = 1.0;
1040  //eig[i] = -1.0;
1041  }
1042  return eig;
1043 }
1044 
1045 template <int dim, int nspecies, int nstate, typename real>
1047 ::max_convective_eigenvalue (const std::array<real,nstate> &conservative_soln) const
1048 {
1049  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
1050 
1051  const real sound = compute_sound (conservative_soln);
1052 
1053  real vel2 = compute_velocity_squared<real>(vel);
1054 
1055  const real max_eig = sqrt(vel2) + sound;
1056 
1057  return max_eig;
1058 }
1059 
1060 template <int dim, int nspecies, int nstate, typename real>
1063  const std::array<real,nstate> &conservative_soln,
1064  const dealii::Tensor<1,dim,real> &normal) const
1065 {
1066  const dealii::Tensor<1,dim,real> vel = compute_velocities<real>(conservative_soln);
1067 
1068  const real sound = compute_sound (conservative_soln);
1069  real vel_dot_n = 0.0;
1070  for (int d=0;d<dim;++d) { vel_dot_n += vel[d]*normal[d]; };
1071  const real max_normal_eig = abs(vel_dot_n) + sound;
1072 
1073  return max_normal_eig;
1074 }
1075 
1076 template <int dim, int nspecies, int nstate, typename real>
1078 ::max_viscous_eigenvalue (const std::array<real,nstate> &/*conservative_soln*/) const
1079 {
1080  return 0.0;
1081 }
1082 
1083 template <int dim, int nspecies, int nstate, typename real>
1084 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
1086  const std::array<real,nstate> &conservative_soln,
1087  const std::array<dealii::Tensor<1,dim,real>,nstate> &solution_gradient,
1088  const dealii::types::global_dof_index /*cell_index*/) const
1089 {
1090  return dissipative_flux(conservative_soln, solution_gradient);
1091 }
1092 
1093 template <int dim, int nspecies, int nstate, typename real>
1094 std::array<dealii::Tensor<1,dim,real>,nstate> Euler<dim,nspecies,nstate,real>
1096  const std::array<real,nstate> &/*conservative_soln*/,
1097  const std::array<dealii::Tensor<1,dim,real>,nstate> &/*solution_gradient*/) const
1098 {
1099  std::array<dealii::Tensor<1,dim,real>,nstate> diss_flux;
1100  // No dissipation for Euler
1101  for (int i=0; i<nstate; i++) {
1102  diss_flux[i] = 0;
1103  }
1104  return diss_flux;
1105 }
1106 
1107 template <int dim, int nspecies, int nstate, typename real>
1110  const dealii::Tensor<1,dim,real> &normal_int,
1111  const std::array<real,nstate> &soln_int,
1112  std::array<real,nstate> &soln_bc) const
1113 {
1114  std::array<real,nstate> primitive_int = convert_conservative_to_primitive_templated<real>(soln_int);
1115  std::array<real,nstate> primitive_ext;
1116  primitive_ext[0] = density_inf;
1117  for (int d=0;d<dim;d++) { primitive_ext[1+d] = velocities_inf[d]; }
1118  primitive_ext[nstate-1] = pressure_inf;
1119 
1120  const dealii::Tensor<1,dim,real> velocities_int = extract_velocities_from_primitive<real>(primitive_int);
1121  const dealii::Tensor<1,dim,real> velocities_ext = extract_velocities_from_primitive<real>(primitive_ext);
1122 
1123  const real sound_int = compute_sound ( primitive_int[0], primitive_int[nstate-1] );
1124  const real sound_ext = compute_sound ( primitive_ext[0], primitive_ext[nstate-1] );
1125 
1126  real vel_int_dot_normal = 0.0;
1127  real vel_ext_dot_normal = 0.0;
1128  for (int d=0; d<dim; d++) {
1129  vel_int_dot_normal = vel_int_dot_normal + velocities_int[d]*normal_int[d];
1130  vel_ext_dot_normal = vel_ext_dot_normal + velocities_ext[d]*normal_int[d];
1131  }
1132 
1133  // Riemann invariants
1134  const real out_riemann_invariant = vel_int_dot_normal + 2.0/gamm1*sound_int, // Outgoing
1135  inc_riemann_invariant = vel_ext_dot_normal - 2.0/gamm1*sound_ext; // Incoming
1136 
1137  const real normal_velocity_bc = 0.5*(out_riemann_invariant+inc_riemann_invariant),
1138  sound_bc = 0.25*gamm1*(out_riemann_invariant-inc_riemann_invariant);
1139 
1140  std::array<real,nstate> primitive_bc;
1141  if (abs(normal_velocity_bc) >= abs(sound_bc)) { // Supersonic
1142  if (normal_velocity_bc < 0.0) { // Inlet
1143  primitive_bc = primitive_ext;
1144  } else { // Outlet
1145  primitive_bc = primitive_int;
1146  }
1147  } else { // Subsonic
1148 
1149  real density_bc;
1150  dealii::Tensor<1,dim,real> velocities_bc;
1151  real pressure_bc;
1152 
1153  dealii::Tensor<1,dim,real> velocities_tangential;
1154  if (normal_velocity_bc < 0.0) { // Inlet
1155  const real entropy_ext = compute_entropy_measure(primitive_ext[0], primitive_ext[nstate-1]);
1156  density_bc = pow( 1.0/gam * sound_bc * sound_bc / entropy_ext, 1.0/gamm1 );
1157  for (int d=0; d<dim; ++d) {
1158  velocities_tangential[d] = velocities_ext[d] - vel_ext_dot_normal * normal_int[d];
1159  }
1160  } else { // Outlet
1161  const real entropy_int = compute_entropy_measure(primitive_int[0], primitive_int[nstate-1]);
1162  density_bc = pow( 1.0/gam * sound_bc * sound_bc / entropy_int, 1.0/gamm1 );
1163  for (int d=0; d<dim; ++d) {
1164  velocities_tangential[d] = velocities_int[d] - vel_int_dot_normal * normal_int[d];
1165  }
1166  }
1167  for (int d=0; d<dim; ++d) {
1168  velocities_bc[d] = velocities_tangential[d] + normal_velocity_bc*normal_int[d];
1169  }
1170 
1171  pressure_bc = 1.0/gam * sound_bc * sound_bc * density_bc;
1172 
1173  primitive_bc[0] = density_bc;
1174  for (int d=0;d<dim;d++) { primitive_bc[1+d] = velocities_bc[d]; }
1175  primitive_bc[nstate-1] = pressure_bc;
1176  }
1177 
1178  soln_bc = convert_primitive_to_conservative(primitive_bc);
1179 }
1180 
1181 template <int dim, int nspecies, int nstate, typename real>
1184  const dealii::Tensor<1,dim,real> &normal_int,
1185  const std::array<real,nstate> &soln_int,
1186  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1187  std::array<real,nstate> &soln_bc,
1188  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1189 {
1190  // Slip wall boundary conditions (No penetration)
1191  // Given by Algorithm II of the following paper
1192  // Krivodonova, L., and Berger, M.,
1193  // “High-order accurate implementation of solid wall boundary conditions in curved geometries,”
1194  // Journal of Computational Physics, vol. 211, 2006, pp. 492–512.
1195  const std::array<real,nstate> primitive_interior_values = convert_conservative_to_primitive_templated<real>(soln_int);
1196 
1197  // Copy density and pressure
1198  std::array<real,nstate> primitive_boundary_values;
1199  primitive_boundary_values[0] = primitive_interior_values[0];
1200  primitive_boundary_values[nstate-1] = primitive_interior_values[nstate-1];
1201 
1202  const dealii::Tensor<1,dim,real> surface_normal = -normal_int;
1203  const dealii::Tensor<1,dim,real> velocities_int = extract_velocities_from_primitive<real>(primitive_interior_values);
1204  //const dealii::Tensor<1,dim,real> velocities_bc = velocities_int - 2.0*(velocities_int*surface_normal)*surface_normal;
1205  real vel_int_dot_normal = 0.0;
1206  for (int d=0; d<dim; d++) {
1207  vel_int_dot_normal = vel_int_dot_normal + velocities_int[d]*surface_normal[d];
1208  }
1209  dealii::Tensor<1,dim,real> velocities_bc;
1210  for (int d=0; d<dim; d++) {
1211  velocities_bc[d] = velocities_int[d] - 2.0*(vel_int_dot_normal)*surface_normal[d];
1212  //velocities_bc[d] = velocities_int[d] - (vel_int_dot_normal)*surface_normal[d];
1213  //velocities_bc[d] += velocities_int[d] * surface_normal.norm_square();
1214  }
1215  for (int d=0; d<dim; ++d) {
1216  primitive_boundary_values[1+d] = velocities_bc[d];
1217  }
1218 
1219  const std::array<real,nstate> modified_conservative_boundary_values = convert_primitive_to_conservative(primitive_boundary_values);
1220  for (int istate=0; istate<nstate; ++istate) {
1221  soln_bc[istate] = modified_conservative_boundary_values[istate];
1222  }
1223 
1224  for (int istate=0; istate<nstate; ++istate) {
1225  soln_grad_bc[istate] = -soln_grad_int[istate];
1226  }
1227 }
1228 
1229 template <int dim, int nspecies, int nstate, typename real>
1232  const dealii::Tensor<1,dim,real> &normal_int,
1233  const std::array<real,nstate> &soln_int,
1234  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1235  std::array<real,nstate> &soln_bc,
1236  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1237 {
1238  // Slip wall boundary for Euler
1239  boundary_slip_wall(normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1240 }
1241 
1242 template <int dim, int nspecies, int nstate, typename real>
1245  const dealii::Point<dim, real> &pos,
1246  const dealii::Tensor<1,dim,real> &normal_int,
1247  const std::array<real,nstate> &soln_int,
1248  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1249  std::array<real,nstate> &soln_bc,
1250  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1251 {
1252  // Manufactured solution
1253  std::array<real,nstate> conservative_boundary_values;
1254  std::array<dealii::Tensor<1,dim,real>,nstate> boundary_gradients;
1255  for (int s=0; s<nstate; s++) {
1256  conservative_boundary_values[s] = this->manufactured_solution_function->value (pos, s);
1257  boundary_gradients[s] = this->manufactured_solution_function->gradient (pos, s);
1258  }
1259  std::array<real,nstate> primitive_boundary_values = convert_conservative_to_primitive_templated<real>(conservative_boundary_values);
1260  for (int istate=0; istate<nstate; ++istate) {
1261 
1262  std::array<real,nstate> characteristic_dot_n = convective_eigenvalues(conservative_boundary_values, normal_int);
1263  const bool inflow = (characteristic_dot_n[istate] <= 0.);
1264 
1265  if (inflow) { // Dirichlet boundary condition
1266 
1267  soln_bc[istate] = conservative_boundary_values[istate];
1268  soln_grad_bc[istate] = soln_grad_int[istate];
1269 
1270  // Only set the pressure and velocity
1271  // primitive_boundary_values[0] = soln_int[0];;
1272  // for(int d=0;d<dim;d++){
1273  // primitive_boundary_values[1+d] = soln_int[1+d]/soln_int[0];;
1274  //}
1275  const std::array<real,nstate> modified_conservative_boundary_values = convert_primitive_to_conservative(primitive_boundary_values);
1276  (void) modified_conservative_boundary_values;
1277  //conservative_boundary_values[nstate-1] = soln_int[nstate-1];
1278  soln_bc[istate] = conservative_boundary_values[istate];
1279 
1280  } else { // Neumann boundary condition
1281  // soln_bc[istate] = -soln_int[istate]+2*conservative_boundary_values[istate];
1282  soln_bc[istate] = soln_int[istate];
1283 
1284  // **************************************************************************************************************
1285  // Note I don't know how to properly impose the soln_grad_bc to obtain an adjoint consistent scheme
1286  // Currently, Neumann boundary conditions are only imposed for the linear advection
1287  // Therefore, soln_grad_bc does not affect the solution
1288  // **************************************************************************************************************
1289  soln_grad_bc[istate] = soln_grad_int[istate];
1290  //soln_grad_bc[istate] = boundary_gradients[istate];
1291  //soln_grad_bc[istate] = -soln_grad_int[istate]+2*boundary_gradients[istate];
1292  }
1293 
1294  // HARDCODE DIRICHLET BC
1295  soln_bc[istate] = conservative_boundary_values[istate];
1296  }
1297 }
1298 
1299 template <int dim, int nspecies, int nstate, typename real>
1302  const real total_inlet_pressure,
1303  const real back_pressure,
1304  const std::array<real,nstate> &soln_int,
1305  std::array<real,nstate> &soln_bc) const
1306 {
1307  // Pressure Outflow Boundary Condition (back pressure)
1308  // Reference: Carlson 2011, sec. 2.4
1309 
1310  const real mach_int = compute_mach_number(soln_int);
1311  if (mach_int > 1.0) {
1312  // Supersonic, simply extrapolate
1313  for (int istate=0; istate<nstate; ++istate) {
1314  soln_bc[istate] = soln_int[istate];
1315  }
1316  }
1317  else {
1318  const std::array<real,nstate> primitive_interior_values = convert_conservative_to_primitive_templated<real>(soln_int);
1319  const real pressure_int = primitive_interior_values[nstate-1];
1320 
1321  const real radicant = 1.0+0.5*gamm1*mach_inf_sqr;
1322  const real pressure_inlet = total_inlet_pressure * pow(radicant, -gam/gamm1);
1323  const real pressure_bc = (mach_int >= 1) * pressure_int + (1-(mach_int >= 1)) * back_pressure*pressure_inlet;
1324  const real temperature_int = compute_temperature<real>(primitive_interior_values);
1325 
1326  // Assign primitive boundary values
1327  std::array<real,nstate> primitive_boundary_values;
1328  primitive_boundary_values[0] = compute_density_from_pressure_temperature(pressure_bc, temperature_int);
1329  for (int d=0;d<dim;d++) { primitive_boundary_values[1+d] = primitive_interior_values[1+d]; }
1330  primitive_boundary_values[nstate-1] = pressure_bc;
1331 
1332  const std::array<real,nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1333  for (int istate=0; istate<nstate; ++istate) {
1334  soln_bc[istate] = conservative_bc[istate];
1335  }
1336  }
1337 }
1338 
1339 template <int dim, int nspecies, int nstate, typename real>
1342  const real total_inlet_pressure,
1343  const real total_inlet_temperature,
1344  const dealii::Tensor<1,dim,real> &normal_int,
1345  const std::array<real,nstate> &soln_int,
1346  std::array<real,nstate> &soln_bc) const
1347 {
1348  // Inflow boundary conditions (both subsonic and supersonic)
1349  // Carlson 2011, sec. 2.2 & sec 2.9
1350 
1351  const std::array<real,nstate> primitive_interior_values = convert_conservative_to_primitive_templated<real>(soln_int);
1352 
1353  const dealii::Tensor<1,dim,real> normal = -normal_int;
1354 
1355  const real density_i = primitive_interior_values[0];
1356  const dealii::Tensor<1,dim,real> velocities_i = extract_velocities_from_primitive<real>(primitive_interior_values);
1357  const real pressure_i = primitive_interior_values[nstate-1];
1358 
1359  //const real normal_vel_i = velocities_i*normal;
1360  real normal_vel_i = 0.0;
1361  for (int d=0; d<dim; ++d) {
1362  normal_vel_i += velocities_i[d]*normal[d];
1363  }
1364  const real sound_i = compute_sound(soln_int);
1365  //const real mach_i = std::abs(normal_vel_i)/sound_i;
1366 
1367  //const dealii::Tensor<1,dim,real> velocities_o = velocities_inf;
1368  //const real normal_vel_o = velocities_o*normal;
1369  //const real sound_o = sound_inf;
1370  //const real mach_o = mach_inf;
1371 
1372  if(mach_inf < 1.0) {
1373  // Subsonic inflow, sec 2.7
1374 
1375  //this->pcout << "Subsonic inflow, mach=" << mach_i << std::endl;
1376 
1377  // Want to solve for c_b (sound_bc), to then solve for U (velocity_magnitude_bc) and M_b (mach_bc)
1378  // Eq. 37
1379  const real riemann_pos = normal_vel_i + 2.0*sound_i/gamm1;
1380  // Could evaluate enthalpy from primitive like eq.36, but easier to use the following
1381  const real specific_total_energy = soln_int[nstate-1]/density_i;
1382  const real specific_total_enthalpy = specific_total_energy + pressure_i/density_i;
1383  // Eq. 43
1384  const real a = 1.0+2.0/gamm1;
1385  const real b = -2.0*riemann_pos;
1386  const real c = 0.5*gamm1 * (riemann_pos*riemann_pos - 2.0*specific_total_enthalpy);
1387  // Eq. 42
1388  const real term1 = -0.5*b/a;
1389  const real term2= 0.5*sqrt(b*b-4.0*a*c)/a;
1390  const real sound_bc1 = term1 + term2;
1391  const real sound_bc2 = term1 - term2;
1392  // Eq. 44
1393  const real sound_bc = std::max(sound_bc1, sound_bc2);
1394  // Eq. 45
1395  //const real velocity_magnitude_bc = 2.0*sound_bc/gamm1 - riemann_pos;
1396  const real velocity_magnitude_bc = riemann_pos - 2.0*sound_bc/gamm1;
1397  const real mach_bc = velocity_magnitude_bc/sound_bc;
1398  // Eq. 46
1399  const real radicant = 1.0+0.5*gamm1*mach_bc*mach_bc;
1400  const real pressure_bc = total_inlet_pressure * pow(radicant, -gam/gamm1);
1401  const real temperature_bc = total_inlet_temperature * pow(radicant, -1.0);
1402  //this->pcout << " pressure_bc " << pressure_bc << "pressure_inf" << pressure_inf << std::endl;
1403  //this->pcout << " temperature_bc " << temperature_bc << "temperature_inf" << temperature_inf << std::endl;
1404 
1405  const real density_bc = compute_density_from_pressure_temperature(pressure_bc, temperature_bc);
1406  std::array<real,nstate> primitive_boundary_values;
1407  primitive_boundary_values[0] = density_bc;
1408  for (int d=0;d<dim;d++) { primitive_boundary_values[1+d] = velocity_magnitude_bc*normal[d]; }
1409  primitive_boundary_values[nstate-1] = pressure_bc;
1410  const std::array<real,nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1411  for (int istate=0; istate<nstate; ++istate) {
1412  soln_bc[istate] = conservative_bc[istate];
1413  }
1414 
1415  //this->pcout << " entropy_bc " << compute_entropy_measure(soln_bc) << "entropy_inf" << entropy_inf << std::endl;
1416 
1417  }
1418  else {
1419  // Supersonic inflow, sec 2.9
1420 
1421  // Specify all quantities through
1422  // total_inlet_pressure, total_inlet_temperature, mach_inf & angle_of_attack
1423  //this->pcout << "Supersonic inflow, mach=" << mach_i << std::endl;
1424  const real radicant = 1.0+0.5*gamm1*mach_inf_sqr;
1425  const real static_inlet_pressure = total_inlet_pressure * pow(radicant, -gam/gamm1);
1426  const real static_inlet_temperature = total_inlet_temperature * pow(radicant, -1.0);
1427 
1428  const real pressure_bc = static_inlet_pressure;
1429  const real temperature_bc = static_inlet_temperature;
1430  const real density_bc = compute_density_from_pressure_temperature(pressure_bc, temperature_bc);
1431  const real sound_bc = sqrt(gam * pressure_bc / density_bc);
1432  const real velocity_magnitude_bc = mach_inf * sound_bc;
1433 
1434  // Assign primitive boundary values
1435  std::array<real,nstate> primitive_boundary_values;
1436  primitive_boundary_values[0] = density_bc;
1437  for (int d=0;d<dim;d++) { primitive_boundary_values[1+d] = -velocity_magnitude_bc*normal_int[d]; } // minus since it's inflow
1438  primitive_boundary_values[nstate-1] = pressure_bc;
1439  const std::array<real,nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1440  for (int istate=0; istate<nstate; ++istate) {
1441  soln_bc[istate] = conservative_bc[istate];
1442  }
1443  }
1444 }
1445 
1446 template <int dim, int nspecies, int nstate, typename real>
1449  std::array<real,nstate> &soln_bc) const
1450 {
1451  const real density_bc = density_inf;
1452  const real pressure_bc = 1.0/(gam*mach_inf_sqr);
1453  std::array<real,nstate> primitive_boundary_values;
1454  primitive_boundary_values[0] = density_bc;
1455  for (int d=0;d<dim;d++) { primitive_boundary_values[1+d] = velocities_inf[d]; } // minus since it's inflow
1456  primitive_boundary_values[nstate-1] = pressure_bc;
1457  const std::array<real,nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1458  for (int istate=0; istate<nstate; ++istate) {
1459  soln_bc[istate] = conservative_bc[istate];
1460  }
1461 }
1462 
1463 template <int dim, int nspecies, int nstate, typename real>
1466  const std::array<real, nstate>& soln_int,
1467  std::array<real, nstate>& soln_bc,
1468  std::array<dealii::Tensor<1, dim, real>, nstate>& soln_grad_bc) const
1469 {
1470  for (int istate = 0; istate < nstate; ++istate) {
1471  soln_bc[istate] = soln_int[istate];
1472  soln_grad_bc[istate] = 0;
1473  }
1474 
1475 }
1476 
1477 template <int dim, int nspecies, int nstate, typename real>
1480  std::array<real, nstate>& soln_bc) const
1481 {
1482  std::array<real, nstate> primitive_boundary_values;
1483  for (int istate = 0; istate < nstate; ++istate) {
1484  primitive_boundary_values[istate] = this->all_parameters->euler_param.custom_boundary_for_each_state[istate];
1485  }
1486 
1487  const std::array<real, nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1488  for (int istate = 0; istate < nstate; ++istate) {
1489  soln_bc[istate] = conservative_bc[istate];
1490  }
1491 }
1492 
1493 template <int dim, int nspecies, int nstate, typename real>
1496  std::array<real, nstate>& soln_bc) const
1497 {
1498  std::array<real, nstate> primitive_boundary_values;
1499  for (int istate = 0; istate < nstate; ++istate) {
1500  if(istate == 0)
1501  primitive_boundary_values[istate] = 0.5;
1502  if(istate == 1)
1503  primitive_boundary_values[istate] = 0.0;
1504  if(istate == 2)
1505  primitive_boundary_values[istate] = 0.0;
1506  if(istate == 3)
1507  primitive_boundary_values[istate] = 0.4127;
1508  if(istate == 4)
1509  primitive_boundary_values[istate] = 0.0;
1510  }
1511 
1512  const std::array<real, nstate> conservative_bc = convert_primitive_to_conservative(primitive_boundary_values);
1513  for (int istate = 0; istate < nstate; ++istate) {
1514  soln_bc[istate] = conservative_bc[istate];
1515  }
1516 }
1517 
1518 template <int dim, int nspecies, int nstate, typename real>
1521  const int boundary_type,
1522  const dealii::Point<dim, real> &pos,
1523  const dealii::Tensor<1,dim,real> &normal_int,
1524  const std::array<real,nstate> &soln_int,
1525  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_int,
1526  std::array<real,nstate> &soln_bc,
1527  std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_bc) const
1528 {
1529  // NEED TO PROVIDE AS INPUT ************************************** (ask Doug where this should be moved to, protected member?)
1530  const real total_inlet_pressure = pressure_inf*pow(1.0+0.5*gamm1*mach_inf_sqr, gam/gamm1);
1531  const real total_inlet_temperature = temperature_inf*pow(total_inlet_pressure/pressure_inf, gamm1/gam);
1532 
1533  if (boundary_type == 1000) {
1534  // Manufactured solution boundary condition
1535  boundary_manufactured_solution (pos, normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1536  }
1537  else if (boundary_type == 1001) {
1538  // Wall boundary condition (solid wall)
1539  boundary_wall (normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1540  }
1541  else if (boundary_type == 1002) {
1542  // Pressure outflow boundary condition (back pressure)
1543  const real back_pressure = 0.99;
1544  boundary_pressure_outflow (total_inlet_pressure, back_pressure, soln_int, soln_bc);
1545  }
1546  else if (boundary_type == 1003) {
1547  // Inflow boundary condition
1548  boundary_inflow (total_inlet_pressure, total_inlet_temperature, normal_int, soln_int, soln_bc);
1549  }
1550  else if (boundary_type == 1004) {
1551  // Riemann-based farfield boundary condition
1552  boundary_riemann (normal_int, soln_int, soln_bc);
1553  }
1554  else if (boundary_type == 1005) {
1555  // Simple farfield boundary condition
1556  boundary_farfield(soln_bc);
1557  }
1558  else if (boundary_type == 1006) {
1559  // Slip wall boundary condition
1560  boundary_slip_wall (normal_int, soln_int, soln_grad_int, soln_bc, soln_grad_bc);
1561  }
1562  else if (boundary_type == 1007) {
1563  // Do nothing bc, p0 interpolation
1564  boundary_p0_extrapolation (soln_int, soln_bc, soln_grad_bc);
1565  }
1566  else if (boundary_type == 1008) {
1567  // Custom boundary condition, user defined in parameters
1568  boundary_custom (soln_bc);
1569  }
1570  else if (boundary_type == 1009) {
1571  // Boundary specific to the the astrophysical jet case
1572  boundary_astrophysical_inflow (soln_bc);
1573  }
1574  else {
1575  this->pcout << "Invalid boundary_type: " << boundary_type << std::endl;
1576  std::abort();
1577  }
1578 }
1579 
1580 template <int dim, int nspecies, int nstate, typename real>
1582  const dealii::Vector<double> &uh,
1583  const std::vector<dealii::Tensor<1,dim> > &duh,
1584  const std::vector<dealii::Tensor<2,dim> > &dduh,
1585  const dealii::Tensor<1,dim> &normals,
1586  const dealii::Point<dim> &evaluation_points) const
1587 {
1588  std::vector<std::string> names = post_get_names ();
1589  dealii::Vector<double> computed_quantities = PhysicsBase<dim,nspecies,nstate,real>::post_compute_derived_quantities_vector ( uh, duh, dduh, normals, evaluation_points);
1590  unsigned int current_data_index = computed_quantities.size() - 1;
1591  computed_quantities.grow_or_shrink(names.size());
1592  if constexpr (std::is_same<real,double>::value) {
1593 
1594  std::array<double, nstate> conservative_soln;
1595  for (unsigned int s=0; s<nstate; ++s) {
1596  conservative_soln[s] = uh(s);
1597  }
1598  const std::array<double, nstate> primitive_soln = convert_conservative_to_primitive_templated<real>(conservative_soln);
1599  // if (primitive_soln[0] < 0) this->pcout << evaluation_points << std::endl;
1600 
1601  // Density
1602  computed_quantities(++current_data_index) = primitive_soln[0];
1603  // Velocities
1604  for (unsigned int d=0; d<dim; ++d) {
1605  computed_quantities(++current_data_index) = primitive_soln[1+d];
1606  }
1607  // Momentum
1608  for (unsigned int d=0; d<dim; ++d) {
1609  computed_quantities(++current_data_index) = conservative_soln[1+d];
1610  }
1611  // Energy
1612  computed_quantities(++current_data_index) = conservative_soln[nstate-1];
1613  // Pressure
1614  computed_quantities(++current_data_index) = primitive_soln[nstate-1];
1615  // Pressure coefficient
1616  computed_quantities(++current_data_index) = (primitive_soln[nstate-1] - pressure_inf) / dynamic_pressure_inf;
1617  // Temperature
1618  computed_quantities(++current_data_index) = compute_temperature<real>(primitive_soln);
1619  // Entropy generation
1620  computed_quantities(++current_data_index) = compute_entropy_measure(conservative_soln) - entropy_inf;
1621  // Mach Number
1622  computed_quantities(++current_data_index) = compute_mach_number(conservative_soln);
1623 
1624  }
1625  if (computed_quantities.size()-1 != current_data_index) {
1626  this->pcout << " Did not assign a value to all the data. Missing " << computed_quantities.size() - current_data_index << " variables."
1627  << " If you added a new output variable, make sure the names and DataComponentInterpretation match the above. "
1628  << std::endl;
1629  }
1630 
1631  return computed_quantities;
1632 }
1633 
1634 template <int dim, int nspecies, int nstate, typename real>
1635 std::vector<dealii::DataComponentInterpretation::DataComponentInterpretation> Euler<dim,nspecies,nstate,real>
1637 {
1638  namespace DCI = dealii::DataComponentInterpretation;
1639  std::vector<DCI::DataComponentInterpretation> interpretation = PhysicsBase<dim,nspecies,nstate,real>::post_get_data_component_interpretation (); // state variables
1640  interpretation.push_back (DCI::component_is_scalar); // Density
1641  for (unsigned int d=0; d<dim; ++d) {
1642  interpretation.push_back (DCI::component_is_part_of_vector); // Velocity
1643  }
1644  for (unsigned int d=0; d<dim; ++d) {
1645  interpretation.push_back (DCI::component_is_part_of_vector); // Momentum
1646  }
1647  interpretation.push_back (DCI::component_is_scalar); // Energy
1648  interpretation.push_back (DCI::component_is_scalar); // Pressure
1649  interpretation.push_back (DCI::component_is_scalar); // Pressure coefficient
1650  interpretation.push_back (DCI::component_is_scalar); // Temperature
1651  interpretation.push_back (DCI::component_is_scalar); // Entropy generation
1652  interpretation.push_back (DCI::component_is_scalar); // Mach number
1653 
1654  std::vector<std::string> names = post_get_names();
1655  if (names.size() != interpretation.size()) {
1656  this->pcout << "Number of DataComponentInterpretation is not the same as number of names for output file" << std::endl;
1657  }
1658  return interpretation;
1659 }
1660 
1661 
1662 template <int dim, int nspecies, int nstate, typename real>
1663 std::vector<std::string> Euler<dim,nspecies,nstate,real>
1665 {
1666  std::vector<std::string> names = PhysicsBase<dim,nspecies,nstate,real>::post_get_names ();
1667  names.push_back ("density");
1668  for (unsigned int d=0; d<dim; ++d) {
1669  names.push_back ("velocity");
1670  }
1671  for (unsigned int d=0; d<dim; ++d) {
1672  names.push_back ("momentum");
1673  }
1674  names.push_back ("energy");
1675  names.push_back ("pressure");
1676  names.push_back ("pressure_coefficient");
1677  names.push_back ("temperature");
1678 
1679  names.push_back ("entropy_generation");
1680  names.push_back ("mach_number");
1681  return names;
1682 }
1683 
1684 template <int dim, int nspecies, int nstate, typename real>
1685 dealii::UpdateFlags Euler<dim,nspecies,nstate,real>
1687 {
1688  //return update_values | update_gradients;
1689  return dealii::update_values
1690  | dealii::update_quadrature_points
1691  ;
1692 }
1693 
1694 #if PHILIP_SPECIES==1
1695  // Define a sequence of possible types
1696  #define POSSIBLE_TYPES (double)(FadType)(RadType)(FadFadType)(RadFadType)
1697 
1698  // Define a macro to instantiate Euler and Euler functions for a specific type
1699  #define INSTANTIATE_TYPES(r, data, type) \
1700  template std::array<dealii::Tensor<1,PHILIP_DIM,type>,PHILIP_DIM+2> Euler<PHILIP_DIM,PHILIP_SPECIES,PHILIP_DIM+2,type>::convert_conservative_gradient_to_primitive_gradient_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; \
1701  template std::array<type, PHILIP_DIM+2> Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type>::convert_conservative_to_primitive_templated< type >(const std::array<type, PHILIP_DIM+2> &conservative_soln) const; \
1702  template class Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >; \
1703  template bool Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::check_positive_quantity< type >(type &qty, const std::string qty_name) const; \
1704  template type Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_pressure_templated< type >(const std::array<type, PHILIP_DIM+2> &conservative_soln) const; \
1705  template type Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_entropy_templated< type >(const std::array<type, PHILIP_DIM+2> &conservative_soln) const; \
1706  template type Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_temperature< type >(const std::array<type, PHILIP_DIM+2> &primitive_soln) const; \
1707  template type Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_velocity_squared< type >(const dealii::Tensor<1,PHILIP_DIM, type > &velocities) const; \
1708  template dealii::Tensor<1,PHILIP_DIM, type > Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::extract_velocities_from_primitive< type >(const std::array<type, PHILIP_DIM+2> &primitive_soln) const; \
1709  template dealii::Tensor<1,PHILIP_DIM, type > Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_velocities< type >(const std::array<type, PHILIP_DIM+2> &conservative_soln) const;
1710  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_TYPES, _, POSSIBLE_TYPES)
1711 // -- -- instantiate all the real types with real2 = FadType for automatic differentiation in NavierStokes::dissipative_flux_directional_jacobian()
1712  #undef POSSIBLE_TYPES
1713  #define POSSIBLE_TYPES (double)(RadType)(FadFadType)(RadFadType)
1714  // Define a macro to instantiate Euler and Euler functions for a specific type
1715  #define INSTANTIATE_FADTYPES(r, data, type) \
1716  template std::array<dealii::Tensor<1,PHILIP_DIM,FadType>,PHILIP_DIM+2> Euler<PHILIP_DIM,PHILIP_SPECIES,PHILIP_DIM+2,type>::convert_conservative_gradient_to_primitive_gradient_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;\
1717  template std::array<FadType, PHILIP_DIM+2> Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type>::convert_conservative_to_primitive_templated< FadType >(const std::array<FadType, PHILIP_DIM+2> &conservative_soln) const; \
1718  template bool Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::check_positive_quantity< FadType >(FadType &qty, const std::string qty_name) const; \
1719  template FadType Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_pressure_templated< FadType >(const std::array<FadType, PHILIP_DIM+2> &conservative_soln) const; \
1720  template FadType Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_entropy_templated< FadType >(const std::array<FadType, PHILIP_DIM+2> &conservative_soln) const; \
1721  template FadType Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_temperature< FadType >(const std::array<FadType, PHILIP_DIM+2> &primitive_soln) const; \
1722  template FadType Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_velocity_squared< FadType >(const dealii::Tensor<1,PHILIP_DIM, FadType > &velocities) const; \
1723  template dealii::Tensor<1,PHILIP_DIM, FadType > Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::extract_velocities_from_primitive< FadType >(const std::array<FadType, PHILIP_DIM+2> &primitive_soln) const; \
1724  template dealii::Tensor<1,PHILIP_DIM, FadType > Euler < PHILIP_DIM, PHILIP_SPECIES, PHILIP_DIM+2, type >::compute_velocities< FadType >(const std::array<FadType, PHILIP_DIM+2> &conservative_soln) const;
1725  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_FADTYPES, _, POSSIBLE_TYPES)
1726 //==============================================================================
1727 
1728 #endif
1729 } // Physics namespace
1730 } // PHiLiP namespace
1731 
LimiterType
Limiter type to be applied on the solution.
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
Manufactured solution used for grid studies to check convergence orders.
Files for the baseline physics.
Definition: ADTypes.hpp:10
Main parameter class that contains the various other sub-parameter classes.
TwoPointNumericalFlux
Two point numerical flux type for split form.
Euler equations. Derived from PhysicsBase.
Definition: euler.h:78
Euler(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, 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_diffusion=false, const bool has_nonzero_physical_source=false)
Constructor.
Definition: euler.cpp:14