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()); // 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; }
// 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()) 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; }