[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
free_form_deformation.cpp
1 #include <fstream>
2 #include <boost/math/special_functions/binomial.hpp>
3 
4 #include <Sacado.hpp>
5 
6 #include "free_form_deformation.h"
7 #include "meshmover_linear_elasticity.hpp"
8 
9 #include <deal.II/base/utilities.h>
10 #include <deal.II/grid/grid_out.h>
11 
12 #include <deal.II/grid/grid_reordering.h>
13 
14 // For FD
15 #include <deal.II/dofs/dof_tools.h>
16 #include <deal.II/lac/dynamic_sparsity_pattern.h>
17 #include <deal.II/lac/sparsity_tools.h>
18 
19 namespace PHiLiP {
20 
21 template<int dim>
23  const dealii::Point<dim> &_origin,
24  const std::array<dealii::Tensor<1,dim,double>,dim> _parallepiped_vectors,
25  const std::array<unsigned int,dim> &_ndim_control_pts)
26  : origin(_origin)
27  , parallepiped_vectors(_parallepiped_vectors)
28  , ndim_control_pts(_ndim_control_pts)
29  , n_control_pts(compute_total_ctl_pts())
30  , pcout(std::cout, dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
31 {
32  control_pts.resize(n_control_pts);
33  for (unsigned int ictl = 0; ictl < n_control_pts; ++ictl) {
34 
35  std::array<unsigned int,dim> ijk = global_to_grid (ictl);
36 
37  control_pts[ictl] = origin;
38  for (int d=0; d<dim; ++d) {
39  control_pts[ictl] += ijk[d] / (ndim_control_pts[d] - 1.0) * parallepiped_vectors[d];
40  }
41 
42  }
43  init_msg();
44 
45  pcout << " **************************************** " << std::endl;
46 }
47 
48 template<int dim>
50  const dealii::Point<dim> &_origin,
51  const std::array<double,dim> &rectangle_lengths,
52  const std::array<unsigned int,dim> &_ndim_control_pts)
53  : FreeFormDeformation (_origin, get_rectangular_parallepiped_vectors(rectangle_lengths), _ndim_control_pts)
54 { }
55 
56 template<int dim>
57 dealii::Point<dim,double> FreeFormDeformation<dim>::get_local_coordinates (const dealii::Point<dim,double> p) const
58 {
59  dealii::Point<dim,double> local_coordinates;
60  std::array<dealii::Tensor<1,dim,double>,dim> perp_vectors;
61  if constexpr (dim == 1) {
62  perp_vectors[0] = 1;
63  }
64  if constexpr (dim == 2) {
65 
66  // X = X_0 + s S + t T
67  // s = ( (X - X_0) . T_perp ) / (S . T_perp)
68  // t = ( (X - X_0) . S_perp ) / (T . S_perp)
69  // In 2D, V_perp = [V_x, V_y]_perp = [V_y, -V_x] = dealii::cross_product_2d(V)
70  perp_vectors[0] = dealii::cross_product_2d(parallepiped_vectors[1]);
71  perp_vectors[1] = dealii::cross_product_2d(parallepiped_vectors[0]);
72  }
73  if constexpr (dim == 3) {
74  // See Sederberg 1986 for 3D
75  perp_vectors[0] = dealii::cross_product_3d(parallepiped_vectors[1], parallepiped_vectors[2]);
76  perp_vectors[1] = cross_product_3d(parallepiped_vectors[0], parallepiped_vectors[2]);
77  perp_vectors[2] = cross_product_3d(parallepiped_vectors[0], parallepiped_vectors[1]);
78  }
79 
80  const dealii::Tensor<1,dim,double> dX = (p - origin);
81  for (int d=0;d<dim;++d) {
82  local_coordinates[d] = (dX * perp_vectors[d]) / (parallepiped_vectors[d] * perp_vectors[d]);
83  // const double TOL = 1e-12;
84  // if (!(-TOL <= local_coordinates[d] && local_coordinates[d] <= 1.0+TOL)) {
85  // std::cout << " Point: " << p << " is not within the FFD box." << std::endl;
86  // std::cout << " Direction: " << d << " Local (s,t,u) coord: " << local_coordinates[d] << std::endl;
87  // throw(1);
88  // }
89  }
90 
91  return local_coordinates;
92 }
93 
94 template<int dim>
95 std::array<dealii::Tensor<1,dim,double>,dim> FreeFormDeformation<dim>
96 ::get_rectangular_parallepiped_vectors (const std::array<double,dim> &rectangle_lengths) const
97 {
98  std::array<dealii::Tensor<1,dim,double>,dim> parallepiped_vectors;
99  for (int d=0; d<dim; ++d) {
100  parallepiped_vectors[d][d] = rectangle_lengths[d];
101  }
102  return parallepiped_vectors;
103 }
104 
105 template<int dim>
106 std::array<unsigned int,dim> FreeFormDeformation<dim>::global_to_grid ( const unsigned int global_ictl ) const
107 {
108  std::array<unsigned int,dim> ijk_index;
109 
110  unsigned int remain = global_ictl;
111  for (int d=0; d<dim; ++d) {
112  ijk_index[d] = remain % ndim_control_pts[d];
113  remain /= ndim_control_pts[d];
114  }
115  assert(remain == 0);
116 
117  return ijk_index;
118 }
119 
120 template<int dim>
121 unsigned int FreeFormDeformation<dim>::grid_to_global ( const std::array<unsigned int,dim> &ijk_index ) const
122 {
123  for (int d=0;d<dim;++d) {
124  assert(ijk_index[d] < ndim_control_pts[d]);
125  }
126 
127  unsigned int global_index = 0;
128  if constexpr (dim == 1) {
129  global_index = ijk_index[0];
130  }
131  if constexpr (dim == 2) {
132  global_index = ijk_index[0];
133  global_index += ijk_index[1] * ndim_control_pts[0];
134  }
135  if constexpr (dim == 3) {
136  global_index = ijk_index[0];
137  global_index += ijk_index[1] * ndim_control_pts[0];
138  global_index += ijk_index[2] * ndim_control_pts[0] * ndim_control_pts[1];
139  }
140  return global_index;
141 }
142 
143 
144 template<int dim>
146 {
147  unsigned int total = 1;
148  for (int d=0;d<dim;++d) { total *= ndim_control_pts[d]; }
149  return total;
150 }
151 
152 template<int dim>
154 {
155  pcout << " **************************************** " << std::endl;
156  pcout << " * Creating Free-Form Deformation (FFD) * " << std::endl;
157 
158  pcout << " Parallepiped with corner volume_nodes located at: * " << std::endl;
159  for (unsigned int ictl = 0; ictl < n_control_pts; ++ictl) {
160  std::array<unsigned int, dim> ijk = global_to_grid(ictl);
161  bool print = true;
162  for (int d=0; d<dim; ++d) {
163  if ( !( ijk[d] == 0 || ijk[d] == (ndim_control_pts[d] - 1) ) ) {
164  print = false;
165  }
166  }
167  if (print) pcout << control_pts[ictl] << std::endl;
168  }
169 }
170 
171 template<int dim>
172 void FreeFormDeformation<dim>::move_ctl_dx ( const unsigned i, const dealii::Tensor<1,dim,double> dx )
173 {
174  control_pts[i] += dx;
175 }
176 
177 template<int dim>
178 void FreeFormDeformation<dim>::move_ctl_dx ( const std::array<unsigned int,dim> ijk, const dealii::Tensor<1,dim,double> dx)
179 {
180  control_pts[grid_to_global(ijk)] += dx;
181 }
182 
183 template<int dim>
184 dealii::Point<dim,double> FreeFormDeformation<dim>
185 ::new_point_location (const dealii::Point<dim,double> &initial_point) const
186 {
187  return new_point_location (initial_point, this->control_pts);
188 }
189 
190 
191 template<int dim>
192 template<typename real>
193 dealii::Point<dim,real> FreeFormDeformation<dim>
195  const dealii::Point<dim,double> &initial_point,
196  const std::vector<dealii::Point<dim,real>> &control_pts) const
197 {
198  const dealii::Point<dim,double> s_t_u = get_local_coordinates (initial_point);
199  for (int d=0; d<dim; ++d) {
200  if (!(0 <= s_t_u[d] && s_t_u[d] <= 1.0)) {
201  dealii::Point<dim,real> initial_point_ad;
202  for (int d=0; d<dim; ++d) {
203  initial_point_ad[d] = initial_point[d];
204  }
205  return initial_point_ad;
206  }
207  }
208  return evaluate_ffd (s_t_u, control_pts);
209 }
210 
211 template<int dim>
212 template<typename real>
213 dealii::Tensor<1,dim,real> FreeFormDeformation<dim>
215  const dealii::Point<dim,double> &initial_point,
216  const std::vector<dealii::Point<dim,real>> &control_pts) const
217 {
218  const dealii::Point<dim,real> new_point = new_point_location (initial_point, control_pts);
219  const dealii::Tensor<1,dim,real> displacement = new_point - initial_point;
220  return displacement;
221 }
222 
223 
224 template<int dim>
225 template<typename real>
226 std::vector<dealii::Tensor<1,dim,real>> FreeFormDeformation<dim>
228  const std::vector<dealii::Point<dim,double>> &initial_points,
229  const std::vector<dealii::Point<dim,real>> &control_pts) const
230 {
231  std::vector<dealii::Tensor<1,dim,real>> displacements;
232  for (unsigned int i=0; i<initial_points.size(); ++i) {
233  displacements[i] = get_displacement (initial_points[i], control_pts);
234  }
235  return displacements;
236 }
237 
238 template<int dim>
239 dealii::Point<dim,double> FreeFormDeformation<dim>
240 ::dXdXp (const dealii::Point<dim,double> &initial_point, const unsigned int ctl_index, const unsigned int ctl_axis) const
241 {
242  assert(ctl_axis < dim);
243  assert(ctl_index < n_control_pts);
244  using FadType = Sacado::Fad::DFad<double>;
245  std::vector<dealii::Point<dim,FadType>> control_pts_ad(control_pts.size());
246  for (unsigned int i=0; i<n_control_pts; ++i) {
247  control_pts_ad[i] = control_pts[i];
248  }
249  control_pts_ad[ctl_index][ctl_axis].diff(0,1);
250 
251  dealii::Point<dim, FadType> new_point_ad = new_point_location(initial_point, control_pts_ad);
252 
253  dealii::Point<dim,double> dXdXp;
254  for (int d=0; d<dim; ++d) {
255  dXdXp[d] = new_point_ad[d].dx(0);
256  }
257  return dXdXp;
258 }
259 
260 template<int dim>
261 template<typename real>
262 dealii::Point<dim,real> FreeFormDeformation<dim>
264  const dealii::Point<dim,double> &s_t_u_point,
265  const std::vector<dealii::Point<dim,real>> &control_pts) const
266 {
267  dealii::Point<dim,real> ffd_location;
268 
269  std::array<std::vector<real>,dim> ijk_coefficients;
270 
271  for (int d=0; d<dim; ++d) {
272  ffd_location[d] = 0.0;
273 
274  ijk_coefficients[d].resize(ndim_control_pts[d]);
275 
276  const unsigned n_intervals = ndim_control_pts[d] - 1;
277 
278  for (unsigned int i = 0; i < ndim_control_pts[d]; ++i) {
279  double bin_coeff = boost::math::binomial_coefficient<double>(n_intervals, i);
280  const unsigned int power = n_intervals - i;
281  ijk_coefficients[d][i] = bin_coeff * std::pow(1.0 - s_t_u_point[d], power) * std::pow(s_t_u_point[d], i);
282  }
283  }
284 
285  for (unsigned int ictl = 0; ictl < n_control_pts; ++ictl) {
286  std::array<unsigned int, dim> ijk = global_to_grid(ictl);
287 
288  real coeff = 1.0;
289  for (int d=0; d<dim; ++d) {
290  coeff *= ijk_coefficients[d][ijk[d]];
291  }
292  for (int d=0; d<dim; ++d) {
293  ffd_location[d] += coeff * control_pts[ictl][d];
294  }
295  }
296 
297  return ffd_location;
298 }
299 
300 template<int dim>
303  const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
304  dealii::LinearAlgebra::distributed::Vector<double> &vector_to_copy_into) const
305 {
306  AssertDimension(ffd_design_variables_indices_dim.size(), vector_to_copy_into.size())
307  auto partitioner = vector_to_copy_into.get_partitioner();
308 
309  for (unsigned int i_dvar = 0; i_dvar < ffd_design_variables_indices_dim.size(); ++i_dvar) {
310  if (partitioner->in_local_range(i_dvar)) {
311  const unsigned int i_ctl = ffd_design_variables_indices_dim[i_dvar].first;
312  const unsigned int d_ctl = ffd_design_variables_indices_dim[i_dvar].second;
313  vector_to_copy_into[i_dvar] = this->control_pts[i_ctl][d_ctl];
314  }
315  }
316  vector_to_copy_into.update_ghost_values();
317 }
318 
319 template<int dim>
322  const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
323  const dealii::LinearAlgebra::distributed::Vector<double> &vector_to_copy_from)
324 {
325  vector_to_copy_from.update_ghost_values();
326  AssertDimension(ffd_design_variables_indices_dim.size(), vector_to_copy_from.size())
327  auto partitioner = vector_to_copy_from.get_partitioner();
328  for (unsigned int i_dvar = 0; i_dvar < ffd_design_variables_indices_dim.size(); ++i_dvar) {
329 
330  assert( partitioner->in_local_range(i_dvar) || partitioner->is_ghost_entry(i_dvar) );
331 
332  const unsigned int i_ctl = ffd_design_variables_indices_dim[i_dvar].first;
333  const unsigned int d_ctl = ffd_design_variables_indices_dim[i_dvar].second;
334  this->control_pts[i_ctl][d_ctl] = vector_to_copy_from[i_dvar];
335  }
336 }
337 
338 template<int dim>
340 ::deform_mesh (HighOrderGrid<dim,double> &high_order_grid) const
341 {
342  dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements = get_surface_displacement (high_order_grid);
343 
345  meshmover(
346  *(high_order_grid.triangulation),
347  high_order_grid.initial_mapping_fe_field,
348  high_order_grid.dof_handler_grid,
349  high_order_grid.surface_to_volume_indices,
350  surface_node_displacements);
351  dealii::LinearAlgebra::distributed::Vector<double> volume_displacements = meshmover.get_volume_displacements();
352  high_order_grid.volume_nodes = high_order_grid.initial_volume_nodes;
353  high_order_grid.volume_nodes += volume_displacements;
354  high_order_grid.volume_nodes.update_ghost_values();
355 }
356 
357 template<int dim>
358 dealii::LinearAlgebra::distributed::Vector<double>
361 {
362  dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements(high_order_grid.surface_nodes);
363 
364  auto index = high_order_grid.surface_to_volume_indices.begin();
365  auto node = high_order_grid.initial_surface_nodes.begin();
366  auto new_node = surface_node_displacements.begin();
367  for (; index != high_order_grid.surface_to_volume_indices.end(); ++index, ++node, ++new_node) {
368  const dealii::types::global_dof_index global_idof_index = *index;
369  const std::pair<unsigned int, unsigned int> ipoint_component = high_order_grid.global_index_to_point_and_axis.at(global_idof_index);
370  const unsigned int ipoint = ipoint_component.first;
371  const unsigned int component = ipoint_component.second;
372  dealii::Point<dim> old_point;
373  for (int d=0;d<dim;d++) {
374  old_point[d] = high_order_grid.initial_locally_relevant_surface_points[ipoint][d];
375  }
376  const dealii::Point<dim> new_point = new_point_location(old_point);
377  *new_node = new_point[component];
378  }
379  surface_node_displacements.update_ghost_values();
380  surface_node_displacements -= high_order_grid.initial_surface_nodes;
381  surface_node_displacements.update_ghost_values();
382 
383  return surface_node_displacements;
384 }
385 
386 template<int dim>
387 std::vector<dealii::LinearAlgebra::distributed::Vector<double>>
390  const HighOrderGrid<dim,double> &high_order_grid,
391  const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
392  const double eps
393  )
394 {
395  std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector_FD;
396 
397  for (auto const &ffd_pair: ffd_design_variables_indices_dim) {
398 
399  const unsigned int ictl = ffd_pair.first;
400  const unsigned int d_ffd = ffd_pair.second;
401 
402  // Save
403  const dealii::Point<dim> old_ffd_point = control_pts[ictl];
404 
405  // Perturb
406  {
407  dealii::Point<dim> new_ffd_point = old_ffd_point;
408  new_ffd_point[d_ffd] += eps;
409  move_ctl_dx ( ictl, new_ffd_point - old_ffd_point);
410  }
411  const auto surface_node_displacements_p = get_surface_displacement (high_order_grid);
412 
413  // Reset FFD
414  control_pts[ictl] = old_ffd_point;
415 
416  // Perturb
417  {
418  dealii::Point<dim> new_ffd_point = old_ffd_point;
419  new_ffd_point[d_ffd] -= eps;
420  move_ctl_dx ( ictl, new_ffd_point - old_ffd_point);
421  }
422  const auto surface_node_displacements_n = get_surface_displacement (high_order_grid);
423 
424  // Reset FFD
425  control_pts[ictl] = old_ffd_point;
426 
427  auto diff = surface_node_displacements_p;
428  diff -= surface_node_displacements_n;
429  diff /= 2.0*eps;
430 
431  // Put into volume-sized vector
432  dealii::LinearAlgebra::distributed::Vector<double> derivative_surface_nodes_ffd_ctl;
433  derivative_surface_nodes_ffd_ctl.reinit(high_order_grid.volume_nodes);
434 
435  high_order_grid.map_nodes_surf_to_vol.vmult(derivative_surface_nodes_ffd_ctl,diff);
436 
437  // auto surf_index = high_order_grid.surface_to_volume_indices.begin();
438  // auto surf_value = diff.begin();
439 
440  // for (; surf_index != high_order_grid.surface_to_volume_indices.end(); ++surf_index, ++surf_value) {
441  // derivative_surface_nodes_ffd_ctl[*surf_index] = *surf_value;
442  // }
443 
444  // derivative_surface_nodes_ffd_ctl.update_ghost_values();
445 
446  dXvsdXp_vector_FD.push_back(derivative_surface_nodes_ffd_ctl);
447  }
448  return dXvsdXp_vector_FD;
449 }
450 
451 template<int dim>
452 std::vector<dealii::LinearAlgebra::distributed::Vector<double>>
455  const HighOrderGrid<dim,double> &high_order_grid,
456  const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim
457  ) const
458 {
459  std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector;
460 
461  const dealii::IndexSet &nodes_locally_owned = high_order_grid.volume_nodes.get_partitioner()->locally_owned_range();
462  for (auto const &ffd_pair: ffd_design_variables_indices_dim) {
463 
464  const unsigned int ctl_index = ffd_pair.first;
465  const unsigned int ctl_axis = ffd_pair.second;
466 
467  dealii::LinearAlgebra::distributed::Vector<double> derivative_surface_nodes_ffd_ctl;
468  derivative_surface_nodes_ffd_ctl.reinit(high_order_grid.volume_nodes);
469  unsigned int ipoint = 0;
470  for (auto const& surface_point: high_order_grid.initial_locally_relevant_surface_points) {
471 
472  dealii::Point<dim,double> dxsdxp = dXdXp (surface_point, ctl_index, ctl_axis);
473 
474  for (int d=0; d<dim; ++d) {
475  if ((unsigned int)d!=ctl_axis) {
476  assert(dxsdxp[d] == 0.0);
477  }
478  const dealii::types::global_dof_index vol_index = high_order_grid.point_and_axis_to_global_index.at(std::make_pair(ipoint,(unsigned int)d));
479  if (nodes_locally_owned.is_element(vol_index)) {
480  derivative_surface_nodes_ffd_ctl[vol_index] = dxsdxp[d];
481  }
482  }
483 
484  ipoint++;
485  }
486  derivative_surface_nodes_ffd_ctl.update_ghost_values();
487 
488  dXvsdXp_vector.push_back(derivative_surface_nodes_ffd_ctl);
489  }
490  return dXvsdXp_vector;
491 }
492 
493 template<int dim>
494 void
497  const HighOrderGrid<dim,double> &high_order_grid,
498  const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
499  dealii::TrilinosWrappers::SparseMatrix &dXvsdXp
500  ) const
501 {
502  const unsigned int n_rows = high_order_grid.dof_handler_grid.n_dofs();
503  const unsigned int n_cols = ffd_design_variables_indices_dim.size();
504  const dealii::IndexSet &row_part = high_order_grid.dof_handler_grid.locally_owned_dofs();
505  const dealii::IndexSet col_part = dealii::Utilities::MPI::create_evenly_distributed_partitioning(MPI_COMM_WORLD,n_cols);
506 
507  dealii::DynamicSparsityPattern full_dsp(n_rows, n_cols, row_part);
508  for (const auto &i_row: row_part) {
509  for (unsigned int i_col = 0; i_col < n_cols; ++i_col) {
510  full_dsp.add(i_row, i_col);
511  }
512  }
513  dealii::IndexSet locally_relevant_dofs;
514  dealii::DoFTools::extract_locally_relevant_dofs(high_order_grid.dof_handler_grid, locally_relevant_dofs);
515  dealii::SparsityTools::distribute_sparsity_pattern(full_dsp, row_part, MPI_COMM_WORLD, locally_relevant_dofs);
516 
517  dealii::SparsityPattern full_sp;
518  full_sp.copy_from(full_dsp);
519 
520  dXvsdXp.reinit(row_part, col_part, full_sp, MPI_COMM_WORLD);
521 
522 
523  const dealii::IndexSet &nodes_locally_owned = high_order_grid.volume_nodes.get_partitioner()->locally_owned_range();
524  for (unsigned int i_col = 0; i_col < ffd_design_variables_indices_dim.size(); ++i_col) {
525 
526  const auto ffd_pair = ffd_design_variables_indices_dim[i_col];
527  const unsigned int ctl_index = ffd_pair.first;
528  const unsigned int ctl_axis = ffd_pair.second;
529 
530  unsigned int ipoint = 0;
531  for (auto const& surface_point: high_order_grid.initial_locally_relevant_surface_points) {
532 
533  dealii::Point<dim,double> dxsdxp = dXdXp (surface_point, ctl_index, ctl_axis);
534 
535  for (int d=0; d<dim; ++d) {
536  const dealii::types::global_dof_index vol_index = high_order_grid.point_and_axis_to_global_index.at(std::make_pair(ipoint,(unsigned int)d));
537  if (nodes_locally_owned.is_element(vol_index)) {
538  dXvsdXp.set(vol_index,i_col, dxsdxp[d]);
539  }
540  if ((unsigned int)d!=ctl_axis) {
541  assert(dxsdxp[d] == 0.0);
542  }
543  }
544 
545  ipoint++;
546  }
547  }
548  dXvsdXp.compress(dealii::VectorOperation::insert);
549 }
550 
551 template<int dim>
552 void
555  const HighOrderGrid<dim,double> &high_order_grid,
556  const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim,
557  dealii::TrilinosWrappers::SparseMatrix &dXvdXp
558  ) const
559 {
560  // const unsigned int n_design_var = ffd_design_variables_indices_dim.size();
561 
562  std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector = get_dXvsdXp(high_order_grid, ffd_design_variables_indices_dim);
563 
564  dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements(high_order_grid.surface_nodes);
566  meshmover(
567  *(high_order_grid.triangulation),
568  high_order_grid.initial_mapping_fe_field,
569  high_order_grid.dof_handler_grid,
570  high_order_grid.surface_to_volume_indices,
571  surface_node_displacements);
572  //meshmover.evaluate_dXvdXs();
573  meshmover.apply_dXvdXvs(dXvsdXp_vector, dXvdXp);
574 }
575 
576 template<int dim>
577 void
580  HighOrderGrid<dim,double> &high_order_grid,
581  const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim,
582  dealii::TrilinosWrappers::SparseMatrix &dXvdXp_FD,
583  const double eps
584  )
585 {
586  const unsigned int n_rows = high_order_grid.volume_nodes.size();
587  const unsigned int n_cols = ffd_design_variables_indices_dim.size();
588 
589  // Row partitioning
590  const dealii::IndexSet &row_part = high_order_grid.dof_handler_grid.locally_owned_dofs();
591 
592  //const unsigned int this_mpi_process = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
593  //const std::vector<dealii::IndexSet> col_parts = dealii::Utilities::MPI::create_evenly_distributed_partitioning(MPI_COMM_WORLD,n_cols);
594  //const dealii::IndexSet &col_part = col_parts[this_mpi_process];
595  const dealii::IndexSet col_part = dealii::Utilities::MPI::create_evenly_distributed_partitioning(MPI_COMM_WORLD,n_cols);
596 
597  // Sparsity pattern
598  dealii::DynamicSparsityPattern full_dsp(n_rows, n_cols, row_part);
599  for (const auto &i_row: row_part) {
600  for (unsigned int i_col = 0; i_col < n_cols; ++i_col) {
601  full_dsp.add(i_row, i_col);
602  }
603  }
604  dealii::IndexSet locally_relevant_dofs;
605  dealii::DoFTools::extract_locally_relevant_dofs(high_order_grid.dof_handler_grid, locally_relevant_dofs);
606  dealii::SparsityTools::distribute_sparsity_pattern(full_dsp, high_order_grid.dof_handler_grid.locally_owned_dofs(), MPI_COMM_WORLD, locally_relevant_dofs);
607  dealii::SparsityPattern full_sp;
608  full_sp.copy_from(full_dsp);
609 
610  // Allocate matrix
611  dXvdXp_FD.reinit(row_part, col_part, full_sp, MPI_COMM_WORLD);
612 
613  // Get finite-differenced dXvdXp_FD
614  auto old_volume_nodes = high_order_grid.volume_nodes;
615  for (unsigned int i_design = 0; i_design < ffd_design_variables_indices_dim.size(); ++i_design) {
616  const unsigned int ictl = ffd_design_variables_indices_dim[i_design].first;
617  const unsigned int d_ffd = ffd_design_variables_indices_dim[i_design].second;
618 
619  // Save
620  const dealii::Point<dim> old_ffd_point = control_pts[ictl];
621 
622  // Perturb
623  {
624  dealii::Point<dim> new_ffd_point = old_ffd_point;
625  new_ffd_point[d_ffd] += eps;
626  move_ctl_dx ( ictl, new_ffd_point - old_ffd_point);
627  deform_mesh(high_order_grid);
628  }
629 
630  auto nodes_p = high_order_grid.volume_nodes;
631 
632  // Reset FFD
633  control_pts[ictl] = old_ffd_point;
634  high_order_grid.volume_nodes = old_volume_nodes;
635 
636  // Perturb
637  {
638  dealii::Point<dim> new_ffd_point = old_ffd_point;
639  new_ffd_point[d_ffd] -= eps;
640  move_ctl_dx ( ictl, new_ffd_point - old_ffd_point);
641  deform_mesh(high_order_grid);
642  }
643 
644  auto nodes_m = high_order_grid.volume_nodes;
645 
646  // Reset FFD
647  control_pts[ictl] = old_ffd_point;
648  high_order_grid.volume_nodes = old_volume_nodes;
649 
650  auto dXvdXp_i = nodes_p;
651  dXvdXp_i -= nodes_m;
652  dXvdXp_i /= (2*eps);
653 
654  const auto &locally_owned = dXvdXp_i.get_partitioner()->locally_owned_range();
655  for (const auto &index: locally_owned) {
656  dXvdXp_FD.set(index,i_design, dXvdXp_i[index]);
657  }
658  }
659  dXvdXp_FD.compress(dealii::VectorOperation::insert);
660 }
661 
662 template<int dim>
664 ::output_ffd_vtu(const unsigned int cycle) const
665 {
666  if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) != 0) return;
667  // next create the cells
668  std::vector<dealii::CellData<dim>> cells;
669  unsigned int n_cells = 1;
670  for (int d = 0; d<dim; ++d) {
671  n_cells *= ndim_control_pts[d]-1;
672  }
673  cells.resize(n_cells);
674 
675  // From here, the code is copied from dealii::GridGenerator::subdivided_parallelpiped()
676  std::array<unsigned int, dim> repetitions;
677  for (int d = 0; d < dim; ++d) {
678  repetitions[d] = ndim_control_pts[d]-1;
679  }
680  switch (dim) {
681  case 1:
682  {
683  for (unsigned int x = 0; x < repetitions[0]; ++x) {
684  cells[x].vertices[0] = x;
685  cells[x].vertices[1] = x + 1;
686  cells[x].material_id = 0;
687  }
688  break;
689  }
690 
691  case 2:
692  {
693  for (unsigned int y = 0; y < repetitions[1]; ++y) {
694  for (unsigned int x = 0; x < repetitions[0]; ++x) {
695  const unsigned int c = x + y * repetitions[0];
696  cells[c].vertices[0] = y * (repetitions[0] + 1) + x;
697  cells[c].vertices[1] = y * (repetitions[0] + 1) + x + 1;
698  cells[c].vertices[2] = (y + 1) * (repetitions[0] + 1) + x;
699  cells[c].vertices[3] = (y + 1) * (repetitions[0] + 1) + x + 1;
700  cells[c].material_id = 0;
701  }
702  }
703  break;
704  }
705 
706  case 3:
707  {
708  const unsigned int n_x = (repetitions[0] + 1);
709  const unsigned int n_xy = (repetitions[0] + 1) * (repetitions[1] + 1);
710 
711  for (unsigned int z = 0; z < repetitions[2]; ++z) {
712  for (unsigned int y = 0; y < repetitions[1]; ++y) {
713  for (unsigned int x = 0; x < repetitions[0]; ++x) {
714  const unsigned int c = x + y * repetitions[0] + z * repetitions[0] * repetitions[1];
715  cells[c].vertices[0] = z * n_xy + y * n_x + x;
716  cells[c].vertices[1] = z * n_xy + y * n_x + x + 1;
717  cells[c].vertices[2] = z * n_xy + (y + 1) * n_x + x;
718  cells[c].vertices[3] = z * n_xy + (y + 1) * n_x + x + 1;
719  cells[c].vertices[4] = (z + 1) * n_xy + y * n_x + x;
720  cells[c].vertices[5] = (z + 1) * n_xy + y * n_x + x + 1;
721  cells[c].vertices[6] = (z + 1) * n_xy + (y + 1) * n_x + x;
722  cells[c].vertices[7] = (z + 1) * n_xy + (y + 1) * n_x + x + 1;
723  cells[c].material_id = 0;
724  }
725  }
726  }
727  break;
728  }
729  } // switch(dim)
730 
731  dealii::GridReordering<dim>::reorder_cells(cells, true);
732  dealii::Triangulation<dim,dim> tria;
733  tria.create_triangulation(control_pts, cells, dealii::SubCellData());
734  std::string nffd_string[3];
735  for (int d=0; d<dim; ++d) {
736  nffd_string[d] = dealii::Utilities::int_to_string(ndim_control_pts[d], 3);
737  }
738  std::string filename = "FFD-" + dealii::Utilities::int_to_string(dim, 1) +"D_";
739  for (int d=0; d<dim; ++d) {
740  filename += dealii::Utilities::int_to_string(ndim_control_pts[d], 3);
741  if (d<dim-1) filename += "X";
742  }
743  filename += "-"+dealii::Utilities::int_to_string(cycle, 4) + ".vtu";
744  pcout << "Outputting FFD grid: " << filename << " ... " << std::endl;
745 
746  std::ofstream output(filename);
747 
748  dealii::GridOut grid_out;
749  grid_out.write_vtu (tria, output);
750 
751 }
752 
753 
754 template class FreeFormDeformation<PHILIP_DIM>;
755 
756 // template dealii::Point<dim,double> FreeFormDeformation<dim>
757 // ::evaluate_ffd (const dealii::Point<PHILIP_DIM,double> &, const std::vector<dealii::Point<PHILIP_DIM,double>> &) const;
758 //
759 // template dealii::Point<PHILIP_DIM, double> FreeFormDeformation<PHILIP_DIM>
760 // ::new_point_location(const dealii::Point<PHILIP_DIM, double>&, const std::vector<dealii::Point<PHILIP_DIM,double>> &) const;
761 //
762 // template dealii::Tensor<1, PHILIP_DIM, double> FreeFormDeformation<PHILIP_DIM>
763 // ::get_displacement (const dealii::Point<PHILIP_DIM,double> &, const std::vector<dealii::Point<PHILIP_DIM,double>> &) const;
764 //
765 // template std::vector<dealii::Tensor<1, PHILIP_DIM, double>> FreeFormDeformation<PHILIP_DIM>
766 // ::get_displacement (const std::vector<dealii::Point<PHILIP_DIM,double>> &, const std::vector<dealii::Point<PHILIP_DIM,double>> &) const;
767 
768 } // namespace PHiLiP
VectorType initial_volume_nodes
Initial nodal coefficients of the high-order grid.
void get_design_variables(const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim, dealii::LinearAlgebra::distributed::Vector< double > &vector_to_copy_into) const
Copies the desired control points from FreeFormDeformation object into vector_to_copy_into.
void get_dXvdXp(const HighOrderGrid< dim, double > &high_order_grid, const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim, dealii::TrilinosWrappers::SparseMatrix &dXvdXp) const
Sacado::Fad::DFad< double > FadType
Sacado AD type for first derivatives.
Definition: ADTypes.hpp:11
std::vector< dealii::Point< dim > > initial_locally_relevant_surface_points
Initial locally relevant surface points.
const std::array< dealii::Tensor< 1, dim, double >, dim > parallepiped_vectors
Parallepiped vectors.
std::vector< dealii::Point< dim > > control_pts
Control points of the FFD box used to deform the geometry.
void deform_mesh(HighOrderGrid< dim, double > &high_order_grid) const
Deform HighOrderGrid using its initial volume_nodes to retrieve the deformed set of volume_nodes...
void init_msg() const
Initial message.
dealii::Point< dim, double > dXdXp(const dealii::Point< dim, double > &initial_point, const unsigned int ctl_index, const unsigned int ctl_axis) const
const dealii::Point< dim > origin
Parallepiped origin.
void move_ctl_dx(const unsigned i, const dealii::Tensor< 1, dim, double >)
Move control point with global index i.
Files for the baseline physics.
Definition: ADTypes.hpp:10
VectorType initial_surface_nodes
Distributed ghosted vector of initial surface nodes.
std::array< unsigned int, dim > global_to_grid(const unsigned int global_ictl) const
Given a control points&#39; global index return its ijk coordinate.
Free form deformation class from Sederberg 1986.
dealii::TrilinosWrappers::SparseMatrix map_nodes_surf_to_vol
const std::shared_ptr< MeshType > triangulation
Mesh.
dealii::Point< dim, double > get_local_coordinates(const dealii::Point< dim, double > p) const
Returns the local coordinates s-t-u within the FFD box.
std::vector< dealii::LinearAlgebra::distributed::Vector< double > > get_dXvsdXp_FD(const HighOrderGrid< dim, double > &high_order_grid, const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim, const double eps)
void apply_dXvdXvs(std::vector< dealii::LinearAlgebra::distributed::Vector< double >> &list_of_vectors, dealii::TrilinosWrappers::SparseMatrix &output_matrix)
dealii::Point< dim, real > new_point_location(const dealii::Point< dim, double > &initial_point, const std::vector< dealii::Point< dim, real >> &control_pts) const
dealii::LinearAlgebra::distributed::Vector< double > get_surface_displacement(const HighOrderGrid< dim, double > &high_order_grid) const
void get_dXvsdXp(const HighOrderGrid< dim, double > &high_order_grid, const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim, dealii::TrilinosWrappers::SparseMatrix &dXvsdXp) const
std::map< dealii::types::global_dof_index, std::pair< unsigned int, unsigned int > > global_index_to_point_and_axis
FreeFormDeformation(const dealii::Point< dim > &_origin, const std::array< dealii::Tensor< 1, dim, double >, dim > _parallepiped_vectors, const std::array< unsigned int, dim > &_ndim_control)
Constructor for an oblique parallepiped.
dealii::ConditionalOStream pcout
Outputs if MPI rank is 0.
dealii::LinearAlgebra::distributed::Vector< int > surface_to_volume_indices
void output_ffd_vtu(const unsigned int cycle) const
Output a .vtu file of the FFD box to visualize.
unsigned int compute_total_ctl_pts() const
Used by constructor to evaluate total number of control points.
void get_dXvdXp_FD(HighOrderGrid< dim, double > &high_order_grid, const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim, dealii::TrilinosWrappers::SparseMatrix &dXvdXp_FD, const double eps)
std::shared_ptr< dealii::MappingFEField< dim, dim, VectorType, DoFHandlerType > > initial_mapping_fe_field
MappingFEField that will provide the polynomial-based grid for the initial volume_nodes.
dealii::DoFHandler< dim > dof_handler_grid
Degrees of freedom handler for the high-order grid.
dealii::Tensor< 1, dim, real > get_displacement(const dealii::Point< dim, double > &initial_point, const std::vector< dealii::Point< dim, real >> &control_pts) const
VectorType volume_nodes
Current nodal coefficients of the high-order grid.
const unsigned int n_control_pts
Total number of control points.
std::map< std::pair< unsigned int, unsigned int >, dealii::types::global_dof_index > point_and_axis_to_global_index
const std::array< unsigned int, dim > ndim_control_pts
Number of control points in each direction.
unsigned int grid_to_global(const std::array< unsigned int, dim > &ijk_index) const
Given a control points&#39; ijk coordinate return its global indexing.
void set_design_variables(const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim, const dealii::LinearAlgebra::distributed::Vector< double > &vector_to_copy_from)
Copies the desired control points from vector_to_copy_from into FreeFormDeformation object...
std::array< dealii::Tensor< 1, dim, double >, dim > get_rectangular_parallepiped_vectors(const std::array< double, dim > &rectangle_lengths) const
Returns rectangular vector box given the box lengths.
dealii::Point< dim, real > evaluate_ffd(const dealii::Point< dim, double > &s_t_u_point, const std::vector< dealii::Point< dim, real >> &control_pts) const