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);
    }
}
예제 #2
0
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
}