int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(butcher_table_type); if (bt.is_explicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage explicit R-K method.", bt.get_size()); if (bt.is_diagonally_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage diagonally implicit R-K method.", bt.get_size()); if (bt.is_fully_implicit()) Hermes::Mixins::Loggable::Static::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) { Hermes::Mixins::Loggable::Static::warn("R-K method not embedded, turning off adaptive time stepping."); ADAPTIVE_TIME_STEP_ON = false; } // Load the mesh. MeshSharedPtr mesh(new Mesh), basemesh(new Mesh); MeshReaderH2D mloader; mloader.load("wall.mesh", basemesh); mesh->copy(basemesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh->refine_all_elements(); mesh->refine_towards_boundary(BDY_RIGHT, 2); mesh->refine_towards_boundary(BDY_FIRE, INIT_REF_NUM_BDY); // Initialize essential boundary conditions (none). EssentialBCs<double> bcs; // Initialize an H1 space with default shapeset. SpaceSharedPtr<double> space(new H1Space<double>(mesh, &bcs, P_INIT)); int ndof = Space<double>::get_num_dofs(space); Hermes::Mixins::Loggable::Static::info("ndof = %d.", ndof); // Convert initial condition into a Solution. MeshFunctionSharedPtr<double> sln_prev_time(new ConstantSolution<double> (mesh, TEMP_INIT)); // Initialize the weak formulation. double current_time = 0; CustomWeakFormHeatRK wf(BDY_FIRE, BDY_AIR, ALPHA_FIRE, ALPHA_AIR, RHO, HEATCAP, TEMP_EXT_AIR, TEMP_INIT, ¤t_time); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, space); // Create a refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST); // 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); ordview.show(space); // Graph for time step history. SimpleGraph time_step_graph; if (ADAPTIVE_TIME_STEP_ON) Hermes::Mixins::Loggable::Static::info("Time step history will be saved to file time_step_history.dat."); // Class for projections. OGProjection<double> ogProjection; // Time stepping loop: int ts = 1; do { Hermes::Mixins::Loggable::Static::info("Begin time step %d.", ts); // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { Hermes::Mixins::Loggable::Static::info("Global mesh derefinement."); switch (UNREF_METHOD) { case 1: mesh->copy(basemesh); space->set_uniform_order(P_INIT); break; case 2: space->unrefine_all_mesh_elements(); space->set_uniform_order(P_INIT); break; case 3: space->unrefine_all_mesh_elements(); //space->adjust_element_order(-1, P_INIT); space->adjust_element_order(-1, -1, P_INIT, P_INIT); break; default: throw Hermes::Exceptions::Exception("Wrong global derefinement method."); } space->assign_dofs(); ndof = Space<double>::get_num_dofs(space); } // Spatial adaptivity loop. Note: sln_prev_time must not be // changed during spatial adaptivity. MeshFunctionSharedPtr<double> ref_sln(new Solution<double>()); MeshFunctionSharedPtr<double> time_error_fn(new Solution<double>(mesh)); bool done = false; int as = 1; double err_est; do { // Construct globally refined reference mesh and setup reference space. Mesh::ReferenceMeshCreator refMeshCreator(mesh); MeshSharedPtr ref_mesh = refMeshCreator.create_ref_mesh(); Space<double>::ReferenceSpaceCreator refSpaceCreator(space, ref_mesh); SpaceSharedPtr<double> ref_space = refSpaceCreator.create_ref_space(); // Initialize Runge-Kutta time stepping on the reference mesh. RungeKutta<double> runge_kutta(&wf, ref_space, &bt); try { ogProjection.project_global(ref_space, sln_prev_time, sln_prev_time); } catch(Exceptions::Exception& e) { std::cout << e.what() << std::endl; Hermes::Mixins::Loggable::Static::error("Projection failed."); return -1; } // Runge-Kutta step on the fine mesh-> Hermes::Mixins::Loggable::Static::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 jacobian_changed = false; try { runge_kutta.set_time(current_time); runge_kutta.set_time_step(time_step); runge_kutta.set_max_allowed_iterations(NEWTON_MAX_ITER); runge_kutta.set_tolerance(NEWTON_TOL_FINE); runge_kutta.rk_time_step_newton(sln_prev_time, ref_sln, bt.is_embedded() ? time_error_fn : NULL); } catch(Exceptions::Exception& e) { std::cout << e.what() << std::endl; Hermes::Mixins::Loggable::Static::error("Runge-Kutta time step failed"); return -1; } /* 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 = 0; if (bt.is_embedded() == true) { Hermes::Mixins::Loggable::Static::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); rel_err_time = Global<double>::calc_norm(time_error_fn.get(), HERMES_H1_NORM) / Global<double>::calc_norm(ref_sln.get(), HERMES_H1_NORM) * 100; if (ADAPTIVE_TIME_STEP_ON == false) Hermes::Mixins::Loggable::Static::info("rel_err_time: %g%%", rel_err_time); } if (ADAPTIVE_TIME_STEP_ON) { if (rel_err_time > TIME_ERR_TOL_UPPER) { Hermes::Mixins::Loggable::Static::info("rel_err_time %g%% is above upper limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); Hermes::Mixins::Loggable::Static::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; continue; } else if (rel_err_time < TIME_ERR_TOL_LOWER) { Hermes::Mixins::Loggable::Static::info("rel_err_time = %g%% is below lower limit %g%%", rel_err_time, TIME_ERR_TOL_LOWER); Hermes::Mixins::Loggable::Static::info("Increasing tau from %g to %g s.", time_step, time_step * TIME_STEP_INC_RATIO); time_step *= TIME_STEP_INC_RATIO; } else { Hermes::Mixins::Loggable::Static::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 */ Hermes::Mixins::Loggable::Static::info("Spatial adaptivity step %d.", as); // Project the fine mesh solution onto the coarse mesh. MeshFunctionSharedPtr<double> sln(new Solution<double>()); Hermes::Mixins::Loggable::Static::info("Projecting fine mesh solution on coarse mesh for error estimation."); ogProjection.project_global(space, ref_sln, sln); // Show spatial error. sprintf(title, "Spatial error est, spatial adaptivity step %d", as); MeshFunctionSharedPtr<double> space_error_fn(new DiffFilter<double>(Hermes::vector<MeshFunctionSharedPtr<double> >(ref_sln, sln))); space_error_view.set_title(title); //space_error_view.show_mesh(false); MeshFunctionSharedPtr<double> abs_sef(new AbsFilter(space_error_fn)); space_error_view.show(abs_sef); // Calculate element errors and spatial error estimate. Hermes::Mixins::Loggable::Static::info("Calculating spatial error estimate."); adaptivity.set_space(space); double err_rel_space = errorCalculator.get_total_error_squared() * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof: %d, ref_ndof: %d, err_rel_space: %g%%", Space<double>::get_num_dofs(space), Space<double>::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 { Hermes::Mixins::Loggable::Static::info("Adapting the coarse mesh."); done = adaptivity.adapt(&selector); if (Space<double>::get_num_dofs(space) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Clean up. if(!done) } while (done == false); // 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); 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); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(butcher_table_type); if (bt.is_explicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage explicit R-K method.", bt.get_size()); if (bt.is_diagonally_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage diagonally implicit R-K method.", bt.get_size()); if (bt.is_fully_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage fully implicit R-K method.", bt.get_size()); // Load the mesh. MeshSharedPtr mesh(new Mesh), basemesh(new Mesh); MeshReaderH2D mloader; mloader.load("square.mesh", basemesh); mesh->copy(basemesh); // Initial mesh refinements. for(int i = 0; i < INIT_GLOB_REF_NUM; i++) mesh->refine_all_elements(); mesh->refine_towards_boundary("Top", INIT_REF_NUM_BDY); // Initialize boundary conditions. CustomEssentialBCNonConst bc_essential(Hermes::vector<std::string>("Bottom", "Right", "Top", "Left")); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. SpaceSharedPtr<double> space(new H1Space<double>(mesh, &bcs, P_INIT)); int ndof_coarse = Space<double>::get_num_dofs(space); adaptivity.set_space(space); Hermes::Mixins::Loggable::Static::info("ndof_coarse = %d.", ndof_coarse); // Zero initial solution. This is why we use H_OFFSET. MeshFunctionSharedPtr<double> h_time_prev(new ZeroSolution<double>(mesh)), h_time_new(new ZeroSolution<double>(mesh)); // Initialize the constitutive relations. ConstitutiveRelations* constitutive_relations; if(constitutive_relations_type == CONSTITUTIVE_GENUCHTEN) constitutive_relations = new ConstitutiveRelationsGenuchten(ALPHA, M, N, THETA_S, THETA_R, K_S, STORATIVITY); else constitutive_relations = new ConstitutiveRelationsGardner(ALPHA, THETA_S, THETA_R, K_S); // Initialize the weak formulation. CustomWeakFormRichardsRK wf(constitutive_relations); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, space); // Create a refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST); // Visualize initial condition. char title[100]; ScalarView view("Initial condition", new WinGeom(0, 0, 440, 350)); OrderView ordview("Initial mesh", new WinGeom(445, 0, 440, 350)); view.show(h_time_prev); ordview.show(space); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. Hermes::Mixins::TimeMeasurable cpu_time; cpu_time.tick(); // Time stepping loop. double current_time = 0; int ts = 1; do { // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { Hermes::Mixins::Loggable::Static::info("Global mesh derefinement."); switch (UNREF_METHOD) { case 1: mesh->copy(basemesh); space->set_uniform_order(P_INIT); break; case 2: mesh->unrefine_all_elements(); space->set_uniform_order(P_INIT); break; case 3: space->unrefine_all_mesh_elements(); space->adjust_element_order(-1, -1, P_INIT, P_INIT); break; default: throw Hermes::Exceptions::Exception("Wrong global derefinement method."); } space->assign_dofs(); ndof_coarse = Space<double>::get_num_dofs(space); } // Spatial adaptivity loop. Note: h_time_prev must not be changed // during spatial adaptivity. bool done = false; int as = 1; double err_est; do { Hermes::Mixins::Loggable::Static::info("Time step %d, adaptivity step %d:", ts, as); // Construct globally refined reference mesh and setup reference space. Mesh::ReferenceMeshCreator refMeshCreator(mesh); MeshSharedPtr ref_mesh = refMeshCreator.create_ref_mesh(); Space<double>::ReferenceSpaceCreator refSpaceCreator(space, ref_mesh); SpaceSharedPtr<double> ref_space = refSpaceCreator.create_ref_space(); int ndof_ref = Space<double>::get_num_dofs(ref_space); // Time measurement. cpu_time.tick(); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&wf, ref_space, &bt); // Perform one Runge-Kutta time step according to the selected Butcher's table. Hermes::Mixins::Loggable::Static::info("Runge-Kutta time step (t = %g s, tau = %g s, stages: %d).", current_time, time_step, bt.get_size()); try { runge_kutta.set_time(current_time); runge_kutta.set_time_step(time_step); runge_kutta.set_max_allowed_iterations(NEWTON_MAX_ITER); runge_kutta.set_tolerance(NEWTON_TOL); runge_kutta.rk_time_step_newton(h_time_prev, h_time_new); } catch(Exceptions::Exception& e) { e.print_msg(); throw Hermes::Exceptions::Exception("Runge-Kutta time step failed"); } // Project the fine mesh solution onto the coarse mesh. MeshFunctionSharedPtr<double> sln_coarse(new Solution<double>); Hermes::Mixins::Loggable::Static::info("Projecting fine mesh solution on coarse mesh for error estimation."); OGProjection<double> ogProjection; ogProjection.project_global(space, h_time_new, sln_coarse); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); errorCalculator.calculate_errors(sln_coarse, h_time_new, true); double err_est_rel_total = errorCalculator.get_total_error_squared() * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof_coarse: %d, ndof_ref: %d, err_est_rel: %g%%", Space<double>::get_num_dofs(space), Space<double>::get_num_dofs(ref_space), err_est_rel_total); // Time measurement. cpu_time.tick(); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) done = true; else { Hermes::Mixins::Loggable::Static::info("Adapting the coarse mesh."); done = adaptivity.adapt(&selector); // Increase the counter of performed adaptivity steps. as++; } } while (done == false); // Add entry to DOF and CPU convergence graphs. graph_dof.add_values(current_time, Space<double>::get_num_dofs(space)); graph_dof.save("conv_dof_est.dat"); graph_cpu.add_values(current_time, cpu_time.accumulated()); graph_cpu.save("conv_cpu_est.dat"); // Visualize the solution and mesh-> char title[100]; sprintf(title, "Solution, time %g", current_time); view.set_title(title); view.show_mesh(false); view.show(h_time_new); sprintf(title, "Mesh, time %g", current_time); ordview.set_title(title); ordview.show(space); // Copy last reference solution into h_time_prev. h_time_prev->copy(h_time_new); // Increase current time and counter of time steps. current_time += time_step; ts++; } while (current_time < T_FINAL); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(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()); // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("../domain.mesh", &mesh); // Convert to quadrilaterals. mesh.convert_triangles_to_quads(); // Refine towards boundary. mesh.refine_towards_boundary("Bdy", 1, true); // Refine once towards vertex #4. mesh.refine_towards_vertex(4, 1); // Initialize solutions. CustomInitialConditionWave u_sln(&mesh); Solution v_sln(&mesh, 0.0); Hermes::vector<Solution*> slns(&u_sln, &v_sln); // Initialize the weak formulation. CustomWeakFormWave wf(time_step, C_SQUARED, &u_sln, &v_sln); // Initialize boundary conditions DefaultEssentialBCConst bc_essential("Bdy", 0.0); EssentialBCs bcs(&bc_essential); // Create x- and y- displacement space using the default H1 shapeset. H1Space u_space(&mesh, &bcs, P_INIT); H1Space v_space(&mesh, &bcs, P_INIT); info("ndof = %d.", Space::get_num_dofs(Hermes::vector<Space *>(&u_space, &v_space))); // Initialize the FE problem. DiscreteProblem dp(&wf, Hermes::vector<Space *>(&u_space, &v_space)); // Initialize Runge-Kutta time stepping. RungeKutta runge_kutta(&dp, &bt, matrix_solver); // Time stepping loop. double current_time = 0; int ts = 1; do { // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, time_step = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool jacobian_changed = false; bool verbose = true; if (!runge_kutta.rk_time_step(current_time, time_step, slns, slns, jacobian_changed, verbose)) error("Runge-Kutta time step failed, try to decrease time step size."); // Update time. current_time += time_step; } while (current_time < T_FINAL); double coord_x[4] = {1, 3, 5, 7}; double coord_y[4] = {1, 3, 5, 7}; info("Coordinate (1.0, 0.0) value = %lf", u_sln.get_pt_value(coord_x[0], coord_y[0])); info("Coordinate (3.0, 3.0) value = %lf", u_sln.get_pt_value(coord_x[1], coord_y[1])); info("Coordinate (5.0, 5.0) value = %lf", u_sln.get_pt_value(coord_x[2], coord_y[2])); info("Coordinate (7.0, 7.0) value = %lf", u_sln.get_pt_value(coord_x[3], coord_y[3])); info("Coordinate (1.0, 0.0) value = %lf", v_sln.get_pt_value(coord_x[0], coord_y[0])); info("Coordinate (3.0, 3.0) value = %lf", v_sln.get_pt_value(coord_x[1], coord_y[1])); info("Coordinate (5.0, 5.0) value = %lf", v_sln.get_pt_value(coord_x[2], coord_y[2])); info("Coordinate (7.0, 7.0) value = %lf", v_sln.get_pt_value(coord_x[3], coord_y[3])); double t_value[8] = {0.212655, 0.000163, 0.000000, 0.000000, -0.793316, 0.007255, 0.000001, 0.000000}; bool success = true; for (int i = 0; i < 4; i++) { if (fabs(t_value[i] - u_sln.get_pt_value(coord_x[i], coord_y[i])) > 1E-6) success = false; } for (int i = 4; i < 8; i++) { if (fabs(t_value[i] - v_sln.get_pt_value(coord_x[i-4], coord_y[i-4])) > 1E-6) success = false; } if (success) { printf("Success!\n"); return ERR_SUCCESS; } else { printf("Failure!\n"); return ERR_FAILURE; } // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(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()); // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("domain.mesh", &mesh); // Perform initial mesh refinemets. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize solutions. CustomInitialConditionWave E_sln(&mesh); ZeroSolution B_sln(&mesh); Hermes::vector<Solution<double>*> slns(&E_sln, &B_sln); // Initialize the weak formulation. CustomWeakFormWave wf(C_SQUARED); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential("Perfect conductor", 0.0); EssentialBCs<double> bcs_E(&bc_essential); EssentialBCs<double> bcs_B; // Create x- and y- displacement space using the default H1 shapeset. HcurlSpace<double> E_space(&mesh, &bcs_E, P_INIT); H1Space<double> B_space(&mesh, &bcs_B, P_INIT); //L2Space<double> B_space(&mesh, P_INIT); Hermes::vector<Space<double> *> spaces = Hermes::vector<Space<double> *>(&E_space, &B_space); info("ndof = %d.", Space<double>::get_num_dofs(spaces)); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, spaces); // Initialize views. ScalarView E1_view("Solution E1", new WinGeom(0, 0, 400, 350)); E1_view.fix_scale_width(50); ScalarView E2_view("Solution E2", new WinGeom(410, 0, 400, 350)); E2_view.fix_scale_width(50); ScalarView B_view("Solution B", new WinGeom(0, 405, 400, 350)); B_view.fix_scale_width(50); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&dp, &bt, matrix_solver_type); // Time stepping loop. double current_time = time_step; int ts = 1; do { // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, time_step = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool jacobian_changed = false; bool verbose = true; try { runge_kutta.rk_time_step_newton(current_time, time_step, slns, slns, jacobian_changed, verbose); } catch(Exceptions::Exception& e) { e.printMsg(); error("Runge-Kutta time step failed"); } // Visualize the solutions. char title[100]; sprintf(title, "E1, t = %g", current_time); E1_view.set_title(title); E1_view.show(&E_sln, HERMES_EPS_NORMAL, H2D_FN_VAL_0); sprintf(title, "E2, t = %g", current_time); E2_view.set_title(title); E2_view.show(&E_sln, HERMES_EPS_NORMAL, H2D_FN_VAL_1); sprintf(title, "B, t = %g", current_time); B_view.set_title(title); B_view.show(&B_sln, HERMES_EPS_NORMAL, H2D_FN_VAL_0); // Update time. current_time += time_step; } while (current_time < T_FINAL); // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(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()); // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("../domain.mesh", &mesh); // Perform initial mesh refinemets. for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Initialize solutions. CustomInitialConditionWave E_sln(&mesh); Solution F_sln(&mesh, 0.0, 0.0); Hermes::vector<Solution*> slns(&E_sln, &F_sln); // Initialize the weak formulation. CustomWeakFormWave wf(C_SQUARED); // Initialize boundary conditions DefaultEssentialBCConst bc_essential(BDY, 0.0); EssentialBCs bcs(&bc_essential); // Create x- and y- displacement space using the default H1 shapeset. HcurlSpace E_space(&mesh, &bcs, P_INIT); HcurlSpace F_space(&mesh, &bcs, P_INIT); Hermes::vector<Space *> spaces = Hermes::vector<Space *>(&E_space, &F_space); info("ndof = %d.", Space::get_num_dofs(spaces)); // Initialize the FE problem. DiscreteProblem dp(&wf, spaces); // Initialize Runge-Kutta time stepping. RungeKutta runge_kutta(&dp, &bt, matrix_solver); // Time stepping loop. double current_time = 0; int ts = 1; do { // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, time_step = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool verbose = true; bool jacobian_changed = true; if (!runge_kutta.rk_time_step(current_time, time_step, slns, slns, jacobian_changed, verbose)) error("Runge-Kutta time step failed, try to decrease time step size."); // Update time. current_time += time_step; } while (current_time < T_FINAL); double coord_x[4] = {0.3, 0.6, 0.9, 1.4}; double coord_y[4] = {0, 0.3, 0.5, 0.7}; info("Coordinate (0.3, 0.0) value = %lf", F_sln.get_pt_value(coord_x[0], coord_y[0])); info("Coordinate (0.6, 0.3) value = %lf", F_sln.get_pt_value(coord_x[1], coord_y[1])); info("Coordinate (0.9, 0.5) value = %lf", F_sln.get_pt_value(coord_x[2], coord_y[2])); info("Coordinate (1.4, 0.7) value = %lf", F_sln.get_pt_value(coord_x[3], coord_y[3])); double t_value[4] = {-0.144673, -0.264077, -0.336536, -0.368983}; bool success = true; for (int i = 0; i < 4; i++) { if (fabs(t_value[i] - F_sln.get_pt_value(coord_x[i], coord_y[i])) > 1E-6) success = false; } if (success) { 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(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()); // Load the mesh. Mesh mesh, basemesh; MeshReaderH2D mloader; mloader.load("square.mesh", &basemesh); mesh.copy(&basemesh); // Initial mesh refinements. for(int i = 0; i < INIT_GLOB_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary("Top", INIT_REF_NUM_BDY); // Initialize boundary conditions. CustomEssentialBCNonConst bc_essential(Hermes::vector<std::string>("Bottom", "Right", "Top", "Left")); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); int ndof_coarse = Space<double>::get_num_dofs(&space); info("ndof_coarse = %d.", ndof_coarse); // Zero initial solution. This is why we use H_OFFSET. ZeroSolution h_time_prev(&mesh), h_time_new(&mesh); // Initialize the constitutive relations. ConstitutiveRelations* constitutive_relations; if(constitutive_relations_type == CONSTITUTIVE_GENUCHTEN) constitutive_relations = new ConstitutiveRelationsGenuchten(ALPHA, M, N, THETA_S, THETA_R, K_S, STORATIVITY); else constitutive_relations = new ConstitutiveRelationsGardner(ALPHA, THETA_S, THETA_R, K_S); // Initialize the weak formulation. CustomWeakFormRichardsRK wf(constitutive_relations); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, &space); // Create a refinement selector. H1ProjBasedSelector<double> selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Visualize initial condition. char title[100]; ScalarView view("Initial condition", new WinGeom(0, 0, 440, 350)); OrderView ordview("Initial mesh", new WinGeom(445, 0, 440, 350)); view.show(&h_time_prev); ordview.show(&space); // DOF and CPU convergence graphs initialization. SimpleGraph graph_dof, graph_cpu; // Time measurement. TimePeriod cpu_time; cpu_time.tick(); // Time stepping loop. double current_time = 0; int ts = 1; do { // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { info("Global mesh derefinement."); switch (UNREF_METHOD) { case 1: mesh.copy(&basemesh); space.set_uniform_order(P_INIT); break; case 2: mesh.unrefine_all_elements(); space.set_uniform_order(P_INIT); break; case 3: space.unrefine_all_mesh_elements(); space.adjust_element_order(-1, -1, P_INIT, P_INIT); break; default: error("Wrong global derefinement method."); } ndof_coarse = Space<double>::get_num_dofs(&space); } // Spatial adaptivity loop. Note: h_time_prev must not be changed // during spatial adaptivity. bool done = false; int as = 1; double err_est; do { info("Time step %d, adaptivity step %d:", ts, as); // Construct globally refined reference mesh and setup reference space. Space<double>* ref_space = Space<double>::construct_refined_space(&space); int ndof_ref = Space<double>::get_num_dofs(ref_space); // Time measurement. cpu_time.tick(); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&wf, ref_space, &bt, matrix_solver); // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, tau = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool freeze_jacobian = false; bool block_diagonal_jacobian = false; bool verbose = true; double damping_coeff = 1.0; double max_allowed_residual_norm = 1e10; try { runge_kutta.rk_time_step_newton(current_time, time_step, &h_time_prev, &h_time_new, freeze_jacobian, block_diagonal_jacobian, verbose, NEWTON_TOL, NEWTON_MAX_ITER, damping_coeff, max_allowed_residual_norm); } catch(Exceptions::Exception& e) { e.printMsg(); error("Runge-Kutta time step failed"); } // Project the fine mesh solution onto the coarse mesh. Solution<double> sln_coarse; info("Projecting fine mesh solution on coarse mesh for error estimation."); OGProjection<double>::project_global(&space, &h_time_new, &sln_coarse, matrix_solver); // Calculate element errors and total error estimate. info("Calculating error estimate."); Adapt<double>* adaptivity = new Adapt<double>(&space); double err_est_rel_total = adaptivity->calc_err_est(&sln_coarse, &h_time_new) * 100; // Report results. info("ndof_coarse: %d, ndof_ref: %d, err_est_rel: %g%%", Space<double>::get_num_dofs(&space), Space<double>::get_num_dofs(ref_space), err_est_rel_total); // Time measurement. cpu_time.tick(); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) done = true; else { info("Adapting the coarse mesh."); done = adaptivity->adapt(&selector, THRESHOLD, STRATEGY, MESH_REGULARITY); if (Space<double>::get_num_dofs(&space) >= NDOF_STOP) done = true; else // Increase the counter of performed adaptivity steps. as++; } // Clean up. delete adaptivity; if(!done) { delete h_time_new.get_space(); delete h_time_new.get_mesh(); } } while (done == false); // Add entry to DOF and CPU convergence graphs. graph_dof.add_values(current_time, Space<double>::get_num_dofs(&space)); graph_dof.save("conv_dof_est.dat"); graph_cpu.add_values(current_time, cpu_time.accumulated()); graph_cpu.save("conv_cpu_est.dat"); // Visualize the solution and mesh. char title[100]; sprintf(title, "Solution, time %g", current_time); view.set_title(title); view.show_mesh(false); view.show(&h_time_new); sprintf(title, "Mesh, time %g", current_time); ordview.set_title(title); ordview.show(&space); // Copy last reference solution into h_time_prev. h_time_prev.copy(&h_time_new); delete h_time_new.get_mesh(); // Increase current time and counter of time steps. current_time += time_step; ts++; } while (current_time < T_FINAL); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { try { // Sanity check for omega. double K_squared = Hermes::sqr(OMEGA / M_PI) * (OMEGA - 2) / (1 - OMEGA); if (K_squared <= 0) throw Hermes::Exceptions::Exception("Wrong choice of omega, K_squared < 0!"); double K_norm_coeff = std::sqrt(K_squared) / std::sqrt(Hermes::sqr(K_x) + Hermes::sqr(K_y)); Hermes::Mixins::Loggable::Static::info("Wave number K = %g", std::sqrt(K_squared)); K_x *= K_norm_coeff; K_y *= K_norm_coeff; // Wave number. double K = std::sqrt(Hermes::sqr(K_x) + Hermes::sqr(K_y)); // Choose a Butcher's table or define your own. ButcherTable bt(butcher_table); if (bt.is_explicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage explicit R-K method.", bt.get_size()); if (bt.is_diagonally_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage diagonally implicit R-K method.", bt.get_size()); if (bt.is_fully_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage fully implicit R-K method.", bt.get_size()); // Load the mesh. MeshSharedPtr E_mesh(new Mesh), H_mesh(new Mesh), P_mesh(new Mesh); MeshReaderH2D mloader; mloader.load("domain.mesh", E_mesh); mloader.load("domain.mesh", H_mesh); mloader.load("domain.mesh", P_mesh); // Perform initial mesh refinemets. for (int i = 0; i < INIT_REF_NUM; i++) { E_mesh->refine_all_elements(); H_mesh->refine_all_elements(); P_mesh->refine_all_elements(); } // Initialize solutions. double current_time = 0; MeshFunctionSharedPtr<double> E_time_prev(new CustomInitialConditionE(E_mesh, current_time, OMEGA, K_x, K_y)); MeshFunctionSharedPtr<double> H_time_prev(new CustomInitialConditionH(H_mesh, current_time, OMEGA, K_x, K_y)); MeshFunctionSharedPtr<double> P_time_prev(new CustomInitialConditionP(P_mesh, current_time, OMEGA, K_x, K_y)); Hermes::vector<MeshFunctionSharedPtr<double> > slns_time_prev(E_time_prev, H_time_prev, P_time_prev); MeshFunctionSharedPtr<double> E_time_new(new Solution<double>(E_mesh)), H_time_new(new Solution<double>(H_mesh)), P_time_new(new Solution<double>(P_mesh)); MeshFunctionSharedPtr<double> E_time_new_coarse(new Solution<double>(E_mesh)), H_time_new_coarse(new Solution<double>(H_mesh)), P_time_new_coarse(new Solution<double>(P_mesh)); Hermes::vector<MeshFunctionSharedPtr<double> > slns_time_new(E_time_new, H_time_new, P_time_new); // Initialize the weak formulation. CustomWeakFormMD wf(OMEGA, K_x, K_y, MU_0, EPS_0, EPS_INF, EPS_Q, TAU); // Initialize boundary conditions DefaultEssentialBCConst<double> bc_essential("Bdy", 0.0); EssentialBCs<double> bcs(&bc_essential); SpaceSharedPtr<double> E_space(new HcurlSpace<double>(E_mesh, &bcs, P_INIT)); SpaceSharedPtr<double> H_space(new H1Space<double>(H_mesh, NULL, P_INIT)); //L2Space<double> H_space(mesh, P_INIT)); SpaceSharedPtr<double> P_space(new HcurlSpace<double>(P_mesh, &bcs, P_INIT)); Hermes::vector<SpaceSharedPtr<double> > spaces = Hermes::vector<SpaceSharedPtr<double> >(E_space, H_space, P_space); // Initialize views. ScalarView E1_view("Solution E1", new WinGeom(0, 0, 400, 350)); E1_view.fix_scale_width(50); ScalarView E2_view("Solution E2", new WinGeom(410, 0, 400, 350)); E2_view.fix_scale_width(50); ScalarView H_view("Solution H", new WinGeom(0, 410, 400, 350)); H_view.fix_scale_width(50); ScalarView P1_view("Solution P1", new WinGeom(410, 410, 400, 350)); P1_view.fix_scale_width(50); ScalarView P2_view("Solution P2", new WinGeom(820, 410, 400, 350)); P2_view.fix_scale_width(50); // Visualize initial conditions. char title[100]; sprintf(title, "E1 - Initial Condition"); E1_view.set_title(title); E1_view.show(E_time_prev, H2D_FN_VAL_0); sprintf(title, "E2 - Initial Condition"); E2_view.set_title(title); E2_view.show(E_time_prev, H2D_FN_VAL_1); sprintf(title, "H - Initial Condition"); H_view.set_title(title); H_view.show(H_time_prev); sprintf(title, "P1 - Initial Condition"); P1_view.set_title(title); P1_view.show(P_time_prev, H2D_FN_VAL_0); sprintf(title, "P2 - Initial Condition"); P2_view.set_title(title); P2_view.show(P_time_prev, H2D_FN_VAL_1); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&wf, spaces, &bt); runge_kutta.set_max_allowed_iterations(NEWTON_MAX_ITER); runge_kutta.set_tolerance(NEWTON_TOL); runge_kutta.set_verbose_output(true); // Initialize refinement selector. H1ProjBasedSelector<double> H1selector(CAND_LIST); HcurlProjBasedSelector<double> HcurlSelector(CAND_LIST); // Time stepping loop. int ts = 1; do { // Perform one Runge-Kutta time step according to the selected Butcher's table. Hermes::Mixins::Loggable::Static::info("\nRunge-Kutta time step (t = %g s, time_step = %g s, stages: %d).", current_time, time_step, bt.get_size()); // Periodic global derefinements. if (ts > 1 && ts % UNREF_FREQ == 0 && REFINEMENT_COUNT > 0) { Hermes::Mixins::Loggable::Static::info("Global mesh derefinement."); REFINEMENT_COUNT = 0; E_space->unrefine_all_mesh_elements(true); H_space->unrefine_all_mesh_elements(true); P_space->unrefine_all_mesh_elements(true); E_space->adjust_element_order(-1, P_INIT); H_space->adjust_element_order(-1, P_INIT); P_space->adjust_element_order(-1, P_INIT); E_space->assign_dofs(); H_space->assign_dofs(); P_space->assign_dofs(); } // Adaptivity loop: int as = 1; bool done = false; do { Hermes::Mixins::Loggable::Static::info("Adaptivity step %d:", as); // Construct globally refined reference mesh and setup reference space. int order_increase = 1; Mesh::ReferenceMeshCreator refMeshCreatorE(E_mesh); Mesh::ReferenceMeshCreator refMeshCreatorH(H_mesh); Mesh::ReferenceMeshCreator refMeshCreatorP(P_mesh); MeshSharedPtr ref_mesh_E = refMeshCreatorE.create_ref_mesh(); MeshSharedPtr ref_mesh_H = refMeshCreatorH.create_ref_mesh(); MeshSharedPtr ref_mesh_P = refMeshCreatorP.create_ref_mesh(); Space<double>::ReferenceSpaceCreator refSpaceCreatorE(E_space, ref_mesh_E, order_increase); SpaceSharedPtr<double> ref_space_E = refSpaceCreatorE.create_ref_space(); Space<double>::ReferenceSpaceCreator refSpaceCreatorH(H_space, ref_mesh_H, order_increase); SpaceSharedPtr<double> ref_space_H = refSpaceCreatorH.create_ref_space(); Space<double>::ReferenceSpaceCreator refSpaceCreatorP(P_space, ref_mesh_P, order_increase); SpaceSharedPtr<double> ref_space_P = refSpaceCreatorP.create_ref_space(); Hermes::vector<SpaceSharedPtr<double> > ref_spaces(ref_space_E, ref_space_H, ref_space_P); int ndof = Space<double>::get_num_dofs(ref_spaces); Hermes::Mixins::Loggable::Static::info("ndof = %d.", ndof); try { runge_kutta.set_spaces(ref_spaces); runge_kutta.set_time(current_time); runge_kutta.set_time_step(time_step); runge_kutta.rk_time_step_newton(slns_time_prev, slns_time_new); } catch (Exceptions::Exception& e) { e.print_msg(); throw Hermes::Exceptions::Exception("Runge-Kutta time step failed"); } // Visualize the solutions. char title[100]; sprintf(title, "E1, t = %g", current_time + time_step); E1_view.set_title(title); E1_view.show(E_time_new, H2D_FN_VAL_0); sprintf(title, "E2, t = %g", current_time + time_step); E2_view.set_title(title); E2_view.show(E_time_new, H2D_FN_VAL_1); sprintf(title, "H, t = %g", current_time + time_step); H_view.set_title(title); H_view.show(H_time_new); sprintf(title, "P1, t = %g", current_time + time_step); P1_view.set_title(title); P1_view.show(P_time_new, H2D_FN_VAL_0); sprintf(title, "P2, t = %g", current_time + time_step); P2_view.set_title(title); P2_view.show(P_time_new, H2D_FN_VAL_1); // Project the fine mesh solution onto the coarse mesh. Hermes::Mixins::Loggable::Static::info("Projecting reference solution on coarse mesh."); OGProjection<double> ogProjection; ogProjection.project_global(Hermes::vector<SpaceSharedPtr<double> >(E_space, H_space, P_space), Hermes::vector<MeshFunctionSharedPtr<double> >(E_time_new, H_time_new, P_time_new), Hermes::vector<MeshFunctionSharedPtr<double> >(E_time_new_coarse, H_time_new_coarse, P_time_new_coarse)); // Calculate element errors and total error estimate. Hermes::Mixins::Loggable::Static::info("Calculating error estimate."); adaptivity.set_spaces(Hermes::vector<SpaceSharedPtr<double> >(E_space, H_space, P_space)); errorCalculator.calculate_errors(Hermes::vector<MeshFunctionSharedPtr<double> >(E_time_new_coarse, H_time_new_coarse, P_time_new_coarse), Hermes::vector<MeshFunctionSharedPtr<double> >(E_time_new, H_time_new, P_time_new)); double err_est_rel_total = errorCalculator.get_total_error_squared() * 100.; // Report results. Hermes::Mixins::Loggable::Static::info("Error estimate: %g%%", err_est_rel_total); // If err_est too large, adapt the mesh. if (err_est_rel_total < ERR_STOP) { Hermes::Mixins::Loggable::Static::info("Error estimate under the specified threshold -> moving to next time step."); done = true; } else { Hermes::Mixins::Loggable::Static::info("Adapting coarse mesh."); REFINEMENT_COUNT++; done = adaptivity.adapt(Hermes::vector<RefinementSelectors::Selector<double> *>(&HcurlSelector, &H1selector, &HcurlSelector)); if (!done) as++; } } while (!done); //View::wait(); E_time_prev->copy(E_time_new); H_time_prev->copy(H_time_new); P_time_prev->copy(P_time_new); // Update time. current_time += time_step; ts++; } while (current_time < T_FINAL); // Wait for the view to be closed. View::wait(); } catch (std::exception& e) { std::cout << e.what(); } return 0; }
// Main function. int main(int argc, char* argv[]) { ConstitutiveRelationsGenuchtenWithLayer constitutive_relations(CONSTITUTIVE_TABLE_METHOD, NUM_OF_INSIDE_PTS, LOW_LIMIT, TABLE_PRECISION, TABLE_LIMIT, K_S_vals, ALPHA_vals, N_vals, M_vals, THETA_R_vals, THETA_S_vals, STORATIVITY_vals); // Either use exact constitutive relations (slow) (method 0) or precalculate // their linear approximations (faster) (method 1) or // precalculate their quintic polynomial approximations (method 2) -- managed by // the following loop "Initializing polynomial approximation". if (CONSTITUTIVE_TABLE_METHOD == 1) constitutive_relations.constitutive_tables_ready = get_constitutive_tables(1, &constitutive_relations, MATERIAL_COUNT); // 1 stands for the Newton's method. // The van Genuchten + Mualem K(h) function is approximated by polynomials close // to zero in case of CONSTITUTIVE_TABLE_METHOD==1. // In case of CONSTITUTIVE_TABLE_METHOD==2, all constitutive functions are approximated by polynomials. info("Initializing polynomial approximations."); for (int i=0; i < MATERIAL_COUNT; i++) { // Points to be used for polynomial approximation of K(h). double* points = new double[NUM_OF_INSIDE_PTS]; init_polynomials(6 + NUM_OF_INSIDE_PTS, LOW_LIMIT, points, NUM_OF_INSIDE_PTS, i, &constitutive_relations, MATERIAL_COUNT, NUM_OF_INTERVALS, INTERVALS_4_APPROX); } constitutive_relations.polynomials_ready = true; if (CONSTITUTIVE_TABLE_METHOD == 2) { constitutive_relations.constitutive_tables_ready = true; //Assign table limit to global definition. constitutive_relations.table_limit = INTERVALS_4_APPROX[NUM_OF_INTERVALS-1]; } // Choose a Butcher's table or define your own. ButcherTable bt(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()); // Load the mesh. Mesh mesh, basemesh; MeshReaderH2D mloader; mloader.load(mesh_file, &basemesh); // Perform initial mesh refinements. mesh.copy(&basemesh); for(int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary("Top", INIT_REF_NUM_BDY_TOP); // Initialize boundary conditions. RichardsEssentialBC bc_essential("Top", H_ELEVATION, PULSE_END_TIME, H_INIT, STARTUP_TIME); EssentialBCs<double> bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); info("ndof = %d.", ndof); // Convert initial condition into a Solution. ZeroSolution h_time_prev(&mesh), h_time_new(&mesh), time_error_fn(&mesh); // Initialize views. ScalarView view("Initial condition", new WinGeom(0, 0, 600, 500)); view.fix_scale_width(80); // Visualize the initial condition. view.show(&h_time_prev); // Initialize the weak formulation. CustomWeakFormRichardsRK wf(&constitutive_relations); // Visualize the projection and mesh. ScalarView sview("Initial condition", new WinGeom(0, 0, 400, 350)); sview.fix_scale_width(50); sview.show(&h_time_prev, HERMES_EPS_VERYHIGH); ScalarView eview("Temporal error", new WinGeom(405, 0, 400, 350)); eview.fix_scale_width(50); eview.show(&time_error_fn, HERMES_EPS_VERYHIGH); OrderView oview("Initial mesh", new WinGeom(810, 0, 350, 350)); oview.show(&space); // Graph for time step history. SimpleGraph time_step_graph; info("Time step history will be saved to file time_step_history.dat."); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&wf, &space, &bt, matrix_solver); // Time stepping: double current_time = 0; int ts = 1; do { info("---- Time step %d, time %3.5f s", ts, current_time); Space<double>::update_essential_bc_values(&space, current_time); // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, time step = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool freeze_jacobian = false; bool block_diagonal_jacobian = false; bool verbose = true; double damping_coeff = 1.0; double max_allowed_residual_norm = 1e10; try { runge_kutta.rk_time_step_newton(current_time, time_step, &h_time_prev, &h_time_new, &time_error_fn, freeze_jacobian, block_diagonal_jacobian, verbose, NEWTON_TOL, NEWTON_MAX_ITER, damping_coeff, max_allowed_residual_norm); } catch(Exceptions::Exception& e) { info("Runge-Kutta time step failed, decreasing time step size from %g to %g days.", time_step, time_step * time_step_dec); time_step *= time_step_dec; if (time_step < time_step_min) error("Time step became too small."); continue; } // Copy solution for the new time step. h_time_prev.copy(&h_time_new); // Show error function. char title[100]; sprintf(title, "Temporal error, t = %g", current_time); eview.set_title(title); eview.show(&time_error_fn, HERMES_EPS_VERYHIGH); // Calculate relative time stepping error and decide whether the // time step can be accepted. If not, then the time step size is // reduced and the entire time step repeated. If yes, then another // check is run, and if the relative error is very low, time step // is increased. double rel_err_time = Global<double>::calc_norm(&time_error_fn, HERMES_H1_NORM) / Global<double>::calc_norm(&h_time_new, HERMES_H1_NORM) * 100; info("rel_err_time = %g%%", rel_err_time); if (rel_err_time > time_tol_upper) { info("rel_err_time above upper limit %g%% -> decreasing time step from %g to %g days and repeating time step.", time_tol_upper, time_step, time_step * time_step_dec); time_step *= time_step_dec; continue; } if (rel_err_time < time_tol_lower) { info("rel_err_time = below lower limit %g%% -> increasing time step from %g to %g days", time_tol_lower, time_step, time_step * time_step_inc); time_step *= time_step_inc; } // Add entry to the timestep graph. time_step_graph.add_values(current_time, time_step); time_step_graph.save("time_step_history.dat"); // Update time. current_time += time_step; // Show the new time level solution. sprintf(title, "Solution, t = %g", current_time); sview.set_title(title); sview.show(&h_time_new, HERMES_EPS_VERYHIGH); oview.show(&space); // Save complete Solution. char filename[100]; sprintf(filename, "outputs/tsln_%f.dat", current_time); h_time_new.save(filename); info("Solution at time %g saved to file %s.", current_time, filename); // Save solution for the next time step. h_time_prev.copy(&h_time_new); // Increase time step counter. ts++; } while (current_time < T_FINAL); // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(butcher_table_type); if (bt.is_explicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage explicit R-K method.", bt.get_size()); if (bt.is_diagonally_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage diagonally implicit R-K method.", bt.get_size()); if (bt.is_fully_implicit()) Hermes::Mixins::Loggable::Static::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) { Hermes::Mixins::Loggable::Static::warn("R-K method not embedded, turning off adaptive time stepping."); ADAPTIVE_TIME_STEP_ON = false; } // Load the mesh. MeshSharedPtr mesh(new Mesh), basemesh(new Mesh); MeshReaderH2D mloader; mloader.load("square.mesh", basemesh); mesh->copy(basemesh); // Initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh->refine_all_elements(); // Convert initial condition into a Solution<complex>. MeshFunctionSharedPtr<complex> psi_time_prev(new CustomInitialCondition(mesh)); // Initialize the weak formulation. double current_time = 0; // Initialize weak formulation. CustomWeakFormGPRK wf(h, m, g, omega); // Initialize boundary conditions. DefaultEssentialBCConst<complex> bc_essential("Bdy", 0.0); EssentialBCs<complex> bcs(&bc_essential); // Create an H1 space with default shapeset. SpaceSharedPtr<complex> space(new H1Space<complex> (mesh, &bcs, P_INIT)); int ndof = space->get_num_dofs(); Hermes::Mixins::Loggable::Static::info("ndof = %d", ndof); // Initialize the FE problem. DiscreteProblem<complex> dp(&wf, space); // Create a refinement selector. H1ProjBasedSelector<complex> selector(CAND_LIST); // Visualize initial condition. char title[100]; ScalarView sview_real("Initial condition - real part", new WinGeom(0, 0, 600, 500)); ScalarView sview_imag("Initial condition - imaginary part", new WinGeom(610, 0, 600, 500)); sview_real.show_mesh(false); sview_imag.show_mesh(false); sview_real.fix_scale_width(50); sview_imag.fix_scale_width(50); OrderView ord_view("Initial mesh", new WinGeom(445, 0, 440, 350)); ord_view.fix_scale_width(50); ScalarView time_error_view("Temporal error", new WinGeom(0, 400, 440, 350)); time_error_view.fix_scale_width(50); time_error_view.fix_scale_width(60); ScalarView space_error_view("Spatial error", new WinGeom(445, 400, 440, 350)); space_error_view.fix_scale_width(50); MeshFunctionSharedPtr<double> real(new RealFilter(psi_time_prev)); MeshFunctionSharedPtr<double> imag(new ImagFilter(psi_time_prev)); sview_real.show(real); sview_imag.show(imag); ord_view.show(space); // Graph for time step history. SimpleGraph time_step_graph; if (ADAPTIVE_TIME_STEP_ON) Hermes::Mixins::Loggable::Static::info("Time step history will be saved to file time_step_history.dat."); // Time stepping: int num_time_steps = (int)(T_FINAL/time_step + 0.5); for(int ts = 1; ts <= num_time_steps; ts++) // Time stepping loop. double current_time = 0.0; int ts = 1; do { Hermes::Mixins::Loggable::Static::info("Begin time step %d.", ts); // Periodic global derefinement. if (ts > 1 && ts % UNREF_FREQ == 0) { Hermes::Mixins::Loggable::Static::info("Global mesh derefinement."); switch (UNREF_METHOD) { case 1: mesh->copy(basemesh); space->set_uniform_order(P_INIT); break; case 2: space->unrefine_all_mesh_elements(); space->set_uniform_order(P_INIT); break; case 3: space->unrefine_all_mesh_elements(); space->adjust_element_order(-1, -1, P_INIT, P_INIT); break; default: throw Hermes::Exceptions::Exception("Wrong global derefinement method."); } ndof = Space<complex>::get_num_dofs(space); } Hermes::Mixins::Loggable::Static::info("ndof: %d", ndof); // Spatial adaptivity loop. Note: psi_time_prev must not be // changed during spatial adaptivity. MeshFunctionSharedPtr<complex> ref_sln(new Solution<complex>()); MeshFunctionSharedPtr<complex> time_error_fn(new Solution<complex>); bool done = false; int as = 1; double err_est; do { // Construct globally refined reference mesh and setup reference space. Mesh::ReferenceMeshCreator refMeshCreator(mesh); MeshSharedPtr ref_mesh = refMeshCreator.create_ref_mesh(); Space<complex>::ReferenceSpaceCreator refSpaceCreator(space, ref_mesh); SpaceSharedPtr<complex> ref_space = refSpaceCreator.create_ref_space(); // Initialize discrete problem on reference mesh. DiscreteProblem<complex>* ref_dp = new DiscreteProblem<complex>(&wf, ref_space); RungeKutta<complex> runge_kutta(&wf, ref_space, &bt); // Runge-Kutta step on the fine mesh-> Hermes::Mixins::Loggable::Static::info("Runge-Kutta time step on fine mesh (t = %g s, time step = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool verbose = true; try { runge_kutta.set_time(current_time); runge_kutta.set_time_step(time_step); runge_kutta.set_max_allowed_iterations(NEWTON_MAX_ITER); runge_kutta.set_tolerance(NEWTON_TOL_FINE); runge_kutta.rk_time_step_newton(psi_time_prev, ref_sln, time_error_fn); } catch(Exceptions::Exception& e) { e.print_msg(); throw Hermes::Exceptions::Exception("Runge-Kutta time step failed"); } /* 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 = 0; if (bt.is_embedded() == true) { Hermes::Mixins::Loggable::Static::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); MeshFunctionSharedPtr<double> abs_time(new RealFilter(time_error_fn)); MeshFunctionSharedPtr<double> abs_tef(new AbsFilter(abs_time)); time_error_view.show(abs_tef); rel_err_time = Global<complex>::calc_norm(time_error_fn.get(), HERMES_H1_NORM) / Global<complex>::calc_norm(ref_sln.get(), HERMES_H1_NORM) * 100; if (ADAPTIVE_TIME_STEP_ON == false) Hermes::Mixins::Loggable::Static::info("rel_err_time: %g%%", rel_err_time); } if (ADAPTIVE_TIME_STEP_ON) { if (rel_err_time > TIME_ERR_TOL_UPPER) { Hermes::Mixins::Loggable::Static::info("rel_err_time %g%% is above upper limit %g%%", rel_err_time, TIME_ERR_TOL_UPPER); Hermes::Mixins::Loggable::Static::info("Decreasing time step 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_dp; continue; } else if (rel_err_time < TIME_ERR_TOL_LOWER) { Hermes::Mixins::Loggable::Static::info("rel_err_time = %g%% is below lower limit %g%%", rel_err_time, TIME_ERR_TOL_LOWER); Hermes::Mixins::Loggable::Static::info("Increasing time step from %g to %g s.", time_step, time_step * TIME_STEP_INC_RATIO); time_step *= TIME_STEP_INC_RATIO; delete ref_dp; continue; } else { Hermes::Mixins::Loggable::Static::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 */ Hermes::Mixins::Loggable::Static::info("Spatial adaptivity step %d.", as); // Project the fine mesh solution onto the coarse mesh. MeshFunctionSharedPtr<complex> sln(new Solution<complex>); Hermes::Mixins::Loggable::Static::info("Projecting fine mesh solution on coarse mesh for error estimation."); OGProjection<complex> ogProjection; ogProjection.project_global(space, ref_sln, sln); // Show spatial error. sprintf(title, "Spatial error est, spatial adaptivity step %d", as); MeshFunctionSharedPtr<complex> space_error_fn(new DiffFilter<complex>(Hermes::vector<MeshFunctionSharedPtr<complex> >(ref_sln, sln))); space_error_view.set_title(title); space_error_view.show_mesh(false); MeshFunctionSharedPtr<double> abs_space(new RealFilter(space_error_fn)); MeshFunctionSharedPtr<double> abs_sef(new AbsFilter(abs_space)); space_error_view.show(abs_sef); // Calculate element errors and spatial error estimate. Hermes::Mixins::Loggable::Static::info("Calculating spatial error estimate."); Adapt<complex> adaptivity(space); double err_rel_space = errorCalculator.get_total_error_squared() * 100; // Report results. Hermes::Mixins::Loggable::Static::info("ndof: %d, ref_ndof: %d, err_rel_space: %g%%", Space<complex>::get_num_dofs(space), Space<complex>::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 { Hermes::Mixins::Loggable::Static::info("Adapting the coarse mesh."); done = adaptivity.adapt(&selector); // Increase the counter of performed adaptivity steps. as++; } // Clean up. delete ref_dp; } while (done == false); // Visualize the solution and mesh-> char title[100]; sprintf(title, "Solution - real part, Time %3.2f s", current_time); sview_real.set_title(title); sprintf(title, "Solution - imaginary part, Time %3.2f s", current_time); sview_imag.set_title(title); MeshFunctionSharedPtr<double> real(new RealFilter(ref_sln)); MeshFunctionSharedPtr<double> imag(new ImagFilter(ref_sln)); sview_real.show(real); sview_imag.show(imag); sprintf(title, "Mesh, time %g s", current_time); ord_view.set_title(title); ord_view.show(space); // Copy last reference solution into psi_time_prev. psi_time_prev->copy(ref_sln); // Increase current time and counter of time steps. current_time += time_step; ts++; } while (current_time < T_FINAL); // Wait for all views to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(butcher_table_type); if (bt.is_explicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage explicit R-K method.", bt.get_size()); if (bt.is_diagonally_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage diagonally implicit R-K method.", bt.get_size()); if (bt.is_fully_implicit()) Hermes::Mixins::Loggable::Static::info("Using a %d-stage fully implicit R-K method.", bt.get_size()); // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("square.mesh", &mesh); // Initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Convert initial condition into a Solution<std::complex<double> >. CustomInitialCondition psi_time_prev(&mesh); Solution<std::complex<double> > psi_time_new(&mesh); // Initialize the weak formulation. double current_time = 0; CustomWeakFormGPRK wf(h, m, g, omega); // Initialize boundary conditions. DefaultEssentialBCConst<std::complex<double> > bc_essential("Bdy", 0.0); EssentialBCs<std::complex<double> > bcs(&bc_essential); // Create an H1 space with default shapeset. H1Space<std::complex<double> > space(&mesh, &bcs, P_INIT); int ndof = space.get_num_dofs(); Hermes::Mixins::Loggable::Static::info("ndof = %d", ndof); // Initialize the FE problem. DiscreteProblem<std::complex<double> > dp(&wf, &space); // Initialize views. ScalarView sview_real("Solution - real part", new WinGeom(0, 0, 600, 500)); ScalarView sview_imag("Solution - imaginary part", new WinGeom(610, 0, 600, 500)); sview_real.fix_scale_width(80); sview_imag.fix_scale_width(80); // Initialize Runge-Kutta time stepping. RungeKutta<std::complex<double> > runge_kutta(&wf, &space, &bt); // Time stepping: int ts = 1; int nstep = (int)(T_FINAL/time_step + 0.5); for(int ts = 1; ts <= nstep; ts++) { // Perform one Runge-Kutta time step according to the selected Butcher's table. Hermes::Mixins::Loggable::Static::info("Runge-Kutta time step (t = %g s, time step = %g s, stages: %d).", current_time, time_step, bt.get_size()); try { runge_kutta.setTime(current_time); runge_kutta.setTimeStep(time_step); runge_kutta.rk_time_step_newton(&psi_time_prev, &psi_time_new); } catch(Exceptions::Exception& e) { e.printMsg(); throw Hermes::Exceptions::Exception("Runge-Kutta time step failed"); } // Show the new time level solution. char title[100]; sprintf(title, "Solution - real part, Time %3.2f s", current_time); sview_real.set_title(title); sprintf(title, "Solution - imaginary part, Time %3.2f s", current_time); sview_imag.set_title(title); RealFilter real(&psi_time_new); ImagFilter imag(&psi_time_new); sview_real.show(&real); sview_imag.show(&imag); // Copy solution for the new time step. psi_time_prev.copy(&psi_time_new); // Increase current time and time step counter. current_time += time_step; ts++; } // Wait for the view to be closed. View::wait(); return 0; }
int main(int argc, char* argv[]) { // Choose a Butcher's table or define your own. ButcherTable bt(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()); // Load the mesh. Mesh mesh; MeshReaderH2D mloader; mloader.load("wall.mesh", &mesh); // Perform initial mesh refinements. for(int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); mesh.refine_towards_boundary(BDY_RIGHT, 2); mesh.refine_towards_boundary(BDY_FIRE, INIT_REF_NUM_BDY); // Initialize essential boundary conditions (none). EssentialBCs<double> bcs; // Initialize an H1 space with default shapeset. H1Space<double> space(&mesh, &bcs, P_INIT); int ndof = Space<double>::get_num_dofs(&space); info("ndof = %d.", ndof); // Previous and next time level solutions. ConstantSolution<double> sln_time_prev(&mesh, TEMP_INIT); ZeroSolution sln_time_new(&mesh); ConstantSolution<double> time_error_fn(&mesh, 0.0); // Initialize the weak formulation. double current_time = 0; CustomWeakFormHeatRK wf(BDY_FIRE, BDY_AIR, ALPHA_FIRE, ALPHA_AIR, RHO, HEATCAP, TEMP_EXT_AIR, TEMP_INIT, ¤t_time); // Initialize the FE problem. DiscreteProblem<double> dp(&wf, &space); // Initialize views. ScalarView Tview("Temperature", new WinGeom(0, 0, 1500, 400)); Tview.fix_scale_width(40); ScalarView eview("Temporal error", new WinGeom(0, 450, 1500, 400)); eview.fix_scale_width(40); // Graph for time step history. SimpleGraph time_step_graph; info("Time step history will be saved to file time_step_history.dat."); // Initialize Runge-Kutta time stepping. RungeKutta<double> runge_kutta(&dp, &bt, matrix_solver_type); // Time stepping loop: int ts = 1; do { // Perform one Runge-Kutta time step according to the selected Butcher's table. info("Runge-Kutta time step (t = %g s, tau = %g s, stages: %d).", current_time, time_step, bt.get_size()); bool jacobian_changed = false; bool verbose = true; try { runge_kutta.rk_time_step_newton(current_time, time_step, &sln_time_prev, &sln_time_new, &time_error_fn, !jacobian_changed, false, verbose); } catch(Exceptions::Exception& e) { e.printMsg(); error("Runge-Kutta time step failed"); } // Plot error function. char title[100]; sprintf(title, "Temporal error, t = %g", current_time); eview.set_title(title); AbsFilter abs_tef(&time_error_fn); eview.show(&abs_tef, HERMES_EPS_VERYHIGH); // Calculate relative time stepping error and decide whether the // time step can be accepted. If not, then the time step size is // reduced and the entire time step repeated. If yes, then another // check is run, and if the relative error is very low, time step // is increased. double rel_err_time = Global<double>::calc_norm(&time_error_fn, HERMES_H1_NORM) / Global<double>::calc_norm(&sln_time_new, HERMES_H1_NORM) * 100; info("rel_err_time = %g%%", rel_err_time); if (rel_err_time > TIME_TOL_UPPER) { info("rel_err_time above upper limit %g%% -> decreasing time step from %g to %g and restarting time step.", TIME_TOL_UPPER, time_step, time_step * TIME_STEP_DEC_RATIO); time_step *= TIME_STEP_DEC_RATIO; continue; } if (rel_err_time < TIME_TOL_LOWER) { info("rel_err_time = below lower limit %g%% -> increasing time step from %g to %g", TIME_TOL_UPPER, time_step, time_step * TIME_STEP_INC_RATIO); time_step *= TIME_STEP_INC_RATIO; } // Add entry to the timestep graph. time_step_graph.add_values(current_time, time_step); time_step_graph.save("time_step_history.dat"); // Update time. current_time += time_step; // Show the new time level solution. sprintf(title, "Time %3.2f s", current_time); Tview.set_title(title); Tview.show(&sln_time_new); // Copy solution for the new time step. sln_time_prev.copy(&sln_time_new); // Increase counter of time steps. ts++; } while (current_time < T_FINAL); // Wait for the view to be closed. View::wait(); return 0; }