int interruptible_accept( int sock, struct sockaddr *addr, socklen_t *addrlen, gboolean (*prolong)(gpointer data), gpointer prolong_data) { SELECT_ARG_TYPE readset; struct timeval tv; int nfound; if (sock < 0 || sock >= FD_SETSIZE) { g_debug("interruptible_accept: bad socket %d", sock); return EBADF; } memset(&readset, 0, sizeof(readset)); while (1) { if (!prolong(prolong_data)) { errno = 0; return -1; } FD_ZERO(&readset); FD_SET(sock, &readset); /* try accepting for 1s */ memset(&tv, 0, sizeof(tv)); tv.tv_sec = 1; nfound = select(sock+1, &readset, NULL, NULL, &tv); if (nfound < 0) { return -1; } else if (nfound == 0) { continue; } else if (!FD_ISSET(sock, &readset)) { g_debug("interruptible_accept: select malfunction"); errno = EBADF; return -1; } else { int rv = accept(sock, addr, addrlen); if (rv < 0 && errno == EAGAIN) continue; return rv; } } }
Pt2dr prolong_iter ( TIm2D<INT1,INT> & im, const Seg2d & seg, REAL step, REAL step_min, REAL Rvlim, bool BorneInf, bool etirement ) { Pt2dr p0 = seg.p0(); Pt2dr p1 = seg.p1(); while (step > step_min) { p0 = prolong(im,Seg2d(p0,p1),step,Rvlim,BorneInf,etirement); step /= 2.0; } return p0; }
bool Sol_MultigridPressure3DBase::do_vcycle(double tolerance, int max_iter, double &result_l2, double &result_linf) { clear_error(); int level; int coarse_level = _num_levels-1; apply_boundary_conditions(0); double orig_l2=0, orig_linf=0; restrict_residuals(0,0, (convergence & CONVERGENCE_CALC_L2) ? &orig_l2 : 0, (convergence & CONVERGENCE_CALC_LINF) ? &orig_linf : 0); //printf("Error Before: l2 = %f, linf = %f\n", orig_l2, orig_linf); double orig_error = (convergence & CONVERGENCE_CRITERIA_L2) ? orig_l2 : (convergence & CONVERGENCE_CRITERIA_LINF) ? orig_linf : 1e20; if (orig_error < tolerance) { if (convergence & CONVERGENCE_CALC_L2) result_l2 = orig_l2; if (convergence & CONVERGENCE_CALC_LINF) result_linf = orig_linf; return true; } for (int i_cyc = 0; i_cyc < max_iter; i_cyc++) { // going down for (level = 0; level < coarse_level; level++) { relax(level, nu1, RO_RED_BLACK); clear_zero(level+1); apply_boundary_conditions(level+1); if (level == 0) { restrict_residuals(0, 1, (convergence & CONVERGENCE_CALC_L2) ? &result_l2 : 0, (convergence & CONVERGENCE_CALC_LINF) ? &result_linf : 0); double residual = (convergence & CONVERGENCE_CRITERIA_L2) ? result_l2 : (convergence & CONVERGENCE_CRITERIA_LINF) ? result_linf : 1e20; //printf("%d: residual = %.12f\n", i_cyc, result_linf); // if we're below tolerance, or we're no longer converging, bail out if (residual < tolerance) { // last time through, we need to apply boundary condition to u[0], since we just relaxed (above), but haven't propagated changes to ghost cells. // in the case we are not finished, by the time we get back to level 0 (via coarsening & then prolongation), ghost cells would be filled in. // but since we are bailing here, we need to explicitly make ghost cells up-to-date with u. apply_boundary_conditions(0); //printf("[INFO] Sol_MultigridPressure3DBase::do_vcycle - error after %d iterations: L2 = %f (%fx), Linf = %f (%fx)\n", i_cyc, result_l2, orig_l2 / result_l2, result_linf, orig_linf / result_linf); return !any_error(); } } else restrict_residuals(level, level+1, 0, 0); } // these relaxation steps are essentially free, so do lots of them // (reference implementation uses nu1+nu2) - this is probably overkill, i need to revisit this // with a good heuristic. Inhomogeneous conditions require more iterations. int coarse_iters = max3(nx(coarse_level)*ny(coarse_level), ny(coarse_level)*nz(coarse_level), nx(coarse_level)*nz(coarse_level))/2; relax(coarse_level, coarse_iters, make_symmetric_operator ? RO_SYMMETRIC : RO_RED_BLACK); //relax(coarse_level, (nx(coarse_level)*ny(coarse_level)*nz(coarse_level))/2); // going up for (level = coarse_level-1; level >= 0; level--) { prolong(level+1, level); // don't need to relax finest grid since it will get relaxed at the beginning of the next v-cycle if (level > 0) relax(level, nu2, make_symmetric_operator ? RO_BLACK_RED : RO_RED_BLACK); } } if (!(convergence & CONVERGENCE_CRITERIA_NONE)) printf("[WARNING] Sol_MultigridPressure3DBase::do_vcycle - Failed to converge, error after: L2 = %f (%fx), Linf = %f (%fx)\n", result_l2, orig_l2 / result_l2, result_linf, orig_linf / result_linf); return false; }
bool Sol_MultigridPressure3DBase::do_fmg(double tolerance, int max_iter, double &result_l2, double &result_linf) { CPUTimer timer; timer.start(); clear_error(); int level_ncyc; int level; result_l2 = result_linf = 0; apply_boundary_conditions(0); double orig_l2=0, orig_linf=0; restrict_residuals(0,0, (convergence & CONVERGENCE_CALC_L2) ? &orig_l2 : 0, (convergence & CONVERGENCE_CALC_LINF) ? &orig_linf : 0); //printf("Error Before: l2 = %f, linf = %f\n", orig_l2, orig_linf); double orig_error = (convergence & CONVERGENCE_CRITERIA_L2) ? orig_l2 : (convergence & CONVERGENCE_CRITERIA_LINF) ? orig_linf : 1e20; if (orig_error < tolerance) { if (convergence & CONVERGENCE_CALC_L2) result_l2 = orig_l2; if (convergence & CONVERGENCE_CALC_LINF) result_linf = orig_linf; return true; } #if 0 // for testing relaxation only, enable this code block double iter_l2, iter_linf; for (int o=0; o < 100; o++) { relax(0, 10, RO_SYMMETRIC); restrict_residuals(0, 0, &iter_l2, &iter_linf); printf("error: l2 = %.12f, linf = %.12f\n", iter_l2, iter_linf); } printf("reduction: l2 = %f, linf = %f\n", orig_l2/iter_l2, orig_linf/iter_linf); result_l2 = iter_l2; result_linf = iter_linf; return true; #endif // initialize all the residuals. // we need this because in the FMG loop below, we don't necessarily start at level 0, but // rather 2 levels from the finest. Which means we first need to propagate the errors all the way down first before // beginning FMG. int coarse_level = _num_levels-1; int num_vcyc = 0; for (level = 0; level < _num_levels-1; level++) { // initialize U (solution) at next level to zero clear_zero(level+1); apply_boundary_conditions(level+1); // restrict residuals to the next level. restrict_residuals(level, level+1,0,0); } // do the full-multigrid loop for (int fine_level = _num_levels-1; fine_level >= 0 ; fine_level--) { //{ int fine_level = 0; // do a single v-cycle instead // we always do one extra v-cycle level_ncyc = (fine_level == 0) ? max_iter+1 : 1; // do ncyc v-cycle's for (int i_cyc = 0; i_cyc < level_ncyc; i_cyc++) { if (fine_level == 0) num_vcyc++; // going down for (level = fine_level; level < coarse_level; level++) { relax(level, nu1, RO_RED_BLACK); clear_zero(level+1); apply_boundary_conditions(level+1); if (level == 0) { restrict_residuals(0, 1, (convergence & CONVERGENCE_CALC_L2) ? &result_l2 : 0, (convergence & CONVERGENCE_CALC_LINF) ? &result_linf : 0); double residual = (convergence & CONVERGENCE_CRITERIA_L2) ? result_l2 : (convergence & CONVERGENCE_CRITERIA_LINF) ? result_linf : 1e20; if (ThreadManager::this_image() == 0) printf("%d: residual = %.12f,%.12f\n", i_cyc, result_linf, result_l2); // if we're below tolerance, or we're no longer converging, bail out if (residual < tolerance) { // last time through, we need to apply boundary condition to u[0], since we just relaxed (above), but haven't propagated changes to ghost cells. // in the case we are not finished, by the time we get back to level 0 (via coarsening & then prolongation), ghost cells would be filled in. // but since we are bailing here, we need to explicitly make ghost cells up-to-date with u. apply_boundary_conditions(0); timer.stop(); //printf("[ELAPSED] Sol_MultigridPressure3DBase::do_fmg - converged in %fms\n", timer.elapsed_ms()); printf("[INFO] Sol_MultigridPressure3DBase::do_fmg - error after %d iterations: L2 = %f (%fx), Linf = %f (%fx)\n", i_cyc, result_l2, orig_l2 / result_l2, result_linf, orig_linf / result_linf); global_counter_add("vcycles", num_vcyc); return !any_error(); } } else restrict_residuals(level, level+1, 0, 0); } // these relaxation steps are essentially free, so do lots of them // (reference implementation uses nu1+nu2) - this is probably overkill, i need to revisit this // with a good heuristic. Inhomogeneous conditions require more iterations. int coarse_iters = max3(nx(coarse_level)*ny(coarse_level), ny(coarse_level)*nz(coarse_level), nx(coarse_level)*nz(coarse_level))/2; relax(coarse_level, coarse_iters, make_symmetric_operator ? RO_SYMMETRIC : RO_RED_BLACK); //relax(coarse_level, (nx(coarse_level)*ny(coarse_level)*nz(coarse_level))/2); // going up for (level = coarse_level-1; level >= fine_level; level--) { prolong(level+1, level); // don't need to relax finest grid since it will get relaxed at the beginning of the next v-cycle if (level > 0) relax(level, nu2, make_symmetric_operator ? RO_BLACK_RED : RO_RED_BLACK); } } if (fine_level > 0) { // if not at finest level, need to prolong once more to next finer level for the next fine_level value prolong(fine_level, fine_level-1); } } timer.stop(); //printf("[ELAPSED] Sol_MultigridPressure3DBase::do_fmg - stopped iterations after %fms\n", timer.elapsed_ms()); if (!(convergence & CONVERGENCE_CRITERIA_NONE)) printf("[WARNING] Sol_MultigridPressure3DBase::do_fmg - Failed to converge, error after: L2 = %.12f (%fx), Linf = %.12f (%fx)\n", result_l2, orig_l2 / result_l2, result_linf, orig_linf / result_linf); return false; }