[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
weak_dg.cpp
1 #include <deal.II/base/tensor.h>
2 #include <deal.II/base/table.h>
3 
4 #include <deal.II/base/qprojector.h>
5 
6 #include <deal.II/lac/full_matrix.templates.h>
7 //#include <deal.II/lac/full_matrix.h>
8 
9 #include <deal.II/fe/fe_values.h>
10 
11 #include <deal.II/dofs/dof_handler.h>
12 #include <deal.II/dofs/dof_tools.h>
13 
14 #include <deal.II/lac/vector.h>
15 
16 #include "ADTypes.hpp"
17 
18 #include "solution/local_solution.hpp"
19 #include "weak_dg.hpp"
20 
21 #define KOPRIVA_METRICS_VOL
22 #define KOPRIVA_METRICS_FACE
23 #define KOPRIVA_METRICS_BOUNDARY
24 
25 namespace {
26 template <typename real, int dim> using Coord = std::array<real, dim>;
27 // First index corresponds to the component of the coordinate, second index corresponds to the component of the gradient.
28 template <typename real, int dim> using CoordGrad = std::array<dealii::Tensor<1, dim, real>, dim>;
29 
30 template <typename real, int nstate> using State = std::array<real, nstate>;
31 // First index corresponds to the component of the state, second index corresponds to the component of the gradient.
32 template <typename real, int dim, int nstate> using DirectionalState = std::array<dealii::Tensor<1, dim, real>, nstate>;
33 }
34 
35 namespace {
38 template <typename number>
39 void gauss_jordan(dealii::FullMatrix<number> &input_matrix) {
40  Assert(!input_matrix.empty(), dealii::ExcMessage("Empty matrix"))
41  Assert(input_matrix.n_cols() == input_matrix.n_rows(), dealii::ExcMessage("Non quadratic matrix"));
42 
43  // Gauss-Jordan-Algorithm from Stoer & Bulirsch I (4th Edition) p. 153
44  const size_t N = input_matrix.n();
45 
46  // First get an estimate of the size of the elements of this matrix,
47  // for later checks whether the pivot element is large enough,
48  // for whether we have to fear that the matrix is not regular
49  number diagonal_sum = 0;
50  for (size_t i = 0; i < N; ++i) diagonal_sum = diagonal_sum + abs(input_matrix(i, i));
51  const number typical_diagonal_element = diagonal_sum / N;
52  (void)typical_diagonal_element;
53 
54  // initialize the array that holds the permutations that we find during pivot search
55  std::vector<size_t> p(N);
56  for (size_t i = 0; i < N; ++i) p[i] = i;
57 
58  for (size_t j = 0; j < N; ++j) {
59  // pivot search: search that part of the line on and
60  // right of the diagonal for the largest element
61  number max_pivot = abs(input_matrix(j, j));
62  size_t r = j;
63  for (size_t i = j + 1; i < N; ++i) {
64  if (abs(input_matrix(i, j)) > max_pivot) {
65  max_pivot = abs(input_matrix(i, j));
66  r = i;
67  }
68  }
69  // check whether the pivot is too small
70  Assert(max_pivot > 1.e-16 * typical_diagonal_element, dealii::ExcMessage("Non regular matrix"));
71 
72  // row interchange
73  if (r > j) {
74  for (size_t k = 0; k < N; ++k) std::swap(input_matrix(j, k), input_matrix(r, k));
75 
76  std::swap(p[j], p[r]);
77  }
78 
79  // transformation
80  const number hr = number(1.) / input_matrix(j, j);
81  input_matrix(j, j) = hr;
82  for (size_t k = 0; k < N; ++k) {
83  if (k == j) continue;
84  for (size_t i = 0; i < N; ++i) {
85  if (i == j) continue;
86  input_matrix(i, k) -= input_matrix(i, j) * input_matrix(j, k) * hr;
87  }
88  }
89  for (size_t i = 0; i < N; ++i) {
90  input_matrix(i, j) *= hr;
91  input_matrix(j, i) *= -hr;
92  }
93  input_matrix(j, j) = hr;
94  }
95  // column interchange
96  std::vector<number> hv(N);
97  for (size_t i = 0; i < N; ++i) {
98  for (size_t k = 0; k < N; ++k) hv[p[k]] = input_matrix(i, k);
99  for (size_t k = 0; k < N; ++k) input_matrix(i, k) = hv[k];
100  }
101 }
102 
104 
106 template <typename real>
107 double getValue(const real &x) {
108  if constexpr (std::is_same<real, double>::value) {
109  return x;
110  } else {
111  return getValue(x.value());
112  }
113 }
115 
119 template <int dim, typename real1, typename real2>
120 dealii::Tensor<1, dim, real1> vmult(const dealii::Tensor<2, dim, real1> A, const dealii::Tensor<1, dim, real2> x) {
121  dealii::Tensor<1, dim, real1> y;
122  for (int row = 0; row < dim; ++row) {
123  y[row] = 0.0;
124  for (int col = 0; col < dim; ++col) {
125  y[row] += A[row][col] * x[col];
126  }
127  }
128  return y;
129 }
130 
132 
136 template <int dim, typename real1>
137 real1 norm(const dealii::Tensor<1, dim, real1> x) {
138  real1 val = 0.0;
139  for (int row = 0; row < dim; ++row) {
140  val += x[row] * x[row];
141  }
142  return sqrt(val);
143 }
144 
145 template <int dim, int nspecies, typename real>
146 bool check_same_coords (
147  const std::vector<dealii::Point<dim>> &unit_quad_pts_int,
148  const std::vector<dealii::Point<dim>> &unit_quad_pts_ext,
151  const double tolerance)
152 {
153  assert(unit_quad_pts_int.size() == unit_quad_pts_ext.size());
154  const unsigned int nquad = unit_quad_pts_int.size();
155  std::vector<Coord<real,dim>> coords_int = metric_int.evaluate_values(unit_quad_pts_int);
156  std::vector<Coord<real,dim>> coords_ext = metric_ext.evaluate_values(unit_quad_pts_ext);
157 
158  bool issame = true;
159  for (unsigned int iquad = 0; iquad < nquad; ++iquad) {
160  for (int d=0; d<dim; ++d) {
161  real abs_diff = abs(coords_int[iquad][d] - coords_ext[iquad][d]);
162  if (abs_diff > tolerance) {
163  real rel_diff = abs_diff / coords_int[iquad][d];
164  if (rel_diff > tolerance) {
165  issame = false;
166  }
167  }
168  }
169  if (!issame) {
170  std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
171  std::cout << "coords_int ";
172  for (int d=0;d<dim;++d) {
173  std::cout << coords_int[iquad][d] << " ";
174  }
175  std::cout << std::endl;
176  std::cout << "coords_ext ";
177  for (int d=0;d<dim;++d) {
178  std::cout << coords_ext[iquad][d] << " ";
179  }
180  std::cout << std::endl;
181  }
182  }
183  return issame;
184 }
185 
186 template <int dim, int nspecies, typename real>
187 std::vector<dealii::Tensor<2,dim,real>> evaluate_metric_jacobian (
188  const std::vector<dealii::Point<dim>> &points,
190 {
191  const unsigned int n_dofs = metric_solution.finite_element.dofs_per_cell;
192  (void) n_dofs;
193  const unsigned int n_pts = points.size();
194 
195  AssertDimension(n_dofs, metric_solution.coefficients.size());
196 
197  std::vector<CoordGrad<real,dim>> coords_gradients = metric_solution.evaluate_reference_gradients(points);
198 
199  std::vector<dealii::Tensor<2,dim,real>> metric_jacobian(n_pts);
200 
201  for (unsigned int ipoint=0; ipoint<n_pts; ++ipoint) {
202  for (int row=0;row<dim;++row) {
203  for (int col=0;col<dim;++col) {
204  metric_jacobian[ipoint][row][col] = coords_gradients[ipoint][row][col];
205  }
206  }
207  }
208  return metric_jacobian;
209 }
210 
211 template <int dim, int nspecies, typename real>
212 std::vector <real> determinant_ArrayTensor(std::vector<CoordGrad<real,dim>> &coords_gradients)
213 {
214  const unsigned int n = coords_gradients.size();
215  std::vector <real> determinants(n);
216  for (unsigned int i=0; i<n; ++i) {
217  if constexpr(dim==1) {
218  determinants[i] = coords_gradients[i][0][0];
219  }
220  if constexpr(dim==2) {
221  determinants[i] = coords_gradients[i][0][0] * coords_gradients[i][1][1] - coords_gradients[i][0][1] * coords_gradients[i][1][0];
222  }
223  if constexpr(dim==3) {
224  determinants[i] = +coords_gradients[i][0][0] * (coords_gradients[i][1][1] * coords_gradients[i][2][2] - coords_gradients[i][1][2] * coords_gradients[i][2][1])
225  -coords_gradients[i][0][1] * (coords_gradients[i][1][0] * coords_gradients[i][2][2] - coords_gradients[i][1][2] * coords_gradients[i][2][0])
226  +coords_gradients[i][0][2] * (coords_gradients[i][1][0] * coords_gradients[i][2][1] - coords_gradients[i][1][1] * coords_gradients[i][2][0]);
227  }
228  }
229  return determinants;
230 }
231 
232 template <int dim, int nspecies, typename real>
233 void evaluate_covariant_metric_jacobian (
234  const dealii::Quadrature<dim> &quadrature,
236  std::vector<dealii::Tensor<2,dim,real>> &covariant_metric_jacobian,
237  std::vector<real> &jacobian_determinants)
238 {
239  const dealii::FiniteElement<dim> &fe_lagrange_grid = metric_solution.finite_element.base_element(0);
240 
241  const std::vector< dealii::Point<dim,double> > &unit_grid_pts = fe_lagrange_grid.get_unit_support_points();
242  std::vector<Coord<real, dim>> coords = metric_solution.evaluate_values(unit_grid_pts);
243  std::vector<CoordGrad<real, dim>> coords_gradients = metric_solution.evaluate_reference_gradients(unit_grid_pts);
244 
245  const std::vector< dealii::Point<dim,double> > &unit_quad_pts = quadrature.get_points();
246  std::vector<CoordGrad<real, dim>> quad_pts_coords_gradients = metric_solution.evaluate_reference_gradients(unit_quad_pts);
247 
248  const unsigned int n_grid_pts = unit_grid_pts.size();
249  const unsigned int n_quad_pts = unit_quad_pts.size();
250 
251  jacobian_determinants = determinant_ArrayTensor<dim,nspecies,real>(quad_pts_coords_gradients);
252 
253  if constexpr (dim==1) {
254  for (unsigned int iquad = 0; iquad<n_quad_pts; ++iquad) {
255  const real invJ = 1.0/jacobian_determinants[iquad];
256  covariant_metric_jacobian[iquad][0][0] = invJ;
257  }
258  }
259 
260  if constexpr (dim==2) {
261  // Remark 5 of Kopriva (2006).
262  // Need to interpolate physical coordinates, and then differentiate it
263  // using the derivatives of the collocated Lagrange basis.
264 
265  std::vector<dealii::Tensor<2,dim,real>> dphys_dref_quad(n_quad_pts);
266 
267  // In 2D Cross-Product Form = Conservative-Curl Form
268  for (unsigned int iquad = 0; iquad<n_quad_pts; ++iquad) {
269 
270  dphys_dref_quad[iquad] = 0.0;
271 
272  const dealii::Point<dim,double> &quad_point = unit_quad_pts[iquad];
273 
274  for (unsigned int igrid = 0; igrid<n_grid_pts; ++igrid) {
275 
276  const dealii::Tensor<1,dim,double> shape_grad = fe_lagrange_grid.shape_grad(igrid, quad_point);
277 
278  for(int dphys=0; dphys<dim; dphys++) {
279  for(int dref=0; dref<dim; dref++) {
280  dphys_dref_quad[iquad][dphys][dref] += coords[igrid][dphys] * shape_grad[dref];
281  }
282  }
283  }
284  }
285 
286  // In 2D Cross-Product Form = Conservative-Curl Form
287  for (unsigned int iquad = 0; iquad<n_quad_pts; ++iquad) {
288 
289  const real invJ = 1.0/jacobian_determinants[iquad];
290 
291  covariant_metric_jacobian[iquad] = 0.0;
292 
293  // inv(A)^T = [ a b ]^-T = (1/det(A)) [ d -c ]
294  // [ c d ] [-b a ]
295  covariant_metric_jacobian[iquad][0][0] = dphys_dref_quad[iquad][1][1] * invJ;
296  covariant_metric_jacobian[iquad][0][1] = -dphys_dref_quad[iquad][1][0] * invJ;
297  covariant_metric_jacobian[iquad][1][0] = -dphys_dref_quad[iquad][0][1] * invJ;
298  covariant_metric_jacobian[iquad][1][1] = dphys_dref_quad[iquad][0][0] * invJ;
299 
300  }
301 
302  }
303  if constexpr (dim == 3) {
304 
305  // Evaluate the physical (Y grad Z), (Z grad X), (X grad
306  std::vector<real> Ta(n_grid_pts);
307  std::vector<real> Tb(n_grid_pts);
308  std::vector<real> Tc(n_grid_pts);
309 
310  std::vector<real> Td(n_grid_pts);
311  std::vector<real> Te(n_grid_pts);
312  std::vector<real> Tf(n_grid_pts);
313 
314  std::vector<real> Tg(n_grid_pts);
315  std::vector<real> Th(n_grid_pts);
316  std::vector<real> Ti(n_grid_pts);
317 
318  for(unsigned int igrid=0; igrid<n_grid_pts; igrid++) {
319  Ta[igrid] = 0.5*(coords_gradients[igrid][1][1] * coords[igrid][2] - coords_gradients[igrid][2][1] * coords[igrid][1]);
320  Tb[igrid] = 0.5*(coords_gradients[igrid][1][2] * coords[igrid][2] - coords_gradients[igrid][2][2] * coords[igrid][1]);
321  Tc[igrid] = 0.5*(coords_gradients[igrid][1][0] * coords[igrid][2] - coords_gradients[igrid][2][0] * coords[igrid][1]);
322 
323  Td[igrid] = 0.5*(coords_gradients[igrid][2][1] * coords[igrid][0] - coords_gradients[igrid][0][1] * coords[igrid][2]);
324  Te[igrid] = 0.5*(coords_gradients[igrid][2][2] * coords[igrid][0] - coords_gradients[igrid][0][2] * coords[igrid][2]);
325  Tf[igrid] = 0.5*(coords_gradients[igrid][2][0] * coords[igrid][0] - coords_gradients[igrid][0][0] * coords[igrid][2]);
326 
327  Tg[igrid] = 0.5*(coords_gradients[igrid][0][1] * coords[igrid][1] - coords_gradients[igrid][1][1] * coords[igrid][0]);
328  Th[igrid] = 0.5*(coords_gradients[igrid][0][2] * coords[igrid][1] - coords_gradients[igrid][1][2] * coords[igrid][0]);
329  Ti[igrid] = 0.5*(coords_gradients[igrid][0][0] * coords[igrid][1] - coords_gradients[igrid][1][0] * coords[igrid][0]);
330  }
331 
332  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++) {
333 
334  covariant_metric_jacobian[iquad] = 0.0;
335 
336  const dealii::Point<dim,double> &quad_point = unit_quad_pts[iquad];
337 
338  for(unsigned int igrid=0; igrid<n_grid_pts; igrid++) {
339 
340  const dealii::Tensor<1,dim,double> shape_grad = fe_lagrange_grid.shape_grad(igrid, quad_point);
341 
342  covariant_metric_jacobian[iquad][0][0] += shape_grad[2] * Ta[igrid] - shape_grad[1] * Tb[igrid];
343  covariant_metric_jacobian[iquad][1][0] += shape_grad[2] * Td[igrid] - shape_grad[1] * Te[igrid];
344  covariant_metric_jacobian[iquad][2][0] += shape_grad[2] * Tg[igrid] - shape_grad[1] * Th[igrid];
345 
346  covariant_metric_jacobian[iquad][0][1] += shape_grad[0] * Tb[igrid] - shape_grad[2] * Tc[igrid];
347  covariant_metric_jacobian[iquad][1][1] += shape_grad[0] * Te[igrid] - shape_grad[2] * Tf[igrid];
348  covariant_metric_jacobian[iquad][2][1] += shape_grad[0] * Th[igrid] - shape_grad[2] * Ti[igrid];
349 
350  covariant_metric_jacobian[iquad][0][2] += shape_grad[1] * Tc[igrid] - shape_grad[0] * Ta[igrid];
351  covariant_metric_jacobian[iquad][1][2] += shape_grad[1] * Tf[igrid] - shape_grad[0] * Td[igrid];
352  covariant_metric_jacobian[iquad][2][2] += shape_grad[1] * Ti[igrid] - shape_grad[0] * Tg[igrid];
353  }
354 
355  const real invJ = 1.0/jacobian_determinants[iquad];
356  covariant_metric_jacobian[iquad] *= invJ;
357 
358  }
359 
360  }
361 
362 }
363 }
364 
365 namespace PHiLiP {
366 
367 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
369  const Parameters::AllParameters *const parameters_input,
370  const unsigned int degree,
371  const unsigned int max_degree_input,
372  const unsigned int grid_degree_input,
373  const std::shared_ptr<Triangulation> triangulation_input)
374  : DGBaseState<dim,nspecies,nstate,real,MeshType>(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input)
375 { }
376 
377 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
379  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
380  const dealii::types::global_dof_index current_cell_index,
381  const dealii::FEValues<dim,dim> &fe_values_vol,
382  const std::vector<dealii::types::global_dof_index> &soln_dof_indices_int,
383  const std::vector<dealii::types::global_dof_index> &/*metric_dof_indices*/,
384  const unsigned int /*poly_degree*/,
385  const unsigned int /*grid_degree*/,
386  dealii::Vector<real> &/*local_rhs_int_cell*/,
387  const dealii::FEValues<dim,dim> &/*fe_values_lagrange*/)
388 {
389  using State = State<real, nstate>;
390  using DirectionalState = DirectionalState<real, dim, nstate>;
391 
392  (void) current_cell_index;
393 
394  const unsigned int n_quad_pts = fe_values_vol.n_quadrature_points;
395  const unsigned int n_soln_dofs_int = fe_values_vol.dofs_per_cell;
396 
397  AssertDimension (n_soln_dofs_int, soln_dof_indices_int.size());
398 
399  const std::vector<real> &JxW = fe_values_vol.get_JxW_values ();
400 
401  real cell_volume_estimate = 0.0;
402  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
403  cell_volume_estimate = cell_volume_estimate + JxW[iquad];
404  }
405  const real cell_volume = cell_volume_estimate;
406 
407  std::vector<State> soln_at_q(n_quad_pts);
408  std::vector<State> source_at_q;
409  std::vector<State> physical_source_at_q;
410  std::vector<DirectionalState> soln_grad_at_q(n_quad_pts);
411  std::vector<DirectionalState> conv_phys_flux_at_q(n_quad_pts);
412  std::vector<DirectionalState> diss_phys_flux_at_q(n_quad_pts);
413 
414  std::vector< real > soln_coeff(n_soln_dofs_int);
415  for (unsigned int idof = 0; idof < n_soln_dofs_int; ++idof) {
416  soln_coeff[idof] = this->solution(soln_dof_indices_int[idof]);
417  }
418 
419  typename dealii::DoFHandler<dim>::active_cell_iterator artificial_dissipation_cell(
420  this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation));
421  const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell;
422  std::vector<dealii::types::global_dof_index> dof_indices_artificial_dissipation(n_dofs_arti_diss);
423  artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation);
424 
425  std::vector<real> artificial_diss_coeff_at_q(n_quad_pts);
426  real max_artificial_diss = 0.0;
427  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
428  artificial_diss_coeff_at_q[iquad] = 0.0;
429 
431  const dealii::Point<dim,real> point = fe_values_vol.get_quadrature().point(iquad);
432  for (unsigned int idof=0; idof<n_dofs_arti_diss; ++idof) {
433  const unsigned int index = dof_indices_artificial_dissipation[idof];
434  artificial_diss_coeff_at_q[iquad] += this->artificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point);
435  }
436  max_artificial_diss = std::max(artificial_diss_coeff_at_q[iquad], max_artificial_diss);
437  }
438  }
439 
440  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
441  for (int istate=0; istate<nstate; istate++) {
442  // Interpolate solution to the face quadrature points
443  soln_at_q[iquad][istate] = 0;
444  soln_grad_at_q[iquad][istate] = 0;
445  }
446  }
447  // Interpolate solution to face
448  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
449  for (unsigned int idof=0; idof<n_soln_dofs_int; ++idof) {
450  const unsigned int istate = fe_values_vol.get_fe().system_to_component_index(idof).first;
451  soln_at_q[iquad][istate] += soln_coeff[idof] * fe_values_vol.shape_value_component(idof, iquad, istate);
452  soln_grad_at_q[iquad][istate] += soln_coeff[idof] * fe_values_vol.shape_grad_component(idof, iquad, istate);
453  }
454  }
455 
456  const unsigned int cell_index = fe_values_vol.get_cell()->active_cell_index();
457  const unsigned int cell_degree = fe_values_vol.get_fe().tensor_degree();
458  const real diameter = fe_values_vol.get_cell()->diameter();
459  const real cell_diameter = cell_volume / std::pow(diameter,dim-1);
460  //const real cell_diameter = std::pow(cell_volume,1.0/dim);
461  //const real cell_diameter = cell_volume;
462  const real cell_radius = 0.5 * cell_diameter;
463  this->cell_volume[cell_index] = cell_volume;
464  this->max_dt_cell[cell_index] = this->evaluate_CFL(soln_at_q, max_artificial_diss, cell_radius, cell_degree);
465 }
466 
467 template <int dim, int nspecies, int nstate, typename real2>
468 void compute_br2_correction(
469  const dealii::FESystem<dim,dim> &fe_soln,
470  const LocalSolution<real2, dim, nspecies, dim> &metric_solution,
471  const std::vector<State<real2, nstate>> &lifting_op_R_rhs,
472  std::vector<State<real2, nstate>> &soln_grad_correction
473  )
474 {
475  const unsigned int n_faces = std::pow(2,dim);
476  const double br2_factor = n_faces * 1.01;
477 
478  // Get the base finite element
479  // Assumption is that the vector-valued finite element uses the same basis for every state equation.
480  const dealii::FiniteElement<dim> &base_fe = fe_soln.get_sub_fe(0,1);
481  const unsigned int n_base_dofs = base_fe.n_dofs_per_cell();
482 
483  // Build lifting term of BR2
484  // For this purposes of BR2, do NOT overintegrate to have a square invertible differentiation matrix
485  const int degree = base_fe.tensor_degree();
486  dealii::QGauss<dim> vol_quad(degree+1);
487  const unsigned int n_vol_quad = vol_quad.size();
488 
489  if (n_base_dofs != n_vol_quad) std::abort();
490 
491  // Obtain metric Jacobians at volume quadratures.
492  const std::vector<dealii::Point<dim,double>> &vol_unit_quad_pts = vol_quad.get_points();
493  using Tensor2D = dealii::Tensor<2,dim,real2>;
494  std::vector<Tensor2D> volume_metric_jac = evaluate_metric_jacobian (vol_unit_quad_pts, metric_solution);
495 
496  // Evaluate Vandermonde operator
497  dealii::FullMatrix<double> vandermonde_inverse(n_base_dofs, n_vol_quad);
498 
499  for (unsigned int idof_base=0; idof_base<n_base_dofs; ++idof_base) {
500  for (unsigned int iquad=0; iquad<n_vol_quad; ++iquad) {
501  vandermonde_inverse[idof_base][iquad] = base_fe.shape_value(idof_base, vol_quad.point(iquad));
502  }
503  }
504  gauss_jordan(vandermonde_inverse);
505 
506  std::vector< std::array<real2,nstate> > vandermonde_inv_rhs(n_vol_quad);
507  for (unsigned int kquad=0; kquad<n_vol_quad; ++kquad) {
508  for (int s=0; s<nstate; s++) {
509  vandermonde_inv_rhs[kquad][s] = 0.0;
510  for (unsigned int jdof_base=0; jdof_base<n_base_dofs; ++jdof_base) {
511  vandermonde_inv_rhs[kquad][s] += vandermonde_inverse[kquad][jdof_base] * lifting_op_R_rhs[jdof_base][s];
512  }
513  }
514  }
515  for (unsigned int kquad=0; kquad<n_vol_quad; ++kquad) {
516  for (int s=0; s<nstate; s++) {
517  vandermonde_inv_rhs[kquad][s] /= dealii::determinant(volume_metric_jac[kquad]) * vol_quad.weight(kquad);
518  }
519  }
520  for (unsigned int idof_base=0; idof_base<n_base_dofs; ++idof_base) {
521  for (int s=0; s<nstate; s++) {
522  soln_grad_correction[idof_base][s] = 0.0;
523  for (unsigned int kquad=0; kquad<n_vol_quad; ++kquad) {
524  soln_grad_correction[idof_base][s] += vandermonde_inverse[kquad][idof_base] * vandermonde_inv_rhs[kquad][s];
525  }
526  soln_grad_correction[idof_base][s] *= br2_factor;
527  //soln_grad_correction[idof_base][s] /= dim; // Due to the dot-product of the vector-valued mass matrix
528  }
529  }
530 }
531 
532 template <int dim, int nspecies, int nstate, typename real2>
533 void correct_the_gradient(
534  const std::vector<State<real2, nstate>> &soln_grad_corr,
535  const dealii::FESystem<dim,dim> &fe_soln,
536  const std::vector<DirectionalState<real2, dim, nstate>> &soln_jump,
537  const dealii::FullMatrix<double> &interpolation_operator,
538  const std::array<dealii::FullMatrix<real2>,dim> &gradient_operator,
539  std::vector<DirectionalState<real2, dim, nstate>> &soln_grad)
540 {
541  (void) soln_jump;
542  (void) soln_grad_corr;
543  (void) interpolation_operator;
544  (void) gradient_operator;
545  const unsigned int n_quad = soln_grad.size();
546  const unsigned int n_soln_dofs = fe_soln.dofs_per_cell;
547 
548  for (unsigned int iquad=0; iquad<n_quad; ++iquad) {
549  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
550  const unsigned int istate = fe_soln.system_to_component_index(idof).first;
551  const unsigned int idof_base = fe_soln.system_to_component_index(idof).second;
552  (void) istate;
553  (void) idof_base;
554  for (int d=0;d<dim;++d) {
555  //soln_grad[iquad][istate][d] += soln_jump[iquad][istate][d];
556  soln_grad[iquad][istate][d] += soln_grad_corr[idof_base][istate] * interpolation_operator[idof][iquad];
557  //soln_grad[iquad][istate][d] += soln_grad_corr[idof_base][istate] * gradient_operator[d][idof][iquad];
558  }
559  }
560  }
561 }
562 
563 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
564 template <typename real2>
566  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
567  const dealii::types::global_dof_index current_cell_index,
568  const LocalSolution<real2, dim, nspecies, nstate> &local_solution,
569  const LocalSolution<real2, dim, nspecies, dim> &local_metric,
570  const std::vector< real > &local_dual,
571  const unsigned int face_number,
572  const unsigned int boundary_id,
576  const dealii::FEFaceValuesBase<dim,dim> &fe_values_boundary,
577  const real penalty,
578  const dealii::Quadrature<dim-1> &quadrature,
579  std::vector<real2> &rhs,
580  real2 &dual_dot_residual,
581  const bool compute_metric_derivatives)
582 {
583  const unsigned int n_soln_dofs = local_solution.finite_element.dofs_per_cell;
584  const unsigned int n_metric_dofs = local_metric.finite_element.dofs_per_cell;
585  const unsigned int n_quad_pts = fe_values_boundary.n_quadrature_points;
586 
587  dual_dot_residual = 0.0;
588  for (unsigned int itest=0; itest<n_soln_dofs; ++itest) {
589  rhs[itest] = 0.0;
590  }
591 
592  using State = State<real2, nstate>;
593  using DirectionalState = DirectionalState<real2, dim, nstate>;
594 
595  const dealii::Quadrature<dim> face_quadrature
596  = dealii::QProjector<dim>::project_to_face(
597  dealii::ReferenceCell::get_hypercube(dim),
598  quadrature,
599  face_number);
600  const std::vector<dealii::Point<dim,real>> &unit_quad_pts = face_quadrature.get_points();
601  std::vector<dealii::Point<dim,real2>> real_quad_pts(unit_quad_pts.size());
602 
603  std::vector<dealii::Tensor<2,dim,real2>> metric_jacobian = evaluate_metric_jacobian (unit_quad_pts, local_metric);
604  std::vector<real2> jac_det(n_quad_pts);
605  std::vector<real2> surface_jac_det(n_quad_pts);
606  std::vector<dealii::Tensor<2,dim,real2>> jac_inv_tran(n_quad_pts);
607 
608  const dealii::Tensor<1,dim,real> unit_normal = dealii::GeometryInfo<dim>::unit_normal_vector[face_number];
609  std::vector<dealii::Tensor<1,dim,real2>> phys_unit_normal(n_quad_pts);
610 
611  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
612  if (compute_metric_derivatives) {
613  for (int d=0;d<dim;++d) { real_quad_pts[iquad][d] = 0;}
614  for (unsigned int idof = 0; idof < n_metric_dofs; ++idof) {
615  const int iaxis = local_metric.finite_element.system_to_component_index(idof).first;
616  real_quad_pts[iquad][iaxis] += local_metric.coefficients[idof] * local_metric.finite_element.shape_value(idof,unit_quad_pts[iquad]);
617  }
618 
619  const real2 jacobian_determinant = dealii::determinant(metric_jacobian[iquad]);
620  const dealii::Tensor<2,dim,real2> jacobian_transpose_inverse = dealii::transpose(dealii::invert(metric_jacobian[iquad]));
621 
622  jac_det[iquad] = jacobian_determinant;
623  jac_inv_tran[iquad] = jacobian_transpose_inverse;
624 
625  const dealii::Tensor<1,dim,real2> normal = vmult(jacobian_transpose_inverse, unit_normal);
626  const real2 area = norm(normal);
627 
628  surface_jac_det[iquad] = norm(normal)*jac_det[iquad];
629  // Technically the normals have jac_det multiplied.
630  // However, we use normalized normals by convention, so the term
631  // ends up appearing in the surface jacobian.
632  for (int d=0;d<dim;++d) {
633  phys_unit_normal[iquad][d] = normal[d] / area;
634  }
635 
636  // Exact mapping
637  // real_quad_pts[iquad] = fe_values_boundary.quadrature_point(iquad);
638  // surface_jac_det[iquad] = fe_values_boundary.JxW(iquad) / face_quadrature.weight(iquad);
639  // phys_unit_normal[iquad] = fe_values_boundary.normal_vector(iquad);
640 
641  } else {
642  real_quad_pts[iquad] = fe_values_boundary.quadrature_point(iquad);
643  surface_jac_det[iquad] = fe_values_boundary.JxW(iquad) / face_quadrature.weight(iquad);
644  phys_unit_normal[iquad] = fe_values_boundary.normal_vector(iquad);
645  }
646  }
647 #ifdef KOPRIVA_METRICS_BOUNDARY
648  auto old_jac_det = jac_det;
649  auto old_jac_inv_tran = jac_inv_tran;
650 
651  if constexpr (dim != 1) {
652  evaluate_covariant_metric_jacobian<dim,nspecies,real2> ( face_quadrature, local_metric, jac_inv_tran, jac_det);
653  }
654 #endif
655 
656  std::vector<real2> faceJxW(n_quad_pts);
657 
658  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
659  if (compute_metric_derivatives) {
660  const dealii::Tensor<1,dim,real2> normal = vmult(jac_inv_tran[iquad], unit_normal);
661  const real2 area = norm(normal);
662 
663  surface_jac_det[iquad] = norm(normal)*jac_det[iquad];
664  // Technically the normals have jac_det multiplied.
665  // However, we use normalized normals by convention, so the term
666  // ends up appearing in the surface jacobian.
667  for (int d=0;d<dim;++d) {
668  phys_unit_normal[iquad][d] = normal[d] / area;
669  }
670  }
671 
672  faceJxW[iquad] = surface_jac_det[iquad] * face_quadrature.weight(iquad);
673  }
674 
675  dealii::FullMatrix<real> interpolation_operator(n_soln_dofs,n_quad_pts);
676  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
677  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
678  interpolation_operator[idof][iquad] = local_solution.finite_element.shape_value(idof,unit_quad_pts[iquad]);
679  }
680  }
681  std::array<dealii::FullMatrix<real2>,dim> gradient_operator;
682  for (int d=0;d<dim;++d) {
683  gradient_operator[d].reinit(dealii::TableIndices<2>(n_soln_dofs, n_quad_pts));
684  }
685  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
686  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
687  if (compute_metric_derivatives) {
688  const dealii::Tensor<1,dim,real> ref_shape_grad = local_solution.finite_element.shape_grad(idof,unit_quad_pts[iquad]);
689  const dealii::Tensor<1,dim,real2> phys_shape_grad = vmult(jac_inv_tran[iquad], ref_shape_grad);
690  for (int d=0;d<dim;++d) {
691  gradient_operator[d][idof][iquad] = phys_shape_grad[d];
692  }
693 
694  // Exact mapping
695  // for (int d=0;d<dim;++d) {
696  // const unsigned int istate = fe_soln.system_to_component_index(idof).first;
697  // gradient_operator[d][idof][iquad] = fe_values_boundary.shape_grad_component(idof, iquad, istate)[d];
698  // }
699  } else {
700  for (int d=0;d<dim;++d) {
701  const unsigned int istate = local_solution.finite_element.system_to_component_index(idof).first;
702  gradient_operator[d][idof][iquad] = fe_values_boundary.shape_grad_component(idof, iquad, istate)[d];
703  }
704  }
705  }
706  }
707 
708  std::vector<State> soln_int = local_solution.evaluate_values(unit_quad_pts);
709  std::vector<State> soln_ext(n_quad_pts), soln_ext_viscous_flux(n_quad_pts);
710  std::vector<DirectionalState> soln_grad_int(n_quad_pts), soln_grad_ext(n_quad_pts), soln_grad_ext_viscous_flux(n_quad_pts);
711 
712  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
713 
714  for (int istate=0; istate<nstate; istate++) {
715  soln_grad_int[iquad][istate] = 0;
716  }
717  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
718  const int istate = fe_values_boundary.get_fe().system_to_component_index(idof).first;
719  for (int d=0;d<dim;++d) {
720  soln_grad_int[iquad][istate][d] += local_solution.coefficients[idof] * gradient_operator[d][idof][iquad];
721  }
722  }
723  }
724 
725  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
726  const dealii::Tensor<1,dim,real2> normal_int = phys_unit_normal[iquad];
727  physics.boundary_face_values (boundary_id, real_quad_pts[iquad], normal_int, soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]);
728  physics.boundary_face_values_viscous_flux (boundary_id, real_quad_pts[iquad], normal_int, soln_int[iquad], soln_grad_int[iquad], soln_int[iquad], soln_grad_int[iquad], soln_ext_viscous_flux[iquad], soln_grad_ext_viscous_flux[iquad]);
729  }
730 
731  // Assemble BR2 gradient correction right-hand side
732  const dealii::FiniteElement<dim> &base_fe_int = local_solution.finite_element.get_sub_fe(0,1);
733  const unsigned int n_base_dofs_int = base_fe_int.n_dofs_per_cell();
734 
735  std::vector<DirectionalState > soln_grad_correction_int(n_base_dofs_int);
737  if (this->all_parameters->diss_num_flux_type == DissFlux::bassi_rebay_2) {
738 
739  // Obtain solution jump
740  std::vector<DirectionalState> soln_jump_int(n_quad_pts);
741  std::vector<DirectionalState> soln_jump_ext(n_quad_pts);
742  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
743  for (int s=0; s<nstate; s++) {
744  for (int d=0; d<dim; d++) {
745  soln_jump_int[iquad][s][d] = (soln_int[iquad][s] - soln_ext[iquad][s]) * (phys_unit_normal[iquad][d]);
746  soln_jump_ext[iquad][s][d] = (soln_ext[iquad][s] - soln_int[iquad][s]) * (-phys_unit_normal[iquad][d]);
747  }
748  }
749  }
750 
751  std::vector<State> lifting_op_R_rhs_int(n_base_dofs_int);
752  for (unsigned int idof_base=0; idof_base<n_base_dofs_int; ++idof_base) {
753  for (int s=0; s<nstate; s++) {
754 
755  const unsigned int idof = local_solution.finite_element.component_to_system_index(s, idof_base);
756  lifting_op_R_rhs_int[idof_base][s] = 0.0;
757 
758  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
759 
760  for (int d=0; d<dim; ++d) {
761  const double basis_average = interpolation_operator[idof][iquad];
762  lifting_op_R_rhs_int[idof_base][s] -= soln_jump_int[iquad][s][d] * basis_average * faceJxW[iquad];
763  }
764  }
765 
766  }
767  }
768  std::vector<State> soln_grad_corr_int(n_base_dofs_int);
769  compute_br2_correction<dim,nspecies,nstate,real2>(local_solution.finite_element, local_metric, lifting_op_R_rhs_int, soln_grad_corr_int);
770 
771  correct_the_gradient<dim,nspecies,nstate,real2>( soln_grad_corr_int, local_solution.finite_element, soln_jump_int, interpolation_operator, gradient_operator, soln_grad_int);
772 
773  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
774  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
775  const unsigned int istate = local_solution.finite_element.system_to_component_index(idof).first;
776  const unsigned int idof_base = local_solution.finite_element.system_to_component_index(idof).second;
777  (void) istate;
778  (void) idof_base;
779  for (int d=0;d<dim;++d) {
780  //soln_grad_int[iquad][istate][d] += soln_jump_int[iquad][istate][d];
781  //soln_grad_int[iquad][istate][d] += soln_grad_corr_int[idof_base][istate] * interpolation_operator[idof][iquad];
782  //soln_grad_int[iquad][istate][d] += soln_grad_corr_int[idof_base][istate] * gradient_operator[d][idof][iquad];
783  //soln_grad_ext[iquad][istate][d] -= soln_grad_corr_int[idof_base][istate] * gradient_operator[d][idof][iquad];
784  soln_grad_ext[iquad][istate][d] = soln_grad_int[iquad][istate][d];
785  }
786  }
787  physics.boundary_face_values (boundary_id, real_quad_pts[iquad], phys_unit_normal[iquad], soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]);
788  }
789 
790  }
791 
792 
793  std::vector<State> conv_num_flux_dot_n(n_quad_pts);
794  std::vector<State> diss_soln_num_flux(n_quad_pts); // u*
795  std::vector<DirectionalState> diss_flux_jump_int(n_quad_pts); // u*-u_int
796  std::vector<State> diss_auxi_num_flux_dot_n(n_quad_pts); // sigma*
797 
798  //const real2 cell_diameter = fe_values_boundary.get_cell()->diameter();
799  //const real2 artificial_diss_coeff = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
800  // this->discontinuity_sensor(cell_diameter, soln_coeff, fe_values_boundary.get_fe())
801  // : 0.0;
802  const real2 artificial_diss_coeff = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
803  this->artificial_dissipation_coeffs[current_cell_index]
804  : 0.0;
805  (void) artificial_diss_coeff;
806 
807  typename dealii::DoFHandler<dim>::active_cell_iterator artificial_dissipation_cell(
808  this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation));
809  const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell;
810  std::vector<dealii::types::global_dof_index> dof_indices_artificial_dissipation(n_dofs_arti_diss);
811  artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation);
812 
813  std::vector<real> artificial_diss_coeff_at_q(n_quad_pts);
814  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
815  artificial_diss_coeff_at_q[iquad] = 0.0;
817  const dealii::Point<dim,real> point = unit_quad_pts[iquad];
818  for (unsigned int idof=0; idof<n_dofs_arti_diss; ++idof) {
819  const unsigned int index = dof_indices_artificial_dissipation[idof];
820  artificial_diss_coeff_at_q[iquad] += this->artificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point);
821  }
822  }
823  artificial_diss_coeff_at_q[iquad] = 0.0;
824  }
825 
826  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
827 
828  const dealii::Tensor<1,dim,real2> normal_int = phys_unit_normal[iquad];
829 
830  // Evaluate physical convective flux, physical dissipative flux
831  // Following the boundary treatment given by
832  // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods,
833  // Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008.
834  // Details given on page 93
835  //conv_num_flux_dot_n[iquad] = conv_num_flux_fad_fad->evaluate_flux(soln_ext[iquad], soln_ext[iquad], normal_int);
836 
837  // So, I wasn't able to get Euler manufactured solutions to converge when F* = F*(Ubc, Ubc)
838  // Changing it back to the standdard F* = F*(Uin, Ubc)
839  // This is known not be adjoint consistent as per the paper above. Page 85, second to last paragraph.
840  // Losing 2p+1 OOA on functionals for all PDEs.
841  //conv_num_flux_dot_n[iquad] = conv_num_flux.evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int);
842  conv_num_flux_dot_n[iquad] = conv_num_flux.evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int);
843  // Notice that the flux uses the solution given by the Dirichlet or Neumann boundary condition
844  diss_soln_num_flux[iquad] = diss_num_flux.evaluate_solution_flux(soln_ext_viscous_flux[iquad], soln_ext_viscous_flux[iquad], normal_int);
845 
846  DirectionalState diss_soln_jump_int;
847  for (int s=0; s<nstate; s++) {
848  for (int d=0; d<dim; d++) {
849  diss_soln_jump_int[s][d] = (diss_soln_num_flux[iquad][s] - soln_int[iquad][s]) * normal_int[d];
850  }
851  }
852  diss_flux_jump_int[iquad] = physics.dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index);
853 
855  const DirectionalState artificial_diss_flux_jump_int = this->artificial_dissip->calc_artificial_dissipation_flux(soln_int[iquad], diss_soln_jump_int, artificial_diss_coeff_at_q[iquad]);
856  for (int s=0; s<nstate; s++) {
857  diss_flux_jump_int[iquad][s] += artificial_diss_flux_jump_int[s];
858  }
859  }
860 
861  diss_auxi_num_flux_dot_n[iquad] = diss_num_flux.evaluate_auxiliary_flux(
862  current_cell_index,
863  current_cell_index,
864  artificial_diss_coeff_at_q[iquad],
865  artificial_diss_coeff_at_q[iquad],
866  soln_int[iquad], soln_ext_viscous_flux[iquad],
867  soln_grad_int[iquad], soln_grad_ext_viscous_flux[iquad],
868  soln_int[iquad], soln_ext_viscous_flux[iquad],
869  soln_grad_int[iquad], soln_grad_ext_viscous_flux[iquad],
870  normal_int, penalty, true, boundary_id);
871  }
872 
873  // Applying convection boundary condition
874  for (unsigned int itest=0; itest<n_soln_dofs; ++itest) {
875 
876  real2 rhs_val = 0.0;
877 
878  const unsigned int istate = fe_values_boundary.get_fe().system_to_component_index(itest).first;
879 
880  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
881 
882  const real2 JxW_iquad = faceJxW[iquad];
883  // Convection
884  rhs_val = rhs_val - interpolation_operator[itest][iquad] * conv_num_flux_dot_n[iquad][istate] * JxW_iquad;
885  // Diffusive
886  rhs_val = rhs_val - interpolation_operator[itest][iquad] * diss_auxi_num_flux_dot_n[iquad][istate] * JxW_iquad;
887  for (int d=0;d<dim;++d) {
888  rhs_val = rhs_val + gradient_operator[d][itest][iquad] * diss_flux_jump_int[iquad][istate][d] * JxW_iquad;
889  }
890  }
891 
892 
893  rhs[itest] = rhs_val;
894  dual_dot_residual += local_dual[itest]*rhs_val;
895  }
896 }
897 
898 
899 template<int dim>
900 dealii::Quadrature<dim> project_face_quadrature(
901  const dealii::Quadrature<dim - 1> &face_quadrature_lower_dim, const std::pair<unsigned int, int> face_subface_pair,
902  const typename dealii::QProjector<dim>::DataSetDescriptor face_data_set) {
903  dealii::Quadrature<dim> face_quadrature;
904 
905  if constexpr (dim == 3) {
906  const dealii::Quadrature<dim> all_faces_quad =
907  face_subface_pair.second == -1 ? dealii::QProjector<dim>::project_to_all_faces(
908  dealii::ReferenceCell::get_hypercube(dim), face_quadrature_lower_dim)
909  : dealii::QProjector<dim>::project_to_all_subfaces(
910  dealii::ReferenceCell::get_hypercube(dim), face_quadrature_lower_dim);
911  const unsigned int n_face_quad_pts = face_quadrature_lower_dim.size();
912  std::vector<dealii::Point<dim>> points(n_face_quad_pts);
913  std::vector<double> weights(n_face_quad_pts);
914  for (unsigned int iquad = 0; iquad < n_face_quad_pts; ++iquad) {
915  points[iquad] = all_faces_quad.point(iquad + face_data_set);
916  weights[iquad] = all_faces_quad.weight(iquad + face_data_set);
917  }
918  face_quadrature = dealii::Quadrature<dim>(points, weights);
919 
920  } else {
921  (void) face_data_set;
922  if (face_subface_pair.second == -1) {
923  face_quadrature = dealii::QProjector<dim>::project_to_face(
924  dealii::ReferenceCell::get_hypercube(dim), face_quadrature_lower_dim, face_subface_pair.first);
925  } else {
926  face_quadrature = dealii::QProjector<dim>::project_to_subface(
927  dealii::ReferenceCell::get_hypercube(dim), face_quadrature_lower_dim, face_subface_pair.first,
928  face_subface_pair.second, dealii::RefinementCase<dim - 1>::isotropic_refinement);
929  }
930  }
931  return face_quadrature;
932 }
933 
934 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
935 template <typename real2>
937  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
938  typename dealii::DoFHandler<dim>::active_cell_iterator /*neighbor_cell*/,
939  const dealii::types::global_dof_index current_cell_index,
940  const dealii::types::global_dof_index neighbor_cell_index,
945  const std::vector< double > &dual_int,
946  const std::vector< double > &dual_ext,
947  const std::pair<unsigned int, int> face_subface_int,
948  const std::pair<unsigned int, int> face_subface_ext,
949  const typename dealii::QProjector<dim>::DataSetDescriptor face_data_set_int,
950  const typename dealii::QProjector<dim>::DataSetDescriptor face_data_set_ext,
954  const dealii::FEFaceValuesBase<dim,dim> &fe_values_int,
955  const dealii::FEFaceValuesBase<dim,dim> &fe_values_ext,
956  const real penalty,
957  const dealii::Quadrature<dim-1> &face_quadrature,
958  std::vector<real2> &rhs_int,
959  std::vector<real2> &rhs_ext,
960  real2 &dual_dot_residual,
961  const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
962 {
963  (void) compute_dRdW;
964  const unsigned int n_soln_dofs_int = soln_int.finite_element.dofs_per_cell;
965  const unsigned int n_soln_dofs_ext = soln_ext.finite_element.dofs_per_cell;
966  const unsigned int n_face_quad_pts = face_quadrature.size();
967 
968  dual_dot_residual = 0.0;
969  for (unsigned int itest=0; itest<n_soln_dofs_int; ++itest) {
970  rhs_int[itest] = 0.0;
971  }
972  for (unsigned int itest=0; itest<n_soln_dofs_ext; ++itest) {
973  rhs_ext[itest] = 0.0;
974  }
975 
976  using State = State<real2, nstate>;
977  using DirectionalState = DirectionalState<real2, dim, nstate>;
978  using Tensor1D = dealii::Tensor<1,dim,real2>;
979  using Tensor2D = dealii::Tensor<2,dim,real2>;
980 
981  dealii::Quadrature<dim> face_quadrature_int = project_face_quadrature<dim>(face_quadrature, face_subface_int, face_data_set_int);
982  dealii::Quadrature<dim> face_quadrature_ext = project_face_quadrature<dim>(face_quadrature, face_subface_ext, face_data_set_ext);
983 
984  (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R;
985  const bool compute_metric_derivatives = true; //(!compute_dRdX && !compute_d2R) ? false : true;
986 
987  const std::vector<dealii::Point<dim,double>> &unit_quad_pts_int = face_quadrature_int.get_points();
988  const std::vector<dealii::Point<dim,double>> &unit_quad_pts_ext = face_quadrature_ext.get_points();
989 
990 
991 
992  // Use the metric Jacobian from the interior cell
993  std::vector<Tensor2D> metric_jac_int = evaluate_metric_jacobian (unit_quad_pts_int, metric_int);
994  std::vector<Tensor2D> metric_jac_ext = evaluate_metric_jacobian (unit_quad_pts_ext, metric_ext);
995 
996  const dealii::Tensor<1,dim,real> unit_normal_int = dealii::GeometryInfo<dim>::unit_normal_vector[face_subface_int.first];
997  const dealii::Tensor<1,dim,real> unit_normal_ext = dealii::GeometryInfo<dim>::unit_normal_vector[face_subface_ext.first];
998 
999 
1000 
1001  // Use quadrature points of neighbor cell
1002  // Might want to use the maximum n_quad_pts1 and n_quad_pts2
1003  //const unsigned int n_face_quad_pts = fe_values_ext.n_quadrature_points;
1004 
1005  //const real2 cell_diameter_int = fe_values_int.get_cell()->diameter();
1006  //const real2 cell_diameter_ext = fe_values_ext.get_cell()->diameter();
1007  //const real2 artificial_diss_coeff_int = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1008  // this->discontinuity_sensor(cell_diameter_int, soln_int.coefficients, fe_values_int.get_fe())
1009  // : 0.0;
1010  //const real2 artificial_diss_coeff_ext = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1011  // this->discontinuity_sensor(cell_diameter_ext, soln_ext.coefficients, fe_values_ext.get_fe())
1012  // : 0.0;
1013  const real2 artificial_diss_coeff_int = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1014  this->artificial_dissipation_coeffs[current_cell_index]
1015  : 0.0;
1016  const real2 artificial_diss_coeff_ext = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1017  this->artificial_dissipation_coeffs[neighbor_cell_index]
1018  : 0.0;
1019 
1020  (void) artificial_diss_coeff_int;
1021  (void) artificial_diss_coeff_ext;
1022  typename dealii::DoFHandler<dim>::active_cell_iterator artificial_dissipation_cell(
1023  this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation));
1024  const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell;
1025  std::vector<dealii::types::global_dof_index> dof_indices_artificial_dissipation(n_dofs_arti_diss);
1026  artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation);
1027 
1028  std::vector<real> artificial_diss_coeff_at_q(n_face_quad_pts);
1029  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1030  artificial_diss_coeff_at_q[iquad] = 0.0;
1031 
1033  const dealii::Point<dim,real> point = unit_quad_pts_int[iquad];
1034  for (unsigned int idof=0; idof<n_dofs_arti_diss; ++idof) {
1035  const unsigned int index = dof_indices_artificial_dissipation[idof];
1036  artificial_diss_coeff_at_q[iquad] += this->artificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point);
1037  }
1038  }
1039  artificial_diss_coeff_at_q[iquad] = 0.0;
1040  }
1041 
1042  std::vector<real2> jacobian_determinant_int(n_face_quad_pts);
1043  std::vector<real2> jacobian_determinant_ext(n_face_quad_pts);
1044  std::vector<Tensor2D> jacobian_transpose_inverse_int(n_face_quad_pts);
1045  std::vector<Tensor2D> jacobian_transpose_inverse_ext(n_face_quad_pts);
1046 
1047  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1048  if (compute_metric_derivatives) {
1049  jacobian_determinant_int[iquad] = dealii::determinant(metric_jac_int[iquad]);
1050  jacobian_determinant_ext[iquad] = dealii::determinant(metric_jac_ext[iquad]);
1051 
1052  jacobian_transpose_inverse_int[iquad] = dealii::transpose(dealii::invert(metric_jac_int[iquad]));
1053  jacobian_transpose_inverse_ext[iquad] = dealii::transpose(dealii::invert(metric_jac_ext[iquad]));
1054  }
1055  }
1056 
1057 #ifdef KOPRIVA_METRICS_FACE
1058  auto old_jacobian_determinant_int = jacobian_determinant_int;
1059  auto old_jacobian_determinant_ext = jacobian_determinant_ext;
1060  auto old_jacobian_transpose_inverse_int = jacobian_transpose_inverse_int;
1061  auto old_jacobian_transpose_inverse_ext = jacobian_transpose_inverse_ext;
1062 
1063  if constexpr (dim != 1) {
1064  evaluate_covariant_metric_jacobian<dim,nspecies,real2> ( face_quadrature_int, metric_int, jacobian_transpose_inverse_int, jacobian_determinant_int);
1065  evaluate_covariant_metric_jacobian<dim,nspecies,real2> ( face_quadrature_ext, metric_ext, jacobian_transpose_inverse_ext, jacobian_determinant_ext);
1066  }
1067 #endif
1068 
1070  check_same_coords<dim,nspecies,real2>(unit_quad_pts_int, unit_quad_pts_ext, metric_int, metric_ext, 1e-10);
1071  }
1072 
1073  // Compute metrics
1074  std::vector<Tensor1D> phys_unit_normal_int(n_face_quad_pts), phys_unit_normal_ext(n_face_quad_pts);
1075  std::vector<real2> surface_jac_det(n_face_quad_pts);
1076  std::vector<real2> faceJxW(n_face_quad_pts);
1077 
1078  dealii::FullMatrix<real> interpolation_operator_int(n_soln_dofs_int, n_face_quad_pts);
1079  dealii::FullMatrix<real> interpolation_operator_ext(n_soln_dofs_ext, n_face_quad_pts);
1080  std::array<dealii::FullMatrix<real2>,dim> gradient_operator_int, gradient_operator_ext;
1081  for (int d=0;d<dim;++d) {
1082  gradient_operator_int[d].reinit(dealii::TableIndices<2>(n_soln_dofs_int, n_face_quad_pts));
1083  gradient_operator_ext[d].reinit(dealii::TableIndices<2>(n_soln_dofs_ext, n_face_quad_pts));
1084  }
1085 
1086  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1087 
1088  real2 surface_jac_det_int, surface_jac_det_ext;
1089 
1090  if (compute_metric_derivatives) {
1091 
1092  const real2 jac_det_int = jacobian_determinant_int[iquad];
1093  const real2 jac_det_ext = jacobian_determinant_ext[iquad];
1094 
1095  const Tensor2D jac_inv_tran_int = jacobian_transpose_inverse_int[iquad];
1096  const Tensor2D jac_inv_tran_ext = jacobian_transpose_inverse_ext[iquad];
1097 
1098  const Tensor1D normal_int = vmult(jac_inv_tran_int, unit_normal_int);
1099  const Tensor1D normal_ext = vmult(jac_inv_tran_ext, unit_normal_ext);
1100  const real2 area_int = norm(normal_int);
1101  const real2 area_ext = norm(normal_ext);
1102  // Technically the normals have jac_det multiplied.
1103  // However, we use normalized normals by convention, so the term
1104  // ends up appearing in the surface jacobian.
1105 
1106  for (int d=0;d<dim;++d) {
1107  phys_unit_normal_int[iquad][d] = normal_int[d] / area_int;
1108  }
1109  for (int d=0;d<dim;++d) {
1110  phys_unit_normal_ext[iquad][d] = normal_ext[d] / area_ext;
1111  }
1112 
1113  surface_jac_det_int = area_int*jac_det_int;
1114  surface_jac_det_ext = area_ext*jac_det_ext;
1115 
1116 
1117  if (std::is_same<double,real2>::value) {
1118  bool valid_metrics = true;
1119  // surface_jac_det is the 'volume' compression/expansion of the face w.r.t. the reference cell,
1120  // analogous to volume jacobian determinant.
1121  //
1122  // When the cells have the same coarseness, their surface Jacobians must be the same.
1123  //
1124  // When the cells do not have the same coarseness, their surface Jacobians will not be the same.
1125  // Therefore, we must use the Jacobians coming from the smaller face since it accurately represents
1126  // the surface area being integrated.
1127  if (face_subface_int.second == -1 && face_subface_ext.second == -1) {
1128  if(abs(surface_jac_det_int-surface_jac_det_ext) > this->all_parameters->matching_surface_jac_det_tolerance) {
1129  pcout << std::endl;
1130  pcout << "iquad " << iquad << " Non-matching surface jacobians, int = "
1131  << surface_jac_det_int << ", ext = " << surface_jac_det_ext << ", diff = "
1132  << abs(surface_jac_det_int-surface_jac_det_ext) << std::endl;
1133 
1134  assert(abs(surface_jac_det_int-surface_jac_det_ext) < this->all_parameters->matching_surface_jac_det_tolerance);
1135  valid_metrics = false;
1136  }
1137  }
1138  real2 diff_norm = 0;
1139  for (int d=0;d<dim;++d) {
1140  const real2 diff = phys_unit_normal_int[iquad][d]+phys_unit_normal_ext[iquad][d];
1141  diff_norm += diff*diff;
1142  }
1143  diff_norm = sqrt(diff_norm);
1144  if (diff_norm > 1e-10) {
1145  std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
1146  std::cout << "Non-matching normals. Error norm: " << diff_norm << std::endl;
1147  for (int d=0;d<dim;++d) {
1148  //assert(abs(phys_unit_normal_int[iquad][d]+phys_unit_normal_ext[iquad][d]) < 1e-10);
1149  std::cout << " normal_int["<<d<<"] : " << phys_unit_normal_int[iquad][d]
1150  << " normal_ext["<<d<<"] : " << phys_unit_normal_ext[iquad][d]
1151  << std::endl;
1152  }
1153  valid_metrics = false;
1154  }
1155  if (!valid_metrics) {
1156  //for (unsigned int itest_int=0; itest_int<n_soln_dofs_int; ++itest_int) {
1157  // rhs_int[itest_int] += 1e20;
1158  //}
1159  //for (unsigned int itest_ext=0; itest_ext<n_soln_dofs_ext; ++itest_ext) {
1160  // rhs_ext[itest_ext] += 1e20;
1161  //}
1162  }
1163 
1164  }
1165  //phys_unit_normal_ext[iquad] = -phys_unit_normal_int[iquad];//normal_ext / area_ext; Must use opposite normal to be consistent with explicit
1166 
1167  for (unsigned int idof=0; idof<n_soln_dofs_int; ++idof) {
1168  interpolation_operator_int[idof][iquad] = soln_int.finite_element.shape_value(idof,unit_quad_pts_int[iquad]);
1169  dealii::Tensor<1,dim,real> ref_shape_grad = soln_int.finite_element.shape_grad(idof,unit_quad_pts_int[iquad]);
1170  const Tensor1D phys_shape_grad = vmult(jac_inv_tran_int, ref_shape_grad);
1171  for (int d=0;d<dim;++d) {
1172  gradient_operator_int[d][idof][iquad] = phys_shape_grad[d];
1173  }
1174  }
1175  for (unsigned int idof=0; idof<n_soln_dofs_ext; ++idof) {
1176  interpolation_operator_ext[idof][iquad] = soln_ext.finite_element.shape_value(idof,unit_quad_pts_ext[iquad]);
1177  dealii::Tensor<1,dim,real> ref_shape_grad = soln_ext.finite_element.shape_grad(idof,unit_quad_pts_ext[iquad]);
1178  const Tensor1D phys_shape_grad = vmult(jac_inv_tran_ext, ref_shape_grad);
1179  for (int d=0;d<dim;++d) {
1180  gradient_operator_ext[d][idof][iquad] = phys_shape_grad[d];
1181  }
1182  }
1183 
1184  } else {
1185  for (unsigned int idof=0; idof<n_soln_dofs_int; ++idof) {
1186  interpolation_operator_int[idof][iquad] = soln_int.finite_element.shape_value(idof,unit_quad_pts_int[iquad]);
1187  }
1188  for (unsigned int idof=0; idof<n_soln_dofs_ext; ++idof) {
1189  interpolation_operator_ext[idof][iquad] = soln_ext.finite_element.shape_value(idof,unit_quad_pts_ext[iquad]);
1190  }
1191  for (int d=0;d<dim;++d) {
1192  for (unsigned int idof=0; idof<n_soln_dofs_int; ++idof) {
1193  const unsigned int istate = soln_int.finite_element.system_to_component_index(idof).first;
1194  gradient_operator_int[d][idof][iquad] = fe_values_int.shape_grad_component(idof, iquad, istate)[d];
1195  }
1196  for (unsigned int idof=0; idof<n_soln_dofs_ext; ++idof) {
1197  const unsigned int istate = soln_ext.finite_element.system_to_component_index(idof).first;
1198  gradient_operator_ext[d][idof][iquad] = fe_values_ext.shape_grad_component(idof, iquad, istate)[d];
1199  }
1200  }
1201  surface_jac_det_int = fe_values_int.JxW(iquad)/face_quadrature_int.weight(iquad);
1202  surface_jac_det_ext = fe_values_ext.JxW(iquad)/face_quadrature_ext.weight(iquad);
1203 
1204  phys_unit_normal_int[iquad] = fe_values_int.normal_vector(iquad);
1205  phys_unit_normal_ext[iquad] = -phys_unit_normal_int[iquad]; // Must use opposite normal to be consistent with explicit
1206 
1207  }
1208  // When the cells do not have the same coarseness, their surface Jacobians will not be the same.
1209  // Therefore, we must use the Jacobians coming from the smaller face since it accurately represents
1210  // the surface area being computed.
1211  //
1212  // Note that it is possible for the smaller cell to have larger surface Jacobians than the larger cell,
1213  // but not at the same physical location.
1214  if ( surface_jac_det_int > surface_jac_det_ext) {
1215  // Interior is the large face.
1216  // Exterior is the small face.
1217  surface_jac_det[iquad] = surface_jac_det_ext;
1218  //phys_unit_normal_ext[iquad] = -phys_unit_normal_int[iquad];
1219  } else {
1220  // Exterior is the large face.
1221  // Interior is the small face.
1222  surface_jac_det[iquad] = surface_jac_det_int;
1223  //phys_unit_normal_int[iquad] = -phys_unit_normal_ext[iquad];
1224  }
1225 
1226  faceJxW[iquad] = surface_jac_det[iquad] * face_quadrature_int.weight(iquad);
1227  }
1228 
1229  // Interpolate solution
1230  std::vector<State> soln_int_at_q = soln_int.evaluate_values(unit_quad_pts_int);
1231  std::vector<State> soln_ext_at_q = soln_ext.evaluate_values(unit_quad_pts_ext);
1232 
1233  // Interpolate solution gradient
1234  std::vector<DirectionalState> soln_grad_int(n_face_quad_pts), soln_grad_ext(n_face_quad_pts);
1235  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1236 
1237  for (int istate=0; istate<nstate; istate++) {
1238  soln_grad_int[iquad][istate] = 0;
1239  soln_grad_ext[iquad][istate] = 0;
1240  }
1241 
1242  for (unsigned int idof=0; idof<n_soln_dofs_int; ++idof) {
1243  const unsigned int istate = soln_int.finite_element.system_to_component_index(idof).first;
1244  for (int d=0;d<dim;++d) {
1245  soln_grad_int[iquad][istate][d] += soln_int.coefficients[idof] * gradient_operator_int[d][idof][iquad];
1246  }
1247  }
1248  for (unsigned int idof=0; idof<n_soln_dofs_ext; ++idof) {
1249  const unsigned int istate = soln_ext.finite_element.system_to_component_index(idof).first;
1250  for (int d=0;d<dim;++d) {
1251  soln_grad_ext[iquad][istate][d] += soln_ext.coefficients[idof] * gradient_operator_ext[d][idof][iquad];
1252  }
1253  }
1254  }
1255 
1256  // Assemble BR2 gradient correction right-hand side
1257 
1259  if (this->all_parameters->diss_num_flux_type == DissFlux::bassi_rebay_2) {
1260 
1261  const dealii::FiniteElement<dim> &base_fe_int = soln_int.finite_element.get_sub_fe(0,1);
1262  const dealii::FiniteElement<dim> &base_fe_ext = soln_ext.finite_element.get_sub_fe(0,1);
1263  const unsigned int n_base_dofs_int = base_fe_int.n_dofs_per_cell();
1264  const unsigned int n_base_dofs_ext = base_fe_ext.n_dofs_per_cell();
1265 
1266  // Obtain solution jump
1267  std::vector<DirectionalState> soln_jump_int(n_face_quad_pts);
1268  std::vector<DirectionalState> soln_jump_ext(n_face_quad_pts);
1269  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1270  for (int s=0; s<nstate; s++) {
1271  for (int d=0; d<dim; d++) {
1272  soln_jump_int[iquad][s][d] = (soln_int_at_q[iquad][s] - soln_ext_at_q[iquad][s]) * phys_unit_normal_int[iquad][d];
1273  soln_jump_ext[iquad][s][d] = (soln_ext_at_q[iquad][s] - soln_int_at_q[iquad][s]) * (-phys_unit_normal_int[iquad][d]);
1274  }
1275  }
1276  }
1277 
1278 
1279  // RHS of R lifting operator.
1280  std::vector<State> lifting_op_R_rhs_int(n_base_dofs_int);
1281  for (unsigned int idof_base=0; idof_base<n_base_dofs_int; ++idof_base) {
1282  for (int s=0; s<nstate; s++) {
1283 
1284  const unsigned int idof = soln_int.finite_element.component_to_system_index(s, idof_base);
1285  lifting_op_R_rhs_int[idof_base][s] = 0.0;
1286 
1287  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1288 
1289  for (int d=0; d<dim; ++d) {
1290  const double basis_average = 0.5 * (interpolation_operator_int[idof][iquad] + 0.0);
1291  lifting_op_R_rhs_int[idof_base][s] -= soln_jump_int[iquad][s][d] * basis_average * faceJxW[iquad];
1292  }
1293  }
1294 
1295  }
1296  }
1297 
1298  std::vector<State> lifting_op_R_rhs_ext(n_base_dofs_ext);
1299  for (unsigned int idof_base=0; idof_base<n_base_dofs_ext; ++idof_base) {
1300  for (int s=0; s<nstate; s++) {
1301 
1302  const unsigned int idof = soln_ext.finite_element.component_to_system_index(s, idof_base);
1303  lifting_op_R_rhs_ext[idof_base][s] = 0.0;
1304 
1305  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1306 
1307  for (int d=0; d<dim; ++d) {
1308  const double basis_average = 0.5 * ( 0.0 + interpolation_operator_ext[idof][iquad] );
1309  lifting_op_R_rhs_ext[idof_base][s] -= soln_jump_ext[iquad][s][d] * basis_average * faceJxW[iquad];
1310  }
1311  }
1312 
1313  }
1314  }
1315 
1316  std::vector<State> soln_grad_corr_int(n_base_dofs_int), soln_grad_corr_ext(n_base_dofs_ext);
1317  compute_br2_correction<dim,nspecies,nstate,real2>(soln_int.finite_element, metric_int, lifting_op_R_rhs_int, soln_grad_corr_int);
1318  compute_br2_correction<dim,nspecies,nstate,real2>(soln_ext.finite_element, metric_ext, lifting_op_R_rhs_ext, soln_grad_corr_ext);
1319 
1320  correct_the_gradient<dim,nspecies,nstate,real2>( soln_grad_corr_int, soln_int.finite_element, soln_jump_int, interpolation_operator_int, gradient_operator_int, soln_grad_int);
1321  correct_the_gradient<dim,nspecies,nstate,real2>( soln_grad_corr_ext, soln_ext.finite_element, soln_jump_ext, interpolation_operator_ext, gradient_operator_ext, soln_grad_ext);
1322 
1323  }
1324 
1325 
1326  State conv_num_flux_dot_n;
1327  State diss_soln_num_flux; // u*
1328  State diss_auxi_num_flux_dot_n; // sigma*
1329 
1330  DirectionalState diss_flux_jump_int; // u*-u_int
1331  DirectionalState diss_flux_jump_ext; // u*-u_ext
1332 
1333  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1334 
1335  // Evaluate physical convective flux, physical dissipative flux, and source term
1336  conv_num_flux_dot_n = conv_num_flux.evaluate_flux(soln_int_at_q[iquad], soln_ext_at_q[iquad], phys_unit_normal_int[iquad]);
1337  diss_soln_num_flux = diss_num_flux.evaluate_solution_flux(soln_int_at_q[iquad], soln_ext_at_q[iquad], phys_unit_normal_int[iquad]);
1338 
1339  DirectionalState diss_soln_jump_int, diss_soln_jump_ext;
1340  for (int s=0; s<nstate; s++) {
1341  for (int d=0; d<dim; d++) {
1342  diss_soln_jump_int[s][d] = (diss_soln_num_flux[s] - soln_int_at_q[iquad][s]) * phys_unit_normal_int[iquad][d];
1343  diss_soln_jump_ext[s][d] = (diss_soln_num_flux[s] - soln_ext_at_q[iquad][s]) * phys_unit_normal_ext[iquad][d];
1344  }
1345  }
1346  diss_flux_jump_int = physics.dissipative_flux (soln_int_at_q[iquad], diss_soln_jump_int, current_cell_index);
1347  diss_flux_jump_ext = physics.dissipative_flux (soln_ext_at_q[iquad], diss_soln_jump_ext, neighbor_cell_index);
1348 
1350  const DirectionalState artificial_diss_flux_jump_int = DGBaseState<dim,nspecies,nstate,real,MeshType>::artificial_dissip->calc_artificial_dissipation_flux(soln_int_at_q[iquad], diss_soln_jump_int,artificial_diss_coeff_at_q[iquad]);
1351  const DirectionalState artificial_diss_flux_jump_ext = DGBaseState<dim,nspecies,nstate,real,MeshType>::artificial_dissip->calc_artificial_dissipation_flux(soln_ext_at_q[iquad], diss_soln_jump_ext,artificial_diss_coeff_at_q[iquad]);
1352  for (int s=0; s<nstate; s++) {
1353  diss_flux_jump_int[s] += artificial_diss_flux_jump_int[s];
1354  diss_flux_jump_ext[s] += artificial_diss_flux_jump_ext[s];
1355  }
1356  }
1357 
1358 
1359  diss_auxi_num_flux_dot_n = diss_num_flux.evaluate_auxiliary_flux(
1360  current_cell_index,
1361  neighbor_cell_index,
1362  artificial_diss_coeff_at_q[iquad],
1363  artificial_diss_coeff_at_q[iquad],
1364  soln_int_at_q[iquad], soln_ext_at_q[iquad],
1365  soln_grad_int[iquad], soln_grad_ext[iquad],
1366  soln_int_at_q[iquad], soln_ext_at_q[iquad],
1367  soln_grad_int[iquad], soln_grad_ext[iquad],
1368  phys_unit_normal_int[iquad], penalty, false);
1369 
1370  // From test functions associated with interior cell point of view
1371  for (unsigned int itest_int=0; itest_int<n_soln_dofs_int; ++itest_int) {
1372  real2 rhs = 0.0;
1373  const unsigned int istate = soln_int.finite_element.system_to_component_index(itest_int).first;
1374 
1375  const real2 JxW_iquad = faceJxW[iquad];
1376  // Convection
1377  rhs = rhs - interpolation_operator_int[itest_int][iquad] * conv_num_flux_dot_n[istate] * JxW_iquad;
1378  // Diffusive
1379  rhs = rhs - interpolation_operator_int[itest_int][iquad] * diss_auxi_num_flux_dot_n[istate] * JxW_iquad;
1380  for (int d=0;d<dim;++d) {
1381  rhs = rhs + gradient_operator_int[d][itest_int][iquad] * diss_flux_jump_int[istate][d] * JxW_iquad;
1382  }
1383 
1384  rhs_int[itest_int] += rhs;
1385  dual_dot_residual += dual_int[itest_int]*rhs;
1386  }
1387 
1388  // From test functions associated with neighbor cell point of view
1389  for (unsigned int itest_ext=0; itest_ext<n_soln_dofs_ext; ++itest_ext) {
1390  real2 rhs = 0.0;
1391  const unsigned int istate = soln_ext.finite_element.system_to_component_index(itest_ext).first;
1392 
1393  const real2 JxW_iquad = faceJxW[iquad];
1394  // Convection
1395  rhs = rhs - interpolation_operator_ext[itest_ext][iquad] * (-conv_num_flux_dot_n[istate]) * JxW_iquad;
1396  // Diffusive
1397  rhs = rhs - interpolation_operator_ext[itest_ext][iquad] * (-diss_auxi_num_flux_dot_n[istate]) * JxW_iquad;
1398  for (int d=0;d<dim;++d) {
1399  rhs = rhs + gradient_operator_ext[d][itest_ext][iquad] * diss_flux_jump_ext[istate][d] * JxW_iquad;
1400  }
1401 
1402  rhs_ext[itest_ext] += rhs;
1403  dual_dot_residual += dual_ext[itest_ext]*rhs;
1404  }
1405  } // Quadrature point loop
1406 
1407 }
1408 
1409 
1410 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
1411 template <typename real2>
1413  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
1414  const dealii::types::global_dof_index current_cell_index,
1415  const LocalSolution<real2, dim, nspecies, nstate> &local_solution,
1416  const LocalSolution<real2, dim, nspecies, dim> &local_metric,
1417  const std::vector<real> &local_dual,
1418  const dealii::Quadrature<dim> &quadrature,
1420  std::vector<real2> &rhs, real2 &dual_dot_residual,
1421  const bool compute_metric_derivatives,
1422  const dealii::FEValues<dim,dim> &fe_values_vol)
1423 {
1424  (void) current_cell_index;
1425  using State = State<real2, nstate>;
1426  using DirectionalState = DirectionalState<real2, dim, nstate>;
1427  using Tensor2D = dealii::Tensor<2,dim,real2>;
1428 
1429  const unsigned int n_quad_pts = quadrature.size();
1430  const unsigned int n_soln_dofs = local_solution.finite_element.dofs_per_cell;
1431 
1432  for (unsigned int itest=0; itest<n_soln_dofs; ++itest) {
1433  rhs[itest] = 0;
1434  }
1435  dual_dot_residual = 0.0;
1436 
1437  const std::vector<dealii::Point<dim>> &points = quadrature.get_points ();
1438 
1439  const unsigned int n_metric_dofs = local_metric.finite_element.dofs_per_cell;
1440 
1441  // Evaluate metric terms
1442  std::vector<Tensor2D> metric_jacobian;
1443  if (compute_metric_derivatives) metric_jacobian = evaluate_metric_jacobian ( points, local_metric);
1444  std::vector<real2> jac_det(n_quad_pts);
1445  std::vector<Tensor2D> jac_inv_tran(n_quad_pts);
1446  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1447 
1448  if (compute_metric_derivatives) {
1449  const real2 jacobian_determinant = dealii::determinant(metric_jacobian[iquad]);
1450  jac_det[iquad] = jacobian_determinant;
1451 
1452  const Tensor2D jacobian_transpose_inverse = dealii::transpose(dealii::invert(metric_jacobian[iquad]));
1453  jac_inv_tran[iquad] = jacobian_transpose_inverse;
1454  } else {
1455  jac_det[iquad] = fe_values_vol.JxW(iquad) / quadrature.weight(iquad);
1456  }
1457  }
1458 #ifdef KOPRIVA_METRICS_VOL
1459  auto old_jac_inv_tran = jac_inv_tran;
1460  auto old_jac_det = jac_det;
1461  if constexpr (dim != 1) {
1462  evaluate_covariant_metric_jacobian<dim,nspecies,real2> ( quadrature, local_metric, jac_inv_tran, jac_det);
1463  }
1464  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1465  if (abs(old_jac_det[iquad] - jac_det[iquad])/abs(old_jac_det[iquad]) > 1e-10) {
1466  std::cout << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
1467  std::cout << "Not the same jac det, iquad " << iquad << std::endl;
1468  std::cout << old_jac_det[iquad] << std::endl;
1469  std::cout << jac_det[iquad] << std::endl;
1470  }
1471  }
1472 #endif
1473 
1474  // Build operators.
1475  const std::vector<dealii::Point<dim,double>> &unit_quad_pts = quadrature.get_points();
1476  dealii::FullMatrix<real> interpolation_operator(n_soln_dofs,n_quad_pts);
1477  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
1478  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1479  interpolation_operator[idof][iquad] = local_solution.finite_element.shape_value(idof,unit_quad_pts[iquad]);
1480  }
1481  }
1482  // Might want to have the dimension as the innermost index
1483  // Need a contiguous 2d-array structure
1484  // std::array<dealii::FullMatrix<real2>,dim> gradient_operator;
1485  // for (int d=0;d<dim;++d) {
1486  // gradient_operator[d].reinit(n_soln_dofs, n_quad_pts);
1487  // }
1488  std::array<dealii::FullMatrix<real2>,dim> gradient_operator;
1489  for (int d=0;d<dim;++d) {
1490  gradient_operator[d].reinit(dealii::TableIndices<2>(n_soln_dofs, n_quad_pts));
1491  }
1492  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
1493  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1494  if (compute_metric_derivatives) {
1495  //const dealii::Tensor<1,dim,real2> phys_shape_grad = dealii::contract<1,0>(jac_inv_tran[iquad], fe_soln.shape_grad(idof,points[iquad]));
1496  const dealii::Tensor<1,dim,real2> ref_shape_grad = local_solution.finite_element.shape_grad(idof,points[iquad]);
1497  dealii::Tensor<1,dim,real2> phys_shape_grad;
1498  for (int dr=0;dr<dim;++dr) {
1499  phys_shape_grad[dr] = 0.0;
1500  for (int dc=0;dc<dim;++dc) {
1501  phys_shape_grad[dr] += jac_inv_tran[iquad][dr][dc] * ref_shape_grad[dc];
1502  }
1503  }
1504  for (int d=0;d<dim;++d) {
1505  gradient_operator[d][idof][iquad] = phys_shape_grad[d];
1506  }
1507 
1508  // Exact mapping
1509  // for (int d=0;d<dim;++d) {
1510  // const unsigned int istate = fe_soln.system_to_component_index(idof).first;
1511  // gradient_operator[d][idof][iquad] = fe_values_vol.shape_grad_component(idof, iquad, istate)[d];
1512  // }
1513  } else {
1514  for (int d=0;d<dim;++d) {
1515  const unsigned int istate = local_solution.finite_element.system_to_component_index(idof).first;
1516  gradient_operator[d][idof][iquad] = fe_values_vol.shape_grad_component(idof, iquad, istate)[d];
1517  }
1518  }
1519  }
1520  }
1521 
1522 
1523 
1524  //const real2 cell_diameter = fe_values_.get_cell()->diameter();
1525  // real2 cell_volume = 0.0;
1526  // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1527 
1528  // const real2 JxW_iquad = jac_det[iquad] * quadrature.weight(iquad);
1529 
1530  // cell_volume = cell_volume + JxW_iquad;
1531  // }
1532  //const real2 cell_diameter = pow(cell_volume,1.0/dim);
1533  //const real2 artificial_diss_coeff = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1534  // this->discontinuity_sensor(cell_diameter, soln_coeff, fe_soln)
1535  // : 0.0;
1536  const real2 artificial_diss_coeff = this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ?
1537  this->artificial_dissipation_coeffs[current_cell_index]
1538  : 0.0;
1539  (void) artificial_diss_coeff;
1540 
1541  typename dealii::DoFHandler<dim>::active_cell_iterator artificial_dissipation_cell(
1542  this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation));
1543  const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell;
1544  std::vector<dealii::types::global_dof_index> dof_indices_artificial_dissipation(n_dofs_arti_diss);
1545  artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation);
1546 /*
1547  std::vector<real> artificial_diss_coeff_at_q(n_quad_pts);
1548  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1549  artificial_diss_coeff_at_q[iquad] = 0.0;
1550 
1551  if ( this->all_parameters->artificial_dissipation_param.add_artificial_dissipation ) {
1552  const dealii::Point<dim,real> point = unit_quad_pts[iquad];
1553  for (unsigned int idof=0; idof<n_dofs_arti_diss; ++idof) {
1554  const unsigned int index = dof_indices_artificial_dissipation[idof];
1555  artificial_diss_coeff_at_q[iquad] += this->artificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point);
1556  }
1557  }
1558  }
1559 
1560 */
1561 
1562  std::vector<real2> artificial_diss_coeff_at_q(n_quad_pts);
1563  real2 arti_diss = this->discontinuity_sensor(quadrature, local_solution.coefficients, local_solution.finite_element, jac_det);
1564  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad)
1565  {
1566  artificial_diss_coeff_at_q[iquad] = arti_diss;
1567  /* dealii::Point<dim,real> point = unit_quad_pts[iquad];
1568  // Rescale over -1,1
1569  for (int d=0; d<dim; ++d)
1570  {
1571  point[d] = point[d]*2 - 1.0;
1572  }
1573  double gegenbauer_factor = 0.1;
1574  double gegenbauer = 1.0;
1575  for (int d=0; d<dim; ++d)
1576  {
1577  gegenbauer *= std::pow(1-point[d]*point[d], gegenbauer_factor);
1578  }
1579  artificial_diss_coeff_at_q[iquad] = arti_diss * gegenbauer;*/
1580  }
1581 
1582  std::vector<State> soln_at_q(n_quad_pts);
1583  std::vector<DirectionalState> soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros
1584 
1585  std::vector<DirectionalState> conv_phys_flux_at_q(n_quad_pts);
1586  std::vector<DirectionalState> diss_phys_flux_at_q(n_quad_pts);
1587  std::vector<State> source_at_q;
1588  std::vector<State> physical_source_at_q;
1589 
1590  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1591  for (int istate=0; istate<nstate; istate++) {
1592  soln_at_q[iquad][istate] = 0;
1593  soln_grad_at_q[iquad][istate] = 0;
1594  }
1595  for (unsigned int idof=0; idof<n_soln_dofs; ++idof) {
1596  const unsigned int istate = local_solution.finite_element.system_to_component_index(idof).first;
1597  soln_at_q[iquad][istate] += local_solution.coefficients[idof] * interpolation_operator[idof][iquad];
1598  for (int d=0;d<dim;++d) {
1599  soln_grad_at_q[iquad][istate][d] += local_solution.coefficients[idof] * gradient_operator[d][idof][iquad];
1600  }
1601  }
1602  conv_phys_flux_at_q[iquad] = physics.convective_flux (soln_at_q[iquad]);
1603  diss_phys_flux_at_q[iquad] = physics.dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index);
1604 
1605  if(physics.has_nonzero_physical_source){
1606  physical_source_at_q.resize(n_quad_pts);
1607  dealii::Point<dim,real2> ad_points;
1608  for (int d=0;d<dim;++d) { ad_points[d] = 0.0;}
1609  for (unsigned int idof = 0; idof < n_metric_dofs; ++idof) {
1610  const int iaxis = local_metric.finite_element.system_to_component_index(idof).first;
1611  ad_points[iaxis] += local_metric.coefficients[idof] * local_metric.finite_element.shape_value(idof,unit_quad_pts[iquad]);
1612  }
1613  physical_source_at_q[iquad] = physics.physical_source_term (ad_points, soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index);
1614  }
1615 
1617  const DirectionalState artificial_diss_phys_flux_at_q = this->artificial_dissip->calc_artificial_dissipation_flux(soln_at_q[iquad], soln_grad_at_q[iquad], artificial_diss_coeff_at_q[iquad]);
1618  for (int s=0; s<nstate; s++) {
1619  diss_phys_flux_at_q[iquad][s] += artificial_diss_phys_flux_at_q[s];
1620  }
1621  }
1622 
1624  source_at_q.resize(n_quad_pts);
1625  dealii::Point<dim,real2> ad_point;
1626  for (int d=0;d<dim;++d) { ad_point[d] = 0.0;}
1627  for (unsigned int idof = 0; idof < n_metric_dofs; ++idof) {
1628  const int iaxis = local_metric.finite_element.system_to_component_index(idof).first;
1629  ad_point[iaxis] += local_metric.coefficients[idof] * local_metric.finite_element.shape_value(idof,unit_quad_pts[iquad]);
1630  }
1631  source_at_q[iquad] = physics.source_term (ad_point, soln_at_q[iquad], this->current_time, current_cell_index);
1632  }
1633  }
1634 
1635  // Weak form
1636  // The right-hand side sends all the term to the side of the source term
1637  // Therefore,
1638  // \divergence ( Fconv + Fdiss ) = source
1639  // has the right-hand side
1640  // rhs = - \divergence( Fconv + Fdiss ) + source
1641  // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss
1642  // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side
1643  for (unsigned int itest=0; itest<n_soln_dofs; ++itest) {
1644 
1645  const unsigned int istate = local_solution.finite_element.system_to_component_index(itest).first;
1646 
1647  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1648 
1649  const real2 JxW_iquad = jac_det[iquad] * quadrature.weight(iquad);
1650 
1651  for (int d=0;d<dim;++d) {
1652  // Convective
1653  rhs[itest] = rhs[itest] + gradient_operator[d][itest][iquad] * conv_phys_flux_at_q[iquad][istate][d] * JxW_iquad;
1656  rhs[itest] = rhs[itest] + gradient_operator[d][itest][iquad] * diss_phys_flux_at_q[iquad][istate][d] * JxW_iquad;
1657  }
1658  // Physical source
1659  if(physics.has_nonzero_physical_source){
1660  rhs[itest] = rhs[itest] + interpolation_operator[itest][iquad]* physical_source_at_q[iquad][istate] * JxW_iquad;
1661  }
1662  // Source
1664  rhs[itest] = rhs[itest] + interpolation_operator[itest][iquad]* source_at_q[iquad][istate] * JxW_iquad;
1665  }
1666  }
1667  dual_dot_residual += local_dual[itest]*rhs[itest];
1668  }
1669 }
1670 
1671 
1672 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
1673 template <typename adtype>
1675  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
1676  const dealii::types::global_dof_index current_cell_index,
1677  const std::vector<adtype> &soln_coeffs,
1678  const dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_soln_coeffs*/,
1679  const std::vector<adtype> &metric_coeffs,
1680  const std::vector<real> &local_dual,
1681  const std::vector<dealii::types::global_dof_index> &soln_dofs_indices,
1682  const std::vector<dealii::types::global_dof_index> &metric_dofs_indices,
1683  const unsigned int poly_degree,
1684  const unsigned int grid_degree,
1686  OPERATOR::basis_functions<dim,2*dim> &/*soln_basis*/,
1687  OPERATOR::basis_functions<dim,2*dim> &/*flux_basis*/,
1688  OPERATOR::local_basis_stiffness<dim,2*dim> &/*flux_basis_stiffness*/,
1689  OPERATOR::vol_projection_operator<dim,2*dim> &/*soln_basis_projection_oper_int*/,
1690  OPERATOR::vol_projection_operator<dim,2*dim> &/*soln_basis_projection_oper_ext*/,
1693  std::array<std::vector<adtype>,dim> &/*mapping_support_points*/,
1694  dealii::hp::FEValues<dim,dim> &fe_values_collection_volume,
1695  dealii::hp::FEValues<dim,dim> &fe_values_collection_volume_lagrange,
1696  const dealii::FESystem<dim,dim> &fe_soln,
1697  std::vector<adtype> &rhs,
1698  dealii::Tensor<1,dim,std::vector<adtype>> &/*local_auxiliary_RHS*/,
1699  const bool /*compute_auxiliary_right_hand_side*/,
1700  adtype &dual_dot_residual)
1701 {
1702  // Current reference element related to this physical cell
1703  const int i_fele = cell->active_fe_index();
1704  const int i_quad = i_fele;
1705  const int i_mapp = 0;
1706  fe_values_collection_volume.reinit (cell, i_quad, i_mapp, i_fele);
1707  dealii::TriaIterator<dealii::CellAccessor<dim, dim>> cell_iterator = static_cast<dealii::TriaIterator<dealii::CellAccessor<dim, dim>> > (cell);
1708  fe_values_collection_volume_lagrange.reinit (cell_iterator, i_quad, i_mapp, i_fele);
1709 
1710  const dealii::FEValues<dim,dim> &fe_values_vol = fe_values_collection_volume.get_present_fe_values();
1711  const dealii::FEValues<dim,dim> &fe_values_lagrange = fe_values_collection_volume_lagrange.get_present_fe_values();
1712 
1713  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
1714  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
1715  const unsigned int n_soln_dofs = fe_soln.dofs_per_cell;
1716 
1717  dealii::Vector<real> local_rhs_dummy (n_soln_dofs);
1718  //Note the explicit is called first to set the max_dt_cell to a non-zero value.
1720  cell,
1721  current_cell_index,
1722  fe_values_vol,
1723  soln_dofs_indices,
1724  metric_dofs_indices,
1725  poly_degree, grid_degree,
1726  local_rhs_dummy,
1727  fe_values_lagrange);
1728 
1729  const dealii::Quadrature<dim> &quadrature = this->volume_quadrature_collection[i_quad];
1730 
1731  LocalSolution<adtype, dim, nspecies, nstate> local_solution(fe_soln);
1732  LocalSolution<adtype, dim, nspecies, dim> local_metric(fe_metric);
1733  for(unsigned int i=0; i<n_soln_dofs; ++i)
1734  {
1735  local_solution.coefficients[i] = soln_coeffs[i];
1736  }
1737  for(unsigned int i=0; i<n_metric_dofs; ++i)
1738  {
1739  local_metric.coefficients[i] = metric_coeffs[i];
1740  }
1741 
1742  const bool compute_metric_derivatives = true;
1743 
1744  assemble_volume_term<adtype>(
1745  cell,
1746  current_cell_index,
1747  local_solution, local_metric,
1748  local_dual,
1749  quadrature,
1750  physics,
1751  rhs, dual_dot_residual,
1752  compute_metric_derivatives, fe_values_vol);
1753 }
1754 
1755 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
1756 template <typename adtype>
1758  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
1759  const dealii::types::global_dof_index current_cell_index,
1760  const std::vector<adtype> &soln_coeffs,
1761  const dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_soln_coeffs*/,
1762  const std::vector<adtype> &metric_coeffs,
1763  const std::vector< real > &local_dual,
1764  const unsigned int face_number,
1765  const unsigned int boundary_id,
1769  const unsigned int /*poly_degree*/,
1770  const unsigned int /*grid_degree*/,
1771  OPERATOR::basis_functions<dim,2*dim> &/*soln_basis*/,
1772  OPERATOR::basis_functions<dim,2*dim> &/*flux_basis*/,
1773  OPERATOR::vol_projection_operator<dim,2*dim> &/*soln_basis_projection_oper_int*/,
1776  std::array<std::vector<adtype>,dim> &/*mapping_support_points*/,
1777  dealii::hp::FEFaceValues<dim,dim> &fe_values_collection_face_int,
1778  const dealii::FESystem<dim,dim> &fe_soln,
1779  const real penalty,
1780  std::vector<adtype> &rhs,
1781  dealii::Tensor<1,dim,std::vector<adtype>> &/*local_auxiliary_RHS*/,
1782  const bool /*compute_auxiliary_right_hand_side*/,
1783  adtype &dual_dot_residual)
1784 {
1785  // Current reference element related to this physical cell
1786  const int i_fele = cell->active_fe_index();
1787  const int i_quad = i_fele;
1788  const int i_mapp = 0;
1789 
1790  fe_values_collection_face_int.reinit (cell, face_number, i_quad, i_mapp, i_fele);
1791  const dealii::FEFaceValues<dim,dim> &fe_values_boundary = fe_values_collection_face_int.get_present_fe_values();
1792  const dealii::Quadrature<dim-1> quadrature = this->face_quadrature_collection[i_quad];
1793 
1794  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
1795  const unsigned int n_soln_dofs = fe_values_boundary.dofs_per_cell;
1796  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
1797  LocalSolution<adtype, dim, nspecies, nstate> local_solution(fe_soln);
1798  LocalSolution<adtype, dim, nspecies, dim> local_metric(fe_metric);
1799  for(unsigned int i=0; i<n_soln_dofs; ++i)
1800  {
1801  local_solution.coefficients[i] = soln_coeffs[i];
1802  }
1803  for(unsigned int i=0; i<n_metric_dofs; ++i)
1804  {
1805  local_metric.coefficients[i] = metric_coeffs[i];
1806  }
1807 
1808  const bool compute_metric_derivatives = true;
1809 
1810  assemble_boundary_term<adtype>(
1811  cell,
1812  current_cell_index,
1813  local_solution,
1814  local_metric,
1815  local_dual,
1816  face_number,
1817  boundary_id,
1818  physics,
1819  conv_num_flux,
1820  diss_num_flux,
1821  fe_values_boundary,
1822  penalty,
1823  quadrature,
1824  rhs,
1825  dual_dot_residual,
1826  compute_metric_derivatives);
1827 }
1828 
1829 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
1830 template <typename adtype>
1832  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
1833  typename dealii::DoFHandler<dim>::active_cell_iterator neighbor_cell,
1834  const dealii::types::global_dof_index current_cell_index,
1835  const dealii::types::global_dof_index neighbor_cell_index,
1836  const unsigned int iface,
1837  const unsigned int neighbor_iface,
1838  const std::vector<adtype> &soln_int,
1839  const std::vector<adtype> &soln_ext,
1840  const dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_soln_coeff_int*/,
1841  const dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_soln_coeff_ext*/,
1842  const std::vector<adtype> &metric_int,
1843  const std::vector<adtype> &metric_ext,
1844  const std::vector< double > &dual_int,
1845  const std::vector< double > &dual_ext,
1846  const unsigned int /*poly_degree_int*/,
1847  const unsigned int /*poly_degree_ext*/,
1848  const unsigned int /*grid_degree_int*/,
1849  const unsigned int /*grid_degree_ext*/,
1850  OPERATOR::basis_functions<dim,2*dim> &/*soln_basis_int*/,
1851  OPERATOR::basis_functions<dim,2*dim> &/*soln_basis_ext*/,
1852  OPERATOR::basis_functions<dim,2*dim> &/*flux_basis_int*/,
1853  OPERATOR::basis_functions<dim,2*dim> &/*flux_basis_ext*/,
1854  OPERATOR::local_basis_stiffness<dim,2*dim> &/*flux_basis_stiffness*/,
1855  OPERATOR::vol_projection_operator<dim,2*dim> &/*soln_basis_projection_oper_int*/,
1856  OPERATOR::vol_projection_operator<dim,2*dim> &/*soln_basis_projection_oper_ext*/,
1857  OPERATOR::metric_operators<adtype,dim,2*dim> &/*metric_oper_int*/,
1858  OPERATOR::metric_operators<adtype,dim,2*dim> &/*metric_oper_ext*/,
1860  std::array<std::vector<adtype>,dim> &/*mapping_support_points*/,
1864  dealii::hp::FEFaceValues<dim,dim> &fe_values_collection_face_int,
1865  dealii::hp::FEFaceValues<dim,dim> &fe_values_collection_face_ext,
1866  dealii::hp::FESubfaceValues<dim,dim> &fe_values_collection_subface,
1867  const dealii::FESystem<dim,dim> &fe_int,
1868  const dealii::FESystem<dim,dim> &fe_ext,
1869  const real penalty,
1870  std::vector<adtype> &rhs_int,
1871  std::vector<adtype> &rhs_ext,
1872  dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_rhs_int*/,
1873  dealii::Tensor<1,dim,std::vector<adtype>> &/*aux_rhs_ext*/,
1874  const bool /*compute_auxiliary_right_hand_side*/,
1875  adtype &dual_dot_residual,
1876  const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R,
1877  const bool is_a_subface,
1878  const unsigned int neighbor_i_subface)
1879 {
1880  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
1881  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
1882  const unsigned int n_soln_dofs_int = fe_int.dofs_per_cell;
1883  const unsigned int n_soln_dofs_ext = fe_ext.dofs_per_cell;
1884 
1885  const int i_fele = cell->active_fe_index();
1886  const int i_quad = i_fele;
1887  const int i_mapp = 0;
1888  const int i_fele_n = neighbor_cell->active_fe_index();
1889  const int i_quad_n = i_fele_n;
1890  const int i_mapp_n = 0;
1891 
1892  fe_values_collection_face_int.reinit (cell, iface, i_quad, i_mapp, i_fele);
1893  const dealii::FEFaceValues<dim,dim> &fe_values_face_int = fe_values_collection_face_int.get_present_fe_values();
1894  const dealii::Quadrature<dim-1> &face_quadrature = this->face_quadrature_collection[(i_quad_n > i_quad) ? i_quad_n : i_quad]; // Use larger quadrature order on the face
1895 
1896  LocalSolution<adtype, dim, nspecies, nstate> local_soln_int(fe_int);
1897  LocalSolution<adtype, dim, nspecies, nstate> local_soln_ext(fe_ext);
1898  LocalSolution<adtype, dim, nspecies, dim> local_metric_int(fe_metric);
1899  LocalSolution<adtype, dim, nspecies, dim> local_metric_ext(fe_metric);
1900 
1901  for (unsigned int idof = 0; idof < n_soln_dofs_int; ++idof) {
1902  local_soln_int.coefficients[idof] = soln_int[idof];
1903  }
1904  for (unsigned int idof = 0; idof < n_soln_dofs_ext; ++idof) {
1905  local_soln_ext.coefficients[idof] = soln_ext[idof];
1906  }
1907  for (unsigned int idof = 0; idof < n_metric_dofs; ++idof) {
1908  local_metric_int.coefficients[idof] = metric_int[idof];
1909  local_metric_ext.coefficients[idof] = metric_ext[idof];
1910  }
1911 
1912  std::pair<unsigned int, int> face_subface_int = std::make_pair(iface, -1);
1913 
1914  const auto face_data_set_int = dealii::QProjector<dim>::DataSetDescriptor::face(
1915  dealii::ReferenceCell::get_hypercube(dim),
1916  iface,
1917  cell->face_orientation(iface),
1918  cell->face_flip(iface),
1919  cell->face_rotation(iface),
1920  face_quadrature.size());
1921 
1922  if(is_a_subface)
1923  {
1924  fe_values_collection_subface.reinit (neighbor_cell, neighbor_iface, neighbor_i_subface, i_quad_n, i_mapp_n, i_fele_n);
1925  const dealii::FESubfaceValues<dim,dim> &fe_values_face_ext = fe_values_collection_subface.get_present_fe_values();
1926  std::pair<unsigned int, int> face_subface_ext = std::make_pair(neighbor_iface, (int)neighbor_i_subface);
1927  const auto face_data_set_ext = dealii::QProjector<dim>::DataSetDescriptor::subface (
1928  dealii::ReferenceCell::get_hypercube(dim),
1929  neighbor_iface,
1930  neighbor_i_subface,
1931  neighbor_cell->face_orientation(neighbor_iface),
1932  neighbor_cell->face_flip(neighbor_iface),
1933  neighbor_cell->face_rotation(neighbor_iface),
1934  face_quadrature.size(),
1935  neighbor_cell->subface_case(neighbor_iface));
1936  assemble_face_term<adtype>(
1937  cell,
1938  neighbor_cell,
1939  current_cell_index,
1940  neighbor_cell_index,
1941  local_soln_int, local_soln_ext, local_metric_int, local_metric_ext,
1942  dual_int,
1943  dual_ext,
1944  face_subface_int,
1945  face_subface_ext,
1946  face_data_set_int,
1947  face_data_set_ext,
1948  physics,
1949  conv_num_flux,
1950  diss_num_flux,
1951  fe_values_face_int,
1952  fe_values_face_ext,
1953  penalty,
1954  face_quadrature,
1955  rhs_int,
1956  rhs_ext,
1957  dual_dot_residual,
1958  compute_dRdW, compute_dRdX, compute_d2R);
1959  }
1960  else
1961  {
1962  fe_values_collection_face_ext.reinit (neighbor_cell, neighbor_iface, i_quad_n, i_mapp_n, i_fele_n);
1963  const dealii::FEFaceValues<dim,dim> &fe_values_face_ext = fe_values_collection_face_ext.get_present_fe_values();
1964  std::pair<unsigned int, int> face_subface_ext = std::make_pair(neighbor_iface, -1);
1965  const auto face_data_set_ext = dealii::QProjector<dim>::DataSetDescriptor::face (
1966  dealii::ReferenceCell::get_hypercube(dim),
1967  neighbor_iface,
1968  neighbor_cell->face_orientation(neighbor_iface),
1969  neighbor_cell->face_flip(neighbor_iface),
1970  neighbor_cell->face_rotation(neighbor_iface),
1971  face_quadrature.size());
1972  assemble_face_term<adtype>(
1973  cell,
1974  neighbor_cell,
1975  current_cell_index,
1976  neighbor_cell_index,
1977  local_soln_int, local_soln_ext, local_metric_int, local_metric_ext,
1978  dual_int,
1979  dual_ext,
1980  face_subface_int,
1981  face_subface_ext,
1982  face_data_set_int,
1983  face_data_set_ext,
1984  physics,
1985  conv_num_flux,
1986  diss_num_flux,
1987  fe_values_face_int,
1988  fe_values_face_ext,
1989  penalty,
1990  face_quadrature,
1991  rhs_int,
1992  rhs_ext,
1993  dual_dot_residual,
1994  compute_dRdW, compute_dRdX, compute_d2R);
1995  }
1996 
1997 }
1998 
1999 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
2000 void DGWeak<dim,nspecies,nstate,real,MeshType>::assemble_auxiliary_residual (const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/)
2001 {
2002  //Do Nothing.
2003 }
2004 
2005 template <int dim, int nspecies, int nstate, typename real, typename MeshType>
2007 {
2008  if(compute_d2R)
2009  this->dual.reinit(this->locally_owned_dofs, this->ghost_dofs, this->mpi_communicator);
2010 }
2011 
2012 #if PHILIP_SPECIES==1
2013  // Define a sequence of indices representing the range [1, 6]
2014  #define POSSIBLE_NSTATE (1)(2)(3)(4)(5)(6)
2015 
2016  // using default MeshType = Triangulation
2017  // 1D: dealii::Triangulation<dim>;
2018  // Otherwise: dealii::parallel::distributed::Triangulation<dim>;
2019 
2020  // Define a macro to instantiate with Meshtype = Triangulation or Shared Triangulation
2021  #define INSTANTIATE_TRIA(r, data, nstate) \
2022  template class DGWeak <PHILIP_DIM, PHILIP_SPECIES, nstate, double, dealii::Triangulation<PHILIP_DIM>>; \
2023  template class DGWeak <PHILIP_DIM, PHILIP_SPECIES, nstate, double, dealii::parallel::shared::Triangulation<PHILIP_DIM>>;
2024  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_TRIA, _, POSSIBLE_NSTATE)
2025 
2026  // Define a macro to instantiate with distributed triangulation
2027  #define INSTANTIATE_DISTRIBUTED(r, data, nstate) \
2028  template class DGWeak <PHILIP_DIM, PHILIP_SPECIES, nstate, double, dealii::parallel::distributed::Triangulation<PHILIP_DIM>>;
2029  #if PHILIP_DIM!=1
2030  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_DISTRIBUTED, _, POSSIBLE_NSTATE)
2031  #endif
2032 #else
2035  #if PHILIP_DIM!=1
2037  #endif
2038 #endif
2039 } // PHiLiP namespace
virtual 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
Physical source term that does require differentiation.
Definition: physics.cpp:252
virtual std::array< real, nstate > evaluate_solution_flux(const std::array< real, nstate > &soln_int, const std::array< real, nstate > &soln_ext, const dealii::Tensor< 1, dim, real > &normal_int) const =0
Solution flux at the interface.
dealii::LinearAlgebra::distributed::Vector< double > artificial_dissipation_c0
Artificial dissipation coefficients.
Definition: dg_base.hpp:1196
void assemble_volume_term_explicit(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::FEValues< dim, dim > &fe_values_volume, const std::vector< dealii::types::global_dof_index > &current_dofs_indices, const std::vector< dealii::types::global_dof_index > &metric_dof_indices, const unsigned int poly_degree, const unsigned int grid_degree, dealii::Vector< real > &current_cell_rhs, const dealii::FEValues< dim, dim > &fe_values_lagrange)
Evaluate the integral over the cell volume.
Definition: weak_dg.cpp:378
std::array< real, nstate > evaluate_flux(const std::array< real, nstate > &soln_int, const std::array< real, nstate > &soln_ext, const dealii::Tensor< 1, dim, real > &normal1) const
Returns the convective numerical flux at an interface.
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
Class to store local solution coefficients and provide evaluation functions.
const dealii::FE_Q< dim > fe_q_artificial_dissipation
Continuous distribution of artificial dissipation.
Definition: dg_base.hpp:1190
virtual std::array< dealii::Tensor< 1, dim, real >, nstate > convective_flux(const std::array< real, nstate > &solution) const =0
Convective fluxes that will be differentiated once in space.
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
Definition: dg_base.hpp:1259
dealii::IndexSet ghost_dofs
Locally relevant ghost degrees of freedom.
Definition: dg_base.hpp:399
std::shared_ptr< ArtificialDissipationBase< dim, nspecies, nstate > > artificial_dissip
Link to Artificial dissipation class (with three dissipation types, depending on the input)...
dealii::hp::QCollection< dim-1 > face_quadrature_collection
Quadrature used to evaluate face integrals.
Definition: dg_base.hpp:1133
Base class of numerical flux associated with dissipation.
Files for the baseline physics.
Definition: ADTypes.hpp:10
const bool has_nonzero_physical_source
Flag to signal that physical source term is non-zero.
Definition: physics.h:62
dealii::DoFHandler< dim > dof_handler_artificial_dissipation
Degrees of freedom handler for C0 artificial dissipation.
Definition: dg_base.hpp:1193
ManufacturedSolutionParam manufactured_solution_param
Associated manufactured solution parameters.
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
Definition: dg_base.hpp:1178
const int nstate
Number of state variables.
Definition: dg_base.hpp:96
DGWeak class templated on the number of state variables.
Definition: weak_dg.hpp:17
virtual std::array< real, nstate > source_term(const dealii::Point< dim, real > &pos, const std::array< real, nstate > &solution, const real current_time, const dealii::types::global_dof_index cell_index) const =0
Artificial dissipative fluxes that will be differentiated ONCE in space.
dealii::hp::QCollection< dim > volume_quadrature_collection
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:1131
virtual std::array< real, nstate > evaluate_auxiliary_flux(const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index_, const real artificial_diss_coeff_int, const real artificial_diss_coeff_ext_, const std::array< real, nstate > &soln_int, const std::array< real, nstate > &soln_ext, const std::array< dealii::Tensor< 1, dim, real >, nstate > &soln_grad_int, const std::array< dealii::Tensor< 1, dim, real >, nstate > &soln_grad_ext_, const std::array< real, nstate > &filtered_soln_int, const std::array< real, nstate > &filtered_soln_ext, const std::array< dealii::Tensor< 1, dim, real >, nstate > &filtered_soln_grad_int, const std::array< dealii::Tensor< 1, dim, real >, nstate > &filtered_soln_grad_ext_, const dealii::Tensor< 1, dim, real > &normal_int, const real &penalty, const bool on_boundary, const int boundary_type=0) const =0
Auxiliary flux at the interface.
DGWeak(const Parameters::AllParameters *const parameters_input, const unsigned int degree, const unsigned int max_degree_input, const unsigned int grid_degree_input, const std::shared_ptr< Triangulation > triangulation_input)
Constructor.
Definition: weak_dg.cpp:368
Main parameter class that contains the various other sub-parameter classes.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
dealii::Vector< double > cell_volume
Time it takes for the maximum wavespeed to cross the cell domain.
Definition: dg_base.hpp:454
DissipativeNumericalFlux
Possible dissipative numerical flux types.
void assemble_auxiliary_residual(const bool, const bool, const bool)
Assembles the auxiliary equations&#39; residuals and solves for the auxiliary variables.
Definition: weak_dg.cpp:2000
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: dg_base.hpp:91
virtual void boundary_face_values_viscous_flux(const int, const dealii::Point< dim, real > &, const dealii::Tensor< 1, dim, real > &, const std::array< real, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, const std::array< real, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, std::array< real, nstate > &, std::array< dealii::Tensor< 1, dim, real >, nstate > &) const
Evaluates boundary values and gradients on the other side of the face for the viscous flux...
Definition: physics.cpp:230
MPI_Comm mpi_communicator
MPI communicator.
Definition: dg_base.hpp:1258
dealii::IndexSet locally_owned_dofs
Locally own degrees of freedom.
Definition: dg_base.hpp:398
Base metric operators class that stores functions used in both the volume and on surface.
Definition: operators.h:1131
void assemble_boundary_term_and_build_operators_ad_templated(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const std::vector< adtype > &soln_coeffs, const dealii::Tensor< 1, dim, std::vector< adtype >> &, const std::vector< adtype > &metric_coeffs, const std::vector< real > &local_dual, const unsigned int face_number, const unsigned int boundary_id, const Physics::PhysicsBase< dim, nspecies, nstate, adtype > &physics, const NumericalFlux::NumericalFluxConvective< dim, nspecies, nstate, adtype > &conv_num_flux, const NumericalFlux::NumericalFluxDissipative< dim, nspecies, nstate, adtype > &diss_num_flux, const unsigned int, const unsigned int, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::vol_projection_operator< dim, 2 *dim > &, OPERATOR::metric_operators< adtype, dim, 2 *dim > &, OPERATOR::mapping_shape_functions< dim, 2 *dim > &, std::array< std::vector< adtype >, dim > &, dealii::hp::FEFaceValues< dim, dim > &fe_values_collection_face_int, const dealii::FESystem< dim, dim > &fe_soln, const real penalty, std::vector< adtype > &rhs, dealii::Tensor< 1, dim, std::vector< adtype >> &, const bool, adtype &dual_dot_residual)
Calls the function to assemble boundary residual.
Definition: weak_dg.cpp:1757
std::vector< std::array< dealii::Tensor< 1, dim, real >, n_components > > evaluate_reference_gradients(const std::vector< dealii::Point< dim >> &unit_points) const
The mapping shape functions evaluated at the desired nodes (facet set included in volume grid nodes f...
Definition: operators.h:1071
Base class of numerical flux associated with convection.
dealii::Vector< double > max_dt_cell
Time it takes for the maximum wavespeed to cross the cell domain.
Definition: dg_base.hpp:461
bool use_manufactured_source_term
Uses non-zero source term based on the manufactured solution and the PDE.
void assemble_volume_term_and_build_operators_ad_templated(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const std::vector< adtype > &soln_coeffs, const dealii::Tensor< 1, dim, std::vector< adtype >> &, const std::vector< adtype > &metric_coeffs, const std::vector< real > &local_dual, const std::vector< dealii::types::global_dof_index > &soln_dofs_indices, const std::vector< dealii::types::global_dof_index > &metric_dofs_indices, const unsigned int poly_degree, const unsigned int grid_degree, const Physics::PhysicsBase< dim, nspecies, nstate, adtype > &physics, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::local_basis_stiffness< dim, 2 *dim > &, OPERATOR::vol_projection_operator< dim, 2 *dim > &, OPERATOR::vol_projection_operator< dim, 2 *dim > &, OPERATOR::metric_operators< adtype, dim, 2 *dim > &, OPERATOR::mapping_shape_functions< dim, 2 *dim > &, std::array< std::vector< adtype >, dim > &, dealii::hp::FEValues< dim, dim > &fe_values_collection_volume, dealii::hp::FEValues< dim, dim > &fe_values_collection_volume_lagrange, const dealii::FESystem< dim, dim > &fe_soln, std::vector< adtype > &rhs, dealii::Tensor< 1, dim, std::vector< adtype >> &, const bool, adtype &dual_dot_residual)
Calls the function to assemble volume residual.
Definition: weak_dg.cpp:1674
virtual void boundary_face_values(const int, const dealii::Point< dim, real > &, const dealii::Tensor< 1, dim, real > &, const std::array< real, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, const std::array< real, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, std::array< real, nstate > &, std::array< dealii::Tensor< 1, dim, real >, nstate > &) const
Evaluates boundary values and gradients on the other side of the face for the convective flux...
Definition: physics.cpp:208
void assemble_boundary_term(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const LocalSolution< real2, dim, nspecies, nstate > &local_solution, const LocalSolution< real2, dim, nspecies, dim > &local_metric, const std::vector< real > &local_dual, const unsigned int face_number, const unsigned int boundary_id, const Physics::PhysicsBase< dim, nspecies, nstate, real2 > &physics, const NumericalFlux::NumericalFluxConvective< dim, nspecies, nstate, real2 > &conv_num_flux, const NumericalFlux::NumericalFluxDissipative< dim, nspecies, nstate, real2 > &diss_num_flux, const dealii::FEFaceValuesBase< dim, dim > &fe_values_boundary, const real penalty, const dealii::Quadrature< dim-1 > &quadrature, std::vector< real2 > &rhs, real2 &dual_dot_residual, const bool compute_metric_derivatives)
Main function responsible for evaluating the boundary integral and the specified derivatives.
Definition: weak_dg.cpp:565
real2 discontinuity_sensor(const dealii::Quadrature< dim > &volume_quadrature, const std::vector< real2 > &soln_coeff_high, const dealii::FiniteElement< dim, dim > &fe_high, const std::vector< real2 > &jac_det)
Definition: dg_base.cpp:4571
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
Definition: dg_base.hpp:409
Abstract class templated on the number of state variables.
dealii::LinearAlgebra::distributed::Vector< real > dual
Current optimization dual variables corresponding to the residual constraints also known as the adjoi...
Definition: dg_base.hpp:483
dealii::Vector< double > artificial_dissipation_coeffs
Artificial dissipation in each cell.
Definition: dg_base.hpp:466
real current_time
The current time set in set_current_time()
Definition: dg_base.hpp:1188
const dealii::FESystem< dim, dim > & finite_element
Reference to the finite element system used to represent the solution.
void assemble_volume_term(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const LocalSolution< real2, dim, nspecies, nstate > &local_solution, const LocalSolution< real2, dim, nspecies, dim > &local_metric, const std::vector< real > &local_dual, const dealii::Quadrature< dim > &quadrature, const Physics::PhysicsBase< dim, nspecies, nstate, real2 > &physics, std::vector< real2 > &rhs, real2 &dual_dot_residual, const bool compute_metric_derivatives, const dealii::FEValues< dim, dim > &fe_values_vol)
Main function responsible for evaluating the integral over the cell volume and the specified derivati...
Definition: weak_dg.cpp:1412
bool add_artificial_dissipation
Flag to add artificial dissipation from Persson&#39;s shock capturing paper.
void allocate_dual_vector(const bool compute_d2R)
Allocate the dual vector for optimization.
Definition: weak_dg.cpp:2006
DissipativeNumericalFlux diss_num_flux_type
Store diffusive flux type.
void assemble_face_term_and_build_operators_ad_templated(typename dealii::DoFHandler< dim >::active_cell_iterator cell, typename dealii::DoFHandler< dim >::active_cell_iterator neighbor_cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, const unsigned int iface, const unsigned int neighbor_iface, const std::vector< adtype > &soln_coeff_int, const std::vector< adtype > &soln_coeff_ext, const dealii::Tensor< 1, dim, std::vector< adtype >> &, const dealii::Tensor< 1, dim, std::vector< adtype >> &, const std::vector< adtype > &metric_coeff_int, const std::vector< adtype > &metric_coeff_ext, const std::vector< double > &dual_int, const std::vector< double > &dual_ext, const unsigned int, const unsigned int, const unsigned int, const unsigned int, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::basis_functions< dim, 2 *dim > &, OPERATOR::local_basis_stiffness< dim, 2 *dim > &, OPERATOR::vol_projection_operator< dim, 2 *dim > &, OPERATOR::vol_projection_operator< dim, 2 *dim > &, OPERATOR::metric_operators< adtype, dim, 2 *dim > &, OPERATOR::metric_operators< adtype, dim, 2 *dim > &, OPERATOR::mapping_shape_functions< dim, 2 *dim > &, std::array< std::vector< adtype >, dim > &, const Physics::PhysicsBase< dim, nspecies, nstate, adtype > &physics, const NumericalFlux::NumericalFluxConvective< dim, nspecies, nstate, adtype > &conv_num_flux, const NumericalFlux::NumericalFluxDissipative< dim, nspecies, nstate, adtype > &diss_num_flux, dealii::hp::FEFaceValues< dim, dim > &fe_values_collection_face_int, dealii::hp::FEFaceValues< dim, dim > &fe_values_collection_face_ext, dealii::hp::FESubfaceValues< dim, dim > &fe_values_collection_subface, const dealii::FESystem< dim, dim > &fe_int, const dealii::FESystem< dim, dim > &fe_ext, const real penalty, std::vector< adtype > &rhs_int, std::vector< adtype > &rhs_ext, dealii::Tensor< 1, dim, std::vector< adtype >> &, dealii::Tensor< 1, dim, std::vector< adtype >> &, const bool, adtype &dual_dot_residual, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R, const bool is_a_subface, const unsigned int neighbor_i_subface)
Calls the function to assemble face residual.
Definition: weak_dg.cpp:1831
std::shared_ptr< Triangulation > triangulation
Mesh.
Definition: dg_base.hpp:160
void assemble_face_term(typename dealii::DoFHandler< dim >::active_cell_iterator cell, typename dealii::DoFHandler< dim >::active_cell_iterator neighbor_cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, const LocalSolution< real2, dim, nspecies, nstate > &soln_int, const LocalSolution< real2, dim, nspecies, nstate > &soln_ext, const LocalSolution< real2, dim, nspecies, dim > &metric_int, const LocalSolution< real2, dim, nspecies, dim > &metric_ext, const std::vector< double > &dual_int, const std::vector< double > &dual_ext, const std::pair< unsigned int, int > face_subface_int, const std::pair< unsigned int, int > face_subface_ext, const typename dealii::QProjector< dim >::DataSetDescriptor face_data_set_int, const typename dealii::QProjector< dim >::DataSetDescriptor face_data_set_ext, const Physics::PhysicsBase< dim, nspecies, nstate, real2 > &physics, const NumericalFlux::NumericalFluxConvective< dim, nspecies, nstate, real2 > &conv_num_flux, const NumericalFlux::NumericalFluxDissipative< dim, nspecies, nstate, real2 > &diss_num_flux, const dealii::FEFaceValuesBase< dim, dim > &fe_values_int, const dealii::FEFaceValuesBase< dim, dim > &fe_values_ext, const real penalty, const dealii::Quadrature< dim-1 > &face_quadrature, std::vector< real2 > &rhs_int, std::vector< real2 > &rhs_ext, real2 &dual_dot_residual, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Main function responsible for evaluating the internal face integral and the specified derivatives...
Definition: weak_dg.cpp:936
real1 norm(const dealii::Tensor< 1, dim, real1 > x)
Returns norm of dealii::Tensor<1,dim,real>
std::vector< real > coefficients
Solution coefficients in the finite element basis.
ArtificialDissipationParam artificial_dissipation_param
Contains parameters for artificial dissipation.
std::vector< std::array< real, n_components > > evaluate_values(const std::vector< dealii::Point< dim >> &unit_points) const
Obtain values at unit points.
virtual std::array< dealii::Tensor< 1, dim, real >, nstate > dissipative_flux(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)
Dissipative fluxes that will be differentiated ONCE in space.
Definition: physics.cpp:128
Projection operator corresponding to basis functions onto M-norm (L2).
Definition: operators.h:723
Local stiffness matrix without jacobian dependence.
Definition: operators.h:497
real evaluate_CFL(std::vector< std::array< real, nstate > > soln_at_q, const real artificial_dissipation, const real cell_diameter, const unsigned int cell_degree)
Evaluate the time it takes for the maximum wavespeed to cross the cell domain.