[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
high_order_grid.cpp
1 #include <type_traits>
2 
3 #include <deal.II/base/exceptions.h>
4 
5 // For metric Jacobian testing
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>
11 // *****************
12 
13 #include <deal.II/fe/fe_q.h>
14 #include <deal.II/fe/fe_bernstein.h>
15 
16 #include <deal.II/grid/tria.h>
17 #include <deal.II/distributed/shared_tria.h>
18 #include <deal.II/distributed/tria.h>
19 
20 #include <deal.II/dofs/dof_tools.h>
21 
22 #include <deal.II/fe/fe_bernstein.h>
23 
24 #include <deal.II/numerics/vector_tools.h>
25 
26 #include <Sacado.hpp>
27 #include <deal.II/differentiation/ad/sacado_product_types.h>
28 
29 #include <deal.II/optimization/solver_bfgs.h>
30 
31 #include <deal.II/grid/grid_tools.h>
32 
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>
38 
39 #include <deal.II/dofs/dof_renumbering.h>
40 
41 #include <deal.II/meshworker/local_integrator.h>
42 #include <deal.II/integrators/l2.h>
43 
44 #include "high_order_grid.h"
45 
46 
47 namespace PHiLiP {
48 
49 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
51 
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)
64  , fe_q(max_degree) // The grid must be at least p1. A p0 solution required a p1 grid.
65  , fe_system(dealii::FESystem<dim>(fe_q,dim)) // The grid must be at least p1. A p0 solution required a p1 grid.
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)
73 {
74  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
75  MPI_Comm_size(MPI_COMM_WORLD, &n_mpi);
76 
77  Assert(max_degree > 0, dealii::ExcMessage("Grid must be at least order 1."));
78 
79  if (triangulation->n_levels() == 0) {
80  // Do nothing
81  // Assume stuff will be read later on.
82  } else {
83  initialize_with_triangulation_manifold(output_high_order_grid);
84  }
85 }
86 
87 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
89 {
90  allocate();
91  const dealii::ComponentMask mask(dim, true);
93  //get_projected_position_vector(dof_handler_grid, volume_nodes, mask);
94 
95  volume_nodes.update_ghost_values();
96 
98 
99  volume_nodes.update_ghost_values();
103  if (output_mesh) output_results_vtk(nth_refinement++);
104 
106  // Used to check Jacobian validity
107  //For future note: the 3D order of the Jacobian in each direction should be
108  // (max_degree-1) * max_degree * max_degree. Then exact_jacobian_order below
109  //is getting passed as a 1D order then a 3D finite element is created based off
110  // exact_jac_order*exact_jac_order*exact_jac_order which does not equal the above.
111  //Also, when the metric terms are built from operators: metric_operators
112  //it check the validity of the metric Jacobian on-the-fly.
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);
116  evaluate_lagrange_to_bernstein_operator(used_jacobian_order);
117 
118  auto cell = dof_handler_grid.begin_active();
119  auto endcell = dof_handler_grid.end();
120  // pcout << "Disabled check_valid_cells. Took too much time due to shape_grad()." << std::endl;
121  for (; cell!=endcell; ++cell) {
122  if (!cell->is_locally_owned()) continue;
123  const bool is_invalid_cell = check_valid_cell(cell);
124 
125  if ( !is_invalid_cell ) {
126  std::cout << " Poly: " << max_degree
127  << " Grid: " << nth_refinement
128  << " Cell: " << cell->active_cell_index() << " has an invalid Jacobian." << std::endl;
129  // bool fixed_invalid_cell = fix_invalid_cell(cell);
130  // if (fixed_invalid_cell) std::cout << "Fixed it." << std::endl;
131  }
132  }
133  }
134 }
135 
136 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
138  allocate();
139  const dealii::ComponentMask mask(dim, true);
141  volume_nodes.update_ghost_values();
145 
146  // Used to check Jacobian validity
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);
150  evaluate_lagrange_to_bernstein_operator(used_jacobian_order);
151 
152  auto cell = dof_handler_grid.begin_active();
153  auto endcell = dof_handler_grid.end();
154  // pcout << "Disabled check_valid_cells. Took too much time due to shape_grad()." << std::endl;
155  for (; cell!=endcell; ++cell) {
156  if (!cell->is_locally_owned()) continue;
157  const bool is_invalid_cell = check_valid_cell(cell);
158 
159  if ( !is_invalid_cell ) {
160  std::cout << " Poly: " << max_degree
161  << " Grid: " << nth_refinement
162  << " Cell: " << cell->active_cell_index() << " has an invalid Jacobian." << std::endl;
163  // bool fixed_invalid_cell = fix_invalid_cell(cell);
164  // if (fixed_invalid_cell) std::cout << "Fixed it." << std::endl;
165  }
166  }
167 }
168 
169 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
171 
172  volume_nodes.update_ghost_values();
173 
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();
178  hanging_node_constraints.distribute(volume_nodes);
179 
180  volume_nodes.update_ghost_values();
181 
183 }
184 
185 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
187  const dealii::ComponentMask mask(dim, true);
188  mapping_fe_field = std::make_shared< dealii::MappingFEField<dim,dim,VectorType,DoFHandlerType> > (dof_handler_grid,volume_nodes,mask);
189  initial_mapping_fe_field = std::make_shared< dealii::MappingFEField<dim,dim,VectorType,DoFHandlerType> > (dof_handler_grid,initial_volume_nodes,mask);
190 }
191 
192 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
193 void
195 {
197  dof_handler_grid.distribute_dofs(fe_system);
198  //if cuthill mckee renumbering
200  dealii::DoFRenumbering::Cuthill_McKee(dof_handler_grid);
201  }
202 
203 
204  locally_owned_dofs_grid = dof_handler_grid.locally_owned_dofs();
205  dealii::DoFTools::extract_locally_relevant_dofs(dof_handler_grid, locally_relevant_dofs_grid);
208 
209  // reinit nodes depending on the MeshType::VectorType
211  volume_nodes,
216 }
217 
218 //template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
219 //dealii::MappingFEField<dim,dim,VectorType,DoFHandlerType>
220 //HighOrderGrid<dim,real,MeshType,VectorType,DoFHandlerType>::get_MappingFEField() {
221 // const dealii::ComponentMask mask(dim, true);
222 // dealii::VectorTools::get_position_vector(dof_handler_grid, volume_nodes, mask);
223 //
224 // dealii::MappingFEField<dim,dim,VectorType,DoFHandlerType> mapping(dof_handler_grid,volume_nodes,mask);
225 //
226 // return mapping;
227 //}
228 //
229 
230 
231 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
233 ::get_position_vector(const DoFHandlerType &dh, VectorType &position_vector, const dealii::ComponentMask &mask)
234 {
235  AssertDimension(position_vector.size(), dh.n_dofs());
236  const dealii::FESystem<dim, dim> &fe = dh.get_fe();
237 
238  // Construct default fe_mask;
239  const dealii::ComponentMask fe_mask(mask.size() ? mask : dealii::ComponentMask(fe.get_nonzero_components(0).size(), true));
240 
241  AssertDimension(fe_mask.size(), fe.get_nonzero_components(0).size());
242 
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++;
247  }
248  Assert(size == dim, dealii::ExcMessage("The Component Mask you provided is invalid. It has to select exactly dim entries."));
249 
250  const dealii::Quadrature<dim> quad(fe.get_unit_support_points());
251 
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);
255 
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."));
258 
259  for (const auto &cell : dh.active_cell_iterators()) {
260  if (cell->is_locally_owned()) {
261  fe_v.reinit(cell);
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);
267  }
268  }
269  }
270 }
271 
272 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
274 ::get_projected_position_vector(const DoFHandlerType &dh, VectorType &position_vector, const dealii::ComponentMask &mask)
275 {
276  AssertDimension(position_vector.size(), dh.n_dofs());
277  const dealii::FESystem<dim, dim> &fe = dh.get_fe();
278 
279  // Construct default fe_mask;
280  const dealii::ComponentMask fe_mask(mask.size() ? mask : dealii::ComponentMask(fe.get_nonzero_components(0).size(), true));
281 
282  AssertDimension(fe_mask.size(), fe.get_nonzero_components(0).size());
283 
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++;
288  }
289  Assert(size == dim, dealii::ExcMessage("The Component Mask you provided is invalid. It has to select exactly dim entries."));
290 
291  const dealii::QGauss<dim> quad((fe.degree+1) * 2);
292 
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);
295 
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);
298 
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);
302 
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);
306 
307  std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_cell);
308 
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."));
311 
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);
316  //dealii::LocalIntegrators::L2::mass_matrix(mass_matrix, fe_values_straight);
317  //mass_matrix.print(std::cout);
318  //inv_mass_matrix.invert(mass_matrix);
319 
320  cell->get_dof_indices(dof_indices);
321  const std::vector<dealii::Point<dim>> &quadrature_points_values = fe_values_curved.get_quadrature_points();
322 
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;
326  rhs[idof] = 0.0;
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);
329  }
330  }
331  dealii::Vector<double> new_dof_values(n_dofs);
332  inv_mass_matrix.vmult(new_dof_values, rhs);
333 
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);
337  }
338  }
339  }
340 }
341 //template <int dim, typename real>
342 //void HighOrderGrid<dim,real>
343 //::get_surface_projected_position_vector(const DoFHandlerType &dh, VectorType &position_vector, const dealii::ComponentMask &mask)
344 //{
345 // AssertDimension(position_vector.size(), dh.n_dofs());
346 // const dealii::FESystem<dim, dim> &fe = dh.get_fe();
347 //
348 // // Construct default fe_mask;
349 // const dealii::ComponentMask fe_mask(mask.size() ? mask : dealii::ComponentMask(fe.get_nonzero_components(0).size(), true));
350 //
351 // AssertDimension(fe_mask.size(), fe.get_nonzero_components(0).size());
352 //
353 // std::vector<unsigned int> fe_to_real(fe_mask.size(), dealii::numbers::invalid_unsigned_int);
354 // unsigned int size = 0;
355 // for (unsigned int i = 0; i < fe_mask.size(); ++i) {
356 // if (fe_mask[i]) fe_to_real[i] = size++;
357 // }
358 // Assert(size == dim, dealii::ExcMessage("The Component Mask you provided is invalid. It has to select exactly dim entries."));
359 //
360 // const dealii::QGauss<dim> quad((fe.degree+1) * 2);
361 //
362 // dealii::MappingQGeneric<dim, dim> map_q(fe.degree);
363 // dealii::FEValues<dim, dim> fe_values_curved(map_q, fe, quad, dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values);
364 //
365 // dealii::MappingQ1<dim, dim> map_q1;
366 // 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);
367 //
368 // const unsigned int n_dofs = fe.dofs_per_cell;
369 // dealii::FullMatrix<double> mass_matrix(n_dofs, n_dofs);
370 // dealii::FullMatrix<double> inv_mass_matrix(n_dofs, n_dofs);
371 //
372 // std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_face);
373 //
374 // AssertDimension(fe.dofs_per_cell, fe.get_unit_support_points().size());
375 // Assert(fe.is_primitive(), dealii::ExcMessage("FE is not Primitive! This won't work."));
376 //
377 // dealii::TrilinosWrappers::SparseMatrix surface_mass_matrix;
378 //
379 // dealii::FEFaceValues<dim,dim> fe_face_values_curved(map_q, fe, quad, dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_jacobians);
380 // dealii::FEFaceValues<dim,dim> fe_face_values_straight(map_q1, fe, quad, dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_jacobians);
381 // for (const auto &cell : dh.active_cell_iterators()) {
382 //
383 // if (!(cell->is_locally_owned())) continue;
384 //
385 // for (unsigned int iface=0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface) {
386 // auto face = cell->face(iface);
387 // if (!face->at_boundary()) continue;
388 // const unsigned int boundary_id = face->boundary_id();
389 // if (!(boundary_id == 1001)) continue;
390 //
391 // face->get_dof_indices(dof_indices);
392 //
393 // fe_face_values_curved.reinit(current_cell, iface);
394 // fe_face_values_straight.reinit(current_cell, iface);
395 //
396 //
397 //
398 // for (unsigned int itest=0; itest<dof_indices.size(); ++itest) {
399 // const unsigned int itest_axis = fe.system_to_component_index(itest).first;
400 // rhs[itest] = 0.0;
401 // for (unsigned int q=0; q<quadrature_points_values.size(); ++q) {
402 // rhs[itest] += fe_values_curved.shape_value_component(itest, q, itest_axis) * quadrature_points_values[q][itest_axis] * quad.weight(q);
403 // }
404 // }
405 //
406 // }
407 //
408 // fe_values_curved.reinit(cell);
409 // fe_values_straight.reinit(cell);
410 // //dealii::LocalIntegrators::L2::mass_matrix(mass_matrix, fe_values_straight);
411 // //mass_matrix.print(std::cout);
412 // //inv_mass_matrix.invert(mass_matrix);
413 //
414 // cell->get_dof_indices(dof_indices);
415 // const std::vector<dealii::Point<dim>> &quadrature_points_values = fe_values_curved.get_quadrature_points();
416 //
417 // dealii::Vector<double> rhs(n_dofs);
418 // for (unsigned int idof=0; idof<n_dofs; ++idof) {
419 // const unsigned int axis = fe.system_to_component_index(idof).first;
420 // rhs[idof] = 0.0;
421 // for (unsigned int q=0; q<quadrature_points_values.size(); ++q) {
422 // rhs[idof] += fe_values_curved.shape_value_component(idof, q, axis) * quadrature_points_values[q][axis] * quad.weight(q);
423 // }
424 // }
425 // dealii::Vector<double> new_dof_values(n_dofs);
426 // inv_mass_matrix.vmult(new_dof_values, rhs);
427 //
428 // for (unsigned int idof = 0; idof < new_dof_values.size(); ++idof) {
429 // const unsigned int comp = fe.system_to_component_index(idof).first;
430 // if (fe_mask[comp]) ::dealii::internal::ElementAccess<VectorType>::set(new_dof_values[idof], dof_indices[idof], position_vector);
431 // }
432 // }
433 //}
434 
435 
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
440 {
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]));
448 }
449 
450 
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
456 {
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;
461 
462  std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_cell);
463  cell->get_dof_indices (dofs_indices);
464 
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);
468 
469  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
470 
471  for (unsigned int iaxis=0; iaxis<n_axis; ++iaxis) {
472  coords[iaxis] = 0;
473  coords_grad[iaxis] = 0;
474  }
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);
479  }
480  jac_det[iquad] = determinant(coords_grad);
481 
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];
486  }
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] << " ";
494  }
495  std::cout << std::endl;
496  }
497  }
498  }
499  return jac_det;
500 }
501 
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
508 {
509  AssertDimension(dim, fe.n_components());
510 
511  const unsigned int n_dofs_coords = fe.n_dofs_per_cell();
512  const unsigned int n_axis = dim;
513 
514  std::array< dealii::Tensor<1,dim,real2>, n_axis > coords_grad; // Tensor initialize with zeros
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);
518  }
519  return determinant(coords_grad);
520 }
521 
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
529 {
530  AssertDimension(dim, fe.n_components());
531  AssertDimension(jacobian_determinants.size(), points.size());
532 
533  const unsigned int n_points = points.size();
534 
535  for (unsigned int i=0; i<n_points; ++i) {
536  jacobian_determinants[i] = evaluate_jacobian_at_point(dofs, fe, points[i]);
537  }
538 }
539 
540 template<typename real>
541 std::vector<real> matrix_stdvector_mult(const dealii::FullMatrix<double> &matrix, const std::vector<real> &vector_in)
542 {
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];
549  }
550  }
551  return vector_out;
552 }
553 
554 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
556 {
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();
560 
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);
564  // Evaluate Vandermonde matrix such that V u_bernstein = u_lagrange
565  // where the matrix's rows correspond to the different Bernstein polynomials
566  // and the matrix's column correspond to the unit support points of the Lagrage polynomials
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);
572  }
573  }
574  lagrange_to_bernstein_operator.reinit(n_lagrange_pts, n_bernstein);
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;
576  lagrange_to_bernstein_operator.invert(bernstein_to_lagrange);
577  if (n_lagrange_pts > 1000) pcout << "Done inverting a " << n_lagrange_pts << " x " << n_lagrange_pts << " dense matrix..." << std::endl;
578 }
579 
580 
581 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
582 bool HighOrderGrid<dim,real,MeshType,VectorType,DoFHandlerType>::check_valid_cell(const typename DoFHandlerType::cell_iterator &cell) const
583 {
584  return true;
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);
587 
588  // Evaluate Jacobian at Lagrange interpolation points
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);
593 
594  std::vector< real > cell_nodes(n_dofs_coords);
595  for (unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
596  cell_nodes[idof] = volume_nodes(dofs_indices[idof]);
597  }
598 
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);
604  evaluate_jacobian_at_points(cell_nodes, fe_coords, lagrange_pts, lagrange_coeff);
605  std::vector<real> bernstein_coeff = matrix_stdvector_mult(lagrange_to_bernstein_operator, lagrange_coeff);
606 
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;
611  // std::cout << "Bernstein vector: " ;
612  // for (unsigned int j=0; j<n_bernstein;++j) {
613  // std::cout << bernstein_coeff[j] << " ";
614  // }
615  //std::cout << std::endl;
616  return false;
617  }
618  }
619  return true;
620 }
621 
622 // dealii::FullMatrix<double> lagrange_to_bernstein_operator(
623 // const dealii::FE_Q<dim> &lagrange_basis,
624 // const dealii::FE_Bernstein<dim> &bernstein_basis,
625 // const typename DoFHandlerType::cell_iterator &cell)
626 // {
627 // const dealii::FE_Bernstein<dim> bernstein_basis(jacobian_order);
628 // const unsigned int n_bernstein = bernstein_basis.n_dofs_per_cell();
629 // const unsigned int n_lagrange_pts = lagrange_pts.size();
630 // AssertDimension(n_bernstein, n_lagrange_pts);
631 // // Evaluate Vandermonde matrix such that V u_bernstein = u_lagrange
632 // // where the matrix's rows correspond to the different Bernstein polynomials
633 // // and the matrix's column correspond to the unit support points of the Lagrage polynomials
634 // dealii::FullMatrix<double> bernstein_to_lagrange(n_bernstein, n_lagrange_pts);
635 // for (unsigned int ibernstein=0; ibernstein<n_bernstein; ++ibernstein) {
636 // for (unsigned int ijacpts=0; ijacpts<n_bernstein; ++ijacpts) {
637 // const dealii::Point<dim> &point = lagrange_pts[ijacpts];
638 // bernstein_to_lagrange[ibernstein][ijacpts] = bernstein_basis.shape_value(ibernstein, point);
639 // }
640 // }
641 // }
642 
643 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
644 bool HighOrderGrid<dim,real,MeshType,VectorType,DoFHandlerType>::fix_invalid_cell(const typename DoFHandlerType::cell_iterator &cell)
645 {
646  // This will be the target ratio between the current minimum (estimated) cell Jacobian
647  // and the value of the straight-sided Jacobian. This estimates depends on the Bernstein
648  // coefficients that serve as a convex hull
649  const double target_ratio = 0.1;
650 
651  // Maximum number of times we will move the barrier
652  const int max_barrier_iterations = 100;
653 
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;
659 
660  const dealii::FESystem<dim> &fe_coords = cell->get_fe();
661  const unsigned int n_dofs_coords = fe_coords.n_dofs_per_cell();
662  // Evaluate Jacobian at Lagrange interpolation points
663  std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_coords);
664  cell->get_dof_indices (dofs_indices);
665 
666  // Use reverse mode for more efficiency
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);
671 
672  // Count and tag movable volume_nodes
673  std::vector< bool > movable(n_dofs_coords);
674  unsigned int n_movable_nodes = 0;
675  // for (unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
676  // bool is_interior_node = true;
677  // for (unsigned int iface = 0; iface<dealii::GeometryInfo<dim>::faces_per_cell; ++iface) {
678  // is_interior_node = is_interior_node && !(fe_coords.has_support_on_face(idof, iface));
679  // }
680  // movable[idof] = is_interior_node;
681  // if (is_interior_node) n_movable_nodes++;
682  // }
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++;
687  }
688 
689  // Evaluate straight sided cell Jacobian.
690  // Note that we can't simply use the Triangulation's cell's vertices since
691  // MappingFEField does not preserves_vertex_locations()
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];
701  }
702  }
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;
707 
708  //const double straight_sided_jacobian = cell->measure();
709  const double straight_sided_jacobian = evaluate_jacobian_at_point(straight_sided_dofs, straight_sided_elem_fesystem, unit_cell_center);
710 
711 
712  // Initialize movable volume_nodes, which are our design variables
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) {
716  cell_nodes[idof] = volume_nodes(dofs_indices[idof]);
717  if (movable[idof]) movable_nodes[idesign++] = cell_nodes[idof].val();
718  }
719  evaluate_jacobian_at_points(cell_nodes, fe_coords, lagrange_pts, lagrange_coeff);
720  bernstein_coeff = matrix_stdvector_mult(lagrange_to_bernstein_operator, lagrange_coeff);
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);
726  }
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;
730 
731  const double barrier = min_ratio - 0.10*std::abs(min_ratio);
732  const double barrierJac = barrier*straight_sided_jacobian;
733 
734  std::function<real (const dealii::Vector<real> &, dealii::Vector<real> &)> func =
735  [&](const dealii::Vector<real> &movable_nodes, dealii::Vector<real> &gradient) {
736 
737  unsigned int idesign = 0;
738  for (unsigned int idof = 0; idof < n_dofs_coords; ++idof) {
739  if (movable[idof]) {
740  cell_nodes[idof] = movable_nodes[idesign];
741  cell_nodes[idof].diff(idesign, n_movable_nodes);
742  idesign++;
743  }
744  }
745  evaluate_jacobian_at_points(cell_nodes, fe_coords, lagrange_pts, lagrange_coeff);
746  bernstein_coeff = matrix_stdvector_mult(lagrange_to_bernstein_operator, lagrange_coeff);
747 
748  FadType functional = 0.0;
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);
755  }
756  min_ratio /= straight_sided_jacobian;
757  //FadType functional = bernstein_coeff[0];
758  //for (unsigned int i=0; i<n_bernstein;++i) {
759  // functional = std::min(functional, bernstein_coeff[i]);
760  //}
761  //functional *= -1.0;
762 
763  for (unsigned int i = 0; i < movable_nodes.size(); ++i) {
764  //gradient[i] = functional.fastAccessDx(i);
765  gradient[i] = functional.dx(i);
766  }
767  return functional.val();
768  };
769 
770  // const unsigned int bfgs_max_it = 150;
771  // const double gradient_tolerance = 1e-5;
772  // const unsigned int max_history = bfgs_max_it;
773 
774  // dealii::SolverControl solver_control(bfgs_max_it, gradient_tolerance, false);
775  // typename dealii::SolverBFGS<dealii::Vector<real>>::AdditionalData data(max_history, false);
776  // dealii::SolverBFGS<dealii::Vector<real>> solver(solver_control, data);
777  // solver.connect_preconditioner_slot(preconditioner);
778  // solver.solve(func, movable_nodes);
779  const unsigned int max_opt_iterations = 1000;
780  const unsigned int n_line_search = 40;
781  const double initial_step_length = 1.0;//1e-3 * cell->minimum_vertex_distance();
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);
794  hessian_inverse = 0;
795  for (unsigned int inode=0; inode<n_movable_nodes; ++inode) {
796  hessian_inverse[inode][inode] = 1.0e-8;
797  }
798 
799 
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) {
802 
803  old_movable_nodes = movable_nodes;
804  old_grad = grad;
805 
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);
814  try {
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; // Armijo condition satisfied.
818  } catch (...)
819  {}
820  step_length *= 0.5;
821  }
822  //if (i_line_search == n_line_search) {
823  // hessian_inverse = 0;
824  // for (unsigned int inode=0; inode<n_movable_nodes; ++inode) {
825  // hessian_inverse[inode][inode] = 1.0e-8;
826  // }
827  // hessian_inverse.vmult(search_direction, grad);
828  // search_direction *= -1.0;
829  // double step_length = initial_step_length;
830  // real old_functional = functional;
831  // unsigned int i_line_search;
832  // for (i_line_search = 0; i_line_search<n_line_search; ++i_line_search) {
833  // movable_nodes = old_movable_nodes;
834  // movable_nodes.add(step_length, search_direction);
835  // try {
836  // functional = func(movable_nodes, grad);
837  // if (std::isnan(functional)) throw -1;
838  // if (functional-old_functional < 1e-4 * step_length * (grad*search_direction)) break; // Armijo condition satisfied.
839  // } catch (...)
840  // {}
841  // step_length *= 0.5;
842  // }
843  //}
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
851  << std::endl;
852  // BFGS inverse Hessian update
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; // skip bfgs update if negative curvature
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);
866  }
867  }
868 
869 
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] << " ";
878  }
879  std::cout << std::endl;
880  return false;
881  }
882  }
883  return true;
884 }
885 
886 
887 
888 // template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
889 // bool HighOrderGrid<dim,real,MeshType,VectorType,DoFHandlerType>::make_valid_cell(
890 // const typename DoFHandlerType::cell_iterator &cell);
891 // {
892 // const dealii::FESystem<dim> &fe_coords = cell->get_fe();
893 // const order = fe_coords.tensor_degree();
894 // const jacobian_order = std::pow(fe_coords.tensor_degree()-1, dim);
895 // const dealii::FE_Q<dim> lagrange_basis(jacobian_order);
896 // const std::vector< dealii::Point<dim> > &jacobian_points = lagrange_basis.get_unit_support_points();
897 //
898 // const dealii::FE_Bernstein<dim> bernstein_basis(jacobian_order);
899 //
900 // const unsigned int n_lagrange_pts = jacobian_points.size();
901 // const unsigned int n_dofs_coords = fe_coords.n_dofs_per_cell();
902 // const unsigned int n_axis = dim;
903 //
904 // // Evaluate Jacobian at Lagrange interpolation points
905 // std::vector<dealii::types::global_dof_index> dofs_indices(n_dofs_cell);
906 // cell->get_dof_indices (dofs_indices);
907 //
908 // dealii::Vector<double> lagrange_coeff(n_lagrange_pts);
909 //
910 // for (unsigned int i_lagrange=0; i_lagrange<n_lagrange_pts; ++i_lagrange) {
911 //
912 // const dealii::Point<dim> &point = jacobian_points[i_lagrange];
913 //
914 // std::array< dealii::Tensor<1,dim,real>, n_axis > > coords_grad; // Tensor initialize with zeros
915 // for (unsigned int idof=0; idof<n_dofs_cell; ++idof) {
916 // const unsigned int axis = fe.system_to_component_index(idof).first;
917 // coords_grad[axis] += coords[dofs_indices[idof]] * fe.shape_grad (idof, point);
918 // }
919 // dealii::Tensor<2,dim,real> jacobian;
920 // for (unsigned int a=0;a<n_axis;++a) {
921 // for (int d=0;d<dim;++d) {
922 // jacobian[a][d] = coords_grad[iquad][a][d];
923 // }
924 // }
925 // dealii::Vector<double> lagrange_coeff(i_lagrange);
926 // }
927 //
928 // const unsigned int n_bernstein = bernstein_basis.n_dofs_per_cell();
929 // AssertDimension(n_bernstein == n_lagrange_pts);
930 // // Evaluate Vandermonde matrix such that V u_bernstein = u_lagrange
931 // // where the matrix's rows correspond to the different Bernstein polynomials
932 // // and the matrix's column correspond to the unit support points of the Lagrage polynomials
933 // dealii::FullMatrix<double> bernstein_to_lagrange(n_bernstein, n_lagrange_pts);
934 // for (unsigned int ibernstein=0; ibernstein<n_bernstein; ++ibernstein) {
935 // for (unsigned int ijacpts=0; ijacpts<n_bernstein; ++ijacpts) {
936 // const dealii::Point<dim> &point = jacobian_points[ijacpts];
937 // bernstein_to_lagrange[ibernstein][ijacpts] = bernstein_basis.shape_value(ibernstein, point);
938 // }
939 // }
940 // dealii::FullMatrix<double> lagrange_to_bernstein;
941 // lagrange_to_bernstein.invert(bernstein_to_lagrange);
942 //
943 // dealii::Vector<double> bernstein_coeff(n_bernstein);
944 // lagrange_to_bernstein.vmult(bernstein_coeff, lagrange_coeff);
945 //
946 // return false;
947 // }
948 
949 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
951 {
952  // // Setup a dummy system
953  // const unsigned int solution_degree = max_degree-1;
954  // const unsigned int dummy_n_state = 5;
955  // const dealii::FE_DGQ<dim> fe_dgq(solution_degree);
956  // const dealii::FESystem<dim> fe_system_dgq(fe_dgq, dummy_n_state);
957  // const dealii::QGauss<dim> qgauss(solution_degree+1);
958  // const dealii::QGaussLobatto<dim> qgauss_lobatto(solution_degree+20);
959 
960  // dealii::DoFHandler<dim> dof_handler;
961  // dof_handler.initialize(*triangulation, fe_system_dgq);
962 
963  // const dealii::Mapping<dim> &mapping = (*(mapping_fe_field));
964  // const dealii::FESystem<dim> &fe = fe_system_dgq;
965  // const dealii::Quadrature<dim> &quadrature = qgauss;
966  // const dealii::UpdateFlags volume_update_flags =
967  // dealii::update_values
968  // | dealii::update_gradients
969  // | dealii::update_quadrature_points
970  // | dealii::update_JxW_values
971  // | dealii::update_jacobians
972  // ;
973 
974  // {
975  // const dealii::Quadrature<dim> &overquadrature = qgauss_lobatto;
976  // const std::vector< dealii::Point< dim > > points = overquadrature.get_points();
977  // std::vector<real> jac_det;
978  // for (auto cell = dof_handler_grid.begin_active(); cell!=dof_handler_grid.end(); ++cell) {
979  // if (!cell->is_locally_owned()) continue;
980  // jac_det = evaluate_jacobian_at_points(volume_nodes, cell, points);
981  // }
982  // }
983 
984  // dealii::FEValues<dim,dim> fe_values(mapping, fe, quadrature, volume_update_flags);
985 
986  // for (auto cell = dof_handler.begin_active(); cell!=dof_handler.end(); ++cell) {
987 
988  // if (!cell->is_locally_owned()) continue;
989 
990  // // const unsigned int n_quad_pts = quadrature.size();
991 
992  // // std::cout << " Cell " << cell->active_cell_index();
993  // // fe_values.reinit(cell);
994  // // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
995  // // const std::vector<dealii::Point<dim>> &points = fe_values.get_quadrature_points();
996  // // std::cout << " Point: " << points[iquad]
997  // // << " JxW: " << fe_values.JxW(iquad)
998  // // << " J: " << (fe_values.jacobian(iquad)).determinant()
999  // // << std::endl;
1000  // // }
1001 
1002  // // for (unsigned int itrial=0; itrial<n_dofs_cell; ++itrial) {
1003  // // const unsigned int istate_trial = fe_values.get_fe().system_to_component_index(itrial).first;
1004  // // real value = 0.0;
1005  // // for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
1006  // // value += fe_values.shape_value_component(itrial,iquad,istate_trial) * fe_values.JxW(iquad);
1007  // // }
1008  // // }
1009 
1010  // //dofs_indices.resize(n_dofs_cell);
1011  // //cell->get_dof_indices (dofs_indices);
1012  // }
1013 }
1014 
1015 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1017 {
1019  triangulation->refine_global();
1021 }
1022 
1023 
1024 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1026 
1028  old_volume_nodes.update_ghost_values();
1029  if constexpr (PHILIP_DIM==1) solution_transfer.clear();
1030  solution_transfer.prepare_for_coarsening_and_refinement(old_volume_nodes);
1031 }
1032 
1033 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1035  allocate();
1036  if constexpr (std::is_same_v<typename dealii::SolutionTransfer<dim,VectorType,DoFHandlerType>,
1037  decltype(solution_transfer)>){
1039  } else {
1040  solution_transfer.interpolate(volume_nodes);
1041  }
1042  const bool use_manifold_for_refined_nodes = false;
1043  const dealii::ComponentMask mask(dim, true);
1044  if (use_manifold_for_refined_nodes) {
1046  }
1047 
1048  volume_nodes.update_ghost_values();
1049 
1051 
1054  if (output_mesh) output_results_vtk(nth_refinement++);
1055 
1056  //auto cell = dof_handler_grid.begin_active();
1057  //auto endcell = dof_handler_grid.end();
1059  //for (; cell!=endcell; ++cell) {
1060  // if (!cell->is_locally_owned()) continue;
1061  // const bool is_invalid_cell = check_valid_cell(cell);
1062 
1063  // if ( !is_invalid_cell ) {
1064  // std::cout << " Poly: " << max_degree
1065  // << " Grid: " << nth_refinement
1066  // << " Cell: " << cell->active_cell_index() << " has an invalid Jacobian." << std::endl;
1067  // //bool fixed_invalid_cell = fix_invalid_cell(cell);
1068  // //if (fixed_invalid_cell) std::cout << "Fixed it." << std::endl;
1069  // }
1070  //}
1071 }
1072 
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();
1078  }
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());
1083  }
1084  return result;
1085 }
1086 
1087 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1089 
1091 
1092  {
1093  const unsigned int n_locally_owned_surface_nodes = locally_owned_surface_nodes_indices.size();
1094  // Copy local surface node locations
1096  locally_owned_surface_nodes.resize(n_locally_owned_surface_nodes);
1097  unsigned int i = 0;
1098  for (auto index = locally_owned_surface_nodes_indices.begin(); index != locally_owned_surface_nodes_indices.end(); index++) {
1100  }
1101 
1104  MPI_Allgather(&n_locally_owned_surface_nodes, 1, MPI_UNSIGNED, &(n_locally_owned_surface_nodes_per_mpi[0]), 1, MPI_UNSIGNED, MPI_COMM_WORLD);
1105 
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) {
1110  vector_locally_owned_surface_nodes[i_mpi].resize(n_locally_owned_surface_nodes_per_mpi[i_mpi]);
1111  vector_locally_owned_surface_indices[i_mpi].resize(n_locally_owned_surface_nodes_per_mpi[i_mpi]);
1112  if (i_mpi == mpi_rank) {
1113  vector_locally_owned_surface_nodes[i_mpi] = locally_owned_surface_nodes;
1114  vector_locally_owned_surface_indices[i_mpi] = locally_owned_surface_nodes_indices;
1115  }
1116  }
1117 
1118  for (int i_mpi=0; i_mpi<n_mpi; ++i_mpi) {
1119  MPI_Bcast(&(vector_locally_owned_surface_nodes[i_mpi][0]), n_locally_owned_surface_nodes_per_mpi[i_mpi], MPI_DOUBLE, i_mpi, MPI_COMM_WORLD);
1120  MPI_Bcast(&(vector_locally_owned_surface_indices[i_mpi][0]), n_locally_owned_surface_nodes_per_mpi[i_mpi], MPI_UNSIGNED, i_mpi, MPI_COMM_WORLD);
1121  }
1122 
1123  all_surface_nodes = flatten(vector_locally_owned_surface_nodes);
1124  all_surface_indices = flatten(vector_locally_owned_surface_indices);
1125 
1126  unsigned int low_range = 0;
1127  for (int i_mpi=0; i_mpi<mpi_rank; ++i_mpi) {
1128  low_range += n_locally_owned_surface_nodes_per_mpi[i_mpi];
1129  }
1130  const unsigned int high_range = low_range + n_locally_owned_surface_nodes_per_mpi[mpi_rank];
1131 
1132  const unsigned int n_surface_nodes = all_surface_nodes.size();
1134  locally_owned_surface_nodes_indexset.set_size(n_surface_nodes);
1135  locally_owned_surface_nodes_indexset.add_range(low_range, high_range);
1136 
1137  }
1138 
1139  {
1140  const unsigned int n_locally_relevant_surface_nodes = locally_relevant_surface_nodes_indices.size();
1141  // Copy local surface node locations
1143  locally_relevant_surface_nodes.resize(n_locally_relevant_surface_nodes);
1144  unsigned int i = 0;
1145  for (auto index = locally_relevant_surface_nodes_indices.begin(); index != locally_relevant_surface_nodes_indices.end(); index++) {
1147  }
1148 
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);
1151 
1152  }
1153 
1154  // Find ghost_surface_nodes_indexset for the surface_nodes vector.
1155  {
1156  const unsigned int n_surface_nodes = all_surface_nodes.size();
1158  ghost_surface_nodes_indexset.set_size(n_surface_nodes);
1159  for (auto index = locally_relevant_surface_nodes_indices.begin(); index != locally_relevant_surface_nodes_indices.end(); ++index) {
1160  auto it = std::find (locally_owned_surface_nodes_indices.begin(), locally_owned_surface_nodes_indices.end(), *index);
1161  if (it == locally_owned_surface_nodes_indices.end()) {
1162  // If not in locally_owned_surface_nodes_indexset then, it must be a ghost entry
1163  bool found = false;
1164  for (unsigned int i = 0; i < all_surface_indices.size(); i++) {
1165  if (all_surface_indices[i] == *index) {
1166  ghost_surface_nodes_indexset.add_index(i);
1167  found = true;
1168  break;
1169  }
1170  }
1171  if (!found) {
1172  std::cout << "Could not find index " << *index << " in the surface indices... Aborting. " << std::endl;
1173  std::cout << "All surface_indices: " << std::endl;
1174  for (unsigned int i = 0; i < all_surface_indices.size(); i++) {
1175  std::cout << "i " << i << " all_surface_indices[i] " << all_surface_indices[i] << std::endl;
1176  }
1177  std::cout << "Locally relevant surface nodes indices: " << std::endl;
1178  for (unsigned int i = 0; i < locally_relevant_surface_nodes_indices.size(); i++) {
1179  std::cout << "i " << i << " locally_relevant_surface_nodes_indices[i] " << locally_relevant_surface_nodes_indices[i] << std::endl;
1180  }
1181  std::cout << "Locally owned surface nodes indices: " << std::endl;
1182  for (unsigned int i = 0; i < locally_owned_surface_nodes_indices.size(); i++) {
1183  std::cout << "i " << i << " locally_owned_surface_nodes_indices[i] " << locally_owned_surface_nodes_indices[i] << std::endl;
1184  }
1185 
1186  std::abort();
1187  }
1188  }
1189  }
1190  }
1191 
1194  unsigned int i = 0;
1195  auto index = surface_to_volume_indices.begin();
1196  AssertDimension(locally_owned_surface_nodes_indexset.n_elements(), locally_owned_surface_nodes.size());
1197  AssertDimension(locally_owned_surface_nodes_indexset.n_elements(), locally_owned_surface_nodes_indices.size());
1198  for (auto node = surface_nodes.begin(); node != surface_nodes.end(); node++, index++, i++) {
1199  *node = locally_owned_surface_nodes[i];
1201  }
1202  surface_to_volume_indices.update_ghost_values();
1203  surface_nodes.update_ghost_values();
1204 
1206 }
1207 
1208 
1209 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1211 {
1212  const unsigned int n_rows = volume_nodes.size();
1213  const unsigned int n_cols = surface_nodes.size();
1214 
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);
1218 
1219  const dealii::IndexSet &col_part = surface_nodes.get_partitioner()->locally_owned_range();
1220 
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)) {
1224  const unsigned int i_row = surface_to_volume_indices[i_col];
1225  dsp.add(i_row, i_col);
1226  }
1227  }
1228 
1229  dealii::SparsityTools::distribute_sparsity_pattern(dsp, row_part, mpi_communicator, locally_relevant_dofs);
1230 
1231  map_nodes_surf_to_vol.reinit(row_part, col_part, dsp, mpi_communicator);
1232 
1233  for (unsigned int i_col = 0; i_col < n_cols; ++i_col) {
1234  if (col_part.is_element(i_col)) {
1235  const unsigned int i_row = surface_to_volume_indices[i_col];
1236  map_nodes_surf_to_vol.set(i_row, i_col, 1.0);
1237  }
1238  }
1239  map_nodes_surf_to_vol.compress(dealii::VectorOperation::insert);
1240 }
1241 
1242 
1243 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1245 {
1247  initial_volume_nodes.update_ghost_values();
1249  initial_surface_nodes.update_ghost_values();
1251 }
1252 
1253 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1263 
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);
1267 
1268  // Use unordered sets which uses hashmap.
1269  // Has an average complexity of O(1) (worst case O(n)) for finding and inserting
1270  // Overall algorithm average will be O(n), worst case O(n^2)
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;
1273  for (auto cell = dof_handler_grid.begin_active(); cell!=dof_handler_grid.end(); ++cell) {
1274 
1275  if (!cell->is_locally_owned() && !cell->is_ghost()) continue;
1276  if (!cell->at_boundary()) continue;
1277 
1278  cell->get_dof_indices(dof_indices);
1279 
1280  // Each time a new shape_within_base is found, add it to the list of points.
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;
1283 
1284  for (unsigned int iface=0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface) {
1285  const auto face = cell->face(iface);
1286 
1287  if (!face->at_boundary()) continue;
1288 
1289  const unsigned int boundary_id = face->boundary_id();
1290  // Can't assign a face of dim 0 (point) a user_index...
1291  // Works in 2D and 3D, but not 1D
1292  // const unsigned int face_user_index = face->user_index();
1293 
1294  for (unsigned int idof_face=0; idof_face<dofs_per_face; ++idof_face) {
1295  // Get the cell dof index based on the current face dof index.
1296  // For example, there might be 9 dofs on the face.
1297  // The 5th dof of that face might correspond to the 24th dof on the cell
1298  unsigned int idof_cell = fe_system.face_to_cell_index(idof_face, iface);
1299 
1300  const dealii::types::global_dof_index global_idof_index = dof_indices[idof_cell];
1301 
1302  // If dof is not already in our hashmap, then insert it into our set of surface indices.
1303  // Even though the set is unique, we are really only creating a vector of indices and boundary ID,
1304  // and therefore can't just insert.
1305  // However, do not add if it is not locally owned, it will get picked up by another processor
1306 
1307 
1308  // For linear elasticity, need access to locally RELEVANT volume_nodes. Not just the locally owned ones.
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);
1311  locally_relevant_surface_nodes_indices.push_back(global_idof_index);
1312  locally_relevant_surface_nodes_boundary_id.push_back(boundary_id);
1313  // Refer to the nonmenclature of
1314  // https://www.dealii.org/current/doxygen/deal.II/classFiniteElement.html#ae2ea16b60a6fc644a9bc7097703a53e8
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() ) {
1320  // If the point does not exist, add it to the list of points.
1321  shape_within_base_found.insert(shape_within_base);
1322 
1323  dealii::Point<dim> point;
1324  point[component] = volume_nodes[global_idof_index];
1325  locally_relevant_surface_points.push_back(point);
1326  point_index = locally_relevant_surface_points.size()-1;
1327  shape_function_within_base_to_point_index[shape_within_base] = point_index;
1328  } else {
1329  // The point has already been visited.
1330  // Simply complete its Point data entries.
1331  point_index = shape_function_within_base_to_point_index[shape_within_base];
1332  locally_relevant_surface_points[point_index][component] = volume_nodes[global_idof_index];
1333  }
1334  //if (global_idof_index == 1682 || global_idof_index == 1683) {
1335  // std::cout << "Point 1682 or 1683 " << locally_relevant_surface_points[point_index] << std::endl;
1336  //}
1337 
1338  global_index_to_point_and_axis[global_idof_index] = std::make_pair(point_index, component);
1339  point_and_axis_to_global_index[std::make_pair(point_index, component)] = global_idof_index;
1340  }
1341 
1342  if (locally_owned_dofs_grid.is_element(global_idof_index)) {
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);
1345  locally_owned_surface_nodes_indices.push_back(global_idof_index);
1346  }
1347  }
1348  }
1349  } // iface loop
1350 
1351  } // cell loop
1352  //std::cout << "I own " << locally_relevant_surface_nodes_indices.size() << " surface nodes" << std::endl;
1353 }
1354 
1355 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1356 
1357 VectorType
1358 HighOrderGrid<dim,real,MeshType,VectorType,DoFHandlerType>::transform_surface_nodes(std::function<dealii::Point<dim>(dealii::Point<dim>)> transformation) const
1359 {
1360  VectorType new_surface_nodes(surface_nodes);
1361  auto index = surface_to_volume_indices.begin();
1362  auto new_node = new_surface_nodes.begin();
1363  for (; index != surface_to_volume_indices.end(); ++index, ++new_node) {
1364  const dealii::types::global_dof_index global_idof_index = *index;
1365  //const std::pair<unsigned int, unsigned int> ipoint_component = global_index_to_point_and_axis[global_idof_index];
1366  //const auto ipoint_component = global_index_to_point_and_axis.at(global_idof_index);
1367  const std::pair<unsigned int, unsigned int> ipoint_component = global_index_to_point_and_axis.at(global_idof_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++) {
1372  point[d] = locally_relevant_surface_points[ipoint][d];
1373  }
1374  dealii::Point<dim> new_point = transformation(point);
1375  *new_node = new_point[component];
1376  }
1377  new_surface_nodes.update_ghost_values();
1378  return new_surface_nodes;
1379 }
1380 
1381 template <int dim, typename real, typename MeshType, typename VectorType, typename DoFHandlerType>
1383 {
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;
1387 
1388  dealii::DataOut<dim, dealii::DoFHandler<dim>> data_out;
1389  data_out.attach_dof_handler (dof_handler_grid);
1390 
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");
1396  }
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);
1399 
1400  dealii::Vector<float> subdomain(triangulation->n_active_cells());
1401  for (unsigned int i = 0; i < subdomain.size(); ++i) {
1402  subdomain[i] = triangulation->locally_owned_subdomain();
1403  }
1404  data_out.add_data_vector(subdomain, "subdomain", dealii::DataOut_DoFData<dealii::DoFHandler<dim>,dim>::DataVectorType::type_cell_data);
1405 
1406  // const GridPostprocessor<dim> grid_post_processor;
1407  // data_out.add_data_vector (volume_nodes, grid_post_processor);
1408 
1409  VectorType jacobian_determinant;
1410  jacobian_determinant.reinit(locally_owned_dofs_grid, ghost_dofs_grid, mpi_communicator);
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;
1415  for (auto cell = dof_handler_grid.begin_active(); cell!=dof_handler_grid.end(); ++cell) {
1416  if (!cell->is_locally_owned()) continue;
1417  jac_det = evaluate_jacobian_at_points(volume_nodes, cell, points);
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];
1421  }
1422  }
1423 
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));
1428  }
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);
1431 
1432  typename dealii::DataOut<dim>::CurvedCellRegion curved = dealii::DataOut<dim>::CurvedCellRegion::curved_inner_cells;
1433  //typename dealii::DataOut<dim>::CurvedCellRegion curved = dealii::DataOut<dim>::CurvedCellRegion::curved_boundary;
1434  //typename dealii::DataOut<dim>::CurvedCellRegion curved = dealii::DataOut<dim>::CurvedCellRegion::no_curved_cells;
1435 
1436  const dealii::Mapping<dim> &mapping = (*(mapping_fe_field));
1437  const int n_subdivisions = max_degree;;//+30; // if write_higher_order_cells, n_subdivisions represents the order of the cell
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);
1442 
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);
1446  filename += ".vtu";
1447  std::ofstream output(filename);
1448  data_out.write_vtu(output);
1449  if (iproc == 0) {
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);
1454  fn += ".vtu";
1455  filenames.push_back(fn);
1456  }
1457  std::ofstream master_output(master_fn);
1458  data_out.write_pvtu_record(master_output, filenames);
1459  }
1460 
1461 }
1462 
1463 template <int dim>
1465  const dealii::DataPostprocessorInputs::Vector<dim> &inputs,
1466  std::vector<dealii::Vector<double>> &computed_quantities) const
1467 {
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());
1474  }
1475  for (unsigned int q=0; q<n_solution_points; ++q) {
1476 
1477  // const dealii::Vector<double> &uh = inputs.solution_values[q];
1478  const std::vector<dealii::Tensor<1,dim> > &duh = inputs.solution_gradients[q];
1479  // const std::vector<dealii::Tensor<2,dim> > &dduh = inputs.solution_hessians[q];
1480  // const dealii::Tensor<1,dim> &normals = inputs.normals[q];
1481  // const dealii::Point<dim> &evaluation_points = inputs.evaluation_points[q];
1482 
1483  unsigned int current_data_index = 0;
1484 
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] << " ";
1490  }
1491  }
1492  computed_quantities[q](current_data_index++) = determinant(jacobian);
1493  std::cout << "Jac: " << computed_quantities[q](current_data_index) << std::endl;
1494 
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. "
1498  << std::endl;
1499  }
1500  }
1501 
1502 }
1503 
1504 template <int dim>
1505 std::vector<dealii::DataComponentInterpretation::DataComponentInterpretation> GridPostprocessor<dim>
1507 {
1508  namespace DCI = dealii::DataComponentInterpretation;
1509  std::vector<DCI::DataComponentInterpretation> interpretation;
1510  interpretation.push_back (DCI::component_is_scalar); // Jacobian
1511 
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;
1515  }
1516  return interpretation;
1517 }
1518 
1519 
1520 template <int dim>
1521 std::vector<std::string> GridPostprocessor<dim>::get_names () const
1522 {
1523  std::vector<std::string> names;
1524  names.push_back ("JacobianDeterminant");
1525  return names;
1526 }
1527 
1528 template <int dim>
1530 {
1531  //return update_values | update_gradients;
1532  return dealii::update_values | dealii::update_gradients;
1533 }
1534 
1535 
1538 #if PHILIP_DIM!=1
1540 #endif
1541 } // namespace PHiLiP
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.
Definition: ADTypes.hpp:11
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.
Definition: ADTypes.hpp:10
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.