[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
tvb_limiter.cpp
1 #include "tvb_limiter.h"
2 
3 namespace PHiLiP {
4 /**********************************
5 *
6 * TVB Limiter Class
7 *
8 **********************************/
9 // Constructor
10 template <int dim, int nstate, typename real>
12  const Parameters::AllParameters* const parameters_input)
13  : BoundPreservingLimiterState<dim,nstate,real>::BoundPreservingLimiterState( parameters_input) {}
14 
15 template <int dim, int nstate, typename real>
17  const double a_state,
18  const double M_state,
19  const double h,
20  const double diff_next_state,
21  const double diff_prev_state,
22  const double cell_avg_state,
23  const bool left_face)
24 {
25  real limited_value = 0.0;
26  real minmod = 0.0;
27  if (abs(a_state) <= M_state * pow(h, 2.0) && left_face) {
28  limited_value = cell_avg_state - a_state;
29  } else if (abs(a_state) <= M_state * pow(h, 2.0) && !left_face) {
30  limited_value = cell_avg_state + a_state;
31  } else if (left_face) {
32  if (signbit(a_state) == signbit(diff_next_state) && signbit(a_state) == signbit(diff_prev_state)) {
33  minmod = std::min({ abs(a_state), abs(diff_next_state), abs(diff_prev_state) });
34 
35  if (signbit(a_state))
36  limited_value = cell_avg_state + std::max(abs(minmod), M_state * pow(h, 2.0));
37  else
38  limited_value = cell_avg_state - std::max(abs(minmod), M_state * pow(h, 2.0));
39  }
40  else
41  limited_value = cell_avg_state - M_state * pow(h, 2.0);
42  } else if (!left_face) {
43  if (signbit(a_state) == signbit(diff_next_state) && signbit(a_state) == signbit(diff_prev_state)) {
44  minmod = std::min({ abs(a_state), abs(diff_next_state), abs(diff_prev_state) });
45 
46  if (signbit(a_state))
47  limited_value = cell_avg_state - std::max(abs(minmod), M_state * pow(h, 2.0));
48  else
49  limited_value = cell_avg_state + std::max(abs(minmod), M_state * pow(h, 2.0));
50  }
51  else
52  limited_value = cell_avg_state - M_state * pow(h, 2.0);
53  }
54 
55  return limited_value;
56 }
57 
58 template <int dim, int nstate, typename real>
59 std::array<std::vector<real>, nstate> TVBLimiter<dim, nstate, real>::limit_cell(
60  std::array<std::vector<real>, nstate> soln_at_q,
61  const unsigned int n_quad_pts,
62  const std::array<real, nstate> prev_cell_avg,
63  const std::array<real, nstate> soln_cell_avg,
64  const std::array<real, nstate> next_cell_avg,
65  const std::array<real, nstate> M,
66  const double h)
67 {
68  std::array<real, nstate> soln_cell_0;
69  std::array<real, nstate> soln_cell_k;
70  std::array<real, nstate> diff_next;
71  std::array<real, nstate> diff_prev;
72  std::array<real, nstate> soln_0_lim;
73  std::array<real, nstate> soln_k_lim;
74  std::array<real, nstate> theta; // Value used to linearly scale solution
75 
76  // This part is only valid for 1D as it uses the value at the first and last quadrature points
77  // as the face values of the cell which does not hold true for 2D and 3D.
78  for (unsigned int istate = 0; istate < nstate; ++istate) {
79  soln_cell_0[istate] = soln_at_q[istate][0]; // Value at left face of the cell
80  soln_cell_k[istate] = soln_at_q[istate][n_quad_pts - 1]; // Value at right face of the cell
81 
82  diff_next[istate] = next_cell_avg[istate] - soln_cell_avg[istate];
83  diff_prev[istate] = soln_cell_avg[istate] - prev_cell_avg[istate];
84  }
85 
86  real a = 0.0; // Chen,Shu 2017, Thm 3.7 minmod function
87 
88  for (unsigned int istate = 0; istate < nstate; ++istate) {
89  a = soln_cell_avg[istate] - soln_cell_0[istate];
90  soln_0_lim[istate] = apply_modified_minmod(a, M[istate], h, diff_next[istate], diff_prev[istate], soln_cell_avg[istate], true);
91 
92  a = soln_cell_k[istate] - soln_cell_avg[istate];
93  soln_k_lim[istate] = apply_modified_minmod(a, M[istate], h, diff_next[istate], diff_prev[istate], soln_cell_avg[istate], false);
94 
95  real scale = ((soln_cell_0[istate] - soln_cell_avg[istate]) + (soln_cell_k[istate] - soln_cell_avg[istate]));
96  if (scale != 0)
97  theta[istate] = ((soln_0_lim[istate] - soln_cell_avg[istate]) + (soln_k_lim[istate] - soln_cell_avg[istate])) / scale;
98  else
99  theta[istate] = 0;
100  }
101 
102  // Limit the values at the quadrature points
103  for (unsigned int istate = 0; istate < nstate; ++istate) {
104  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
105  if (iquad == 0) {
106  soln_at_q[istate][iquad] = soln_0_lim[istate];
107  }
108  else if (iquad == n_quad_pts - 1) {
109  soln_at_q[istate][iquad] = soln_k_lim[istate];
110  }
111  else {
112  soln_at_q[istate][iquad] = theta[istate] * (soln_at_q[istate][iquad] - soln_cell_avg[istate])
113  + soln_cell_avg[istate];
114  }
115  }
116  }
117 
118  return soln_at_q;
119 }
120 
121 template <int dim, int nstate, typename real>
123  const dealii::LinearAlgebra::distributed::Vector<double>& solution,
124  const dealii::hp::FECollection<dim>& fe_collection,
125  const dealii::hp::QCollection<dim>& volume_quadrature_collection,
127  const int poly_degree,
128  const std::vector<dealii::types::global_dof_index>& neigh_dofs_indices,
129  const unsigned int n_dofs_neigh_cell)
130 {
131  // Extract the local solution dofs in the cell from the global solution dofs
132  std::array<std::vector<real>, nstate> soln_coeff;
133  const unsigned int n_shape_fns = n_dofs_neigh_cell / nstate;
134 
135  for (unsigned int istate = 0; istate < nstate; ++istate) {
136  soln_coeff[istate].resize(n_shape_fns);
137  }
138 
139  // Allocate soln_coeff
140  for (unsigned int idof = 0; idof < n_dofs_neigh_cell; ++idof) {
141  const unsigned int istate = fe_collection[poly_degree].system_to_component_index(idof).first;
142  const unsigned int ishape = fe_collection[poly_degree].system_to_component_index(idof).second;
143  soln_coeff[istate][ishape] = solution[neigh_dofs_indices[idof]];
144  }
145  const unsigned int n_quad_pts = volume_quadrature_collection[poly_degree].size();
146  const std::vector<real>& quad_weights = volume_quadrature_collection[poly_degree].get_weights();
147 
148  std::array<real, nstate> cell_avg;
149  for (unsigned int istate = 0; istate < nstate; ++istate) {
150  cell_avg[istate] = 0;
151  }
152 
153  std::array<std::vector<real>, nstate> soln_at_q_neigh;
154 
155  // Interpolate solution dofs to quadrature pts
156  for (int istate = 0; istate < nstate; istate++) {
157  soln_at_q_neigh[istate].resize(n_quad_pts);
158  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q_neigh[istate],
159  soln_basis.oneD_vol_operator);
160  }
161 
162  // Apply integral for solution cell average (dealii quadrature operates from [0,1])
163  for (unsigned int istate = 0; istate < nstate; ++istate) {
164  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
165  cell_avg[istate] += quad_weights[iquad]
166  * soln_at_q_neigh[istate][iquad];
167  }
168  }
169 
170  return cell_avg;
171 }
172 
173 template <int dim, int nstate, typename real>
175  dealii::LinearAlgebra::distributed::Vector<double>& solution,
176  const dealii::DoFHandler<dim>& dof_handler,
177  const dealii::hp::FECollection<dim>& fe_collection,
178  const dealii::hp::QCollection<dim>& volume_quadrature_collection,
179  const unsigned int grid_degree,
180  const unsigned int max_degree,
181  const dealii::hp::FECollection<1> oneD_fe_collection_1state,
182  dealii::hp::QCollection<1> oneD_quadrature_collection)
183 {
184  double h = this->all_parameters->limiter_param.max_delta_x;
185 
186  std::array<real, nstate> M;
187  for (unsigned int istate = 0; istate < nstate; ++istate) {
189  }
190 
191  //create 1D solution polynomial basis functions and corresponding projection operator
192  //to interpolate the solution to the quadrature nodes, and to project it back to the
193  //modal coefficients.
194  const unsigned int init_grid_degree = grid_degree;
195  //Constructor for the operators
196  OPERATOR::basis_functions<dim, 2 * dim, real> soln_basis(1, max_degree, init_grid_degree);
197  OPERATOR::vol_projection_operator<dim, 2 * dim, real> soln_basis_projection_oper(1, max_degree, init_grid_degree);
198 
199 
200  //build the oneD operator to perform interpolation/projection
201  soln_basis.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]);
202  soln_basis_projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]);
203 
204  for (auto soln_cell : dof_handler.active_cell_iterators()) {
205  if (!soln_cell->is_locally_owned()) continue;
206 
207  std::array<real, nstate> prev_cell_avg;
208  std::array<real, nstate> next_cell_avg;
209 
210  // Initialize all cell_avg arrays to zero
211  for (unsigned int istate = 0; istate < nstate; ++istate) {
212  prev_cell_avg[istate] = 0;
213  next_cell_avg[istate] = 0;
214  }
215 
216  for (const auto face_no : soln_cell->face_indices()) {
217  if (soln_cell->neighbor(face_no).state() != dealii::IteratorState::valid) continue;
218 
219  std::vector<dealii::types::global_dof_index> neigh_dofs_indices;
220  // Current reference element related to this physical cell
221  auto neigh = soln_cell->neighbor(face_no);
222  const int i_fele = soln_cell->active_fe_index();
223  const dealii::FESystem<dim, dim>& neigh_fe_ref = fe_collection[i_fele];
224  const int poly_degree = neigh_fe_ref.tensor_degree();
225 
226  const unsigned int n_dofs_neigh_cell = neigh_fe_ref.n_dofs_per_cell();
227  // Obtain the mapping from local dof indices to global dof indices
228  neigh_dofs_indices.resize(n_dofs_neigh_cell);
229  neigh->get_dof_indices(neigh_dofs_indices);
230 
231  std::array<real, nstate> neigh_cell_avg = get_neighbour_cell_avg(solution, fe_collection, volume_quadrature_collection, soln_basis,
232  poly_degree, neigh_dofs_indices, n_dofs_neigh_cell);
233 
234  if (face_no == 0) {
235  prev_cell_avg = neigh_cell_avg;
236  }
237  else if (face_no == 1) {
238  next_cell_avg = neigh_cell_avg;
239  }
240  }
241 
242  std::vector<dealii::types::global_dof_index> current_dofs_indices;
243  // Current reference element related to this physical cell
244  const int i_fele = soln_cell->active_fe_index();
245  const dealii::FESystem<dim, dim>& current_fe_ref = fe_collection[i_fele];
246  const int poly_degree = current_fe_ref.tensor_degree();
247 
248  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
249  // Obtain the mapping from local dof indices to global dof indices
250  current_dofs_indices.resize(n_dofs_curr_cell);
251  soln_cell->get_dof_indices(current_dofs_indices);
252 
253  // Extract the local solution dofs in the cell from the global solution dofs
254  std::array<std::vector<real>, nstate> soln_coeff;
255  const unsigned int n_shape_fns = n_dofs_curr_cell / nstate;
256 
257  for (unsigned int istate = 0; istate < nstate; ++istate) {
258  soln_coeff[istate].resize(n_shape_fns);
259  }
260 
261  // Allocate soln_coeff
262  for (unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof) {
263  const unsigned int istate = fe_collection[poly_degree].system_to_component_index(idof).first;
264  const unsigned int ishape = fe_collection[poly_degree].system_to_component_index(idof).second;
265  soln_coeff[istate][ishape] = solution[current_dofs_indices[idof]];
266  }
267 
268 
269  const unsigned int n_quad_pts = volume_quadrature_collection[poly_degree].size();
270  const std::vector<real>& quad_weights = volume_quadrature_collection[poly_degree].get_weights();
271 
272  std::array<std::vector<real>, nstate> soln_at_q;
273 
274  // Interpolate solution dofs to quadrature pts.
275  for (int istate = 0; istate < nstate; istate++) {
276  soln_at_q[istate].resize(n_quad_pts);
277  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q[istate],
278  soln_basis.oneD_vol_operator);
279  }
280 
281  std::array<real, nstate> soln_cell_avg = get_soln_cell_avg(soln_at_q, n_quad_pts, quad_weights);
282 
283  std::array<std::vector<real>, nstate> soln_at_q_lim = limit_cell(soln_at_q, n_quad_pts, prev_cell_avg, soln_cell_avg, next_cell_avg, M, h);
284 
285  // Project solution at quadrature points to dofs.
286  for (int istate = 0; istate < nstate; istate++) {
287  soln_basis_projection_oper.matrix_vector_mult_1D(soln_at_q_lim[istate], soln_coeff[istate],
288  soln_basis_projection_oper.oneD_vol_operator);
289  }
290 
291  // Write limited solution dofs to the global solution vector.
292  for (int istate = 0; istate < nstate; istate++) {
293  for (unsigned int ishape = 0; ishape < n_shape_fns; ++ishape) {
294  const unsigned int idof = istate * n_shape_fns + ishape;
295  solution[current_dofs_indices[idof]] = soln_coeff[istate][ishape];
296  }
297  }
298  }
299 }
300 
301 #if PHILIP_DIM==1
308 #endif
309 } // PHiLiP namespace
void build_1D_volume_operator(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Assembles the one dimensional operator.
Definition: operators.cpp:1082
LimiterParam limiter_param
Contains parameters for limiter.
Base Class for bound preserving limiters templated on state.
void build_1D_volume_operator(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Assembles the one dimensional operator.
Definition: operators.cpp:1732
double max_delta_x
Maximum delta_x for TVB Limiter.
TVBLimiter(const Parameters::AllParameters *const parameters_input)
Constructor.
Definition: tvb_limiter.cpp:11
void limit(dealii::LinearAlgebra::distributed::Vector< double > &solution, const dealii::DoFHandler< dim > &dof_handler, const dealii::hp::FECollection< dim > &fe_collection, const dealii::hp::QCollection< dim > &volume_quadrature_collection, const unsigned int grid_degree, const unsigned int max_degree, const dealii::hp::FECollection< 1 > oneD_fe_collection_1state, const dealii::hp::QCollection< 1 > oneD_quadrature_collection)
real apply_modified_minmod(const double a_state, const double M_state, const double h, const double diff_next_state, const double diff_prev_state, const double cell_avg_state, const bool left_face)
Function to apply modified_minmod using Thm3.7 in Chen, Shu 2017.
Definition: tvb_limiter.cpp:16
const int nstate
Number of states.
Files for the baseline physics.
Definition: ADTypes.hpp:10
std::array< std::vector< real >, nstate > limit_cell(std::array< std::vector< real >, nstate > soln_at_q, const unsigned int n_quad_pts, const std::array< real, nstate > prev_cell_avg, const std::array< real, nstate > soln_cell_avg, const std::array< real, nstate > next_cell_avg, const std::array< real, nstate > M, const double h)
Function to limit cell - apply minmod function, obtain theta (linear scaling value) and apply limiter...
Definition: tvb_limiter.cpp:59
Main parameter class that contains the various other sub-parameter classes.
std::array< real, nstate > get_soln_cell_avg(const std::array< std::vector< real >, nstate > &soln_at_q, const unsigned int n_quad_pts, const std::vector< real > &quad_weights)
Function to obtain the solution cell average.
Class for implementation of a TVD/TVB limiter derived from BoundPreservingLimiterState class...
Definition: tvb_limiter.h:15
std::array< real, nstate > get_neighbour_cell_avg(const dealii::LinearAlgebra::distributed::Vector< double > &solution, const dealii::hp::FECollection< dim > &fe_collection, const dealii::hp::QCollection< dim > &volume_quadrature_collection, OPERATOR::basis_functions< dim, 2 *dim, real > soln_basis, const int poly_degree, const std::vector< dealii::types::global_dof_index > &neigh_dofs_indices, const unsigned int n_dofs_neigh_cell)
Function to obtain the neighbour cell average.
dealii::FullMatrix< double > oneD_vol_operator
Stores the one dimensional volume operator.
Definition: operators.h:355
dealii::Tensor< 1, 4, double > tuning_parameter_for_each_state
Tuning parameters for TVB Limiter.
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 Parameters::AllParameters *const all_parameters
Pointer to parameters object.
Projection operator corresponding to basis functions onto M-norm (L2).
Definition: operators.h:694