[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
adjoint.cpp
1 #include "adjoint.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.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 // constructor
29 template <int dim, int nstate, typename real, typename MeshType>
31  std::shared_ptr< DGBase<dim,real,MeshType> > _dg,
32  std::shared_ptr< Functional<dim, nstate, real, MeshType> > _functional,
33  std::shared_ptr< Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<real>> > _physics):
34  dg(_dg),
35  functional(_functional),
36  physics(_physics),
37  triangulation(dg->triangulation),
38  solution_coarse(dg->solution),
39  adjoint_state(AdjointStateEnum::coarse),
40  mpi_communicator(MPI_COMM_WORLD),
41  pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0)
42 {
43  // storing the original FE degree distribution
44  coarse_fe_index.reinit(dg->triangulation->n_active_cells());
45 
46  // looping over the cells
47  for(auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell)
48  if(cell->is_locally_owned())
49  coarse_fe_index[cell->active_cell_index()] = cell->active_fe_index();
50 }
51 
52 template <int dim, int nstate, typename real, typename MeshType>
54 {
55  // assuming that all pointers are still valid
56  // reinitilizing all variables after triangulation in the constructor
57  solution_coarse = dg->solution;
58  adjoint_state = AdjointStateEnum::coarse;
59 
60  // storing the original FE degree distribution
61  coarse_fe_index.reinit(dg->triangulation->n_active_cells());
62 
63  // looping over the cells
64  for(auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell)
65  if(cell->is_locally_owned())
66  coarse_fe_index[cell->active_cell_index()] = cell->active_fe_index();
67 
68  // for remaining, clearing the values
69  dIdw_fine = dealii::LinearAlgebra::distributed::Vector<real>();
70  dIdw_coarse = dealii::LinearAlgebra::distributed::Vector<real>();
71  adjoint_fine = dealii::LinearAlgebra::distributed::Vector<real>();
72  adjoint_coarse = dealii::LinearAlgebra::distributed::Vector<real>();
73 
74  dual_weighted_residual_fine = dealii::Vector<real>();
75 }
76 
77 template <int dim, int nstate, typename real, typename MeshType>
79 {
80  // checks if conversion is needed
81  if(adjoint_state == state)
82  return;
83 
84  // then calls corresponding function for state conversions
85  if(adjoint_state == AdjointStateEnum::coarse && state == AdjointStateEnum::fine)
87 
88  if(adjoint_state == AdjointStateEnum::fine && state == AdjointStateEnum::coarse)
90 }
91 
92 template <int dim, int nstate, typename real, typename MeshType>
94 {
95  dealii::IndexSet locally_owned_dofs, locally_relevant_dofs;
96  locally_owned_dofs = dg->dof_handler.locally_owned_dofs();
97  dealii::DoFTools::extract_locally_relevant_dofs(dg->dof_handler, locally_relevant_dofs);
98 
99  // dealii::LinearAlgebra::distributed::Vector<double> solution_coarse(dg->solution);
100  solution_coarse.update_ghost_values();
101 
102  // Solution Transfer to fine grid
103  using VectorType = typename dealii::LinearAlgebra::distributed::Vector<double>;
104  using DoFHandlerType = typename dealii::DoFHandler<dim>;
105  using SolutionTransfer = typename MeshTypeHelper<MeshType>::template SolutionTransfer<dim,VectorType,DoFHandlerType>;
106 
107  SolutionTransfer solution_transfer(dg->dof_handler);
108  solution_transfer.prepare_for_coarsening_and_refinement(solution_coarse);
109 
110  dg->high_order_grid->prepare_for_coarsening_and_refinement();
111  dg->triangulation->prepare_coarsening_and_refinement();
112 
113  for (auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell)
114  if (cell->is_locally_owned())
115  cell->set_future_fe_index(cell->active_fe_index()+1);
116 
117  dg->triangulation->execute_coarsening_and_refinement();
118  dg->high_order_grid->execute_coarsening_and_refinement();
119 
120  dg->allocate_system();
121  dg->solution.zero_out_ghosts();
122 
123  if constexpr (std::is_same_v<typename dealii::SolutionTransfer<dim,VectorType,DoFHandlerType>,
124  decltype(solution_transfer)>){
125  solution_transfer.interpolate(solution_coarse, dg->solution);
126  }else{
127  solution_transfer.interpolate(dg->solution);
128  }
129 
130  dg->solution.update_ghost_values();
131 
132  adjoint_state = AdjointStateEnum::fine;
133 }
134 
135 template <int dim, int nstate, typename real, typename MeshType>
137 {
138  dg->high_order_grid->prepare_for_coarsening_and_refinement();
139  dg->triangulation->prepare_coarsening_and_refinement();
140 
141  for (auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell)
142  if (cell->is_locally_owned())
143  cell->set_future_fe_index(coarse_fe_index[cell->active_cell_index()]);
144 
145  dg->triangulation->execute_coarsening_and_refinement();
146  dg->high_order_grid->execute_coarsening_and_refinement();
147 
148  dg->allocate_system();
149  dg->solution.zero_out_ghosts();
150 
151  dg->solution = solution_coarse;
152 
153  adjoint_state = AdjointStateEnum::coarse;
154 }
155 
156 template <int dim, int nstate, typename real, typename MeshType>
157 dealii::LinearAlgebra::distributed::Vector<real> Adjoint<dim, nstate, real, MeshType>::fine_grid_adjoint()
158 {
159  convert_to_state(AdjointStateEnum::fine);
160 
161  // dIdw_fine.reinit(dg->solution);
162  // dIdw_fine = functional.evaluate_dIdw(dg, physics);
163  const bool compute_dIdW = true, compute_dIdX = false;
164  const real functional_value = functional->evaluate_functional(compute_dIdW,compute_dIdX);
165  (void) functional_value;
166  dIdw_fine = functional->dIdw;
167 
168  adjoint_fine.reinit(dg->solution);
169 
170  dg->assemble_residual(true);
171  dg->system_matrix *= -1.0;
172 
173  dealii::TrilinosWrappers::SparseMatrix system_matrix_transpose;
174  Epetra_CrsMatrix *system_matrix_transpose_tril;
175 
176  Epetra_RowMatrixTransposer epmt(const_cast<Epetra_CrsMatrix *>(&dg->system_matrix.trilinos_matrix()));
177  epmt.CreateTranspose(false, system_matrix_transpose_tril);
178  system_matrix_transpose.reinit(*system_matrix_transpose_tril,true);
179  delete system_matrix_transpose_tril;
180  solve_linear(system_matrix_transpose, dIdw_fine, adjoint_fine, dg->all_parameters->linear_solver_param);
181  // solve_linear(dg.system_matrix, dIdw_fine, adjoint_fine, dg.all_parameters->linear_solver_param);
182 
183  return adjoint_fine;
184 }
185 
186 template <int dim, int nstate, typename real, typename MeshType>
187 dealii::LinearAlgebra::distributed::Vector<real> Adjoint<dim, nstate, real, MeshType>::coarse_grid_adjoint()
188 {
189  convert_to_state(AdjointStateEnum::coarse);
190 
191  dIdw_coarse.reinit(dg->solution);
192  //dIdw_coarse = functional.evaluate_dIdw(dg, physics);
193  const bool compute_dIdW = true, compute_dIdX = false;
194  const real functional_value = functional->evaluate_functional(compute_dIdW,compute_dIdX);
195  (void) functional_value;
196  dIdw_coarse = functional->dIdw;
197 
198  adjoint_coarse.reinit(dg->solution);
199 
200  dg->assemble_residual(true);
201  dg->system_matrix *= -1.0;
202 
203  dealii::TrilinosWrappers::SparseMatrix system_matrix_transpose;
204  Epetra_CrsMatrix *system_matrix_transpose_tril;
205 
206  Epetra_RowMatrixTransposer epmt(const_cast<Epetra_CrsMatrix *>(&dg->system_matrix.trilinos_matrix()));
207  epmt.CreateTranspose(false, system_matrix_transpose_tril);
208  system_matrix_transpose.reinit(*system_matrix_transpose_tril);
209  solve_linear(system_matrix_transpose, dIdw_coarse, adjoint_coarse, dg->all_parameters->linear_solver_param);
210  // solve_linear(dg->system_matrix, dIdw_coarse, adjoint_coarse, dg->all_parameters->linear_solver_param);
211 
212  return adjoint_coarse;
213 }
214 
215 template <int dim, int nstate, typename real, typename MeshType>
217 {
218  convert_to_state(AdjointStateEnum::fine);
219 
220  // allocating
221  dual_weighted_residual_fine.reinit(dg->triangulation->n_active_cells());
222 
223  const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell();
224  std::vector<dealii::types::global_dof_index> current_dofs_indices(max_dofs_per_cell);
225 
226  // computing the error indicator cell-wise by taking the dot product over the DOFs with the residual vector
227  for(auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell){
228  if(!cell->is_locally_owned()) continue;
229 
230  const unsigned int fe_index_curr_cell = cell->active_fe_index();
231  const dealii::FESystem<dim,dim> &current_fe_ref = dg->fe_collection[fe_index_curr_cell];
232  const unsigned int n_dofs_curr_cell = current_fe_ref.n_dofs_per_cell();
233 
234  current_dofs_indices.resize(n_dofs_curr_cell);
235  cell->get_dof_indices(current_dofs_indices);
236 
237  real dwr_cell = 0;
238  for(unsigned int idof = 0; idof < n_dofs_curr_cell; ++idof){
239  dwr_cell += dg->right_hand_side[current_dofs_indices[idof]]*adjoint_fine[current_dofs_indices[idof]];
240  }
241 
242  dual_weighted_residual_fine[cell->active_cell_index()] = std::abs(dwr_cell);
243  }
244 
246 }
247 
248 template <int dim, int nstate, typename real, typename MeshType>
250 {
251  dealii::DataOut<dim, dealii::DoFHandler<dim>> data_out;
252  data_out.attach_dof_handler(dg->dof_handler);
253 
254  const std::unique_ptr< dealii::DataPostprocessor<dim> > post_processor = Postprocess::PostprocessorFactory<dim>::create_Postprocessor(dg->all_parameters);
255  data_out.add_data_vector(dg->solution, *post_processor);
256 
257  dealii::Vector<float> subdomain(dg->triangulation->n_active_cells());
258  for (unsigned int i = 0; i < subdomain.size(); ++i) {
259  subdomain(i) = dg->triangulation->locally_owned_subdomain();
260  }
261  data_out.add_data_vector(subdomain, "subdomain", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
262 
263  // Output the polynomial degree in each cell
264  std::vector<unsigned int> active_fe_indices;
265  dg->dof_handler.get_active_fe_indices(active_fe_indices);
266  dealii::Vector<double> active_fe_indices_dealiivector(active_fe_indices.begin(), active_fe_indices.end());
267  dealii::Vector<double> cell_poly_degree = active_fe_indices_dealiivector;
268 
269  data_out.add_data_vector(active_fe_indices_dealiivector, "PolynomialDegree", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
270 
271  std::vector<std::string> residual_names;
272  for(int s=0;s<nstate;++s) {
273  std::string varname = "residual" + dealii::Utilities::int_to_string(s,1);
274  residual_names.push_back(varname);
275  }
276 
277  data_out.add_data_vector(dg->right_hand_side, residual_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
278 
279  // setting up the naming
280  std::vector<std::string> dIdw_names;
281  for(int s=0;s<nstate;++s) {
282  std::string varname = "dIdw" + dealii::Utilities::int_to_string(s,1);
283  dIdw_names.push_back(varname);
284  }
285 
286  std::vector<std::string> adjoint_names;
287  for(int s=0;s<nstate;++s) {
288  std::string varname = "psi" + dealii::Utilities::int_to_string(s,1);
289  adjoint_names.push_back(varname);
290  }
291 
292  // adding the data structures specific to this particular class, checking if currently fine or coarse
293  if(adjoint_state == AdjointStateEnum::fine){
294  data_out.add_data_vector(dIdw_fine, dIdw_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
295  data_out.add_data_vector(adjoint_fine, adjoint_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
296 
297  data_out.add_data_vector(dual_weighted_residual_fine, "DWR", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
298  }else if(adjoint_state == AdjointStateEnum::coarse){
299  data_out.add_data_vector(dIdw_coarse, dIdw_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
300  data_out.add_data_vector(adjoint_coarse, adjoint_names, dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_dof_data);
301  }
302 
303  const int iproc = dealii::Utilities::MPI::this_mpi_process(mpi_communicator);
304  //data_out.build_patches (mapping_collection[mapping_collection.size()-1]);
305  data_out.build_patches();
306  // data_out.build_patches(*(dg->high_order_grid.mapping_fe_field), dg->max_degree, dealii::DataOut<dim, dealii::DoFHandler<dim>>::CurvedCellRegion::curved_inner_cells);
307  //data_out.build_patches(*(high_order_grid.mapping_fe_field), fe_collection.size(), dealii::DataOut<dim>::CurvedCellRegion::curved_inner_cells);
308  std::string filename = "adjoint-" ;
309  if(adjoint_state == AdjointStateEnum::fine)
310  filename += dealii::Utilities::int_to_string(cycle, 4) + ".";
311  filename += dealii::Utilities::int_to_string(iproc, 4);
312  filename += ".vtu";
313  std::ofstream output(filename);
314  data_out.write_vtu(output);
315 
316  if (iproc == 0) {
317  std::vector<std::string> filenames;
318  for (unsigned int iproc = 0; iproc < dealii::Utilities::MPI::n_mpi_processes(mpi_communicator); ++iproc) {
319  std::string fn = "adjoint-";
320  if(adjoint_state == AdjointStateEnum::fine)
321  fn += "fine-";
322  else if(adjoint_state == AdjointStateEnum::coarse)
323  fn += "coarse-";
324  fn += dealii::Utilities::int_to_string(dim, 1) + "D-";
325  fn += dealii::Utilities::int_to_string(cycle, 4) + ".";
326  fn += dealii::Utilities::int_to_string(iproc, 4);
327  fn += ".vtu";
328  filenames.push_back(fn);
329  }
330  std::string master_fn = "adjoint-";
331  if(adjoint_state == AdjointStateEnum::fine)
332  master_fn += "fine-";
333  else if(adjoint_state == AdjointStateEnum::coarse)
334  master_fn += "coarse-";
335  master_fn += dealii::Utilities::int_to_string(dim, 1) +"D-";
336  master_fn += dealii::Utilities::int_to_string(cycle, 4) + ".pvtu";
337  std::ofstream master_output(master_fn);
338  data_out.write_pvtu_record(master_output, filenames);
339  }
340 }
341 
347 
353 
354 #if PHILIP_DIM!=1
360 #endif
361 
362 } // PHiLiP namespace
dealii::LinearAlgebra::distributed::Vector< real > dIdw_coarse
functional derivative (on the coarse grid)
Definition: adjoint.h:134
std::shared_ptr< Functional< dim, nstate, real, MeshType > > functional
Functional class pointer.
Definition: adjoint.h:123
void convert_to_state(AdjointStateEnum state)
Converts the adjoint to specified state.
Definition: adjoint.cpp:78
AdjointStateEnum adjoint_state
Current adjoint state.
Definition: adjoint.h:148
dealii::LinearAlgebra::distributed::Vector< real > fine_grid_adjoint()
Computes the fine grid adjoint.
Definition: adjoint.cpp:157
void fine_to_coarse()
Return the problem to the original solution and polynomial distribution.
Definition: adjoint.cpp:136
dealii::LinearAlgebra::distributed::Vector< real > adjoint_coarse
coarse grid adjoint ( )
Definition: adjoint.h:138
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
Adjoint class.
Definition: adjoint.h:39
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)
Adjoint(std::shared_ptr< DGBase< dim, real, MeshType > > _dg, std::shared_ptr< Functional< dim, nstate, real, MeshType > > _functional, std::shared_ptr< Physics::PhysicsBase< dim, nstate, Sacado::Fad::DFad< real >> > _physics)
Constructor.
Definition: adjoint.cpp:30
Files for the baseline physics.
Definition: ADTypes.hpp:10
AdjointStateEnum
For storing the current state in the adjoint.
Definition: adjoint.h:44
dealii::Vector< real > dual_weighted_residual()
compute the Dual Weighted Residual (DWR)
Definition: adjoint.cpp:216
dealii::LinearAlgebra::distributed::Vector< real > coarse_grid_adjoint()
Computes the coarse grid adjoint.
Definition: adjoint.cpp:187
dealii::LinearAlgebra::distributed::Vector< real > dIdw_fine
functional derivative (on the fine grid)
Definition: adjoint.h:132
void reinit()
Reinitialize Adjoint with the same pointers.
Definition: adjoint.cpp:53
dealii::Vector< real > coarse_fe_index
Original FE_index distribution.
Definition: adjoint.h:145
MPI_Comm mpi_communicator
MPI communicator.
Definition: adjoint.h:151
static std::unique_ptr< dealii::DataPostprocessor< dim > > create_Postprocessor(const Parameters::AllParameters *const parameters_input)
Create the post-processor with the correct template parameters.
dealii::LinearAlgebra::distributed::Vector< real > solution_coarse
original solution
Definition: adjoint.h:130
std::shared_ptr< DGBase< dim, real, MeshType > > dg
DG class pointer.
Definition: adjoint.h:121
void output_results_vtk(const unsigned int cycle)
Outputs the current solution and adjoint values.
Definition: adjoint.cpp:249
dealii::Vector< real > dual_weighted_residual_fine
dual weighted residual
Definition: adjoint.h:142
void coarse_to_fine()
Projects the problem to a p-enriched space.
Definition: adjoint.cpp:93
Functional base class.
Definition: functional.h:43
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
dealii::LinearAlgebra::distributed::Vector< real > adjoint_fine
fine grid adjoint ( )
Definition: adjoint.h:136