[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
functional_dw_finiteDifferences.cpp
1 #include <stdlib.h> /* srand, rand */
2 #include <iostream>
3 
4 #include <deal.II/base/conditional_ostream.h>
5 
6 #include <deal.II/grid/grid_generator.h>
7 #include <deal.II/grid/grid_refinement.h>
8 #include <deal.II/grid/grid_tools.h>
9 
10 #include <deal.II/numerics/vector_tools.h>
11 
12 #include <Sacado.hpp>
13 
14 #include "physics/physics_factory.h"
15 #include "physics/manufactured_solution.h"
16 #include "parameters/all_parameters.h"
17 #include "parameters/parameters.h"
18 #include "ode_solver/ode_solver_factory.h"
19 #include "dg/dg_factory.hpp"
20 #include "functional/functional.h"
21 
22 const double STEPSIZE = 1e-7;
23 const double TOLERANCE = 1e-5;
24 
25 #if PHILIP_DIM==1
26  using Triangulation = dealii::Triangulation<PHILIP_DIM>;
27 #else
28  using Triangulation = dealii::parallel::distributed::Triangulation<PHILIP_DIM>;
29 #endif
30 
31 template <int dim, int nstate, typename real>
32 class L2_Norm_Functional : public PHiLiP::Functional<dim, nstate, real>
33 {
34  using FadType = Sacado::Fad::DFad<real>;
35  using FadFadType = Sacado::Fad::DFad<FadType>;
36 public:
39  std::shared_ptr<PHiLiP::DGBase<dim,real>> dg_input,
40  const bool uses_solution_values = true,
41  const bool uses_solution_gradient = false)
42  : PHiLiP::Functional<dim,nstate,real>(dg_input,uses_solution_values,uses_solution_gradient)
43  {}
44 
46  template <typename real2>
49  const dealii::Point<dim,real2> &phys_coord,
50  const std::array<real2,nstate> &soln_at_q,
51  const std::array<dealii::Tensor<1,dim,real2>,nstate> &/*soln_grad_at_q*/) const
52  {
53  real2 l2error = 0;
54  for (int istate=0; istate<nstate; ++istate) {
55  const real2 uexact = physics.manufactured_solution_function->value(phys_coord, istate);
56  l2error += std::pow(soln_at_q[istate] - uexact, 2);
57  }
58  return l2error;
59  }
60 
62 
63  template<typename real2>
66  const unsigned int /*boundary_id*/,
67  const dealii::Point<dim,real2> &phys_coord,
68  const dealii::Tensor<1,dim,real2> &/*normal*/,
69  const std::array<real2,nstate> &soln_at_q,
70  const std::array<dealii::Tensor<1,dim,real2>,nstate> &/*soln_grad_at_q*/) const
71  {
72  real2 l1error = 0;
73  for (int istate=0; istate<nstate; ++istate) {
74  const real2 uexact = physics.manufactured_solution_function->value(phys_coord, istate);
75  l1error += std::abs(soln_at_q[istate] - uexact);
76  }
77  return l1error;
78  }
79 
81 
84  const unsigned int boundary_id,
85  const dealii::Point<dim,real> &phys_coord,
86  const dealii::Tensor<1,dim,real> &normal,
87  const std::array<real,nstate> &soln_at_q,
88  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_at_q) const override
89  {
90  return evaluate_boundary_integrand<real>(
91  physics,
92  boundary_id,
93  phys_coord,
94  normal,
95  soln_at_q,
96  soln_grad_at_q);
97  }
99 
102  const unsigned int boundary_id,
103  const dealii::Point<dim,FadFadType> &phys_coord,
104  const dealii::Tensor<1,dim,FadFadType> &normal,
105  const std::array<FadFadType,nstate> &soln_at_q,
106  const std::array<dealii::Tensor<1,dim,FadFadType>,nstate> &soln_grad_at_q) const override
107  {
108  return evaluate_boundary_integrand<FadFadType>(
109  physics,
110  boundary_id,
111  phys_coord,
112  normal,
113  soln_at_q,
114  soln_grad_at_q);
115  }
116 
120  const dealii::Point<dim,real> &phys_coord,
121  const std::array<real,nstate> &soln_at_q,
122  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_at_q) const override
123  {
124  return evaluate_volume_integrand<real>(physics, phys_coord, soln_at_q, soln_grad_at_q);
125  }
129  const dealii::Point<dim,FadFadType> &phys_coord,
130  const std::array<FadFadType,nstate> &soln_at_q,
131  const std::array<dealii::Tensor<1,dim,FadFadType>,nstate> &soln_grad_at_q) const override
132  {
133  return evaluate_volume_integrand<FadFadType>(physics, phys_coord, soln_at_q, soln_grad_at_q);
134  }
135 
136 };
137 
138 
139 template <int dim, int nstate>
140 void initialize_perturbed_solution(PHiLiP::DGBase<dim,double> &dg, const PHiLiP::Physics::PhysicsBase<dim,nstate,double> &physics)
141 {
142  dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
143  solution_no_ghost.reinit(dg.locally_owned_dofs, MPI_COMM_WORLD);
144  dealii::VectorTools::interpolate(dg.dof_handler, *physics.manufactured_solution_function, solution_no_ghost);
145  dg.solution = solution_no_ghost;
146 }
147 
148 int main(int argc, char *argv[])
149 {
150 
151  const int dim = PHILIP_DIM;
152  const int nstate = 1;
153  int fail_bool = false;
154 
155  // Initializing MPI
156  dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
157  const int this_mpi_process = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
158  dealii::ConditionalOStream pcout(std::cout, this_mpi_process==0);
159 
160  // Initializing parameter handling
161  dealii::ParameterHandler parameter_handler;
163  PHiLiP::Parameters::AllParameters all_parameters;
164  all_parameters.parse_parameters(parameter_handler);
165 
166  // polynomial order and mesh size
167  const unsigned poly_degree = 1;
168 
169  // creating the grid
170  std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation>(
171 #if PHILIP_DIM!=1
172  MPI_COMM_WORLD,
173 #endif
174  typename dealii::Triangulation<dim>::MeshSmoothing(
175  dealii::Triangulation<dim>::smoothing_on_refinement |
176  dealii::Triangulation<dim>::smoothing_on_coarsening));
177 
178  const unsigned int n_refinements = 2;
179  double left = 0.0;
180  double right = 2.0;
181  const bool colorize = true;
182 
183  dealii::GridGenerator::hyper_cube(*grid, left, right, colorize);
184  grid->refine_global(n_refinements);
185  const double random_factor = 0.2;
186  const bool keep_boundary = false;
187  if (random_factor > 0.0) dealii::GridTools::distort_random (random_factor, *grid, keep_boundary);
188 
189  dealii::Point<dim> center;
190  double inner_radius = 0.5;
191  double outer_radius = 1.5;
192  grid->clear();
193  dealii::GridGenerator::hyper_shell(*grid, center, inner_radius, outer_radius);
194  grid->refine_global();
195 
196  pcout << "Grid generated and refined" << std::endl;
197 
198  // creating the dg
199  std::shared_ptr < PHiLiP::DGBase<dim, double> > dg = PHiLiP::DGFactory<dim,double>::create_discontinuous_galerkin(&all_parameters, poly_degree, grid);
200  pcout << "dg created" << std::endl;
201 
202  dg->allocate_system();
203  pcout << "dg allocated" << std::endl;
204 
205  const int n_refine = 2;
206  for (int i=0; i<n_refine;i++) {
207  dg->high_order_grid->prepare_for_coarsening_and_refinement();
208  grid->prepare_coarsening_and_refinement();
209  unsigned int icell = 0;
210  for (auto cell = grid->begin_active(); cell!=grid->end(); ++cell) {
211  icell++;
212  if (!cell->is_locally_owned()) continue;
213  if (icell < grid->n_global_active_cells()/2) {
214  cell->set_refine_flag();
215  }
216  }
217  grid->execute_coarsening_and_refinement();
218  bool mesh_out = (i==n_refine-1);
219  dg->high_order_grid->execute_coarsening_and_refinement(mesh_out);
220  }
221  dg->allocate_system ();
222 
223  // manufactured solution function
224  using FadType = Sacado::Fad::DFad<double>;
225  std::shared_ptr <PHiLiP::Physics::PhysicsBase<dim,nstate,double>> physics_double = PHiLiP::Physics::PhysicsFactory<dim, nstate, double>::create_Physics(&all_parameters);
226  pcout << "Physics created" << std::endl;
227 
228  // performing the interpolation for the intial conditions
229  initialize_perturbed_solution(*dg, *physics_double);
230  pcout << "solution initialized" << std::endl;
231 
232  // evaluating the derivative (using SACADO)
233  pcout << std::endl << "Starting AD... " << std::endl;
234  L2_Norm_Functional<dim,nstate,double> l2norm(dg,true,false);
235  double l2error_mpi_sum2 = std::sqrt(l2norm.evaluate_functional(true,true));
236 
237  dealii::LinearAlgebra::distributed::Vector<double> dIdw = l2norm.dIdw;
238  dealii::LinearAlgebra::distributed::Vector<double> dIdX = l2norm.dIdX;
239 
240  pcout << std::endl << "Overall error (its ok that it's high since we have extraneous boundary terms): " << l2error_mpi_sum2 << std::endl;
241 
242  // evaluating the derivative (using finite differences)
243  pcout << std::endl << "Starting FD dIdW... " << std::endl;
244  dealii::LinearAlgebra::distributed::Vector<double> dIdw_FD = l2norm.evaluate_dIdw_finiteDifferences(*dg, *physics_double, STEPSIZE);
245  // dIdw_FD.print(std::cout);
246 
247  pcout << std::endl << "Starting FD dIdX... " << std::endl;
248  dealii::LinearAlgebra::distributed::Vector<double> dIdX_FD = l2norm.evaluate_dIdX_finiteDifferences(*dg, *physics_double, STEPSIZE);
249 
250  // comparing the results and checking its within the specified tolerance
251  dealii::LinearAlgebra::distributed::Vector<double> dIdw_difference = dIdw;
252  pcout << "L2 norm of AD dIdW: " << dIdw.l2_norm();
253  pcout << "L2 norm of FD dIdW: " << dIdw_FD.l2_norm();
254  dIdw_difference -= dIdw_FD;
255  double dIdW_L2_diff = dIdw_difference.l2_norm();
256  pcout << "L2 norm of FD-AD dIdW: " << dIdW_L2_diff << std::endl;
257 
258  // comparing the results and checking its within the specified tolerance
259  dealii::LinearAlgebra::distributed::Vector<double> dIdX_difference = dIdX;
260  dIdX_difference -= dIdX_FD;
261  double dIdX_L2_diff = dIdX_difference.l2_norm();
262  pcout << "L2 norm of FD-AD dIdX: " << dIdX_L2_diff << std::endl;
263 
264  fail_bool = dIdW_L2_diff > TOLERANCE || dIdX_L2_diff > TOLERANCE;
265  return fail_bool;
266 }
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
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
real2 evaluate_volume_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real2 > &physics, const dealii::Point< dim, real2 > &phys_coord, const std::array< real2, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, real2 >, nstate > &) const
Templated L2 norm integrand.
virtual FadFadType evaluate_boundary_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, FadFadType > &physics, const unsigned int boundary_id, const dealii::Point< dim, FadFadType > &phys_coord, const dealii::Tensor< 1, dim, FadFadType > &normal, const std::array< FadFadType, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, FadFadType >, nstate > &soln_grad_at_q) const override
Virtual function for Sacado computation of cell boundary functional term and derivatives.
FadFadType evaluate_volume_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, FadFadType > &physics, const dealii::Point< dim, FadFadType > &phys_coord, const std::array< FadFadType, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, FadFadType >, nstate > &soln_grad_at_q) const override
non-template functions to override the template classes
Files for the baseline physics.
Definition: ADTypes.hpp:10
Main parameter class that contains the various other sub-parameter classes.
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
Definition: dg_base.hpp:409
dealii::IndexSet locally_owned_dofs
Locally own degrees of freedom.
Definition: dg_base.hpp:398
L2_Norm_Functional(std::shared_ptr< PHiLiP::DGBase< dim, real >> dg_input, const bool uses_solution_values=true, const bool uses_solution_gradient=false)
Constructor.
Sacado::Fad::DFad< real > FadType
Sacado AD type for first derivatives.
static std::shared_ptr< DGBase< dim, real, MeshType > > create_discontinuous_galerkin(const Parameters::AllParameters *const parameters_input, const unsigned int degree, const unsigned int max_degree_input, const unsigned int grid_degree_input, const std::shared_ptr< Triangulation > triangulation_input)
Creates a derived object DG, but returns it as DGBase.
Definition: dg_factory.cpp:10
dealii::LinearAlgebra::distributed::Vector< real > evaluate_dIdw_finiteDifferences(DGBase< dim, real, dealii::parallel::distributed::Triangulation< dim > > &dg, const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const double stepsize)
Definition: functional.cpp:984
real evaluate_volume_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const dealii::Point< dim, real > &phys_coord, const std::array< real, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &soln_grad_at_q) const override
non-template functions to override the template classes
dealii::LinearAlgebra::distributed::Vector< real > evaluate_dIdX_finiteDifferences(DGBase< dim, real, dealii::parallel::distributed::Triangulation< dim > > &dg, const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const double stepsize)
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.
Functional(std::shared_ptr< PHiLiP::DGBase< dim, real, dealii::parallel::distributed::Triangulation< dim > >> _dg, const bool _uses_solution_values=true, const bool _uses_solution_gradient=true)
void parse_parameters(dealii::ParameterHandler &prm)
Retrieve parameters from dealii::ParameterHandler.
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.
Functional base class.
Definition: functional.h:43
static void declare_parameters(dealii::ParameterHandler &prm)
Declare parameters that can be set as inputs and set up the default options.
virtual real evaluate_boundary_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const unsigned int boundary_id, const dealii::Point< dim, real > &phys_coord, const dealii::Tensor< 1, dim, real > &normal, const std::array< real, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &soln_grad_at_q) const override
Virtual function for computation of cell boundary functional term.
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
std::shared_ptr< ManufacturedSolutionFunction< dim, real > > manufactured_solution_function
Manufactured solution function.
Definition: physics.h:71
virtual real evaluate_functional(const bool compute_dIdW=false, const bool compute_dIdX=false, const bool compute_d2I=false)
Evaluates the functional derivative with respect to the solution variable.
Definition: functional.cpp:795
real2 evaluate_boundary_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real2 > &physics, const unsigned int, const dealii::Point< dim, real2 > &phys_coord, const dealii::Tensor< 1, dim, real2 > &, const std::array< real2, nstate > &soln_at_q, const std::array< dealii::Tensor< 1, dim, real2 >, nstate > &) const
Virtual function for computation of cell boundary functional term.
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
Definition: functional.h:317