[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
maximum_principle_limiter.cpp
1 #include "maximum_principle_limiter.h"
2 #include "tvb_limiter.h"
3 
4 namespace PHiLiP {
5 /**********************************
6 *
7 * Maximum Principle Limiter Class
8 *
9 **********************************/
10 // Constructor
11 template <int dim, int nstate, typename real>
13  const Parameters::AllParameters* const parameters_input)
14  : BoundPreservingLimiterState<dim,nstate, real>::BoundPreservingLimiterState(parameters_input)
15 {
16  // Create pointer to TVB Limiter class if use_tvb_limiter==true && dim == 1
17  if (parameters_input->limiter_param.use_tvb_limiter) {
18  if (dim == 1) {
19  tvbLimiter = std::make_shared < TVBLimiter<dim, nstate, real> >(parameters_input);
20  }
21  else {
22  std::cout << "Error: Cannot create TVB limiter for dim > 1" << std::endl;
23  std::abort();
24  }
25  }
26 }
27 
28 template <int dim, int nstate, typename real>
30  const dealii::LinearAlgebra::distributed::Vector<double>& solution,
31  const dealii::DoFHandler<dim>& dof_handler,
32  const dealii::hp::FECollection<dim>& fe_collection)
33 {
34  for (auto soln_cell : dof_handler.active_cell_iterators()) {
35  if (!soln_cell->is_locally_owned()) continue;
36 
37  std::vector<dealii::types::global_dof_index> current_dofs_indices;
38  // Current reference element related to this physical cell
39  const int i_fele = soln_cell->active_fe_index();
40  const dealii::FESystem<dim, dim>& current_fe_ref = fe_collection[i_fele];
41  const int poly_degree = current_fe_ref.tensor_degree();
42 
43  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
44  // Obtain the mapping from local dof indices to global dof indices
45  current_dofs_indices.resize(n_dofs_curr_cell);
46  soln_cell->get_dof_indices(current_dofs_indices);
47 
48  // Extract the local solution dofs in the cell from the global solution dofs
49  if (global_max.size() < nstate && global_min.size() < nstate) {
50  for (unsigned int istate = 0; istate < nstate; ++istate) {
51  global_max.push_back(-1e9);
52  global_min.push_back(1e9);
53  }
54  }
55 
56  // Allocate solution dofs and set global max and min
57  std::array<std::vector<real>, nstate> soln_coeff;
58  const unsigned int n_shape_fns = n_dofs_curr_cell / nstate;
59  for (unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof) {
60  const unsigned int istate = fe_collection[poly_degree].system_to_component_index(idof).first;
61  const unsigned int ishape = fe_collection[poly_degree].system_to_component_index(idof).second;
62  if (ishape == 0) {
63  soln_coeff[istate].resize(n_shape_fns);
64  }
65  soln_coeff[istate][ishape] = solution[current_dofs_indices[idof]]; //
66  if (soln_coeff[istate][ishape] > global_max[istate])
67  global_max[istate] = soln_coeff[istate][ishape];
68  if (soln_coeff[istate][ishape] < global_min[istate])
69  global_min[istate] = soln_coeff[istate][ishape];
70  }
71  }
72 
73  // Print the obtained values for verification
74  for (unsigned int istate = 0; istate < nstate; ++istate) {
75  std::cout << std::fixed;
76  std::cout << std::setprecision(14);
77  std::cout << "global_max: " << global_max[istate] << " global_min: " << global_min[istate] << std::endl;
78  }
79 }
80 
81 template <int dim, int nstate, typename real>
83  dealii::LinearAlgebra::distributed::Vector<double>& solution,
84  const std::array<std::vector<real>, nstate>& soln_coeff,
85  const unsigned int n_shape_fns,
86  const std::vector<dealii::types::global_dof_index>& current_dofs_indices)
87 {
88  // Write limited solution back to global solution & verify that strict maximum principle is satisfied
89  for (int istate = 0; istate < nstate; istate++) {
90  for (unsigned int ishape = 0; ishape < n_shape_fns; ++ishape) {
91  const unsigned int idof = istate * n_shape_fns + ishape;
92  solution[current_dofs_indices[idof]] = soln_coeff[istate][ishape];
93 
94  if (solution[current_dofs_indices[idof]] > global_max[istate] + 1e-13) {
95  std::cout << "Error: Solution exceeds global maximum - Aborting... Value: " << solution[current_dofs_indices[idof]] << std::endl << std::flush;
96  std::abort();
97  }
98  if (solution[current_dofs_indices[idof]] < global_min[istate] - 1e-13) {
99  std::cout << "Error: Solution exceeds global minimum - Aborting... Value: " << solution[current_dofs_indices[idof]] << std::endl << std::flush;
100  std::abort();
101  }
102  }
103  }
104 }
105 
106 template <int dim, int nstate, typename real>
108  dealii::LinearAlgebra::distributed::Vector<double>& solution,
109  const dealii::DoFHandler<dim>& dof_handler,
110  const dealii::hp::FECollection<dim>& fe_collection,
111  const dealii::hp::QCollection<dim>& volume_quadrature_collection,
112  const unsigned int grid_degree,
113  const unsigned int max_degree,
114  const dealii::hp::FECollection<1> oneD_fe_collection_1state,
115  const dealii::hp::QCollection<1> oneD_quadrature_collection,
116  double dt)
117 {
118  // If use_tvb_limiter is true, apply TVB limiter before applying maximum-principle-satisfying limiter
119  if (this->all_parameters->limiter_param.use_tvb_limiter == true)
120  this->tvbLimiter->limit(solution, dof_handler, fe_collection, volume_quadrature_collection, grid_degree, max_degree, oneD_fe_collection_1state, oneD_quadrature_collection, dt);
121 
122  // Construct 1D Quad Points
123  const unsigned int init_grid_degree = grid_degree;
124  dealii::QGauss<1> oneD_quad_GL(max_degree + 1);
125  dealii::QGaussLobatto<1> oneD_quad_GLL(max_degree + 1);
126 
127  // Constructor for the operators
128  OPERATOR::basis_functions<dim, 2 * dim, real> soln_basis_GLL(1, max_degree, init_grid_degree);
129  soln_basis_GLL.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quad_GLL);
130  OPERATOR::basis_functions<dim, 2 * dim, real> soln_basis_GL(1, max_degree, init_grid_degree);
131  soln_basis_GL.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quad_GL);
132 
133  // Obtain the global max and min (ie. max and min of the initial solution)
134  if (global_max.empty() && global_min.empty())
135  get_global_max_and_min_of_solution(solution, dof_handler, fe_collection);
136 
137  for (auto soln_cell : dof_handler.active_cell_iterators()) {
138  if (!soln_cell->is_locally_owned()) continue;
139 
140  std::vector<dealii::types::global_dof_index> current_dofs_indices;
141  // Current reference element related to this physical cell
142  const int i_fele = soln_cell->active_fe_index();
143  const dealii::FESystem<dim, dim>& current_fe_ref = fe_collection[i_fele];
144  const int poly_degree = current_fe_ref.tensor_degree();
145 
146  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
147 
148  // Obtain the mapping from local dof indices to global dof indices
149  current_dofs_indices.resize(n_dofs_curr_cell);
150  soln_cell->get_dof_indices(current_dofs_indices);
151 
152  // Extract the local solution dofs in the cell from the global solution dofs
153  std::array<std::vector<real>, nstate> soln_coeff;
154  const unsigned int n_shape_fns = n_dofs_curr_cell / nstate;
155  std::array<real, nstate> local_max;
156  std::array<real, nstate> local_min;
157  for (unsigned int istate = 0; istate < nstate; ++istate) {
158  local_max[istate] = -1e9;
159  local_min[istate] = 1e9;
160 
161  soln_coeff[istate].resize(n_shape_fns);
162  }
163 
164  // Allocate solution dofs and set local max and min
165  for (unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof) {
166  const unsigned int istate = fe_collection[poly_degree].system_to_component_index(idof).first;
167  const unsigned int ishape = fe_collection[poly_degree].system_to_component_index(idof).second;
168  soln_coeff[istate][ishape] = solution[current_dofs_indices[idof]];
169 
170  if (soln_coeff[istate][ishape] > local_max[istate])
171  local_max[istate] = soln_coeff[istate][ishape];
172 
173  if (soln_coeff[istate][ishape] < local_min[istate])
174  local_min[istate] = soln_coeff[istate][ishape];
175  }
176 
177 
178  const unsigned int n_quad_pts = volume_quadrature_collection[poly_degree].size();
179  const std::vector<real>& quad_weights = volume_quadrature_collection[poly_degree].get_weights();
180 
181  std::array<std::array<std::vector<real>, nstate>, dim> soln_at_q;
182  std::array<std::vector<real>, nstate> soln_at_q_dim;
183 
184  // Interpolate solution dofs to quadrature pts.
185  for(unsigned int idim = 0; idim < dim; idim++) {
186  for (int istate = 0; istate < nstate; istate++) {
187  soln_at_q_dim[istate].resize(n_quad_pts);
188 
189  if(idim == 0) {
190  soln_basis_GLL.matrix_vector_mult(soln_coeff[istate], soln_at_q_dim[istate],
191  soln_basis_GLL.oneD_vol_operator, soln_basis_GL.oneD_vol_operator, soln_basis_GL.oneD_vol_operator);
192  }
193 
194  if(idim == 1) {
195  soln_basis_GLL.matrix_vector_mult(soln_coeff[istate], soln_at_q_dim[istate],
196  soln_basis_GL.oneD_vol_operator, soln_basis_GLL.oneD_vol_operator, soln_basis_GL.oneD_vol_operator);
197  }
198 
199  if(idim == 2) {
200  soln_basis_GLL.matrix_vector_mult(soln_coeff[istate], soln_at_q_dim[istate],
201  soln_basis_GL.oneD_vol_operator, soln_basis_GL.oneD_vol_operator, soln_basis_GLL.oneD_vol_operator);
202  }
203  }
204  soln_at_q[idim] = soln_at_q_dim;
205  }
206 
207  for (unsigned int idim = 0; idim < dim; ++idim) {
208  for (unsigned int istate = 0; istate < nstate; ++istate) {
209  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
210  if(soln_at_q[idim][istate][iquad] > local_max[istate]) {
211  local_max[istate] = soln_at_q[idim][istate][iquad];
212  }
213  if(soln_at_q[idim][istate][iquad] < local_min[istate]) {
214  local_min[istate] = soln_at_q[idim][istate][iquad];
215  }
216  }
217  }
218  }
219 
220  // Obtain solution cell average
221  std::array<real, nstate> soln_cell_avg = get_soln_cell_avg(soln_coeff, n_quad_pts, quad_weights);
222 
223  // Obtain theta value
224  std::array<real, nstate> theta; // Value used to linearly scale solution
225  for (unsigned int istate = 0; istate < nstate; ++istate) {
226  real maxscale = 1.0;
227  real minscale = 1.0;
228 
229  if (local_max[istate] - soln_cell_avg[istate] != 0)
230  maxscale = local_max[istate] - soln_cell_avg[istate];
231  if (local_min[istate] - soln_cell_avg[istate] != 0)
232  minscale = local_min[istate] - soln_cell_avg[istate];
233 
234  theta[istate] = std::min({ abs((global_max[istate] - soln_cell_avg[istate]) / maxscale),
235  abs((global_min[istate] - soln_cell_avg[istate]) / minscale), 1.0 });
236  }
237 
238  // Apply limiter on solution values at quadrature points
239  for (unsigned int istate = 0; istate < nstate; ++istate) {
240  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
241  soln_coeff[istate][iquad] = theta[istate] * (soln_coeff[istate][iquad] - soln_cell_avg[istate])
242  + soln_cell_avg[istate];
243  }
244  }
245 
246  // Write limited solution back and verify that the strict maximum principle is satisfied
247  write_limited_solution(solution, soln_coeff, n_shape_fns, current_dofs_indices);
248  }
249 }
250 
257 } // 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.
std::vector< real > global_max
Maximum of initial solution for each state in domain.
void matrix_vector_mult(const std::vector< real > &input_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis_x, const dealii::FullMatrix< double > &basis_y, const dealii::FullMatrix< double > &basis_z, const bool adding=false, const double factor=1.0) override
Computes a matrix-vector product using sum-factorization. Pass the one-dimensional basis...
Definition: operators.cpp:196
Base Class for bound preserving limiters templated on state.
Class for implementation of Maximum-Principle-Satisfying limiter derived from BoundPreservingLimiterS...
const int nstate
Number of states.
Files for the baseline physics.
Definition: ADTypes.hpp:10
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.
MaximumPrincipleLimiter(const Parameters::AllParameters *const parameters_input)
Constructor.
std::vector< real > global_min
Minimum of initial solution for each state in domain.
void get_global_max_and_min_of_solution(const dealii::LinearAlgebra::distributed::Vector< double > &solution, const dealii::DoFHandler< dim > &dof_handler, const dealii::hp::FECollection< dim > &fe_collection)
Function to obtain the maximum and minimum of the initial solution for each state.
dealii::FullMatrix< double > oneD_vol_operator
Stores the one dimensional volume operator.
Definition: operators.h:355
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, double dt) override
bool use_tvb_limiter
Flag for applying TVB Limiter.
void write_limited_solution(dealii::LinearAlgebra::distributed::Vector< double > &solution, const std::array< std::vector< real >, nstate > &soln_coeff, const unsigned int n_shape_fns, const std::vector< dealii::types::global_dof_index > &current_dofs_indices)
const Parameters::AllParameters *const all_parameters
Pointer to parameters object.
std::shared_ptr< BoundPreservingLimiter< dim, real > > tvbLimiter
Pointer to TVB limiter class (TVB limiter can be applied in conjunction with this limiter) ...