void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector & error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Get the mean value from the error vector const Real mean = error_per_cell.mean(); // Get the standard deviation. This equals the // square-root of the variance const Real stddev = std::sqrt (error_per_cell.variance()); // Check for valid fractions libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // The refine and coarsen cutoff const Real refine_cutoff = mean + _refine_fraction * stddev; const Real coarsen_cutoff = std::max(mean - _coarsen_fraction * stddev, 0.); // Loop over the elements and flag them for coarsening or // refinement based on the element error for (auto & elem : _mesh.active_element_ptr_range()) { const dof_id_type id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const ErrorVectorReal elem_error = error_per_cell[id]; // Possibly flag the element for coarsening ... if (elem_error <= coarsen_cutoff) elem->set_refinement_flag(Elem::COARSEN); // ... or refinement if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level)) elem->set_refinement_flag(Elem::REFINE); } }
int main(int argc, char** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); // Adaptive constraint calculations for fine Hermite elements seems // to require half-decent precision #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION libmesh_example_assert(false, "double precision"); #endif // This example requires Adaptive Mesh Refinement support #ifndef LIBMESH_ENABLE_AMR libmesh_example_assert(false, "--enable-amr"); #else // This example requires second derivative calculation support #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES libmesh_example_assert(false, "--enable-second"); #else // Parse the input file GetPot input_file("adaptivity_ex4.in"); // Read in parameters from the input file const unsigned int max_r_level = input_file("max_r_level", 10); const unsigned int max_r_steps = input_file("max_r_steps", 4); const std::string approx_type = input_file("approx_type", "HERMITE"); const unsigned int uniform_refine = input_file("uniform_refine", 0); const Real refine_percentage = input_file("refine_percentage", 0.5); const Real coarsen_percentage = input_file("coarsen_percentage", 0.5); const unsigned int dim = input_file("dimension", 2); const unsigned int max_linear_iterations = input_file("max_linear_iterations", 10000); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_assert(dim <= LIBMESH_DIM, "2D/3D support"); // We have only defined 2 and 3 dimensional problems libmesh_assert (dim == 2 || dim == 3); // Currently only the Hermite cubics give a 3D C^1 basis libmesh_assert (dim == 2 || approx_type == "HERMITE"); // Create a mesh. Mesh mesh; // Output file for plotting the error std::string output_file = ""; if (dim == 2) output_file += "2D_"; else if (dim == 3) output_file += "3D_"; if (approx_type == "HERMITE") output_file += "hermite_"; else if (approx_type == "SECOND") output_file += "reducedclough_"; else output_file += "clough_"; if (uniform_refine == 0) output_file += "adaptive"; else output_file += "uniform"; std::string exd_file = output_file; exd_file += ".e"; output_file += ".m"; std::ofstream out (output_file.c_str()); out << "% dofs L2-error H1-error H2-error\n" << "e = [\n"; // Set up the dimension-dependent coarse mesh and solution // We build more than one cell so as to avoid bugs on fewer than // 4 processors in 2D or 8 in 3D. if (dim == 2) { MeshTools::Generation::build_square(mesh, 2, 2); exact_solution = &exact_2D_solution; exact_derivative = &exact_2D_derivative; exact_hessian = &exact_2D_hessian; forcing_function = &forcing_function_2D; } else if (dim == 3) { MeshTools::Generation::build_cube(mesh, 2, 2, 2); exact_solution = &exact_3D_solution; exact_derivative = &exact_3D_derivative; exact_hessian = &exact_3D_hessian; forcing_function = &forcing_function_3D; } // Convert the mesh to second order: necessary for computing with // Clough-Tocher elements, useful for getting slightly less // broken visualization output with Hermite elements mesh.all_second_order(); // Convert it to triangles if necessary if (approx_type != "HERMITE") MeshTools::Modification::all_tri(mesh); // Mesh Refinement object MeshRefinement mesh_refinement(mesh); mesh_refinement.refine_fraction() = refine_percentage; mesh_refinement.coarsen_fraction() = coarsen_percentage; mesh_refinement.max_h_level() = max_r_level; // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Biharmonic" LinearImplicitSystem& system = equation_systems.add_system<LinearImplicitSystem> ("Biharmonic"); // Adds the variable "u" to "Biharmonic". "u" // will be approximated using Hermite tensor product squares // or (possibly reduced) cubic Clough-Tocher triangles if (approx_type == "HERMITE") system.add_variable("u", THIRD, HERMITE); else if (approx_type == "SECOND") system.add_variable("u", SECOND, CLOUGH); else if (approx_type == "CLOUGH") system.add_variable("u", THIRD, CLOUGH); else libmesh_error(); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_biharmonic); // Initialize the data structures for the equation system. equation_systems.init(); // Set linear solver max iterations equation_systems.parameters.set<unsigned int> ("linear solver maximum iterations") = max_linear_iterations; // Linear solver tolerance. equation_systems.parameters.set<Real> ("linear solver tolerance") = TOLERANCE * TOLERANCE; // Prints information about the system to the screen. equation_systems.print_info(); // Construct ExactSolution object and attach function to compute exact solution ExactSolution exact_sol(equation_systems); exact_sol.attach_exact_value(exact_solution); exact_sol.attach_exact_deriv(exact_derivative); exact_sol.attach_exact_hessian(exact_hessian); // Construct zero solution object, useful for computing solution norms // Attaching "zero_solution" functions is unnecessary ExactSolution zero_sol(equation_systems); // A refinement loop. for (unsigned int r_step=0; r_step<max_r_steps; r_step++) { mesh.print_info(); equation_systems.print_info(); std::cout << "Beginning Solve " << r_step << std::endl; // Solve the system "Biharmonic", just like example 2. system.solve(); std::cout << "Linear solver converged at step: " << system.n_linear_iterations() << ", final residual: " << system.final_linear_residual() << std::endl; // Compute the error. exact_sol.compute_error("Biharmonic", "u"); // Compute the norm. zero_sol.compute_error("Biharmonic", "u"); // Print out the error values std::cout << "L2-Norm is: " << zero_sol.l2_error("Biharmonic", "u") << std::endl; std::cout << "H1-Norm is: " << zero_sol.h1_error("Biharmonic", "u") << std::endl; std::cout << "H2-Norm is: " << zero_sol.h2_error("Biharmonic", "u") << std::endl << std::endl; std::cout << "L2-Error is: " << exact_sol.l2_error("Biharmonic", "u") << std::endl; std::cout << "H1-Error is: " << exact_sol.h1_error("Biharmonic", "u") << std::endl; std::cout << "H2-Error is: " << exact_sol.h2_error("Biharmonic", "u") << std::endl << std::endl; // Print to output file out << equation_systems.n_active_dofs() << " " << exact_sol.l2_error("Biharmonic", "u") << " " << exact_sol.h1_error("Biharmonic", "u") << " " << exact_sol.h2_error("Biharmonic", "u") << std::endl; // Possibly refine the mesh if (r_step+1 != max_r_steps) { std::cout << " Refining the mesh..." << std::endl; if (uniform_refine == 0) { ErrorVector error; LaplacianErrorEstimator error_estimator; error_estimator.estimate_error(system, error); mesh_refinement.flag_elements_by_elem_fraction (error); std::cout << "Mean Error: " << error.mean() << std::endl; std::cout << "Error Variance: " << error.variance() << std::endl; mesh_refinement.refine_and_coarsen_elements(); } else { mesh_refinement.uniformly_refine(1); } // This call reinitializes the \p EquationSystems object for // the newly refined mesh. One of the steps in the // reinitialization is projecting the \p solution, // \p old_solution, etc... vectors from the old mesh to // the current one. equation_systems.reinit (); } } #ifdef LIBMESH_HAVE_EXODUS_API // Write out the solution // After solving the system write the solution // to a ExodusII-formatted plot file. ExodusII_IO (mesh).write_equation_systems (exd_file, equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API // Close up the output file. out << "];\n" << "hold on\n" << "loglog(e(:,1), e(:,2), 'bo-');\n" << "loglog(e(:,1), e(:,3), 'ro-');\n" << "loglog(e(:,1), e(:,4), 'go-');\n" << "xlabel('log(dofs)');\n" << "ylabel('log(error)');\n" << "title('C1 " << approx_type << " elements');\n" << "legend('L2-error', 'H1-error', 'H2-error');\n"; // All done. return 0; #endif // #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES #endif // #ifndef LIBMESH_ENABLE_AMR }