Exemple #1
0
/** 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();
}
Exemple #2
0
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;
}
Exemple #3
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();
}