bool calc_errors(Hermes::Tuple<Solution* > left, Hermes::Tuple<Solution *> right, Hermes::Tuple<double> & err_abs, Hermes::Tuple<double> & norm_vals, double & err_abs_total, double & norm_total, double & err_rel_total, Hermes::Tuple<ProjNormType> norms) { bool default_norms = false; // Checks. if(left.size() != right.size()) return false; if (norms != Hermes::Tuple<ProjNormType>()) { if(left.size() != norms.size()) return false; } else default_norms = true; // Zero the resulting Tuples. err_abs.clear(); norm_vals.clear(); // Zero the sums. err_abs_total = 0; norm_total = 0; err_rel_total = 0; // Calculation. for(unsigned int i = 0; i < left.size(); i++) { err_abs.push_back(calc_abs_error(left[i], right[i], default_norms ? HERMES_H1_NORM : norms[i])); norm_vals.push_back(calc_norm(right[i], default_norms ? HERMES_H1_NORM : norms[i])); err_abs_total += err_abs[i] * err_abs[i]; norm_total += norm_vals[i] * norm_vals[i]; } err_abs_total = sqrt(err_abs_total); norm_total = sqrt(norm_total); err_rel_total = err_abs_total / norm_total * 100.; // Everything went well, return appropriate flag. return true; }
int main(int argc, char* argv[]) { if (NUMBER_OF_EIGENVALUES > 6) error("Maximum number of eigenvalues is 6."); info("Desired number of eigenvalues: %d.", NUMBER_OF_EIGENVALUES); // Load the mesh. Mesh mesh; H2DReader mloader; mloader.load("domain.mesh", &mesh); // Perform initial mesh refinements (optional). for (int i = 0; i < INIT_REF_NUM; i++) mesh.refine_all_elements(); // Enter boundary markers. // Note: "essential" means that solution value is prescribed. BCTypes bc_types; bc_types.add_bc_dirichlet(Hermes::Tuple<int>(BDY_BOTTOM, BDY_RIGHT, BDY_TOP, BDY_LEFT)); // Enter Dirichlet boudnary values. BCValues bc_values; bc_values.add_zero(Hermes::Tuple<int>(BDY_BOTTOM, BDY_RIGHT, BDY_TOP, BDY_LEFT)); // Create an H1 space with default shapeset. H1Space space(&mesh, &bc_types, &bc_values, P_INIT); // Initialize the weak formulation for the left hand side i.e. H WeakForm wf_left, wf_right; wf_left.add_matrix_form(callback(bilinear_form_left)); wf_right.add_matrix_form(callback(bilinear_form_right)); // Initialize refinement selector. H1ProjBasedSelector selector(CAND_LIST, CONV_EXP, H2DRS_DEFAULT_ORDER); // Initialize views. ScalarView sview_1("", new WinGeom(0, 0, 350, 250)); sview_1.show_mesh(false); sview_1.fix_scale_width(60); ScalarView sview_2("", new WinGeom(360, 0, 350, 250)); sview_2.show_mesh(false); sview_2.fix_scale_width(60); ScalarView sview_3("", new WinGeom(720, 0, 350, 250)); sview_3.show_mesh(false); sview_3.fix_scale_width(60); ScalarView sview_4("", new WinGeom(0, 305, 350, 250)); sview_4.show_mesh(false); sview_4.fix_scale_width(60); ScalarView sview_5("", new WinGeom(360, 305, 350, 250)); sview_5.show_mesh(false); sview_5.fix_scale_width(60); ScalarView sview_6("", new WinGeom(720, 305, 350, 250)); sview_6.show_mesh(false); sview_6.fix_scale_width(60); OrderView oview("Polynomial orders", new WinGeom(1080, 0, 410, 350)); // DOF and CPU convergence graphs. SimpleGraph graph_dof_est, graph_cpu_est; // Time measurement. TimePeriod cpu_time; cpu_time.tick(); Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES]; // Adaptivity loop: int as = 1; bool done = false; do { info("---- Adaptivity step %d:", as); info("Solving on reference mesh."); // Construct globally refined reference mesh and setup reference space. Space* ref_space = construct_refined_space(&space); int ref_ndof = Space::get_num_dofs(ref_space); info("ref_ndof: %d.", ref_ndof); // Initialize matrices and matrix solver on referenc emesh. SparseMatrix* matrix_left = create_matrix(matrix_solver); SparseMatrix* matrix_right = create_matrix(matrix_solver); Solver* solver = create_linear_solver(matrix_solver, matrix_left); // Assemble the matrices on reference mesh. bool is_linear = true; DiscreteProblem* dp_left = new DiscreteProblem(&wf_left, ref_space, is_linear); dp_left->assemble(matrix_left); DiscreteProblem* dp_right = new DiscreteProblem(&wf_right, ref_space, is_linear); dp_right->assemble(matrix_right); // Time measurement. cpu_time.tick(); // Write matrix_left in MatrixMarket format. write_matrix_mm("mat_left.mtx", matrix_left); // Write matrix_left in MatrixMarket format. write_matrix_mm("mat_right.mtx", matrix_right); // Time measurement. cpu_time.tick(HERMES_SKIP); // Calling Python eigensolver. Solution will be written to "eivecs.dat". info("Calling Pysparse..."); char call_cmd[255]; sprintf(call_cmd, "python solveGenEigenFromMtx.py mat_left.mtx mat_right.mtx %g %d %g %d", TARGET_VALUE, NUMBER_OF_EIGENVALUES, TOL, MAX_ITER); system(call_cmd); info("Pysparse finished."); // Initializing solution vector, solution and ScalarView. double* ref_coeff_vec = new double[ref_ndof]; //Solution sln[NUMBER_OF_EIGENVALUES], ref_sln[NUMBER_OF_EIGENVALUES]; //ScalarView view("Solution", new WinGeom(0, 0, 440, 350)); // Reading solution vectors from file and visualizing. double eigenval[NUMBER_OF_EIGENVALUES]; FILE *file = fopen("eivecs.dat", "r"); char line [64]; // Maximum line size. fgets(line, sizeof line, file); // ref_ndof int n = atoi(line); if (n != ref_ndof) error("Mismatched ndof in the eigensolver output file."); fgets(line, sizeof line, file); // Number of eigenvectors in the file. int neig = atoi(line); if (neig != NUMBER_OF_EIGENVALUES) error("Mismatched number of eigenvectors in the eigensolver output file."); for (int ieig = 0; ieig < NUMBER_OF_EIGENVALUES; ieig++) { // Get next eigenvalue from the file fgets(line, sizeof line, file); // eigenval eigenval[ieig] = atof(line); // Get the corresponding eigenvector. for (int i = 0; i < ref_ndof; i++) { fgets(line, sizeof line, file); ref_coeff_vec[i] = atof(line); } // Convert coefficient vector into a Solution. Solution::vector_to_solution(ref_coeff_vec, ref_space, &(ref_sln[ieig])); // Project the fine mesh solution onto the coarse mesh. info("Projecting reference solution %d on coarse mesh.", ieig); OGProjection::project_global(&space, &(ref_sln[ieig]), &(sln[ieig]), matrix_solver); } fclose(file); delete [] ref_coeff_vec; // FIXME: Below, the adaptivity is done for the last eigenvector only, // this needs to be changed to take into account all eigenvectors. // View the coarse mesh solution and polynomial orders. char title[100]; if (NUMBER_OF_EIGENVALUES > 0) { sprintf(title, "Solution 0, val = %g", eigenval[0]); sview_1.set_title(title); sview_1.show(&(sln[0])); } if (NUMBER_OF_EIGENVALUES > 1) { sprintf(title, "Solution 1, val = %g", eigenval[1]); sview_2.set_title(title); sview_2.show(&(sln[1])); } if (NUMBER_OF_EIGENVALUES > 2) { sprintf(title, "Solution 2, val = %g", eigenval[2]); sview_3.set_title(title); sview_3.show(&(sln[2])); } if (NUMBER_OF_EIGENVALUES > 3) { sprintf(title, "Solution 3, val = %g", eigenval[3]); sview_4.set_title(title); sview_4.show(&(sln[3])); } if (NUMBER_OF_EIGENVALUES > 4) { sprintf(title, "Solution 4, val = %g", eigenval[4]); sview_5.set_title(title); sview_5.show(&(sln[4])); } if (NUMBER_OF_EIGENVALUES > 5) { sprintf(title, "Solution 5, val = %g", eigenval[5]); sview_6.set_title(title); sview_6.show(&(sln[5])); } oview.show(&space); // Calculate element errors and total error estimate. info("Calculating error estimate."); Hermes::Tuple<Space *> spaces; for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++) spaces.push_back(&space); Hermes::Tuple<ProjNormType> proj_norms; for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++) proj_norms.push_back(HERMES_H1_NORM); Adapt* adaptivity = new Adapt(spaces, proj_norms); bool solutions_for_adapt = true; Hermes::Tuple<Solution *> slns; if (NUMBER_OF_EIGENVALUES > 0) slns.push_back(&sln[0]); if (NUMBER_OF_EIGENVALUES > 1) slns.push_back(&sln[1]); if (NUMBER_OF_EIGENVALUES > 2) slns.push_back(&sln[2]); if (NUMBER_OF_EIGENVALUES > 3) slns.push_back(&sln[3]); if (NUMBER_OF_EIGENVALUES > 4) slns.push_back(&sln[4]); if (NUMBER_OF_EIGENVALUES > 5) slns.push_back(&sln[5]); Hermes::Tuple<Solution *> ref_slns; if (NUMBER_OF_EIGENVALUES > 0) ref_slns.push_back(&ref_sln[0]); if (NUMBER_OF_EIGENVALUES > 1) ref_slns.push_back(&ref_sln[1]); if (NUMBER_OF_EIGENVALUES > 2) ref_slns.push_back(&ref_sln[2]); if (NUMBER_OF_EIGENVALUES > 3) ref_slns.push_back(&ref_sln[3]); if (NUMBER_OF_EIGENVALUES > 4) ref_slns.push_back(&ref_sln[4]); if (NUMBER_OF_EIGENVALUES > 5) ref_slns.push_back(&ref_sln[5]); Hermes::Tuple<double> component_errors; double err_est_rel = adaptivity->calc_err_est(slns, ref_slns, solutions_for_adapt, HERMES_TOTAL_ERROR_REL | HERMES_ELEMENT_ERROR_REL, &component_errors) * 100; // Report results. info("ndof_coarse: %d, ndof_fine: %d.", Space::get_num_dofs(&space), Space::get_num_dofs(ref_space)); if (NUMBER_OF_EIGENVALUES > 0) info("err_est_rel[0]: %g%%", component_errors[0] * 100); if (NUMBER_OF_EIGENVALUES > 1) info("err_est_rel[1]: %g%%", component_errors[1] * 100); if (NUMBER_OF_EIGENVALUES > 2) info("err_est_rel[2]: %g%%", component_errors[2] * 100); if (NUMBER_OF_EIGENVALUES > 3) info("err_est_rel[3]: %g%%", component_errors[3] * 100); if (NUMBER_OF_EIGENVALUES > 4) info("err_est_rel[4]: %g%%", component_errors[4] * 100); if (NUMBER_OF_EIGENVALUES > 5) info("err_est_rel[5]: %g%%", component_errors[5] * 100); // Time measurement. cpu_time.tick(); // Add entry to DOF and CPU convergence graphs. graph_dof_est.add_values(Space::get_num_dofs(&space), err_est_rel); graph_dof_est.save("conv_dof_est.dat"); graph_cpu_est.add_values(cpu_time.accumulated(), err_est_rel); graph_cpu_est.save("conv_cpu_est.dat"); // If err_est too large, adapt the mesh. if (err_est_rel < ERR_STOP) done = true; else { info("Adapting coarse mesh."); Hermes::Tuple<RefinementSelectors::Selector *> selectors; for(int i = 0; i < NUMBER_OF_EIGENVALUES; i++) selectors.push_back(&selector); done = adaptivity->adapt(selectors, THRESHOLD, STRATEGY, MESH_REGULARITY); // Increase the counter of performed adaptivity steps. if (done == false) as++; } if (Space::get_num_dofs(&space) >= NDOF_STOP) done = true; // Clean up. delete solver; delete matrix_left; delete matrix_right; delete adaptivity; if(done == false) delete ref_space->get_mesh(); delete ref_space; delete dp_left; delete dp_right; } while (done == false); // Wait for all views to be closed. View::wait(); return 0; };
Adapt::Adapt(Hermes::Tuple< Space* > spaces_, Hermes::Tuple<ProjNormType> proj_norms) : num_act_elems(-1), have_errors(false), have_coarse_solutions(false), have_reference_solutions(false) { // sanity check if (proj_norms.size() > 0 && spaces_.size() != proj_norms.size()) error("Mismatched numbers of spaces and projection types in Adapt::Adapt()."); this->num = spaces_.size(); // sanity checks error_if(this->num <= 0, "Too few components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS); error_if(this->num >= H2D_MAX_COMPONENTS, "Too many components (%d), only %d supported.", this->num, H2D_MAX_COMPONENTS); for (int i = 0; i < this->num; i++) { if (spaces_[i] == NULL) error("spaces[%d] is NULL in Adapt::Adapt().", i); this->spaces.push_back(spaces_[i]); } // reset values memset(errors, 0, sizeof(errors)); memset(form, 0, sizeof(form)); memset(ord, 0, sizeof(ord)); memset(sln, 0, sizeof(sln)); memset(rsln, 0, sizeof(rsln)); // if norms were not set by the user, set them to defaults // according to spaces if (proj_norms.size() == 0) { for (int i = 0; i < this->num; i++) { switch (spaces[i]->get_type()) { case HERMES_H1_SPACE: proj_norms.push_back(HERMES_H1_NORM); break; case HERMES_HCURL_SPACE: proj_norms.push_back(HERMES_HCURL_NORM); break; case HERMES_HDIV_SPACE: proj_norms.push_back(HERMES_HDIV_NORM); break; case HERMES_L2_SPACE: proj_norms.push_back(HERMES_L2_NORM); break; default: error("Unknown space type in Adapt::Adapt()."); } } } // assign norm weak forms according to norms selection for (int i = 0; i < this->num; i++) { switch (proj_norms[i]) { case HERMES_H1_NORM: form[i][i] = h1_form<double, scalar>; ord[i][i] = h1_form<Ord, Ord>; //printf("H1 norm.\n"); break; case HERMES_H1_SEMINORM: form[i][i] = h1_semi_form<double, scalar>; ord[i][i] = h1_semi_form<Ord, Ord>; //printf("H1 semi norm.\n"); break; case HERMES_HCURL_NORM: form[i][i] = hcurl_form<double, scalar>; ord[i][i] = hcurl_form<Ord, Ord>; //printf("Hcurl norm.\n"); break; case HERMES_HDIV_NORM: form[i][i] = hdiv_form<double, scalar>; ord[i][i] = hdiv_form<Ord, Ord>; //printf("Hdiv norm.\n"); break; case HERMES_L2_NORM: form[i][i] = l2_form<double, scalar>; ord[i][i] = l2_form<Ord, Ord>; //printf("L2 norm.\n"); break; default: error("Unknown projection type in Adapt::Adapt()."); } } }