[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
mesh_error_estimate.cpp
1 #include "mesh_error_estimate.h"
2 
3 #include <Epetra_RowMatrixTransposer.h>
4 #include <deal.II/distributed/shared_tria.h>
5 #include <deal.II/distributed/solution_transfer.h>
6 #include <deal.II/distributed/tria.h>
7 #include <deal.II/dofs/dof_tools.h>
8 #include <deal.II/fe/fe_q.h>
9 #include <deal.II/fe/fe_values.h>
10 #include <deal.II/grid/tria.h>
11 #include <deal.II/lac/la_parallel_vector.h>
12 #include <deal.II/numerics/data_out.h>
13 #include <deal.II/numerics/vector_tools.h>
14 
15 #include <fstream>
16 #include <iostream>
17 #include <vector>
18 
19 #include "dg/dg_base.hpp"
20 #include "functional/functional.h"
21 #include "linear_solver/linear_solver.h"
22 #include "parameters/all_parameters.h"
23 #include "physics/physics.h"
24 #include "post_processor/physics_post_processor.h"
25 
26 namespace PHiLiP {
27 
28 template <int dim, typename real, typename MeshType>
30  : dg(dg_input)
31  {}
32 
33 template <int dim, typename real, typename MeshType>
35  : MeshErrorEstimateBase<dim, real, MeshType> (dg_input)
36  {}
37 
38 template <int dim, typename real, typename MeshType>
40 {
41  std::vector<dealii::types::global_dof_index> dofs_indices;
42  dealii::Vector<real> cellwise_errors (this->dg->high_order_grid->triangulation->n_active_cells());
43  this->dg->assemble_residual();
44 
45  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
46  {
47  if(!cell->is_locally_owned()) continue;
48 
49  const int i_fele = cell->active_fe_index();
50  const dealii::FESystem<dim,dim> &fe_ref = this->dg->fe_collection[i_fele];
51  const unsigned int n_dofs_cell = fe_ref.n_dofs_per_cell();
52  dofs_indices.resize(n_dofs_cell);
53  cell->get_dof_indices (dofs_indices);
54  real max_residual = 0;
55  for (unsigned int idof = 0; idof < n_dofs_cell; ++idof)
56  {
57  const unsigned int index = dofs_indices[idof];
58  const real res = std::abs(this->dg->right_hand_side[index]);
59  if (res > max_residual)
60  max_residual = res;
61  }
62  cellwise_errors[cell->active_cell_index()] = max_residual;
63  }
64 
65  return cellwise_errors;
66 }
67 
68 // constructor
69 template <int dim, int nstate, typename real, typename MeshType>
71  : MeshErrorEstimateBase<dim,real,MeshType> (dg_input)
72  , solution_coarse(this->dg->solution)
73  , solution_refinement_state(SolutionRefinementStateEnum::coarse)
74  , mpi_communicator(MPI_COMM_WORLD)
75  , pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0)
76 {
77  Assert(this->dg->triangulation->get_mesh_smoothing() == typename dealii::Triangulation<dim>::MeshSmoothing(dealii::Triangulation<dim>::none),
78  dealii::ExcMessage("Mesh smoothing might h-refine cells while computing the dual weighted residual."));
79  // storing the original FE degree distribution
80  coarse_fe_index.reinit(this->dg->triangulation->n_active_cells());
81 
82  // create functional
83  functional = FunctionalFactory<dim,nstate,real,MeshType>::create_Functional(this->dg->all_parameters->functional_param, this->dg);
84 
85  // looping over the cells
86  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
87  {
88  if(cell->is_locally_owned())
89  {
90  coarse_fe_index[cell->active_cell_index()] = cell->active_fe_index();
91  }
92  }
93 }
94 
95 template <int dim, int nstate, typename real, typename MeshType>
97 {
98  dealii::Vector<real> cellwise_errors = compute_cellwise_errors();
99  real error_sum = cellwise_errors.l1_norm();
100  return dealii::Utilities::MPI::sum(error_sum, mpi_communicator);
101 }
102 
103 template <int dim, int nstate, typename real, typename MeshType>
105 {
106  dealii::Vector<real> cellwise_errors(this->dg->triangulation->n_active_cells());
107  reinit();
108  convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum::fine);
109  pcout<<"Computing fine grid adjoint..."<<std::endl;
111  pcout<<"Computing dual weighted residual..."<<std::endl;
112  cellwise_errors = dual_weighted_residual();
113  convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum::coarse);
114 
115  pcout<<"Done computing the goal oriented error indicator."<<std::endl;
116  return cellwise_errors;
117 }
118 
119 
120 template <int dim, int nstate, typename real, typename MeshType>
122 {
123  // reinitilizing all variables after triangulation in the constructor
124  solution_coarse = this->dg->solution;
125  solution_refinement_state = SolutionRefinementStateEnum::coarse;
126 
127  // storing the original FE degree distribution
128  coarse_fe_index.reinit(this->dg->triangulation->n_active_cells());
129 
130  // looping over the cells
131  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
132  {
133  if(cell->is_locally_owned())
134  {
135  coarse_fe_index[cell->active_cell_index()] = cell->active_fe_index();
136  }
137  }
138 
139  // for remaining, clear the values
140  derivative_functional_wrt_solution_fine = dealii::LinearAlgebra::distributed::Vector<real>();
141  derivative_functional_wrt_solution_coarse = dealii::LinearAlgebra::distributed::Vector<real>();
142  adjoint_fine = dealii::LinearAlgebra::distributed::Vector<real>();
143  adjoint_coarse = dealii::LinearAlgebra::distributed::Vector<real>();
144 
145  dual_weighted_residual_fine = dealii::Vector<real>();
146 }
147 
148 template <int dim, int nstate, typename real, typename MeshType>
150 {
151  // checks if conversion is needed
152  if(solution_refinement_state == required_refinement_state)
153  {
154  return;
155  }
156  // calls corresponding function for state conversions
157  else if(solution_refinement_state == SolutionRefinementStateEnum::coarse && required_refinement_state == SolutionRefinementStateEnum::fine)
158  {
159  coarse_to_fine();
160  }
161 
162  else if(solution_refinement_state == SolutionRefinementStateEnum::fine && required_refinement_state == SolutionRefinementStateEnum::coarse)
163  {
164  fine_to_coarse();
165  }
166  else
167  {
168  pcout<<"Invalid state. Aborting.."<<std::endl;
169  std::abort();
170  }
171 }
172 
173 template <int dim, int nstate, typename real, typename MeshType>
175 {
176  if (this->dg->get_max_fe_degree() >= this->dg->max_degree)
177  {
178  pcout<<"Polynomial degree of DG will exceed the maximum allowable after refinement. Update max_degree in dg"<<std::endl;
179  std::abort();
180  }
181 
182  [[maybe_unused]] unsigned int no_of_cells_before_changing_p = this->dg->triangulation->n_active_cells(); // used in debug mode (in assert).
183 
184  dealii::IndexSet locally_owned_dofs, locally_relevant_dofs;
185  locally_owned_dofs = this->dg->dof_handler.locally_owned_dofs();
186  dealii::DoFTools::extract_locally_relevant_dofs(this->dg->dof_handler, locally_relevant_dofs);
187 
188  solution_coarse.update_ghost_values();
189 
190  // Solution Transfer to fine grid
191  using VectorType = typename dealii::LinearAlgebra::distributed::Vector<double>;
192  using DoFHandlerType = typename dealii::DoFHandler<dim>;
193  using SolutionTransfer = typename MeshTypeHelper<MeshType>::template SolutionTransfer<dim,VectorType,DoFHandlerType>;
194 
195  SolutionTransfer solution_transfer(this->dg->dof_handler);
196  solution_transfer.prepare_for_coarsening_and_refinement(solution_coarse);
197 
198  this->dg->high_order_grid->prepare_for_coarsening_and_refinement();
199 
200  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
201  {
202  if (cell->is_locally_owned())
203  {
204  cell->set_future_fe_index(cell->active_fe_index()+1);
205  }
206  }
207 
208  this->dg->triangulation->execute_coarsening_and_refinement();
209  this->dg->high_order_grid->execute_coarsening_and_refinement();
210 
211  this->dg->allocate_system();
212  this->dg->solution.zero_out_ghosts();
213 
214  if constexpr (std::is_same_v<typename dealii::SolutionTransfer<dim,VectorType,DoFHandlerType>,
215  decltype(solution_transfer)>) {
216  solution_transfer.interpolate(solution_coarse, this->dg->solution);
217  } else {
218  solution_transfer.interpolate(this->dg->solution);
219  }
220 
221  this->dg->solution.update_ghost_values();
222 
223  [[maybe_unused]] unsigned int no_of_cells_after_changing_p = this->dg->triangulation->n_active_cells(); // It's used when compiled in debug mode (in assert).
224 
225  AssertDimension(no_of_cells_before_changing_p, no_of_cells_after_changing_p);
226 
227  solution_refinement_state = SolutionRefinementStateEnum::fine;
228 }
229 
230 template <int dim, int nstate, typename real, typename MeshType>
232 {
233  [[maybe_unused]] unsigned int no_of_cells_before_changing_p = this->dg->triangulation->n_active_cells(); // Used in assert (i.e remains unused in Release mode).
234  this->dg->high_order_grid->prepare_for_coarsening_and_refinement();
235 
236  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
237  {
238  if (cell->is_locally_owned())
239  {
240  cell->set_future_fe_index(coarse_fe_index[cell->active_cell_index()]);
241  }
242  }
243 
244  this->dg->triangulation->execute_coarsening_and_refinement();
245  this->dg->high_order_grid->execute_coarsening_and_refinement();
246 
247  this->dg->allocate_system();
248  this->dg->solution.zero_out_ghosts();
249 
250  this->dg->solution = solution_coarse;
251 
252  [[maybe_unused]] unsigned int no_of_cells_after_changing_p = this->dg->triangulation->n_active_cells(); // Used when compiled in debug mode (in assert).
253 
254  AssertDimension(no_of_cells_before_changing_p, no_of_cells_after_changing_p);
255 
256  solution_refinement_state = SolutionRefinementStateEnum::coarse;
257 }
258 
259 template <int dim, int nstate, typename real, typename MeshType>
260 dealii::LinearAlgebra::distributed::Vector<real> DualWeightedResidualError<dim, nstate, real, MeshType>::fine_grid_adjoint()
261 {
262  convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum::fine);
263 
265 
266  return adjoint_fine;
267 }
268 
269 template <int dim, int nstate, typename real, typename MeshType>
270 dealii::LinearAlgebra::distributed::Vector<real> DualWeightedResidualError<dim, nstate, real, MeshType>::coarse_grid_adjoint()
271 {
272  convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum::coarse);
273 
275 
276  return adjoint_coarse;
277 }
278 
279 template <int dim, int nstate, typename real, typename MeshType>
280 dealii::LinearAlgebra::distributed::Vector<real> DualWeightedResidualError<dim, nstate, real, MeshType>
281 ::compute_adjoint(dealii::LinearAlgebra::distributed::Vector<real> &derivative_functional_wrt_solution,
282  dealii::LinearAlgebra::distributed::Vector<real> &adjoint_variable)
283 {
284  derivative_functional_wrt_solution.reinit(this->dg->solution);
285  adjoint_variable.reinit(this->dg->solution);
286 
287  const bool compute_derivative_functional_wrt_solution = true, compute_derivative_functional_wrt_grid_dofs = false;
288  const real functional_value = functional->evaluate_functional(compute_derivative_functional_wrt_solution, compute_derivative_functional_wrt_grid_dofs);
289  (void) functional_value;
290  derivative_functional_wrt_solution = functional->dIdw;
291  derivative_functional_wrt_solution.update_ghost_values();
292 
293 
294  this->dg->assemble_residual(true);
295 
296  AssertDimension(derivative_functional_wrt_solution.size(), adjoint_variable.size());
297  AssertDimension(this->dg->system_matrix_transpose.n(), adjoint_variable.size());
298 
299  solve_linear(this->dg->system_matrix_transpose, derivative_functional_wrt_solution, adjoint_variable, this->dg->all_parameters->linear_solver_param);
300  adjoint_variable *= -1.0;
301 
302  adjoint_variable.compress(dealii::VectorOperation::add);
303  adjoint_variable.update_ghost_values();
304 
305  return adjoint_variable;
306 }
307 
308 template <int dim, int nstate, typename real, typename MeshType>
310 {
311  convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum::fine);
312 
313  // allocate
314  dual_weighted_residual_fine.reinit(this->dg->triangulation->n_active_cells());
315 
316  const unsigned int max_dofs_per_cell = this->dg->dof_handler.get_fe_collection().max_dofs_per_cell();
317  std::vector<dealii::types::global_dof_index> current_dofs_indices(max_dofs_per_cell);
318 
319  // compute the error indicator cell-wise by taking the dot product over the DOFs with the residual vector
320  for (const auto &cell : this->dg->dof_handler.active_cell_iterators())
321  {
322  if(!cell->is_locally_owned()) continue;
323 
324  const unsigned int fe_index_curr_cell = cell->active_fe_index();
325  const dealii::FESystem<dim,dim> &current_fe_ref = this->dg->fe_collection[fe_index_curr_cell];
326  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
327 
328  current_dofs_indices.resize(n_dofs_curr_cell);
329  cell->get_dof_indices(current_dofs_indices);
330 
331  real dwr_cell = 0;
332  for(unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof)
333  {
334  dwr_cell += this->dg->right_hand_side[current_dofs_indices[idof]]*adjoint_fine[current_dofs_indices[idof]];
335  }
336 
337  dual_weighted_residual_fine[cell->active_cell_index()] = std::abs(dwr_cell);
338  }
339 
341 }
342 
343 template <int dim, int nstate, typename real, typename MeshType>
345 {
346  dealii::DataOut<dim, dealii::DoFHandler<dim>> data_out;
347  data_out.attach_dof_handler(this->dg->dof_handler);
348 
349  const std::unique_ptr< dealii::DataPostprocessor<dim> > post_processor = Postprocess::PostprocessorFactory<dim>::create_Postprocessor(this->dg->all_parameters);
350  data_out.add_data_vector(this->dg->solution, *post_processor);
351 
352  dealii::Vector<float> subdomain(this->dg->triangulation->n_active_cells());
353  for (unsigned int i = 0; i < subdomain.size(); ++i)
354  {
355  subdomain(i) = this->dg->triangulation->locally_owned_subdomain();
356  }
357  data_out.add_data_vector(subdomain, "subdomain", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
358 
359  // Output the polynomial degree in each cell
360  std::vector<unsigned int> active_fe_indices;
361  this->dg->dof_handler.get_active_fe_indices(active_fe_indices);
362  dealii::Vector<double> active_fe_indices_dealiivector(active_fe_indices.begin(), active_fe_indices.end());
363  dealii::Vector<double> cell_poly_degree = active_fe_indices_dealiivector;
364 
365  data_out.add_data_vector(active_fe_indices_dealiivector, "PolynomialDegree", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
366 
367  std::vector<std::string> residual_names;
368  for(int s=0;s<nstate;++s)
369  {
370  std::string varname = "residual" + dealii::Utilities::int_to_string(s,1);
371  residual_names.push_back(varname);
372  }
373 
374  data_out.add_data_vector(this->dg->right_hand_side, residual_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
375 
376  // set names of data to be output in the vtu file.
377  std::vector<std::string> derivative_functional_wrt_solution_names;
378  for(int s=0;s<nstate;++s)
379  {
380  std::string varname = "derivative_functional_wrt_solution" + dealii::Utilities::int_to_string(s,1);
381  derivative_functional_wrt_solution_names.push_back(varname);
382  }
383 
384  std::vector<std::string> adjoint_names;
385  for(int s=0;s<nstate;++s)
386  {
387  std::string varname = "psi" + dealii::Utilities::int_to_string(s,1);
388  adjoint_names.push_back(varname);
389  }
390 
391  // add the data structures specific to this class, check if currently fine or coarse
392  if(solution_refinement_state == SolutionRefinementStateEnum::fine) {
393  data_out.add_data_vector(derivative_functional_wrt_solution_fine, derivative_functional_wrt_solution_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
394  data_out.add_data_vector(adjoint_fine, adjoint_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
395 
396  data_out.add_data_vector(dual_weighted_residual_fine, "DWR", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
397  } else if(solution_refinement_state == SolutionRefinementStateEnum::coarse) {
398  data_out.add_data_vector(derivative_functional_wrt_solution_coarse, derivative_functional_wrt_solution_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
399  data_out.add_data_vector(adjoint_coarse, adjoint_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
400  }
401 
402  const int iproc = dealii::Utilities::MPI::this_mpi_process(mpi_communicator);
403  //data_out.build_patches (mapping_collection[mapping_collection.size()-1]);
404  data_out.build_patches();
405  // data_out.build_patches(*(this->dg->high_order_grid.mapping_fe_field), this->dg->max_degree, dealii::DataOut<dim, dealii::DoFHandler<dim>>::CurvedCellRegion::curved_inner_cells);
406  //data_out.build_patches(*(high_order_grid.mapping_fe_field), fe_collection.size(), dealii::DataOut<dim>::CurvedCellRegion::curved_inner_cells);
407  std::string filename = "adjoint-" ;
408  if(solution_refinement_state == SolutionRefinementStateEnum::fine)
409  filename += dealii::Utilities::int_to_string(cycle, 4) + ".";
410  filename += dealii::Utilities::int_to_string(iproc, 4);
411  filename += ".vtu";
412  std::ofstream output(filename);
413  data_out.write_vtu(output);
414 
415  if (iproc == 0)
416  {
417  std::vector<std::string> filenames;
418  for (unsigned int iproc = 0; iproc < dealii::Utilities::MPI::n_mpi_processes(mpi_communicator); ++iproc)
419  {
420  std::string fn = "adjoint-";
421  if(solution_refinement_state == SolutionRefinementStateEnum::fine)
422  fn += "fine-";
423  else if(solution_refinement_state == SolutionRefinementStateEnum::coarse)
424  fn += "coarse-";
425  fn += dealii::Utilities::int_to_string(dim, 1) + "D-";
426  fn += dealii::Utilities::int_to_string(cycle, 4) + ".";
427  fn += dealii::Utilities::int_to_string(iproc, 4);
428  fn += ".vtu";
429  filenames.push_back(fn);
430  }
431  std::string master_fn = "adjoint-";
432  if(solution_refinement_state == SolutionRefinementStateEnum::fine)
433  master_fn += "fine-";
434  else if(solution_refinement_state == SolutionRefinementStateEnum::coarse)
435  master_fn += "coarse-";
436  master_fn += dealii::Utilities::int_to_string(dim, 1) +"D-";
437  master_fn += dealii::Utilities::int_to_string(cycle, 4) + ".pvtu";
438  std::ofstream master_output(master_fn);
439  data_out.write_pvtu_record(master_output, filenames);
440  }
441 }
442 
445 #if PHILIP_DIM != 1
447 #endif
448 
449 
452 #if PHILIP_DIM != 1
454 #endif
455 
461 
467 
468 #if PHILIP_DIM!=1
474 #endif
475 
476 } // PHiLiP namespace
Abstract class to estimate error for mesh adaptation.
void reinit()
Reinitializes member variables of DualWeightedResidualError.
std::pair< unsigned int, double > solve_linear(const dealii::TrilinosWrappers::SparseMatrix &system_matrix, dealii::LinearAlgebra::distributed::Vector< double > &right_hand_side, dealii::LinearAlgebra::distributed::Vector< double > &solution, const Parameters::LinearSolverParam &param)
dealii::LinearAlgebra::distributed::Vector< real > coarse_grid_adjoint()
Computes the coarse grid adjoint.
Files for the baseline physics.
Definition: ADTypes.hpp:10
MeshErrorEstimateBase(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input)
Constructor.
std::shared_ptr< Functional< dim, nstate, real, MeshType > > functional
Functional class pointer.
MPI_Comm mpi_communicator
MPI communicator.
void convert_dgsolution_to_coarse_or_fine(SolutionRefinementStateEnum refinement_state)
Converts DG solution to the specified state.
dealii::Vector< real > compute_cellwise_errors() override
Computes maximum residual error in each cell.
DualWeightedResidualError(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input)
Constructor.
dealii::LinearAlgebra::distributed::Vector< real > derivative_functional_wrt_solution_coarse
functional derivative (on the coarse grid)
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
dealii::LinearAlgebra::distributed::Vector< real > adjoint_coarse
coarse grid adjoint ( )
dealii::LinearAlgebra::distributed::Vector< real > fine_grid_adjoint()
Computes the fine grid adjoint.
SolutionRefinementStateEnum
For storing the current refinement state of the solution.
dealii::Vector< real > dual_weighted_residual()
Computes the Dual Weighted Residual (DWR)
dealii::LinearAlgebra::distributed::Vector< real > compute_adjoint(dealii::LinearAlgebra::distributed::Vector< real > &derivative_functional_wrt_solution, dealii::LinearAlgebra::distributed::Vector< real > &adjoint_variable)
Solves the adjoint equation.
dealii::Vector< real > compute_cellwise_errors() override
Computes dual weighted residual error in each cell, by integrating over all quadrature points...
dealii::LinearAlgebra::distributed::Vector< real > solution_coarse
original solution
static std::unique_ptr< dealii::DataPostprocessor< dim > > create_Postprocessor(const Parameters::AllParameters *const parameters_input)
Create the post-processor with the correct template parameters.
Class to compute residual based error.
static std::shared_ptr< Functional< dim, nstate, real, MeshType > > create_Functional(PHiLiP::Parameters::AllParameters const *const param, std::shared_ptr< PHiLiP::DGBase< dim, real, MeshType > > dg)
Create standard functional object from constant parameter file.
void fine_to_coarse()
Return the problem to the original solution and polynomial distribution.
std::shared_ptr< DGBase< dim, real, MeshType > > dg
Pointer to DGBase.
DualWeightedResidualError class.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
real total_dual_weighted_residual_error()
Computes the sum of dual weighted residual error over all the cells in the domain.
ResidualErrorEstimate(std::shared_ptr< DGBase< dim, real, MeshType >> dg_input)
Constructor.
dealii::LinearAlgebra::distributed::Vector< real > derivative_functional_wrt_solution_fine
functional derivative (on the fine grid)
dealii::LinearAlgebra::distributed::Vector< real > adjoint_fine
fine grid adjoint ( )
dealii::Vector< real > dual_weighted_residual_fine
Dual weighted residual (.
void output_results_vtk(const unsigned int cycle)
Outputs the current solution and adjoint values.
void coarse_to_fine()
Projects the problem to a p-enriched space.