1 #include "anisotropic_mesh_adaptation.h"     2 #include <deal.II/base/symmetric_tensor.h>     3 #include "linear_solver/linear_solver.h"     4 #include "physics/physics_factory.h"     5 #include "physics/model_factory.h"     6 #include "mesh/gmsh_reader.hpp"     7 #include "metric_to_mesh_generator.h"     8 #include <deal.II/dofs/dof_renumbering.h>     9 #include "fe_values_shape_hessian.h"    13 template <
int dim, 
int nstate, 
typename real, 
typename MeshType>
    17     const real _complexity,
    18     const bool _use_goal_oriented_approach)
    20     , use_goal_oriented_approach(_use_goal_oriented_approach)
    22     , complexity(_complexity)
    23     , mpi_communicator(MPI_COMM_WORLD)
    24     , pcout(
std::cout, dealii::Utilities::MPI::this_mpi_process(mpi_communicator)==0)
    25     , initial_poly_degree(dg->get_min_fe_degree())
    26     , max_dofs_per_cell(dg->dof_handler.get_fe_collection().max_dofs_per_cell())
    35             std::cout<<
"Optimal metric for the goal oriented approach has been derived w.r.t the error in L1 norm. Aborting..."<<std::flush;
    44     if(
dg->get_min_fe_degree() != 
dg->get_max_fe_degree())
    46         std::cout<<
"This class is currently coded assuming a constant poly degree. To be changed in future if required."<<std::endl;
    52         pcout<<
"Warning: The optimal metric used by this class has been derived for p1."    53              <<
" For any other p, it might be a good approximation but will not be optimal."<<std::endl; 
    56     Assert(this->
dg->triangulation->get_mesh_smoothing() == 
typename dealii::Triangulation<dim>::MeshSmoothing(dealii::Triangulation<dim>::none),
    57            dealii::ExcMessage(
"Mesh smoothing might h-refine cells while changing p order."));
    61 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
    66     dealii::Tensor<2, dim, real> input_tensor_copy = input_tensor;
    67     for(
int i=0; i<dim; ++i)
    69         for(
int j=0; j<dim-i; ++j)
    71             if(abs(input_tensor_copy[i][j] - input_tensor_copy[j][i]) > 1.0e-10)
    73                 std::cout<<
"Input tensor needs to be symmetric. Difference = "<< abs(input_tensor_copy[i][j] - input_tensor_copy[j][i]) <<
".  Aborting.."<<std::endl<<std::flush;
    78                 input_tensor_copy[j][i] = input_tensor_copy[i][j];
    82     dealii::SymmetricTensor<2,dim,real> symmetric_input_tensor(input_tensor_copy); 
    83     std::array<std::pair<real, dealii::Tensor<1, dim, real>>, dim> eigen_pair = dealii::eigenvectors(symmetric_input_tensor);
    85     std::array<real, dim> abs_eigenvalues;
    86     const real min_eigenvalue = 1.0e-8;
    87     const real max_eigenvalue = 1.0e8;
    89     for(
unsigned int i = 0; i<dim; ++i)
    91         abs_eigenvalues[i] = abs(eigen_pair[i].first);
    92         if(abs_eigenvalues[i] < min_eigenvalue) {abs_eigenvalues[i] = min_eigenvalue;}
    93         if(abs_eigenvalues[i] > max_eigenvalue) {abs_eigenvalues[i] = max_eigenvalue;}
    96     dealii::Tensor<2, dim, real> positive_definite_tensor; 
   102     for(
unsigned int i=0; i<dim; ++i)
   104         dealii::Tensor<1, dim, real> eigenvector_i = eigen_pair[i].second;
   105         dealii::Tensor<2, dim, real> outer_product_i = dealii::outer_product(eigenvector_i, eigenvector_i);
   106         outer_product_i *= abs_eigenvalues[i];
   107         positive_definite_tensor += outer_product_i;
   110     return positive_definite_tensor;
   113 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   118     const unsigned int n_active_cells = 
dg->triangulation->n_active_cells();
   120     dealii::Tensor<2, dim, real> zero_tensor; 
   121     for(
unsigned int i=0; i<n_active_cells; ++i)
   128 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   134     pcout<<
"Computing optimal metric field."<<std::endl;
   136     const unsigned int n_active_cells = 
dg->triangulation->n_active_cells();
   137     dealii::Vector<real> abs_hessian_determinant(n_active_cells);
   140     for(
const auto &cell : 
dg->dof_handler.active_cell_iterators())
   142         if(! cell->is_locally_owned()) {
continue;}
   144         const unsigned int cell_index = cell->active_cell_index();
   145         abs_hessian_determinant[cell_index] = dealii::determinant(
cellwise_hessian[cell_index]);    
   149     const auto mapping = (*(
dg->high_order_grid->mapping_fe_field));
   150     dealii::hp::MappingCollection<dim> mapping_collection(mapping);
   151     const dealii::UpdateFlags update_flags = dealii::update_JxW_values;
   152     dealii::hp::FEValues<dim,dim>   fe_values_collection_volume (mapping_collection, 
dg->fe_collection, 
dg->volume_quadrature_collection, update_flags);
   154     real integral_val = 0;
   155     for(
const auto &cell : 
dg->dof_handler.active_cell_iterators())
   157         if(! cell->is_locally_owned()) {
continue;}
   159         const unsigned int cell_index = cell->active_cell_index();
   160         const unsigned int i_fele = cell->active_fe_index();
   161         const unsigned int i_quad = i_fele;
   162         const unsigned int i_mapp = 0;
   163         fe_values_collection_volume.reinit(cell, i_quad, i_mapp, i_fele);
   164         const dealii::FEValues<dim,dim> &fe_values_volume = fe_values_collection_volume.get_present_fe_values();
   167         const real integrand = pow(abs_hessian_determinant[cell_index], exponent);
   169         for(
unsigned int iquad = 0; iquad<fe_values_volume.n_quadrature_points; ++iquad)
   171             integral_val += integrand * fe_values_volume.JxW(iquad);
   175     const real integral_val_global = dealii::Utilities::MPI::sum(integral_val, 
mpi_communicator);
   176     const real exponent = 2.0/dim;
   177     const real scaling_factor = pow(
complexity, exponent) * pow(integral_val_global, -exponent); 
   180     for(
const auto &cell : 
dg->dof_handler.active_cell_iterators())
   182         if(! cell->is_locally_owned()) {
continue;}
   184         const unsigned int cell_index = cell->active_cell_index();
   186         const real exponent2 = -1.0/(2.0*
normLp + dim);
   187         const real scaling_factor2 = pow(abs_hessian_determinant[cell_index], exponent2);
   188         const real scaling_factor_this_cell = scaling_factor * scaling_factor2;
   194     pcout<<
"Done computing optimal metric."<<std::endl;
   197 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   201     solution_old.update_ghost_values();
   217     dg->solution = solution_old; 
   218     dg->solution.update_ghost_values();
   221 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   224     assert(
dg->get_min_fe_degree() == 
dg->get_max_fe_degree());
   225     const unsigned int current_poly_degree = 
dg->get_min_fe_degree();
   226     pcout<<
"Changing poly degree from "<<current_poly_degree<< 
" to "<<poly_degree<<
" and interpolating solution."<<std::endl;
   228     solution_coarse.update_ghost_values();
   230     using DoFHandlerType   = 
typename dealii::DoFHandler<dim>;
   233     SolutionTransfer solution_transfer(this->
dg->dof_handler);
   234     solution_transfer.prepare_for_coarsening_and_refinement(solution_coarse);
   236     dg->set_all_cells_fe_degree(poly_degree);
   237     dg->allocate_system();
   238     dg->solution.zero_out_ghosts();
   240     if constexpr (std::is_same_v<
typename dealii::SolutionTransfer<dim,VectorType,DoFHandlerType>,
   241                                  decltype(solution_transfer)>) {
   242         solution_transfer.interpolate(solution_coarse, this->
dg->solution);
   244         solution_transfer.interpolate(this->
dg->solution);
   247     this->
dg->solution.update_ghost_values();
   250 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   253     assert(
dg->get_min_fe_degree() == 2);
   254     pcout<<
"Reconstructing p2 solution."<<std::endl;
   255     dg->assemble_residual(
true);
   257     solve_linear(
dg->system_matrix, 
dg->right_hand_side, delU, 
dg->all_parameters->linear_solver_param);
   259     delU.update_ghost_values();
   260     dg->solution += delU;
   261     dg->solution.update_ghost_values();
   264 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   267     assert(
dg->get_min_fe_degree() == 
dg->get_max_fe_degree());
   268     assert(
dg->get_min_fe_degree() == 2);
   269     pcout<<
"Computing feature based Hessian."<<std::endl;
   272     const auto mapping = (*(
dg->high_order_grid->mapping_fe_field));
   273     dealii::hp::MappingCollection<dim> mapping_collection(mapping);
   274     const dealii::UpdateFlags update_flags = dealii::update_jacobian_pushed_forward_grads | dealii::update_inverse_jacobians;
   275     dealii::hp::FEValues<dim,dim>   fe_values_collection_volume (mapping_collection, 
dg->fe_collection, 
dg->volume_quadrature_collection, update_flags);
   280     for(
const auto &cell : 
dg->dof_handler.active_cell_iterators())
   282         if(! cell->is_locally_owned()) {
continue;}
   284         const unsigned int cell_index = cell->active_cell_index();
   285         const unsigned int i_fele = cell->active_fe_index();
   286         const unsigned int i_quad = i_fele;
   287         const unsigned int i_mapp = 0;
   288         fe_values_collection_volume.reinit(cell, i_quad, i_mapp, i_fele);
   289         const dealii::FEValues<dim,dim> &fe_values_volume = fe_values_collection_volume.get_present_fe_values();
   291         const unsigned int n_dofs_cell = fe_values_volume.dofs_per_cell; 
   292         dof_indices.resize(n_dofs_cell);
   293         cell->get_dof_indices(dof_indices);
   297         fe_values_shape_hessian.
reinit(fe_values_volume, iquad);
   298         const dealii::FESystem<dim,dim> &fe_ref = fe_values_volume.get_fe();
   300         for(
unsigned int idof = 0; idof<n_dofs_cell; ++idof)
   302             const unsigned int icomp = fe_values_volume.get_fe().system_to_component_index(idof).first;
   313 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   316     assert(
dg->get_min_fe_degree() == 
dg->get_max_fe_degree());
   317     assert(
dg->get_min_fe_degree() == 2);
   326     dg->assemble_residual(
true);
   330     adjoint.update_ghost_values();
   333     pcout<<
"Computing goal-oriented Hessian."<<std::endl;
   334     const auto mapping = (*(
dg->high_order_grid->mapping_fe_field));
   335     dealii::hp::MappingCollection<dim> mapping_collection(mapping);
   336     const dealii::UpdateFlags update_flags = dealii::update_values | dealii::update_gradients | dealii::update_jacobian_pushed_forward_grads | dealii::update_inverse_jacobians;
   337     dealii::hp::FEValues<dim,dim>   fe_values_collection_volume (mapping_collection, 
dg->fe_collection, 
dg->volume_quadrature_collection, update_flags);
   342     for(
const auto &cell : 
dg->dof_handler.active_cell_iterators())
   344         if(! cell->is_locally_owned()) {
continue;}
   346         const unsigned int cell_index = cell->active_cell_index();
   347         const unsigned int i_fele = cell->active_fe_index();
   348         const unsigned int i_quad = i_fele;
   349         const unsigned int i_mapp = 0;
   350         fe_values_collection_volume.reinit(cell, i_quad, i_mapp, i_fele);
   351         const dealii::FEValues<dim,dim> &fe_values_volume = fe_values_collection_volume.get_present_fe_values();
   353         const unsigned int n_dofs_cell = fe_values_volume.dofs_per_cell; 
   354         dof_indices.resize(n_dofs_cell);
   355         cell->get_dof_indices(dof_indices);
   358         fe_values_shape_hessian.
reinit(fe_values_volume, iquad);
   359         const dealii::FESystem<dim,dim> &fe_ref = fe_values_volume.get_fe();
   362         std::array<dealii::Tensor<1,dim,real>,nstate> adjoint_gradient; 
   363         for(
unsigned int idof = 0; idof<n_dofs_cell; ++idof)
   365             const unsigned int istate = fe_ref.system_to_component_index(idof).first;
   366             adjoint_gradient[istate] += adjoint(dof_indices[idof]) * fe_values_volume.shape_grad_component(idof,iquad,istate);
   370         std::vector<std::array<dealii::Tensor<1,dim,real>,nstate>> flux_at_support_pts(n_dofs_cell);
   375         for(
unsigned int istate = 0; istate < nstate; ++istate)
   377             for(
unsigned int idim = 0; idim < dim; ++idim)
   379                 dealii::Tensor<2,dim,real> flux_hessian_at_istate_idim;
   380                 for(
unsigned int idof = 0; idof<n_dofs_cell; ++idof)
   382                     const unsigned int icomp = fe_values_volume.get_fe().system_to_component_index(idof).first;
   385                         flux_hessian_at_istate_idim += flux_at_support_pts[idof][istate][idim]*fe_values_shape_hessian.
shape_hessian_component(idof, iquad, istate, fe_ref);
   389                 flux_hessian_at_istate_idim *= abs(adjoint_gradient[istate][idim]);
   396 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   398     const dealii::Quadrature<dim> &volume_quadrature)
 const   400     dealii::Point<dim,real> ref_center;
   401     for(
unsigned int idim = 0; idim < dim; ++idim){
   402         ref_center[idim] = 0.5;}
   404     unsigned int iquad_center = 0;
   405     real min_distance = 10000.0;
   406     for(
unsigned int iquad = 0; iquad<volume_quadrature.size(); ++iquad)
   408         const dealii::Point<dim, real> &ref_point = volume_quadrature.point(iquad);
   409         const real ref_distance = ref_point.distance(ref_center); 
   410         if(min_distance > ref_distance)
   412             min_distance = ref_distance;
   413             iquad_center = iquad;
   421 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   423     std::vector<std::array<dealii::Tensor<1,dim,real>,nstate>> &flux_at_support_pts, 
   424     const dealii::FEValues<dim,dim> &fe_values_input,
   425     const std::vector<dealii::types::global_dof_index> &dof_indices,
   426     typename dealii::DoFHandler<dim>::active_cell_iterator cell)
 const   428     if( ! fe_values_input.get_fe().has_support_points() )
   430         pcout<<
"The code here treats flux at support points as flux coeff at idof "   431              <<
"which requires an interpolatory FE with support points. Aborting.."<<std::endl;
   435     const unsigned int n_dofs_cell = dof_indices.size();
   436     dealii::Quadrature<dim> support_pts = fe_values_input.get_fe().get_unit_support_points();
   437     dealii::FEValues<dim, dim> fe_values_support_pts(fe_values_input.get_mapping(), fe_values_input.get_fe(),
   438                                                      support_pts, dealii::update_values);
   439     fe_values_support_pts.reinit(cell);
   440     const unsigned int n_quad_pts = fe_values_support_pts.n_quadrature_points;
   441     Assert(n_quad_pts == n_dofs_cell, dealii::ExcMessage(
"n_quad_pts != n_dofs_cell"));
   443     for(
unsigned int iquad = 0; iquad<n_quad_pts; ++iquad)
   445         std::array< real, nstate > soln_at_q;
   447         for(
unsigned int idof = 0; idof < n_dofs_cell; ++idof)
   449             const unsigned int istate = fe_values_support_pts.get_fe().system_to_component_index(idof).first;
   450             soln_at_q[istate] += 
dg->solution(dof_indices[idof]) * fe_values_support_pts.shape_value_component(idof, iquad, istate);
   458 template<
int dim, 
int nstate, 
typename real, 
typename MeshType>
   463     std::unique_ptr<MetricToMeshGenerator<dim, nstate, real>> metric_to_mesh_generator
   464         = std::make_unique<MetricToMeshGenerator<dim, nstate, real>> (
dg->high_order_grid->mapping_fe_field, 
dg->triangulation);
   467     std::shared_ptr<HighOrderGrid<dim,double,MeshType>> new_high_order_mesh = 
   468                                                         read_gmsh <dim, dim> (metric_to_mesh_generator->get_generated_mesh_filename(), 
dg->all_parameters->do_renumber_dofs);
   469     dg->set_high_order_grid(new_high_order_mesh);
   470     dg->allocate_system();
   474     dg->solution.update_ghost_values();
 std::shared_ptr< Functional< dim, nstate, real, MeshType > > functional
Functional to evaluate the adjoint for goal oriented anisotropic meshing. 
int mpi_rank
Processor# of current processor. 
void compute_feature_based_hessian()
Computes feature based hessian (i.e. hessian of the solution). 
std::shared_ptr< DGBase< dim, real, MeshType > > dg
Shared pointer to DGBase. 
dealii::Tensor< 2, dim, double > shape_hessian_component(const unsigned int idof, const unsigned int iquad, const unsigned int istate, const dealii::FESystem< dim, dim > &fe_ref) const
Evaluates hessian of shape functions w.r.t. phyical quadrature points. 
void initialize_cellwise_metric_and_hessians()
Initializes cellwise metric and hessian to zero tensors. 
std::pair< unsigned int, double > solve_linear(const dealii::TrilinosWrappers::SparseMatrix &system_matrix, dealii::LinearAlgebra::distributed::Vector< double > &right_hand_side, dealii::LinearAlgebra::distributed::Vector< double > &solution, const Parameters::LinearSolverParam ¶m)
dealii::ConditionalOStream pcout
std::cout only on processor #0. 
std::shared_ptr< Physics::PhysicsBase< dim, nstate, real > > pde_physics_double
Contains the physics of the PDE with real type. 
Files for the baseline physics. 
void adapt_mesh()
Function which adapts mesh and loads in new mesh. 
std::vector< dealii::Tensor< 2, dim, real > > cellwise_hessian
Stores hessian in each cell. 
void get_flux_at_support_pts(std::vector< std::array< dealii::Tensor< 1, dim, real >, nstate >> &flux_at_support_pts, const dealii::FEValues< dim, dim > &fe_values_input, const std::vector< dealii::types::global_dof_index > &dof_indices, typename dealii::DoFHandler< dim >::active_cell_iterator cell) const
Returns flux coeffs by evaluating flux at support points of fe. 
void reinit(const dealii::FEValues< dim, dim > &fe_values_volume, const unsigned int iquad)
Store inverse jacobian and 3rd order tensors which will be the same for a combination of cell/physica...
const real normLp
Lp Norm w.r.t. which the anlytical optimization is done. 
dealii::LinearAlgebra::distributed::Vector< double > VectorType
Alias for dealii's parallel distributed vector. 
unsigned int get_iquad_near_cellcenter(const dealii::Quadrature< dim > &volume_quadrature) const
Returns quadrature number of a point which is closest to the reference cell's center. 
void compute_goal_oriented_hessian()
Computes pseudo Hessian for the goal oriented approach. 
std::vector< dealii::Tensor< 2, dim, real > > cellwise_optimal_metric
Stores optimal metric in each cell. 
const unsigned int max_dofs_per_cell
Stores max dofs per cell to initialize dof_indices. 
void change_p_degree_and_interpolate_solution(const unsigned int poly_degree)
Change the polynomial order and interpolate solution. 
static std::shared_ptr< ModelBase< dim, nstate, real > > create_Model(const Parameters::AllParameters *const parameters_input)
Factory to return the correct model given input parameters. 
int n_mpi
Total no. of processors. 
AnisotropicMeshAdaptation(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input, const real _norm_Lp, const real _complexity, const bool _use_goal_oriented_approach=false)
Constructor. 
dealii::Tensor< 2, dim, real > get_positive_definite_tensor(const dealii::Tensor< 2, dim, real > &input_tensor) const
Returns positive tensor from an input tensor by taking absolute of eigenvalues. 
static std::shared_ptr< PhysicsBase< dim, nstate, real > > create_Physics(const Parameters::AllParameters *const parameters_input, std::shared_ptr< ModelBase< dim, nstate, real > > model_input=nullptr)
Factory to return the correct physics given input file. 
void reconstruct_p2_solution()
Reconstructs p2 solution after interpolation. 
const unsigned int initial_poly_degree
Stores initial polynomial degree. 
Class to evaluate hessians of shape functions w.r.t. physical quadrature points. 
static std::shared_ptr< Functional< dim, nstate, real, MeshType > > create_Functional(PHiLiP::Parameters::AllParameters const *const param, std::shared_ptr< PHiLiP::DGBase< dim, real, MeshType > > dg)
Create standard functional object from constant parameter file. 
const bool use_goal_oriented_approach
Flag to use goal oriented approach. It is set to false by default. 
void compute_cellwise_optimal_metric()
Computes optimal metric depending on goal oriented or feature based approach. 
void compute_abs_hessian()
Computes hessian using the input coefficients, which can be a solution sensor or (for goal oriented a...
DGBase is independent of the number of state variables. 
MPI_Comm mpi_communicator
Alias for MPI_COMM_WORLD. 
const real complexity
Analogue of number of vertices/elements in continuous mesh framework.