[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
strong_dg.cpp
1 #include <deal.II/base/tensor.h>
2 
3 #include <deal.II/fe/fe_values.h>
4 
5 #include <deal.II/dofs/dof_handler.h>
6 #include <deal.II/dofs/dof_tools.h>
7 
8 #include <deal.II/dofs/dof_renumbering.h>
9 
10 #include <deal.II/dofs/dof_accessor.h>
11 
12 #include <deal.II/lac/vector.h>
13 
14 #include "ADTypes.hpp"
15 
16 #include <deal.II/fe/fe_dgq.h> // Used for flux interpolation
17 
18 #include "strong_dg.hpp"
19 
20 namespace PHiLiP {
21 
22 template <int dim, int nstate, typename real, typename MeshType>
24  const Parameters::AllParameters *const parameters_input,
25  const unsigned int degree,
26  const unsigned int max_degree_input,
27  const unsigned int grid_degree_input,
28  const std::shared_ptr<Triangulation> triangulation_input)
29  : DGBaseState<dim,nstate,real,MeshType>::DGBaseState(parameters_input, degree, max_degree_input, grid_degree_input, triangulation_input)
30 { }
31 
32 /***********************************************************
33 *
34 * Build operators and solve for RHS
35 *
36 ***********************************************************/
37 template <int dim, int nstate, typename real, typename MeshType>
39  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
40  const dealii::types::global_dof_index current_cell_index,
41  const std::vector<dealii::types::global_dof_index> &cell_dofs_indices,
42  const std::vector<dealii::types::global_dof_index> &metric_dof_indices,
43  const unsigned int poly_degree,
44  const unsigned int grid_degree,
48  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_int,
49  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_ext,
52  std::array<std::vector<real>,dim> &mapping_support_points,
53  dealii::hp::FEValues<dim,dim> &/*fe_values_collection_volume*/,
54  dealii::hp::FEValues<dim,dim> &/*fe_values_collection_volume_lagrange*/,
55  const dealii::FESystem<dim,dim> &/*current_fe_ref*/,
56  dealii::Vector<real> &local_rhs_int_cell,
57  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS,
58  const bool compute_auxiliary_right_hand_side,
59  const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/)
60 {
61  // Check if the current cell's poly degree etc is different then previous cell's.
62  // If the current cell's poly degree is different, then we recompute the 1D
63  // polynomial basis functions. Otherwise, we use the previous values in reference space.
64  if(poly_degree != soln_basis.current_degree){
65  soln_basis.current_degree = poly_degree;
66  flux_basis.current_degree = poly_degree;
67  mapping_basis.current_degree = poly_degree;
68  this->reinit_operators_for_cell_residual_loop(poly_degree, poly_degree, grid_degree,
69  soln_basis, soln_basis,
70  flux_basis, flux_basis,
71  flux_basis_stiffness,
72  soln_basis_projection_oper_int, soln_basis_projection_oper_ext,
73  mapping_basis);
74  }
75 
76  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
77  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
78  const unsigned int n_grid_nodes = n_metric_dofs / dim;
79  //Rewrite the high_order_grid->volume_nodes in a way we can use sum-factorization on.
80  //That is, splitting up the vector by the dimension.
81  for(int idim=0; idim<dim; idim++){
82  mapping_support_points[idim].resize(n_grid_nodes);
83  }
84  const std::vector<unsigned int > &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering<dim>(grid_degree);
85  for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) {
86  const real val = (this->high_order_grid->volume_nodes[metric_dof_indices[idof]]);
87  const unsigned int istate = fe_metric.system_to_component_index(idof).first;
88  const unsigned int ishape = fe_metric.system_to_component_index(idof).second;
89  const unsigned int igrid_node = index_renumbering[ishape];
90  mapping_support_points[istate][igrid_node] = val;
91  }
92 
93  //build the volume metric cofactor matrix and the determinant of the volume metric Jacobian
94  //Also, computes the physical volume flux nodes if needed from flag passed to constructor in dg.cpp
96  this->volume_quadrature_collection[poly_degree].size(), n_grid_nodes,
97  mapping_support_points,
98  mapping_basis,
100 
101  if(compute_auxiliary_right_hand_side){
103  cell_dofs_indices,
104  poly_degree,
105  soln_basis,
106  flux_basis,
107  metric_oper,
108  local_auxiliary_RHS);
109  }
110  else{
112  cell,
113  current_cell_index,
114  cell_dofs_indices,
115  poly_degree,
116  soln_basis,
117  flux_basis,
118  flux_basis_stiffness,
119  soln_basis_projection_oper_int,
120  metric_oper,
121  local_rhs_int_cell);
122  }
123 }
124 template <int dim, int nstate, typename real, typename MeshType>
126  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
127  const dealii::types::global_dof_index current_cell_index,
128  const unsigned int iface,
129  const unsigned int boundary_id,
130  const real penalty,
131  const std::vector<dealii::types::global_dof_index> &cell_dofs_indices,
132  const std::vector<dealii::types::global_dof_index> &/*metric_dof_indices*/,
133  const unsigned int poly_degree,
134  const unsigned int /*grid_degree*/,
137  OPERATOR::local_basis_stiffness<dim,2*dim,real> &/*flux_basis_stiffness*/,
138  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_int,
139  OPERATOR::vol_projection_operator<dim,2*dim,real> &/*soln_basis_projection_oper_ext*/,
142  std::array<std::vector<real>,dim> &mapping_support_points,
143  dealii::hp::FEFaceValues<dim,dim> &/*fe_values_collection_face_int*/,
144  const dealii::FESystem<dim,dim> &/*current_fe_ref*/,
145  dealii::Vector<real> &local_rhs_int_cell,
146  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS,
147  const bool compute_auxiliary_right_hand_side,
148  const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/)
149 {
150 
151  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
152  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
153  const unsigned int n_grid_nodes = n_metric_dofs / dim;
154  //build the surface metric operators for interior
155  metric_oper.build_facet_metric_operators(
156  iface,
157  this->face_quadrature_collection[poly_degree].size(),
158  n_grid_nodes,
159  mapping_support_points,
160  mapping_basis,
162 
163  if(compute_auxiliary_right_hand_side){
165  iface, current_cell_index, poly_degree,
166  boundary_id, cell_dofs_indices,
167  soln_basis, metric_oper,
168  local_auxiliary_RHS);
169  }
170  else{
172  iface,
173  current_cell_index,
174  boundary_id, poly_degree, penalty,
175  cell_dofs_indices,
176  soln_basis,
177  flux_basis,
178  soln_basis_projection_oper_int,
179  metric_oper,
180  local_rhs_int_cell);
181  }
182 
183 }
184 
185 template <int dim, int nstate, typename real, typename MeshType>
187  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
188  typename dealii::DoFHandler<dim>::active_cell_iterator neighbor_cell,
189  const dealii::types::global_dof_index current_cell_index,
190  const dealii::types::global_dof_index neighbor_cell_index,
191  const unsigned int iface,
192  const unsigned int neighbor_iface,
193  const real penalty,
194  const std::vector<dealii::types::global_dof_index> &current_dofs_indices,
195  const std::vector<dealii::types::global_dof_index> &neighbor_dofs_indices,
196  const std::vector<dealii::types::global_dof_index> &/*current_metric_dofs_indices*/,
197  const std::vector<dealii::types::global_dof_index> &neighbor_metric_dofs_indices,
198  const unsigned int poly_degree_int,
199  const unsigned int poly_degree_ext,
200  const unsigned int /*grid_degree_int*/,
201  const unsigned int grid_degree_ext,
207  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_int,
208  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_ext,
212  std::array<std::vector<real>,dim> &mapping_support_points,
213  dealii::hp::FEFaceValues<dim,dim> &/*fe_values_collection_face_int*/,
214  dealii::hp::FEFaceValues<dim,dim> &/*fe_values_collection_face_ext*/,
215  dealii::Vector<real> &current_cell_rhs,
216  dealii::Vector<real> &neighbor_cell_rhs,
217  std::vector<dealii::Tensor<1,dim,real>> &current_cell_rhs_aux,
218  dealii::LinearAlgebra::distributed::Vector<double> &rhs,
219  std::array<dealii::LinearAlgebra::distributed::Vector<double>,dim> &rhs_aux,
220  const bool compute_auxiliary_right_hand_side,
221  const bool /*compute_dRdW*/, const bool /*compute_dRdX*/, const bool /*compute_d2R*/)
222 {
223 
224  const dealii::FESystem<dim> &fe_metric = this->high_order_grid->fe_system;
225  const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
226  const unsigned int n_grid_nodes = n_metric_dofs / dim;
227  //build the surface metric operators for interior
228  metric_oper_int.build_facet_metric_operators(
229  iface,
230  this->face_quadrature_collection[poly_degree_int].size(),
231  n_grid_nodes,
232  mapping_support_points,
233  mapping_basis,
235 
236  if(poly_degree_ext != soln_basis_ext.current_degree){
237  soln_basis_ext.current_degree = poly_degree_ext;
238  flux_basis_ext.current_degree = poly_degree_ext;
239  mapping_basis.current_degree = poly_degree_ext;
240  this->reinit_operators_for_cell_residual_loop(poly_degree_int, poly_degree_ext, grid_degree_ext,
241  soln_basis_int, soln_basis_ext,
242  flux_basis_int, flux_basis_ext,
243  flux_basis_stiffness,
244  soln_basis_projection_oper_int, soln_basis_projection_oper_ext,
245  mapping_basis);
246  }
247 
248  if(!compute_auxiliary_right_hand_side){//only for primary equations
249  //get neighbor metric operator
250  //rewrite the high_order_grid->volume_nodes in a way we can use sum-factorization on.
251  //that is, splitting up the vector by the dimension.
252  std::array<std::vector<real>,dim> mapping_support_points_neigh;
253  for(int idim=0; idim<dim; idim++){
254  mapping_support_points_neigh[idim].resize(n_grid_nodes);
255  }
256  const std::vector<unsigned int > &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering<dim>(grid_degree_ext);
257  for (unsigned int idof = 0; idof< n_metric_dofs; ++idof) {
258  const real val = (this->high_order_grid->volume_nodes[neighbor_metric_dofs_indices[idof]]);
259  const unsigned int istate = fe_metric.system_to_component_index(idof).first;
260  const unsigned int ishape = fe_metric.system_to_component_index(idof).second;
261  const unsigned int igrid_node = index_renumbering[ishape];
262  mapping_support_points_neigh[istate][igrid_node] = val;
263  }
264  //build the metric operators for strong form
265  metric_oper_ext.build_volume_metric_operators(
266  this->volume_quadrature_collection[poly_degree_ext].size(), n_grid_nodes,
267  mapping_support_points_neigh,
268  mapping_basis,
270  }
271 
272  if(compute_auxiliary_right_hand_side){
273  const unsigned int n_dofs_neigh_cell = this->fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell();
274  std::vector<dealii::Tensor<1,dim,double>> neighbor_cell_rhs_aux (n_dofs_neigh_cell ); // defaults to 0.0 initialization
276  iface, neighbor_iface,
277  current_cell_index, neighbor_cell_index,
278  poly_degree_int, poly_degree_ext,
279  current_dofs_indices, neighbor_dofs_indices,
280  soln_basis_int, soln_basis_ext,
281  metric_oper_int,
282  current_cell_rhs_aux, neighbor_cell_rhs_aux);
283  // add local contribution from neighbor cell to global vector
284  for (unsigned int i=0; i<n_dofs_neigh_cell; ++i) {
285  for(int idim=0; idim<dim; idim++){
286  rhs_aux[idim][neighbor_dofs_indices[i]] += neighbor_cell_rhs_aux[i][idim];
287  }
288  }
289  }
290  else{
292  iface, neighbor_iface,
293  current_cell_index,
294  neighbor_cell_index,
295  poly_degree_int, poly_degree_ext,
296  penalty,
297  current_dofs_indices, neighbor_dofs_indices,
298  soln_basis_int, soln_basis_ext,
299  flux_basis_int, flux_basis_ext,
300  soln_basis_projection_oper_int, soln_basis_projection_oper_ext,
301  metric_oper_int, metric_oper_ext,
302  current_cell_rhs, neighbor_cell_rhs);
303  // add local contribution from neighbor cell to global vector
304  const unsigned int n_dofs_neigh_cell = this->fe_collection[neighbor_cell->active_fe_index()].n_dofs_per_cell();
305  for (unsigned int i=0; i<n_dofs_neigh_cell; ++i) {
306  rhs[neighbor_dofs_indices[i]] += neighbor_cell_rhs[i];
307  }
308  }
309 
310 }
311 
312 template <int dim, int nstate, typename real, typename MeshType>
314  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
315  typename dealii::DoFHandler<dim>::active_cell_iterator neighbor_cell,
316  const dealii::types::global_dof_index current_cell_index,
317  const dealii::types::global_dof_index neighbor_cell_index,
318  const unsigned int iface,
319  const unsigned int neighbor_iface,
320  const unsigned int /*neighbor_i_subface*/,
321  const real penalty,
322  const std::vector<dealii::types::global_dof_index> &current_dofs_indices,
323  const std::vector<dealii::types::global_dof_index> &neighbor_dofs_indices,
324  const std::vector<dealii::types::global_dof_index> &current_metric_dofs_indices,
325  const std::vector<dealii::types::global_dof_index> &neighbor_metric_dofs_indices,
326  const unsigned int poly_degree_int,
327  const unsigned int poly_degree_ext,
328  const unsigned int grid_degree_int,
329  const unsigned int grid_degree_ext,
335  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_int,
336  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_ext,
340  std::array<std::vector<real>,dim> &mapping_support_points,
341  dealii::hp::FEFaceValues<dim,dim> &fe_values_collection_face_int,
342  dealii::hp::FESubfaceValues<dim,dim> &/*fe_values_collection_subface*/,
343  dealii::Vector<real> &current_cell_rhs,
344  dealii::Vector<real> &neighbor_cell_rhs,
345  std::vector<dealii::Tensor<1,dim,real>> &current_cell_rhs_aux,
346  dealii::LinearAlgebra::distributed::Vector<double> &rhs,
347  std::array<dealii::LinearAlgebra::distributed::Vector<double>,dim> &rhs_aux,
348  const bool compute_auxiliary_right_hand_side,
349  const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
350 {
352  cell,
353  neighbor_cell,
354  current_cell_index,
355  neighbor_cell_index,
356  iface,
357  neighbor_iface,
358  penalty,
359  current_dofs_indices,
360  neighbor_dofs_indices,
361  current_metric_dofs_indices,
362  neighbor_metric_dofs_indices,
363  poly_degree_int,
364  poly_degree_ext,
365  grid_degree_int,
366  grid_degree_ext,
367  soln_basis_int,
368  soln_basis_ext,
369  flux_basis_int,
370  flux_basis_ext,
371  flux_basis_stiffness,
372  soln_basis_projection_oper_int,
373  soln_basis_projection_oper_ext,
374  metric_oper_int,
375  metric_oper_ext,
376  mapping_basis,
377  mapping_support_points,
378  fe_values_collection_face_int,
379  fe_values_collection_face_int,
380  current_cell_rhs,
381  neighbor_cell_rhs,
382  current_cell_rhs_aux,
383  rhs,
384  rhs_aux,
385  compute_auxiliary_right_hand_side,
386  compute_dRdW, compute_dRdX, compute_d2R);
387 
388 }
389 /*******************************************************************
390  *
391  *
392  * AUXILIARY EQUATIONS
393  *
394  *
395  *******************************************************************/
396 
397 template <int dim, int nstate, typename real, typename MeshType>
399 {
402  const PDE_enum pde_type = this->all_parameters->pde_type;
403 
404  if(pde_type == PDE_enum::burgers_viscous){
405  pcout << "DG Strong not yet verified for Burgers' viscous. Aborting..." << std::endl;
406  std::abort();
407  }
408  // NOTE: auxiliary currently only works explicit time advancement - not implicit
409  if (this->use_auxiliary_eq && !(this->all_parameters->ode_solver_param.ode_solver_type == ODE_enum::implicit_solver)) {
410  //set auxiliary rhs to 0
411  for(int idim=0; idim<dim; idim++){
412  this->auxiliary_right_hand_side[idim] = 0;
413  }
414  //initialize this to use DG cell residual loop. Note, FEValues to be deprecated in future.
415  const auto mapping = (*(this->high_order_grid->mapping_fe_field));
416 
417  dealii::hp::MappingCollection<dim> mapping_collection(mapping);
418 
419  dealii::hp::FEValues<dim,dim> fe_values_collection_volume (mapping_collection, this->fe_collection, this->volume_quadrature_collection, this->volume_update_flags);
420  dealii::hp::FEFaceValues<dim,dim> fe_values_collection_face_int (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->face_update_flags);
421  dealii::hp::FEFaceValues<dim,dim> fe_values_collection_face_ext (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->neighbor_face_update_flags);
422  dealii::hp::FESubfaceValues<dim,dim> fe_values_collection_subface (mapping_collection, this->fe_collection, this->face_quadrature_collection, this->face_update_flags);
423 
424  dealii::hp::FEValues<dim,dim> fe_values_collection_volume_lagrange (mapping_collection, this->fe_collection_lagrange, this->volume_quadrature_collection, this->volume_update_flags);
425 
430  OPERATOR::local_basis_stiffness<dim,2*dim,real> flux_basis_stiffness(1, this->max_degree, this->max_grid_degree);
432  OPERATOR::vol_projection_operator<dim,2*dim,real> soln_basis_projection_oper_int(1, this->max_degree, this->max_grid_degree);
433  OPERATOR::vol_projection_operator<dim,2*dim,real> soln_basis_projection_oper_ext(1, this->max_degree, this->max_grid_degree);
434 
436  this->max_degree, this->max_degree, this->max_grid_degree,
437  soln_basis_int, soln_basis_ext,
438  flux_basis_int, flux_basis_ext,
439  flux_basis_stiffness,
440  soln_basis_projection_oper_int, soln_basis_projection_oper_ext,
441  mapping_basis);
442 
443  //loop over cells solving for auxiliary rhs
444  auto metric_cell = this->high_order_grid->dof_handler_grid.begin_active();
445  for (auto soln_cell = this->dof_handler.begin_active(); soln_cell != this->dof_handler.end(); ++soln_cell, ++metric_cell) {
446  if (!soln_cell->is_locally_owned()) continue;
447 
448  this->assemble_cell_residual (
449  soln_cell,
450  metric_cell,
451  false, false, false,
452  fe_values_collection_volume,
453  fe_values_collection_face_int,
454  fe_values_collection_face_ext,
455  fe_values_collection_subface,
456  fe_values_collection_volume_lagrange,
457  soln_basis_int,
458  soln_basis_ext,
459  flux_basis_int,
460  flux_basis_ext,
461  flux_basis_stiffness,
462  soln_basis_projection_oper_int,
463  soln_basis_projection_oper_ext,
464  mapping_basis,
465  true,
466  this->right_hand_side,
468  } // end of cell loop
469 
470  for(int idim=0; idim<dim; idim++){
471  //compress auxiliary rhs for solution transfer across mpi ranks
472  this->auxiliary_right_hand_side[idim].compress(dealii::VectorOperation::add);
473  //update ghost values
474  this->auxiliary_right_hand_side[idim].update_ghost_values();
475 
476  //solve for auxiliary solution for each dimension
479  else
481 
482  //update ghost values of auxiliary solution
483  this->auxiliary_solution[idim].update_ghost_values();
484  }
485  }//end of if statement for diffusive
486  else if (this->use_auxiliary_eq && (this->all_parameters->ode_solver_param.ode_solver_type == ODE_enum::implicit_solver)) {
487  pcout << "ERROR: " << "auxiliary currently only works for explicit time advancement. Aborting..." << std::endl;
488  std::abort();
489  } else {
490  // Do nothing
491  }
492 }
493 
494 /**************************************************
495  *
496  * AUXILIARY RESIDUAL FUNCTIONS
497  *
498  **************************************************/
499 
500 template <int dim, int nstate, typename real, typename MeshType>
502  const std::vector<dealii::types::global_dof_index> &current_dofs_indices,
503  const unsigned int poly_degree,
507  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS)
508 {
509  //Please see header file for exact formula we are solving.
510  const unsigned int n_quad_pts = this->volume_quadrature_collection[poly_degree].size();
511  const unsigned int n_dofs_cell = this->fe_collection[poly_degree].dofs_per_cell;
512  const unsigned int n_shape_fns = n_dofs_cell / nstate;
513  const std::vector<double> &quad_weights = this->volume_quadrature_collection[poly_degree].get_weights();
514 
515  //Fetch the modal soln coefficients and the modal auxiliary soln coefficients
516  //We immediately separate them by state as to be able to use sum-factorization
517  //in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector
518  //mult would sum the states at the quadrature point.
519  //That is why the basis functions are of derived class state rather than base.
520  std::array<std::vector<real>,nstate> soln_coeff;
521  for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
522  const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first;
523  const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second;
524  if(ishape == 0)
525  soln_coeff[istate].resize(n_shape_fns);
526 
527  soln_coeff[istate][ishape] = DGBase<dim,real,MeshType>::solution(current_dofs_indices[idof]);
528  }
529  //Interpolate each state to the quadrature points using sum-factorization
530  //with the basis functions in each reference direction.
531  for(int istate=0; istate<nstate; istate++){
532  std::vector<real> soln_at_q(n_quad_pts);
533  //interpolate soln coeff to volume cubature nodes
534  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q,
535  soln_basis.oneD_vol_operator);
536  //the volume integral for the auxiliary equation is the physical integral of the physical gradient of the solution.
537  //That is, we need to physically integrate (we have determinant of Jacobian cancel) the Eq. (12) (with u for chi) in
538  //Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics 463 (2022): 111259.
539 
540  //apply gradient of reference basis functions on the solution at volume cubature nodes
541  dealii::Tensor<1,dim,std::vector<real>> ref_gradient_basis_fns_times_soln;
542  for(int idim=0; idim<dim; idim++){
543  ref_gradient_basis_fns_times_soln[idim].resize(n_quad_pts);
544  }
545  flux_basis.gradient_matrix_vector_mult_1D(soln_at_q, ref_gradient_basis_fns_times_soln,
546  flux_basis.oneD_vol_operator,
547  flux_basis.oneD_grad_operator);
548  //transform the gradient into a physical gradient operator scaled by determinant of metric Jacobian
549  //then apply the inner product in each direction
550  for(int idim=0; idim<dim; idim++){
551  std::vector<real> phys_gradient_u(n_quad_pts);
552  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
553  for(int jdim=0; jdim<dim; jdim++){
554  //transform into the physical gradient
555  phys_gradient_u[iquad] += metric_oper.metric_cofactor_vol[idim][jdim][iquad]
556  * ref_gradient_basis_fns_times_soln[jdim][iquad];
557  }
558  }
559  //Note that we let the determiant of the metric Jacobian cancel off between the integral and physical gradient
560  std::vector<real> rhs(n_shape_fns);
561  soln_basis.inner_product_1D(phys_gradient_u, quad_weights,
562  rhs,
563  soln_basis.oneD_vol_operator,
564  false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln
565 
566  //write the the auxiliary rhs for the test function.
567  for(unsigned int ishape=0; ishape<n_shape_fns; ishape++){
568  local_auxiliary_RHS[istate*n_shape_fns + ishape][idim] += rhs[ishape];
569  }
570  }
571  }
572 }
573 
574 template <int dim, int nstate, typename real, typename MeshType>
576  const unsigned int iface,
577  const dealii::types::global_dof_index current_cell_index,
578  const unsigned int poly_degree,
579  const unsigned int boundary_id,
580  const std::vector<dealii::types::global_dof_index> &dofs_indices,
583  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS)
584 {
585  (void) current_cell_index;
586 
587  const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree].size();
588  const unsigned int n_quad_pts_vol = this->volume_quadrature_collection[poly_degree].size();
589  const unsigned int n_dofs = this->fe_collection[poly_degree].dofs_per_cell;
590  const unsigned int n_shape_fns = n_dofs / nstate;
591  AssertDimension (n_dofs, dofs_indices.size());
592 
593  //Extract interior modal coefficients of solution
594  std::array<std::vector<real>,nstate> soln_coeff;
595  for (unsigned int idof = 0; idof < n_dofs; ++idof) {
596  const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first;
597  const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second;
598  //allocate
599  if(ishape == 0)
600  soln_coeff[istate].resize(n_shape_fns);
601  //solve
602  soln_coeff[istate][ishape] = DGBase<dim,real,MeshType>::solution(dofs_indices[idof]);
603  }
604 
605  //Interpolate soln to facet, and gradient to facet.
606  std::array<std::vector<real>,nstate> soln_at_surf_q;
607  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> ref_grad_soln_at_vol_q;
608  for(int istate=0; istate<nstate; ++istate){
609  //allocate
610  soln_at_surf_q[istate].resize(n_face_quad_pts);
611  //solve soln at facet cubature nodes
612  soln_basis.matrix_vector_mult_surface_1D(iface, soln_coeff[istate], soln_at_surf_q[istate],
613  soln_basis.oneD_surf_operator,
614  soln_basis.oneD_vol_operator);
615  //solve reference gradient of soln at facet cubature nodes
616  for(int idim=0; idim<dim; idim++){
617  ref_grad_soln_at_vol_q[istate][idim].resize(n_quad_pts_vol);
618  }
619  soln_basis.gradient_matrix_vector_mult_1D(soln_coeff[istate], ref_grad_soln_at_vol_q[istate],
620  soln_basis.oneD_vol_operator,
621  soln_basis.oneD_grad_operator);
622  }
623 
624  // Get physical gradient of solution on the surface
625  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> phys_grad_soln_at_surf_q;
626  for(int istate=0; istate<nstate; istate++){
627  //transform the gradient into a physical gradient operator
628  for(int idim=0; idim<dim; idim++){
629  std::vector<real> phys_gradient_u(n_quad_pts_vol);
630  for(unsigned int iquad=0; iquad<n_quad_pts_vol; iquad++){
631  for(int jdim=0; jdim<dim; jdim++){
632  //transform into the physical gradient
633  phys_gradient_u[iquad] += metric_oper.metric_cofactor_vol[idim][jdim][iquad]
634  * ref_grad_soln_at_vol_q[istate][jdim][iquad];
635  }
636  phys_gradient_u[iquad] /= metric_oper.det_Jac_vol[iquad];
637  }
638  phys_grad_soln_at_surf_q[istate][idim].resize(n_face_quad_pts);
639  //interpolate physical volume gradient of the solution to the surface
640  soln_basis.matrix_vector_mult_surface_1D(iface, phys_gradient_u, phys_grad_soln_at_surf_q[istate][idim],
641  soln_basis.oneD_surf_operator,
642  soln_basis.oneD_vol_operator);
643  }
644  }
645 
646  //evaluate physical facet fluxes dot product with physical unit normal scaled by determinant of metric facet Jacobian
647  //the outward reference normal dircetion.
648  const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo<dim>::unit_normal_vector[iface];
649  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> surf_num_flux_minus_surf_soln_dot_normal;
650  for(unsigned int iquad=0; iquad<n_face_quad_pts; iquad++){
651  //Copy Metric Cofactor on the facet in a way can use for transforming Tensor Blocks to reference space
652  //The way it is stored in metric_operators is to use sum-factorization in each direction,
653  //but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
654  //Note that for a conforming mesh, the facet metric cofactor matrix is the same from either interioir or exterior metric terms.
655  //This is verified for the metric computations in: unit_tests/operator_tests/surface_conforming_test.cpp
656  dealii::Tensor<2,dim,real> metric_cofactor_surf;
657  for(int idim=0; idim<dim; idim++){
658  for(int jdim=0; jdim<dim; jdim++){
659  metric_cofactor_surf[idim][jdim] = metric_oper.metric_cofactor_surf[idim][jdim][iquad];
660  }
661  }
662  std::array<real,nstate> soln_state;
663  std::array<dealii::Tensor<1,dim,real>,nstate> phys_grad_soln_state;
664  for(int istate=0; istate<nstate; istate++){
665  soln_state[istate] = soln_at_surf_q[istate][iquad];
666  for(int idim=0; idim<dim; idim++){
667  phys_grad_soln_state[istate][idim] = phys_grad_soln_at_surf_q[istate][idim][iquad];
668  }
669  }
670  //numerical fluxes
671  dealii::Tensor<1,dim,real> unit_phys_normal_int;
672  metric_oper.transform_reference_to_physical(unit_ref_normal_int,
673  metric_cofactor_surf,
674  unit_phys_normal_int);
675  const double face_Jac_norm_scaled = unit_phys_normal_int.norm();
676  unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it.
677 
678  std::array<real,nstate> soln_boundary;
679  std::array<dealii::Tensor<1,dim,real>,nstate> grad_soln_boundary;
680  dealii::Point<dim,real> surf_flux_node;
681  for(int idim=0; idim<dim; idim++){
682  surf_flux_node[idim] = metric_oper.flux_nodes_surf[iface][idim][iquad];
683  }
684  this->pde_physics_double->boundary_face_values (boundary_id, surf_flux_node, unit_phys_normal_int, soln_state, phys_grad_soln_state, soln_boundary, grad_soln_boundary);
685 
686  std::array<real,nstate> diss_soln_num_flux;
687  diss_soln_num_flux = this->diss_num_flux_double->evaluate_solution_flux(soln_state, soln_boundary, unit_phys_normal_int);
688 
689  for(int istate=0; istate<nstate; istate++){
690  for(int idim=0; idim<dim; idim++){
691  //allocate
692  if(iquad == 0){
693  surf_num_flux_minus_surf_soln_dot_normal[istate][idim].resize(n_face_quad_pts);
694  }
695  //solve
696  surf_num_flux_minus_surf_soln_dot_normal[istate][idim][iquad]
697  = (diss_soln_num_flux[istate] - soln_at_surf_q[istate][iquad]) * unit_phys_normal_int[idim] * face_Jac_norm_scaled;
698  }
699  }
700  }
701  //solve residual and set
702  const std::vector<double> &surf_quad_weights = this->face_quadrature_collection[poly_degree].get_weights();
703  for(int istate=0; istate<nstate; istate++){
704  for(int idim=0; idim<dim; idim++){
705  std::vector<real> rhs(n_shape_fns);
706 
707  soln_basis.inner_product_surface_1D(iface,
708  surf_num_flux_minus_surf_soln_dot_normal[istate][idim],
709  surf_quad_weights, rhs,
710  soln_basis.oneD_surf_operator,
711  soln_basis.oneD_vol_operator,
712  false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln
713  for(unsigned int ishape=0; ishape<n_shape_fns; ishape++){
714  local_auxiliary_RHS[istate*n_shape_fns + ishape][idim] += rhs[ishape];
715  }
716  }
717  }
718 }
719 /*********************************************************************************/
720 template <int dim, int nstate, typename real, typename MeshType>
722  const unsigned int iface, const unsigned int neighbor_iface,
723  const dealii::types::global_dof_index current_cell_index,
724  const dealii::types::global_dof_index neighbor_cell_index,
725  const unsigned int poly_degree_int,
726  const unsigned int poly_degree_ext,
727  const std::vector<dealii::types::global_dof_index> &dof_indices_int,
728  const std::vector<dealii::types::global_dof_index> &dof_indices_ext,
732  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS_int,
733  std::vector<dealii::Tensor<1,dim,real>> &local_auxiliary_RHS_ext)
734 {
735  (void) current_cell_index;
736  (void) neighbor_cell_index;
737 
738  const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree_int].size();//assume interior cell does the work
739 
740  const unsigned int n_dofs_int = this->fe_collection[poly_degree_int].dofs_per_cell;
741  const unsigned int n_dofs_ext = this->fe_collection[poly_degree_ext].dofs_per_cell;
742 
743  const unsigned int n_shape_fns_int = n_dofs_int / nstate;
744  const unsigned int n_shape_fns_ext = n_dofs_ext / nstate;
745 
746  AssertDimension (n_dofs_int, dof_indices_int.size());
747  AssertDimension (n_dofs_ext, dof_indices_ext.size());
748 
749  //Extract interior modal coefficients of solution
750  std::array<std::vector<real>,nstate> soln_coeff_int;
751  for (unsigned int idof = 0; idof < n_dofs_int; ++idof) {
752  const unsigned int istate = this->fe_collection[poly_degree_int].system_to_component_index(idof).first;
753  const unsigned int ishape = this->fe_collection[poly_degree_int].system_to_component_index(idof).second;
754  //allocate
755  if(ishape == 0) soln_coeff_int[istate].resize(n_shape_fns_int);
756 
757  //solve
758  soln_coeff_int[istate][ishape] = DGBase<dim,real,MeshType>::solution(dof_indices_int[idof]);
759  }
760 
761  //Extract exterior modal coefficients of solution
762  std::array<std::vector<real>,nstate> soln_coeff_ext;
763  for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) {
764  const unsigned int istate = this->fe_collection[poly_degree_ext].system_to_component_index(idof).first;
765  const unsigned int ishape = this->fe_collection[poly_degree_ext].system_to_component_index(idof).second;
766  //allocate
767  if(ishape == 0) soln_coeff_ext[istate].resize(n_shape_fns_ext);
768 
769  //solve
770  soln_coeff_ext[istate][ishape] = DGBase<dim,real,MeshType>::solution(dof_indices_ext[idof]);
771  }
772 
773  //Interpolate soln modal coefficients to the facet
774  std::array<std::vector<real>,nstate> soln_at_surf_q_int;
775  std::array<std::vector<real>,nstate> soln_at_surf_q_ext;
776  for(int istate=0; istate<nstate; ++istate){
777  //allocate
778  soln_at_surf_q_int[istate].resize(n_face_quad_pts);
779  soln_at_surf_q_ext[istate].resize(n_face_quad_pts);
780  //solve soln at facet cubature nodes
781  soln_basis_int.matrix_vector_mult_surface_1D(iface,
782  soln_coeff_int[istate], soln_at_surf_q_int[istate],
783  soln_basis_int.oneD_surf_operator,
784  soln_basis_int.oneD_vol_operator);
785  soln_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
786  soln_coeff_ext[istate], soln_at_surf_q_ext[istate],
787  soln_basis_ext.oneD_surf_operator,
788  soln_basis_ext.oneD_vol_operator);
789  }
790 
791  //evaluate physical facet fluxes dot product with physical unit normal scaled by determinant of metric facet Jacobian
792  //the outward reference normal dircetion.
793  const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo<dim>::unit_normal_vector[iface];
794  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> surf_num_flux_minus_surf_soln_int_dot_normal;
795  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> surf_num_flux_minus_surf_soln_ext_dot_normal;
796  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
797  //Copy Metric Cofactor on the facet in a way can use for transforming Tensor Blocks to reference space
798  //The way it is stored in metric_operators is to use sum-factorization in each direction,
799  //but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
800  //Note that for a conforming mesh, the facet metric cofactor matrix is the same from either interioir or exterior metric terms.
801  //This is verified for the metric computations in: unit_tests/operator_tests/surface_conforming_test.cpp
802  dealii::Tensor<2,dim,real> metric_cofactor_surf;
803  for(int idim=0; idim<dim; idim++){
804  for(int jdim=0; jdim<dim; jdim++){
805  metric_cofactor_surf[idim][jdim] = metric_oper_int.metric_cofactor_surf[idim][jdim][iquad];
806  }
807  }
808  //numerical fluxes
809  dealii::Tensor<1,dim,real> unit_phys_normal_int;
810  metric_oper_int.transform_reference_to_physical(unit_ref_normal_int,
811  metric_cofactor_surf,
812  unit_phys_normal_int);
813  const double face_Jac_norm_scaled = unit_phys_normal_int.norm();
814  unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it.
815 
816  std::array<real,nstate> diss_soln_num_flux;
817  std::array<real,nstate> soln_state_int;
818  std::array<real,nstate> soln_state_ext;
819  for(int istate=0; istate<nstate; istate++){
820  soln_state_int[istate] = soln_at_surf_q_int[istate][iquad];
821  soln_state_ext[istate] = soln_at_surf_q_ext[istate][iquad];
822  }
823  diss_soln_num_flux = this->diss_num_flux_double->evaluate_solution_flux(soln_state_int, soln_state_ext, unit_phys_normal_int);
824 
825  for(int istate=0; istate<nstate; istate++){
826  for(int idim=0; idim<dim; idim++){
827  //allocate
828  if(iquad == 0){
829  surf_num_flux_minus_surf_soln_int_dot_normal[istate][idim].resize(n_face_quad_pts);
830  surf_num_flux_minus_surf_soln_ext_dot_normal[istate][idim].resize(n_face_quad_pts);
831  }
832  //solve
833  surf_num_flux_minus_surf_soln_int_dot_normal[istate][idim][iquad]
834  = (diss_soln_num_flux[istate] - soln_at_surf_q_int[istate][iquad]) * unit_phys_normal_int[idim] * face_Jac_norm_scaled;
835 
836  surf_num_flux_minus_surf_soln_ext_dot_normal[istate][idim][iquad]
837  = (diss_soln_num_flux[istate] - soln_at_surf_q_ext[istate][iquad]) * (- unit_phys_normal_int[idim]) * face_Jac_norm_scaled;
838  }
839  }
840  }
841  //solve residual and set
842  const std::vector<double> &surf_quad_weights = this->face_quadrature_collection[poly_degree_int].get_weights();
843  for(int istate=0; istate<nstate; istate++){
844  for(int idim=0; idim<dim; idim++){
845  std::vector<real> rhs_int(n_shape_fns_int);
846 
847  soln_basis_int.inner_product_surface_1D(iface,
848  surf_num_flux_minus_surf_soln_int_dot_normal[istate][idim],
849  surf_quad_weights, rhs_int,
850  soln_basis_int.oneD_surf_operator,
851  soln_basis_int.oneD_vol_operator,
852  false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln
853 
854  for(unsigned int ishape=0; ishape<n_shape_fns_int; ishape++){
855  local_auxiliary_RHS_int[istate*n_shape_fns_int + ishape][idim] += rhs_int[ishape];
856  }
857  std::vector<real> rhs_ext(n_shape_fns_ext);
858 
859  soln_basis_ext.inner_product_surface_1D(neighbor_iface,
860  surf_num_flux_minus_surf_soln_ext_dot_normal[istate][idim],
861  surf_quad_weights, rhs_ext,
862  soln_basis_ext.oneD_surf_operator,
863  soln_basis_ext.oneD_vol_operator,
864  false, 1.0);//it's added since auxiliary is EQUAL to the gradient of the soln
865 
866  for(unsigned int ishape=0; ishape<n_shape_fns_ext; ishape++){
867  local_auxiliary_RHS_ext[istate*n_shape_fns_ext + ishape][idim] += rhs_ext[ishape];
868  }
869  }
870  }
871 }
872 
873 /****************************************************
874 *
875 * PRIMARY EQUATIONS STRONG FORM
876 *
877 ****************************************************/
878 template <int dim, int nstate, typename real, typename MeshType>
880  typename dealii::DoFHandler<dim>::active_cell_iterator cell,
881  const dealii::types::global_dof_index current_cell_index,
882  const std::vector<dealii::types::global_dof_index> &cell_dofs_indices,
883  const unsigned int poly_degree,
887  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper,
889  dealii::Vector<real> &local_rhs_int_cell)
890 {
891  (void) current_cell_index;
892 
893  const unsigned int n_quad_pts = this->volume_quadrature_collection[poly_degree].size();
894  const unsigned int n_dofs_cell = this->fe_collection[poly_degree].dofs_per_cell;
895  const unsigned int n_shape_fns = n_dofs_cell / nstate;
896  const unsigned int n_quad_pts_1D = this->oneD_quadrature_collection[poly_degree].size();
897  assert(n_quad_pts == pow(n_quad_pts_1D, dim));
898  const std::vector<double> &vol_quad_weights = this->volume_quadrature_collection[poly_degree].get_weights();
899  const std::vector<double> &oneD_vol_quad_weights = this->oneD_quadrature_collection[poly_degree].get_weights();
900 
901  AssertDimension (n_dofs_cell, cell_dofs_indices.size());
902 
903  // Fetch the modal soln coefficients and the modal auxiliary soln coefficients
904  // We immediately separate them by state as to be able to use sum-factorization
905  // in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector
906  // mult would sum the states at the quadrature point.
907  std::array<std::vector<real>,nstate> soln_coeff;
908  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_coeff;
909  for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
910  const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first;
911  const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second;
912  if(ishape == 0)
913  soln_coeff[istate].resize(n_shape_fns);
914  soln_coeff[istate][ishape] = DGBase<dim,real,MeshType>::solution(cell_dofs_indices[idof]);
915  for(int idim=0; idim<dim; idim++){
916  if(ishape == 0)
917  aux_soln_coeff[istate][idim].resize(n_shape_fns);
918  if(this->use_auxiliary_eq){
919  aux_soln_coeff[istate][idim][ishape] = DGBase<dim,real,MeshType>::auxiliary_solution[idim](cell_dofs_indices[idof]);
920  }
921  else{
922  aux_soln_coeff[istate][idim][ishape] = 0.0;
923  }
924  }
925  }
926  std::array<std::vector<real>,nstate> soln_at_q;
927  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_q; //auxiliary sol at flux nodes
928  std::vector<std::array<real,nstate>> soln_at_q_for_max_CFL(n_quad_pts);//Need soln written in a different for to use pre-existing max CFL function
929  // Interpolate each state to the quadrature points using sum-factorization
930  // with the basis functions in each reference direction.
931  for(int istate=0; istate<nstate; istate++){
932  soln_at_q[istate].resize(n_quad_pts);
933  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q[istate],
934  soln_basis.oneD_vol_operator);
935  for(int idim=0; idim<dim; idim++){
936  aux_soln_at_q[istate][idim].resize(n_quad_pts);
937  soln_basis.matrix_vector_mult_1D(aux_soln_coeff[istate][idim], aux_soln_at_q[istate][idim],
938  soln_basis.oneD_vol_operator);
939  }
940  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
941  soln_at_q_for_max_CFL[iquad][istate] = soln_at_q[istate][iquad];
942  }
943  }
944 
945  // For pseudotime, we need to compute the time_scaled_solution.
946  // Thus, we need to evaluate the max_dt_cell (as previously done in dg/weak_dg.cpp -> assemble_volume_term_explicit)
947  // Get max artificial dissipation
948  real max_artificial_diss = 0.0;
949  const unsigned int n_dofs_arti_diss = this->fe_q_artificial_dissipation.dofs_per_cell;
950  typename dealii::DoFHandler<dim>::active_cell_iterator artificial_dissipation_cell(
951  this->triangulation.get(), cell->level(), cell->index(), &(this->dof_handler_artificial_dissipation));
952  std::vector<dealii::types::global_dof_index> dof_indices_artificial_dissipation(n_dofs_arti_diss);
953  artificial_dissipation_cell->get_dof_indices (dof_indices_artificial_dissipation);
954  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
955  real artificial_diss_coeff_at_q = 0.0;
957  const dealii::Point<dim,real> point = this->volume_quadrature_collection[poly_degree].point(iquad);
958  for (unsigned int idof=0; idof<n_dofs_arti_diss; ++idof) {
959  const unsigned int index = dof_indices_artificial_dissipation[idof];
960  artificial_diss_coeff_at_q += this->artificial_dissipation_c0[index] * this->fe_q_artificial_dissipation.shape_value(idof, point);
961  }
962  max_artificial_diss = std::max(artificial_diss_coeff_at_q, max_artificial_diss);
963  }
964  }
965  // Get max_dt_cell for time_scaled_solution with pseudotime
966  real cell_volume_estimate = 0.0;
967  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
968  cell_volume_estimate += metric_oper.det_Jac_vol[iquad] * vol_quad_weights[iquad];
969  }
970  const real cell_volume = cell_volume_estimate;
971  const real diameter = cell->diameter();
972  const real cell_diameter = cell_volume / std::pow(diameter,dim-1);
973  const real cell_radius = 0.5 * cell_diameter;
974  this->cell_volume[current_cell_index] = cell_volume;
975  this->max_dt_cell[current_cell_index] = this->evaluate_CFL ( soln_at_q_for_max_CFL, max_artificial_diss, cell_radius, poly_degree);
976 
977  //get entropy projected variables
978  std::array<std::vector<real>,nstate> entropy_var_at_q;
979  std::array<std::vector<real>,nstate> projected_entropy_var_at_q;
980  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
981  for(int istate=0; istate<nstate; istate++){
982  entropy_var_at_q[istate].resize(n_quad_pts);
983  projected_entropy_var_at_q[istate].resize(n_quad_pts);
984  }
985  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
986  std::array<real,nstate> soln_state;
987  for(int istate=0; istate<nstate; istate++){
988  soln_state[istate] = soln_at_q[istate][iquad];
989  }
990  std::array<real,nstate> entropy_var;
991  entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state);
992  for(int istate=0; istate<nstate; istate++){
993  entropy_var_at_q[istate][iquad] = entropy_var[istate];
994  }
995  }
996  for(int istate=0; istate<nstate; istate++){
997  std::vector<real> entropy_var_coeff(n_shape_fns);;
998  soln_basis_projection_oper.matrix_vector_mult_1D(entropy_var_at_q[istate],
999  entropy_var_coeff,
1000  soln_basis_projection_oper.oneD_vol_operator);
1001  soln_basis.matrix_vector_mult_1D(entropy_var_coeff,
1002  projected_entropy_var_at_q[istate],
1003  soln_basis.oneD_vol_operator);
1004  }
1005  }
1006 
1007 
1008  //Compute the physical fluxes, then convert them into reference fluxes.
1009  //From the paper: Cicchino, Alexander, et al. "Provably stable flux reconstruction high-order methods on curvilinear elements." Journal of Computational Physics 463 (2022): 111259.
1010  //For conservative DG, we compute the reference flux as per Eq. (9), to then recover the second volume integral in Eq. (17).
1011  //For curvilinear split-form in Eq. (22), we apply a two-pt flux of the metric-cofactor matrix on the matrix operator constructed by the entropy stable/conservtive 2pt flux.
1012  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> conv_ref_flux_at_q;
1013  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> diffusive_ref_flux_at_q;
1014  std::array<std::vector<real>,nstate> source_at_q;
1015  std::array<std::vector<real>,nstate> physical_source_at_q;
1016 
1017  // The matrix of two-pt fluxes for Hadamard products
1018  std::array<std::array<dealii::FullMatrix<real>,dim>,nstate> conv_ref_2pt_flux_at_q;
1019  //Hadamard tensor-product sparsity pattern
1020  std::vector<std::array<unsigned int,dim>> Hadamard_rows_sparsity(n_quad_pts * n_quad_pts_1D);//size n^{d+1}
1021  std::vector<std::array<unsigned int,dim>> Hadamard_columns_sparsity(n_quad_pts * n_quad_pts_1D);
1022  //allocate reference 2pt flux for Hadamard product
1023  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1024  for(int istate=0; istate<nstate; istate++){
1025  for(int idim=0; idim<dim; idim++){
1026  conv_ref_2pt_flux_at_q[istate][idim].reinit(n_quad_pts, n_quad_pts_1D);//size n^d x n
1027  }
1028  }
1029  //extract the dof pairs that give non-zero entries for each direction
1030  //to use the "sum-factorized" Hadamard product.
1031  flux_basis.sum_factorized_Hadamard_sparsity_pattern(n_quad_pts_1D, n_quad_pts_1D, Hadamard_rows_sparsity, Hadamard_columns_sparsity);
1032  }
1033 
1034 
1035  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1036  //extract soln and auxiliary soln at quad pt to be used in physics
1037  std::array<real,nstate> soln_state;
1038  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state;
1039  for(int istate=0; istate<nstate; istate++){
1040  soln_state[istate] = soln_at_q[istate][iquad];
1041  for(int idim=0; idim<dim; idim++){
1042  aux_soln_state[istate][idim] = aux_soln_at_q[istate][idim][iquad];
1043  }
1044  }
1045 
1046  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
1047  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1048  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1049  dealii::Tensor<2,dim,real> metric_cofactor;
1050  for(int idim=0; idim<dim; idim++){
1051  for(int jdim=0; jdim<dim; jdim++){
1052  metric_cofactor[idim][jdim] = metric_oper.metric_cofactor_vol[idim][jdim][iquad];
1053  }
1054  }
1055 
1056  // Evaluate physical convective flux
1057  // If 2pt flux, transform to reference at construction to improve performance.
1058  // We technically use a REFERENCE 2pt flux for all entropy stable schemes.
1059  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux;
1060  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1061  //get the soln for iquad from projected entropy variables
1062  std::array<real,nstate> entropy_var;
1063  for(int istate=0; istate<nstate; istate++){
1064  entropy_var[istate] = projected_entropy_var_at_q[istate][iquad];
1065  }
1066  soln_state = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var);
1067 
1068  //loop over all the non-zero entries for "sum-factorized" Hadamard product that corresponds to the iquad.
1069  for(unsigned int row_index = iquad * n_quad_pts_1D, column_index = 0;
1070  // Hadamard_rows_sparsity[row_index][0] == iquad;
1071  column_index < n_quad_pts_1D;
1072  row_index++, column_index++){
1073 
1074  if(Hadamard_rows_sparsity[row_index][0] != iquad){
1075  pcout<<"The volume Hadamard rows sparsity pattern does not match. Aborting..."<<std::endl;
1076  std::abort();
1077  }
1078 
1079  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
1080  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1081  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1082 
1083  for(int ref_dim=0; ref_dim<dim; ref_dim++){
1084  const unsigned int flux_quad = Hadamard_columns_sparsity[row_index][ref_dim];//extract flux_quad pt that corresponds to a non-zero entry for Hadamard product.
1085 
1086  dealii::Tensor<2,dim,real> metric_cofactor_flux_basis;
1087  for(int idim=0; idim<dim; idim++){
1088  for(int jdim=0; jdim<dim; jdim++){
1089  metric_cofactor_flux_basis[idim][jdim] = metric_oper.metric_cofactor_vol[idim][jdim][flux_quad];
1090  }
1091  }
1092  std::array<real,nstate> soln_state_flux_basis;
1093  std::array<real,nstate> entropy_var_flux_basis;
1094  for(int istate=0; istate<nstate; istate++){
1095  entropy_var_flux_basis[istate] = projected_entropy_var_at_q[istate][flux_quad];
1096  }
1097  soln_state_flux_basis = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_flux_basis);
1098 
1099  //Compute the physical flux
1100  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux_2pt;
1101  conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_flux_basis);
1102 
1103  for(int istate=0; istate<nstate; istate++){
1104  dealii::Tensor<1,dim,real> conv_ref_flux_2pt;
1105  //For each state, transform the physical flux to a reference flux.
1106  metric_oper.transform_physical_to_reference(
1107  conv_phys_flux_2pt[istate],
1108  0.5*(metric_cofactor + metric_cofactor_flux_basis),
1109  conv_ref_flux_2pt);
1110  //write into reference Hadamard flux matrix
1111  conv_ref_2pt_flux_at_q[istate][ref_dim][iquad][column_index] = conv_ref_flux_2pt[ref_dim];
1112  }
1113  }
1114  }
1115  }
1116  else{
1117  //Compute the physical flux
1118  conv_phys_flux = this->pde_physics_double->convective_flux (soln_state);
1119  }
1120 
1121  //Diffusion
1122  std::array<dealii::Tensor<1,dim,real>,nstate> diffusive_phys_flux;
1123  //Compute the physical dissipative flux
1124  diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index);
1125 
1126  // Manufactured source
1127  std::array<real,nstate> manufactured_source;
1129  dealii::Point<dim,real> vol_flux_node;
1130  for(int idim=0; idim<dim; idim++){
1131  vol_flux_node[idim] = metric_oper.flux_nodes_vol[idim][iquad];
1132  }
1133  //compute the manufactured source
1134  manufactured_source = this->pde_physics_double->source_term (vol_flux_node, soln_state, this->current_time, current_cell_index);
1135  }
1136 
1137  // Physical source
1138  std::array<real,nstate> physical_source;
1139  if(this->pde_physics_double->has_nonzero_physical_source) {
1140  dealii::Point<dim,real> vol_flux_node;
1141  for(int idim=0; idim<dim; idim++){
1142  vol_flux_node[idim] = metric_oper.flux_nodes_vol[idim][iquad];
1143  }
1144  //compute the physical source
1145  physical_source = this->pde_physics_double->physical_source_term (vol_flux_node, soln_state, aux_soln_state, current_cell_index);
1146  }
1147 
1148  //Write the values in a way that we can use sum-factorization on.
1149  for(int istate=0; istate<nstate; istate++){
1150  dealii::Tensor<1,dim,real> conv_ref_flux;
1151  dealii::Tensor<1,dim,real> diffusive_ref_flux;
1152  //Trnasform to reference fluxes
1153  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1154  //Do Nothing.
1155  //I am leaving this block here so the diligent reader
1156  //remembers that, for entropy stable schemes, we construct
1157  //a REFERENCE two-point flux at construction, where the physical
1158  //to reference transformation was done by splitting the metric cofactor.
1159  }
1160  else{
1161  //transform the conservative convective physical flux to reference space
1162  metric_oper.transform_physical_to_reference(
1163  conv_phys_flux[istate],
1164  metric_cofactor,
1165  conv_ref_flux);
1166  }
1167  //transform the dissipative flux to reference space
1168  metric_oper.transform_physical_to_reference(
1169  diffusive_phys_flux[istate],
1170  metric_cofactor,
1171  diffusive_ref_flux);
1172 
1173  //Write the data in a way that we can use sum-factorization on.
1174  //Since sum-factorization improves the speed for matrix-vector multiplications,
1175  //We need the values to have their inner elements be vectors.
1176  for(int idim=0; idim<dim; idim++){
1177  //allocate
1178  if(iquad == 0){
1179  conv_ref_flux_at_q[istate][idim].resize(n_quad_pts);
1180  diffusive_ref_flux_at_q[istate][idim].resize(n_quad_pts);
1181  }
1182  //write data
1183  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1184  //Do nothing because written in a Hadamard product sum-factorized form above.
1185  }
1186  else{
1187  conv_ref_flux_at_q[istate][idim][iquad] = conv_ref_flux[idim];
1188  }
1189 
1190  diffusive_ref_flux_at_q[istate][idim][iquad] = diffusive_ref_flux[idim];
1191  }
1193  if(iquad == 0){
1194  source_at_q[istate].resize(n_quad_pts);
1195  }
1196  source_at_q[istate][iquad] = manufactured_source[istate];
1197  }
1198  if(this->pde_physics_double->has_nonzero_physical_source) {
1199  if(iquad == 0){
1200  physical_source_at_q[istate].resize(n_quad_pts);
1201  }
1202  physical_source_at_q[istate][iquad] = physical_source[istate];
1203  }
1204  }
1205  }
1206 
1207  // Get a flux basis reference gradient operator in a sum-factorized Hadamard product sparse form. Then apply the divergence.
1208  std::array<dealii::FullMatrix<real>,dim> flux_basis_stiffness_skew_symm_oper_sparse;
1209  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1210  for(int idim=0; idim<dim; idim++){
1211  flux_basis_stiffness_skew_symm_oper_sparse[idim].reinit(n_quad_pts, n_quad_pts_1D);
1212  }
1213  flux_basis.sum_factorized_Hadamard_basis_assembly(n_quad_pts_1D, n_quad_pts_1D,
1214  Hadamard_rows_sparsity, Hadamard_columns_sparsity,
1215  flux_basis_stiffness.oneD_skew_symm_vol_oper,
1216  oneD_vol_quad_weights,
1217  flux_basis_stiffness_skew_symm_oper_sparse);
1218  }
1219 
1220  //For each state we:
1221  // 1. Compute reference divergence.
1222  // 2. Then compute and write the rhs for the given state.
1223  for(int istate=0; istate<nstate; istate++){
1224 
1225  //Compute reference divergence of the reference fluxes.
1226  std::vector<real> conv_flux_divergence(n_quad_pts);
1227  std::vector<real> diffusive_flux_divergence(n_quad_pts);
1228 
1229  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1230  //2pt flux Hadamard Product, and then multiply by vector of ones scaled by 1.
1231  // Same as the volume term in Eq. (15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485. but,
1232  // where we use the reference skew-symmetric stiffness operator of the flux basis for the Q operator and the reference two-point flux as to make use of Alex's Hadamard product
1233  // sum-factorization type algorithm that exploits the structure of the flux basis in the reference space to have O(n^{d+1}).
1234 
1235  for(int ref_dim=0; ref_dim<dim; ref_dim++){
1236  dealii::FullMatrix<real> divergence_ref_flux_Hadamard_product(n_quad_pts, n_quad_pts_1D);
1237  flux_basis.Hadamard_product(flux_basis_stiffness_skew_symm_oper_sparse[ref_dim], conv_ref_2pt_flux_at_q[istate][ref_dim], divergence_ref_flux_Hadamard_product);
1238  //Hadamard product times the vector of ones.
1239  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
1240  if(ref_dim == 0){
1241  conv_flux_divergence[iquad] = 0.0;
1242  }
1243  for(unsigned int iquad_1D=0; iquad_1D<n_quad_pts_1D; iquad_1D++){
1244  conv_flux_divergence[iquad] += divergence_ref_flux_Hadamard_product[iquad][iquad_1D];
1245  }
1246  }
1247  }
1248 
1249  }
1250  else{
1251  //Reference divergence of the reference convective flux.
1252  flux_basis.divergence_matrix_vector_mult_1D(conv_ref_flux_at_q[istate], conv_flux_divergence,
1253  flux_basis.oneD_vol_operator,
1254  flux_basis.oneD_grad_operator);
1255  }
1256  //Reference divergence of the reference diffusive flux.
1257  flux_basis.divergence_matrix_vector_mult_1D(diffusive_ref_flux_at_q[istate], diffusive_flux_divergence,
1258  flux_basis.oneD_vol_operator,
1259  flux_basis.oneD_grad_operator);
1260 
1261 
1262  // Strong form
1263  // The right-hand side sends all the term to the side of the source term
1264  // Therefore,
1265  // \divergence ( Fconv + Fdiss ) = source
1266  // has the right-hand side
1267  // rhs = - \divergence( Fconv + Fdiss ) + source
1268  // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss
1269  // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side
1270  std::vector<real> rhs(n_shape_fns);
1271 
1272  // Convective
1273  if (this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1274  std::vector<real> ones(n_quad_pts, 1.0);
1275  soln_basis.inner_product_1D(conv_flux_divergence, ones, rhs, soln_basis.oneD_vol_operator, false, -1.0);
1276  }
1277  else {
1278  soln_basis.inner_product_1D(conv_flux_divergence, vol_quad_weights, rhs, soln_basis.oneD_vol_operator, false, -1.0);
1279  }
1280 
1281  // Diffusive
1282  // Note that for diffusion, the negative is defined in the physics. Since we used the auxiliary
1283  // variable, put a negative here.
1284  soln_basis.inner_product_1D(diffusive_flux_divergence, vol_quad_weights, rhs, soln_basis.oneD_vol_operator, true, -1.0);
1285 
1286  // Manufactured source
1288  std::vector<real> JxW(n_quad_pts);
1289  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
1290  JxW[iquad] = vol_quad_weights[iquad] * metric_oper.det_Jac_vol[iquad];
1291  }
1292  soln_basis.inner_product_1D(source_at_q[istate], JxW, rhs, soln_basis.oneD_vol_operator, true, 1.0);
1293  }
1294 
1295  // Physical source
1296  if(this->pde_physics_double->has_nonzero_physical_source) {
1297  std::vector<real> JxW(n_quad_pts);
1298  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
1299  JxW[iquad] = vol_quad_weights[iquad] * metric_oper.det_Jac_vol[iquad];
1300  }
1301  soln_basis.inner_product_1D(physical_source_at_q[istate], JxW, rhs, soln_basis.oneD_vol_operator, true, 1.0);
1302  }
1303 
1304  for(unsigned int ishape=0; ishape<n_shape_fns; ishape++){
1305  local_rhs_int_cell(istate*n_shape_fns + ishape) += rhs[ishape];
1306  }
1307 
1308  }
1309 }
1310 
1311 template <int dim, int nstate, typename real, typename MeshType>
1313  const unsigned int iface,
1314  const dealii::types::global_dof_index current_cell_index,
1315  const unsigned int boundary_id,
1316  const unsigned int poly_degree,
1317  const real penalty,
1318  const std::vector<dealii::types::global_dof_index> &dof_indices,
1321  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper,
1323  dealii::Vector<real> &local_rhs_cell)
1324 {
1325  (void) current_cell_index;
1326 
1327  const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree].size();
1328  const unsigned int n_quad_pts_vol = this->volume_quadrature_collection[poly_degree].size();
1329  const unsigned int n_quad_pts_1D = this->oneD_quadrature_collection[poly_degree].size();
1330  const unsigned int n_dofs = this->fe_collection[poly_degree].dofs_per_cell;
1331  const unsigned int n_shape_fns = n_dofs / nstate;
1332  const std::vector<double> &face_quad_weights = this->face_quadrature_collection[poly_degree].get_weights();
1333 
1334  AssertDimension (n_dofs, dof_indices.size());
1335 
1336  // Fetch the modal soln coefficients and the modal auxiliary soln coefficients
1337  // We immediately separate them by state as to be able to use sum-factorization
1338  // in the interpolation operator. If we left it by n_dofs_cell, then the matrix-vector
1339  // mult would sum the states at the quadrature point.
1340  std::array<std::vector<real>,nstate> soln_coeff;
1341  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_coeff;
1342  for (unsigned int idof = 0; idof < n_dofs; ++idof) {
1343  const unsigned int istate = this->fe_collection[poly_degree].system_to_component_index(idof).first;
1344  const unsigned int ishape = this->fe_collection[poly_degree].system_to_component_index(idof).second;
1345  // allocate
1346  if(ishape == 0){
1347  soln_coeff[istate].resize(n_shape_fns);
1348  }
1349  // solve
1350  soln_coeff[istate][ishape] = DGBase<dim,real,MeshType>::solution(dof_indices[idof]);
1351  for(int idim=0; idim<dim; idim++){
1352  //allocate
1353  if(ishape == 0){
1354  aux_soln_coeff[istate][idim].resize(n_shape_fns);
1355  }
1356  //solve
1357  if(this->use_auxiliary_eq){
1358  aux_soln_coeff[istate][idim][ishape] = DGBase<dim,real,MeshType>::auxiliary_solution[idim](dof_indices[idof]);
1359  }
1360  else{
1361  aux_soln_coeff[istate][idim][ishape] = 0.0;
1362  }
1363  }
1364  }
1365  // Interpolate the modal coefficients to the volume cubature nodes.
1366  std::array<std::vector<real>,nstate> soln_at_vol_q;
1367  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_vol_q;
1368  // Interpolate modal soln coefficients to the facet.
1369  std::array<std::vector<real>,nstate> soln_at_surf_q;
1370  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_surf_q;
1371  for(int istate=0; istate<nstate; ++istate){
1372  //allocate
1373  soln_at_vol_q[istate].resize(n_quad_pts_vol);
1374  //solve soln at volume cubature nodes
1375  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_vol_q[istate],
1376  soln_basis.oneD_vol_operator);
1377 
1378  //allocate
1379  soln_at_surf_q[istate].resize(n_face_quad_pts);
1380  //solve soln at facet cubature nodes
1381  soln_basis.matrix_vector_mult_surface_1D(iface,
1382  soln_coeff[istate], soln_at_surf_q[istate],
1383  soln_basis.oneD_surf_operator,
1384  soln_basis.oneD_vol_operator);
1385 
1386  for(int idim=0; idim<dim; idim++){
1387  //alocate
1388  aux_soln_at_vol_q[istate][idim].resize(n_quad_pts_vol);
1389  //solve auxiliary soln at volume cubature nodes
1390  soln_basis.matrix_vector_mult_1D(aux_soln_coeff[istate][idim], aux_soln_at_vol_q[istate][idim],
1391  soln_basis.oneD_vol_operator);
1392 
1393  //allocate
1394  aux_soln_at_surf_q[istate][idim].resize(n_face_quad_pts);
1395  //solve auxiliary soln at facet cubature nodes
1396  soln_basis.matrix_vector_mult_surface_1D(iface,
1397  aux_soln_coeff[istate][idim], aux_soln_at_surf_q[istate][idim],
1398  soln_basis.oneD_surf_operator,
1399  soln_basis.oneD_vol_operator);
1400  }
1401  }
1402 
1403  // Get volume reference fluxes and interpolate them to the facet.
1404  // Compute reference volume fluxes in both interior and exterior cells.
1405 
1406  // First we do interior.
1407  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> conv_ref_flux_at_vol_q;
1408  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> diffusive_ref_flux_at_vol_q;
1409  for (unsigned int iquad=0; iquad<n_quad_pts_vol; ++iquad) {
1410  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
1411  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1412  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1413  dealii::Tensor<2,dim,real> metric_cofactor_vol;
1414  for(int idim=0; idim<dim; idim++){
1415  for(int jdim=0; jdim<dim; jdim++){
1416  metric_cofactor_vol[idim][jdim] = metric_oper.metric_cofactor_vol[idim][jdim][iquad];
1417  }
1418  }
1419  std::array<real,nstate> soln_state;
1420  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state;
1421  for(int istate=0; istate<nstate; istate++){
1422  soln_state[istate] = soln_at_vol_q[istate][iquad];
1423  for(int idim=0; idim<dim; idim++){
1424  aux_soln_state[istate][idim] = aux_soln_at_vol_q[istate][idim][iquad];
1425  }
1426  }
1427 
1428  // Evaluate physical convective flux
1429  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux;
1430  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1431  conv_phys_flux = this->pde_physics_double->convective_flux (soln_state);
1432  }
1433 
1434  // Compute the physical dissipative flux
1435  std::array<dealii::Tensor<1,dim,real>,nstate> diffusive_phys_flux;
1436  diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index);
1437 
1438  // Write the values in a way that we can use sum-factorization on.
1439  for(int istate=0; istate<nstate; istate++){
1440  dealii::Tensor<1,dim,real> conv_ref_flux;
1441  dealii::Tensor<1,dim,real> diffusive_ref_flux;
1442  // transform the conservative convective physical flux to reference space
1443  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1444  metric_oper.transform_physical_to_reference(
1445  conv_phys_flux[istate],
1446  metric_cofactor_vol,
1447  conv_ref_flux);
1448  }
1449  // transform the dissipative flux to reference space
1450  metric_oper.transform_physical_to_reference(
1451  diffusive_phys_flux[istate],
1452  metric_cofactor_vol,
1453  diffusive_ref_flux);
1454 
1455  // Write the data in a way that we can use sum-factorization on.
1456  // Since sum-factorization improves the speed for matrix-vector multiplications,
1457  // We need the values to have their inner elements be vectors.
1458  for(int idim=0; idim<dim; idim++){
1459  //allocate
1460  if(iquad == 0){
1461  conv_ref_flux_at_vol_q[istate][idim].resize(n_quad_pts_vol);
1462  diffusive_ref_flux_at_vol_q[istate][idim].resize(n_quad_pts_vol);
1463  }
1464  //write data
1465  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1466  conv_ref_flux_at_vol_q[istate][idim][iquad] = conv_ref_flux[idim];
1467  }
1468 
1469  diffusive_ref_flux_at_vol_q[istate][idim][iquad] = diffusive_ref_flux[idim];
1470  }
1471  }
1472  }
1473 
1474  // Interpolate the volume reference fluxes to the facet.
1475  // And do the dot product with the UNIT REFERENCE normal.
1476  // Since we are computing a dot product with the unit reference normal,
1477  // we exploit the fact that the unit reference normal has a value of 0 in all reference directions except
1478  // the outward reference normal dircetion.
1479  const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo<dim>::unit_normal_vector[iface];
1480  const int dim_not_zero = iface / 2;//reference direction of face integer division
1481 
1482  std::array<std::vector<real>,nstate> conv_int_vol_ref_flux_interp_to_face_dot_ref_normal;
1483  std::array<std::vector<real>,nstate> diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal;
1484  for(int istate=0; istate<nstate; istate++){
1485  //allocate
1486  conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
1487  diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
1488 
1489  //solve
1490  //Note, since the normal is zero in all other reference directions, we only have to interpolate one given reference direction to the facet
1491 
1492  //interpolate reference volume convective flux to the facet, and apply unit reference normal as scaled by 1.0 or -1.0
1493  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1494  flux_basis.matrix_vector_mult_surface_1D(iface,
1495  conv_ref_flux_at_vol_q[istate][dim_not_zero],
1496  conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
1497  flux_basis.oneD_surf_operator,//the flux basis interpolates from the flux nodes
1498  flux_basis.oneD_vol_operator,
1499  false, unit_ref_normal_int[dim_not_zero]);//don't add to previous value, scale by unit_normal int
1500  }
1501 
1502  //interpolate reference volume dissipative flux to the facet, and apply unit reference normal as scaled by 1.0 or -1.0
1503  flux_basis.matrix_vector_mult_surface_1D(iface,
1504  diffusive_ref_flux_at_vol_q[istate][dim_not_zero],
1505  diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
1506  flux_basis.oneD_surf_operator,
1507  flux_basis.oneD_vol_operator,
1508  false, unit_ref_normal_int[dim_not_zero]);
1509  }
1510 
1511  //Note that for entropy-dissipation and entropy stability, the conservative variables
1512  //are functions of projected entropy variables. For Euler etc, the transformation is nonlinear
1513  //so careful attention to what is evaluated where and interpolated to where is needed.
1514  //For further information, please see Chan, Jesse. "On discretely entropy conservative and entropy stable discontinuous Galerkin methods." Journal of Computational Physics 362 (2018): 346-374.
1515  //pages 355 (Eq. 57 with text around it) and page 359 (Eq 86 and text below it).
1516 
1517  // First, transform the volume conservative solution at volume cubature nodes to entropy variables.
1518  std::array<std::vector<real>,nstate> entropy_var_vol;
1519  for(unsigned int iquad=0; iquad<n_quad_pts_vol; iquad++){
1520  std::array<real,nstate> soln_state;
1521  for(int istate=0; istate<nstate; istate++){
1522  soln_state[istate] = soln_at_vol_q[istate][iquad];
1523  }
1524  std::array<real,nstate> entropy_var;
1525  entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state);
1526  for(int istate=0; istate<nstate; istate++){
1527  if(iquad==0){
1528  entropy_var_vol[istate].resize(n_quad_pts_vol);
1529  }
1530  entropy_var_vol[istate][iquad] = entropy_var[istate];
1531  }
1532  }
1533 
1534  //project it onto the solution basis functions and interpolate it
1535  std::array<std::vector<real>,nstate> projected_entropy_var_vol;
1536  std::array<std::vector<real>,nstate> projected_entropy_var_surf;
1537  for(int istate=0; istate<nstate; istate++){
1538  // allocate
1539  projected_entropy_var_vol[istate].resize(n_quad_pts_vol);
1540  projected_entropy_var_surf[istate].resize(n_face_quad_pts);
1541 
1542  //interior
1543  std::vector<real> entropy_var_coeff(n_shape_fns);
1544  soln_basis_projection_oper.matrix_vector_mult_1D(entropy_var_vol[istate],
1545  entropy_var_coeff,
1546  soln_basis_projection_oper.oneD_vol_operator);
1547  soln_basis.matrix_vector_mult_1D(entropy_var_coeff,
1548  projected_entropy_var_vol[istate],
1549  soln_basis.oneD_vol_operator);
1550  soln_basis.matrix_vector_mult_surface_1D(iface,
1551  entropy_var_coeff,
1552  projected_entropy_var_surf[istate],
1553  soln_basis.oneD_surf_operator,
1554  soln_basis.oneD_vol_operator);
1555  }
1556 
1557  //get the surface-volume sparsity pattern for a "sum-factorized" Hadamard product only computing terms needed for the operation.
1558  const unsigned int row_size = n_face_quad_pts * n_quad_pts_1D;
1559  const unsigned int col_size = n_face_quad_pts * n_quad_pts_1D;
1560  std::vector<unsigned int> Hadamard_rows_sparsity(row_size);
1561  std::vector<unsigned int> Hadamard_columns_sparsity(col_size);
1562  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1563  flux_basis.sum_factorized_Hadamard_surface_sparsity_pattern(n_face_quad_pts, n_quad_pts_1D, Hadamard_rows_sparsity, Hadamard_columns_sparsity, dim_not_zero);
1564  }
1565 
1566  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_surf;
1567  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_vol;
1568  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1569  //get surface-volume hybrid 2pt flux from Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485.
1570  std::array<dealii::FullMatrix<real>,nstate> surface_ref_2pt_flux;
1571  //make use of the sparsity pattern from above to assemble only n^d non-zero entries without ever allocating not computing zeros.
1572  for(int istate=0; istate<nstate; istate++){
1573  surface_ref_2pt_flux[istate].reinit(n_face_quad_pts, n_quad_pts_1D);
1574  }
1575  for(unsigned int iquad_face=0; iquad_face<n_face_quad_pts; iquad_face++){
1576  dealii::Tensor<2,dim,real> metric_cofactor_surf;
1577  for(int idim=0; idim<dim; idim++){
1578  for(int jdim=0; jdim<dim; jdim++){
1579  metric_cofactor_surf[idim][jdim] = metric_oper.metric_cofactor_surf[idim][jdim][iquad_face];
1580  }
1581  }
1582 
1583  //Compute the conservative values on the facet from the interpolated entorpy variables.
1584  std::array<real,nstate> entropy_var_face;
1585  for(int istate=0; istate<nstate; istate++){
1586  entropy_var_face[istate] = projected_entropy_var_surf[istate][iquad_face];
1587  }
1588  std::array<real,nstate> soln_state_face;
1589  soln_state_face= this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face);
1590 
1591  //only do the n_quad_1D vol points that give non-zero entries from Hadamard product.
1592  for(unsigned int row_index = iquad_face * n_quad_pts_1D, column_index = 0;
1593  column_index < n_quad_pts_1D;
1594  row_index++, column_index++){
1595 
1596  if(Hadamard_rows_sparsity[row_index] != iquad_face){
1597  pcout<<"The boundary Hadamard rows sparsity pattern does not match."<<std::endl;
1598  std::abort();
1599  }
1600 
1601  const unsigned int iquad_vol = Hadamard_columns_sparsity[row_index];//extract flux_quad pt that corresponds to a non-zero entry for Hadamard product.
1602  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
1603  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1604  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1605  dealii::Tensor<2,dim,real> metric_cofactor_vol;
1606  for(int idim=0; idim<dim; idim++){
1607  for(int jdim=0; jdim<dim; jdim++){
1608  metric_cofactor_vol[idim][jdim] = metric_oper.metric_cofactor_vol[idim][jdim][iquad_vol];
1609  }
1610  }
1611  std::array<real,nstate> entropy_var;
1612  for(int istate=0; istate<nstate; istate++){
1613  entropy_var[istate] = projected_entropy_var_vol[istate][iquad_vol];
1614  }
1615  std::array<real,nstate> soln_state;
1616  soln_state = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var);
1617  //Note that the flux basis is collocated on the volume cubature set so we don't need to evaluate the entropy variables
1618  //on the volume set then transform back to the conservative variables since the flux basis volume
1619  //projection is identity.
1620 
1621  //Compute the physical flux
1622  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux_2pt;
1623  conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_face);
1624  for(int istate=0; istate<nstate; istate++){
1625  dealii::Tensor<1,dim,real> conv_ref_flux_2pt;
1626  //For each state, transform the physical flux to a reference flux.
1627  metric_oper.transform_physical_to_reference(
1628  conv_phys_flux_2pt[istate],
1629  0.5*(metric_cofactor_surf + metric_cofactor_vol),
1630  conv_ref_flux_2pt);
1631  //only store the dim not zero in reference space bc dot product with unit ref normal later.
1632  surface_ref_2pt_flux[istate][iquad_face][column_index] = conv_ref_flux_2pt[dim_not_zero];
1633  }
1634  }
1635  }
1636  //get the surface basis operator from Hadamard sparsity pattern
1637  //to be applied at n^d operations (on the face so n^{d+1-1}=n^d flops)
1638  //also only allocates n^d terms.
1639  const int iface_1D = iface % 2;//the reference face number
1640  const std::vector<double> &oneD_quad_weights_vol= this->oneD_quadrature_collection[poly_degree].get_weights();
1641  dealii::FullMatrix<real> surf_oper_sparse(n_face_quad_pts, n_quad_pts_1D);
1642  flux_basis.sum_factorized_Hadamard_surface_basis_assembly(n_face_quad_pts, n_quad_pts_1D,
1643  Hadamard_rows_sparsity, Hadamard_columns_sparsity,
1644  flux_basis.oneD_surf_operator[iface_1D],
1645  oneD_quad_weights_vol,
1646  surf_oper_sparse,
1647  dim_not_zero);
1648 
1649  // Apply the surface Hadamard products and multiply with vector of ones for both off diagonal terms in
1650  // Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485.
1651  for(int istate=0; istate<nstate; istate++){
1652  //first apply Hadamard product with the structure made above.
1653  dealii::FullMatrix<real> surface_ref_2pt_flux_int_Hadamard_with_surf_oper(n_face_quad_pts, n_quad_pts_1D);
1654  flux_basis.Hadamard_product(surf_oper_sparse,
1655  surface_ref_2pt_flux[istate],
1656  surface_ref_2pt_flux_int_Hadamard_with_surf_oper);
1657  //sum with reference unit normal
1658  surf_vol_ref_2pt_flux_interp_surf[istate].resize(n_face_quad_pts);
1659  surf_vol_ref_2pt_flux_interp_vol[istate].resize(n_quad_pts_vol);
1660 
1661  for(unsigned int iface_quad=0; iface_quad<n_face_quad_pts; iface_quad++){
1662  for(unsigned int iquad_int=0; iquad_int<n_quad_pts_1D; iquad_int++){
1663  surf_vol_ref_2pt_flux_interp_surf[istate][iface_quad]
1664  -= surface_ref_2pt_flux_int_Hadamard_with_surf_oper[iface_quad][iquad_int]
1665  * unit_ref_normal_int[dim_not_zero];
1666  const unsigned int column_index = iface_quad * n_quad_pts_1D + iquad_int;
1667  surf_vol_ref_2pt_flux_interp_vol[istate][Hadamard_columns_sparsity[column_index]]
1668  += surface_ref_2pt_flux_int_Hadamard_with_surf_oper[iface_quad][iquad_int]
1669  * unit_ref_normal_int[dim_not_zero];
1670  }
1671  }
1672  }
1673  }//end of if split form or curvilinear split form
1674 
1675 
1676  //the outward reference normal dircetion.
1677  std::array<std::vector<real>,nstate> conv_flux_dot_normal;
1678  std::array<std::vector<real>,nstate> diss_flux_dot_normal_diff;
1679  // Get surface numerical fluxes
1680  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
1681  // Copy Metric Cofactor on the facet in a way can use for transforming Tensor Blocks to reference space
1682  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1683  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1684  // Note that for a conforming mesh, the facet metric cofactor matrix is the same from either interioir or exterior metric terms.
1685  // This is verified for the metric computations in: unit_tests/operator_tests/surface_conforming_test.cpp
1686  dealii::Tensor<2,dim,real> metric_cofactor_surf;
1687  for(int idim=0; idim<dim; idim++){
1688  for(int jdim=0; jdim<dim; jdim++){
1689  metric_cofactor_surf[idim][jdim] = metric_oper.metric_cofactor_surf[idim][jdim][iquad];
1690  }
1691  }
1692  //numerical fluxes
1693  dealii::Tensor<1,dim,real> unit_phys_normal_int;
1694  metric_oper.transform_reference_to_physical(unit_ref_normal_int,
1695  metric_cofactor_surf,
1696  unit_phys_normal_int);
1697  const double face_Jac_norm_scaled = unit_phys_normal_int.norm();
1698  unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it.
1699 
1700  //get the projected entropy variables, soln, and
1701  //auxiliary solution on the surface point.
1702  std::array<real,nstate> entropy_var_face_int;
1703  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state_int;
1704  std::array<real,nstate> soln_interp_to_face_int;
1705  for(int istate=0; istate<nstate; istate++){
1706  soln_interp_to_face_int[istate] = soln_at_surf_q[istate][iquad];
1707  entropy_var_face_int[istate] = projected_entropy_var_surf[istate][iquad];
1708  for(int idim=0; idim<dim; idim++){
1709  aux_soln_state_int[istate][idim] = aux_soln_at_surf_q[istate][idim][iquad];
1710  }
1711  }
1712 
1713  //extract solution on surface from projected entropy variables
1714  std::array<real,nstate> soln_state_int;
1715  soln_state_int = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_int);
1716 
1717 
1718  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1719  for(int istate=0; istate<nstate; istate++){
1720  soln_state_int[istate] = soln_at_surf_q[istate][iquad];
1721  }
1722  }
1723 
1724  std::array<real,nstate> soln_boundary;
1725  std::array<dealii::Tensor<1,dim,real>,nstate> grad_soln_boundary;
1726  dealii::Point<dim,real> surf_flux_node;
1727  for(int idim=0; idim<dim; idim++){
1728  surf_flux_node[idim] = metric_oper.flux_nodes_surf[iface][idim][iquad];
1729  }
1730  //I am not sure if BC should be from solution interpolated to face
1731  //or solution from the projected entropy variables.
1732  //Now, it uses projected entropy variables for NSFR, and solution
1733  //interpolated to face for conservative DG.
1734  this->pde_physics_double->boundary_face_values (boundary_id, surf_flux_node, unit_phys_normal_int, soln_state_int, aux_soln_state_int, soln_boundary, grad_soln_boundary);
1735 
1736  // Convective numerical flux.
1737  std::array<real,nstate> conv_num_flux_dot_n_at_q;
1738  conv_num_flux_dot_n_at_q = this->conv_num_flux_double->evaluate_flux(soln_state_int, soln_boundary, unit_phys_normal_int);
1739 
1740  // Dissipative numerical flux
1741  std::array<real,nstate> diss_auxi_num_flux_dot_n_at_q;
1742  diss_auxi_num_flux_dot_n_at_q = this->diss_num_flux_double->evaluate_auxiliary_flux(
1743  current_cell_index, current_cell_index,
1744  0.0, 0.0,
1745  soln_interp_to_face_int, soln_boundary,
1746  aux_soln_state_int, grad_soln_boundary,
1747  unit_phys_normal_int, penalty, true);
1748 
1749  for(int istate=0; istate<nstate; istate++){
1750  // allocate
1751  if(iquad==0){
1752  conv_flux_dot_normal[istate].resize(n_face_quad_pts);
1753  diss_flux_dot_normal_diff[istate].resize(n_face_quad_pts);
1754  }
1755  // write data
1756  conv_flux_dot_normal[istate][iquad] = face_Jac_norm_scaled * conv_num_flux_dot_n_at_q[istate];
1757  diss_flux_dot_normal_diff[istate][iquad] = face_Jac_norm_scaled * diss_auxi_num_flux_dot_n_at_q[istate]
1758  - diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate][iquad];
1759  }
1760  }
1761 
1762  //solve rhs
1763  for(int istate=0; istate<nstate; istate++){
1764  std::vector<real> rhs(n_shape_fns);
1765  //Convective flux on the facet
1766  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
1767  std::vector<real> ones_surf(n_face_quad_pts, 1.0);
1768  soln_basis.inner_product_surface_1D(iface,
1769  surf_vol_ref_2pt_flux_interp_surf[istate],
1770  ones_surf, rhs,
1771  soln_basis.oneD_surf_operator,
1772  soln_basis.oneD_vol_operator,
1773  false, -1.0);
1774  std::vector<real> ones_vol(n_quad_pts_vol, 1.0);
1775  soln_basis.inner_product_1D(surf_vol_ref_2pt_flux_interp_vol[istate],
1776  ones_vol, rhs,
1777  soln_basis.oneD_vol_operator,
1778  true, -1.0);
1779  }
1780  else{
1781  soln_basis.inner_product_surface_1D(iface, conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
1782  face_quad_weights, rhs,
1783  soln_basis.oneD_surf_operator,
1784  soln_basis.oneD_vol_operator,
1785  false, 1.0);//adding=false, scaled by factor=-1.0 bc subtract it
1786  }
1787  //Convective surface nnumerical flux.
1788  soln_basis.inner_product_surface_1D(iface, conv_flux_dot_normal[istate],
1789  face_quad_weights, rhs,
1790  soln_basis.oneD_surf_operator,
1791  soln_basis.oneD_vol_operator,
1792  true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it
1793  //Dissipative surface numerical flux.
1794  soln_basis.inner_product_surface_1D(iface, diss_flux_dot_normal_diff[istate],
1795  face_quad_weights, rhs,
1796  soln_basis.oneD_surf_operator,
1797  soln_basis.oneD_vol_operator,
1798  true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it
1799 
1800  for(unsigned int ishape=0; ishape<n_shape_fns; ishape++){
1801  local_rhs_cell(istate*n_shape_fns + ishape) += rhs[ishape];
1802  }
1803  }
1804 }
1805 
1806 
1807 template <int dim, int nstate, typename real, typename MeshType>
1809  const unsigned int iface, const unsigned int neighbor_iface,
1810  const dealii::types::global_dof_index current_cell_index,
1811  const dealii::types::global_dof_index neighbor_cell_index,
1812  const unsigned int poly_degree_int,
1813  const unsigned int poly_degree_ext,
1814  const real penalty,
1815  const std::vector<dealii::types::global_dof_index> &dof_indices_int,
1816  const std::vector<dealii::types::global_dof_index> &dof_indices_ext,
1821  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_int,
1822  OPERATOR::vol_projection_operator<dim,2*dim,real> &soln_basis_projection_oper_ext,
1825  dealii::Vector<real> &local_rhs_int_cell,
1826  dealii::Vector<real> &local_rhs_ext_cell)
1827 {
1828  (void) current_cell_index;
1829  (void) neighbor_cell_index;
1830 
1831  const unsigned int n_face_quad_pts = this->face_quadrature_collection[poly_degree_int].size();//assume interior cell does the work
1832 
1833  const unsigned int n_quad_pts_vol_int = this->volume_quadrature_collection[poly_degree_int].size();
1834  const unsigned int n_quad_pts_vol_ext = this->volume_quadrature_collection[poly_degree_ext].size();
1835  const unsigned int n_quad_pts_1D_int = this->oneD_quadrature_collection[poly_degree_int].size();
1836  const unsigned int n_quad_pts_1D_ext = this->oneD_quadrature_collection[poly_degree_ext].size();
1837 
1838  const unsigned int n_dofs_int = this->fe_collection[poly_degree_int].dofs_per_cell;
1839  const unsigned int n_dofs_ext = this->fe_collection[poly_degree_ext].dofs_per_cell;
1840 
1841  const unsigned int n_shape_fns_int = n_dofs_int / nstate;
1842  const unsigned int n_shape_fns_ext = n_dofs_ext / nstate;
1843 
1844  AssertDimension (n_dofs_int, dof_indices_int.size());
1845  AssertDimension (n_dofs_ext, dof_indices_ext.size());
1846 
1847  // Extract interior modal coefficients of solution
1848  std::array<std::vector<real>,nstate> soln_coeff_int;
1849  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_coeff_int;
1850  for (unsigned int idof = 0; idof < n_dofs_int; ++idof) {
1851  const unsigned int istate = this->fe_collection[poly_degree_int].system_to_component_index(idof).first;
1852  const unsigned int ishape = this->fe_collection[poly_degree_int].system_to_component_index(idof).second;
1853  if(ishape == 0)
1854  soln_coeff_int[istate].resize(n_shape_fns_int);
1855 
1856  soln_coeff_int[istate][ishape] = DGBase<dim,real,MeshType>::solution(dof_indices_int[idof]);
1857  for(int idim=0; idim<dim; idim++){
1858  if(ishape == 0){
1859  aux_soln_coeff_int[istate][idim].resize(n_shape_fns_int);
1860  }
1861  if(this->use_auxiliary_eq){
1862  aux_soln_coeff_int[istate][idim][ishape] = DGBase<dim,real,MeshType>::auxiliary_solution[idim](dof_indices_int[idof]);
1863  }
1864  else{
1865  aux_soln_coeff_int[istate][idim][ishape] = 0.0;
1866  }
1867  }
1868  }
1869 
1870  // Extract exterior modal coefficients of solution
1871  std::array<std::vector<real>,nstate> soln_coeff_ext;
1872  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_coeff_ext;
1873  for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) {
1874  const unsigned int istate = this->fe_collection[poly_degree_ext].system_to_component_index(idof).first;
1875  const unsigned int ishape = this->fe_collection[poly_degree_ext].system_to_component_index(idof).second;
1876  if(ishape == 0){
1877  soln_coeff_ext[istate].resize(n_shape_fns_ext);
1878  }
1879  soln_coeff_ext[istate][ishape] = DGBase<dim,real,MeshType>::solution(dof_indices_ext[idof]);
1880  for(int idim=0; idim<dim; idim++){
1881  if(ishape == 0){
1882  aux_soln_coeff_ext[istate][idim].resize(n_shape_fns_ext);
1883  }
1884  if(this->use_auxiliary_eq){
1885  aux_soln_coeff_ext[istate][idim][ishape] = DGBase<dim,real,MeshType>::auxiliary_solution[idim](dof_indices_ext[idof]);
1886  }
1887  else{
1888  aux_soln_coeff_ext[istate][idim][ishape] = 0.0;
1889  }
1890  }
1891  }
1892 
1893  // Interpolate the modal coefficients to the volume cubature nodes.
1894  std::array<std::vector<real>,nstate> soln_at_vol_q_int;
1895  std::array<std::vector<real>,nstate> soln_at_vol_q_ext;
1896  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_vol_q_int;
1897  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_vol_q_ext;
1898  // Interpolate modal soln coefficients to the facet.
1899  std::array<std::vector<real>,nstate> soln_at_surf_q_int;
1900  std::array<std::vector<real>,nstate> soln_at_surf_q_ext;
1901  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_surf_q_int;
1902  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> aux_soln_at_surf_q_ext;
1903  for(int istate=0; istate<nstate; ++istate){
1904  // allocate
1905  soln_at_vol_q_int[istate].resize(n_quad_pts_vol_int);
1906  soln_at_vol_q_ext[istate].resize(n_quad_pts_vol_ext);
1907  // solve soln at volume cubature nodes
1908  soln_basis_int.matrix_vector_mult_1D(soln_coeff_int[istate], soln_at_vol_q_int[istate],
1909  soln_basis_int.oneD_vol_operator);
1910  soln_basis_ext.matrix_vector_mult_1D(soln_coeff_ext[istate], soln_at_vol_q_ext[istate],
1911  soln_basis_ext.oneD_vol_operator);
1912 
1913  // allocate
1914  soln_at_surf_q_int[istate].resize(n_face_quad_pts);
1915  soln_at_surf_q_ext[istate].resize(n_face_quad_pts);
1916  // solve soln at facet cubature nodes
1917  soln_basis_int.matrix_vector_mult_surface_1D(iface,
1918  soln_coeff_int[istate], soln_at_surf_q_int[istate],
1919  soln_basis_int.oneD_surf_operator,
1920  soln_basis_int.oneD_vol_operator);
1921  soln_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
1922  soln_coeff_ext[istate], soln_at_surf_q_ext[istate],
1923  soln_basis_ext.oneD_surf_operator,
1924  soln_basis_ext.oneD_vol_operator);
1925 
1926  for(int idim=0; idim<dim; idim++){
1927  // alocate
1928  aux_soln_at_vol_q_int[istate][idim].resize(n_quad_pts_vol_int);
1929  aux_soln_at_vol_q_ext[istate][idim].resize(n_quad_pts_vol_ext);
1930  // solve auxiliary soln at volume cubature nodes
1931  soln_basis_int.matrix_vector_mult_1D(aux_soln_coeff_int[istate][idim], aux_soln_at_vol_q_int[istate][idim],
1932  soln_basis_int.oneD_vol_operator);
1933  soln_basis_ext.matrix_vector_mult_1D(aux_soln_coeff_ext[istate][idim], aux_soln_at_vol_q_ext[istate][idim],
1934  soln_basis_ext.oneD_vol_operator);
1935 
1936  // allocate
1937  aux_soln_at_surf_q_int[istate][idim].resize(n_face_quad_pts);
1938  aux_soln_at_surf_q_ext[istate][idim].resize(n_face_quad_pts);
1939  // solve auxiliary soln at facet cubature nodes
1940  soln_basis_int.matrix_vector_mult_surface_1D(iface,
1941  aux_soln_coeff_int[istate][idim], aux_soln_at_surf_q_int[istate][idim],
1942  soln_basis_int.oneD_surf_operator,
1943  soln_basis_int.oneD_vol_operator);
1944  soln_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
1945  aux_soln_coeff_ext[istate][idim], aux_soln_at_surf_q_ext[istate][idim],
1946  soln_basis_ext.oneD_surf_operator,
1947  soln_basis_ext.oneD_vol_operator);
1948  }
1949  }
1950 
1951 
1952 
1953 
1954  // Get volume reference fluxes and interpolate them to the facet.
1955  // Compute reference volume fluxes in both interior and exterior cells.
1956 
1957  // First we do interior.
1958  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> conv_ref_flux_at_vol_q_int;
1959  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> diffusive_ref_flux_at_vol_q_int;
1960  for (unsigned int iquad=0; iquad<n_quad_pts_vol_int; ++iquad) {
1961  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
1962  // The way it is stored in metric_operators is to use sum-factorization in each direction,
1963  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
1964  dealii::Tensor<2,dim,real> metric_cofactor_vol_int;
1965  for(int idim=0; idim<dim; idim++){
1966  for(int jdim=0; jdim<dim; jdim++){
1967  metric_cofactor_vol_int[idim][jdim] = metric_oper_int.metric_cofactor_vol[idim][jdim][iquad];
1968  }
1969  }
1970  std::array<real,nstate> soln_state;
1971  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state;
1972  for(int istate=0; istate<nstate; istate++){
1973  soln_state[istate] = soln_at_vol_q_int[istate][iquad];
1974  for(int idim=0; idim<dim; idim++){
1975  aux_soln_state[istate][idim] = aux_soln_at_vol_q_int[istate][idim][iquad];
1976  }
1977  }
1978 
1979  // Evaluate physical convective flux
1980  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux;
1981  //Only for conservtive DG do we interpolate volume fluxes to the facet
1982  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1983  conv_phys_flux = this->pde_physics_double->convective_flux (soln_state);
1984  }
1985 
1986  // Compute the physical dissipative flux
1987  std::array<dealii::Tensor<1,dim,real>,nstate> diffusive_phys_flux;
1988  diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, current_cell_index);
1989 
1990  // Write the values in a way that we can use sum-factorization on.
1991  for(int istate=0; istate<nstate; istate++){
1992  dealii::Tensor<1,dim,real> conv_ref_flux;
1993  dealii::Tensor<1,dim,real> diffusive_ref_flux;
1994  // transform the conservative convective physical flux to reference space
1995  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
1996  metric_oper_int.transform_physical_to_reference(
1997  conv_phys_flux[istate],
1998  metric_cofactor_vol_int,
1999  conv_ref_flux);
2000  }
2001  // transform the dissipative flux to reference space
2002  metric_oper_int.transform_physical_to_reference(
2003  diffusive_phys_flux[istate],
2004  metric_cofactor_vol_int,
2005  diffusive_ref_flux);
2006 
2007  // Write the data in a way that we can use sum-factorization on.
2008  // Since sum-factorization improves the speed for matrix-vector multiplications,
2009  // We need the values to have their inner elements be vectors.
2010  for(int idim=0; idim<dim; idim++){
2011  // allocate
2012  if(iquad == 0){
2013  conv_ref_flux_at_vol_q_int[istate][idim].resize(n_quad_pts_vol_int);
2014  diffusive_ref_flux_at_vol_q_int[istate][idim].resize(n_quad_pts_vol_int);
2015  }
2016  // write data
2017  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2018  conv_ref_flux_at_vol_q_int[istate][idim][iquad] = conv_ref_flux[idim];
2019  }
2020  diffusive_ref_flux_at_vol_q_int[istate][idim][iquad] = diffusive_ref_flux[idim];
2021  }
2022  }
2023  }
2024 
2025  // Next we do exterior volume reference fluxes.
2026  // Note we split the quad integrals because the interior and exterior could be of different poly basis
2027  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> conv_ref_flux_at_vol_q_ext;
2028  std::array<dealii::Tensor<1,dim,std::vector<real>>,nstate> diffusive_ref_flux_at_vol_q_ext;
2029  for (unsigned int iquad=0; iquad<n_quad_pts_vol_ext; ++iquad) {
2030 
2031  // Extract exterior volume metric cofactor matrix at given volume cubature node.
2032  dealii::Tensor<2,dim,real> metric_cofactor_vol_ext;
2033  for(int idim=0; idim<dim; idim++){
2034  for(int jdim=0; jdim<dim; jdim++){
2035  metric_cofactor_vol_ext[idim][jdim] = metric_oper_ext.metric_cofactor_vol[idim][jdim][iquad];
2036  }
2037  }
2038 
2039  std::array<real,nstate> soln_state;
2040  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state;
2041  for(int istate=0; istate<nstate; istate++){
2042  soln_state[istate] = soln_at_vol_q_ext[istate][iquad];
2043  for(int idim=0; idim<dim; idim++){
2044  aux_soln_state[istate][idim] = aux_soln_at_vol_q_ext[istate][idim][iquad];
2045  }
2046  }
2047 
2048  // Evaluate physical convective flux
2049  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux;
2050  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2051  conv_phys_flux = this->pde_physics_double->convective_flux (soln_state);
2052  }
2053 
2054  // Compute the physical dissipative flux
2055  std::array<dealii::Tensor<1,dim,real>,nstate> diffusive_phys_flux;
2056  diffusive_phys_flux = this->pde_physics_double->dissipative_flux(soln_state, aux_soln_state, neighbor_cell_index);
2057 
2058  // Write the values in a way that we can use sum-factorization on.
2059  for(int istate=0; istate<nstate; istate++){
2060  dealii::Tensor<1,dim,real> conv_ref_flux;
2061  dealii::Tensor<1,dim,real> diffusive_ref_flux;
2062  // transform the conservative convective physical flux to reference space
2063  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2064  metric_oper_ext.transform_physical_to_reference(
2065  conv_phys_flux[istate],
2066  metric_cofactor_vol_ext,
2067  conv_ref_flux);
2068  }
2069  // transform the dissipative flux to reference space
2070  metric_oper_ext.transform_physical_to_reference(
2071  diffusive_phys_flux[istate],
2072  metric_cofactor_vol_ext,
2073  diffusive_ref_flux);
2074 
2075  // Write the data in a way that we can use sum-factorization on.
2076  // Since sum-factorization improves the speed for matrix-vector multiplications,
2077  // We need the values to have their inner elements be vectors.
2078  for(int idim=0; idim<dim; idim++){
2079  // allocate
2080  if(iquad == 0){
2081  conv_ref_flux_at_vol_q_ext[istate][idim].resize(n_quad_pts_vol_ext);
2082  diffusive_ref_flux_at_vol_q_ext[istate][idim].resize(n_quad_pts_vol_ext);
2083  }
2084  // write data
2085  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2086  conv_ref_flux_at_vol_q_ext[istate][idim][iquad] = conv_ref_flux[idim];
2087  }
2088  diffusive_ref_flux_at_vol_q_ext[istate][idim][iquad] = diffusive_ref_flux[idim];
2089  }
2090  }
2091  }
2092 
2093  // Interpolate the volume reference fluxes to the facet.
2094  // And do the dot product with the UNIT REFERENCE normal.
2095  // Since we are computing a dot product with the unit reference normal,
2096  // we exploit the fact that the unit reference normal has a value of 0 in all reference directions except
2097  // the outward reference normal dircetion.
2098  const dealii::Tensor<1,dim,double> unit_ref_normal_int = dealii::GeometryInfo<dim>::unit_normal_vector[iface];
2099  const dealii::Tensor<1,dim,double> unit_ref_normal_ext = dealii::GeometryInfo<dim>::unit_normal_vector[neighbor_iface];
2100  // Extract the reference direction that is outward facing on the facet.
2101  const int dim_not_zero_int = iface / 2;//reference direction of face integer division
2102  const int dim_not_zero_ext = neighbor_iface / 2;//reference direction of face integer division
2103 
2104  std::array<std::vector<real>,nstate> conv_int_vol_ref_flux_interp_to_face_dot_ref_normal;
2105  std::array<std::vector<real>,nstate> conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal;
2106  std::array<std::vector<real>,nstate> diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal;
2107  std::array<std::vector<real>,nstate> diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal;
2108  for(int istate=0; istate<nstate; istate++){
2109  //allocate
2110  conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
2111  conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
2112  diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
2113  diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate].resize(n_face_quad_pts);
2114 
2115  // solve
2116  // Note, since the normal is zero in all other reference directions, we only have to interpolate one given reference direction to the facet
2117 
2118  // interpolate reference volume convective flux to the facet, and apply unit reference normal as scaled by 1.0 or -1.0
2119  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2120  flux_basis_int.matrix_vector_mult_surface_1D(iface,
2121  conv_ref_flux_at_vol_q_int[istate][dim_not_zero_int],
2122  conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2123  flux_basis_int.oneD_surf_operator,//the flux basis interpolates from the flux nodes
2124  flux_basis_int.oneD_vol_operator,
2125  false, unit_ref_normal_int[dim_not_zero_int]);//don't add to previous value, scale by unit_normal int
2126  flux_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
2127  conv_ref_flux_at_vol_q_ext[istate][dim_not_zero_ext],
2128  conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2129  flux_basis_ext.oneD_surf_operator,
2130  flux_basis_ext.oneD_vol_operator,
2131  false, unit_ref_normal_ext[dim_not_zero_ext]);//don't add to previous value, unit_normal ext is -unit normal int
2132  }
2133 
2134  // interpolate reference volume dissipative flux to the facet, and apply unit reference normal as scaled by 1.0 or -1.0
2135  flux_basis_int.matrix_vector_mult_surface_1D(iface,
2136  diffusive_ref_flux_at_vol_q_int[istate][dim_not_zero_int],
2137  diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2138  flux_basis_int.oneD_surf_operator,
2139  flux_basis_int.oneD_vol_operator,
2140  false, unit_ref_normal_int[dim_not_zero_int]);
2141  flux_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
2142  diffusive_ref_flux_at_vol_q_ext[istate][dim_not_zero_ext],
2143  diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2144  flux_basis_ext.oneD_surf_operator,
2145  flux_basis_ext.oneD_vol_operator,
2146  false, unit_ref_normal_ext[dim_not_zero_ext]);
2147  }
2148 
2149 
2150  //Note that for entropy-dissipation and entropy stability, the conservative variables
2151  //are functions of projected entropy variables. For Euler etc, the transformation is nonlinear
2152  //so careful attention to what is evaluated where and interpolated to where is needed.
2153  //For further information, please see Chan, Jesse. "On discretely entropy conservative and entropy stable discontinuous Galerkin methods." Journal of Computational Physics 362 (2018): 346-374.
2154  //pages 355 (Eq. 57 with text around it) and page 359 (Eq 86 and text below it).
2155 
2156  // First, transform the volume conservative solution at volume cubature nodes to entropy variables.
2157  std::array<std::vector<real>,nstate> entropy_var_vol_int;
2158  for(unsigned int iquad=0; iquad<n_quad_pts_vol_int; iquad++){
2159  std::array<real,nstate> soln_state;
2160  for(int istate=0; istate<nstate; istate++){
2161  soln_state[istate] = soln_at_vol_q_int[istate][iquad];
2162  }
2163  std::array<real,nstate> entropy_var;
2164  entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state);
2165  for(int istate=0; istate<nstate; istate++){
2166  if(iquad==0){
2167  entropy_var_vol_int[istate].resize(n_quad_pts_vol_int);
2168  }
2169  entropy_var_vol_int[istate][iquad] = entropy_var[istate];
2170  }
2171  }
2172  std::array<std::vector<real>,nstate> entropy_var_vol_ext;
2173  for(unsigned int iquad=0; iquad<n_quad_pts_vol_ext; iquad++){
2174  std::array<real,nstate> soln_state;
2175  for(int istate=0; istate<nstate; istate++){
2176  soln_state[istate] = soln_at_vol_q_ext[istate][iquad];
2177  }
2178  std::array<real,nstate> entropy_var;
2179  entropy_var = this->pde_physics_double->compute_entropy_variables(soln_state);
2180  for(int istate=0; istate<nstate; istate++){
2181  if(iquad==0){
2182  entropy_var_vol_ext[istate].resize(n_quad_pts_vol_ext);
2183  }
2184  entropy_var_vol_ext[istate][iquad] = entropy_var[istate];
2185  }
2186  }
2187 
2188  //project it onto the solution basis functions and interpolate it
2189  std::array<std::vector<real>,nstate> projected_entropy_var_vol_int;
2190  std::array<std::vector<real>,nstate> projected_entropy_var_vol_ext;
2191  std::array<std::vector<real>,nstate> projected_entropy_var_surf_int;
2192  std::array<std::vector<real>,nstate> projected_entropy_var_surf_ext;
2193  for(int istate=0; istate<nstate; istate++){
2194  // allocate
2195  projected_entropy_var_vol_int[istate].resize(n_quad_pts_vol_int);
2196  projected_entropy_var_vol_ext[istate].resize(n_quad_pts_vol_ext);
2197  projected_entropy_var_surf_int[istate].resize(n_face_quad_pts);
2198  projected_entropy_var_surf_ext[istate].resize(n_face_quad_pts);
2199 
2200  //interior
2201  std::vector<real> entropy_var_coeff_int(n_shape_fns_int);
2202  soln_basis_projection_oper_int.matrix_vector_mult_1D(entropy_var_vol_int[istate],
2203  entropy_var_coeff_int,
2204  soln_basis_projection_oper_int.oneD_vol_operator);
2205  soln_basis_int.matrix_vector_mult_1D(entropy_var_coeff_int,
2206  projected_entropy_var_vol_int[istate],
2207  soln_basis_int.oneD_vol_operator);
2208  soln_basis_int.matrix_vector_mult_surface_1D(iface,
2209  entropy_var_coeff_int,
2210  projected_entropy_var_surf_int[istate],
2211  soln_basis_int.oneD_surf_operator,
2212  soln_basis_int.oneD_vol_operator);
2213 
2214  //exterior
2215  std::vector<real> entropy_var_coeff_ext(n_shape_fns_ext);
2216  soln_basis_projection_oper_ext.matrix_vector_mult_1D(entropy_var_vol_ext[istate],
2217  entropy_var_coeff_ext,
2218  soln_basis_projection_oper_ext.oneD_vol_operator);
2219 
2220  soln_basis_ext.matrix_vector_mult_1D(entropy_var_coeff_ext,
2221  projected_entropy_var_vol_ext[istate],
2222  soln_basis_ext.oneD_vol_operator);
2223  soln_basis_ext.matrix_vector_mult_surface_1D(neighbor_iface,
2224  entropy_var_coeff_ext,
2225  projected_entropy_var_surf_ext[istate],
2226  soln_basis_ext.oneD_surf_operator,
2227  soln_basis_ext.oneD_vol_operator);
2228  }
2229 
2230  //get the surface-volume sparsity pattern for a "sum-factorized" Hadamard product only computing terms needed for the operation.
2231  const unsigned int row_size_int = n_face_quad_pts * n_quad_pts_1D_int;
2232  const unsigned int col_size_int = n_face_quad_pts * n_quad_pts_1D_int;
2233  std::vector<unsigned int> Hadamard_rows_sparsity_int(row_size_int);
2234  std::vector<unsigned int> Hadamard_columns_sparsity_int(col_size_int);
2235  const unsigned int row_size_ext = n_face_quad_pts * n_quad_pts_1D_ext;
2236  const unsigned int col_size_ext = n_face_quad_pts * n_quad_pts_1D_ext;
2237  std::vector<unsigned int> Hadamard_rows_sparsity_ext(row_size_ext);
2238  std::vector<unsigned int> Hadamard_columns_sparsity_ext(col_size_ext);
2239  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
2240  flux_basis_int.sum_factorized_Hadamard_surface_sparsity_pattern(n_face_quad_pts, n_quad_pts_1D_int, Hadamard_rows_sparsity_int, Hadamard_columns_sparsity_int, dim_not_zero_int);
2241  flux_basis_ext.sum_factorized_Hadamard_surface_sparsity_pattern(n_face_quad_pts, n_quad_pts_1D_ext, Hadamard_rows_sparsity_ext, Hadamard_columns_sparsity_ext, dim_not_zero_ext);
2242  }
2243 
2244  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_surf_int;
2245  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_surf_ext;
2246  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_vol_int;
2247  std::array<std::vector<real>,nstate> surf_vol_ref_2pt_flux_interp_vol_ext;
2248  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
2249  //get surface-volume hybrid 2pt flux from Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485.
2250  std::array<dealii::FullMatrix<real>,nstate> surface_ref_2pt_flux_int;
2251  std::array<dealii::FullMatrix<real>,nstate> surface_ref_2pt_flux_ext;
2252  //make use of the sparsity pattern from above to assemble only n^d non-zero entries without ever allocating not computing zeros.
2253  for(int istate=0; istate<nstate; istate++){
2254  surface_ref_2pt_flux_int[istate].reinit(n_face_quad_pts, n_quad_pts_1D_int);
2255  surface_ref_2pt_flux_ext[istate].reinit(n_face_quad_pts, n_quad_pts_1D_ext);
2256  }
2257  for(unsigned int iquad_face=0; iquad_face<n_face_quad_pts; iquad_face++){
2258  dealii::Tensor<2,dim,real> metric_cofactor_surf;
2259  for(int idim=0; idim<dim; idim++){
2260  for(int jdim=0; jdim<dim; jdim++){
2261  metric_cofactor_surf[idim][jdim] = metric_oper_int.metric_cofactor_surf[idim][jdim][iquad_face];
2262  }
2263  }
2264 
2265  //Compute the conservative values on the facet from the interpolated entorpy variables.
2266  std::array<real,nstate> entropy_var_face_int;
2267  std::array<real,nstate> entropy_var_face_ext;
2268  for(int istate=0; istate<nstate; istate++){
2269  entropy_var_face_int[istate] = projected_entropy_var_surf_int[istate][iquad_face];
2270  entropy_var_face_ext[istate] = projected_entropy_var_surf_ext[istate][iquad_face];
2271  }
2272  std::array<real,nstate> soln_state_face_int;
2273  soln_state_face_int = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_int);
2274  std::array<real,nstate> soln_state_face_ext;
2275  soln_state_face_ext = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_ext);
2276 
2277  //only do the n_quad_1D vol points that give non-zero entries from Hadamard product.
2278  for(unsigned int row_index = iquad_face * n_quad_pts_1D_int, column_index = 0;
2279  column_index < n_quad_pts_1D_int;
2280  row_index++, column_index++){
2281 
2282  if(Hadamard_rows_sparsity_int[row_index] != iquad_face){
2283  pcout<<"The interior Hadamard rows sparsity pattern does not match."<<std::endl;
2284  std::abort();
2285  }
2286 
2287  const unsigned int iquad_vol = Hadamard_columns_sparsity_int[row_index];//extract flux_quad pt that corresponds to a non-zero entry for Hadamard product.
2288  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
2289  // The way it is stored in metric_operators is to use sum-factorization in each direction,
2290  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
2291  dealii::Tensor<2,dim,real> metric_cofactor_vol_int;
2292  for(int idim=0; idim<dim; idim++){
2293  for(int jdim=0; jdim<dim; jdim++){
2294  metric_cofactor_vol_int[idim][jdim] = metric_oper_int.metric_cofactor_vol[idim][jdim][iquad_vol];
2295  }
2296  }
2297  std::array<real,nstate> entropy_var;
2298  for(int istate=0; istate<nstate; istate++){
2299  entropy_var[istate] = projected_entropy_var_vol_int[istate][iquad_vol];
2300  }
2301  std::array<real,nstate> soln_state;
2302  soln_state = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var);
2303  //Note that the flux basis is collocated on the volume cubature set so we don't need to evaluate the entropy variables
2304  //on the volume set then transform back to the conservative variables since the flux basis volume
2305  //projection is identity.
2306 
2307  //Compute the physical flux
2308  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux_2pt;
2309  conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_face_int);
2310  for(int istate=0; istate<nstate; istate++){
2311  dealii::Tensor<1,dim,real> conv_ref_flux_2pt;
2312  //For each state, transform the physical flux to a reference flux.
2313  metric_oper_int.transform_physical_to_reference(
2314  conv_phys_flux_2pt[istate],
2315  0.5*(metric_cofactor_surf + metric_cofactor_vol_int),
2316  conv_ref_flux_2pt);
2317  //only store the dim not zero in reference space bc dot product with unit ref normal later.
2318  surface_ref_2pt_flux_int[istate][iquad_face][column_index] = conv_ref_flux_2pt[dim_not_zero_int];
2319  }
2320  }
2321  for(unsigned int row_index = iquad_face * n_quad_pts_1D_ext, column_index = 0;
2322  column_index < n_quad_pts_1D_ext;
2323  row_index++, column_index++){
2324 
2325  if(Hadamard_rows_sparsity_ext[row_index] != iquad_face){
2326  pcout<<"The exterior Hadamard rows sparsity pattern does not match."<<std::endl;
2327  std::abort();
2328  }
2329 
2330  const unsigned int iquad_vol = Hadamard_columns_sparsity_ext[row_index];//extract flux_quad pt that corresponds to a non-zero entry for Hadamard product.
2331  // Copy Metric Cofactor in a way can use for transforming Tensor Blocks to reference space
2332  // The way it is stored in metric_operators is to use sum-factorization in each direction,
2333  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
2334  dealii::Tensor<2,dim,real> metric_cofactor_vol_ext;
2335  for(int idim=0; idim<dim; idim++){
2336  for(int jdim=0; jdim<dim; jdim++){
2337  metric_cofactor_vol_ext[idim][jdim] = metric_oper_ext.metric_cofactor_vol[idim][jdim][iquad_vol];
2338  }
2339  }
2340  std::array<real,nstate> entropy_var;
2341  for(int istate=0; istate<nstate; istate++){
2342  entropy_var[istate] = projected_entropy_var_vol_ext[istate][iquad_vol];
2343  }
2344  std::array<real,nstate> soln_state;
2345  soln_state = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var);
2346  //Compute the physical flux
2347  std::array<dealii::Tensor<1,dim,real>,nstate> conv_phys_flux_2pt;
2348  conv_phys_flux_2pt = this->pde_physics_double->convective_numerical_split_flux(soln_state, soln_state_face_ext);
2349  for(int istate=0; istate<nstate; istate++){
2350  dealii::Tensor<1,dim,real> conv_ref_flux_2pt;
2351  //For each state, transform the physical flux to a reference flux.
2352  metric_oper_ext.transform_physical_to_reference(
2353  conv_phys_flux_2pt[istate],
2354  0.5*(metric_cofactor_surf + metric_cofactor_vol_ext),
2355  conv_ref_flux_2pt);
2356  //only store the dim not zero in reference space bc dot product with unit ref normal later.
2357  surface_ref_2pt_flux_ext[istate][iquad_face][column_index] = conv_ref_flux_2pt[dim_not_zero_ext];
2358  }
2359  }
2360  }
2361 
2362  //get the surface basis operator from Hadamard sparsity pattern
2363  //to be applied at n^d operations (on the face so n^{d+1-1}=n^d flops)
2364  //also only allocates n^d terms.
2365  const int iface_1D = iface % 2;//the reference face number
2366  const std::vector<double> &oneD_quad_weights_vol_int = this->oneD_quadrature_collection[poly_degree_int].get_weights();
2367  dealii::FullMatrix<real> surf_oper_sparse_int(n_face_quad_pts, n_quad_pts_1D_int);
2368  flux_basis_int.sum_factorized_Hadamard_surface_basis_assembly(n_face_quad_pts, n_quad_pts_1D_int,
2369  Hadamard_rows_sparsity_int, Hadamard_columns_sparsity_int,
2370  flux_basis_int.oneD_surf_operator[iface_1D],
2371  oneD_quad_weights_vol_int,
2372  surf_oper_sparse_int,
2373  dim_not_zero_int);
2374  const int neighbor_iface_1D = neighbor_iface % 2;//the reference neighbour face number
2375  const std::vector<double> &oneD_quad_weights_vol_ext = this->oneD_quadrature_collection[poly_degree_ext].get_weights();
2376  dealii::FullMatrix<real> surf_oper_sparse_ext(n_face_quad_pts, n_quad_pts_1D_ext);
2377  flux_basis_ext.sum_factorized_Hadamard_surface_basis_assembly(n_face_quad_pts, n_quad_pts_1D_ext,
2378  Hadamard_rows_sparsity_ext, Hadamard_columns_sparsity_ext,
2379  flux_basis_ext.oneD_surf_operator[neighbor_iface_1D],
2380  oneD_quad_weights_vol_ext,
2381  surf_oper_sparse_ext,
2382  dim_not_zero_ext);
2383 
2384  // Apply the surface Hadamard products and multiply with vector of ones for both off diagonal terms in
2385  // Eq.(15) in Chan, Jesse. "Skew-symmetric entropy stable modal discontinuous Galerkin formulations." Journal of Scientific Computing 81.1 (2019): 459-485.
2386  for(int istate=0; istate<nstate; istate++){
2387  //first apply Hadamard product with the structure made above.
2388  dealii::FullMatrix<real> surface_ref_2pt_flux_int_Hadamard_with_surf_oper(n_face_quad_pts, n_quad_pts_1D_int);
2389  flux_basis_int.Hadamard_product(surf_oper_sparse_int,
2390  surface_ref_2pt_flux_int[istate],
2391  surface_ref_2pt_flux_int_Hadamard_with_surf_oper);
2392  dealii::FullMatrix<real> surface_ref_2pt_flux_ext_Hadamard_with_surf_oper(n_face_quad_pts, n_quad_pts_1D_ext);
2393  flux_basis_ext.Hadamard_product(surf_oper_sparse_ext,
2394  surface_ref_2pt_flux_ext[istate],
2395  surface_ref_2pt_flux_ext_Hadamard_with_surf_oper);
2396  //sum with reference unit normal
2397  surf_vol_ref_2pt_flux_interp_surf_int[istate].resize(n_face_quad_pts);
2398  surf_vol_ref_2pt_flux_interp_surf_ext[istate].resize(n_face_quad_pts);
2399  surf_vol_ref_2pt_flux_interp_vol_int[istate].resize(n_quad_pts_vol_int);
2400  surf_vol_ref_2pt_flux_interp_vol_ext[istate].resize(n_quad_pts_vol_ext);
2401 
2402  for(unsigned int iface_quad=0; iface_quad<n_face_quad_pts; iface_quad++){
2403  for(unsigned int iquad_int=0; iquad_int<n_quad_pts_1D_int; iquad_int++){
2404  surf_vol_ref_2pt_flux_interp_surf_int[istate][iface_quad]
2405  -= surface_ref_2pt_flux_int_Hadamard_with_surf_oper[iface_quad][iquad_int]
2406  * unit_ref_normal_int[dim_not_zero_int];
2407  const unsigned int column_index = iface_quad * n_quad_pts_1D_int + iquad_int;
2408  surf_vol_ref_2pt_flux_interp_vol_int[istate][Hadamard_columns_sparsity_int[column_index]]
2409  += surface_ref_2pt_flux_int_Hadamard_with_surf_oper[iface_quad][iquad_int]
2410  * unit_ref_normal_int[dim_not_zero_int];
2411  }
2412  for(unsigned int iquad_ext=0; iquad_ext<n_quad_pts_1D_ext; iquad_ext++){
2413  surf_vol_ref_2pt_flux_interp_surf_ext[istate][iface_quad]
2414  -= surface_ref_2pt_flux_ext_Hadamard_with_surf_oper[iface_quad][iquad_ext]
2415  * (unit_ref_normal_ext[dim_not_zero_ext]);
2416  const unsigned int column_index = iface_quad * n_quad_pts_1D_ext + iquad_ext;
2417  surf_vol_ref_2pt_flux_interp_vol_ext[istate][Hadamard_columns_sparsity_ext[column_index]]
2418  += surface_ref_2pt_flux_ext_Hadamard_with_surf_oper[iface_quad][iquad_ext]
2419  * (unit_ref_normal_ext[dim_not_zero_ext]);
2420  }
2421  }
2422  }
2423  }//end of if split form or curvilinear split form
2424 
2425 
2426 
2427  // Evaluate reference numerical fluxes.
2428 
2429  std::array<std::vector<real>,nstate> conv_num_flux_dot_n;
2430  std::array<std::vector<real>,nstate> diss_auxi_num_flux_dot_n;
2431  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
2432  // Copy Metric Cofactor on the facet in a way can use for transforming Tensor Blocks to reference space
2433  // The way it is stored in metric_operators is to use sum-factorization in each direction,
2434  // but here it is cleaner to apply a reference transformation in each Tensor block returned by physics.
2435  // Note that for a conforming mesh, the facet metric cofactor matrix is the same from either interioir or exterior metric terms.
2436  // This is verified for the metric computations in: unit_tests/operator_tests/surface_conforming_test.cpp
2437  dealii::Tensor<2,dim,real> metric_cofactor_surf;
2438  for(int idim=0; idim<dim; idim++){
2439  for(int jdim=0; jdim<dim; jdim++){
2440  metric_cofactor_surf[idim][jdim] = metric_oper_int.metric_cofactor_surf[idim][jdim][iquad];
2441  }
2442  }
2443 
2444  std::array<real,nstate> entropy_var_face_int;
2445  std::array<real,nstate> entropy_var_face_ext;
2446  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state_int;
2447  std::array<dealii::Tensor<1,dim,real>,nstate> aux_soln_state_ext;
2448  std::array<real,nstate> soln_interp_to_face_int;
2449  std::array<real,nstate> soln_interp_to_face_ext;
2450  for(int istate=0; istate<nstate; istate++){
2451  soln_interp_to_face_int[istate] = soln_at_surf_q_int[istate][iquad];
2452  soln_interp_to_face_ext[istate] = soln_at_surf_q_ext[istate][iquad];
2453  entropy_var_face_int[istate] = projected_entropy_var_surf_int[istate][iquad];
2454  entropy_var_face_ext[istate] = projected_entropy_var_surf_ext[istate][iquad];
2455  for(int idim=0; idim<dim; idim++){
2456  aux_soln_state_int[istate][idim] = aux_soln_at_surf_q_int[istate][idim][iquad];
2457  aux_soln_state_ext[istate][idim] = aux_soln_at_surf_q_ext[istate][idim][iquad];
2458  }
2459  }
2460 
2461  std::array<real,nstate> soln_state_int;
2462  soln_state_int = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_int);
2463  std::array<real,nstate> soln_state_ext;
2464  soln_state_ext = this->pde_physics_double->compute_conservative_variables_from_entropy_variables (entropy_var_face_ext);
2465 
2466 
2467  if(!this->all_parameters->use_split_form && !this->all_parameters->use_curvilinear_split_form){
2468  for(int istate=0; istate<nstate; istate++){
2469  soln_state_int[istate] = soln_at_surf_q_int[istate][iquad];
2470  soln_state_ext[istate] = soln_at_surf_q_ext[istate][iquad];
2471  }
2472  }
2473 
2474  // numerical fluxes
2475  dealii::Tensor<1,dim,real> unit_phys_normal_int;
2476  metric_oper_int.transform_reference_to_physical(unit_ref_normal_int,
2477  metric_cofactor_surf,
2478  unit_phys_normal_int);
2479  const double face_Jac_norm_scaled = unit_phys_normal_int.norm();
2480  unit_phys_normal_int /= face_Jac_norm_scaled;//normalize it.
2481  // Note that the facet determinant of metric jacobian is the above norm multiplied by the determinant of the metric Jacobian evaluated on the facet.
2482  // Since the determinant of the metric Jacobian evaluated on the face cancels off, we can just scale the numerical flux by the norm.
2483 
2484  std::array<real,nstate> conv_num_flux_dot_n_at_q;
2485  std::array<real,nstate> diss_auxi_num_flux_dot_n_at_q;
2486  // Convective numerical flux.
2487  conv_num_flux_dot_n_at_q = this->conv_num_flux_double->evaluate_flux(soln_state_int, soln_state_ext, unit_phys_normal_int);
2488  // dissipative numerical flux
2489  diss_auxi_num_flux_dot_n_at_q = this->diss_num_flux_double->evaluate_auxiliary_flux(
2490  current_cell_index, neighbor_cell_index,
2491  0.0, 0.0,
2492  soln_interp_to_face_int, soln_interp_to_face_ext,
2493  aux_soln_state_int, aux_soln_state_ext,
2494  unit_phys_normal_int, penalty, false);
2495 
2496  // Write the values in a way that we can use sum-factorization on.
2497  for(int istate=0; istate<nstate; istate++){
2498  // Write the data in a way that we can use sum-factorization on.
2499  // Since sum-factorization improves the speed for matrix-vector multiplications,
2500  // We need the values to have their inner elements be vectors of n_face_quad_pts.
2501 
2502  // allocate
2503  if(iquad == 0){
2504  conv_num_flux_dot_n[istate].resize(n_face_quad_pts);
2505  diss_auxi_num_flux_dot_n[istate].resize(n_face_quad_pts);
2506  }
2507 
2508  // write data
2509  conv_num_flux_dot_n[istate][iquad] = face_Jac_norm_scaled * conv_num_flux_dot_n_at_q[istate];
2510  diss_auxi_num_flux_dot_n[istate][iquad] = face_Jac_norm_scaled * diss_auxi_num_flux_dot_n_at_q[istate];
2511  }
2512  }
2513 
2514  // Compute RHS
2515  const std::vector<double> &surf_quad_weights = this->face_quadrature_collection[poly_degree_int].get_weights();
2516  for(int istate=0; istate<nstate; istate++){
2517  // interior RHS
2518  std::vector<real> rhs_int(n_shape_fns_int);
2519 
2520  // convective flux
2521  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
2522  std::vector<real> ones_surf(n_face_quad_pts, 1.0);
2523  soln_basis_int.inner_product_surface_1D(iface,
2524  surf_vol_ref_2pt_flux_interp_surf_int[istate],
2525  ones_surf, rhs_int,
2526  soln_basis_int.oneD_surf_operator,
2527  soln_basis_int.oneD_vol_operator,
2528  false, -1.0);
2529  std::vector<real> ones_vol(n_quad_pts_vol_int, 1.0);
2530  soln_basis_int.inner_product_1D(surf_vol_ref_2pt_flux_interp_vol_int[istate],
2531  ones_vol, rhs_int,
2532  soln_basis_int.oneD_vol_operator,
2533  true, -1.0);
2534  }
2535  else
2536  {
2537  soln_basis_int.inner_product_surface_1D(iface,
2538  conv_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2539  surf_quad_weights, rhs_int,
2540  soln_basis_int.oneD_surf_operator,
2541  soln_basis_int.oneD_vol_operator,
2542  false, 1.0);
2543  }
2544  // dissipative flux
2545  soln_basis_int.inner_product_surface_1D(iface,
2546  diffusive_int_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2547  surf_quad_weights, rhs_int,
2548  soln_basis_int.oneD_surf_operator,
2549  soln_basis_int.oneD_vol_operator,
2550  true, 1.0);//adding=true, subtract the negative so add it
2551  // convective numerical flux
2552  soln_basis_int.inner_product_surface_1D(iface, conv_num_flux_dot_n[istate],
2553  surf_quad_weights, rhs_int,
2554  soln_basis_int.oneD_surf_operator,
2555  soln_basis_int.oneD_vol_operator,
2556  true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it
2557  // dissipative numerical flux
2558  soln_basis_int.inner_product_surface_1D(iface, diss_auxi_num_flux_dot_n[istate],
2559  surf_quad_weights, rhs_int,
2560  soln_basis_int.oneD_surf_operator,
2561  soln_basis_int.oneD_vol_operator,
2562  true, -1.0);//adding=true, scaled by factor=-1.0 bc subtract it
2563 
2564 
2565  for(unsigned int ishape=0; ishape<n_shape_fns_int; ishape++){
2566  local_rhs_int_cell(istate*n_shape_fns_int + ishape) += rhs_int[ishape];
2567  }
2568 
2569  // exterior RHS
2570  std::vector<real> rhs_ext(n_shape_fns_ext);
2571 
2572  // convective flux
2573  if(this->all_parameters->use_split_form || this->all_parameters->use_curvilinear_split_form){
2574  std::vector<real> ones_surf(n_face_quad_pts, 1.0);
2575  soln_basis_ext.inner_product_surface_1D(neighbor_iface,
2576  surf_vol_ref_2pt_flux_interp_surf_ext[istate],
2577  ones_surf, rhs_ext,
2578  soln_basis_ext.oneD_surf_operator,
2579  soln_basis_ext.oneD_vol_operator,
2580  false, -1.0);//the negative sign is bc the surface Hadamard function computes it on the otherside.
2581  //to satisfy the unit test that checks consistency with Jesse Chan's formulation.
2582  std::vector<real> ones_vol(n_quad_pts_vol_ext, 1.0);
2583  soln_basis_ext.inner_product_1D(surf_vol_ref_2pt_flux_interp_vol_ext[istate],
2584  ones_vol, rhs_ext,
2585  soln_basis_ext.oneD_vol_operator,
2586  true, -1.0);
2587  }
2588  else
2589  {
2590  soln_basis_ext.inner_product_surface_1D(neighbor_iface,
2591  conv_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2592  surf_quad_weights, rhs_ext,
2593  soln_basis_ext.oneD_surf_operator,
2594  soln_basis_ext.oneD_vol_operator,
2595  false, 1.0);//adding false
2596  }
2597  // dissipative flux
2598  soln_basis_ext.inner_product_surface_1D(neighbor_iface,
2599  diffusive_ext_vol_ref_flux_interp_to_face_dot_ref_normal[istate],
2600  surf_quad_weights, rhs_ext,
2601  soln_basis_ext.oneD_surf_operator,
2602  soln_basis_ext.oneD_vol_operator,
2603  true, 1.0);//adding=true
2604  // convective numerical flux
2605  soln_basis_ext.inner_product_surface_1D(neighbor_iface, conv_num_flux_dot_n[istate],
2606  surf_quad_weights, rhs_ext,
2607  soln_basis_ext.oneD_surf_operator,
2608  soln_basis_ext.oneD_vol_operator,
2609  true, 1.0);//adding=true, scaled by factor=1.0 because negative numerical flux and subtract it
2610  // dissipative numerical flux
2611  soln_basis_ext.inner_product_surface_1D(neighbor_iface, diss_auxi_num_flux_dot_n[istate],
2612  surf_quad_weights, rhs_ext,
2613  soln_basis_ext.oneD_surf_operator,
2614  soln_basis_ext.oneD_vol_operator,
2615  true, 1.0);//adding=true, scaled by factor=1.0 because negative numerical flux and subtract it
2616 
2617 
2618  for(unsigned int ishape=0; ishape<n_shape_fns_ext; ishape++){
2619  local_rhs_ext_cell(istate*n_shape_fns_ext + ishape) += rhs_ext[ishape];
2620  }
2621  }
2622 }
2623 
2624 
2625 /*******************************************************************
2626  *
2627  *
2628  * PRIMARY EQUATIONS
2629  *
2630  * NOTE: the implicit functions have not been modified.
2631  *
2632  * EVERYTHING BELOW Untouched/unverified/not used anymore
2633  *
2634  *******************************************************************/
2635 
2636 template <int dim, int nstate, typename real, typename MeshType>
2638  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
2639  const dealii::types::global_dof_index /*current_cell_index*/,
2640  const unsigned int ,//face_number,
2641  const unsigned int /*boundary_id*/,
2642  const dealii::FEFaceValuesBase<dim,dim> &/*fe_values_boundary*/,
2643  const real /*penalty*/,
2644  const dealii::FESystem<dim,dim> &,//fe,
2645  const dealii::Quadrature<dim-1> &,//quadrature,
2646  const std::vector<dealii::types::global_dof_index> &,//metric_dof_indices,
2647  const std::vector<dealii::types::global_dof_index> &/*soln_dof_indices*/,
2648  dealii::Vector<real> &/*local_rhs_int_cell*/,
2649  const bool /*compute_dRdW*/,
2650  const bool /*compute_dRdX*/,
2651  const bool /*compute_d2R*/)
2652 {
2653  //Do nothing
2654 
2655 // (void) current_cell_index;
2656 // assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R);
2657 // (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R;
2658 // using ADArray = std::array<FadType,nstate>;
2659 // using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >;
2660 //
2661 // const unsigned int n_dofs_cell = fe_values_boundary.dofs_per_cell;
2662 // const unsigned int n_face_quad_pts = fe_values_boundary.n_quadrature_points;
2663 //
2664 // AssertDimension (n_dofs_cell, soln_dof_indices.size());
2665 //
2666 // const std::vector<real> &JxW = fe_values_boundary.get_JxW_values ();
2667 // const std::vector<dealii::Tensor<1,dim>> &normals = fe_values_boundary.get_normal_vectors ();
2668 //
2669 // std::vector<real> residual_derivatives(n_dofs_cell);
2670 //
2671 // std::vector<ADArray> soln_int(n_face_quad_pts);
2672 // std::vector<ADArray> soln_ext(n_face_quad_pts);
2673 //
2674 // std::vector<ADArrayTensor1> soln_grad_int(n_face_quad_pts);
2675 // std::vector<ADArrayTensor1> soln_grad_ext(n_face_quad_pts);
2676 //
2677 // std::vector<ADArray> conv_num_flux_dot_n(n_face_quad_pts);
2678 // std::vector<ADArray> diss_soln_num_flux(n_face_quad_pts); // u*
2679 // std::vector<ADArrayTensor1> diss_flux_jump_int(n_face_quad_pts); // u*-u_int
2680 // std::vector<ADArrayTensor1> diss_flux_jump_ext(n_face_quad_pts); // u*-u_int
2681 // std::vector<ADArray> diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma*
2682 //
2683 // std::vector<ADArrayTensor1> conv_phys_flux(n_face_quad_pts);
2684 //
2685 // // AD variable
2686 // std::vector< FadType > soln_coeff_int(n_dofs_cell);
2687 // const unsigned int n_total_indep = n_dofs_cell;
2688 // for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
2689 // soln_coeff_int[idof] = DGBase<dim,real,MeshType>::solution(soln_dof_indices[idof]);
2690 // soln_coeff_int[idof].diff(idof, n_total_indep);
2691 // }
2692 //
2693 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
2694 // for (int istate=0; istate<nstate; istate++) {
2695 // // Interpolate solution to the face quadrature points
2696 // soln_int[iquad][istate] = 0;
2697 // soln_grad_int[iquad][istate] = 0;
2698 // }
2699 // }
2700 // // Interpolate solution to face
2701 // const std::vector< dealii::Point<dim,real> > quad_pts = fe_values_boundary.get_quadrature_points();
2702 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
2703 //
2704 // const dealii::Tensor<1,dim,FadType> normal_int = normals[iquad];
2705 // const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int;
2706 //
2707 // for (unsigned int idof=0; idof<n_dofs_cell; ++idof) {
2708 // const int istate = fe_values_boundary.get_fe().system_to_component_index(idof).first;
2709 // soln_int[iquad][istate] += soln_coeff_int[idof] * fe_values_boundary.shape_value_component(idof, iquad, istate);
2710 // soln_grad_int[iquad][istate] += soln_coeff_int[idof] * fe_values_boundary.shape_grad_component(idof, iquad, istate);
2711 // }
2712 //
2713 // const dealii::Point<dim, real> real_quad_point = quad_pts[iquad];
2714 // dealii::Point<dim,FadType> ad_point;
2715 // for (int d=0;d<dim;++d) { ad_point[d] = real_quad_point[d]; }
2716 // this->pde_physics_fad->boundary_face_values (boundary_id, ad_point, normal_int, soln_int[iquad], soln_grad_int[iquad], soln_ext[iquad], soln_grad_ext[iquad]);
2717 //
2718 // //
2719 // // Evaluate physical convective flux, physical dissipative flux
2720 // // Following the the boundary treatment given by
2721 // // Hartmann, R., Numerical Analysis of Higher Order Discontinuous Galerkin Finite Element Methods,
2722 // // Institute of Aerodynamics and Flow Technology, DLR (German Aerospace Center), 2008.
2723 // // Details given on page 93
2724 // //conv_num_flux_dot_n[iquad] = DGBaseState<dim,nstate,real,MeshType>::conv_num_flux_fad->evaluate_flux(soln_ext[iquad], soln_ext[iquad], normal_int);
2725 //
2726 // // So, I wasn't able to get Euler manufactured solutions to converge when F* = F*(Ubc, Ubc)
2727 // // Changing it back to the standdard F* = F*(Uin, Ubc)
2728 // // This is known not be adjoint consistent as per the paper above. Page 85, second to last paragraph.
2729 // // Losing 2p+1 OOA on functionals for all PDEs.
2730 // conv_num_flux_dot_n[iquad] = DGBaseState<dim,nstate,real,MeshType>::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int);
2731 //
2732 // // Used for strong form
2733 // // Which physical convective flux to use?
2734 // conv_phys_flux[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]);
2735 //
2736 // // Notice that the flux uses the solution given by the Dirichlet or Neumann boundary condition
2737 // diss_soln_num_flux[iquad] = DGBaseState<dim,nstate,real,MeshType>::diss_num_flux_fad->evaluate_solution_flux(soln_ext[iquad], soln_ext[iquad], normal_int);
2738 //
2739 // ADArrayTensor1 diss_soln_jump_int;
2740 // ADArrayTensor1 diss_soln_jump_ext;
2741 // for (int s=0; s<nstate; s++) {
2742 // for (int d=0; d<dim; d++) {
2743 // diss_soln_jump_int[s][d] = (diss_soln_num_flux[iquad][s] - soln_int[iquad][s]) * normal_int[d];
2744 // diss_soln_jump_ext[s][d] = (diss_soln_num_flux[iquad][s] - soln_ext[iquad][s]) * normal_ext[d];
2745 // }
2746 // }
2747 // diss_flux_jump_int[iquad] = this->pde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index);
2748 // diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index);
2749 //
2750 // diss_auxi_num_flux_dot_n[iquad] = DGBaseState<dim,nstate,real,MeshType>::diss_num_flux_fad->evaluate_auxiliary_flux(
2751 // current_cell_index, neighbor_cell_index,
2752 // 0.0, 0.0,
2753 // soln_int[iquad], soln_ext[iquad],
2754 // soln_grad_int[iquad], soln_grad_ext[iquad],
2755 // normal_int, penalty, true);
2756 // }
2757 //
2758 // // Boundary integral
2759 // for (unsigned int itest=0; itest<n_dofs_cell; ++itest) {
2760 //
2761 // FadType rhs = 0.0;
2762 //
2763 // const unsigned int istate = fe_values_boundary.get_fe().system_to_component_index(itest).first;
2764 //
2765 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
2766 //
2767 // // Convection
2768 // const FadType flux_diff = conv_num_flux_dot_n[iquad][istate] - conv_phys_flux[iquad][istate]*normals[iquad];
2769 // rhs = rhs - fe_values_boundary.shape_value_component(itest,iquad,istate) * flux_diff * JxW[iquad];
2770 // // Diffusive
2771 // rhs = rhs - fe_values_boundary.shape_value_component(itest,iquad,istate) * diss_auxi_num_flux_dot_n[iquad][istate] * JxW[iquad];
2772 // rhs = rhs + fe_values_boundary.shape_grad_component(itest,iquad,istate) * diss_flux_jump_int[iquad][istate] * JxW[iquad];
2773 // }
2774 // // *******************
2775 //
2776 // local_rhs_int_cell(itest) += rhs.val();
2777 //
2778 // if (this->all_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) {
2779 // for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
2780 // //residual_derivatives[idof] = rhs.fastAccessDx(idof);
2781 // residual_derivatives[idof] = rhs.fastAccessDx(idof);
2782 // }
2783 // this->system_matrix.add(soln_dof_indices[itest], soln_dof_indices, residual_derivatives);
2784 // }
2785 // }
2786 }
2787 
2788 template <int dim, int nstate, typename real, typename MeshType>
2790  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
2791  const dealii::types::global_dof_index /*current_cell_index*/,
2792  const dealii::FEValues<dim,dim> &/*fe_values_vol*/,
2793  const dealii::FESystem<dim,dim> &,//fe,
2794  const dealii::Quadrature<dim> &,//quadrature,
2795  const std::vector<dealii::types::global_dof_index> &,//metric_dof_indices,
2796  const std::vector<dealii::types::global_dof_index> &/*cell_dofs_indices*/,
2797  dealii::Vector<real> &/*local_rhs_int_cell*/,
2798  const dealii::FEValues<dim,dim> &/*fe_values_lagrange*/,
2799  const bool /*compute_dRdW*/,
2800  const bool /*compute_dRdX*/,
2801  const bool /*compute_d2R*/)
2802 {
2803  //Do nothing
2804 
2805 // (void) current_cell_index;
2806 // assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R);
2807 // (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R;
2808 // using ADArray = std::array<FadType,nstate>;
2809 // using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >;
2810 //
2811 // const unsigned int n_quad_pts = fe_values_vol.n_quadrature_points;
2812 // const unsigned int n_dofs_cell = fe_values_vol.dofs_per_cell;
2813 //
2814 // AssertDimension (n_dofs_cell, cell_dofs_indices.size());
2815 //
2816 // const std::vector<real> &JxW = fe_values_vol.get_JxW_values ();
2817 //
2818 // std::vector<real> residual_derivatives(n_dofs_cell);
2819 //
2820 // std::vector< ADArray > soln_at_q(n_quad_pts);
2821 // std::vector< ADArrayTensor1 > soln_grad_at_q(n_quad_pts); // Tensor initialize with zeros
2822 //
2823 // std::vector< ADArrayTensor1 > conv_phys_flux_at_q(n_quad_pts);
2824 // std::vector< ADArrayTensor1 > diss_phys_flux_at_q(n_quad_pts);
2825 // std::vector< ADArray > source_at_q(n_quad_pts);
2826 //
2827 // // AD variable
2828 // std::vector< FadType > soln_coeff(n_dofs_cell);
2829 // for (unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
2830 // soln_coeff[idof] = DGBase<dim,real,MeshType>::solution(cell_dofs_indices[idof]);
2831 // soln_coeff[idof].diff(idof, n_dofs_cell);
2832 // }
2833 // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
2834 // for (int istate=0; istate<nstate; istate++) {
2835 // // Interpolate solution to the volume quadrature points
2836 // soln_at_q[iquad][istate] = 0;
2837 // soln_grad_at_q[iquad][istate] = 0;
2838 // }
2839 // }
2840 // // Interpolate solution to face
2841 // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
2842 // for (unsigned int idof=0; idof<n_dofs_cell; ++idof) {
2843 // const unsigned int istate = fe_values_vol.get_fe().system_to_component_index(idof).first;
2844 // soln_at_q[iquad][istate] += soln_coeff[idof] * fe_values_vol.shape_value_component(idof, iquad, istate);
2845 // soln_grad_at_q[iquad][istate] += soln_coeff[idof] * fe_values_vol.shape_grad_component(idof, iquad, istate);
2846 // }
2847 // //std::cout << "Density " << soln_at_q[iquad][0] << std::endl;
2848 // //if(nstate>1) std::cout << "Momentum " << soln_at_q[iquad][1] << std::endl;
2849 // //std::cout << "Energy " << soln_at_q[iquad][nstate-1] << std::endl;
2850 // // Evaluate physical convective flux and source term
2851 // conv_phys_flux_at_q[iquad] = DGBaseState<dim,nstate,real,MeshType>::pde_physics_double->convective_flux (soln_at_q[iquad]);
2852 // diss_phys_flux_at_q[iquad] = DGBaseState<dim,nstate,real,MeshType>::pde_physics_double->dissipative_flux (soln_at_q[iquad], soln_grad_at_q[iquad], current_cell_index);
2853 // if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) {
2854 // source_at_q[iquad] = DGBaseState<dim,nstate,real,MeshType>::pde_physics_double->source_term (fe_values_vol.quadrature_point(iquad), soln_at_q[iquad], current_cell_index, DGBase<dim,real,MeshType>::current_time);
2855 // }
2856 // }
2857 //
2858 //
2859 // // Evaluate flux divergence by interpolating the flux
2860 // // Since we have nodal values of the flux, we use the Lagrange polynomials to obtain the gradients at the quadrature points.
2861 // //const dealii::FEValues<dim,dim> &fe_values_lagrange = this->fe_values_collection_volume_lagrange.get_present_fe_values();
2862 // std::vector<ADArray> flux_divergence(n_quad_pts);
2863 //
2864 // std::array<std::array<std::vector<FadType>,nstate>,dim> f;
2865 // std::array<std::array<std::vector<FadType>,nstate>,dim> g;
2866 //
2867 // for (int istate = 0; istate<nstate; ++istate) {
2868 // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
2869 // flux_divergence[iquad][istate] = 0.0;
2870 // for ( unsigned int flux_basis = 0; flux_basis < n_quad_pts; ++flux_basis ) {
2871 // flux_divergence[iquad][istate] += conv_phys_flux_at_q[flux_basis][istate] * fe_values_lagrange.shape_grad(flux_basis,iquad);
2872 // }
2873 //
2874 // }
2875 // }
2876 //
2877 // // Strong form
2878 // // The right-hand side sends all the term to the side of the source term
2879 // // Therefore,
2880 // // \divergence ( Fconv + Fdiss ) = source
2881 // // has the right-hand side
2882 // // rhs = - \divergence( Fconv + Fdiss ) + source
2883 // // Since we have done an integration by parts, the volume term resulting from the divergence of Fconv and Fdiss
2884 // // is negative. Therefore, negative of negative means we add that volume term to the right-hand-side
2885 // for (unsigned int itest=0; itest<n_dofs_cell; ++itest) {
2886 //
2887 // FadType rhs = 0;
2888 //
2889 //
2890 // const unsigned int istate = fe_values_vol.get_fe().system_to_component_index(itest).first;
2891 //
2892 // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
2893 //
2894 // // Convective
2895 // // Now minus such 2 integrations by parts
2896 // assert(JxW[iquad] - fe_values_lagrange.JxW(iquad) < 1e-14);
2897 //
2898 // rhs = rhs - fe_values_vol.shape_value_component(itest,iquad,istate) * flux_divergence[iquad][istate] * JxW[iquad];
2899 //
2900 // //// Diffusive
2901 // //// Note that for diffusion, the negative is defined in the physics
2902 // rhs = rhs + fe_values_vol.shape_grad_component(itest,iquad,istate) * diss_phys_flux_at_q[iquad][istate] * JxW[iquad];
2903 // // Source
2904 //
2905 // if(this->all_parameters->manufactured_convergence_study_param.manufactured_solution_param.use_manufactured_source_term) {
2906 // rhs = rhs + fe_values_vol.shape_value_component(itest,iquad,istate) * source_at_q[iquad][istate] * JxW[iquad];
2907 // }
2908 // }
2909 // //local_rhs_int_cell(itest) += rhs;
2910 //
2911 // }
2912 }
2913 
2914 
2915 template <int dim, int nstate, typename real, typename MeshType>
2917  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
2918  const dealii::types::global_dof_index /*current_cell_index*/,
2919  const dealii::types::global_dof_index /*neighbor_cell_index*/,
2920  const std::pair<unsigned int, int> /*face_subface_int*/,
2921  const std::pair<unsigned int, int> /*face_subface_ext*/,
2922  const typename dealii::QProjector<dim>::DataSetDescriptor /*face_data_set_int*/,
2923  const typename dealii::QProjector<dim>::DataSetDescriptor /*face_data_set_ext*/,
2924  const dealii::FEFaceValuesBase<dim,dim> &/*fe_values_int*/,
2925  const dealii::FEFaceValuesBase<dim,dim> &/*fe_values_ext*/,
2926  const real /*penalty*/,
2927  const dealii::FESystem<dim,dim> &,//fe_int,
2928  const dealii::FESystem<dim,dim> &,//fe_ext,
2929  const dealii::Quadrature<dim-1> &,//face_quadrature_int,
2930  const std::vector<dealii::types::global_dof_index> &,//metric_dof_indices_int,
2931  const std::vector<dealii::types::global_dof_index> &,//metric_dof_indices_ext,
2932  const std::vector<dealii::types::global_dof_index> &/*soln_dof_indices_int*/,
2933  const std::vector<dealii::types::global_dof_index> &/*soln_dof_indices_ext*/,
2934  dealii::Vector<real> &/*local_rhs_int_cell*/,
2935  dealii::Vector<real> &/*local_rhs_ext_cell*/,
2936  const bool /*compute_dRdW*/,
2937  const bool /*compute_dRdX*/,
2938  const bool /*compute_d2R*/)
2939 {
2940  //Do nothing
2941 
2942 // (void) current_cell_index;
2943 // (void) neighbor_cell_index;
2944 // assert(compute_dRdW); assert(!compute_dRdX); assert(!compute_d2R);
2945 // (void) compute_dRdW; (void) compute_dRdX; (void) compute_d2R;
2946 // using ADArray = std::array<FadType,nstate>;
2947 // using ADArrayTensor1 = std::array< dealii::Tensor<1,dim,FadType>, nstate >;
2948 //
2949 // // Use quadrature points of neighbor cell
2950 // // Might want to use the maximum n_quad_pts1 and n_quad_pts2
2951 // const unsigned int n_face_quad_pts = fe_values_ext.n_quadrature_points;
2952 //
2953 // const unsigned int n_dofs_int = fe_values_int.dofs_per_cell;
2954 // const unsigned int n_dofs_ext = fe_values_ext.dofs_per_cell;
2955 //
2956 // AssertDimension (n_dofs_int, soln_dof_indices_int.size());
2957 // AssertDimension (n_dofs_ext, soln_dof_indices_ext.size());
2958 //
2959 // // Jacobian and normal should always be consistent between two elements
2960 // // even for non-conforming meshes?
2961 // const std::vector<real> &JxW_int = fe_values_int.get_JxW_values ();
2962 // const std::vector<dealii::Tensor<1,dim> > &normals_int = fe_values_int.get_normal_vectors ();
2963 //
2964 // // AD variable
2965 // std::vector<FadType> soln_coeff_int_ad(n_dofs_int);
2966 // std::vector<FadType> soln_coeff_ext_ad(n_dofs_ext);
2967 //
2968 //
2969 // // Jacobian blocks
2970 // std::vector<real> dR1_dW1(n_dofs_int);
2971 // std::vector<real> dR1_dW2(n_dofs_ext);
2972 // std::vector<real> dR2_dW1(n_dofs_int);
2973 // std::vector<real> dR2_dW2(n_dofs_ext);
2974 //
2975 // std::vector<ADArray> conv_num_flux_dot_n(n_face_quad_pts);
2976 // std::vector<ADArrayTensor1> conv_phys_flux_int(n_face_quad_pts);
2977 // std::vector<ADArrayTensor1> conv_phys_flux_ext(n_face_quad_pts);
2978 //
2979 // // Interpolate solution to the face quadrature points
2980 // std::vector< ADArray > soln_int(n_face_quad_pts);
2981 // std::vector< ADArray > soln_ext(n_face_quad_pts);
2982 //
2983 // std::vector< ADArrayTensor1 > soln_grad_int(n_face_quad_pts); // Tensor initialize with zeros
2984 // std::vector< ADArrayTensor1 > soln_grad_ext(n_face_quad_pts); // Tensor initialize with zeros
2985 //
2986 // std::vector<ADArray> diss_soln_num_flux(n_face_quad_pts); // u*
2987 // std::vector<ADArray> diss_auxi_num_flux_dot_n(n_face_quad_pts); // sigma*
2988 //
2989 // std::vector<ADArrayTensor1> diss_flux_jump_int(n_face_quad_pts); // u*-u_int
2990 // std::vector<ADArrayTensor1> diss_flux_jump_ext(n_face_quad_pts); // u*-u_ext
2991 // // AD variable
2992 // const unsigned int n_total_indep = n_dofs_int + n_dofs_ext;
2993 // for (unsigned int idof = 0; idof < n_dofs_int; ++idof) {
2994 // soln_coeff_int_ad[idof] = DGBase<dim,real,MeshType>::solution(soln_dof_indices_int[idof]);
2995 // soln_coeff_int_ad[idof].diff(idof, n_total_indep);
2996 // }
2997 // for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) {
2998 // soln_coeff_ext_ad[idof] = DGBase<dim,real,MeshType>::solution(soln_dof_indices_ext[idof]);
2999 // soln_coeff_ext_ad[idof].diff(idof+n_dofs_int, n_total_indep);
3000 // }
3001 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
3002 // for (int istate=0; istate<nstate; istate++) {
3003 // soln_int[iquad][istate] = 0;
3004 // soln_grad_int[iquad][istate] = 0;
3005 // soln_ext[iquad][istate] = 0;
3006 // soln_grad_ext[iquad][istate] = 0;
3007 // }
3008 // }
3009 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
3010 //
3011 // const dealii::Tensor<1,dim,FadType> normal_int = normals_int[iquad];
3012 // const dealii::Tensor<1,dim,FadType> normal_ext = -normal_int;
3013 //
3014 // // Interpolate solution to face
3015 // for (unsigned int idof=0; idof<n_dofs_int; ++idof) {
3016 // const unsigned int istate = fe_values_int.get_fe().system_to_component_index(idof).first;
3017 // soln_int[iquad][istate] += soln_coeff_int_ad[idof] * fe_values_int.shape_value_component(idof, iquad, istate);
3018 // soln_grad_int[iquad][istate] += soln_coeff_int_ad[idof] * fe_values_int.shape_grad_component(idof, iquad, istate);
3019 // }
3020 // for (unsigned int idof=0; idof<n_dofs_ext; ++idof) {
3021 // const unsigned int istate = fe_values_ext.get_fe().system_to_component_index(idof).first;
3022 // soln_ext[iquad][istate] += soln_coeff_ext_ad[idof] * fe_values_ext.shape_value_component(idof, iquad, istate);
3023 // soln_grad_ext[iquad][istate] += soln_coeff_ext_ad[idof] * fe_values_ext.shape_grad_component(idof, iquad, istate);
3024 // }
3025 // //std::cout << "Density int" << soln_int[iquad][0] << std::endl;
3026 // //if(nstate>1) std::cout << "Momentum int" << soln_int[iquad][1] << std::endl;
3027 // //std::cout << "Energy int" << soln_int[iquad][nstate-1] << std::endl;
3028 // //std::cout << "Density ext" << soln_ext[iquad][0] << std::endl;
3029 // //if(nstate>1) std::cout << "Momentum ext" << soln_ext[iquad][1] << std::endl;
3030 // //std::cout << "Energy ext" << soln_ext[iquad][nstate-1] << std::endl;
3031 //
3032 // // Evaluate physical convective flux, physical dissipative flux, and source term
3033 // conv_num_flux_dot_n[iquad] = DGBaseState<dim,nstate,real,MeshType>::conv_num_flux_fad->evaluate_flux(soln_int[iquad], soln_ext[iquad], normal_int);
3034 //
3035 // conv_phys_flux_int[iquad] = this->pde_physics_fad->convective_flux (soln_int[iquad]);
3036 // conv_phys_flux_ext[iquad] = this->pde_physics_fad->convective_flux (soln_ext[iquad]);
3037 //
3038 // diss_soln_num_flux[iquad] = DGBaseState<dim,nstate,real,MeshType>::diss_num_flux_fad->evaluate_solution_flux(soln_int[iquad], soln_ext[iquad], normal_int);
3039 //
3040 // ADArrayTensor1 diss_soln_jump_int, diss_soln_jump_ext;
3041 // for (int s=0; s<nstate; s++) {
3042 // for (int d=0; d<dim; d++) {
3043 // diss_soln_jump_int[s][d] = (diss_soln_num_flux[iquad][s] - soln_int[iquad][s]) * normal_int[d];
3044 // diss_soln_jump_ext[s][d] = (diss_soln_num_flux[iquad][s] - soln_ext[iquad][s]) * normal_ext[d];
3045 // }
3046 // }
3047 // diss_flux_jump_int[iquad] = this->pde_physics_fad->dissipative_flux (soln_int[iquad], diss_soln_jump_int, current_cell_index);
3048 // diss_flux_jump_ext[iquad] = this->pde_physics_fad->dissipative_flux (soln_ext[iquad], diss_soln_jump_ext, neighbor_cell_index);
3049 //
3050 // diss_auxi_num_flux_dot_n[iquad] = DGBaseState<dim,nstate,real,MeshType>::diss_num_flux_fad->evaluate_auxiliary_flux(
3051 // current_cell_index, neighbor_cell_index,
3052 // 0.0, 0.0,
3053 // soln_int[iquad], soln_ext[iquad],
3054 // soln_grad_int[iquad], soln_grad_ext[iquad],
3055 // normal_int, penalty);
3056 // }
3057 //
3058 // // From test functions associated with interior cell point of view
3059 // for (unsigned int itest_int=0; itest_int<n_dofs_int; ++itest_int) {
3060 // FadType rhs = 0.0;
3061 // const unsigned int istate = fe_values_int.get_fe().system_to_component_index(itest_int).first;
3062 //
3063 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
3064 // // Convection
3065 // const FadType flux_diff = conv_num_flux_dot_n[iquad][istate] - conv_phys_flux_int[iquad][istate]*normals_int[iquad];
3066 // rhs = rhs - fe_values_int.shape_value_component(itest_int,iquad,istate) * flux_diff * JxW_int[iquad];
3067 // // Diffusive
3068 // rhs = rhs - fe_values_int.shape_value_component(itest_int,iquad,istate) * diss_auxi_num_flux_dot_n[iquad][istate] * JxW_int[iquad];
3069 // rhs = rhs + fe_values_int.shape_grad_component(itest_int,iquad,istate) * diss_flux_jump_int[iquad][istate] * JxW_int[iquad];
3070 // }
3071 //
3072 // local_rhs_int_cell(itest_int) += rhs.val();
3073 // if (this->all_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) {
3074 // for (unsigned int idof = 0; idof < n_dofs_int; ++idof) {
3075 // dR1_dW1[idof] = rhs.fastAccessDx(idof);
3076 // }
3077 // for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) {
3078 // dR1_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof);
3079 // }
3080 // this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_int, dR1_dW1);
3081 // this->system_matrix.add(soln_dof_indices_int[itest_int], soln_dof_indices_ext, dR1_dW2);
3082 // }
3083 // }
3084 //
3085 // // From test functions associated with neighbour cell point of view
3086 // for (unsigned int itest_ext=0; itest_ext<n_dofs_ext; ++itest_ext) {
3087 // FadType rhs = 0.0;
3088 // const unsigned int istate = fe_values_int.get_fe().system_to_component_index(itest_ext).first;
3089 //
3090 // for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
3091 // // Convection
3092 // const FadType flux_diff = (-conv_num_flux_dot_n[iquad][istate]) - conv_phys_flux_ext[iquad][istate]*(-normals_int[iquad]);
3093 // rhs = rhs - fe_values_ext.shape_value_component(itest_ext,iquad,istate) * flux_diff * JxW_int[iquad];
3094 // // Diffusive
3095 // rhs = rhs - fe_values_ext.shape_value_component(itest_ext,iquad,istate) * (-diss_auxi_num_flux_dot_n[iquad][istate]) * JxW_int[iquad];
3096 // rhs = rhs + fe_values_ext.shape_grad_component(itest_ext,iquad,istate) * diss_flux_jump_ext[iquad][istate] * JxW_int[iquad];
3097 // }
3098 //
3099 // local_rhs_ext_cell(itest_ext) += rhs.val();
3100 // if (this->all_parameters->ode_solver_param.ode_solver_type == Parameters::ODESolverParam::ODESolverEnum::implicit_solver) {
3101 // for (unsigned int idof = 0; idof < n_dofs_int; ++idof) {
3102 // dR2_dW1[idof] = rhs.fastAccessDx(idof);
3103 // }
3104 // for (unsigned int idof = 0; idof < n_dofs_ext; ++idof) {
3105 // dR2_dW2[idof] = rhs.fastAccessDx(n_dofs_int+idof);
3106 // }
3107 // this->system_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_int, dR2_dW1);
3108 // this->system_matrix.add(soln_dof_indices_ext[itest_ext], soln_dof_indices_ext, dR2_dW2);
3109 // }
3110 // }
3111 }
3112 
3113 /*******************************************************
3114  *
3115  * EXPLICIT
3116  *
3117  *******************************************************/
3118 
3119 template <int dim, int nstate, typename real, typename MeshType>
3121  typename dealii::DoFHandler<dim>::active_cell_iterator /*cell*/,
3122  const dealii::types::global_dof_index /*current_cell_index*/,
3123  const dealii::FEValues<dim,dim> &/*fe_values_vol*/,
3124  const std::vector<dealii::types::global_dof_index> &/*cell_dofs_indices*/,
3125  const std::vector<dealii::types::global_dof_index> &/*metric_dof_indices*/,
3126  const unsigned int /*poly_degree*/,
3127  const unsigned int /*grid_degree*/,
3128  dealii::Vector<real> &/*local_rhs_int_cell*/,
3129  const dealii::FEValues<dim,dim> &/*fe_values_lagrange*/)
3130 {
3131  //do nothing
3132 }
3133 
3134 
3135 template <int dim, int nstate, typename real, typename MeshType>
3137 {
3138  //Do nothing.
3139 }
3140 
3141 // using default MeshType = Triangulation
3142 // 1D: dealii::Triangulation<dim>;
3143 // Otherwise: dealii::parallel::distributed::Triangulation<dim>;
3150 
3157 
3158 #if PHILIP_DIM!=1
3165 #endif
3166 
3167 } // PHiLiP namespace
dealii::Tensor< 2, dim, std::vector< real > > metric_cofactor_vol
The volume metric cofactor matrix.
Definition: operators.h:1165
PartialDifferentialEquation pde_type
Store the PDE type to be solved.
std::array< dealii::FullMatrix< double >, 2 > oneD_surf_operator
Stores the one dimensional surface operator.
Definition: operators.h:360
void assemble_face_term_derivatives(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, 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 dealii::FEFaceValuesBase< dim, dim > &, const dealii::FEFaceValuesBase< dim, dim > &, const real penalty, const dealii::FESystem< dim, dim > &fe_int, const dealii::FESystem< dim, dim > &fe_ext, const dealii::Quadrature< dim-1 > &face_quadrature, const std::vector< dealii::types::global_dof_index > &metric_dof_indices_int, const std::vector< dealii::types::global_dof_index > &metric_dof_indices_ext, const std::vector< dealii::types::global_dof_index > &soln_dof_indices_int, const std::vector< dealii::types::global_dof_index > &soln_dof_indices_ext, dealii::Vector< real > &local_rhs_int_cell, dealii::Vector< real > &local_rhs_ext_cell, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Evaluate the integral over the internal cell edges and its specified derivatives. ...
Definition: strong_dg.cpp:2916
void assemble_boundary_term_strong(const unsigned int iface, const dealii::types::global_dof_index current_cell_index, const unsigned int boundary_id, const unsigned int poly_degree, const real penalty, const std::vector< dealii::types::global_dof_index > &dof_indices, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, dealii::Vector< real > &local_rhs_cell)
Strong form primary equation&#39;s boundary right-hand-side.
Definition: strong_dg.cpp:1312
bool use_auxiliary_eq
Flag for using the auxiliary equation.
Definition: dg_base.hpp:938
std::unique_ptr< NumericalFlux::NumericalFluxDissipative< dim, nstate, real > > diss_num_flux_double
Dissipative numerical flux with real type.
const dealii::UpdateFlags neighbor_face_update_flags
Update flags needed at neighbor&#39; face points.
Definition: dg_base.hpp:877
dealii::LinearAlgebra::distributed::Vector< double > artificial_dissipation_c0
Artificial dissipation coefficients.
Definition: dg_base.hpp:673
void sum_factorized_Hadamard_surface_sparsity_pattern(const unsigned int rows_size, const unsigned int columns_size, std::vector< unsigned int > &rows, std::vector< unsigned int > &columns, const int dim_not_zero)
Computes the rows and columns vectors with non-zero indices for surface sum-factorized Hadamard produ...
Definition: operators.cpp:932
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: dg_base.hpp:91
void inner_product_surface_1D(const unsigned int face_number, const std::vector< real > &input_vect, const std::vector< real > &weight_vect, std::vector< real > &output_vect, const std::array< dealii::FullMatrix< double >, 2 > &basis_surf, const dealii::FullMatrix< double > &basis_vol, const bool adding=false, const double factor=1.0)
Apply sum-factorization inner product on a surface.
Definition: operators.cpp:344
void assemble_auxiliary_residual()
Assembles the auxiliary equations&#39; residuals and solves for the auxiliary variables.
Definition: strong_dg.cpp:398
dealii::FullMatrix< double > oneD_grad_operator
Stores the one dimensional gradient operator.
Definition: operators.h:363
std::unique_ptr< NumericalFlux::NumericalFluxConvective< dim, nstate, real > > conv_num_flux_double
Convective numerical flux with real type.
std::array< dealii::LinearAlgebra::distributed::Vector< double >, dim > auxiliary_right_hand_side
The auxiliary equations&#39; right hand sides.
Definition: dg_base.hpp:412
DGStrong(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: strong_dg.cpp:23
std::shared_ptr< Triangulation > triangulation
Mesh.
Definition: dg_base.hpp:160
void Hadamard_product(const dealii::FullMatrix< real > &input_mat1, const dealii::FullMatrix< real > &input_mat2, dealii::FullMatrix< real > &output_mat)
Computes a single Hadamard product.
Definition: operators.cpp:795
void inner_product_1D(const std::vector< real > &input_vect, const std::vector< real > &weight_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis_x, const bool adding=false, const double factor=1.0)
Apply the inner product operation using the 1D operator in each direction.
Definition: operators.cpp:524
PartialDifferentialEquation
Possible Partial Differential Equations to solve.
Files for the baseline physics.
Definition: ADTypes.hpp:10
ManufacturedSolutionParam manufactured_solution_param
Associated manufactured solution parameters.
unsigned int current_degree
Stores the degree of the current poly degree.
Definition: operators.h:1036
bool use_invariant_curl_form
Flag to use invariant curl form for metric cofactor operator.
dealii::Tensor< 2, dim, std::vector< real > > metric_cofactor_surf
The facet metric cofactor matrix, for ONE face.
Definition: operators.h:1168
void assemble_volume_term_strong(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const std::vector< dealii::types::global_dof_index > &cell_dofs_indices, const unsigned int poly_degree, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, dealii::Vector< real > &local_rhs_int_cell)
Strong form primary equation&#39;s volume right-hand-side.
Definition: strong_dg.cpp:879
void assemble_face_term_strong(const unsigned int iface, const unsigned int neighbor_iface, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, const unsigned int poly_degree_int, const unsigned int poly_degree_ext, const real penalty, const std::vector< dealii::types::global_dof_index > &dof_indices_int, const std::vector< dealii::types::global_dof_index > &dof_indices_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_ext, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_int, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_ext, dealii::Vector< real > &local_rhs_int_cell, dealii::Vector< real > &local_rhs_ext_cell)
Strong form primary equation&#39;s facet right-hand-side.
Definition: strong_dg.cpp:1808
dealii::FullMatrix< double > oneD_skew_symm_vol_oper
Skew-symmetric volume operator .
Definition: operators.h:494
void reinit_operators_for_cell_residual_loop(const unsigned int poly_degree_int, const unsigned int poly_degree_ext, const unsigned int grid_degree, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_ext, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis)
Builds needed operators for cell residual loop.
Definition: dg_base.cpp:1045
void assemble_volume_term_derivatives(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const dealii::FEValues< dim, dim > &, const dealii::FESystem< dim, dim > &fe, const dealii::Quadrature< dim > &quadrature, const std::vector< dealii::types::global_dof_index > &metric_dof_indices, const std::vector< dealii::types::global_dof_index > &soln_dof_indices, dealii::Vector< real > &local_rhs_cell, const dealii::FEValues< dim, dim > &, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Evaluate the integral over the cell volume and the specified derivatives.
Definition: strong_dg.cpp:2789
dealii::Vector< double > max_dt_cell
Time it takes for the maximum wavespeed to cross the cell domain.
Definition: dg_base.hpp:457
Main parameter class that contains the various other sub-parameter classes.
void transform_reference_to_physical(const dealii::Tensor< 1, dim, real > &ref, const dealii::Tensor< 2, dim, real > &metric_cofactor, dealii::Tensor< 1, dim, real > &phys)
Given a reference tensor, return the physical tensor.
Definition: operators.cpp:2219
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
Definition: dg_base.hpp:409
void assemble_face_term_auxiliary_equation(const unsigned int iface, const unsigned int neighbor_iface, const dealii::types::global_dof_index current_cell_index, const dealii::types::global_dof_index neighbor_cell_index, const unsigned int poly_degree_int, const unsigned int poly_degree_ext, const std::vector< dealii::types::global_dof_index > &dof_indices_int, const std::vector< dealii::types::global_dof_index > &dof_indices_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_int, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS_int, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS_ext)
Evaluate the facet RHS for the auxiliary equation.
Definition: strong_dg.cpp:721
std::vector< real > det_Jac_vol
The determinant of the metric Jacobian at volume cubature nodes.
Definition: operators.h:1171
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
const int nstate
Number of state variables.
Definition: dg_base.hpp:96
dealii::DoFHandler< dim > dof_handler_artificial_dissipation
Degrees of freedom handler for C0 artificial dissipation.
Definition: dg_base.hpp:670
DGStrong class templated on the number of state variables.
Definition: strong_dg.hpp:16
ODESolverParam ode_solver_param
Contains parameters for ODE solver.
unsigned int current_degree
Stores the degree of the current poly degree.
Definition: operators.h:391
dealii::TrilinosWrappers::SparseMatrix global_inverse_mass_matrix_auxiliary
Global inverse of the auxiliary mass matrix.
Definition: dg_base.hpp:339
void sum_factorized_Hadamard_surface_basis_assembly(const unsigned int rows_size, const unsigned int columns_size_1D, const std::vector< unsigned int > &rows, const std::vector< unsigned int > &columns, const dealii::FullMatrix< double > &basis, const std::vector< double > &weights, dealii::FullMatrix< double > &basis_sparse, const int dim_not_zero)
Constructs the basis operator storing all non-zero entries for a "sum-factorized" surface Hadamard p...
Definition: operators.cpp:1000
dealii::hp::QCollection< dim-1 > face_quadrature_collection
Quadrature used to evaluate face integrals.
Definition: dg_base.hpp:610
const unsigned int max_degree
Maximum degree used for p-refi1nement.
Definition: dg_base.hpp:104
std::shared_ptr< Physics::PhysicsBase< dim, nstate, real > > pde_physics_double
Contains the physics of the PDE with real type.
Base metric operators class that stores functions used in both the volume and on surface.
Definition: operators.h:1086
void matrix_vector_mult_surface_1D(const unsigned int face_number, const std::vector< real > &input_vect, std::vector< real > &output_vect, const std::array< dealii::FullMatrix< double >, 2 > &basis_surf, const dealii::FullMatrix< double > &basis_vol, const bool adding=false, const double factor=1.0)
Apply sum-factorization matrix vector multiplication on a surface.
Definition: operators.cpp:319
real current_time
The current time set in set_current_time()
Definition: dg_base.hpp:665
void divergence_matrix_vector_mult_1D(const dealii::Tensor< 1, dim, std::vector< real >> &input_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis, const dealii::FullMatrix< double > &gradient_basis)
Computes the divergence using sum-factorization where the basis are the same in each direction...
Definition: operators.cpp:369
void assemble_boundary_term_derivatives(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const unsigned int face_number, const unsigned int boundary_id, const dealii::FEFaceValuesBase< dim, dim > &fe_values_boundary, const real penalty, const dealii::FESystem< dim, dim > &fe, const dealii::Quadrature< dim-1 > &quadrature, const std::vector< dealii::types::global_dof_index > &metric_dof_indices, const std::vector< dealii::types::global_dof_index > &soln_dof_indices, dealii::Vector< real > &local_rhs_cell, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Assemble boundary term derivatives.
Definition: strong_dg.cpp:2637
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
Definition: dg_base.hpp:894
The mapping shape functions evaluated at the desired nodes (facet set included in volume grid nodes f...
Definition: operators.h:1026
bool use_manufactured_source_term
Uses non-zero source term based on the manufactured solution and the PDE.
bool use_split_form
Flag to use split form.
const dealii::UpdateFlags face_update_flags
Update flags needed at face points.
Definition: dg_base.hpp:873
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
Definition: dg_base.hpp:655
void gradient_matrix_vector_mult_1D(const std::vector< real > &input_vect, dealii::Tensor< 1, dim, std::vector< real >> &output_vect, const dealii::FullMatrix< double > &basis, const dealii::FullMatrix< double > &gradient_basis)
Computes the gradient of a scalar using sum-factorization where the basis are the same in each direct...
Definition: operators.cpp:414
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.
void assemble_subface_term_and_build_operators(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 unsigned int, const real penalty, const std::vector< dealii::types::global_dof_index > &current_dofs_indices, const std::vector< dealii::types::global_dof_index > &neighbor_dofs_indices, const std::vector< dealii::types::global_dof_index > &current_metric_dofs_indices, const std::vector< dealii::types::global_dof_index > &neighbor_metric_dofs_indices, const unsigned int poly_degree_int, const unsigned int poly_degree_ext, const unsigned int grid_degree_int, const unsigned int grid_degree_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_ext, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_int, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_ext, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis, std::array< std::vector< real >, dim > &mapping_support_points, dealii::hp::FEFaceValues< dim, dim > &fe_values_collection_face_int, dealii::hp::FESubfaceValues< dim, dim > &, dealii::Vector< real > &current_cell_rhs, dealii::Vector< real > &neighbor_cell_rhs, std::vector< dealii::Tensor< 1, dim, real >> &current_cell_rhs_aux, dealii::LinearAlgebra::distributed::Vector< double > &rhs, std::array< dealii::LinearAlgebra::distributed::Vector< double >, dim > &rhs_aux, const bool compute_auxiliary_right_hand_side, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Builds the necessary operators and assembles subface residual.
Definition: strong_dg.cpp:313
const unsigned int max_grid_degree
Maximum grid degree used for hp-refi1nement.
Definition: dg_base.hpp:109
const dealii::UpdateFlags volume_update_flags
Update flags needed at volume points.
Definition: dg_base.hpp:870
void transform_physical_to_reference(const dealii::Tensor< 1, dim, real > &phys, const dealii::Tensor< 2, dim, real > &metric_cofactor, dealii::Tensor< 1, dim, real > &ref)
Given a physical tensor, return the reference tensor.
Definition: operators.cpp:2205
dealii::FullMatrix< double > oneD_vol_operator
Stores the one dimensional volume operator.
Definition: operators.h:355
void sum_factorized_Hadamard_basis_assembly(const unsigned int rows_size_1D, const unsigned int columns_size_1D, const std::vector< std::array< unsigned int, dim >> &rows, const std::vector< std::array< unsigned int, dim >> &columns, const dealii::FullMatrix< double > &basis, const std::vector< double > &weights, std::array< dealii::FullMatrix< double >, dim > &basis_sparse)
Constructs the basis operator storing all non-zero entries for a "sum-factorized" Hadamard product...
Definition: operators.cpp:879
void assemble_volume_term_auxiliary_equation(const std::vector< dealii::types::global_dof_index > &current_dofs_indices, const unsigned int poly_degree, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS)
Evaluate the volume RHS for the auxiliary equation.
Definition: strong_dg.cpp:501
void build_facet_metric_operators(const unsigned int iface, const unsigned int n_quad_pts, const unsigned int n_metric_dofs, const std::array< std::vector< real >, dim > &mapping_support_points, mapping_shape_functions< dim, n_faces, real > &mapping_basis, const bool use_invariant_curl_form=false)
Builds the facet metric operators.
Definition: operators.cpp:2351
void assemble_boundary_term_auxiliary_equation(const unsigned int iface, const dealii::types::global_dof_index current_cell_index, const unsigned int poly_degree, const unsigned int boundary_id, const std::vector< dealii::types::global_dof_index > &dofs_indices, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS)
Evaluate the boundary RHS for the auxiliary equation.
Definition: strong_dg.cpp:575
Abstract class templated on the number of state variables.
bool use_inverse_mass_on_the_fly
Flag to use inverse mass matrix on-the-fly for explicit solves.
ODESolverEnum ode_solver_type
ODE solver type.
dealii::DoFHandler< dim > dof_handler
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:652
void assemble_face_term_and_build_operators(typename dealii::DoFHandler< dim >::active_cell_iterator, typename dealii::DoFHandler< dim >::active_cell_iterator, 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 real penalty, const std::vector< dealii::types::global_dof_index > &current_dofs_indices, const std::vector< dealii::types::global_dof_index > &neighbor_dofs_indices, const std::vector< dealii::types::global_dof_index > &current_metric_dofs_indices, const std::vector< dealii::types::global_dof_index > &neighbor_metric_dofs_indices, const unsigned int poly_degree_int, const unsigned int poly_degree_ext, const unsigned int grid_degree_int, const unsigned int grid_degree_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_ext, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_int, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper_ext, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis, std::array< std::vector< real >, dim > &mapping_support_points, dealii::hp::FEFaceValues< dim, dim > &, dealii::hp::FEFaceValues< dim, dim > &, dealii::Vector< real > &current_cell_rhs, dealii::Vector< real > &neighbor_cell_rhs, std::vector< dealii::Tensor< 1, dim, real >> &current_cell_rhs_aux, dealii::LinearAlgebra::distributed::Vector< double > &rhs, std::array< dealii::LinearAlgebra::distributed::Vector< double >, dim > &rhs_aux, const bool compute_auxiliary_right_hand_side, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R)
Builds the necessary operators and assembles face residual.
Definition: strong_dg.cpp:186
void assemble_volume_term_and_build_operators(typename dealii::DoFHandler< dim >::active_cell_iterator cell, const dealii::types::global_dof_index current_cell_index, const std::vector< dealii::types::global_dof_index > &cell_dofs_indices, const std::vector< dealii::types::global_dof_index > &metric_dof_indices, const unsigned int poly_degree, const unsigned int grid_degree, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis, std::array< std::vector< real >, dim > &mapping_support_points, dealii::hp::FEValues< dim, dim > &, dealii::hp::FEValues< dim, dim > &, const dealii::FESystem< dim, dim > &, dealii::Vector< real > &local_rhs_int_cell, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS, const bool compute_auxiliary_right_hand_side, const bool, const bool, const bool)
Builds the necessary operators and assembles volume residual for either primary or auxiliary...
Definition: strong_dg.cpp:38
void build_volume_metric_operators(const unsigned int n_quad_pts, const unsigned int n_metric_dofs, const std::array< std::vector< real >, dim > &mapping_support_points, mapping_shape_functions< dim, n_faces, real > &mapping_basis, const bool use_invariant_curl_form=false)
Builds the volume metric operators.
Definition: operators.cpp:2294
std::array< dealii::Tensor< 1, dim, std::vector< real > >, n_faces > flux_nodes_surf
Stores the physical facet flux nodes.
Definition: operators.h:1183
bool add_artificial_dissipation
Flag to add artificial dissipation from Persson&#39;s shock capturing paper.
const dealii::hp::FECollection< dim > fe_collection_lagrange
Lagrange basis used in strong form.
Definition: dg_base.hpp:614
dealii::Vector< double > cell_volume
Time it takes for the maximum wavespeed to cross the cell domain.
Definition: dg_base.hpp:450
void assemble_boundary_term_and_build_operators(typename dealii::DoFHandler< dim >::active_cell_iterator, const dealii::types::global_dof_index current_cell_index, const unsigned int iface, const unsigned int boundary_id, const real penalty, const std::vector< dealii::types::global_dof_index > &cell_dofs_indices, const std::vector< dealii::types::global_dof_index > &metric_dof_indices, const unsigned int poly_degree, const unsigned int grid_degree, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::metric_operators< real, dim, 2 *dim > &metric_oper, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis, std::array< std::vector< real >, dim > &mapping_support_points, dealii::hp::FEFaceValues< dim, dim > &, const dealii::FESystem< dim, dim > &, dealii::Vector< real > &local_rhs_int_cell, std::vector< dealii::Tensor< 1, dim, real >> &local_auxiliary_RHS, const bool compute_auxiliary_right_hand_side, const bool, const bool, const bool)
Builds the necessary operators and assembles boundary residual for either primary or auxiliary...
Definition: strong_dg.cpp:125
dealii::hp::QCollection< 1 > oneD_quadrature_collection
1D quadrature to generate Lagrange polynomials for the sake of flux interpolation.
Definition: dg_base.hpp:632
std::array< dealii::LinearAlgebra::distributed::Vector< double >, dim > auxiliary_solution
The auxiliary equations&#39; solution.
Definition: dg_base.hpp:415
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
void assemble_cell_residual(const DoFCellAccessorType1 &current_cell, const DoFCellAccessorType2 &current_metric_cell, const bool compute_dRdW, const bool compute_dRdX, const bool compute_d2R, dealii::hp::FEValues< dim, dim > &fe_values_collection_volume, 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, dealii::hp::FEValues< dim, dim > &fe_values_collection_volume_lagrange, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &soln_basis_ext, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_int, OPERATOR::basis_functions< dim, 2 *dim, real > &flux_basis_ext, OPERATOR::local_basis_stiffness< dim, 2 *dim, real > &flux_basis_stiffness, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_int, OPERATOR::vol_projection_operator< dim, 2 *dim, real > &soln_basis_projection_oper_ext, OPERATOR::mapping_shape_functions< dim, 2 *dim, real > &mapping_basis, const bool compute_auxiliary_right_hand_side, dealii::LinearAlgebra::distributed::Vector< double > &rhs, std::array< dealii::LinearAlgebra::distributed::Vector< double >, dim > &rhs_aux)
Used in assemble_residual().
Definition: dg_base.cpp:454
dealii::hp::QCollection< dim > volume_quadrature_collection
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:608
unsigned int n_dofs() const
Number of degrees of freedom.
Definition: dg_base.cpp:1458
ArtificialDissipationParam artificial_dissipation_param
Contains parameters for artificial dissipation.
void matrix_vector_mult_1D(const std::vector< real > &input_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis_x, const bool adding=false, const double factor=1.0)
Apply the matrix vector operation using the 1D operator in each direction.
Definition: operators.cpp:308
const dealii::hp::FECollection< dim > fe_collection
Finite Element Collection for p-finite-element to represent the solution.
Definition: dg_base.hpp:597
dealii::Tensor< 1, dim, std::vector< real > > flux_nodes_vol
Stores the physical volume flux nodes.
Definition: operators.h:1180
void allocate_dual_vector()
Allocate the dual vector for optimization.
Definition: strong_dg.cpp:3136
Projection operator corresponding to basis functions onto M-norm (L2).
Definition: operators.h:694
dealii::LinearAlgebra::distributed::Vector< double > right_hand_side
Residual of the current solution.
Definition: dg_base.hpp:396
Local stiffness matrix without jacobian dependence.
Definition: operators.h:472
void sum_factorized_Hadamard_sparsity_pattern(const unsigned int rows_size, const unsigned int columns_size, std::vector< std::array< unsigned int, dim >> &rows, std::vector< std::array< unsigned int, dim >> &columns)
Computes the rows and columns vectors with non-zero indices for sum-factorized Hadamard products...
Definition: operators.cpp:814
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: strong_dg.cpp:3120
const dealii::FE_Q< dim > fe_q_artificial_dissipation
Continuous distribution of artificial dissipation.
Definition: dg_base.hpp:667
void apply_inverse_global_mass_matrix(const dealii::LinearAlgebra::distributed::Vector< double > &input_vector, dealii::LinearAlgebra::distributed::Vector< double > &output_vector, const bool use_auxiliary_eq=false)
Applies the inverse of the local metric dependent mass matrices when the global is not stored...
Definition: dg_base.cpp:2452