[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
optimization_inverse_manufactured.cpp
1 #include <Epetra_RowMatrixTransposer.h>
2 
3 #include <stdlib.h>
4 #include <iostream>
5 
6 #include <deal.II/distributed/tria.h>
7 #include <deal.II/distributed/grid_refinement.h>
8 
9 #include <deal.II/grid/grid_generator.h>
10 #include <deal.II/grid/grid_tools.h>
11 
12 #include <deal.II/numerics/vector_tools.h>
13 
14 #include <deal.II/lac/solver_bicgstab.h>
15 #include <deal.II/lac/solver_cg.h>
16 #include <deal.II/lac/solver_gmres.h>
17 #include <deal.II/lac/solver_minres.h>
18 
19 #include <deal.II/lac/full_matrix.h>
20 
21 #include <deal.II/lac/trilinos_block_sparse_matrix.h>
22 #include <deal.II/lac/trilinos_precondition.h>
23 #include <deal.II/lac/trilinos_solver.h>
24 #include <deal.II/lac/trilinos_sparsity_pattern.h>
25 #include <deal.II/lac/trilinos_sparse_matrix.h>
26 
27 #include <deal.II/lac/trilinos_parallel_block_vector.h>
28 #include <deal.II/lac/la_parallel_block_vector.h>
29 #include <deal.II/lac/read_write_vector.h>
30 
31 #include <deal.II/lac/packaged_operation.h>
32 #include <deal.II/lac/trilinos_linear_operator.h>
33 
34 #include "optimization_inverse_manufactured.h"
35 
36 #include "physics/physics_factory.h"
37 #include "physics/physics.h"
38 #include "dg/dg_factory.hpp"
39 #include "ode_solver/ode_solver_factory.h"
40 
41 #include "functional/target_functional.h"
42 #include "functional/adjoint.h"
43 
44 #include "linear_solver/linear_solver.h"
45 
46 #include "testing/full_space_optimization.h"
47 
48 #include <list>
49 
50 namespace PHiLiP {
51 namespace Tests {
52 
53 #define AMPLITUDE_OPT 0.1
54 //#define HESSIAN_DIAG 1e7
55 #define HESSIAN_DIAG 1e0
56 
57 
58 template<int dim>
59 dealii::Point<dim> reverse_deformation(dealii::Point<dim> point) {
60  dealii::Point<dim> new_point = point;
61  const double amplitude = AMPLITUDE_OPT;
62  double denom = amplitude;
63  if(dim>=2) {
64  denom *= std::sin(2.0*dealii::numbers::PI*point[1]);
65  }
66  if(dim>=3) {
67  denom *= std::sin(2.0*dealii::numbers::PI*point[2]);
68  }
69  denom += 1.0;
70  new_point[0] /= denom;
71  return new_point;
72 }
73 template<int dim>
74 dealii::Point<dim> target_deformation(dealii::Point<dim> point) {
75  const double amplitude = AMPLITUDE_OPT;
76  dealii::Tensor<1,dim,double> disp;
77  disp[0] = amplitude;
78  disp[0] *= point[0];
79  if(dim>=2) {
80  disp[0] *= std::sin(2.0*dealii::numbers::PI*point[1]);
81  }
82  if(dim>=3) {
83  disp[0] *= std::sin(2.0*dealii::numbers::PI*point[2]);
84  }
85  return point + disp;
86 }
87 
88 // class SplineY
89 // {
90 // private:
91 // double getbij(const double x, const unsigned int i, const unsigned int j) const
92 // {
93 // if (j==0) {
94 // if (knots[i] <= x && x < knots[i+1]) return 1;
95 // else return 0;
96 // }
97 //
98 // double h = getbij(x, i, j-1);
99 // double k = getbij(x, i+1, j-1);
100 //
101 // double bij = 0;
102 //
103 // if (h!=0) bij += (x - knots[i]) / (knots[i+j] - knots[i] ) * h;
104 // if (k!=0) bij += (knots[i+j+1] - x ) / (knots[i+j+1] - knots[i+1]) * k;
105 //
106 // return bij;
107 // }
108 // public:
109 // const unsigned int n_design;
110 // const unsigned int spline_degree;
111 // const unsigned int n_control_pts; // n_design + 2
112 // const unsigned int n_knots; // n_control_pts + spline_degree + 1;
113 //
114 // const double x_start, x_end;
115 //
116 // std::vector<double> knots;
117 // std::vector<double> control_pts;
118 //
119 // SplineY(const unsigned int n_design, const unsigned int spline_degree, const double x_start, const double x_end)
120 // : n_design(n_design)
121 // , spline_degree(spline_degree)
122 // , n_control_pts(n_design+2)
123 // , n_knots(n_control_pts + spline_degree + 1)
124 // , x_start(x_start)
125 // , x_end(x_end)
126 // {
127 // knots = getKnots(n_knots, spline_degree, x_start, x_end);
128 // };
129 //
130 // template<typename real>
131 // std::vector<real> evalSpline(const std::vector<real> &x) const
132 // {
133 // const unsigned int nx = x.size();
134 // std::vector<real> value(nx, 0);
135 // for (unsigned int ix = 0; ix < nx; ix++) {
136 // for (unsigned int ictl = 0; ictl < n_control_pts; ictl++) {
137 // value[ix] += control_pts[ictl] * getbij(x[ix], ictl, spline_degree);
138 // }
139 // }
140 // return value;
141 // }
142 // template<typename real, typename MatrixType>
143 // MatrixType eval_dVal_dDesign(const std::vector<real> &x) const
144 // {
145 // const unsigned int nx = x.size();
146 //
147 // MatrixType dArea_dSpline = evalSplineDerivative(x);
148 //
149 // const unsigned int block_start_i = 0;
150 // const unsigned int block_start_j = 0;
151 // const unsigned int i_size = nx;
152 // const unsigned int j_size = n_design;
153 // return dArea_dSpline.block(block_start_i, block_start_j, i_size, j_size); // Do not return the endpoints
154 // }
155 // // now returns dSdCtl instead of dSdDesign (nctl = ndes+2)
156 // template<typename real, typename MatrixType>
157 // MatrixType evalSplineDerivative(const std::vector<real> &x) const
158 // {
159 // const int nx = x.size();
160 // MatrixType dSdCtl(nx, n_control_pts);
161 // dSdCtl.setZero();
162 //
163 // // Define Area at i+1/2
164 // for (int Si = 0; Si < nx; Si++) {
165 // //if (Si < n_elem) xh = x[Si] - dx[Si] / 2.0;
166 // //else xh = 1.0;
167 // const real xh = x[Si];
168 // for (int ictl = 0; ictl < n_control_pts; ictl++) {// Not including the inlet/outlet
169 // dSdCtl(Si, ictl) += getbij(xh, ictl, spline_degree);
170 // }
171 // }
172 // return dSdCtl;
173 // }
174 //
175 // //std::vector<dreal> fit_bspline(
176 // // const std::vector<double> &x,
177 // // const std::vector<double> &dx,
178 // // const std::vector<dreal> &area,
179 // // const int n_control_pts,
180 // // const int spline_degree)
181 // //{
182 // // int n_face = x.size();
183 // // // Get Knot Vector
184 // // int nknots = n_control_pts + spline_degree + 1;
185 // // std::vector<double> knots(nknots);
186 // // const double x_start = 0.0;
187 // // const double x_end = 1.0;
188 // // knots = getKnots(nknots, spline_degree, x_start, x_end);
189 //
190 // // VectorXd ctl_pts(n_control_pts), s_eig(n_face);
191 // // MatrixXd A(n_face, n_control_pts);
192 // // A.setZero();
193 // //
194 // // //double xend = 1.0;
195 // // for (int iface = 0; iface < n_face; iface++) {
196 // // //if (iface < n_elem) xh = x[iface] - dx[iface] / 2.0;
197 // // //else xh = xend;
198 // // const double xh = x[iface];
199 // // s_eig(iface) = area[iface];
200 // // for (int ictl = 0; ictl < n_control_pts; ictl++)
201 // // {
202 // // A(iface, ictl) = getbij(xh, ictl, spline_degree, knots);
203 // // }
204 // // }
205 // // // Solve least square to fit bspline onto sine parametrization
206 // // ctl_pts = A.jacobiSvd(ComputeThinU | ComputeThinV).solve(s_eig);
207 // //
208 // // std::vector<dreal> ctlpts(n_control_pts);
209 // // for (int ictl = 0; ictl < n_control_pts; ictl++)
210 // // {
211 // // ctlpts[ictl] = ctl_pts(ictl);
212 // // }
213 // // //ctlpts[0] = area[0];
214 // // //ctlpts[n_control_pts - 1] = area[n_elem];
215 //
216 // // return ctlpts;
217 // //}
218 // private:
219 // std::vector<double> getKnots(
220 // const unsigned int n_knots,
221 // const unsigned int spline_degree,
222 // const double grid_xstart,
223 // const double grid_xend) const
224 // {
225 // std::vector<double> knots(n_knots);
226 // const unsigned int nb_outer = 2 * (spline_degree + 1);
227 // const unsigned int nb_inner = n_knots - nb_outer;
228 // double eps = 2e-15; // Allow Spline Definition at End Point
229 // // Clamped Open-Ended
230 // for (unsigned int iknot = 0; iknot < spline_degree + 1; iknot++) {
231 // knots[iknot] = grid_xstart;
232 // knots[n_knots - iknot - 1] = grid_xend + eps;
233 // }
234 // // Uniform Knot Vector
235 // double knot_dx = (grid_xend + eps - grid_xstart) / (nb_inner + 1);
236 // for (unsigned int iknot = 1; iknot < nb_inner+1; iknot++) {
237 // knots[iknot + spline_degree] = iknot * knot_dx;
238 // }
239 // return knots;
240 // }
241 // };
242 
243 
247 template <int dim, int nstate, typename real>
248 class BoundaryInverseTarget : public TargetFunctional<dim, nstate, real>
249 {
250  using FadType = Sacado::Fad::DFad<real>;
251  using FadFadType = Sacado::Fad::DFad<FadType>;
252 
254 
259 
260 public:
263  std::shared_ptr<DGBase<dim,real>> dg_input,
264  const dealii::LinearAlgebra::distributed::Vector<real> &target_solution,
265  const bool uses_solution_values = true,
266  const bool uses_solution_gradient = true)
267  : TargetFunctional<dim,nstate,real>(dg_input, target_solution, uses_solution_values, uses_solution_gradient)
268  {}
269 
271  template <typename real2>
274  const dealii::Point<dim,real2> &/*phys_coord*/,
275  const std::array<real2,nstate> &,//soln_at_q,
276  const std::array<real,nstate> &,//target_soln_at_q,
277  const std::array<dealii::Tensor<1,dim,real2>,nstate> &/*soln_grad_at_q*/,
278  const std::array<dealii::Tensor<1,dim,real2>,nstate> &/*target_soln_grad_at_q*/) const
279  {
280  real2 l2error = 0;
281 
282  return l2error;
283  }
284 
288  const dealii::Point<dim,real> &phys_coord,
289  const std::array<real,nstate> &soln_at_q,
290  const std::array<real,nstate> &target_soln_at_q,
291  const std::array<dealii::Tensor<1,dim,real>,nstate> &soln_grad_at_q,
292  const std::array<dealii::Tensor<1,dim,real>,nstate> &target_soln_grad_at_q) const override
293  {
294  return evaluate_volume_integrand<>(physics, phys_coord, soln_at_q, target_soln_at_q, soln_grad_at_q, target_soln_grad_at_q);
295  }
299  const dealii::Point<dim,FadFadType> &phys_coord,
300  const std::array<FadFadType,nstate> &soln_at_q,
301  const std::array<real,nstate> &target_soln_at_q,
302  const std::array<dealii::Tensor<1,dim,FadFadType>,nstate> &soln_grad_at_q,
303  const std::array<dealii::Tensor<1,dim,FadFadType>,nstate> &target_soln_grad_at_q) const override
304  {
305  return evaluate_volume_integrand<>(physics, phys_coord, soln_at_q, target_soln_at_q, soln_grad_at_q, target_soln_grad_at_q);
306  }
307 };
308 
309 template <int dim, int nstate>
311  :
312  TestsBase::TestsBase(parameters_input)
313 {}
314 
315 template <int dim, int nstate>
316 void initialize_perturbed_solution(PHiLiP::DGBase<dim,double> &dg, const PHiLiP::Physics::PhysicsBase<dim,nstate,double> &physics)
317 {
318  dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
319  solution_no_ghost.reinit(dg.locally_owned_dofs, MPI_COMM_WORLD);
320  dealii::VectorTools::interpolate(dg.dof_handler, *physics.manufactured_solution_function, solution_no_ghost);
321  dg.solution = solution_no_ghost;
322 }
323 
324 template<int dim, int nstate>
326 ::run_test () const
327 {
328  const double amplitude = AMPLITUDE_OPT;
329  const int poly_degree = 1;
330  int fail_bool = false;
331  pcout << " Running optimization case... " << std::endl;
332 
333  // *****************************************************************************
334  // Create target mesh
335  // *****************************************************************************
336  //const unsigned int initial_n_cells = 10;
337  const unsigned int initial_n_cells = 4;
338 
339 #if PHILIP_DIM==1
340  using Triangulation = dealii::Triangulation<dim>;
341 #else
342  using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
343 #endif
344 
345  std::shared_ptr <Triangulation> grid = std::make_shared<Triangulation> (
346 #if PHILIP_DIM!=1
347  this->mpi_communicator,
348 #endif
349  typename dealii::Triangulation<dim>::MeshSmoothing(
350  dealii::Triangulation<dim>::smoothing_on_refinement |
351  dealii::Triangulation<dim>::smoothing_on_coarsening));
352 
353  dealii::GridGenerator::subdivided_hyper_cube(*grid, initial_n_cells);
354  for (auto cell = grid->begin_active(); cell != grid->end(); ++cell) {
355  // Set a dummy boundary ID
356  cell->set_material_id(9002);
357  for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
358  if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
359  }
360  }
361 
362  // Create DG from which we'll modify the HighOrderGrid
363  std::shared_ptr < PHiLiP::DGBase<dim, double> > dg = PHiLiP::DGFactory<dim,double>::create_discontinuous_galerkin(all_parameters, poly_degree, grid);
364  dg->allocate_system ();
365 
366  std::shared_ptr<HighOrderGrid<dim,double>> high_order_grid = dg->high_order_grid;
367 #if PHILIP_DIM!=1
368  high_order_grid->prepare_for_coarsening_and_refinement();
369  grid->repartition();
370  high_order_grid->execute_coarsening_and_refinement();
371  high_order_grid->output_results_vtk(high_order_grid->nth_refinement++);
372 #endif
373 
374  // *****************************************************************************
375  // Prescribe surface displacements
376  // *****************************************************************************
377  std::vector<dealii::Tensor<1,dim,double>> point_displacements(high_order_grid->locally_relevant_surface_points.size());
378  const unsigned int n_locally_relevant_surface_nodes = dim * high_order_grid->locally_relevant_surface_points.size();
379  std::vector<dealii::types::global_dof_index> surface_node_global_indices(n_locally_relevant_surface_nodes);
380  std::vector<double> surface_node_displacements(n_locally_relevant_surface_nodes);
381  {
382  auto displacement = point_displacements.begin();
383  auto point = high_order_grid->locally_relevant_surface_points.begin();
384  auto point_end = high_order_grid->locally_relevant_surface_points.end();
385  for (;point != point_end; ++point, ++displacement) {
386  (*displacement)[0] = amplitude * (*point)[0];
387  if(dim>=2) {
388  (*displacement)[0] *= std::sin(2.0*dealii::numbers::PI*(*point)[1]);
389  }
390  if(dim>=3) {
391  (*displacement)[0] *= std::sin(2.0*dealii::numbers::PI*(*point)[2]);
392  }
393  }
394  int inode = 0;
395  for (unsigned int ipoint=0; ipoint<point_displacements.size(); ++ipoint) {
396  for (unsigned int d=0;d<dim;++d) {
397  const std::pair<unsigned int, unsigned int> point_axis = std::make_pair(ipoint,d);
398  const dealii::types::global_dof_index global_index = high_order_grid->point_and_axis_to_global_index[point_axis];
399  surface_node_global_indices[inode] = global_index;
400  surface_node_displacements[inode] = point_displacements[ipoint][d];
401  inode++;
402  }
403  }
404  }
405  const auto initial_grid = high_order_grid->volume_nodes;
406  // *****************************************************************************
407  // Obtain target grid
408  // *****************************************************************************
409  using VectorType = dealii::LinearAlgebra::distributed::Vector<double>;
410  std::function<dealii::Point<dim>(dealii::Point<dim>)> target_transformation = target_deformation<dim>;
411  VectorType surface_node_displacements_vector = high_order_grid->transform_surface_nodes(target_transformation);
412  surface_node_displacements_vector -= high_order_grid->surface_nodes;
413  surface_node_displacements_vector.update_ghost_values();
414 
415 
416  // const unsigned int n_design = 10;
417  // const unsigned int spline_degree = 2;
418  // const double y_start = 0.0, y_end = 0.0;
419  // SplineY spline(n_design, spline_degree, y_start, y_end);
420  // auto x_displacements = spline.evalSpline(y_locations);
421 
422  MeshMover::LinearElasticity<dim, double> meshmover(*high_order_grid, surface_node_displacements_vector);
423  VectorType volume_displacements = meshmover.get_volume_displacements();
424 
425  high_order_grid->volume_nodes += volume_displacements;
426  high_order_grid->volume_nodes.update_ghost_values();
427  high_order_grid->update_surface_nodes();
428  //{
429  // std::function<dealii::Point<dim>(dealii::Point<dim>)> reverse_transformation = reverse_deformation<dim>;
430  // surface_node_displacements_vector = high_order_grid->transform_surface_nodes(reverse_transformation);
431  // surface_node_displacements_vector -= high_order_grid->surface_nodes;
432  // surface_node_displacements_vector.update_ghost_values();
433  // volume_displacements = meshmover.get_volume_displacements();
434  //}
435  //high_order_grid->volume_nodes += volume_displacements;
436  //high_order_grid->volume_nodes.update_ghost_values();
437  //high_order_grid->update_surface_nodes();
438 
439  // Get discrete solution on this target grid
440  std::shared_ptr <PHiLiP::Physics::PhysicsBase<dim,nstate,double>> physics_double = PHiLiP::Physics::PhysicsFactory<dim, nstate, double>::create_Physics(all_parameters);
441  initialize_perturbed_solution(*dg, *physics_double);
442  dg->output_results_vtk(999);
443  high_order_grid->output_results_vtk(high_order_grid->nth_refinement++);
444  std::shared_ptr<ODE::ODESolverBase<dim, double>> ode_solver = ODE::ODESolverFactory<dim, double>::create_ODESolver(dg);
445  ode_solver->steady_state();
446 
447  // Save target solution and volume_nodes
448  const auto target_solution = dg->solution;
449  const auto target_nodes = high_order_grid->volume_nodes;
450 
451  pcout << "Target grid: " << std::endl;
452  dg->output_results_vtk(9999);
453  high_order_grid->output_results_vtk(9999);
454 
455  // *****************************************************************************
456  // Get back our square mesh through mesh deformation
457  // *****************************************************************************
458  {
459  auto displacement = point_displacements.begin();
460  auto point = high_order_grid->locally_relevant_surface_points.begin();
461  auto point_end = high_order_grid->locally_relevant_surface_points.end();
462  for (;point != point_end; ++point, ++displacement) {
463  if ((*point)[0] > 0.5 && (*point)[1] > 1e-10 && (*point)[1] < 1-1e-10) {
464  const double final_location = 1.0;
465  const double current_location = (*point)[0];
466  (*displacement)[0] = final_location - current_location;
467  }
468 
469  // (*displacement)[0] = (*point)[0] * 0.5 - (*point)[0];
470  // (*displacement)[1] = (*point)[1] * 0.9 - (*point)[1];
471  }
472  int inode = 0;
473  for (unsigned int ipoint=0; ipoint<point_displacements.size(); ++ipoint) {
474  for (unsigned int d=0;d<dim;++d) {
475  const std::pair<unsigned int, unsigned int> point_axis = std::make_pair(ipoint,d);
476  const dealii::types::global_dof_index global_index = high_order_grid->point_and_axis_to_global_index[point_axis];
477  surface_node_global_indices[inode] = global_index;
478  surface_node_displacements[inode] = point_displacements[ipoint][d];
479  inode++;
480  }
481  }
482  }
483 
484  //{
485  // std::function<dealii::Point<dim>(dealii::Point<dim>)> reverse_transformation = reverse_deformation<dim>;
486  // surface_node_displacements_vector = high_order_grid->transform_surface_nodes(reverse_transformation);
487  // surface_node_displacements_vector -= high_order_grid->surface_nodes;
488  // surface_node_displacements_vector.update_ghost_values();
489  // volume_displacements = meshmover.get_volume_displacements();
490  //}
491  //high_order_grid->volume_nodes += volume_displacements;
492  //high_order_grid->volume_nodes.update_ghost_values();
493  //high_order_grid->update_surface_nodes();
494 
495  high_order_grid->volume_nodes = initial_grid;
496  high_order_grid->volume_nodes.update_ghost_values();
497  high_order_grid->update_surface_nodes();
498  pcout << "Initial grid: " << std::endl;
499  dg->output_results_vtk(9998);
500  high_order_grid->output_results_vtk(9998);
501 
502  // Solve on this new grid
503  ode_solver->steady_state();
504 
505  // Compute current error
506  auto error_vector = dg->solution;
507  error_vector -= target_solution;
508  const double l2_vector_error = error_vector.l2_norm();
509 
510  BoundaryInverseTarget<dim,nstate,double> inverse_target_functional(dg, target_solution, true, false);
511  bool compute_dIdW = false, compute_dIdX = false, compute_d2I = true;
512  const double current_l2_error = inverse_target_functional.evaluate_functional(compute_dIdW, compute_dIdX, compute_d2I);
513  pcout << "Vector l2_norm of the coefficients: " << l2_vector_error << std::endl;
514  pcout << "Functional l2_norm : " << current_l2_error << std::endl;
515 
516  pcout << "*************************************************************" << std::endl;
517  pcout << "Starting design... " << std::endl;
518  pcout << "Number of state variables: " << dg->dof_handler.n_dofs() << std::endl;
519  pcout << "Number of mesh volume_nodes: " << high_order_grid->dof_handler_grid.n_dofs() << std::endl;
520  pcout << "Number of constraints: " << dg->dof_handler.n_dofs() << std::endl;
521 
522  const dealii::IndexSet surface_locally_owned_indexset = high_order_grid->surface_nodes.locally_owned_elements();
523  dealii::TrilinosWrappers::SparseMatrix dRdXs;
524  dealii::TrilinosWrappers::SparseMatrix d2LdWdXs;
525  dealii::TrilinosWrappers::SparseMatrix d2LdXsdXs;
526  // Analytical dXvdXs
527  meshmover.evaluate_dXvdXs();
528 
529  VectorType dIdXs;
530  dIdXs.reinit(dg->high_order_grid->surface_nodes);
531 
532  auto grad_lagrangian = dIdXs;
533 
534  // Assemble KKT rhs
535  dealii::LinearAlgebra::distributed::BlockVector<double> kkt_rhs(3);
536  pcout << "Evaluating KKT right-hand side: dIdW, dIdX, d2I, Residual..." << std::endl;
537  compute_dIdW = true, compute_dIdX = true, compute_d2I = true;
538  (void) inverse_target_functional.evaluate_functional(compute_dIdW, compute_dIdX, compute_d2I);
539  bool compute_dRdW = false, compute_dRdX = false, compute_d2R = false;
540  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
541  for (unsigned int isurf = 0; isurf < dg->high_order_grid->surface_nodes.size(); ++isurf) {
542  const auto scalar_product = meshmover.dXvdXs[isurf] * inverse_target_functional.dIdX;
543  if (dIdXs.locally_owned_elements().is_element(isurf)) {
544  dIdXs[isurf] = scalar_product;
545  }
546  }
547  dIdXs.update_ghost_values();
548 
549  kkt_rhs.block(0) = inverse_target_functional.dIdw;
550  kkt_rhs.block(1) = dIdXs;
551  kkt_rhs.block(2) = dg->right_hand_side;
552  kkt_rhs *= -1.0;
553 
554  dealii::LinearAlgebra::distributed::BlockVector<double> kkt_soln(3), p4inv_kkt_rhs(3);
555  kkt_soln.reinit(kkt_rhs);
556  p4inv_kkt_rhs.reinit(kkt_rhs);
557 
558  auto mesh_error = target_nodes;
559  mesh_error -= high_order_grid->volume_nodes;
560 
561  double current_functional = inverse_target_functional.current_functional_value;
562  double current_kkt_norm = kkt_rhs.l2_norm();
563  double current_constraint_satisfaction = kkt_rhs.block(2).l2_norm();
564  double current_mesh_error = mesh_error.l2_norm();
565  pcout << std::scientific << std::setprecision(5);
566  pcout << "*************************************************************" << std::endl;
567  pcout << "Initial design " << std::endl;
568  pcout << "*************************************************************" << std::endl;
569  pcout << "Current functional: " << current_functional << std::endl;
570  pcout << "Constraint satisfaction: " << current_constraint_satisfaction << std::endl;
571  pcout << "l2norm(Current mesh - optimal mesh): " << current_mesh_error << std::endl;
572  pcout << "Current KKT norm: " << current_kkt_norm << std::endl;
573  //pcout << std::fixed << std::setprecision(6);
574 
575  const unsigned int n_des_var = high_order_grid->surface_nodes.size();
576  dealii::FullMatrix<double> Hessian_inverse = dealii::IdentityMatrix(n_des_var);
577  const double diagonal_hessian = HESSIAN_DIAG;
578  Hessian_inverse *= 1.0/diagonal_hessian;
579  dealii::Vector<double> oldg(n_des_var), currentg(n_des_var), searchD(n_des_var);
580 
581  const bool use_BFGS = true;
582  const unsigned int bfgs_max_history = n_des_var;
583  const unsigned int n_max_design = 1000;
584  const double kkt_tolerance = 1e-10;
585 
586  // Initialize Lagrange multipliers to zero
587  dg->set_dual(kkt_soln.block(2));
588 
589  std::list<VectorType> bfgs_search_s;
590  std::list<VectorType> bfgs_dgrad_y;
591  std::list<double> bfgs_denom_rho;
592 
593  // Conventional design optimization
594  {
595  // Solve the flow
596  ode_solver->steady_state();
597 
598  // Analytical dXvdXs
599  meshmover.evaluate_dXvdXs();
600 
601  // Functional derivatives
602  pcout << "Evaluating KKT right-hand side: dIdW, dIdX, Residual..." << std::endl;
603  bool compute_dIdW = true, compute_dIdX = true, compute_d2I = false;
604  (void) inverse_target_functional.evaluate_functional(compute_dIdW, compute_dIdX, compute_d2I);
605  compute_dRdW = false, compute_dRdX = false, compute_d2R = false;
606  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
607  for (unsigned int isurf = 0; isurf < dg->high_order_grid->surface_nodes.size(); ++isurf) {
608 
609  const auto scalar_product = meshmover.dXvdXs[isurf] * inverse_target_functional.dIdX;
610  if (dIdXs.locally_owned_elements().is_element(isurf)) {
611 
612  // Only do X-direction
613  const unsigned int surface_index = high_order_grid->surface_to_volume_indices[isurf];
614  const unsigned int component = high_order_grid->global_index_to_point_and_axis[surface_index].second;
615  if (component != 0) dIdXs[isurf] = 0.0;
616  else dIdXs[isurf] = scalar_product;
617  }
618  }
619  dIdXs.update_ghost_values();
620 
621  // Residual derivatives
622  pcout << "Evaluating dRdW..." << std::endl;
623  compute_dRdW = true, compute_dRdX = false, compute_d2R = false;
624  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
625  pcout << "Evaluating dRdX..." << std::endl;
626  compute_dRdW = false; compute_dRdX = true, compute_d2R = false;
627  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
628 
629  {
630  dRdXs.clear();
631  dealii::SparsityPattern sparsity_pattern_dRdXs = dg->get_dRdXs_sparsity_pattern ();
632  const dealii::IndexSet &row_parallel_partitioning_dRdXs = dg->locally_owned_dofs;
633  const dealii::IndexSet &col_parallel_partitioning_dRdXs = surface_locally_owned_indexset;
634  dRdXs.reinit(row_parallel_partitioning_dRdXs, col_parallel_partitioning_dRdXs, sparsity_pattern_dRdXs, mpi_communicator);
635  }
636  for (unsigned int isurf = 0; isurf < high_order_grid->surface_nodes.size(); ++isurf) {
637  VectorType dRdXs_i(dg->solution);
638  dg->dRdXv.vmult(dRdXs_i,meshmover.dXvdXs[isurf]);
639  for (unsigned int irow = 0; irow < dg->dof_handler.n_dofs(); ++irow) {
640  if (dg->locally_owned_dofs.is_element(irow)) {
641  dRdXs.add(irow, isurf, dRdXs_i[irow]);
642  }
643  }
644  }
645  dRdXs.compress(dealii::VectorOperation::add);
646 
647  // Solve for the adjoint variable
648  auto dRdW_T = transpose_trilinos_matrix(dg->system_matrix);
649 
651  solve_linear (dRdW_T, inverse_target_functional.dIdw, dg->dual, linear_solver_param);
652 
653  grad_lagrangian = dIdXs;
654  grad_lagrangian *= -1.0;
655  dRdXs.Tvmult_add(grad_lagrangian, dg->dual);
656  grad_lagrangian *= -1.0;
657  }
658  for (unsigned int i_design = 0; i_design < n_max_design && current_kkt_norm > kkt_tolerance; i_design++) {
659 
660  // Gradient descent
661  auto search_direction = grad_lagrangian;
662  if (use_BFGS && bfgs_search_s.size() > 0) {
663  search_direction = LBFGS(grad_lagrangian, bfgs_search_s, bfgs_dgrad_y, bfgs_denom_rho);
664  auto descent = search_direction * grad_lagrangian;
665  if (descent < 0) {
666  search_direction = grad_lagrangian;
667  bfgs_search_s.pop_front();
668  bfgs_dgrad_y.pop_front();
669  bfgs_denom_rho.pop_front();
670  }
671  }
672  search_direction *= -1.0;
673  pcout << "Gradient magnitude = " << grad_lagrangian.l2_norm() << " Search direction magnitude = " << search_direction.l2_norm() << std::endl;
674  for (unsigned int isurf = 0; isurf < dg->high_order_grid->surface_nodes.size(); ++isurf) {
675  if (search_direction.locally_owned_elements().is_element(isurf)) {
676  // Only do X-direction
677  const unsigned int surface_index = high_order_grid->surface_to_volume_indices[isurf];
678  const unsigned int component = high_order_grid->global_index_to_point_and_axis[surface_index].second;
679  if (component != 0) search_direction[isurf] = 0.0;
680  }
681  }
682 
683  const auto old_solution = dg->solution;
684  const auto old_volume_nodes = high_order_grid->volume_nodes;
685  const auto old_surface_nodes = high_order_grid->surface_nodes;
686  const auto old_functional = current_functional;
687 
688  // Line search
689  double step_length = 1.0;
690  const unsigned int max_linesearch = 80;
691  unsigned int i_linesearch = 0;
692  for (; i_linesearch < max_linesearch; i_linesearch++) {
693 
694  surface_node_displacements_vector = search_direction;
695  surface_node_displacements_vector *= step_length;
696 
697 
698  const auto disp_norm = surface_node_displacements_vector.l2_norm();
699  if (disp_norm > 1e-2) {
700  pcout << "Displacement of " << disp_norm << " too large. Reducing step length" << std::endl;
701 
702  } else {
703 
704  VectorType volume_displacements = meshmover.get_volume_displacements();
705  high_order_grid->volume_nodes += volume_displacements;
706  high_order_grid->volume_nodes.update_ghost_values();
707  high_order_grid->update_surface_nodes();
708 
709  ode_solver->steady_state();
710 
711  current_functional = inverse_target_functional.evaluate_functional();
712 
713  pcout << "Linesearch " << i_linesearch+1
714  << std::scientific << std::setprecision(15)
715  << " step = " << step_length
716  << " Old functional = " << old_functional
717  << " New functional = " << current_functional << std::endl;
718  pcout << std::fixed << std::setprecision(6);
719 
720  const double wolfe_c = 1e-4;
721  double old_func_plus = search_direction*grad_lagrangian;
722  old_func_plus *= wolfe_c * step_length;
723  old_func_plus += old_functional;
724 
725  if (current_functional < old_func_plus) break;
726  }
727 
728  dg->solution = old_solution;
729  high_order_grid->volume_nodes = old_volume_nodes;
730  high_order_grid->volume_nodes.update_ghost_values();
731  high_order_grid->update_surface_nodes();
732  step_length *= 0.5;
733  }
734  if (i_linesearch == max_linesearch) return 1;
735 
736  // Analytical dXvdXs
737  meshmover.evaluate_dXvdXs();
738 
739  // Functional derivatives
740  pcout << "Evaluating KKT right-hand side: dIdW, dIdX, Residual..." << std::endl;
741  bool compute_dIdW = true, compute_dIdX = true, compute_d2I = false;
742  (void) inverse_target_functional.evaluate_functional(compute_dIdW, compute_dIdX, compute_d2I);
743  compute_dRdW = false, compute_dRdX = false, compute_d2R = false;
744  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
745  for (unsigned int isurf = 0; isurf < dg->high_order_grid->surface_nodes.size(); ++isurf) {
746  const auto scalar_product = meshmover.dXvdXs[isurf] * inverse_target_functional.dIdX;
747  if (dIdXs.locally_owned_elements().is_element(isurf)) {
748  // Only do X-direction
749  const unsigned int surface_index = high_order_grid->surface_to_volume_indices[isurf];
750  const unsigned int component = high_order_grid->global_index_to_point_and_axis[surface_index].second;
751  if (component != 0) dIdXs[isurf] = 0.0;
752  else dIdXs[isurf] = scalar_product;
753  }
754  }
755  dIdXs.update_ghost_values();
756 
757  // Residual derivatives
758  pcout << "Evaluating dRdW..." << std::endl;
759  compute_dRdW = true, compute_dRdX = false, compute_d2R = false;
760  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
761  pcout << "Evaluating dRdX..." << std::endl;
762  compute_dRdW = false; compute_dRdX = true, compute_d2R = false;
763  dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
764 
765  {
766  dRdXs.clear();
767  dealii::SparsityPattern sparsity_pattern_dRdXs = dg->get_dRdXs_sparsity_pattern ();
768  const dealii::IndexSet &row_parallel_partitioning_dRdXs = dg->locally_owned_dofs;
769  const dealii::IndexSet &col_parallel_partitioning_dRdXs = surface_locally_owned_indexset;
770  dRdXs.reinit(row_parallel_partitioning_dRdXs, col_parallel_partitioning_dRdXs, sparsity_pattern_dRdXs, mpi_communicator);
771  }
772  for (unsigned int isurf = 0; isurf < high_order_grid->surface_nodes.size(); ++isurf) {
773  VectorType dRdXs_i(dg->solution);
774  dg->dRdXv.vmult(dRdXs_i,meshmover.dXvdXs[isurf]);
775  for (unsigned int irow = 0; irow < dg->dof_handler.n_dofs(); ++irow) {
776  if (dg->locally_owned_dofs.is_element(irow)) {
777  dRdXs.add(irow, isurf, dRdXs_i[irow]);
778  }
779  }
780  }
781  dRdXs.compress(dealii::VectorOperation::add);
782 
783  // Solve for the adjoint variable
784  auto dRdW_T = transpose_trilinos_matrix(dg->system_matrix);
785 
787  solve_linear (dRdW_T, inverse_target_functional.dIdw, dg->dual, linear_solver_param);
788 
789  const auto old_grad_lagrangian = grad_lagrangian;
790  grad_lagrangian = dIdXs;
791  grad_lagrangian *= -1.0;
792  dRdXs.Tvmult_add(grad_lagrangian, dg->dual);
793  grad_lagrangian *= -1.0;
794 
795  if (use_BFGS) {
796 
797  auto s = search_direction;
798  s *= step_length;
799  const auto y = grad_lagrangian - old_grad_lagrangian;
800  const double curvature = s*y;
801  if (curvature > 0 && bfgs_max_history > 0) {
802  bfgs_denom_rho.push_front(1.0/curvature);
803  bfgs_search_s.push_front(s);
804  bfgs_dgrad_y.push_front(y);
805  }
806 
807  if (bfgs_search_s.size() > bfgs_max_history) {
808  bfgs_search_s.pop_back();
809  bfgs_dgrad_y.pop_back();
810  bfgs_denom_rho.pop_back();
811  }
812  }
813 
814 
815  dg->output_results_vtk(high_order_grid->nth_refinement);
816  high_order_grid->output_results_vtk(high_order_grid->nth_refinement++);
817 
818  mesh_error = target_nodes;
819  mesh_error -= high_order_grid->volume_nodes;
820  current_kkt_norm = grad_lagrangian.l2_norm();
821  current_constraint_satisfaction = dg->right_hand_side.l2_norm();
822  current_mesh_error = mesh_error.l2_norm();
823  pcout << std::scientific << std::setprecision(5);
824  pcout << "*************************************************************" << std::endl;
825  pcout << "Design iteration " << i_design+1 << std::endl;
826  pcout << "Current functional: " << current_functional << std::endl;
827  pcout << "Constraint satisfaction: " << current_constraint_satisfaction << std::endl;
828  pcout << "l2norm(Current mesh - optimal mesh): " << current_mesh_error << std::endl;
829  pcout << "Current KKT norm: " << current_kkt_norm << std::endl;
830  //pcout << std::fixed << std::setprecision(6);
831 
832 
833  }
834  // for (unsigned int i_design = 0; i_design < n_max_design && current_kkt_norm > kkt_tolerance; i_design++) {
835 
836  // // Evaluate KKT right-hand side
837  // dealii::LinearAlgebra::distributed::BlockVector<double> kkt_rhs(3);
838  // pcout << "Evaluating KKT right-hand side: dIdW, dIdX, d2I, Residual..." << std::endl;
839  // bool compute_dIdW = true, compute_dIdX = true, compute_d2I = true;
840  // (void) inverse_target_functional.evaluate_functional(compute_dIdW, compute_dIdX, compute_d2I);
841  // compute_dRdW = false, compute_dRdX = false, compute_d2R = false;
842  // dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
843  // for (unsigned int isurf = 0; isurf < dg->high_order_grid->surface_nodes.size(); ++isurf) {
844  // const auto scalar_product = meshmover.dXvdXs[isurf] * inverse_target_functional.dIdX;
845  // if (dIdXs.locally_owned_elements().is_element(isurf)) {
846  // dIdXs[isurf] = scalar_product;
847  // }
848  // }
849  // dIdXs.update_ghost_values();
850 
851  // kkt_rhs.block(0) = inverse_target_functional.dIdw;
852  // kkt_rhs.block(1) = dIdXs;
853  // kkt_rhs.block(2) = dg->right_hand_side;
854  // kkt_rhs *= -1.0;
855 
856  // // Evaluate KKT system matrix
857  // pcout << "Evaluating dRdW..." << std::endl;
858  // compute_dRdW = true, compute_dRdX = false, compute_d2R = false;
859  // dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
860  // pcout << "Evaluating dRdX..." << std::endl;
861  // compute_dRdW = false; compute_dRdX = true, compute_d2R = false;
862  // dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
863  // pcout << "Evaluating residual 2nd order partials..." << std::endl;
864  // compute_dRdW = false; compute_dRdX = false, compute_d2R = true;
865  // dg->assemble_residual(compute_dRdW, compute_dRdX, compute_d2R);
866 
867  // std::vector<dealii::types::global_dof_index> surface_node_global_indices(dim*high_order_grid->locally_relevant_surface_points.size());
868  // std::vector<double> surface_node_displacements(dim*high_order_grid->locally_relevant_surface_points.size());
869  // {
870  // int inode = 0;
871  // for (unsigned int ipoint=0; ipoint<point_displacements.size(); ++ipoint) {
872  // for (unsigned int d=0;d<dim;++d) {
873  // const std::pair<unsigned int, unsigned int> point_axis = std::make_pair(ipoint,d);
874  // const dealii::types::global_dof_index global_index = high_order_grid->point_and_axis_to_global_index[point_axis];
875  // surface_node_global_indices[inode] = global_index;
876  // surface_node_displacements[inode] = point_displacements[ipoint][d];
877  // inode++;
878  // }
879  // }
880  // }
881 
882  // // Form Lagrangian Hessian
883  // inverse_target_functional.d2IdWdW.add(1.0,dg->d2RdWdW);
884  // inverse_target_functional.d2IdWdX.add(1.0,dg->d2RdWdX);
885  // inverse_target_functional.d2IdXdX.add(1.0,dg->d2RdXdX);
886 
887  // // Analytical dXvdXs
888  // meshmover.evaluate_dXvdXs();
889 
890  // {
891  // dRdXs.clear();
892  // dealii::SparsityPattern sparsity_pattern_dRdXs = dg->get_dRdXs_sparsity_pattern ();
893  // const dealii::IndexSet &row_parallel_partitioning_dRdXs = dg->locally_owned_dofs;
894  // const dealii::IndexSet &col_parallel_partitioning_dRdXs = surface_locally_owned_indexset;
895  // dRdXs.reinit(row_parallel_partitioning_dRdXs, col_parallel_partitioning_dRdXs, sparsity_pattern_dRdXs, mpi_communicator);
896  // }
897  // {
898  // d2LdWdXs.clear();
899  // dealii::SparsityPattern sparsity_pattern_d2LdWdXs = dg->get_d2RdWdXs_sparsity_pattern ();
900  // const dealii::IndexSet &row_parallel_partitioning_d2LdWdXs = dg->locally_owned_dofs;
901  // const dealii::IndexSet &col_parallel_partitioning_d2LdWdXs = surface_locally_owned_indexset;
902  // d2LdWdXs.reinit(row_parallel_partitioning_d2LdWdXs, col_parallel_partitioning_d2LdWdXs, sparsity_pattern_d2LdWdXs, mpi_communicator);
903  // }
904  // {
905  // d2LdXsdXs.clear();
906  // dealii::SparsityPattern sparsity_pattern_d2LdXsdXs = dg->get_d2RdXsdXs_sparsity_pattern ();
907  // const dealii::IndexSet &row_parallel_partitioning_d2LdXsdXs = surface_locally_owned_indexset;
908  // d2LdXsdXs.reinit(row_parallel_partitioning_d2LdXsdXs, sparsity_pattern_d2LdXsdXs, mpi_communicator);
909  // }
910  // for (unsigned int isurf = 0; isurf < high_order_grid->surface_nodes.size(); ++isurf) {
911  // VectorType dLdWdXs_i(dg->solution);
912  // inverse_target_functional.d2IdWdX.vmult(dLdWdXs_i,meshmover.dXvdXs[isurf]);
913  // for (unsigned int irow = 0; irow < dg->dof_handler.n_dofs(); ++irow) {
914  // if (dg->locally_owned_dofs.is_element(irow)) {
915  // d2LdWdXs.add(irow, isurf, dLdWdXs_i[irow]);
916  // }
917  // }
918 
919  // VectorType dRdXs_i(dg->solution);
920  // dg->dRdXv.vmult(dRdXs_i,meshmover.dXvdXs[isurf]);
921  // for (unsigned int irow = 0; irow < dg->dof_handler.n_dofs(); ++irow) {
922  // if (dg->locally_owned_dofs.is_element(irow)) {
923  // dRdXs.add(irow, isurf, dRdXs_i[irow]);
924  // }
925  // }
926 
927 
928  // const dealii::IndexSet volume_locally_owned_indexset = high_order_grid->volume_nodes.locally_owned_elements();
929  // dealii::TrilinosWrappers::MPI::Vector dXvdXs_i(volume_locally_owned_indexset);
930  // dealii::LinearAlgebra::ReadWriteVector<double> dXvdXs_i_rwv(volume_locally_owned_indexset);
931  // dXvdXs_i_rwv.import(meshmover.dXvdXs[isurf], dealii::VectorOperation::insert);
932  // dXvdXs_i.import(dXvdXs_i_rwv, dealii::VectorOperation::insert);
933  // for (unsigned int jsurf = isurf; jsurf < high_order_grid->surface_nodes.size(); ++jsurf) {
934 
935  // dealii::TrilinosWrappers::MPI::Vector dXvdXs_j(volume_locally_owned_indexset);
936  // dealii::LinearAlgebra::ReadWriteVector<double> dXvdXs_j_rwv(volume_locally_owned_indexset);
937  // dXvdXs_j_rwv.import(meshmover.dXvdXs[jsurf], dealii::VectorOperation::insert);
938  // dXvdXs_j.import(dXvdXs_j_rwv, dealii::VectorOperation::insert);
939 
940  // const auto d2LdXsidXsj = inverse_target_functional.d2IdXdX.matrix_scalar_product(dXvdXs_i,dXvdXs_j);
941  // if (volume_locally_owned_indexset.is_element(isurf)) {
942  // d2LdXsdXs.add(isurf,jsurf,d2LdXsidXsj);
943  // }
944  // if (volume_locally_owned_indexset.is_element(jsurf)) {
945  // d2LdXsdXs.add(jsurf,isurf,d2LdXsidXsj);
946  // }
947  // }
948  // }
949  // d2LdWdXs.compress(dealii::VectorOperation::add);
950  // dRdXs.compress(dealii::VectorOperation::add);
951  // d2LdXsdXs.compress(dealii::VectorOperation::add);
952 
953 
954  // // Build required operators
955  // dealii::TrilinosWrappers::SparsityPattern zero_sparsity_pattern(dg->locally_owned_dofs, MPI_COMM_WORLD, 0);
956  // zero_sparsity_pattern.compress();
957  // dealii::TrilinosWrappers::BlockSparseMatrix kkt_system_matrix;
958  // kkt_system_matrix.reinit(3,3);
959  // kkt_system_matrix.block(0, 0).copy_from( inverse_target_functional.d2IdWdW);
960  // kkt_system_matrix.block(0, 1).copy_from( d2LdWdXs);
961  // kkt_system_matrix.block(0, 2).copy_from( transpose_trilinos_matrix(dg->system_matrix));
962 
963  // kkt_system_matrix.block(1, 0).copy_from( transpose_trilinos_matrix(d2LdWdXs));
964  // kkt_system_matrix.block(1, 1).copy_from( d2LdXsdXs);
965  // kkt_system_matrix.block(1, 2).copy_from( transpose_trilinos_matrix(dRdXs));
966 
967  // kkt_system_matrix.block(2, 0).copy_from( dg->system_matrix);
968  // kkt_system_matrix.block(2, 1).copy_from( dRdXs);
969  // kkt_system_matrix.block(2, 2).reinit(zero_sparsity_pattern);
970  // //kkt_system_matrix.block(0, 0).copy_from( inverse_target_functional.d2IdWdW);
971  // //kkt_system_matrix.block(0, 1).copy_from( inverse_target_functional.d2IdWdX);
972  // //kkt_system_matrix.block(0, 2).copy_from( transpose_trilinos_matrix(dg->system_matrix));
973 
974  // //kkt_system_matrix.block(1, 0).copy_from( transpose_trilinos_matrix(inverse_target_functional.d2IdWdX));
975  // //kkt_system_matrix.block(1, 1).copy_from( inverse_target_functional.d2IdXdX);
976  // //kkt_system_matrix.block(1, 2).copy_from( transpose_trilinos_matrix(dg->dRdXv));
977 
978  // //kkt_system_matrix.block(2, 0).copy_from( dg->system_matrix);
979  // //kkt_system_matrix.block(2, 1).copy_from( dg->dRdXv);
980  // //kkt_system_matrix.block(2, 2).reinit(zero_sparsity_pattern);
981 
982  // kkt_system_matrix.collect_sizes();
983 
984  // Parameters::LinearSolverParam linear_solver_param = all_parameters->linear_solver_param;
985  // linear_solver_param.linear_residual = 1e-12;
986  // pcout << "Applying P4" << std::endl;
987  // apply_P4 (
988  // kkt_system_matrix, // A
989  // kkt_rhs, // b
990  // p4inv_kkt_rhs, // x
991  // linear_solver_param);
992 
993  // kkt_soln = p4inv_kkt_rhs;
994  // const auto old_solution = dg->solution;
995  // const auto old_volume_nodes = high_order_grid->volume_nodes;
996  // const auto old_surface_nodes = high_order_grid->surface_nodes;
997  // const auto old_dual = dg->dual;
998  // auto dual_step = kkt_soln.block(2);
999  // dual_step -= old_dual;
1000 
1001  // const auto old_functional = current_functional;
1002 
1003  // // Line search
1004  // double step_length = 1.0;
1005  // const unsigned int max_linesearch = 40;
1006  // unsigned int i_linesearch = 0;
1007  // pcout << "l2norm of DW no linesearch " << kkt_soln.block(0).l2_norm() << std::endl;
1008  // pcout << "l2norm of DX no linesearch " << kkt_soln.block(1).l2_norm() << std::endl;
1009  // pcout << "l2norm of DL no linesearch " << dual_step.l2_norm() << std::endl;
1010  // //if (i_design > 6) {
1011  // // dg->solution.add(step_length, kkt_soln.block(0));
1012  // //} else
1013  // for (; i_linesearch < max_linesearch; i_linesearch++) {
1014 
1015  // dg->solution.add(step_length, kkt_soln.block(0));
1016  // //high_order_grid->surface_nodes.add(step_length, kkt_soln.block(1));
1017 
1018  // surface_node_displacements_vector = kkt_soln.block(1);
1019  // surface_node_displacements_vector *= step_length;
1020  // VectorType volume_displacements = meshmover.get_volume_displacements();
1021  // high_order_grid->volume_nodes += volume_displacements;
1022  // high_order_grid->volume_nodes.update_ghost_values();
1023  // high_order_grid->update_surface_nodes();
1024 
1025  // current_functional = inverse_target_functional.evaluate_functional();
1026 
1027  // pcout << "Linesearch " << i_linesearch+1
1028  // << std::scientific << std::setprecision(15)
1029  // << " step = " << step_length
1030  // << " Old functional = " << old_functional
1031  // << " New functional = " << current_functional << std::endl;
1032  // pcout << std::fixed << std::setprecision(6);
1033  // if (current_functional < old_functional) {
1034  // break;
1035  // } else {
1036  // dg->solution = old_solution;
1037  // high_order_grid->volume_nodes = old_volume_nodes;
1038  // high_order_grid->volume_nodes.update_ghost_values();
1039  // high_order_grid->update_surface_nodes();
1040  // step_length *= 0.5;
1041  // }
1042  // }
1043  // dg->dual.add(step_length, dual_step);
1044  // if (i_linesearch == max_linesearch) return 1;
1045 
1046  // high_order_grid->volume_nodes.update_ghost_values();
1047  // high_order_grid->update_surface_nodes();
1048 
1049 
1050  // dg->output_results_vtk(high_order_grid->nth_refinement);
1051  // high_order_grid->output_results_vtk(high_order_grid->nth_refinement++);
1052 
1053  // mesh_error = target_nodes;
1054  // mesh_error -= high_order_grid->volume_nodes;
1055  // current_kkt_norm = kkt_rhs.l2_norm();
1056  // current_constraint_satisfaction = dg->right_hand_side.l2_norm();
1057  // current_mesh_error = mesh_error.l2_norm();
1058  // pcout << std::scientific << std::setprecision(5);
1059  // pcout << "*************************************************************" << std::endl;
1060  // pcout << "Design iteration " << i_design+1 << std::endl;
1061  // pcout << "Current functional: " << current_functional << std::endl;
1062  // pcout << "Constraint satisfaction: " << current_constraint_satisfaction << std::endl;
1063  // pcout << "l2norm(Current mesh - optimal mesh): " << current_mesh_error << std::endl;
1064  // pcout << "Current KKT norm: " << current_kkt_norm << std::endl;
1065  // pcout << std::fixed << std::setprecision(6);
1066 
1067 
1068  // }
1069 
1070  pcout << std::endl << std::endl << std::endl << std::endl;
1071  // Make sure that if the volume_nodes are located at the target volume_nodes, then we recover our target functional
1072  high_order_grid->volume_nodes = target_nodes;
1073  high_order_grid->volume_nodes.update_ghost_values();
1074  high_order_grid->update_surface_nodes();
1075  // Solve on this new grid
1076  ode_solver->steady_state();
1077  const double zero_l2_error = inverse_target_functional.evaluate_functional();
1078  pcout << "Nodes at target volume_nodes should have zero functional l2 error : " << zero_l2_error << std::endl;
1079  if (zero_l2_error > 1e-10) return 1;
1080 
1081  if (current_kkt_norm > kkt_tolerance) return 1;
1082  return fail_bool;
1083 }
1084 
1090 
1091 } // Tests namespace
1092 } // PHiLiP namespace
1093 
1094 
1095 
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.
Parameters related to the linear solver.
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
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.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)
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.
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
Sacado::Fad::DFad< real > FadType
Sacado AD type for first derivatives.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
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
LinearSolverParam linear_solver_param
Contains parameters for linear solver.
const dealii::LinearAlgebra::distributed::Vector< real > target_solution
Solution used to evaluate target functional.
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< real, nstate > &target_soln_at_q, const std::array< dealii::Tensor< 1, dim, FadFadType >, nstate > &soln_grad_at_q, const std::array< dealii::Tensor< 1, dim, FadFadType >, nstate > &target_soln_grad_at_q) const override
non-template functions to override the template classes
real2 evaluate_volume_integrand(const PHiLiP::Physics::PhysicsBase< dim, nstate, real2 > &, const dealii::Point< dim, real2 > &, const std::array< real2, nstate > &, const std::array< real, nstate > &, const std::array< dealii::Tensor< 1, dim, real2 >, nstate > &, const std::array< dealii::Tensor< 1, dim, real2 >, nstate > &) const
Zero out the default inverse target volume functional.
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.
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.
OptimizationInverseManufactured(const Parameters::AllParameters *const parameters_input)
Constructor.
int run_test() const override
Grid convergence on Euler Gaussian Bump.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
Functional base class.
Definition: functional.h:43
Performs grid convergence for various polynomial degrees.
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
static std::shared_ptr< ODESolverBase< dim, real, MeshType > > create_ODESolver(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input)
Creates either implicit or explicit ODE solver based on parameter value(no POD basis given) ...
Base class of all the tests.
Definition: tests.h:17
std::vector< dealii::LinearAlgebra::distributed::Vector< double > > dXvdXs
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< real, nstate > &target_soln_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &soln_grad_at_q, const std::array< dealii::Tensor< 1, dim, real >, nstate > &target_soln_grad_at_q) const override
non-template functions to override the template classes
BoundaryInverseTarget(std::shared_ptr< DGBase< dim, real >> dg_input, const dealii::LinearAlgebra::distributed::Vector< real > &target_solution, const bool uses_solution_values=true, const bool uses_solution_gradient=true)
Constructor.