int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable* bt = new ButcherTable(butcher_table_type); if (bt->is_explicit()) info("Using a %d-stage explicit R-K method.", bt->get_size()); if (bt->is_diagonally_implicit()) info("Using a %d-stage diagonally implicit R-K method.", bt->get_size()); if (bt->is_fully_implicit()) info("Using a %d-stage fully implicit R-K method.", bt->get_size()); // Turn off adaptive time stepping if R-K method is not embedded. if (bt->is_embedded() == false && ADAPTIVE_TIME_STEP_ON == true) { warn("R-K method not embedded, turning off adaptive time stepping."); ADAPTIVE_TIME_STEP_ON = false; } // Load the mesh. Mesh mesh, basemesh; H2DReader mloader; mloader.load("square.mesh", &basemesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) basemesh.refine_all_elements(); mesh.copy(&basemesh); // Enter boundary markers. BCTypes bc_types; bc_types.add_bc_dirichlet(BDY_DIRICHLET); // Enter Dirichlet boundary values. BCValues bc_values; bc_values.add_function(BDY_DIRICHLET, essential_bc_values); // Create an H1 space with default shapeset. H1Space space(&mesh, &bc_types, &bc_values, P_INIT); int ndof = Space::get_num_dofs(&space); // Convert initial condition into a Solution. Solution* sln_prev_time = new Solution(&mesh, init_cond); // Initialize the weak formulation. WeakForm wf; wf.add_matrix_form(callback(stac_jacobian), HERMES_NONSYM, HERMES_ANY, sln_prev_time); wf.add_vector_form(callback(stac_residual), HERMES_ANY, sln_prev_time); // Initialize the discrete problem. bool is_linear = false; DiscreteProblem dp_coarse(&wf, &space, is_linear); // Create a refinement selector. H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Graph for time step history. SimpleGraph time_step_graph; if (ADAPTIVE_TIME_STEP_ON) info("Time step history will be saved to file time_step_history.dat."); // Time stepping loop. double current_time = time_step; int ts = 1; do { info("Begin time step %d.", ts); // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { info("Global mesh derefinement."); if (UNREF_LEVEL == 1) mesh.unrefine_all_elements(); else mesh.copy(&basemesh); space.set_uniform_order(P_INIT); ndof = Space::get_num_dofs(&space); } // Spatial adaptivity loop. Note: sln_prev_time must not be // changed during spatial adaptivity. Solution ref_sln; Solution* time_error_fn; if (bt->is_embedded() == true) time_error_fn = new Solution(&mesh); else time_error_fn = NULL; bool done = false; int as = 1; double err_est; do { // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(&space); // Initialize discrete problem on reference mesh. DiscreteProblem* ref_dp = new DiscreteProblem(&wf, ref_space); // Runge-Kutta step on the fine mesh. info("Runge-Kutta time step on fine mesh (t = %g s, tau = %g s, stages: %d).", current_time, time_step, bt->get_size()); bool verbose = true; bool is_linear = false; if (!rk_time_step(current_time, time_step, bt, sln_prev_time, &ref_sln, time_error_fn, ref_dp, matrix_solver, verbose, is_linear, NEWTON_TOL_FINE, NEWTON_MAX_ITER)) { error("Runge-Kutta time step failed, try to decrease time step size."); } /* If ADAPTIVE_TIME_STEP_ON == true, estimate temporal error. If too large or too small, then adjust it and restart the time step. */ double rel_err_time; if (bt->is_embedded() == true) { info("Calculating temporal error estimate."); rel_err_time = calc_norm(time_error_fn, HERMES_H1_NORM) / calc_norm(&ref_sln, HERMES_H1_NORM) * 100; if (ADAPTIVE_TIME_STEP_ON == false) info("rel_err_time: %g%%", rel_err_time); } if (ADAPTIVE_TIME_STEP_ON) { if (rel_err_time > TIME_ERR_TOL_UPPER) { info("rel_err_time %g%% is above upper limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); info("Decreasing tau from %g to %g s and restarting time step.", time_step, time_step * TIME_STEP_DEC_RATIO); time_step *= TIME_STEP_DEC_RATIO; delete ref_space; delete ref_dp; continue; } else if (rel_err_time < TIME_ERR_TOL_LOWER) { info("rel_err_time = %g%% is below lower limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); info("Increasing tau from %g to %g s and restarting time step.", time_step, time_step * TIME_STEP_INC_RATIO); time_step *= TIME_STEP_INC_RATIO; delete ref_space; delete ref_dp; continue; } else { info("rel_err_time = %g%% is in acceptable interval (%g%%, %g%%)", rel_err_time, TIME_ERR_TOL_LOWER, TIME_ERR_TOL_UPPER); } // Add entry to time step history graph. time_step_graph.add_values(current_time, time_step); time_step_graph.save("time_step_history.dat"); } /* Estimate spatial errors and perform mesh refinement */ info("Spatial adaptivity step %d.", as); // Project the fine mesh solution onto the coarse mesh. Solution sln; info("Projecting fine mesh solution on coarse mesh for error estimation."); OGProjection::project_global(&space, &ref_sln, &sln, matrix_solver); // Calculate element errors and spatial error estimate. info("Calculating spatial error estimate."); Adapt* adaptivity = new Adapt(&space); double err_rel_space = adaptivity->calc_err_est(&sln, &ref_sln) * 100; // Report results. info("ndof: %d, ref_ndof: %d, err_rel_space: %g%%", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space), err_rel_space); // If err_est too large, adapt the mesh. if (err_rel_space < SPACE_ERR_TOL) done = true; else { info("Adapting the coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Clean up. delete adaptivity; delete ref_space; delete ref_dp; } while (done == false); // Clean up. if (time_error_fn != NULL) delete time_error_fn; // Copy last reference solution into sln_prev_time. sln_prev_time->copy(&ref_sln); // Increase current time and counter of time steps. current_time += time_step; ts++; } while (current_time < T_FINAL); // Clean up. delete sln_prev_time; delete bt; ndof = Space::get_num_dofs(&space); printf("ndof allowed = %d\n", 130); printf("ndof actual = %d\n", ndof); if (ndof < 130) { // ndofs was 121 at the time this test was created. printf("Success!\n"); return ERR_SUCCESS; } else { printf("Failure!\n"); return ERR_FAILURE; } }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable* bt = new ButcherTable(butcher_table_type); if (bt->is_explicit()) info("Using a %d-stage explicit R-K method.", bt->get_size()); if (bt->is_diagonally_implicit()) info("Using a %d-stage diagonally implicit R-K method.", bt->get_size()); if (bt->is_fully_implicit()) info("Using a %d-stage fully implicit R-K method.", bt->get_size()); // Turn off adaptive time stepping if R-K method is not embedded. if (bt->is_embedded() == false && ADAPTIVE_TIME_STEP_ON == true) { warn("R-K method not embedded, turning off adaptive time stepping."); ADAPTIVE_TIME_STEP_ON = false; } // Load the mesh. Mesh mesh, basemesh; H2DReader mloader; mloader.load("wall.mesh", &basemesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) basemesh.refine_all_elements(); basemesh.refine_towards_boundary(BDY_BOTTOM, INIT_REF_NUM_BDY); mesh.copy(&basemesh); // Enter boundary markers. BCTypes bc_types; bc_types.add_bc_neumann(Hermes::vector<int>(BDY_RIGHT, BDY_LEFT)); bc_types.add_bc_newton(Hermes::vector<int>(BDY_BOTTOM, BDY_TOP)); // Initialize an H1 space with default shapeset. H1Space space(&mesh, &bc_types, NULL, P_INIT); int ndof = Space::get_num_dofs(&space); info("ndof = %d.", ndof); // Convert initial condition into a Solution. Solution* sln_prev_time = new Solution(&mesh, TEMP_INIT); // Initialize weak formulation. WeakForm wf; wf.add_matrix_form(stac_jacobian_vol, stac_jacobian_vol_ord, HERMES_NONSYM, HERMES_ANY, sln_prev_time); wf.add_vector_form(stac_residual_vol, stac_residual_vol_ord, HERMES_ANY, sln_prev_time); wf.add_matrix_form_surf(stac_jacobian_bottom, stac_jacobian_bottom_ord, BDY_BOTTOM, sln_prev_time); wf.add_vector_form_surf(stac_residual_bottom, stac_residual_bottom_ord, BDY_BOTTOM, sln_prev_time); wf.add_matrix_form_surf(stac_jacobian_top, stac_jacobian_top_ord, BDY_TOP, sln_prev_time); wf.add_vector_form_surf(stac_residual_top, stac_residual_top_ord, BDY_TOP, sln_prev_time); // Initialize the FE problem. bool is_linear = true; DiscreteProblem dp(&wf, &space, is_linear); // Create a refinement selector. H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Visualize initial condition. char title[100]; ScalarView sln_view("Initial condition", new WinGeom(0, 0, 1500, 360)); OrderView ordview("Initial mesh", new WinGeom(0, 410, 1500, 360)); ScalarView time_error_view("Temporal error", new WinGeom(0, 800, 1500, 360)); time_error_view.fix_scale_width(40); ScalarView space_error_view("Spatial error", new WinGeom(0, 1220, 1500, 360)); space_error_view.fix_scale_width(40); sln_view.show(sln_prev_time, HERMES_EPS_VERYHIGH); ordview.show(&space); // Graph for time step history. SimpleGraph time_step_graph; if (ADAPTIVE_TIME_STEP_ON) info("Time step history will be saved to file time_step_history.dat."); // Time stepping loop: double current_time = 0; int ts = 1; do { info("Begin time step %d.", ts); // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { info("Global mesh derefinement."); if (UNREF_LEVEL == 1) mesh.unrefine_all_elements(); else mesh.copy(&basemesh); space.set_uniform_order(P_INIT); ndof = Space::get_num_dofs(&space); } // Spatial adaptivity loop. Note: sln_prev_time must not be // changed during spatial adaptivity. Solution ref_sln; Solution* time_error_fn; if (bt->is_embedded() == true) time_error_fn = new Solution(&mesh); else time_error_fn = NULL; bool done = false; int as = 1; double err_est; do { // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(&space); // Initialize discrete problem on reference mesh. DiscreteProblem* ref_dp = new DiscreteProblem(&wf, ref_space); // Runge-Kutta step on the fine mesh. info("Runge-Kutta time step on fine mesh (t = %g s, tau = %g s, stages: %d).", current_time, time_step, bt->get_size()); bool verbose = true; bool is_linear = false; if (!rk_time_step(current_time, time_step, bt, sln_prev_time, &ref_sln, time_error_fn, ref_dp, matrix_solver, verbose, is_linear, NEWTON_TOL_FINE, NEWTON_MAX_ITER)) { error("Runge-Kutta time step failed, try to decrease time step size."); } /* If ADAPTIVE_TIME_STEP_ON == true, estimate temporal error. If too large or too small, then adjust it and restart the time step. */ double rel_err_time; if (bt->is_embedded() == true) { info("Calculating temporal error estimate."); // Show temporal error. char title[100]; sprintf(title, "Temporal error est, spatial adaptivity step %d", as); time_error_view.set_title(title); time_error_view.show_mesh(false); time_error_view.show(time_error_fn, HERMES_EPS_VERYHIGH); rel_err_time = calc_norm(time_error_fn, HERMES_H1_NORM) / calc_norm(&ref_sln, HERMES_H1_NORM) * 100; if (ADAPTIVE_TIME_STEP_ON == false) info("rel_err_time: %g%%", rel_err_time); } if (ADAPTIVE_TIME_STEP_ON) { if (rel_err_time > TIME_ERR_TOL_UPPER) { info("rel_err_time %g%% is above upper limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); info("Decreasing tau from %g to %g s and restarting time step.", time_step, time_step * TIME_STEP_DEC_RATIO); time_step *= TIME_STEP_DEC_RATIO; delete ref_space; delete ref_dp; continue; } else if (rel_err_time < TIME_ERR_TOL_LOWER) { info("rel_err_time = %g%% is below lower limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); info("Increasing tau from %g to %g s.", time_step, time_step * TIME_STEP_INC_RATIO); time_step *= TIME_STEP_INC_RATIO; } else { info("rel_err_time = %g%% is in acceptable interval (%g%%, %g%%)", rel_err_time, TIME_ERR_TOL_LOWER, TIME_ERR_TOL_UPPER); } // Add entry to time step history graph. time_step_graph.add_values(current_time, time_step); time_step_graph.save("time_step_history.dat"); } /* Estimate spatial errors and perform mesh refinement */ info("Spatial adaptivity step %d.", as); // Project the fine mesh solution onto the coarse mesh. Solution sln; info("Projecting fine mesh solution on coarse mesh for error estimation."); OGProjection::project_global(&space, &ref_sln, &sln, matrix_solver); // Show spatial error. sprintf(title, "Spatial error est, spatial adaptivity step %d", as); DiffFilter* space_error_fn = new DiffFilter(Hermes::vector<MeshFunction*>(&ref_sln, &sln)); space_error_view.set_title(title); space_error_view.show_mesh(false); AbsFilter abs_sef(space_error_fn); space_error_view.show(&abs_sef, HERMES_EPS_VERYHIGH); // Calculate element errors and spatial error estimate. info("Calculating spatial error estimate."); Adapt* adaptivity = new Adapt(&space); double err_rel_space = adaptivity->calc_err_est(&sln, &ref_sln) * 100; // Report results. info("ndof: %d, ref_ndof: %d, err_rel_space: %g%%", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space), err_rel_space); // If err_est too large, adapt the mesh. if (err_rel_space < SPACE_ERR_TOL) done = true; else { info("Adapting the coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Clean up. delete adaptivity; delete ref_space; delete ref_dp; delete space_error_fn; } while (done == false); // Clean up. if (time_error_fn != NULL) delete time_error_fn; // Visualize the solution and mesh. char title[100]; sprintf(title, "Solution, time %g s", current_time); sln_view.set_title(title); sln_view.show_mesh(false); sln_view.show(&ref_sln, HERMES_EPS_VERYHIGH); sprintf(title, "Mesh, time %g s", current_time); ordview.set_title(title); ordview.show(&space); // Copy last reference solution into sln_prev_time. sln_prev_time->copy(&ref_sln); // Increase current time and counter of time steps. current_time += time_step; ts++; } while (current_time < T_FINAL); // Clean up. delete sln_prev_time; delete bt; // Wait for all views to be closed. View::wait(); return 0; }