/** Nonadaptive solver.*/ void solveNonadaptive(Mesh &mesh, NonlinSystem &nls, Solution &Cp, Solution &Ci, Solution &phip, Solution &phii) { begin_time(); //VectorView vview("electric field [V/m]", 0, 0, 600, 600); ScalarView Cview("Concentration [mol/m3]", 0, 0, 800, 800); ScalarView phiview("Voltage [V]", 650, 0, 600, 600); #ifdef CONT_OUTPUT phiview.show(&phii); Cview.show(&Ci); Cview.wait_for_keypress(); #endif Solution Csln, phisln; for (int n = 1; n <= NSTEP; n++) { #ifdef VERBOSE info("\n---- Time step %d ----", n); #endif int it = 1; double res_l2_norm; do { #ifdef VERBOSE info("\n -------- Time step %d, Newton iter %d --------\n", n, it); #endif it++; nls.assemble(); nls.solve(2, &Csln, &phisln); res_l2_norm = nls.get_residuum_l2_norm(); #ifdef VERBOSE info("Residuum L2 norm: %g\n", res_l2_norm); #endif Ci.copy(&Csln); phii.copy(&phisln); } while (res_l2_norm > NEWTON_TOL); #ifdef CONT_OUTPUT phiview.show(&phii); Cview.show(&Ci); #endif phip.copy(&phii); Cp.copy(&Ci); } verbose("\nTotal run time: %g sec", end_time()); Cview.show(&Ci); phiview.show(&phii); //MeshView mview("small.mesh", 100, 30, 800, 800); //mview.show(&mesh); View::wait(); }
int main (int argc, char* argv[]) { // load the mesh file Mesh Cmesh, phimesh, basemesh; H2DReader mloader; #ifdef CIRCULAR mloader.load("../circular.mesh", &basemesh); basemesh.refine_all_elements(0); basemesh.refine_towards_boundary(TOP_MARKER, 2); basemesh.refine_towards_boundary(BOT_MARKER, 4); MeshView mview("Mesh", 0, 600, 400, 400); mview.show(&basemesh); #else mloader.load("../small.mesh", &basemesh); basemesh.refine_all_elements(1); //basemesh.refine_all_elements(1); // when only p-adapt is used //basemesh.refine_all_elements(1); // when only p-adapt is used basemesh.refine_towards_boundary(TOP_MARKER, REF_INIT); //basemesh.refine_towards_boundary(BOT_MARKER, (REF_INIT - 1) + 8); // when only p-adapt is used basemesh.refine_towards_boundary(BOT_MARKER, REF_INIT - 1); #endif Cmesh.copy(&basemesh); phimesh.copy(&basemesh); // Spaces for concentration and the voltage H1Space Cspace(&Cmesh, C_bc_types, C_essential_bc_values, P_INIT); H1Space phispace(MULTIMESH ? &phimesh : &Cmesh, phi_bc_types, phi_essential_bc_values, P_INIT); // The weak form for 2 equations WeakForm wf(2); Solution C_prev_time, // prveious time step solution, for the time integration C_prev_newton, // solution convergin during the Newton's iteration phi_prev_time, phi_prev_newton; // Add the bilinear and linear forms // generally, the equation system is described: if (TIME_DISCR == 1) { // Implicit Euler. wf.add_vector_form(0, callback(Fc_euler), H2D_ANY, Tuple<MeshFunction*>(&C_prev_time, &C_prev_newton, &phi_prev_newton)); wf.add_vector_form(1, callback(Fphi_euler), H2D_ANY, Tuple<MeshFunction*>(&C_prev_newton, &phi_prev_newton)); wf.add_matrix_form(0, 0, callback(J_euler_DFcDYc), H2D_UNSYM, H2D_ANY, &phi_prev_newton); wf.add_matrix_form(0, 1, callback(J_euler_DFcDYphi), H2D_UNSYM, H2D_ANY, &C_prev_newton); wf.add_matrix_form(1, 0, callback(J_euler_DFphiDYc), H2D_UNSYM); wf.add_matrix_form(1, 1, callback(J_euler_DFphiDYphi), H2D_UNSYM); } else { wf.add_vector_form(0, callback(Fc_cranic), H2D_ANY, Tuple<MeshFunction*>(&C_prev_time, &C_prev_newton, &phi_prev_newton, &phi_prev_time)); wf.add_vector_form(1, callback(Fphi_cranic), H2D_ANY, Tuple<MeshFunction*>(&C_prev_newton, &phi_prev_newton)); wf.add_matrix_form(0, 0, callback(J_cranic_DFcDYc), H2D_UNSYM, H2D_ANY, Tuple<MeshFunction*>(&phi_prev_newton, &phi_prev_time)); wf.add_matrix_form(0, 1, callback(J_cranic_DFcDYphi), H2D_UNSYM, H2D_ANY, Tuple<MeshFunction*>(&C_prev_newton, &C_prev_time)); wf.add_matrix_form(1, 0, callback(J_cranic_DFphiDYc), H2D_UNSYM); wf.add_matrix_form(1, 1, callback(J_cranic_DFphiDYphi), H2D_UNSYM); } // Nonlinear solver NonlinSystem nls(&wf, Tuple<Space*>(&Cspace, &phispace)); phi_prev_time.set_exact(MULTIMESH ? &phimesh : &Cmesh, voltage_ic); C_prev_time.set_exact(&Cmesh, concentration_ic); C_prev_newton.copy(&C_prev_time); phi_prev_newton.copy(&phi_prev_time); // Project the function init_cond() on the FE space // to obtain initial coefficient vector for the Newton's method. info("Projecting initial conditions to obtain initial vector for the Newton'w method."); nls.project_global(Tuple<MeshFunction*>(&C_prev_time, &phi_prev_time), Tuple<Solution*>(&C_prev_newton, &phi_prev_newton)); //VectorView vview("electric field [V/m]", 0, 0, 600, 600); ScalarView Cview("Concentration [mol/m3]", 0, 0, 800, 800); ScalarView phiview("Voltage [V]", 650, 0, 600, 600); phiview.show(&phi_prev_time); Cview.show(&C_prev_time); char title[100]; int nstep = (int) (T_FINAL / TAU + 0.5); for (int n = 1; n <= nstep; n++) { verbose("\n---- Time step %d ----", n); bool verbose = true; // Default is false. if (!nls.solve_newton(Tuple<Solution*>(&C_prev_newton, &phi_prev_newton), NEWTON_TOL, NEWTON_MAX_ITER, verbose)) error("Newton's method did not converge."); sprintf(title, "time step = %i", n); phiview.set_title(title); phiview.show(&phi_prev_newton); Cview.set_title(title); Cview.show(&C_prev_newton); phi_prev_time.copy(&phi_prev_newton); C_prev_time.copy(&C_prev_newton); } View::wait(); return 0; }
/** Adaptive solver.*/ void solveAdaptive(Mesh &Cmesh, Mesh &phimesh, Mesh &basemesh, NonlinSystem &nls, H1Space &C, H1Space &phi, Solution &Cp, Solution &Ci, Solution &phip, Solution &phii) { char title[100]; //VectorView vview("electric field [V/m]", 0, 0, 600, 600); ScalarView Cview("Concentration [mol/m3]", 0, 0, 800, 800); ScalarView phiview("Voltage [V]", 650, 0, 600, 600); OrderView Cordview("C order", 0, 300, 600, 600); OrderView phiordview("Phi order", 600, 300, 600, 600); // Different Gnuplot graphs. // convergence graph wrt. the number of degrees of freedom GnuplotGraph graph_err; graph_err.set_captions("", "Timestep", "Error (Energy Norm)"); graph_err.add_row("Reference solution", "k", "-", "O"); // convergence graph wrt. CPU time GnuplotGraph graph_dof; graph_dof.set_captions("", "Timestep", "DOF"); graph_dof.add_row(MULTIMESH ? "multi-mesh" : "single-mesh", "k", "-", "o"); sprintf(title, "Initial iteration"); phiview.set_title(title); Cview.set_title(title); phiview.show(&phii); Cview.show(&Ci); Cordview.show(&C); phiordview.show(&phi); Solution Csln_coarse, phisln_coarse, Csln_fine, phisln_fine; int at_index = 1; //for saving screenshot for (int n = 1; n <= NSTEP; n++) { if (n % UNREF_FREQ == 0) { Cmesh.copy(&basemesh); if (MULTIMESH) { phimesh.copy(&basemesh); } C.set_uniform_order(P_INIT); phi.set_uniform_order(P_INIT); int ndofs; ndofs = C.assign_dofs(); phi.assign_dofs(ndofs); } #ifdef VERBOSE info("\n---- Time step %d ----", n); #endif int at = 0; bool done = false; double err; do { at++; at_index++; int it = 1; double res_l2_norm; if (n > 1 || at > 1) { nls.set_ic(&Csln_fine, &phisln_fine, &Ci, &phii); } else { /* No need to set anything, already set. */ nls.set_ic(&Ci, &phii, &Ci, &phii); } //Loop for coarse mesh solution do { it++; #ifdef VERBOSE info("\n -------- Time step %d, Newton iter %d --------\n", n, it); #endif nls.assemble(); nls.solve(2, &Csln_coarse, &phisln_coarse); res_l2_norm = nls.get_residuum_l2_norm(); #ifdef VERBOSE info("Residuum L2 norm: %g\n", res_l2_norm); #endif Ci.copy(&Csln_coarse); phii.copy(&phisln_coarse); } while (res_l2_norm > NEWTON_TOL_COARSE); it = 1; // Loop for fine mesh solution RefNonlinSystem rs(&nls); rs.prepare(); if (n > 1 || at > 1) { rs.set_ic(&Csln_fine, &phisln_fine, &Ci, &phii); } else { rs.set_ic(&Ci, &phii, &Ci, &phii); } do { it++; #ifdef VERBOSE info("\n -------- Time step %d, Adaptivity step %d, Newton iter %d (Fine mesh) --------\n", n, at, it); #endif rs.assemble(); rs.solve(2, &Csln_fine, &phisln_fine); res_l2_norm = rs.get_residuum_l2_norm(); #ifdef VERBOSE info("Residuum L2 norm: %g\n", res_l2_norm); #endif Ci.copy(&Csln_fine); phii.copy(&phisln_fine); } while (res_l2_norm > NEWTON_TOL_REF); // Calculate element errors and total estimate H1OrthoHP hp(2, &C, &phi); info("\n Calculating element errors\n"); err = hp.calc_error_2(&Csln_coarse, &phisln_coarse, &Csln_fine, &phisln_fine) * 100; info("Error: %g", err); if (err < ERR_STOP) { done = true; } else { hp.adapt(THRESHOLD, STRATEGY, ADAPT_TYPE); } int ndofs; ndofs = C.assign_dofs(); ndofs += phi.assign_dofs(ndofs); info("NDOFS after adapting: %d", ndofs); if (ndofs >= NDOF_STOP) { info("NDOFs reached to the max %d", NDOF_STOP); done = true; } sprintf(title, "hp-mesh (C), time level %d, adaptivity %d", n, at); Cordview.set_title(title); sprintf(title, "hp-mesh (phi), time level %d, adaptivity %d", n, at); phiordview.set_title(title); Cordview.show(&C); phiordview.show(&phi); #ifdef SCREENSHOT Cordview.save_numbered_screenshot("screenshots/Cord%03d.bmp", at_index, true); phiordview.save_numbered_screenshot("screenshots/phiord%03d.bmp", at_index, true); #endif } while (!done); phip.copy(&phii); Cp.copy(&Ci); graph_err.add_values(0, n, err); graph_err.save("error.gp"); graph_dof.add_values(0, n, C.get_num_dofs() + phi.get_num_dofs()); graph_dof.save("dofs.gp"); if (n == 1) { sprintf(title, "phi after time step %d, adjust the graph and PRESS ANY KEY", n); } else { sprintf(title, "phi after time step %d", n); } phiview.set_title(title); phiview.show(&phii); if (n == 1) { sprintf(title, "C after time step %d, adjust the graph and PRESS ANY KEY", n); } else { sprintf(title, "C after time step %d", n); } Cview.set_title(title); Cview.show(&Ci); #ifdef SCREENSHOT Cview.save_numbered_screenshot("screenshots/C%03d.bmp", n, true); phiview.save_numbered_screenshot("screenshots/phi%03d.bmp", n, true); #endif if (n == 1) { // Wait for key press, so one can go to 3D mode // which is way more informative in case of Nernst Planck Cview.wait_for_keypress(); } } View::wait(); }