2 #include <boost/math/special_functions/binomial.hpp> 6 #include "free_form_deformation.h" 7 #include "meshmover_linear_elasticity.hpp" 9 #include <deal.II/base/utilities.h> 10 #include <deal.II/grid/grid_out.h> 12 #include <deal.II/grid/grid_reordering.h> 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> 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)
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)
38 for (
int d=0; d<dim; ++d) {
45 pcout <<
" **************************************** " << std::endl;
50 const dealii::Point<dim> &_origin,
51 const std::array<double,dim> &rectangle_lengths,
52 const std::array<unsigned int,dim> &_ndim_control_pts)
59 dealii::Point<dim,double> local_coordinates;
60 std::array<dealii::Tensor<1,dim,double>,dim> perp_vectors;
61 if constexpr (dim == 1) {
64 if constexpr (dim == 2) {
73 if constexpr (dim == 3) {
80 const dealii::Tensor<1,dim,double> dX = (p -
origin);
81 for (
int d=0;d<dim;++d) {
91 return local_coordinates;
99 for (
int d=0; d<dim; ++d) {
100 parallepiped_vectors[d][d] = rectangle_lengths[d];
108 std::array<unsigned int,dim> ijk_index;
110 unsigned int remain = global_ictl;
111 for (
int d=0; d<dim; ++d) {
123 for (
int d=0;d<dim;++d) {
127 unsigned int global_index = 0;
128 if constexpr (dim == 1) {
129 global_index = ijk_index[0];
131 if constexpr (dim == 2) {
132 global_index = ijk_index[0];
135 if constexpr (dim == 3) {
136 global_index = ijk_index[0];
138 global_index += ijk_index[2] * ndim_control_pts[0] * ndim_control_pts[1];
147 unsigned int total = 1;
155 pcout <<
" **************************************** " << std::endl;
156 pcout <<
" * Creating Free-Form Deformation (FFD) * " << std::endl;
158 pcout <<
" Parallepiped with corner volume_nodes located at: * " << std::endl;
162 for (
int d=0; d<dim; ++d) {
192 template<
typename real>
195 const dealii::Point<dim,double> &initial_point,
196 const std::vector<dealii::Point<dim,real>> &
control_pts)
const 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];
205 return initial_point_ad;
212 template<
typename real>
215 const dealii::Point<dim,double> &initial_point,
216 const std::vector<dealii::Point<dim,real>> &
control_pts)
const 219 const dealii::Tensor<1,dim,real> displacement = new_point - initial_point;
225 template<
typename real>
228 const std::vector<dealii::Point<dim,double>> &initial_points,
229 const std::vector<dealii::Point<dim,real>> &
control_pts)
const 231 std::vector<dealii::Tensor<1,dim,real>> displacements;
232 for (
unsigned int i=0; i<initial_points.size(); ++i) {
235 return displacements;
240 ::dXdXp (
const dealii::Point<dim,double> &initial_point,
const unsigned int ctl_index,
const unsigned int ctl_axis)
const 242 assert(ctl_axis < dim);
244 using FadType = Sacado::Fad::DFad<double>;
245 std::vector<dealii::Point<dim,FadType>> control_pts_ad(
control_pts.size());
249 control_pts_ad[ctl_index][ctl_axis].diff(0,1);
251 dealii::Point<dim, FadType> new_point_ad =
new_point_location(initial_point, control_pts_ad);
253 dealii::Point<dim,double>
dXdXp;
254 for (
int d=0; d<dim; ++d) {
255 dXdXp[d] = new_point_ad[d].dx(0);
261 template<
typename real>
264 const dealii::Point<dim,double> &s_t_u_point,
265 const std::vector<dealii::Point<dim,real>> &
control_pts)
const 267 dealii::Point<dim,real> ffd_location;
269 std::array<std::vector<real>,dim> ijk_coefficients;
271 for (
int d=0; d<dim; ++d) {
272 ffd_location[d] = 0.0;
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);
289 for (
int d=0; d<dim; ++d) {
290 coeff *= ijk_coefficients[d][ijk[d]];
292 for (
int d=0; d<dim; ++d) {
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 306 AssertDimension(ffd_design_variables_indices_dim.size(), vector_to_copy_into.size())
307 auto partitioner = vector_to_copy_into.get_partitioner();
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];
316 vector_to_copy_into.update_ghost_values();
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)
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) {
330 assert( partitioner->in_local_range(i_dvar) || partitioner->is_ghost_entry(i_dvar) );
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];
342 dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements =
get_surface_displacement (high_order_grid);
350 surface_node_displacements);
358 dealii::LinearAlgebra::distributed::Vector<double>
362 dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements(high_order_grid.
surface_nodes);
366 auto new_node = surface_node_displacements.begin();
368 const dealii::types::global_dof_index global_idof_index = *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++) {
377 *new_node = new_point[component];
379 surface_node_displacements.update_ghost_values();
381 surface_node_displacements.update_ghost_values();
383 return surface_node_displacements;
387 std::vector<dealii::LinearAlgebra::distributed::Vector<double>>
391 const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
395 std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector_FD;
397 for (
auto const &ffd_pair: ffd_design_variables_indices_dim) {
399 const unsigned int ictl = ffd_pair.first;
400 const unsigned int d_ffd = ffd_pair.second;
403 const dealii::Point<dim> old_ffd_point =
control_pts[ictl];
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);
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);
427 auto diff = surface_node_displacements_p;
428 diff -= surface_node_displacements_n;
432 dealii::LinearAlgebra::distributed::Vector<double> derivative_surface_nodes_ffd_ctl;
433 derivative_surface_nodes_ffd_ctl.reinit(high_order_grid.
volume_nodes);
446 dXvsdXp_vector_FD.push_back(derivative_surface_nodes_ffd_ctl);
448 return dXvsdXp_vector_FD;
452 std::vector<dealii::LinearAlgebra::distributed::Vector<double>>
456 const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim
459 std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector;
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) {
464 const unsigned int ctl_index = ffd_pair.first;
465 const unsigned int ctl_axis = ffd_pair.second;
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;
472 dealii::Point<dim,double> dxsdxp =
dXdXp (surface_point, ctl_index, ctl_axis);
474 for (
int d=0; d<dim; ++d) {
475 if ((
unsigned int)d!=ctl_axis) {
476 assert(dxsdxp[d] == 0.0);
479 if (nodes_locally_owned.is_element(vol_index)) {
480 derivative_surface_nodes_ffd_ctl[vol_index] = dxsdxp[d];
486 derivative_surface_nodes_ffd_ctl.update_ghost_values();
488 dXvsdXp_vector.push_back(derivative_surface_nodes_ffd_ctl);
490 return dXvsdXp_vector;
498 const std::vector< std::pair< unsigned int, unsigned int > > &ffd_design_variables_indices_dim,
499 dealii::TrilinosWrappers::SparseMatrix &dXvsdXp
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);
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);
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);
517 dealii::SparsityPattern full_sp;
518 full_sp.copy_from(full_dsp);
520 dXvsdXp.reinit(row_part, col_part, full_sp, MPI_COMM_WORLD);
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) {
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;
530 unsigned int ipoint = 0;
533 dealii::Point<dim,double> dxsdxp =
dXdXp (surface_point, ctl_index, ctl_axis);
535 for (
int d=0; d<dim; ++d) {
537 if (nodes_locally_owned.is_element(vol_index)) {
538 dXvsdXp.set(vol_index,i_col, dxsdxp[d]);
540 if ((
unsigned int)d!=ctl_axis) {
541 assert(dxsdxp[d] == 0.0);
548 dXvsdXp.compress(dealii::VectorOperation::insert);
556 const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim,
557 dealii::TrilinosWrappers::SparseMatrix &dXvdXp
562 std::vector<dealii::LinearAlgebra::distributed::Vector<double>> dXvsdXp_vector =
get_dXvsdXp(high_order_grid, ffd_design_variables_indices_dim);
564 dealii::LinearAlgebra::distributed::Vector<double> surface_node_displacements(high_order_grid.
surface_nodes);
571 surface_node_displacements);
581 const std::vector< std::pair< unsigned int, unsigned int > > ffd_design_variables_indices_dim,
582 dealii::TrilinosWrappers::SparseMatrix &dXvdXp_FD,
586 const unsigned int n_rows = high_order_grid.
volume_nodes.size();
587 const unsigned int n_cols = ffd_design_variables_indices_dim.size();
590 const dealii::IndexSet &row_part = high_order_grid.
dof_handler_grid.locally_owned_dofs();
595 const dealii::IndexSet col_part = dealii::Utilities::MPI::create_evenly_distributed_partitioning(MPI_COMM_WORLD,n_cols);
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);
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);
611 dXvdXp_FD.reinit(row_part, col_part, full_sp, MPI_COMM_WORLD);
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;
620 const dealii::Point<dim> old_ffd_point =
control_pts[ictl];
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);
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);
650 auto dXvdXp_i = nodes_p;
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]);
659 dXvdXp_FD.compress(dealii::VectorOperation::insert);
666 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) != 0)
return;
668 std::vector<dealii::CellData<dim>> cells;
669 unsigned int n_cells = 1;
670 for (
int d = 0; d<dim; ++d) {
673 cells.resize(n_cells);
676 std::array<unsigned int, dim> repetitions;
677 for (
int d = 0; d < dim; ++d) {
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;
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;
708 const unsigned int n_x = (repetitions[0] + 1);
709 const unsigned int n_xy = (repetitions[0] + 1) * (repetitions[1] + 1);
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;
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) {
738 std::string filename =
"FFD-" + dealii::Utilities::int_to_string(dim, 1) +
"D_";
739 for (
int d=0; d<dim; ++d) {
741 if (d<dim-1) filename +=
"X";
743 filename +=
"-"+dealii::Utilities::int_to_string(cycle, 4) +
".vtu";
744 pcout <<
"Outputting FFD grid: " << filename <<
" ... " << std::endl;
746 std::ofstream output(filename);
748 dealii::GridOut grid_out;
749 grid_out.write_vtu (tria, output);
VectorType initial_volume_nodes
Initial nodal coefficients of the high-order grid.
Sacado::Fad::DFad< double > FadType
Sacado AD type for first derivatives.
std::vector< dealii::Point< dim > > initial_locally_relevant_surface_points
Initial locally relevant surface points.
Files for the baseline physics.
VectorType initial_surface_nodes
Distributed ghosted vector of initial surface nodes.
dealii::TrilinosWrappers::SparseMatrix map_nodes_surf_to_vol
const std::shared_ptr< MeshType > triangulation
Mesh.
void apply_dXvdXvs(std::vector< dealii::LinearAlgebra::distributed::Vector< double >> &list_of_vectors, dealii::TrilinosWrappers::SparseMatrix &output_matrix)
std::map< dealii::types::global_dof_index, std::pair< unsigned int, unsigned int > > global_index_to_point_and_axis
dealii::LinearAlgebra::distributed::Vector< int > surface_to_volume_indices
VectorType get_volume_displacements()
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.
VectorType volume_nodes
Current nodal coefficients of the high-order grid.
std::map< std::pair< unsigned int, unsigned int >, dealii::types::global_dof_index > point_and_axis_to_global_index