[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 {
117  // If use_tvb_limiter is true, apply TVB limiter before applying maximum-principle-satisfying limiter
118  if (this->all_parameters->limiter_param.use_tvb_limiter == true)
119  this->tvbLimiter->limit(solution, dof_handler, fe_collection, volume_quadrature_collection, grid_degree, max_degree, oneD_fe_collection_1state, oneD_quadrature_collection);
120 
121  //create 1D solution polynomial basis functions and corresponding projection operator
122  //to interpolate the solution to the quadrature nodes, and to project it back to the
123  //modal coefficients.
124  const unsigned int init_grid_degree = grid_degree;
125  //Constructor for the operators
126  OPERATOR::basis_functions<dim, 2 * dim, real> soln_basis(1, max_degree, init_grid_degree);
127  OPERATOR::vol_projection_operator<dim, 2 * dim, real> soln_basis_projection_oper(1, max_degree, init_grid_degree);
128 
129 
130  // Build the oneD operator to perform interpolation/projection
131  soln_basis.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]);
132  soln_basis_projection_oper.build_1D_volume_operator(oneD_fe_collection_1state[max_degree], oneD_quadrature_collection[max_degree]);
133 
134  // Obtain the global max and min (ie. max and min of the initial solution)
135  if (global_max.empty() && global_min.empty())
136  get_global_max_and_min_of_solution(solution, dof_handler, fe_collection);
137 
138  for (auto soln_cell : dof_handler.active_cell_iterators()) {
139  if (!soln_cell->is_locally_owned()) continue;
140 
141  std::vector<dealii::types::global_dof_index> current_dofs_indices;
142  // Current reference element related to this physical cell
143  const int i_fele = soln_cell->active_fe_index();
144  const dealii::FESystem<dim, dim>& current_fe_ref = fe_collection[i_fele];
145  const int poly_degree = current_fe_ref.tensor_degree();
146 
147  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
148 
149  // Obtain the mapping from local dof indices to global dof indices
150  current_dofs_indices.resize(n_dofs_curr_cell);
151  soln_cell->get_dof_indices(current_dofs_indices);
152 
153  // Extract the local solution dofs in the cell from the global solution dofs
154  std::array<std::vector<real>, nstate> soln_coeff;
155  const unsigned int n_shape_fns = n_dofs_curr_cell / nstate;
156  std::array<real, nstate> local_max;
157  std::array<real, nstate> local_min;
158  for (unsigned int istate = 0; istate < nstate; ++istate) {
159  local_max[istate] = -1e9;
160  local_min[istate] = 1e9;
161 
162  soln_coeff[istate].resize(n_shape_fns);
163  }
164 
165  // Allocate solution dofs and set local max and min
166  for (unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof) {
167  const unsigned int istate = fe_collection[poly_degree].system_to_component_index(idof).first;
168  const unsigned int ishape = fe_collection[poly_degree].system_to_component_index(idof).second;
169  soln_coeff[istate][ishape] = solution[current_dofs_indices[idof]];
170 
171  if (soln_coeff[istate][ishape] > local_max[istate])
172  local_max[istate] = soln_coeff[istate][ishape];
173 
174  if (soln_coeff[istate][ishape] < local_min[istate])
175  local_min[istate] = soln_coeff[istate][ishape];
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::vector<real>, nstate> soln_at_q;
182 
183  // Interpolate solution dofs to quadrature pts.
184  for (int istate = 0; istate < nstate; istate++) {
185  soln_at_q[istate].resize(n_quad_pts);
186  soln_basis.matrix_vector_mult_1D(soln_coeff[istate], soln_at_q[istate], soln_basis.oneD_vol_operator);
187  }
188 
189  // Obtain solution cell average
190  std::array<real, nstate> soln_cell_avg = get_soln_cell_avg(soln_at_q, n_quad_pts, quad_weights);
191 
192  // Obtain theta value
193  std::array<real, nstate> theta; // Value used to linearly scale solution
194  for (unsigned int istate = 0; istate < nstate; ++istate) {
195  real maxscale = 1.0;
196  real minscale = 1.0;
197 
198  if (local_max[istate] - soln_cell_avg[istate] != 0)
199  maxscale = local_max[istate] - soln_cell_avg[istate];
200  if (local_min[istate] - soln_cell_avg[istate] != 0)
201  minscale = local_min[istate] - soln_cell_avg[istate];
202 
203  theta[istate] = std::min({ abs((global_max[istate] - soln_cell_avg[istate]) / maxscale),
204  abs((global_min[istate] - soln_cell_avg[istate]) / minscale), 1.0 });
205  }
206 
207  // Apply limiter on solution values at quadrature points
208  for (unsigned int istate = 0; istate < nstate; ++istate) {
209  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
210  soln_at_q[istate][iquad] = theta[istate] * (soln_at_q[istate][iquad] - soln_cell_avg[istate])
211  + soln_cell_avg[istate];
212  }
213  }
214 
215  // Project solution at quadrature points to dofs.
216  for (int istate = 0; istate < nstate; istate++) {
217  soln_basis_projection_oper.matrix_vector_mult_1D(soln_at_q[istate], soln_coeff[istate],
218  soln_basis_projection_oper.oneD_vol_operator);
219  }
220 
221  // Write limited solution back and verify that the strict maximum principle is satisfied
222  write_limited_solution(solution, soln_coeff, n_shape_fns, current_dofs_indices);
223  }
224 }
225 
232 } // 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.
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
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.
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)
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
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)
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
std::shared_ptr< BoundPreservingLimiter< dim, real > > tvbLimiter
Pointer to TVB limiter class (TVB limiter can be applied in conjunction with this limiter) ...