[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
target_functional.cpp
1 // includes
2 #include "target_functional.h"
3 
4 #include <deal.II/base/qprojector.h>
5 #include <deal.II/differentiation/ad/sacado_math.h>
6 #include <deal.II/differentiation/ad/sacado_number_types.h>
7 #include <deal.II/differentiation/ad/sacado_product_types.h>
8 #include <deal.II/dofs/dof_tools.h>
9 #include <deal.II/fe/fe_q.h>
10 #include <deal.II/fe/fe_values.h>
11 #include <deal.II/lac/la_parallel_vector.h>
12 
13 #include <Sacado.hpp>
14 #include <vector>
15 
16 #include "dg/dg_base.hpp"
17 #include "physics/model.h"
18 #include "physics/model_factory.h"
19 #include "physics/physics.h"
20 #include "physics/physics_factory.h"
21 
22 namespace PHiLiP {
23 template<int dim, typename real1, typename real2>
24 dealii::Tensor<1,dim,real1> vmult(const dealii::Tensor<2,dim,real1> A, const dealii::Tensor<1,dim,real2> x)
25 {
26  dealii::Tensor<1,dim,real1> y;
27  for (int row=0;row<dim;++row) {
28  y[row] = 0.0;
29  for (int col=0;col<dim;++col) {
30  y[row] += A[row][col] * x[col];
31  }
32  }
33  return y;
34 }
36 
40 template<int dim, typename real1>
41 real1 norm(const dealii::Tensor<1,dim,real1> x)
42 {
43  real1 val = 0.0;
44  for (int row=0;row<dim;++row) {
45  val += x[row] * x[row];
46  }
47  return sqrt(val);
48 }
49 
50 template <int dim, int nstate, typename real>
52  std::shared_ptr<DGBase<dim,real>> _dg,
53  const bool _uses_solution_values,
54  const bool _uses_solution_gradient)
55  : Functional<dim,nstate,real>::Functional(_dg, _uses_solution_values, _uses_solution_gradient)
56  , target_solution(dg->solution)
57 {
58  using FadType = Sacado::Fad::DFad<real>;
59  using FadFadType = Sacado::Fad::DFad<FadType>;
61 }
62 
63 template <int dim, int nstate, typename real>
65  std::shared_ptr<DGBase<dim,real>> _dg,
66  const dealii::LinearAlgebra::distributed::Vector<real> &target_solution,
67  const bool _uses_solution_values,
68  const bool _uses_solution_gradient)
69  : Functional<dim,nstate,real>::Functional(_dg, _uses_solution_values, _uses_solution_gradient)
70  , target_solution(target_solution)
71 {
72  using FadType = Sacado::Fad::DFad<real>;
73  using FadFadType = Sacado::Fad::DFad<FadType>;
74  std::shared_ptr<Physics::ModelBase<dim,nstate,FadFadType>> model_fad_fad = Physics::ModelFactory<dim,nstate,FadFadType>::create_Model(dg->all_parameters);
76 }
77 
78 template <int dim, int nstate, typename real>
80  std::shared_ptr<DGBase<dim,real>> _dg,
81  std::shared_ptr< Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<Sacado::Fad::DFad<real>>> > _physics_fad_fad,
82  const bool _uses_solution_values,
83  const bool _uses_solution_gradient)
84  : Functional<dim,nstate,real>::Functional(_dg, _physics_fad_fad, _uses_solution_values, _uses_solution_gradient)
85  , target_solution(dg->solution)
86 { }
87 
88 template <int dim, int nstate, typename real>
90  std::shared_ptr<DGBase<dim,real>> _dg,
91  const dealii::LinearAlgebra::distributed::Vector<real> &target_solution,
92  std::shared_ptr< Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<Sacado::Fad::DFad<real>>> > _physics_fad_fad,
93  const bool _uses_solution_values,
94  const bool _uses_solution_gradient)
95  : Functional<dim,nstate,real>::Functional(_dg, _physics_fad_fad, _uses_solution_values, _uses_solution_gradient)
96  , target_solution(target_solution)
97 { }
98 
99 
100 template <int dim, int nstate, typename real>
101 template <typename real2>
104  const std::vector< real2 > &soln_coeff,
105  const std::vector< real > &target_soln_coeff,
106  const dealii::FESystem<dim> &fe_solution,
107  const std::vector< real2 > &coords_coeff,
108  const dealii::FESystem<dim> &fe_metric,
109  const dealii::Quadrature<dim> &volume_quadrature) const
110 {
111  const unsigned int n_vol_quad_pts = volume_quadrature.size();
112  const unsigned int n_soln_dofs_cell = soln_coeff.size();
113  const unsigned int n_metric_dofs_cell = coords_coeff.size();
114 
115  real2 volume_local_sum = 0.0;
116  for (unsigned int iquad=0; iquad<n_vol_quad_pts; ++iquad) {
117 
118  const dealii::Point<dim,double> &ref_point = volume_quadrature.point(iquad);
119  const double quad_weight = volume_quadrature.weight(iquad);
120 
121  // Obtain physical quadrature coordinates (Might be used if there is a source term or a wall distance)
122  // and evaluate metric terms such as the metric Jacobian, its inverse transpose, and its determinant
123  dealii::Point<dim,real2> phys_coord;
124  for (int d=0;d<dim;++d) { phys_coord[d] = 0.0;}
125  std::array< dealii::Tensor<1,dim,real2>, dim > coord_grad; // Tensor initialize with zeros
126  dealii::Tensor<2,dim,real2> metric_jacobian;
127  for (unsigned int idof=0; idof<n_metric_dofs_cell; ++idof) {
128  const unsigned int axis = fe_metric.system_to_component_index(idof).first;
129  phys_coord[axis] += coords_coeff[idof] * fe_metric.shape_value(idof, ref_point);
130  coord_grad[axis] += coords_coeff[idof] * fe_metric.shape_grad (idof, ref_point);
131  }
132  for (int row=0;row<dim;++row) {
133  for (int col=0;col<dim;++col) {
134  metric_jacobian[row][col] = coord_grad[row][col];
135  }
136  }
137  const real2 jacobian_determinant = dealii::determinant(metric_jacobian);
138  dealii::Tensor<2,dim,real2> jacobian_transpose_inverse;
139  jacobian_transpose_inverse = dealii::transpose(dealii::invert(metric_jacobian));
140 
141  // Evaluate the solution and gradient at the quadrature points
142  std::array<real2, nstate> soln_at_q;
143  std::array<real, nstate> target_soln_at_q;
144  soln_at_q.fill(0.0);
145  target_soln_at_q.fill(0.0);
146  std::array< dealii::Tensor<1,dim,real2>, nstate > soln_grad_at_q;
147  std::array< dealii::Tensor<1,dim,real2>, nstate > target_soln_grad_at_q; // Target solution grad needs to be FadType since metric term involve mesh DoFs
148  for (unsigned int idof=0; idof<n_soln_dofs_cell; ++idof) {
149  const unsigned int istate = fe_solution.system_to_component_index(idof).first;
150  if (uses_solution_values) {
151  soln_at_q[istate] += soln_coeff[idof] * fe_solution.shape_value(idof,ref_point);
152  target_soln_at_q[istate] += target_soln_coeff[idof] * fe_solution.shape_value(idof,ref_point);
153  }
155  const dealii::Tensor<1,dim,real2> phys_shape_grad = dealii::contract<1,0>(jacobian_transpose_inverse, fe_solution.shape_grad(idof,ref_point));
156  soln_grad_at_q[istate] += soln_coeff[idof] * phys_shape_grad;
157  target_soln_grad_at_q[istate] += target_soln_coeff[idof] * phys_shape_grad;
158  }
159  }
160  real2 volume_integrand = evaluate_volume_integrand(physics, phys_coord, soln_at_q, target_soln_at_q, soln_grad_at_q, target_soln_grad_at_q);
161 
162  (void) jacobian_determinant;
163  (void) quad_weight;
164  volume_local_sum += volume_integrand;// * jacobian_determinant * quad_weight;
165  if (volume_local_sum != 0.0 && jacobian_determinant < 0) {
166  std::cout << "Bad jacobian... setting volume_local_sum *= 1e200" << std::endl;
167  volume_local_sum += 1e200;
168  }
169  }
170  return volume_local_sum;
171 }
172 
173 template <int dim, int nstate, typename real>
176  const std::vector< real > &soln_coeff,
177  const std::vector< real > &target_soln_coeff,
178  const dealii::FESystem<dim> &fe_solution,
179  const std::vector< real > &coords_coeff,
180  const dealii::FESystem<dim> &fe_metric,
181  const dealii::Quadrature<dim> &volume_quadrature) const
182 {
183  return evaluate_volume_cell_functional<real>(physics, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
184 }
185 
186 template <int dim, int nstate, typename real>
188  const Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<Sacado::Fad::DFad<real>>> &physics_fad_fad,
189  const std::vector< Sacado::Fad::DFad<Sacado::Fad::DFad<real>> > &soln_coeff,
190  const std::vector< real > &target_soln_coeff,
191  const dealii::FESystem<dim> &fe_solution,
192  const std::vector< Sacado::Fad::DFad<Sacado::Fad::DFad<real>> > &coords_coeff,
193  const dealii::FESystem<dim> &fe_metric,
194  const dealii::Quadrature<dim> &volume_quadrature) const
195 {
196  return evaluate_volume_cell_functional<Sacado::Fad::DFad<Sacado::Fad::DFad<real>>>(physics_fad_fad, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
197 }
198 
199 template <int dim, int nstate, typename real>
200 template <typename real2>
203  const unsigned int boundary_id,
204  const std::vector< real2 > &soln_coeff,
205  const std::vector< real > &target_soln_coeff,
206  const dealii::FESystem<dim> &fe_solution,
207  const std::vector< real2 > &coords_coeff,
208  const dealii::FESystem<dim> &fe_metric,
209  const dealii::Quadrature<dim-1> &fquadrature,
210  const unsigned int face_number) const
211 {
212  const dealii::Quadrature<dim> face_quadrature = dealii::QProjector<dim>::project_to_face( dealii::ReferenceCell::get_hypercube(dim), fquadrature, face_number);
213  const dealii::Tensor<1,dim,real> ref_unit_normal = dealii::GeometryInfo<dim>::unit_normal_vector[face_number];
214 
215  const unsigned int n_face_quad_pts = face_quadrature.size();
216  const unsigned int n_soln_dofs_cell = soln_coeff.size();
217  const unsigned int n_metric_dofs_cell = coords_coeff.size();
218 
219  real2 face_local_sum = 0.0;
220  for (unsigned int iquad=0; iquad<n_face_quad_pts; ++iquad) {
221 
222  const dealii::Point<dim,double> &ref_point = face_quadrature.point(iquad);
223  const double quad_weight = face_quadrature.weight(iquad);
224 
225  // Obtain physical quadrature coordinates (Might be used if there is a source term or a wall distance)
226  // and evaluate metric terms such as the metric Jacobian, its inverse transpose, and its determinant
227  dealii::Point<dim,real2> phys_coord;
228  for (int d=0;d<dim;++d) { phys_coord[d] = 0.0;}
229  std::array< dealii::Tensor<1,dim,real2>, dim > coord_grad; // Tensor initialize with zeros
230  dealii::Tensor<2,dim,real2> metric_jacobian;
231  for (unsigned int idof=0; idof<n_metric_dofs_cell; ++idof) {
232  const unsigned int axis = fe_metric.system_to_component_index(idof).first;
233  phys_coord[axis] += coords_coeff[idof] * fe_metric.shape_value(idof, ref_point);
234  coord_grad[axis] += coords_coeff[idof] * fe_metric.shape_grad (idof, ref_point);
235  }
236  for (int row=0;row<dim;++row) {
237  for (int col=0;col<dim;++col) {
238  metric_jacobian[row][col] = coord_grad[row][col];
239  }
240  }
241  const real2 jacobian_determinant = dealii::determinant(metric_jacobian);
242  dealii::Tensor<2,dim,real2> jacobian_transpose_inverse;
243  jacobian_transpose_inverse = dealii::transpose(dealii::invert(metric_jacobian));
244 
245  // Evaluate the solution and gradient at the quadrature points
246  std::array<real2, nstate> soln_at_q;
247  std::array<real, nstate> target_soln_at_q;
248  soln_at_q.fill(0.0);
249  target_soln_at_q.fill(0.0);
250  std::array< dealii::Tensor<1,dim,real2>, nstate > soln_grad_at_q;
251  std::array< dealii::Tensor<1,dim,real2>, nstate > target_soln_grad_at_q; // Target solution grad needs to be FadType since metric term involve mesh DoFs
252  for (unsigned int idof=0; idof<n_soln_dofs_cell; ++idof) {
253  const unsigned int istate = fe_solution.system_to_component_index(idof).first;
254  if (uses_solution_values) {
255  soln_at_q[istate] += soln_coeff[idof] * fe_solution.shape_value(idof,ref_point);
256  target_soln_at_q[istate] += target_soln_coeff[idof] * fe_solution.shape_value(idof,ref_point);
257  }
259  const dealii::Tensor<1,dim,real2> phys_shape_grad = dealii::contract<1,0>(jacobian_transpose_inverse, fe_solution.shape_grad(idof,ref_point));
260  soln_grad_at_q[istate] += soln_coeff[idof] * phys_shape_grad;
261  target_soln_grad_at_q[istate] += target_soln_coeff[idof] * phys_shape_grad;
262  }
263  }
264 
265  const dealii::Tensor<1,dim,real2> phys_normal = vmult(jacobian_transpose_inverse, ref_unit_normal);
266  const real2 area = norm(phys_normal);
267  const dealii::Tensor<1,dim,real2> phys_unit_normal = phys_normal/area;
268  real2 boundary_integrand = evaluate_boundary_integrand(physics, boundary_id, phys_coord, phys_unit_normal, soln_at_q, target_soln_at_q, soln_grad_at_q, target_soln_grad_at_q);
269 
270  real2 surface_jacobian_determinant = area*jacobian_determinant;
271 
272  face_local_sum += boundary_integrand * surface_jacobian_determinant * quad_weight;
273  if (face_local_sum != 0.0 && jacobian_determinant < 0) {
274  std::cout << "Bad jacobian... setting face_local_sum *= 1e40" << std::endl;
275  face_local_sum += 1e40;
276  }
277  //face_local_sum += boundary_integrand;// * jacobian_determinant * quad_weight;
278  }
279  return face_local_sum;
280 }
281 
282 template <int dim, int nstate, typename real>
285  const unsigned int boundary_id,
286  const std::vector< real > &soln_coeff,
287  const std::vector< real > &target_soln_coeff,
288  const dealii::FESystem<dim> &fe_solution,
289  const std::vector< real > &coords_coeff,
290  const dealii::FESystem<dim> &fe_metric,
291  const dealii::Quadrature<dim-1> &face_quadrature,
292  const unsigned int face_number) const
293 {
294  return evaluate_boundary_cell_functional<real>(physics, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, face_quadrature, face_number);
295 }
296 
297 template <int dim, int nstate, typename real>
299  const Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<Sacado::Fad::DFad<real>>> &physics_fad_fad,
300  const unsigned int boundary_id,
301  const std::vector< Sacado::Fad::DFad<Sacado::Fad::DFad<real>> > &soln_coeff,
302  const std::vector< real > &target_soln_coeff,
303  const dealii::FESystem<dim> &fe_solution,
304  const std::vector< Sacado::Fad::DFad<Sacado::Fad::DFad<real>> > &coords_coeff,
305  const dealii::FESystem<dim> &fe_metric,
306  const dealii::Quadrature<dim-1> &face_quadrature,
307  const unsigned int face_number) const
308 {
309  return evaluate_boundary_cell_functional<Sacado::Fad::DFad<Sacado::Fad::DFad<real>>>(physics_fad_fad, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, face_quadrature, face_number);
310 }
311 
312 template <int dim, int nstate, typename real>
314  const bool compute_dIdW,
315  const bool compute_dIdX,
316  const bool compute_d2I)
317 {
318  using FadType = Sacado::Fad::DFad<real>;
319  using FadFadType = Sacado::Fad::DFad<FadType>;
320 
321  bool actually_compute_value = true;
322  bool actually_compute_dIdW = compute_dIdW;
323  bool actually_compute_dIdX = compute_dIdX;
324  bool actually_compute_d2I = compute_d2I;
325 
326  Functional<dim,nstate,real>::pcout << "Evaluating functional... ";
327  Functional<dim,nstate,real>::need_compute(actually_compute_value, actually_compute_dIdW, actually_compute_dIdX, actually_compute_d2I);
329  if (!actually_compute_value && !actually_compute_dIdW && !actually_compute_dIdX && !actually_compute_d2I) {
331  }
332 
333  // for taking the local derivatives
334  const dealii::FESystem<dim,dim> &fe_metric = dg->high_order_grid->fe_system;
335  const unsigned int n_metric_dofs_cell = fe_metric.dofs_per_cell;
336  std::vector<dealii::types::global_dof_index> cell_metric_dofs_indices(n_metric_dofs_cell);
337 
338  // setup it mostly the same as evaluating the value (with exception that local solution is also AD)
339  const unsigned int max_dofs_per_cell = dg->dof_handler.get_fe_collection().max_dofs_per_cell();
340  std::vector<dealii::types::global_dof_index> cell_soln_dofs_indices(max_dofs_per_cell);
341  std::vector<FadFadType> soln_coeff(max_dofs_per_cell); // for obtaining the local derivatives (to be copied back afterwards)
342  std::vector<real> target_soln_coeff(max_dofs_per_cell); // for obtaining the local derivatives (to be copied back afterwards)
343  std::vector<real> local_dIdw(max_dofs_per_cell);
344 
345  std::vector<real> local_dIdX(n_metric_dofs_cell);
346 
347  const auto mapping = (*(dg->high_order_grid->mapping_fe_field));
348  dealii::hp::MappingCollection<dim> mapping_collection(mapping);
349 
350  dealii::hp::FEFaceValues<dim,dim> fe_values_collection_face (mapping_collection, dg->fe_collection, dg->face_quadrature_collection, this->face_update_flags);
351 
352  this->allocate_derivatives(actually_compute_dIdW, actually_compute_dIdX, actually_compute_d2I);
353 
354  dg->solution.update_ghost_values();
355  auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active();
356  auto soln_cell = dg->dof_handler.begin_active();
357 
358  real local_functional = 0.0;
359 
360  for( ; soln_cell != dg->dof_handler.end(); ++soln_cell, ++metric_cell) {
361  if(!soln_cell->is_locally_owned()) continue;
362 
363  // setting up the volume integration
364  const unsigned int i_mapp = 0; // *** ask doug if this will ever be
365  const unsigned int i_fele = soln_cell->active_fe_index();
366  const unsigned int i_quad = i_fele;
367  (void) i_mapp;
368 
369  // Get solution coefficients
370  const dealii::FESystem<dim,dim> &fe_solution = dg->fe_collection[i_fele];
371  const unsigned int n_soln_dofs_cell = fe_solution.n_dofs_per_cell();
372  cell_soln_dofs_indices.resize(n_soln_dofs_cell);
373  soln_cell->get_dof_indices(cell_soln_dofs_indices);
374  soln_coeff.resize(n_soln_dofs_cell);
375  target_soln_coeff.resize(n_soln_dofs_cell);
376 
377  // Get metric coefficients
378  metric_cell->get_dof_indices (cell_metric_dofs_indices);
379  std::vector< FadFadType > coords_coeff(n_metric_dofs_cell);
380  for (unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof) {
381  coords_coeff[idof] = dg->high_order_grid->volume_nodes[cell_metric_dofs_indices[idof]];
382  }
383 
384  // Setup automatic differentiation
385  unsigned int n_total_indep = 0;
386  if (actually_compute_dIdW || actually_compute_d2I) n_total_indep += n_soln_dofs_cell;
387  if (actually_compute_dIdX || actually_compute_d2I) n_total_indep += n_metric_dofs_cell;
388  unsigned int i_derivative = 0;
389  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof) {
390  const real val = dg->solution[cell_soln_dofs_indices[idof]];
391  soln_coeff[idof] = val;
392  if (actually_compute_dIdW || actually_compute_d2I) soln_coeff[idof].diff(i_derivative++, n_total_indep);
393  }
394  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof) {
395  const real val = target_solution[cell_soln_dofs_indices[idof]];
396  target_soln_coeff[idof] = val;
397  }
398  for (unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof) {
399  const real val = dg->high_order_grid->volume_nodes[cell_metric_dofs_indices[idof]];
400  coords_coeff[idof] = val;
401  if (actually_compute_dIdX || actually_compute_d2I) coords_coeff[idof].diff(i_derivative++, n_total_indep);
402  }
403  AssertDimension(i_derivative, n_total_indep);
404  if (actually_compute_d2I) {
405  unsigned int i_derivative = 0;
406  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof) {
407  const real val = dg->solution[cell_soln_dofs_indices[idof]];
408  soln_coeff[idof].val() = val;
409  soln_coeff[idof].val().diff(i_derivative++, n_total_indep);
410  }
411  for (unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof) {
412  const real val = dg->high_order_grid->volume_nodes[cell_metric_dofs_indices[idof]];
413  coords_coeff[idof].val() = val;
414  coords_coeff[idof].val().diff(i_derivative++, n_total_indep);
415  }
416  }
417  AssertDimension(i_derivative, n_total_indep);
418 
419  // Get quadrature point on reference cell
420  const dealii::Quadrature<dim> &volume_quadrature = dg->volume_quadrature_collection[i_quad];
421 
422  // Evaluate integral on the cell volume
423  FadFadType volume_local_sum;
424  volume_local_sum.resizeAndZero(n_total_indep);
425  volume_local_sum += evaluate_volume_cell_functional(*physics_fad_fad, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
426 
427  // std::cout << "volume_local_sum.val().val() : " << volume_local_sum.val().val() << std::endl;
428 
429  // next looping over the faces of the cell checking for boundary elements
430  for(unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
431  auto face = soln_cell->face(iface);
432 
433  if(face->at_boundary()){
434 
435  const unsigned int boundary_id = face->boundary_id();
436 
437  volume_local_sum += evaluate_boundary_cell_functional(*physics_fad_fad, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, dg->face_quadrature_collection[i_quad], iface);
438  }
439 
440  }
441 
442  local_functional += volume_local_sum.val().val();
443  // now getting the values and adding them to the derivaitve vector
444 
445  this->set_derivatives(actually_compute_dIdW, actually_compute_dIdX, actually_compute_d2I, volume_local_sum, cell_soln_dofs_indices, cell_metric_dofs_indices);
446  }
447  //std::cout << local_functional << std::endl;
448  current_functional_value = dealii::Utilities::MPI::sum(local_functional, MPI_COMM_WORLD);
449  //std::cout << current_functional_value << std::endl;
450  // compress before the return
451  if (actually_compute_dIdW) dIdw.compress(dealii::VectorOperation::add);
452  if (actually_compute_dIdX) dIdX.compress(dealii::VectorOperation::add);
453  if (actually_compute_d2I) {
454  d2IdWdW->compress(dealii::VectorOperation::add);
455  d2IdWdX->compress(dealii::VectorOperation::add);
456  d2IdXdX->compress(dealii::VectorOperation::add);
457  }
458 
460 }
461 
462 template <int dim, int nstate, typename real>
463 dealii::LinearAlgebra::distributed::Vector<real> TargetFunctional<dim,nstate,real>::evaluate_dIdw_finiteDifferences(
466  const double stepsize)
467 {
468  // for taking the local derivatives
469  double local_sum_old;
470  double local_sum_new;
471 
472  // vector for storing the derivatives with respect to each DOF
473  dealii::LinearAlgebra::distributed::Vector<real> dIdw;
474 
475  // allocating the vector
476  dealii::IndexSet locally_owned_dofs = dg.dof_handler.locally_owned_dofs();
477  dIdw.reinit(locally_owned_dofs, MPI_COMM_WORLD);
478 
479  // setup it mostly the same as evaluating the value (with exception that local solution is also AD)
480  const unsigned int max_dofs_per_cell = dg.dof_handler.get_fe_collection().max_dofs_per_cell();
481  std::vector<dealii::types::global_dof_index> cell_soln_dofs_indices(max_dofs_per_cell);
482  std::vector<dealii::types::global_dof_index> neighbor_dofs_indices(max_dofs_per_cell);
483  std::vector<real> soln_coeff(max_dofs_per_cell); // for obtaining the local derivatives (to be copied back afterwards)
484  std::vector<real> target_soln_coeff(max_dofs_per_cell);
485  std::vector<real> local_dIdw(max_dofs_per_cell);
486 
487  const auto mapping = (*(dg.high_order_grid->mapping_fe_field));
488  dealii::hp::MappingCollection<dim> mapping_collection(mapping);
489 
490  dealii::hp::FEValues<dim,dim> fe_values_collection_volume(mapping_collection, dg.fe_collection, dg.volume_quadrature_collection, this->volume_update_flags);
491  dealii::hp::FEFaceValues<dim,dim> fe_values_collection_face (mapping_collection, dg.fe_collection, dg.face_quadrature_collection, this->face_update_flags);
492 
493  dg.solution.update_ghost_values();
494  auto metric_cell = dg.high_order_grid->dof_handler_grid.begin_active();
495  auto cell = dg.dof_handler.begin_active();
496  for( ; cell != dg.dof_handler.end(); ++cell, ++metric_cell) {
497  if(!cell->is_locally_owned()) continue;
498 
499  // setting up the volume integration
500  const unsigned int i_mapp = 0;
501  const unsigned int i_fele = cell->active_fe_index();
502  const unsigned int i_quad = i_fele;
503  (void) i_mapp;
504 
505  // Get solution coefficients
506  const dealii::FESystem<dim,dim> &fe_solution = dg.fe_collection[i_fele];
507  const unsigned int n_soln_dofs_cell = fe_solution.n_dofs_per_cell();
508  cell_soln_dofs_indices.resize(n_soln_dofs_cell);
509  cell->get_dof_indices(cell_soln_dofs_indices);
510  soln_coeff.resize(n_soln_dofs_cell);
511  target_soln_coeff.resize(n_soln_dofs_cell);
512  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof) {
513  soln_coeff[idof] = dg.solution[cell_soln_dofs_indices[idof]];
514  target_soln_coeff[idof] = target_solution[cell_soln_dofs_indices[idof]];
515  }
516 
517  // Get metric coefficients
518  const dealii::FESystem<dim,dim> &fe_metric = dg.high_order_grid->fe_system;
519  const unsigned int n_metric_dofs_cell = fe_metric.dofs_per_cell;
520  std::vector<dealii::types::global_dof_index> cell_metric_dofs_indices(n_metric_dofs_cell);
521  metric_cell->get_dof_indices (cell_metric_dofs_indices);
522  std::vector<real> coords_coeff(n_metric_dofs_cell);
523  for (unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof) {
524  coords_coeff[idof] = dg.high_order_grid->volume_nodes[cell_metric_dofs_indices[idof]];
525  }
526 
527  const dealii::Quadrature<dim> &volume_quadrature = dg.volume_quadrature_collection[i_quad];
528 
529  // adding the contribution from the current volume, also need to pass the solution vector on these points
530  //local_sum_old = this->evaluate_volume_integrand(physics, fe_values_volume, soln_coeff);
531  local_sum_old = this->evaluate_volume_cell_functional(physics, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
532 
533  // Next looping over the faces of the cell checking for boundary elements
534  for(unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
535  auto face = cell->face(iface);
536 
537  if(face->at_boundary()){
538  const unsigned int boundary_id = face->boundary_id();
539  local_sum_old += evaluate_boundary_cell_functional(physics, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, dg.face_quadrature_collection[i_quad], iface);
540  }
541 
542  }
543 
544  // now looping over all the DOFs in this cell and taking the FD
545  local_dIdw.resize(n_soln_dofs_cell);
546  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof){
547  // for each dof copying the solution
548  for(unsigned int idof2 = 0; idof2 < n_soln_dofs_cell; ++idof2){
549  soln_coeff[idof2] = dg.solution[cell_soln_dofs_indices[idof2]];
550  }
551  soln_coeff[idof] += stepsize;
552 
553  // then peturb the idof'th value
554  // local_sum_new = this->evaluate_volume_integrand(physics, fe_values_volume, soln_coeff);
555  local_sum_new = this->evaluate_volume_cell_functional(physics, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
556 
557  // Next looping over the faces of the cell checking for boundary elements
558  for(unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
559  auto face = cell->face(iface);
560 
561  if(face->at_boundary()){
562  const unsigned int boundary_id = face->boundary_id();
563  local_sum_new += evaluate_boundary_cell_functional(physics, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, dg.face_quadrature_collection[i_quad], iface);
564  }
565 
566  }
567 
568  local_dIdw[idof] = (local_sum_new-local_sum_old)/stepsize;
569  }
570 
571  dIdw.add(cell_soln_dofs_indices, local_dIdw);
572  }
573  // compress before the return
574  dIdw.compress(dealii::VectorOperation::add);
575 
576  return dIdw;
577 }
578 
579 template <int dim, int nstate, typename real>
580 dealii::LinearAlgebra::distributed::Vector<real> TargetFunctional<dim,nstate,real>::evaluate_dIdX_finiteDifferences(
583  const double stepsize)
584 {
585  // for taking the local derivatives
586  double local_sum_old;
587  double local_sum_new;
588 
589  // vector for storing the derivatives with respect to each DOF
590  dealii::LinearAlgebra::distributed::Vector<real> dIdX_FD;
591  this->allocate_dIdX(dIdX_FD);
592 
593  // setup it mostly the same as evaluating the value (with exception that local solution is also AD)
594  const unsigned int max_dofs_per_cell = dg.dof_handler.get_fe_collection().max_dofs_per_cell();
595  std::vector<dealii::types::global_dof_index> cell_soln_dofs_indices(max_dofs_per_cell);
596  std::vector<dealii::types::global_dof_index> neighbor_dofs_indices(max_dofs_per_cell);
597  std::vector<real> soln_coeff(max_dofs_per_cell); // for obtaining the local derivatives (to be copied back afterwards)
598  std::vector<real> target_soln_coeff(max_dofs_per_cell);
599  std::vector<real> local_dIdX(max_dofs_per_cell);
600 
601  const auto mapping = (*(dg.high_order_grid->mapping_fe_field));
602  dealii::hp::MappingCollection<dim> mapping_collection(mapping);
603 
604  dealii::hp::FEValues<dim,dim> fe_values_collection_volume(mapping_collection, dg.fe_collection, dg.volume_quadrature_collection, this->volume_update_flags);
605  dealii::hp::FEFaceValues<dim,dim> fe_values_collection_face (mapping_collection, dg.fe_collection, dg.face_quadrature_collection, this->face_update_flags);
606 
607  dg.solution.update_ghost_values();
608  auto metric_cell = dg.high_order_grid->dof_handler_grid.begin_active();
609  auto cell = dg.dof_handler.begin_active();
610  for( ; cell != dg.dof_handler.end(); ++cell, ++metric_cell) {
611  if(!cell->is_locally_owned()) continue;
612 
613  // setting up the volume integration
614  const unsigned int i_mapp = 0;
615  const unsigned int i_fele = cell->active_fe_index();
616  const unsigned int i_quad = i_fele;
617  (void) i_mapp;
618 
619  // Get solution coefficients
620  const dealii::FESystem<dim,dim> &fe_solution = dg.fe_collection[i_fele];
621  const unsigned int n_soln_dofs_cell = fe_solution.n_dofs_per_cell();
622  cell_soln_dofs_indices.resize(n_soln_dofs_cell);
623  cell->get_dof_indices(cell_soln_dofs_indices);
624  soln_coeff.resize(n_soln_dofs_cell);
625  target_soln_coeff.resize(n_soln_dofs_cell);
626  for(unsigned int idof = 0; idof < n_soln_dofs_cell; ++idof) {
627  soln_coeff[idof] = dg.solution[cell_soln_dofs_indices[idof]];
628  target_soln_coeff[idof] = target_solution[cell_soln_dofs_indices[idof]];
629  }
630 
631  // Get metric coefficients
632  const dealii::FESystem<dim,dim> &fe_metric = dg.high_order_grid->fe_system;
633  const unsigned int n_metric_dofs_cell = fe_metric.dofs_per_cell;
634  std::vector<dealii::types::global_dof_index> cell_metric_dofs_indices(n_metric_dofs_cell);
635  metric_cell->get_dof_indices (cell_metric_dofs_indices);
636  std::vector<real> coords_coeff(n_metric_dofs_cell);
637  for (unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof) {
638  coords_coeff[idof] = dg.high_order_grid->volume_nodes[cell_metric_dofs_indices[idof]];
639  }
640 
641  const dealii::Quadrature<dim> &volume_quadrature = dg.volume_quadrature_collection[i_quad];
642 
643  // adding the contribution from the current volume, also need to pass the solution vector on these points
644  //local_sum_old = this->evaluate_volume_integrand(physics, fe_values_volume, soln_coeff);
645  local_sum_old = this->evaluate_volume_cell_functional(physics, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
646 
647  // Next looping over the faces of the cell checking for boundary elements
648  for(unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
649  auto face = cell->face(iface);
650 
651  if(face->at_boundary()){
652  const unsigned int boundary_id = face->boundary_id();
653  local_sum_old += evaluate_boundary_cell_functional(physics, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, dg.face_quadrature_collection[i_quad], iface);
654  }
655 
656  }
657 
658  // now looping over all the DOFs in this cell and taking the FD
659  local_dIdX.resize(n_metric_dofs_cell);
660  for(unsigned int idof = 0; idof < n_metric_dofs_cell; ++idof){
661  // for each dof copying the solution
662  for(unsigned int idof2 = 0; idof2 < n_metric_dofs_cell; ++idof2){
663  coords_coeff[idof2] = dg.high_order_grid->volume_nodes[cell_metric_dofs_indices[idof2]];
664  }
665  coords_coeff[idof] += stepsize;
666 
667  // then peturb the idof'th value
668  local_sum_new = this->evaluate_volume_cell_functional(physics, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, volume_quadrature);
669 
670  // Next looping over the faces of the cell checking for boundary elements
671  for(unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
672  auto face = cell->face(iface);
673 
674  if(face->at_boundary()){
675  const unsigned int boundary_id = face->boundary_id();
676  local_sum_new += evaluate_boundary_cell_functional(physics, boundary_id, soln_coeff, target_soln_coeff, fe_solution, coords_coeff, fe_metric, dg.face_quadrature_collection[i_quad], iface);
677  }
678 
679  }
680 
681  local_dIdX[idof] = (local_sum_new-local_sum_old)/stepsize;
682  }
683 
684  dIdX_FD.add(cell_metric_dofs_indices, local_dIdX);
685  }
686  // compress before the return
687  dIdX_FD.compress(dealii::VectorOperation::add);
688 
689  return dIdX_FD;
690 }
691 
697 
698 } // PHiLiP namespace
699 
std::shared_ptr< dealii::TrilinosWrappers::SparseMatrix > d2IdXdX
Sparse matrix for storing the functional partial second derivatives.
Definition: functional.h:128
const bool uses_solution_gradient
Will evaluate solution gradient at quadrature points.
Definition: functional.h:315
dealii::LinearAlgebra::distributed::Vector< real > dIdX
Vector for storing the derivatives with respect to each grid DoF.
Definition: functional.h:121
TargetFunctional base class.
const bool uses_solution_values
Will evaluate solution values at quadrature points.
Definition: functional.h:314
dealii::LinearAlgebra::distributed::Vector< real > dIdw
Vector for storing the derivatives with respect to each solution DoF.
Definition: functional.h:119
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
virtual real evaluate_boundary_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &, const unsigned int, const dealii::Point< dim, real > &, const dealii::Tensor< 1, dim, real > &, const std::array< real, nstate > &soln_at_q, const std::array< real, nstate > &target_soln_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &) const
Virtual function for computation of cell face functional term.
std::shared_ptr< dealii::TrilinosWrappers::SparseMatrix > d2IdWdW
Sparse matrix for storing the functional partial second derivatives.
Definition: functional.h:124
dealii::LinearAlgebra::distributed::Vector< real > evaluate_dIdX_finiteDifferences(DGBase< dim, real > &dg, const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const double stepsize)
virtual real evaluate_volume_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &, const dealii::Point< dim, real > &, const std::array< real, nstate > &soln_at_q, const std::array< real, nstate > &target_soln_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &, const std::array< dealii::Tensor< 1, dim, real >, nstate > &) const
Virtual function for computation of cell volume functional term.
Files for the baseline physics.
Definition: ADTypes.hpp:10
virtual real evaluate_functional(const bool compute_dIdW=false, const bool compute_dIdX=false, const bool compute_d2I=false) override
Evaluates the functional derivative with respect to the solution variable.
real2 evaluate_boundary_cell_functional(const Physics::PhysicsBase< dim, nstate, real2 > &physics, const unsigned int boundary_id, const std::vector< real2 > &soln_coeff, const std::vector< real > &target_soln_coeff, const dealii::FESystem< dim > &fe_solution, const std::vector< real2 > &coords_coeff, const dealii::FESystem< dim > &fe_metric, const dealii::Quadrature< dim-1 > &face_quadrature, const unsigned int face_number) const
Templated function to evaluate a cell&#39;s face functional.
void allocate_dIdX(dealii::LinearAlgebra::distributed::Vector< real > &dIdX) const
Allocate and setup the derivative dIdX vector.
Definition: functional.cpp:388
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
Definition: dg_base.hpp:409
TargetFunctional(std::shared_ptr< DGBase< dim, real >> dg_input, const bool uses_solution_values=true, const bool uses_solution_gradient=true)
Constructor.
Sacado::Fad::DFad< real > FadType
Sacado AD type for first derivatives.
dealii::hp::QCollection< dim-1 > face_quadrature_collection
Quadrature used to evaluate face integrals.
Definition: dg_base.hpp:610
const dealii::LinearAlgebra::distributed::Vector< real > target_solution
Solution used to evaluate target functional.
static std::shared_ptr< ModelBase< dim, nstate, real > > create_Model(const Parameters::AllParameters *const parameters_input)
Factory to return the correct model given input parameters.
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
Definition: dg_base.hpp:655
real2 evaluate_volume_cell_functional(const Physics::PhysicsBase< dim, nstate, real2 > &physics, const std::vector< real2 > &soln_coeff, const std::vector< real > &target_soln_coeff, const dealii::FESystem< dim > &fe_solution, const std::vector< real2 > &coords_coeff, const dealii::FESystem< dim > &fe_metric, const dealii::Quadrature< dim > &volume_quadrature) const
Templated function to evaluate a cell&#39;s volume functional.
dealii::LinearAlgebra::distributed::Vector< real > evaluate_dIdw_finiteDifferences(DGBase< dim, real > &dg, const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const double stepsize)
real current_functional_value
Store the functional value from the last time evaluate_functional() was called.
Definition: functional.h:116
static std::shared_ptr< PhysicsBase< dim, nstate, real > > create_Physics(const Parameters::AllParameters *const parameters_input, std::shared_ptr< ModelBase< dim, nstate, real > > model_input=nullptr)
Factory to return the correct physics given input file.
void need_compute(bool &compute_value, bool &compute_dIdW, bool &compute_dIdX, bool &compute_d2I)
Checks which derivatives actually need to be recomputed.
Definition: functional.cpp:690
dealii::DoFHandler< dim > dof_handler
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:652
Sacado::Fad::DFad< FadType > FadFadType
Sacado AD type that allows 2nd derivatives.
std::shared_ptr< Physics::PhysicsBase< dim, nstate, FadFadType > > physics_fad_fad
Physics that should correspond to the one in DGBase.
Definition: functional.h:54
std::shared_ptr< dealii::TrilinosWrappers::SparseMatrix > d2IdWdX
Sparse matrix for storing the functional partial second derivatives.
Definition: functional.h:126
Functional base class.
Definition: functional.h:43
std::shared_ptr< DGBase< dim, real, dealii::parallel::distributed::Triangulation< dim > > > dg
Smart pointer to DGBase.
Definition: functional.h:50
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
real1 norm(const dealii::Tensor< 1, dim, real1 > x)
Returns norm of dealii::Tensor<1,dim,real>
dealii::hp::QCollection< dim > volume_quadrature_collection
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:608
void allocate_derivatives(const bool compute_dIdW, const bool compute_dIdX, const bool compute_d2I)
Allocate and setup the derivative vectors/matrices.
Definition: functional.cpp:400
void set_derivatives(const bool compute_dIdW, const bool compute_dIdX, const bool compute_d2I, const Sacado::Fad::DFad< Sacado::Fad::DFad< real >> volume_local_sum, std::vector< dealii::types::global_dof_index > cell_soln_dofs_indices, std::vector< dealii::types::global_dof_index > cell_metric_dofs_indices)
Set the derivative vectors/matrices.
Definition: functional.cpp:436
const dealii::hp::FECollection< dim > fe_collection
Finite Element Collection for p-finite-element to represent the solution.
Definition: dg_base.hpp:597