3 #include <deal.II/base/exceptions.h> 6 #include <deal.II/fe/mapping_q.h> 7 #include <deal.II/fe/mapping_q_generic.h> 8 #include <deal.II/fe/fe_dgq.h> 9 #include <deal.II/fe/fe_system.h> 10 #include <deal.II/dofs/dof_handler.h> 13 #include <deal.II/fe/fe_q.h> 14 #include <deal.II/fe/fe_bernstein.h> 16 #include <deal.II/grid/tria.h> 17 #include <deal.II/distributed/shared_tria.h> 18 #include <deal.II/distributed/tria.h> 20 #include <deal.II/dofs/dof_tools.h> 22 #include <deal.II/fe/fe_bernstein.h> 24 #include <deal.II/numerics/vector_tools.h> 27 #include <deal.II/differentiation/ad/sacado_product_types.h> 29 #include <deal.II/optimization/solver_bfgs.h> 31 #include <deal.II/grid/grid_tools.h> 33 #include <deal.II/lac/sparsity_tools.h> 34 #include <deal.II/lac/sparse_matrix.h> 35 #include <deal.II/lac/dynamic_sparsity_pattern.h> 36 #include <deal.II/lac/sparsity_pattern.h> 37 #include <deal.II/lac/lapack_full_matrix.h> 39 #include <deal.II/dofs/dof_renumbering.h> 41 #include <deal.II/meshworker/local_integrator.h> 42 #include <deal.II/integrators/l2.h> 44 #include "high_order_grid.h" 49 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
52 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
54 const unsigned int max_degree,
55 const std::shared_ptr<MeshType> triangulation_input,
56 const bool check_valid_metric_Jacobian_input,
57 const bool renumber_dof_handler_Cuthill_Mckee_input,
58 const bool output_high_order_grid)
59 : max_degree(max_degree)
60 , triangulation(triangulation_input)
61 , check_valid_metric_Jacobian(check_valid_metric_Jacobian_input)
62 , renumber_dof_handler_Cuthill_Mckee(renumber_dof_handler_Cuthill_Mckee_input)
63 , dof_handler_grid(*triangulation)
65 , fe_system(dealii::FESystem<dim>(fe_q,dim))
66 , oneD_fe_q(max_degree)
67 , oneD_fe_system(oneD_fe_q,1)
68 , oneD_grid_nodes(max_degree+1)
69 , dim_grid_nodes(max_degree+1)
70 , solution_transfer(dof_handler_grid)
71 , mpi_communicator(MPI_COMM_WORLD)
72 , pcout(
std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0)
74 MPI_Comm_rank(MPI_COMM_WORLD, &
mpi_rank);
75 MPI_Comm_size(MPI_COMM_WORLD, &
n_mpi);
77 Assert(max_degree > 0, dealii::ExcMessage(
"Grid must be at least order 1."));
87 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
91 const dealii::ComponentMask mask(dim,
true);
113 const unsigned int exact_jacobian_order = (
max_degree-1) * dim;
114 const unsigned int min_jacobian_order = 1;
115 const unsigned int used_jacobian_order = std::max(exact_jacobian_order, min_jacobian_order);
121 for (; cell!=endcell; ++cell) {
122 if (!cell->is_locally_owned())
continue;
125 if ( !is_invalid_cell ) {
128 <<
" Cell: " << cell->active_cell_index() <<
" has an invalid Jacobian." << std::endl;
136 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
139 const dealii::ComponentMask mask(dim,
true);
147 const unsigned int exact_jacobian_order = (
max_degree-1) * dim;
148 const unsigned int min_jacobian_order = 1;
149 const unsigned int used_jacobian_order = std::max(exact_jacobian_order, min_jacobian_order);
155 for (; cell!=endcell; ++cell) {
156 if (!cell->is_locally_owned())
continue;
159 if ( !is_invalid_cell ) {
162 <<
" Cell: " << cell->active_cell_index() <<
" has an invalid Jacobian." << std::endl;
169 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
174 dealii::AffineConstraints<double> hanging_node_constraints;
175 hanging_node_constraints.clear();
176 dealii::DoFTools::make_hanging_node_constraints(
dof_handler_grid, hanging_node_constraints);
177 hanging_node_constraints.close();
185 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
187 const dealii::ComponentMask mask(dim,
true);
192 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
231 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
235 AssertDimension(position_vector.size(), dh.n_dofs());
236 const dealii::FESystem<dim, dim> &fe = dh.get_fe();
239 const dealii::ComponentMask fe_mask(mask.size() ? mask : dealii::ComponentMask(fe.get_nonzero_components(0).size(),
true));
241 AssertDimension(fe_mask.size(), fe.get_nonzero_components(0).size());
243 std::vector<unsigned int> fe_to_real(fe_mask.size(), dealii::numbers::invalid_unsigned_int);
244 unsigned int size = 0;
245 for (
unsigned int i = 0; i < fe_mask.size(); ++i) {
246 if (fe_mask[i]) fe_to_real[i] = size++;
248 Assert(size == dim, dealii::ExcMessage(
"The Component Mask you provided is invalid. It has to select exactly dim entries."));
250 const dealii::Quadrature<dim> quad(fe.get_unit_support_points());
252 dealii::MappingQGeneric<dim, dim> map_q(fe.degree);
253 dealii::FEValues<dim, dim> fe_v(map_q, fe, quad, dealii::update_quadrature_points);
254 std::vector<dealii::types::global_dof_index> dofs(fe.dofs_per_cell);
256 AssertDimension(fe.dofs_per_cell, fe.get_unit_support_points().size());
257 Assert(fe.is_primitive(), dealii::ExcMessage(
"FE is not Primitive! This won't work."));
259 for (
const auto &cell : dh.active_cell_iterators()) {
260 if (cell->is_locally_owned()) {
262 cell->get_dof_indices(dofs);
263 const std::vector<dealii::Point<dim>> &points = fe_v.get_quadrature_points();
264 for (
unsigned int q = 0; q < points.size(); ++q) {
265 const unsigned int comp = fe.system_to_component_index(q).first;
266 if (fe_mask[comp]) ::dealii::internal::ElementAccess<VectorType>::set(points[q][fe_to_real[comp]], dofs[q], position_vector);
272 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
276 AssertDimension(position_vector.size(), dh.n_dofs());
277 const dealii::FESystem<dim, dim> &fe = dh.get_fe();
280 const dealii::ComponentMask fe_mask(mask.size() ? mask : dealii::ComponentMask(fe.get_nonzero_components(0).size(),
true));
282 AssertDimension(fe_mask.size(), fe.get_nonzero_components(0).size());
284 std::vector<unsigned int> fe_to_real(fe_mask.size(), dealii::numbers::invalid_unsigned_int);
285 unsigned int size = 0;
286 for (
unsigned int i = 0; i < fe_mask.size(); ++i) {
287 if (fe_mask[i]) fe_to_real[i] = size++;
289 Assert(size == dim, dealii::ExcMessage(
"The Component Mask you provided is invalid. It has to select exactly dim entries."));
291 const dealii::QGauss<dim> quad((fe.degree+1) * 2);
293 dealii::MappingQGeneric<dim, dim> map_q(fe.degree);
294 dealii::FEValues<dim, dim> fe_values_curved(map_q, fe, quad, dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values);
296 dealii::MappingQ1<dim, dim> map_q1;
297 dealii::FEValues<dim, dim> fe_values_straight(map_q1, fe, quad, dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_jacobians);
299 const unsigned int n_dofs = fe.dofs_per_cell;
300 dealii::FullMatrix<double> mass_matrix(n_dofs, n_dofs);
301 dealii::FullMatrix<double> inv_mass_matrix(n_dofs, n_dofs);
303 fe_values_straight.reinit(dh.begin_active());
304 dealii::LocalIntegrators::L2::mass_matrix(mass_matrix, fe_values_straight);
305 inv_mass_matrix.invert(mass_matrix);
307 std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_cell);
309 AssertDimension(fe.dofs_per_cell, fe.get_unit_support_points().size());
310 Assert(fe.is_primitive(), dealii::ExcMessage(
"FE is not Primitive! This won't work."));
312 for (
const auto &cell : dh.active_cell_iterators()) {
313 if (cell->is_locally_owned()) {
314 fe_values_curved.reinit(cell);
315 fe_values_straight.reinit(cell);
320 cell->get_dof_indices(dof_indices);
321 const std::vector<dealii::Point<dim>> &quadrature_points_values = fe_values_curved.get_quadrature_points();
323 dealii::Vector<double> rhs(n_dofs);
324 for (
unsigned int idof=0; idof<n_dofs; ++idof) {
325 const unsigned int axis = fe.system_to_component_index(idof).first;
327 for (
unsigned int q=0; q<quadrature_points_values.size(); ++q) {
328 rhs[idof] += fe_values_curved.shape_value_component(idof, q, axis) * quadrature_points_values[q][axis] * quad.weight(q);
331 dealii::Vector<double> new_dof_values(n_dofs);
332 inv_mass_matrix.vmult(new_dof_values, rhs);
334 for (
unsigned int idof = 0; idof < new_dof_values.size(); ++idof) {
335 const unsigned int comp = fe.system_to_component_index(idof).first;
336 if (fe_mask[comp]) ::dealii::internal::ElementAccess<VectorType>::set(new_dof_values[idof], dof_indices[idof], position_vector);
436 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
437 template <
typename real2>
439 ::determinant(
const std::array< dealii::Tensor<1,dim,real2>, dim > jacobian)
const 441 if constexpr(dim == 1)
return jacobian[0][0];
442 if constexpr(dim == 2)
443 return jacobian[0][0] * jacobian[1][1] - jacobian[1][0] * jacobian[0][1];
444 if constexpr(dim == 3)
445 return (+ jacobian[0][0] *(jacobian[1][1] * jacobian[2][2] - jacobian[1][2] * jacobian[2][1])
446 - jacobian[0][1] *(jacobian[1][0] * jacobian[2][2] - jacobian[1][2] * jacobian[2][0])
447 + jacobian[0][2] *(jacobian[1][0] * jacobian[2][1] - jacobian[1][1] * jacobian[2][0]));
451 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
453 const VectorType &solution,
454 const typename DoFHandlerType::cell_iterator &cell,
455 const std::vector<dealii::Point<dim>> &points)
const 457 const dealii::FESystem<dim> &fe = cell->get_fe();
458 const unsigned int n_quad_pts = points.size();
459 const unsigned int n_dofs_cell = fe.n_dofs_per_cell();
460 const unsigned int n_axis = dim;
462 std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_cell);
463 cell->get_dof_indices (dofs_indices);
465 std::array<real,n_axis> coords;
466 std::array< dealii::Tensor<1,dim,real>, n_axis > coords_grad;
467 std::vector<real> jac_det(n_quad_pts);
469 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
471 for (
unsigned int iaxis=0; iaxis<n_axis; ++iaxis) {
473 coords_grad[iaxis] = 0;
475 for (
unsigned int idof=0; idof<n_dofs_cell; ++idof) {
476 const unsigned int axis = fe.system_to_component_index(idof).first;
477 coords[axis] += solution[dofs_indices[idof]] * fe.shape_value_component (idof, points[iquad], axis);
478 coords_grad[axis] += solution[dofs_indices[idof]] * fe.shape_grad_component (idof, points[iquad], axis);
482 if(jac_det[iquad] < 0) {
483 dealii::Point<dim> phys_point;
484 for (
int d=0;d<dim;++d) {
485 phys_point[d] = coords[d];
487 std::cout <<
" Negative Jacobian determinant. Ref Point: " << points[iquad]
488 <<
" Phys Point: " << phys_point
489 <<
" J: " << jac_det[iquad] << std::endl;
490 std::cout <<
"Jacobian " << std::endl;
491 for (
int row=0;row<dim;++row) {
492 for (
int col=0;col<dim;++col) {
493 std::cout << coords_grad[row][col] <<
" ";
495 std::cout << std::endl;
502 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
503 template <
typename real2>
505 const std::vector<real2> &dofs,
506 const dealii::FESystem<dim> &fe,
507 const dealii::Point<dim> &point)
const 509 AssertDimension(dim, fe.n_components());
511 const unsigned int n_dofs_coords = fe.n_dofs_per_cell();
512 const unsigned int n_axis = dim;
514 std::array< dealii::Tensor<1,dim,real2>, n_axis > coords_grad;
515 for (
unsigned int idof=0; idof<n_dofs_coords; ++idof) {
516 const unsigned int axis = fe.system_to_component_index(idof).first;
517 coords_grad[axis] += dofs[idof] * fe.shape_grad (idof, point);
522 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
523 template <
typename real2>
525 const std::vector<real2> &dofs,
526 const dealii::FESystem<dim> &fe,
527 const std::vector<dealii::Point<dim>> &points,
528 std::vector<real2> &jacobian_determinants)
const 530 AssertDimension(dim, fe.n_components());
531 AssertDimension(jacobian_determinants.size(), points.size());
533 const unsigned int n_points = points.size();
535 for (
unsigned int i=0; i<n_points; ++i) {
540 template<
typename real>
541 std::vector<real> matrix_stdvector_mult(
const dealii::FullMatrix<double> &matrix,
const std::vector<real> &vector_in)
543 const unsigned int m = matrix.m(), n = matrix.n();
544 AssertDimension(vector_in.size(),n);
545 std::vector<real> vector_out(m,0.0);
546 for (
unsigned int row=0; row<m; ++row) {
547 for (
unsigned int col=0; col<n; ++col) {
548 vector_out[row] += matrix[row][col]*vector_in[col];
554 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
557 const dealii::FE_Q<dim> lagrange_basis(order);
558 const std::vector< dealii::Point<dim> > &lagrange_pts = lagrange_basis.get_unit_support_points();
559 const unsigned int n_lagrange_pts = lagrange_pts.size();
561 const dealii::FE_Bernstein<dim> bernstein_basis(order);
562 const unsigned int n_bernstein = bernstein_basis.n_dofs_per_cell();
563 AssertDimension(n_bernstein, n_lagrange_pts);
567 dealii::FullMatrix<double> bernstein_to_lagrange(n_bernstein, n_lagrange_pts);
568 for (
unsigned int ibernstein=0; ibernstein<n_bernstein; ++ibernstein) {
569 for (
unsigned int ijacpts=0; ijacpts<n_bernstein; ++ijacpts) {
570 const dealii::Point<dim> &point = lagrange_pts[ijacpts];
571 bernstein_to_lagrange[ibernstein][ijacpts] = bernstein_basis.shape_value(ibernstein, point);
575 if (n_lagrange_pts > 1000)
pcout <<
"Careful, about to invert a " << n_lagrange_pts <<
" x " << n_lagrange_pts <<
" dense matrix for Mesh..." << std::endl;
577 if (n_lagrange_pts > 1000)
pcout <<
"Done inverting a " << n_lagrange_pts <<
" x " << n_lagrange_pts <<
" dense matrix..." << std::endl;
581 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
585 const unsigned int exact_jacobian_order = (
max_degree-1) * dim, min_jacobian_order = 1;
586 const unsigned int used_jacobian_order = std::max(exact_jacobian_order, min_jacobian_order);
589 const dealii::FESystem<dim> &fe_coords = cell->get_fe();
590 const unsigned int n_dofs_coords = fe_coords.n_dofs_per_cell();
591 std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_coords);
592 cell->get_dof_indices (dofs_indices);
594 std::vector< real > cell_nodes(n_dofs_coords);
595 for (
unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
599 const dealii::FE_Q<dim> lagrange_basis(used_jacobian_order);
600 const std::vector< dealii::Point<dim> > &lagrange_pts = lagrange_basis.get_unit_support_points();
601 const unsigned int n_lagrange_pts = lagrange_pts.size();
602 const unsigned int n_bernstein = n_lagrange_pts;
603 std::vector<real> lagrange_coeff(n_lagrange_pts);
607 const real tol = 1e-12;
608 for (
unsigned int i=0; i<n_bernstein;++i) {
609 if (bernstein_coeff[i] <= tol) {
610 std::cout <<
"Negative bernstein coeff: " << i <<
" " << bernstein_coeff[i] << std::endl;
643 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
649 const double target_ratio = 0.1;
652 const int max_barrier_iterations = 100;
654 const unsigned int exact_jacobian_order = (
max_degree-1) * dim, min_jacobian_order = 1;
655 const unsigned int used_jacobian_order = std::max(exact_jacobian_order, min_jacobian_order);
656 const dealii::FE_Q<dim> lagrange_basis(used_jacobian_order);
657 const std::vector< dealii::Point<dim> > &lagrange_pts = lagrange_basis.get_unit_support_points();
658 const unsigned int n_lagrange_pts = lagrange_pts.size(), n_bernstein = n_lagrange_pts;
660 const dealii::FESystem<dim> &fe_coords = cell->get_fe();
661 const unsigned int n_dofs_coords = fe_coords.n_dofs_per_cell();
663 std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_coords);
664 cell->get_dof_indices (dofs_indices);
667 using FadType = Sacado::Fad::DFad<real>;
668 std::vector<FadType> cell_nodes(n_dofs_coords);
669 std::vector<FadType> lagrange_coeff(n_lagrange_pts);
670 std::vector<FadType> bernstein_coeff(n_bernstein);
673 std::vector< bool > movable(n_dofs_coords);
674 unsigned int n_movable_nodes = 0;
683 for (
unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
684 const bool is_movable = (idof/dim > 2*dim);
685 movable[idof] = is_movable;
686 if (is_movable) n_movable_nodes++;
692 const unsigned int n_vertices = dealii::GeometryInfo<dim>::vertices_per_cell;
693 const dealii::FE_Q<dim> straight_sided_elem_fe(1);
694 const dealii::FESystem<dim> straight_sided_elem_fesystem(straight_sided_elem_fe, dim);
695 std::vector<real> straight_sided_dofs(straight_sided_elem_fesystem.n_dofs_per_cell());
696 for (
unsigned int ivertex = 0; ivertex < n_vertices; ++ivertex) {
697 const dealii::Point<dim> unit_vertex = dealii::GeometryInfo<dim>::unit_cell_vertex(ivertex);
698 const dealii::Point<dim> phys_vertex =
mapping_fe_field->transform_unit_to_real_cell(cell, unit_vertex);
699 for (
int d=0;d<dim;++d) {
700 straight_sided_dofs[ivertex*dim+d] = phys_vertex[d];
703 dealii::Point<dim> unit_cell_center;
704 unit_cell_center[0] = 0.5;
705 if constexpr (dim>=2) unit_cell_center[1] = 0.5;
706 if constexpr (dim>=3) unit_cell_center[2] = 0.5;
709 const double straight_sided_jacobian =
evaluate_jacobian_at_point(straight_sided_dofs, straight_sided_elem_fesystem, unit_cell_center);
713 dealii::Vector<real> movable_nodes(n_movable_nodes);
714 unsigned int idesign = 0;
715 for (
unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
717 if (movable[idof]) movable_nodes[idesign++] = cell_nodes[idof].val();
721 real min_ratio = -1.0;
722 for (
int barrier_iterations = 0; barrier_iterations < max_barrier_iterations && min_ratio < target_ratio; ++barrier_iterations) {
723 min_ratio = bernstein_coeff[0].val();
724 for (
unsigned int i=0; i<n_bernstein;++i) {
725 min_ratio = std::min(bernstein_coeff[i].val(), min_ratio);
727 min_ratio /= straight_sided_jacobian;
728 std::cout <<
" Barrier iteration : " << barrier_iterations << std::endl;
729 std::cout <<
"Current minimum Jacobian ratio: " << min_ratio << std::endl;
731 const double barrier = min_ratio - 0.10*std::abs(min_ratio);
732 const double barrierJac = barrier*straight_sided_jacobian;
734 std::function<real (const dealii::Vector<real> &, dealii::Vector<real> &)> func =
735 [&](
const dealii::Vector<real> &movable_nodes, dealii::Vector<real> &gradient) {
737 unsigned int idesign = 0;
738 for (
unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
740 cell_nodes[idof] = movable_nodes[idesign];
741 cell_nodes[idof].diff(idesign, n_movable_nodes);
749 min_ratio = bernstein_coeff[0].val();
750 for (
unsigned int i=0; i<n_bernstein;++i) {
751 FadType logterm = std::log((bernstein_coeff[i] - barrierJac) / (straight_sided_jacobian - barrierJac));
752 FadType quadraticterm = bernstein_coeff[i] / straight_sided_jacobian - 1.0;
753 functional += std::pow(logterm,2) + std::pow(quadraticterm,2);
754 min_ratio = std::min(bernstein_coeff[i].val(), min_ratio);
756 min_ratio /= straight_sided_jacobian;
763 for (
unsigned int i = 0; i < movable_nodes.size(); ++i) {
765 gradient[i] = functional.dx(i);
767 return functional.val();
779 const unsigned int max_opt_iterations = 1000;
780 const unsigned int n_line_search = 40;
781 const double initial_step_length = 1.0;
782 dealii::Vector<real> old_movable_nodes(n_movable_nodes);
783 dealii::Vector<real> search_direction(n_movable_nodes);
784 dealii::Vector<real> grad(n_movable_nodes);
785 dealii::Vector<real> old_grad(n_movable_nodes);
786 real functional = func(movable_nodes, grad);
787 const real initial_grad_norm = grad.l2_norm();
788 double grad_norm = grad.l2_norm();
789 dealii::FullMatrix<real> hessian_inverse(n_movable_nodes);
790 dealii::FullMatrix<real> outer_product_term(n_movable_nodes);
791 dealii::Vector<real> dg(n_movable_nodes);
792 dealii::Vector<real> dx(n_movable_nodes);
793 dealii::Vector<real> B_dg(n_movable_nodes);
795 for (
unsigned int inode=0; inode<n_movable_nodes; ++inode) {
796 hessian_inverse[inode][inode] = 1.0e-8;
800 const double gradient_drop = 1e-2;
801 for (
unsigned int i=0;i<max_opt_iterations && grad_norm/initial_grad_norm > gradient_drop;++i) {
803 old_movable_nodes = movable_nodes;
806 hessian_inverse.vmult(search_direction, grad);
807 search_direction *= -1.0;
808 double step_length = initial_step_length;
809 real old_functional = functional;
810 unsigned int i_line_search;
811 for (i_line_search = 0; i_line_search<n_line_search; ++i_line_search) {
812 movable_nodes = old_movable_nodes;
813 movable_nodes.add(step_length, search_direction);
815 functional = func(movable_nodes, grad);
816 if (std::isnan(functional))
throw -1;
817 if (functional-old_functional < 1e-4 * step_length * (grad*search_direction))
break;
844 grad_norm = grad.l2_norm();
845 std::cout <<
" Barrier its : " << barrier_iterations
846 <<
" min_ratio: " << min_ratio
847 <<
" BFGS its : " << i
848 <<
" Func : " << functional
849 <<
" |Grad|: " << grad_norm / initial_grad_norm
850 <<
" Step length: " << step_length
853 dx = movable_nodes; dx -= old_movable_nodes;
854 dg = grad; dg -= old_grad;
855 const real dgdx = dg*dx;
856 if (dgdx < 0)
continue;
857 hessian_inverse.vmult(B_dg, dg);
858 const real dg_B_dg = dg*B_dg;
859 const real scaling1 = (dgdx + dg_B_dg) / (dgdx*dgdx);
860 const real scaling2 = -1.0/dgdx;
861 outer_product_term.outer_product(dx, dx);
862 hessian_inverse.add(scaling1, outer_product_term);
863 outer_product_term.outer_product(B_dg, dx);
864 hessian_inverse.add(scaling2, outer_product_term);
865 hessian_inverse.Tadd(scaling2, outer_product_term);
870 const real tol = 1e-12;
871 for (
unsigned int i=0; i<n_bernstein;++i) {
872 if (bernstein_coeff[i] <= tol) {
873 std::cout <<
"Unable to fix cell "<< std::endl;
874 std::cout <<
"Bernstein coeff: " << bernstein_coeff[i] << std::endl;
875 std::cout <<
"Bernstein vector: " ;
876 for (
unsigned int j=0; j<n_bernstein;++j) {
877 std::cout << bernstein_coeff[j] <<
" ";
879 std::cout << std::endl;
949 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1015 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1024 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1033 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1036 if constexpr (std::is_same_v<
typename dealii::SolutionTransfer<dim,VectorType,DoFHandlerType>,
1042 const bool use_manifold_for_refined_nodes =
false;
1043 const dealii::ComponentMask mask(dim,
true);
1044 if (use_manifold_for_refined_nodes) {
1073 template <
typename T>
1074 std::vector<T> flatten(
const std::vector<std::vector<T>>& v) {
1075 std::size_t total_size = 0;
1076 for (
const auto& sub : v) {
1077 total_size += sub.size();
1079 std::vector<T> result;
1080 result.reserve(total_size);
1081 for (
const auto& sub : v) {
1082 result.insert(result.end(), sub.begin(), sub.end());
1087 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1106 std::vector<std::vector<real>> vector_locally_owned_surface_nodes(
n_mpi);
1107 std::vector<std::vector<unsigned int>> vector_locally_owned_surface_indices(
n_mpi);
1108 std::vector<MPI_Request> request(
n_mpi);
1109 for (
int i_mpi=0; i_mpi<
n_mpi; ++i_mpi) {
1118 for (
int i_mpi=0; i_mpi<
n_mpi; ++i_mpi) {
1126 unsigned int low_range = 0;
1127 for (
int i_mpi=0; i_mpi<
mpi_rank; ++i_mpi) {
1149 std::vector<unsigned int> n_locally_relevant_surface_nodes_per_mpi(
n_mpi);
1150 MPI_Allgather(&n_locally_relevant_surface_nodes, 1, MPI_UNSIGNED, &(n_locally_relevant_surface_nodes_per_mpi[0]), 1, MPI_UNSIGNED, MPI_COMM_WORLD);
1172 std::cout <<
"Could not find index " << *index <<
" in the surface indices... Aborting. " << std::endl;
1173 std::cout <<
"All surface_indices: " << std::endl;
1175 std::cout <<
"i " << i <<
" all_surface_indices[i] " <<
all_surface_indices[i] << std::endl;
1177 std::cout <<
"Locally relevant surface nodes indices: " << std::endl;
1181 std::cout <<
"Locally owned surface nodes indices: " << std::endl;
1209 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1215 const dealii::IndexSet &row_part =
volume_nodes.get_partitioner()->locally_owned_range();
1216 dealii::IndexSet locally_relevant_dofs;
1217 dealii::DoFTools::extract_locally_relevant_dofs(
dof_handler_grid, locally_relevant_dofs);
1219 const dealii::IndexSet &col_part =
surface_nodes.get_partitioner()->locally_owned_range();
1221 dealii::DynamicSparsityPattern dsp(n_rows, n_cols, row_part);
1222 for (
unsigned int i_col = 0; i_col < n_cols; ++i_col) {
1223 if (col_part.is_element(i_col)) {
1225 dsp.add(i_row, i_col);
1229 dealii::SparsityTools::distribute_sparsity_pattern(dsp, row_part,
mpi_communicator, locally_relevant_dofs);
1233 for (
unsigned int i_col = 0; i_col < n_cols; ++i_col) {
1234 if (col_part.is_element(i_col)) {
1243 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1253 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1264 const unsigned int dofs_per_cell =
fe_system.n_dofs_per_cell();
1265 const unsigned int dofs_per_face =
fe_system.n_dofs_per_face();
1266 std::vector< dealii::types::global_dof_index > dof_indices(dofs_per_cell);
1271 std::unordered_set<dealii::types::global_dof_index> locally_relevant_surface_dof_indices_set;
1272 std::unordered_set<dealii::types::global_dof_index> locally_owned_surface_dof_indices_set;
1275 if (!cell->is_locally_owned() && !cell->is_ghost())
continue;
1276 if (!cell->at_boundary())
continue;
1278 cell->get_dof_indices(dof_indices);
1281 std::unordered_set<dealii::types::global_dof_index> shape_within_base_found;
1282 std::map<unsigned int, unsigned int> shape_function_within_base_to_point_index;
1284 for (
unsigned int iface=0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface) {
1285 const auto face = cell->face(iface);
1287 if (!face->at_boundary())
continue;
1289 const unsigned int boundary_id = face->boundary_id();
1294 for (
unsigned int idof_face=0; idof_face<dofs_per_face; ++idof_face) {
1298 unsigned int idof_cell =
fe_system.face_to_cell_index(idof_face, iface);
1300 const dealii::types::global_dof_index global_idof_index = dof_indices[idof_cell];
1309 if ( locally_relevant_surface_dof_indices_set.find(global_idof_index) == locally_relevant_surface_dof_indices_set.end() ) {
1310 locally_relevant_surface_dof_indices_set.insert(global_idof_index);
1315 const unsigned int i = idof_cell;
1316 const unsigned int component =
fe_system.system_to_component_index(i).first;
1317 const unsigned int shape_within_base =
fe_system.system_to_component_index(i).second;
1318 unsigned int point_index = 0;
1319 if ( shape_within_base_found.find(shape_within_base) == shape_within_base_found.end() ) {
1321 shape_within_base_found.insert(shape_within_base);
1323 dealii::Point<dim> point;
1327 shape_function_within_base_to_point_index[shape_within_base] = point_index;
1331 point_index = shape_function_within_base_to_point_index[shape_within_base];
1343 if ( locally_owned_surface_dof_indices_set.find(global_idof_index) == locally_owned_surface_dof_indices_set.end() ) {
1344 locally_owned_surface_dof_indices_set.insert(global_idof_index);
1355 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1362 auto new_node = new_surface_nodes.begin();
1364 const dealii::types::global_dof_index global_idof_index = *index;
1368 const unsigned int ipoint = ipoint_component.first;
1369 const unsigned int component = ipoint_component.second;
1370 dealii::Point<dim> point;
1371 for (
int d=0;d<dim;d++) {
1374 dealii::Point<dim> new_point = transformation(point);
1375 *new_node = new_point[component];
1377 new_surface_nodes.update_ghost_values();
1378 return new_surface_nodes;
1381 template <
int dim,
typename real,
typename MeshType,
typename VectorType,
typename DoFHandlerType>
1384 std::string master_fn =
"Mesh-" + dealii::Utilities::int_to_string(dim, 1) +
"D_GridP"+dealii::Utilities::int_to_string(
max_degree, 2)+
"-";
1385 master_fn += dealii::Utilities::int_to_string(cycle, 4) +
".pvtu";
1386 pcout <<
"Outputting grid: " << master_fn <<
" ... " << std::endl;
1388 dealii::DataOut<dim, dealii::DoFHandler<dim>> data_out;
1391 std::vector<std::string> solution_names;
1392 for(
int d=0;d<dim;++d) {
1393 if (d==0) solution_names.push_back(
"x");
1394 if (d==1) solution_names.push_back(
"y");
1395 if (d==2) solution_names.push_back(
"z");
1397 std::vector<dealii::DataComponentInterpretation::DataComponentInterpretation> data_component_interpretation(dim, dealii::DataComponentInterpretation::component_is_scalar);
1398 data_out.add_data_vector (
volume_nodes, solution_names, dealii::DataOut<dim>::type_dof_data, data_component_interpretation);
1400 dealii::Vector<float> subdomain(
triangulation->n_active_cells());
1401 for (
unsigned int i = 0; i < subdomain.size(); ++i) {
1404 data_out.add_data_vector(subdomain,
"subdomain", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
1409 VectorType jacobian_determinant;
1411 const unsigned int n_dofs_per_cell =
fe_system.n_dofs_per_cell();
1412 std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_per_cell);
1413 const std::vector< dealii::Point<dim> > &points =
fe_system.get_unit_support_points();
1414 std::vector<real> jac_det;
1416 if (!cell->is_locally_owned())
continue;
1418 cell->get_dof_indices (dofs_indices);
1419 for (
unsigned int i=0; i<n_dofs_per_cell; ++i) {
1420 jacobian_determinant[dofs_indices[i]] = jac_det[i];
1424 jacobian_determinant.update_ghost_values();
1425 std::vector<std::string> jacobian_name;
1426 for (
int d=0;d<dim;++d) {
1427 jacobian_name.push_back(
"JacobianDeterminant" + dealii::Utilities::int_to_string(d, 1));
1429 std::vector<dealii::DataComponentInterpretation::DataComponentInterpretation> jacobian_component_interpretation(dim, dealii::DataComponentInterpretation::component_is_scalar);
1430 data_out.add_data_vector (jacobian_determinant, jacobian_name, dealii::DataOut<dim>::type_dof_data, jacobian_component_interpretation);
1432 typename dealii::DataOut<dim>::CurvedCellRegion curved = dealii::DataOut<dim>::CurvedCellRegion::curved_inner_cells;
1438 data_out.build_patches(mapping, n_subdivisions, curved);
1439 const bool write_higher_order_cells = (dim>1) ?
true :
false;
1440 dealii::DataOutBase::VtkFlags vtkflags(0.0,cycle,
true,dealii::DataOutBase::VtkFlags::ZlibCompressionLevel::best_compression,write_higher_order_cells);
1441 data_out.set_flags(vtkflags);
1443 const int iproc = dealii::Utilities::MPI::this_mpi_process(
mpi_communicator);
1444 std::string filename =
"Mesh-" + dealii::Utilities::int_to_string(dim, 1) +
"D_GridP"+dealii::Utilities::int_to_string(
max_degree, 2)+
"-";
1445 filename += dealii::Utilities::int_to_string(cycle, 4) +
"." + dealii::Utilities::int_to_string(iproc, 4);
1447 std::ofstream output(filename);
1448 data_out.write_vtu(output);
1450 std::vector<std::string> filenames;
1451 for (
unsigned int iproc = 0; iproc < dealii::Utilities::MPI::n_mpi_processes(
mpi_communicator); ++iproc) {
1452 std::string fn =
"Mesh-" + dealii::Utilities::int_to_string(dim, 1) +
"D_GridP"+dealii::Utilities::int_to_string(
max_degree, 2)+
"-";
1453 fn += dealii::Utilities::int_to_string(cycle, 4) +
"." + dealii::Utilities::int_to_string(iproc, 4);
1455 filenames.push_back(fn);
1457 std::ofstream master_output(master_fn);
1458 data_out.write_pvtu_record(master_output, filenames);
1465 const dealii::DataPostprocessorInputs::Vector<dim> &inputs,
1466 std::vector<dealii::Vector<double>> &computed_quantities)
const 1468 const unsigned int n_solution_points = inputs.solution_values.size();
1469 Assert (computed_quantities.size() == n_solution_points, dealii::ExcInternalError());
1470 Assert (inputs.solution_values[0].size() == dim, dealii::ExcInternalError());
1471 std::vector<std::string> names = get_names ();
1472 for (
unsigned int q=0; q<n_solution_points; ++q) {
1473 computed_quantities[q].grow_or_shrink(names.size());
1475 for (
unsigned int q=0; q<n_solution_points; ++q) {
1478 const std::vector<dealii::Tensor<1,dim> > &duh = inputs.solution_gradients[q];
1483 unsigned int current_data_index = 0;
1485 dealii::Tensor<2,dim,double> jacobian;
1486 for (
unsigned int a=0;a<dim;++a) {
1487 for (
int d=0;d<dim;++d) {
1488 jacobian[a][d] = duh[a][d];
1489 std::cout << jacobian[a][d] <<
" ";
1492 computed_quantities[q](current_data_index++) =
determinant(jacobian);
1493 std::cout <<
"Jac: " << computed_quantities[q](current_data_index) << std::endl;
1495 if (computed_quantities[q].size() != current_data_index) {
1496 std::cout <<
" Did not assign a value to all the data. Missing " << computed_quantities[q].size() - current_data_index <<
" variables." 1497 <<
" If you added a new output variable, make sure the names and DataComponentInterpretation match the above. " 1508 namespace DCI = dealii::DataComponentInterpretation;
1509 std::vector<DCI::DataComponentInterpretation> interpretation;
1510 interpretation.push_back (DCI::component_is_scalar);
1512 std::vector<std::string> names = get_names();
1513 if (names.size() != interpretation.size()) {
1514 std::cout <<
"Number of DataComponentInterpretation is not the same as number of names for output file" << std::endl;
1516 return interpretation;
1523 std::vector<std::string> names;
1524 names.push_back (
"JacobianDeterminant");
1532 return dealii::update_values | dealii::update_gradients;
void update_mapping_fe_field()
Update the MappingFEField.
VectorType initial_volume_nodes
Initial nodal coefficients of the high-order grid.
std::vector< dealii::types::global_dof_index > locally_relevant_surface_nodes_indices
List of surface node indices.
std::vector< real > locally_relevant_surface_nodes
List of surface nodes.
std::shared_ptr< dealii::MappingFEField< dim, dim, VectorType, DoFHandlerType > > mapping_fe_field
MappingFEField that will provide the polynomial-based grid.
real2 determinant(const std::array< dealii::Tensor< 1, dim, real2 >, dim > jacobian) const
Evaluate the determinant of a matrix given in the format of a std::array<dealii::Tensor<1,dim,real2>,dim>.
void test_jacobian()
Test metric Jacobian.
Sacado::Fad::DFad< double > FadType
Sacado AD type for first derivatives.
void evaluate_lagrange_to_bernstein_operator(const unsigned int order)
Evaluates the operator to obtain Bernstein coefficients from a set of Lagrange coefficients.
void execute_coarsening_and_refinement(const bool output_mesh=false)
Executes the solution transfer such that the curved refined grid is on top of the curved coarse grid...
std::vector< dealii::Point< dim > > initial_locally_relevant_surface_points
Initial locally relevant surface points.
void reinit()
Reinitialize high_order_grid after a change in triangulation.
dealii::IndexSet ghost_dofs_grid
Locally relevant ghost degrees of freedom for the grid.
void update_map_nodes_surf_to_vol()
Sets the initial_volume_nodes and initial_surface_nodes to the current volume_nodes and surface_nodes...
const bool renumber_dof_handler_Cuthill_Mckee
Flag to renumber dof_handler_grid with Cuthill Mckee.
SolutionTransfer solution_transfer
virtual dealii::UpdateFlags get_needed_update_flags() const override
Returns the update flags required to evaluate the output data.
MPI_Comm mpi_communicator
MPI communicator.
dealii::IndexSet ghost_surface_nodes_indexset
Files for the baseline physics.
void ensure_conforming_mesh()
Ensures that hanging nodes are updated for a conforming mesh.
VectorType initial_surface_nodes
Distributed ghosted vector of initial surface nodes.
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
HighOrderGrid(const unsigned int max_degree, const std::shared_ptr< MeshType > triangulation_input, const bool check_valid_metric_Jacobian_input=true, const bool renumber_dof_handler_Cuthill_Mckee_input=true, const bool output_high_order_grid=true)
Principal constructor that will call delegated constructor.
void get_projected_position_vector(const DoFHandlerType &dh, VectorType &vector, const dealii::ComponentMask &mask)
VectorType transform_surface_nodes(std::function< dealii::Point< dim >(dealii::Point< dim >)> transformation) const
dealii::TrilinosWrappers::SparseMatrix map_nodes_surf_to_vol
virtual std::vector< dealii::DataComponentInterpretation::DataComponentInterpretation > get_data_component_interpretation() const override
Returns the DCI associated with the output data.
bool check_valid_cell(const typename DoFHandlerType::cell_iterator &cell) const
Evaluate exact Jacobian determinant polynomial and uses Bernstein polynomials to determine positivity...
const std::shared_ptr< MeshType > triangulation
Mesh.
std::vector< real > all_surface_nodes
List of all surface nodes.
const bool check_valid_metric_Jacobian
Flag to check validity of Jacobian.
VectorType old_volume_nodes
Used for the SolutionTransfer when performing grid adaptation.
void output_results_vtk(const unsigned int cycle) const
Output mesh with metric informations.
dealii::FullMatrix< double > lagrange_to_bernstein_operator
Used to transform coefficients from a Lagrange basis to a Bernstein basis.
virtual void evaluate_vector_field(const dealii::DataPostprocessorInputs::Vector< dim > &inputs, std::vector< dealii::Vector< double >> &computed_quantities) const override
Evaluates the values of interest to output.
std::vector< dealii::types::global_dof_index > locally_owned_surface_nodes_indices
List of surface node indices.
std::map< dealii::types::global_dof_index, std::pair< unsigned int, unsigned int > > global_index_to_point_and_axis
void initialize_with_triangulation_manifold(const bool output_mesh=true)
Sets the volume_nodes to the interpolated position of the Manifold associated to the triangulation...
std::vector< dealii::types::global_dof_index > all_surface_indices
dealii::LinearAlgebra::distributed::Vector< int > surface_to_volume_indices
dealii::IndexSet locally_relevant_dofs_grid
Union of locally owned degrees of freedom and relevant ghost degrees of freedom for the grid...
void get_position_vector(const DoFHandlerType &dh, VectorType &vector, const dealii::ComponentMask &mask)
A stripped down copy of dealii::VectorTools::get_position_vector()
const unsigned int max_degree
Maximum degree of the geometry polynomial representing the grid.
void update_surface_nodes()
Update list of surface nodes (all_locally_relevant_surface_nodes).
real2 evaluate_jacobian_at_point(const std::vector< real2 > &dofs, const dealii::FESystem< dim > &fe, const dealii::Point< dim > &point) const
Evaluates Jacobian given some DoF, associated FE, and some point.
std::vector< real > evaluate_jacobian_at_points(const VectorType &solution, const typename DoFHandlerType::cell_iterator &cell, const std::vector< dealii::Point< dim >> &points) const
Evaluates Jacobian of a cell given some points using a global solution vector.
static unsigned int nth_refinement
Used to name the various files outputted.
int n_mpi
Number of MPI processes.
void refine_global()
Globally refines the high-order mesh.
std::vector< unsigned int > n_locally_owned_surface_nodes_per_mpi
void allocate()
Needed to allocate the correct number of volume_nodes when initializing and after the mesh is refined...
void reset_initial_nodes()
Sets the initial_volume_nodes and initial_surface_nodes to the current volume_nodes and surface_nodes...
std::vector< dealii::Point< dim > > locally_relevant_surface_points
Locally relevant surface points.
void update_surface_indices()
Update list of surface indices (locally_relevant_surface_nodes_indices and locally_relevant_surface_n...
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.
bool fix_invalid_cell(const typename DoFHandlerType::cell_iterator &cell)
Evaluate exact Jacobian determinant polynomial and uses Bernstein polynomials to determine positivity...
std::vector< dealii::types::global_dof_index > locally_relevant_surface_nodes_boundary_id
List of surface node boundary IDs, corresponding to locally_relevant_surface_nodes_indices.
dealii::DoFHandler< dim > dof_handler_grid
Degrees of freedom handler for the high-order grid.
std::vector< real > locally_owned_surface_nodes
List of surface nodes.
virtual std::vector< std::string > get_names() const override
Returns the names associated with the output data.
dealii::IndexSet locally_owned_dofs_grid
Locally own degrees of freedom for the 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
dealii::IndexSet locally_owned_surface_nodes_indexset
void prepare_for_coarsening_and_refinement()
Prepares the solution transfer such that the curved refined grid is on top of the curved coarse grid...
const dealii::FESystem< dim > fe_system
Using system of polynomials to represent the x, y, and z directions.