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; }
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; } }