Example #1
0
int main(int argc, char* argv[])
{
  // Load the mesh.
  Mesh mesh;
  H2DReader mloader;
  mloader.load("square_quad.mesh", &mesh);

  // Perform initial mesh refinement.
  for (int i=0; i<INIT_REF_NUM; i++) mesh.refine_all_elements();
  mesh.refine_towards_boundary(BOUNDARY_LAYER, INIT_BDY_REF_NUM);
  //mesh.refine_towards_boundary(NONZERO_DIRICHLET, INIT_BDY_REF_NUM/2);

  // Create a space and refinement selector appropriate for the selected discretization method.
  Space *space;
  ProjBasedSelector *selector;
  ProjNormType norm;
  if (method != DG)
  {
    space = new H1Space(&mesh, bc_types, essential_bc_values, P_INIT);
    selector = new L2ProjBasedSelector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);
    norm = HERMES_L2_NORM;  // WARNING: In order to compare the errors with DG, L2 norm should be here.
  }
  else
  {
    space = new L2Space(&mesh, bc_types, NULL, Ord2(P_INIT));
    selector = new L2ProjBasedSelector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);
    norm = HERMES_L2_NORM;
    // Disable weighting of refinement candidates.
    selector->set_error_weights(1, 1, 1);
  }

  // Initialize the weak formulation.
  info("Discretization method: %s", method_names[method].c_str());
    
  if (method != CG && method != DG)
  {
    if (STRATEGY > -1 && CAND_LIST != H2D_H_ISO && CAND_LIST != H2D_H_ANISO)
      error("The %s method may be used only with h-refinement.", method_names[method].c_str());
  
    int eff_order = (STRATEGY == -1) ? P_INIT : P_INIT + ORDER_INCREASE;
    
    if (method != CG_STAB_GLS)
    {
      if (eff_order > 1)
        error("The %s method may be used only with at most 1st order elements.", method_names[method].c_str());
    }
    else
    {
      if (eff_order > 2)
        error("The %s method may be used only with at most 2nd order elements.", method_names[method].c_str());
    }
  }
  
  WeakForm wf;
  switch(method)
  {
    case CG:
      wf.add_matrix_form(callback(cg_biform));
      break;
    case CG_STAB_SUPG:
      wf.add_matrix_form(callback(cg_biform));
      wf.add_matrix_form(callback(stabilization_biform_supg));
      break; 
    case CG_STAB_GLS:
      wf.add_matrix_form(callback(cg_biform));
      wf.add_matrix_form(callback(stabilization_biform_gls));
      break;
    case CG_STAB_SGS:
      wf.add_matrix_form(callback(cg_biform));
      wf.add_matrix_form(callback(stabilization_biform_sgs));
      break;
    case CG_STAB_SGS_ALT:
      wf.add_matrix_form(callback(cg_biform));
      wf.add_matrix_form(callback(stabilization_biform_sgs_alt));
      break;
    case DG:
      wf.add_matrix_form(callback(dg_volumetric_biform_advection));
      wf.add_matrix_form(callback(dg_volumetric_biform_diffusion));
      wf.add_matrix_form_surf(callback(dg_interface_biform_advection), H2D_DG_INNER_EDGE);
      wf.add_matrix_form_surf(callback(dg_interface_biform_diffusion), H2D_DG_INNER_EDGE);
      wf.add_matrix_form_surf(callback(dg_boundary_biform_advection));
      wf.add_matrix_form_surf(callback(dg_boundary_biform_diffusion));
      wf.add_vector_form_surf(callback(dg_boundary_liform_advection));
      wf.add_vector_form_surf(callback(dg_boundary_liform_diffusion));
      break;
  }
  
  // Initialize coarse and reference mesh solution.
  Solution sln, ref_sln;
  
  // Set exact solution.
  ExactSolution exact(&mesh, exact_sln);
  
  // Initialize views.
  ScalarView sview("Solution", new WinGeom(0, 0, 440, 350));
  sview.fix_scale_width(50);
  sview.show_mesh(false);
  OrderView  oview("Polynomial orders", new WinGeom(450, 0, 400, 350));
  
  // DOF and CPU convergence graphs initialization.
  SimpleGraph graph_dof, graph_cpu, graph_dof_exact, graph_cpu_exact;
  
  // Time measurement.
  TimePeriod cpu_time;
  cpu_time.tick();

  // Set up the solver, matrix, and rhs according to the solver selection.
  SparseMatrix* matrix = create_matrix(matrix_solver);
  Vector* rhs = create_vector(matrix_solver);
  Solver* solver = create_linear_solver(matrix_solver, matrix, rhs);
  
  // Adaptivity loop:
  int as = 1; 
  bool done = false;
  Space* actual_sln_space;
  do
  {
    info("---- Adaptivity step %d:", as);

    if (STRATEGY == -1)
      actual_sln_space = space;
    else
      // Construct globally refined reference mesh and setup reference space.
      actual_sln_space = Space::construct_refined_space(space, ORDER_INCREASE);

    // Assemble the reference problem.
    info("Solving on reference mesh.");
    bool is_linear = true;
    DiscreteProblem* dp = new DiscreteProblem(&wf, actual_sln_space, is_linear);
    dp->assemble(matrix, rhs);
    
    // Solve the linear system of the reference problem. 
    // If successful, obtain the solution.
    if(solver->solve()) Solution::vector_to_solution(solver->get_solution(), actual_sln_space, &ref_sln);
    else error ("Matrix solver failed.\n");
    
    // Instantiate adaptivity and error calculation driver. Space is used only for adaptivity, it is ignored when 
    // STRATEGY == -1 and only the exact error is calculated by this object.
    Adapt* adaptivity = new Adapt(space, norm);
    
    // Calculate exact error.
    bool solutions_for_adapt = false;
    double err_exact_rel = calc_rel_error(&sln, &exact, HERMES_H1_NORM) * 100;
    info("ndof_fine: %d, err_exact_rel: %g%%", Space::get_num_dofs(actual_sln_space), err_exact_rel);

    // Time measurement.
    cpu_time.tick();
    
    // View the fine mesh solution and polynomial orders.
    sview.show(&ref_sln);
    oview.show(actual_sln_space);
    
    // Skip visualization time.
    cpu_time.tick(HERMES_SKIP);

    if (STRATEGY == -1) done = true;  // Do not adapt.
    else
    {  
      // Project the fine mesh solution onto the coarse mesh.
      info("Projecting reference solution on coarse mesh.");
      OGProjection::project_global(space, &ref_sln, &sln, matrix_solver, norm); 

      // Calculate element errors and total error estimate.
      info("Calculating error estimate."); 
      bool solutions_for_adapt = true;
      double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln, solutions_for_adapt, HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL) * 100;

      // Report results.
      info("ndof_coarse: %d, err_est_rel: %g%%", Space::get_num_dofs(space), err_est_rel);

      // Time measurement.
      cpu_time.tick();
      
      // Add entry to DOF and CPU convergence graphs.
      graph_dof.add_values(Space::get_num_dofs(space), err_est_rel);
      graph_dof.save("conv_dof_est.dat");
      graph_cpu.add_values(cpu_time.accumulated(), err_est_rel);
      graph_cpu.save("conv_cpu_est.dat");
      graph_dof_exact.add_values(Space::get_num_dofs(space), err_exact_rel);
      graph_dof_exact.save("conv_dof_exact.dat");
      graph_cpu_exact.add_values(cpu_time.accumulated(), err_exact_rel);
      graph_cpu_exact.save("conv_cpu_exact.dat");

      // Skip graphing time.
      cpu_time.tick(HERMES_SKIP);
      
      // If err_est too large, adapt the mesh.
      if (err_exact_rel < ERR_STOP) done = true;
      else 
      {
        info("Adapting coarse mesh.");
        done = adaptivity->adapt(selector, THRESHOLD, STRATEGY, MESH_REGULARITY);
  
        // Increase the counter of performed adaptivity steps.
        if (done == false)  as++;
      }
      if (Space::get_num_dofs(space) >= NDOF_STOP) done = true;
      
      if(done == false) 
      {
        delete actual_sln_space->get_mesh();
        delete actual_sln_space;
      }
    }
    
    // Clean up.
    delete adaptivity;
    delete dp;
  }
  while (done == false);
  
  if (space != actual_sln_space) 
  {
    delete space;
    delete actual_sln_space->get_mesh();
  }
  delete actual_sln_space;
  delete solver;
  delete matrix;
  delete rhs;
  delete selector;
  
  verbose("Total running time: %g s", cpu_time.accumulated());
  
  // Wait for all views to be closed.
  View::wait();
  
  return 0;
}
Example #2
0
int main(int argc, char* argv[])
{ 
  GalerkinMethod method;
  CandList CAND_LIST;
  int P_INIT;                             
  int ORDER_INCREASE;
  int n_dof_allowed;
  int iter_allowed;
  
  std::string arg = (argc == 1) ? "CG" : argv[1];
  
  if (arg == "CG")
  {
    method = CG;
    CAND_LIST = H2D_HP_ANISO;
    P_INIT = 1;
    ORDER_INCREASE = 1;
    n_dof_allowed = 7;
    iter_allowed = 3;
  }
  else if (arg == "SUPG")
  {
    method = CG_STAB_SUPG;
    CAND_LIST = H2D_H_ANISO;
    P_INIT = 1;
    ORDER_INCREASE = 0;
    n_dof_allowed = 190;
    iter_allowed = 11;
  }
  else if (arg == "GLS_1")
  {
    method = CG_STAB_GLS_1;
    CAND_LIST = H2D_H_ANISO;
    P_INIT = 1;
    ORDER_INCREASE = 0;
    n_dof_allowed = 195;
    iter_allowed = 12;
  }
  else if (arg == "GLS_2")
  {
    method = CG_STAB_GLS_2;
    CAND_LIST = H2D_H_ANISO;
    P_INIT = 2;
    ORDER_INCREASE = 0;
    n_dof_allowed = 80;
    iter_allowed = 4;
  }
  else if (arg == "SGS")
  {
    method = CG_STAB_SGS;
    CAND_LIST = H2D_H_ANISO;
    P_INIT = 1;
    ORDER_INCREASE = 0;
    n_dof_allowed = 430;
    iter_allowed = 14;
  }
  else if (arg == "SGS_ALT")
  {
    method = CG_STAB_SGS_ALT;
    CAND_LIST = H2D_H_ANISO;
    P_INIT = 1;
    ORDER_INCREASE = 0;
    n_dof_allowed = 190;
    iter_allowed = 11;
  }
  else if (arg == "DG")
  {
    method = DG;
    CAND_LIST = H2D_HP_ANISO;
    P_INIT = 0;
    ORDER_INCREASE = 1;
    n_dof_allowed = 0;//TODO
    iter_allowed = 0;//TODO
    error("DG option not yet supported.");
  }
  else
  {
    error("Invalid discretization method.");
  }
  
  // Instantiate a class with global functions.
  Hermes2D hermes2d;
  
  info("Discretization method: %s", method_names[method].c_str());
  
  // Load the mesh.
  Mesh mesh;
  H2DReader mloader;
  mloader.load("../square_quad.mesh", &mesh);

  // Perform initial mesh refinement.
  for (int i=0; i<INIT_REF_NUM; i++) mesh.refine_all_elements();
  mesh.refine_towards_boundary("outflow", INIT_BDY_REF_NUM);
  //mesh.refine_towards_boundary(NONZERO_DIRICHLET, INIT_BDY_REF_NUM/2);

  // Create a space and refinement selector appropriate for the selected discretization method.
  Space *space;
  ProjBasedSelector *selector;
  ProjNormType norm;
  
  WeaklyImposableBC bc_fn(Hermes::vector<std::string>("nonzero_Dirichlet"), new NonzeroBoundaryValues(&mesh));
  WeaklyImposableBC bc_zero(Hermes::vector<std::string>("zero_Dirichlet", "outflow"), 0.0);
  EssentialBCs bcs(Hermes::vector<EssentialBoundaryCondition*>(&bc_fn, &bc_zero));
  
  // Initialize the weak formulation.
  WeakForm *wf;
  
  if (method != DG)
  {    
    space = new H1Space(&mesh, &bcs, P_INIT);
    selector = new L2ProjBasedSelector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);
    norm = HERMES_L2_NORM;  // WARNING: In order to compare the errors with DG, L2 norm should be here.
    
    wf = new CustomWeakFormContinuousGalerkin(method, EPSILON);
  }
  else
  {
    space = new L2Space(&mesh, P_INIT);
    selector = new L2ProjBasedSelector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER);
    norm = HERMES_L2_NORM;
    // Disable weighting of refinement candidates.
    selector->set_error_weights(1, 1, 1);
    
    wf = new CustomWeakFormDiscontinuousGalerkin(bcs, EPSILON);
  }
  
  // Initialize coarse and reference mesh solution.
  Solution sln, ref_sln;
  
  // Set exact solution.
  CustomExactSolution exact(&mesh, EPSILON);
  
  // DOF and CPU convergence graphs initialization.
  SimpleGraph graph_dof, graph_cpu, graph_dof_exact, graph_cpu_exact;
  
  // Time measurement.
  TimePeriod cpu_time;
  cpu_time.tick();

  // Setup data structures for solving the discrete algebraic problem.
  SparseMatrix* matrix = create_matrix(matrix_solver);
  Vector* rhs = create_vector(matrix_solver);
  Solver* solver = create_linear_solver(matrix_solver, matrix, rhs);
  
  // Adaptivity loop:
  int as = 1; 
  bool done = false;
  Space* actual_sln_space;
  do
  {
    info("---- Adaptivity step %d:", as);

    if (STRATEGY == -1)
      actual_sln_space = space;
    else
      // Construct globally refined reference mesh and setup reference space.
      actual_sln_space = Space::construct_refined_space(space, ORDER_INCREASE);

    int ndof_fine = Space::get_num_dofs(actual_sln_space);
    int ndof_coarse = Space::get_num_dofs(space);
    
    // Solve the linear system. If successful, obtain the solution.
    info("Solving on the refined mesh (%d NDOF).", ndof_fine);
    
    DiscreteProblem dp(wf, actual_sln_space);
    
    // Initial coefficient vector for the Newton's method.  
    scalar* coeff_vec = new scalar[ndof_fine];
    memset(coeff_vec, 0, ndof_fine * sizeof(scalar));
    
    // Perform Newton's iteration.
    if (!hermes2d.solve_newton(coeff_vec, &dp, solver, matrix, rhs)) 
      error("Newton's iteration failed.");
    Solution::vector_to_solution(solver->get_solution(), actual_sln_space, &ref_sln);
    
    // Calculate exact error.
    double err_exact_rel = hermes2d.calc_rel_error(&ref_sln, &exact, norm) * 100;
    info("ndof_fine: %d, err_exact_rel: %g%%", ndof_fine, err_exact_rel);

    if (STRATEGY == -1) done = true;  // Do not adapt.
    else
    {  
      Adapt* adaptivity = new Adapt(space, norm);
      
      // Project the fine mesh solution onto the coarse mesh.
      info("Projecting reference solution on coarse mesh.");
      OGProjection::project_global(space, &ref_sln, &sln, matrix_solver, norm); 

      // Calculate element errors and total error estimate.
      info("Calculating error estimate."); 
      bool solutions_for_adapt = true;
      double err_est_rel = adaptivity->calc_err_est(&sln, &ref_sln, solutions_for_adapt) * 100;

      // Report results.
      info("ndof_coarse: %d, err_est_rel: %g%%", ndof_coarse, err_est_rel);

      // Time measurement.
      cpu_time.tick();
      
      // Add entry to DOF and CPU convergence graphs.
      graph_dof.add_values(ndof_coarse, err_est_rel);
      graph_dof.save("conv_dof_est.dat");
      graph_cpu.add_values(cpu_time.accumulated(), err_est_rel);
      graph_cpu.save("conv_cpu_est.dat");
      graph_dof_exact.add_values(ndof_coarse, err_exact_rel);
      graph_dof_exact.save("conv_dof_exact.dat");
      graph_cpu_exact.add_values(cpu_time.accumulated(), err_exact_rel);
      graph_cpu_exact.save("conv_cpu_exact.dat");

      // Skip graphing time.
      cpu_time.tick(HERMES_SKIP);
      
      // If err_est too large, adapt the mesh.
      if (err_exact_rel < ERR_STOP) done = true;
      else 
      {
        info("Adapting coarse mesh.");
        done = adaptivity->adapt(selector, THRESHOLD, STRATEGY, MESH_REGULARITY);
  
        // Increase the counter of performed adaptivity steps.
        if (done == false)  as++;
      }
      if (Space::get_num_dofs(space) >= NDOF_STOP) done = true;
      
      // Clean up.
      if(done == false) 
      {
        delete actual_sln_space->get_mesh();
        delete actual_sln_space;
      }
       
      delete adaptivity;
    }
  }
  while (done == false);
  
  int ndof = Space::get_num_dofs(space);

  if (space != actual_sln_space) 
  {
    delete space;
    delete actual_sln_space->get_mesh();
  }
  delete actual_sln_space;
  delete solver;
  delete matrix;
  delete rhs;
  delete selector;
  
  verbose("Total running time: %g s", cpu_time.accumulated());

  // Test number of DOF.
  printf("n_dof_actual = %d\n", ndof);
  printf("n_dof_allowed = %d\n", n_dof_allowed);
  if (ndof <= n_dof_allowed) {
    printf("Success!\n");
    return ERR_SUCCESS;
  }
  else {
    printf("Failure!\n");
    return ERR_FAILURE;
  }
  
  // Test number of iterations.
  printf("iterations = %d\n", as);
  printf("iterations allowed = %d\n", iter_allowed);
  if (as <= iter_allowed) {
    printf("Success!\n");
    return ERR_SUCCESS;
  }
  else {
    printf("Failure!\n");
    return ERR_FAILURE;
  }
}