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.