1 #include "grid_refinement_study.h" 3 #include <deal.II/base/convergence_table.h> 4 #include <deal.II/distributed/shared_tria.h> 5 #include <deal.II/distributed/tria.h> 6 #include <deal.II/dofs/dof_tools.h> 7 #include <deal.II/fe/fe_values.h> 8 #include <deal.II/grid/grid_generator.h> 9 #include <deal.II/grid/grid_in.h> 10 #include <deal.II/grid/grid_out.h> 11 #include <deal.II/grid/grid_refinement.h> 12 #include <deal.II/grid/grid_tools.h> 13 #include <deal.II/grid/tria.h> 14 #include <deal.II/numerics/vector_tools.h> 20 #include <type_traits> 22 #include "dg/dg_base.hpp" 23 #include "dg/dg_factory.hpp" 24 #include "functional/adjoint.h" 25 #include "functional/functional.h" 26 #include "grid_refinement/gmsh_out.h" 27 #include "grid_refinement/gnu_out.h" 28 #include "grid_refinement/grid_refinement.h" 29 #include "grid_refinement/msh_out.h" 30 #include "grid_refinement/size_field.h" 31 #include "ode_solver/ode_solver_factory.h" 32 #include "physics/manufactured_solution.h" 33 #include "physics/model_factory.h" 34 #include "physics/physics_factory.h" 41 template <
int dim,
int nstate>
47 double value(
const dealii::Point<dim> &,
const unsigned int )
const override 53 template <
int dim,
int nstate,
typename MeshType>
58 template <
int dim,
int nstate,
typename MeshType>
61 pcout <<
" Running Grid Refinement Study. " << std::endl;
65 using ADtype = Sacado::Fad::DFad<double>;
67 const unsigned int poly_degree = grs_param.
poly_degree;
74 std::shared_ptr< Physics::ModelBase<dim,nstate,double> > model_double
76 std::shared_ptr< Physics::ModelBase<dim,nstate,ADtype> > model_adtype
80 std::shared_ptr< Physics::PhysicsBase<dim,nstate,double> > physics_double
82 std::shared_ptr< Physics::PhysicsBase<dim,nstate,ADtype> > physics_adtype
86 std::vector<dealii::ConvergenceTable> convergence_table_vector;
92 std::vector<double> error_per_cell;
95 for(
unsigned int iref = 0; iref < (num_refinements?num_refinements:1); ++iref){
101 std::shared_ptr<MeshType> grid =
108 double functional_value_exact;
118 std::cout <<
"Functional estimate = " << functional_value_exact << std::endl;
121 std::shared_ptr< DGBase<dim, double, MeshType> > dg
128 dg->allocate_system();
131 std::shared_ptr<dealii::Function<dim>> initial_conditions =
132 std::make_shared<InitialConditions<dim,nstate>>();
134 dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
135 solution_no_ghost.reinit(dg->locally_owned_dofs, MPI_COMM_WORLD);
136 const auto mapping = *(dg->high_order_grid->mapping_fe_field);
137 dealii::VectorTools::interpolate(mapping, dg->dof_handler, *initial_conditions, solution_no_ghost);
138 dg->solution = solution_no_ghost;
141 std::shared_ptr< ODE::ODESolverBase<dim,double,MeshType> > ode_solver
147 std::shared_ptr< Functional<dim,nstate,double,MeshType> > functional
151 std::shared_ptr< Adjoint<dim,nstate,double,MeshType> > adjoint
152 = std::make_shared< Adjoint<dim,nstate,double,MeshType> >(dg, functional, physics_adtype);
155 std::shared_ptr< GridRefinement::GridRefinementBase<dim,nstate,double,MeshType> > grid_refinement
159 dealii::ConvergenceTable convergence_table;
160 dealii::Vector<float> estimated_error_per_cell(grid->n_active_cells());
163 std::vector<double> solution_error;
164 std::vector<double> functional_error;
165 std::vector<double> dofs;
167 for(
unsigned int igrid = 0; igrid < refinement_steps; ++igrid){
169 grid_refinement->refine_grid();
177 const unsigned int n_global_active_cells = grid->n_global_active_cells();
178 const unsigned int n_dofs = dg->dof_handler.n_dofs();
179 pcout <<
"Dimension: " << dim <<
"\t Polynomial degree p: " << poly_degree << std::endl
180 <<
"Grid number: " << igrid+1 <<
"/" << refinement_steps
181 <<
". Number of active cells: " << n_global_active_cells
182 <<
". Number of degrees of freedom: " << n_dofs
192 auto solve_start = std::chrono::steady_clock::now();
194 ode_solver->steady_state();
196 dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
197 solution_no_ghost.reinit(dg->locally_owned_dofs, MPI_COMM_WORLD);
198 dealii::VectorTools::interpolate(dg->dof_handler, *(physics_double->manufactured_solution_function), solution_no_ghost);
199 dg->solution = solution_no_ghost;
201 auto solve_end = std::chrono::steady_clock::now();
202 auto solve_diff = solve_end - solve_start;
205 int overintegrate = 10;
206 dealii::QGauss<dim> quad_extra(dg->max_degree+overintegrate);
207 dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
208 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
209 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
210 std::array<double,nstate> soln_at_q;
212 double linf_norm = 0.0;
213 double l2_norm = 0.0;
215 std::vector<dealii::types::global_dof_index> dofs_indices(fe_values_extra.dofs_per_cell);
217 error_per_cell.resize(n_global_active_cells);
219 for(
auto cell = dg->dof_handler.begin_active(); cell < dg->dof_handler.end(); ++cell){
220 if(!cell->is_locally_owned())
continue;
222 fe_values_extra.reinit(cell);
223 cell->get_dof_indices(dofs_indices);
225 double cell_l2error = 0.0;
226 std::array<double,nstate> cell_linf;
227 std::fill(cell_linf.begin(), cell_linf.end(), 0);
229 for(
unsigned int iquad = 0; iquad < n_quad_pts; ++iquad){
230 std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
231 for(
unsigned int idof = 0; idof < fe_values_extra.dofs_per_cell; ++idof){
232 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
233 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
236 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
238 for(
unsigned int istate = 0; istate < nstate; ++ istate){
239 const double uexact = physics_double->manufactured_solution_function->value(qpoint, istate);
240 cell_l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
241 cell_linf[istate] = std::max(cell_linf[istate], abs(soln_at_q[istate]-uexact));
245 error_per_cell[cell->active_cell_index()] = l2_norm;
247 l2_norm += cell_l2error;
248 for(
unsigned int istate = 0; istate < nstate; ++ istate){
249 linf_norm = std::max(linf_norm, cell_linf[istate]);
252 const double l2_norm_mpi = std::sqrt(dealii::Utilities::MPI::sum(l2_norm,
mpi_communicator));
253 const double linf_norm_mpi = dealii::Utilities::MPI::max(linf_norm,
mpi_communicator);
256 double functional_value = functional->evaluate_functional();
259 double func_error = abs(functional_value - functional_value_exact);
267 if(dg->get_max_fe_degree() + 1 <= dg->max_degree){
268 auto adj_start = std::chrono::steady_clock::now();
270 adjoint->fine_grid_adjoint();
271 estimated_error_per_cell.reinit(grid->n_active_cells());
272 estimated_error_per_cell = adjoint->dual_weighted_residual();
273 auto adj_end = std::chrono::steady_clock::now();
274 auto adj_diff = adj_end - adj_start;
278 convergence_table.add_value(
"adj_time", ((
double)std::chrono::duration_cast<std::chrono::milliseconds>(adj_diff).count())/1000.);
281 adjoint->output_results_vtk(iref*10+igrid);
286 adjoint->coarse_grid_adjoint();
287 adjoint->output_results_vtk(iref*10+igrid);
292 grid_refinement->output_results_vtk(iref);
296 convergence_table.add_value(
"cells", n_global_active_cells);
297 convergence_table.add_value(
"DoFs", n_dofs);
302 convergence_table.add_value(
"value", functional_value);
303 convergence_table.add_value(
"func_error", func_error);
308 convergence_table.add_value(
"l2_error", l2_norm_mpi);
309 convergence_table.add_value(
"linf_error", linf_norm_mpi);
314 convergence_table.add_value(
"solve_time", ((
double)std::chrono::duration_cast<std::chrono::milliseconds>(solve_diff).count())/1000.);
317 solution_error.push_back(l2_norm_mpi);
318 functional_error.push_back(func_error);
320 dofs.push_back(n_dofs);
324 std::string write_msh_name =
"test-msh-" + dealii::Utilities::int_to_string(iref*10+igrid) +
".msh";
325 std::ofstream out_msh(write_msh_name);
326 msh_out.
add_data_vector(error_per_cell, PHiLiP::GridRefinement::StorageType::element);
331 pcout <<
" ********************************************" << std::endl
332 <<
" Convergence rates for p = " << poly_degree << std::endl
333 <<
" ********************************************" << std::endl;
338 convergence_table.evaluate_convergence_rates(
"value",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
339 convergence_table.set_scientific(
"value",
true);
340 convergence_table.evaluate_convergence_rates(
"func_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
341 convergence_table.set_scientific(
"func_error",
true);
346 convergence_table.evaluate_convergence_rates(
"l2_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
347 convergence_table.set_scientific(
"l2_error",
true);
348 convergence_table.evaluate_convergence_rates(
"linf_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
349 convergence_table.set_scientific(
"linf_error",
true);
352 if(
pcout.is_active()) convergence_table.write_text(
pcout.get_stream());
354 convergence_table_vector.push_back(convergence_table);
358 gf_solution.
add_xy_data(dofs, solution_error,
"l2error."+dealii::Utilities::int_to_string(iref,1));
362 output_gnufig_solution(gf_solution);
366 gf_functional.
add_xy_data(dofs, functional_error,
"ferror."+dealii::Utilities::int_to_string(iref,1));
370 output_gnufig_functional(gf_functional);
375 pcout << std::endl << std::endl << std::endl << std::endl
376 <<
" ********************************************" << std::endl
377 <<
" Convergence summary" << std::endl
378 <<
" ********************************************" << std::endl;
379 for(
auto conv = convergence_table_vector.begin(); conv != convergence_table_vector.end(); ++conv){
380 if(
pcout.is_active()) conv->write_text(
pcout.get_stream());
381 pcout <<
" ********************************************" << std::endl;
385 output_gnufig_solution(gf_solution);
388 output_gnufig_functional(gf_functional);
394 template <
int dim,
int nstate,
typename MeshType>
396 const std::shared_ptr<MeshType>& grid,
399 const unsigned int grid_size = grs_param.
grid_size;
408 if(grs_param.
grid_type == GridEnum::hypercube){
410 dealii::Point<dim,double> p_left;
411 dealii::Point<dim,double> p_right;
412 std::vector<unsigned int> repetitions;
413 for(
unsigned int i = 0; i < dim; ++i){
416 repetitions.push_back(grid_size);
420 bool colorize =
true;
421 dealii::GridGenerator::subdivided_hyper_rectangle(*grid, repetitions, p_left, p_right, colorize);
423 for(
auto cell = grid->begin_active(); cell != grid->end(); ++cell){
424 cell->set_material_id(9002);
425 for(
unsigned int face = 0; face < dealii::GeometryInfo<dim>::faces_per_cell; ++face)
426 if(cell->face(face)->at_boundary()){
433 }
else if(grs_param.
grid_type == GridEnum::read_grid){
436 std::string read_mshname = grs_param.
input_grid;
437 std::cout <<
"Reading grid from: " << read_mshname << std::endl;
440 std::ifstream in_msh(read_mshname);
441 dealii::GridIn<dim,dim> grid_in;
443 grid_in.attach_triangulation(*grid);
444 grid_in.read_msh(in_msh);
450 template <
int dim,
int nstate,
typename MeshType>
458 std::shared_ptr<MeshType> grid_fine =
466 std::cout <<
"Starting refinement." << std::endl;
467 grid_fine->refine_global(N_ref);
468 std::cout <<
"Finished refinement." << std::endl;
470 const unsigned int poly_degree = grs_param.
poly_degree;
475 std::cout <<
"Creating fine dg." << std::endl;
476 std::shared_ptr< DGBase<dim, double, MeshType> > dg_fine =
483 dg_fine->allocate_system();
486 std::cout <<
"Performing solution transfer." << std::endl;
487 dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
488 solution_no_ghost.reinit(dg_fine->locally_owned_dofs, MPI_COMM_WORLD);
489 dealii::VectorTools::interpolate(dg_fine->dof_handler, *(physics_double->manufactured_solution_function), solution_no_ghost);
490 dg_fine->solution = solution_no_ghost;
493 std::cout <<
"Generating the functional." << std::endl;
494 std::shared_ptr< Functional<dim,nstate,double,MeshType> > functional_fine
498 std::cout <<
"Computing and returning approximation" << std::endl;
499 return functional_fine->evaluate_functional();
507 gf.
set_title(
"Error Convergence, |u|_2 vs. Dofs");
521 void output_gnufig_functional(
526 gf.
set_title(
"Functional Convergence, |J(u)-J_h(u_h)| vs. Dofs");
528 gf.
set_y_label(
"Functional error, |J(u)-J_h(u_h)|");
541 std::shared_ptr<dealii::Triangulation<PHILIP_DIM>>
544 return std::make_shared<dealii::Triangulation<PHILIP_DIM>>();
552 std::shared_ptr<dealii::parallel::shared::Triangulation<PHILIP_DIM>>
555 return std::make_shared<dealii::parallel::shared::Triangulation<PHILIP_DIM>>(
557 typename dealii::Triangulation<PHILIP_DIM>::MeshSmoothing(
558 dealii::Triangulation<PHILIP_DIM>::smoothing_on_refinement |
559 dealii::Triangulation<PHILIP_DIM>::smoothing_on_coarsening));
564 std::shared_ptr<dealii::parallel::distributed::Triangulation<PHILIP_DIM>>
567 return std::make_shared<dealii::parallel::distributed::Triangulation<PHILIP_DIM>>(
569 typename dealii::Triangulation<PHILIP_DIM>::MeshSmoothing(
570 dealii::Triangulation<PHILIP_DIM>::smoothing_on_refinement |
571 dealii::Triangulation<PHILIP_DIM>::smoothing_on_coarsening));
Output class for GMSH .msh v4.1 file format.
void set_y_scale_log(const bool ylog_bool_input)
Set flag for logarithmic y-axis.
bool output_gnuplot_functional
Flag to enable output of gnuplot graph of functional error convergence.
void add_data_vector(std::vector< T > data, StorageType storage_type)
Add data vector of specified storage type and values.
bool refresh_gnuplot
Flag to enable gnuplot refresh between iteration runs.
void set_x_label(const std::string &xlabel_input)
Sets the x-axis label.
void set_y_label(const std::string &ylabel_input)
Sets the y-axis label.
const MPI_Comm mpi_communicator
MPI communicator.
unsigned int poly_degree_grid
Initial grid polynomial degree.
void set_name(const std::string &name_input)
Sets the file output name (without extension)
GridEnum grid_type
Grid type selection.
bool use_interpolation
Flag to enable interpolation operation.
double approximate_exact_functional(const std::shared_ptr< Physics::PhysicsBase< dim, nstate, double >> &physics_double, const std::shared_ptr< Physics::PhysicsBase< dim, nstate, Sacado::Fad::DFad< double >>> &physics_adtype, const Parameters::AllParameters ¶m, const Parameters::GridRefinementStudyParam &grs_param) const
Approximates the exact functional using a uniformly refined grid.
void set_legend(const bool legend_bool_input)
Sets display visibility of figure legend.
unsigned int num_refinements
Number of different refinement procedures stored, 0 indicates to use the default pathway.
Files for the baseline physics.
bool output_solution_time
Flag to enable output of grid refinement wall-clock solution time.
GridRefinementStudyParam grid_refinement_study_param
Contains the parameters for grid refinement study.
void write_msh(std::ostream &out)
Output formatted .msh v4.1 file with mesh description and data field.
std::array< GridRefinementParam, MAX_REFINEMENTS > grid_refinement_param_vector
Array of grid refinement parameters to be run as part of grid refinement study.
unsigned int poly_degree_max
Maximimum allocated solution polynomial degree.
void add_xy_data(const std::vector< real > &x_data, const std::vector< real > &y_data)
Adds 2D x vs. y data to be plotted (default legend label)
Main parameter class that contains the various other sub-parameter classes.
bool approximate_functional
Flag to enable approximation of the functional value on a fine grid before refinement run...
void exec_gnuplot()
Executes the gnuplot file.
Performs grid convergence for various polynomial degrees.
GridRefinementStudy()=delete
Constructor. Deleted the default constructor since it should not be used.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
std::string input_grid
Input pathway for GridEnum::read_grid type.
static std::shared_ptr< DGBase< dim, real, MeshType > > create_discontinuous_galerkin(const Parameters::AllParameters *const parameters_input, const unsigned int degree, const unsigned int max_degree_input, const unsigned int grid_degree_input, const std::shared_ptr< Triangulation > triangulation_input)
Creates a derived object DG, but returns it as DGBase.
bool output_solution_error
Flag to enable output of grid refinement solution error convergence.
bool output_gnuplot_solution
Flag to enable output of gnuplot graph of solution error convergence.
bool output_vtk
Flag to enable output of grid refinement .vtk file.
FunctionalParam functional_param
Functional parameters to be used with grid refinement study.
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.
unsigned int refinement_steps
Number of refinement steps to be performed.
void write_gnuplot()
Main write function call.
bool exit_after_refine
Flag to exit after call to refinement.
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.
Parameters related to individual grid refinement run.
void set_grid(const bool grid_bool_input)
Set flag for enabling background grid.
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.
Parameters related to collection of grid refinement runs.
double functional_value
Specified exact functional value for comparison of error convergence.
static std::shared_ptr< GridRefinementBase< dim, nstate, real, MeshType > > create_GridRefinement(PHiLiP::Parameters::GridRefinementParam gr_param, std::shared_ptr< PHiLiP::Adjoint< dim, nstate, real, MeshType > > adj, std::shared_ptr< PHiLiP::Physics::PhysicsBase< dim, nstate, real > > physics_input)
Construct grid refinement class based on adjoint and physics.
void set_x_scale_log(const bool xlog_bool_input)
Set flag for logarithmic x-axis.
int run_test() const
Basically the main and only function of this class.
dealii::ConditionalOStream pcout
ConditionalOStream.
bool output_functional_error
Flag to enable output of grid refinement functional error convergence.
unsigned int grid_size
Number of initial elements in each axis for GridEnum::hypercube type.
void set_title(const std::string &title_input)
Sets the figure title.
double grid_left
Lower coordinate bound for GridEnum::hypercube type.
bool output_adjoint_time
Flag to enable output of grid refinement wall-clock adjoint time.
static std::shared_ptr< ODESolverBase< dim, real, MeshType > > create_ODESolver(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input)
Creates either implicit or explicit ODE solver based on parameter value(no POD basis given) ...
unsigned int poly_degree
Initial solution polynomial degree.
double grid_right
Upper coordinate bound for GridEnum::hypercube type.
Base class of all the tests.
GridEnum
Types of grids that can be used for convergence study.
void get_grid(const std::shared_ptr< MeshType > &grid, const Parameters::GridRefinementStudyParam &grs_param) const
gets the grid from the enum and reads file if neccesary
bool output_adjoint_vtk
Flag to enable output of adjoint .vtk file.