VPUBLIC void Vpower(int *nx, int *ny, int *nz, int *iz, int *ilev, int *ipc, double *rpc, double *ac, double *cc, double *w1, double *w2, double *w3, double *w4, double *eigmax, double *eigmax_model, double *tol, int *itmax, int *iters, int *iinfo) { int lev, level; double denom, fac, rho, oldrho, error, relerr; /// @todo Just use a constant definition of PI here double pi = 4.0 * atan( 1.0 ); // Utility variables int skipIters = 0; double alpha; MAT2(iz, 50, 1); WARN_UNTESTED; // Recover level information level = 1; lev = (*ilev - 1) + level; // Seed vector: random to contain all components Vaxrand(nx, ny, nz, w1); Vazeros(nx, ny, nz, w2); Vazeros(nx, ny, nz, w3); Vazeros(nx, ny, nz, w4); // Compute raleigh quotient with the seed vector denom = Vxnrm2(nx, ny, nz, w1); fac = 1.0 / denom; Vxscal(nx, ny, nz, &fac, w1); Vmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6,lev)), RAT(ac, VAT2(iz, 7, lev)), RAT(cc, VAT2(iz, 1,lev)), w1, w2); oldrho = Vxdot(nx, ny, nz, w1, w2); // I/O if (oldrho == 0.0) { if (*iinfo > 3) { Vnm_print(2, "POWER: iter: estimate = %d %g\n", *iters, oldrho); } rho = oldrho; } else { // Main iteration *iters = 0; while(1) { (*iters)++; // Apply the matrix A Vmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT(ac, VAT2(iz, 7, lev)), RAT(cc, VAT2(iz, 1, lev)), w1, w2); Vxcopy(nx, ny, nz, w2, w1); // Normalize the new vector denom = Vxnrm2(nx, ny, nz, w1); fac = 1.0 / denom; Vxscal(nx, ny, nz, &fac, w1); // Compute the new raleigh quotient Vmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), w1, w2); rho = Vxdot(nx, ny, nz, w1, w2); // Stopping test *** // w2=A*x, w1=x, stop = 2-norm(A*x-lamda*x) Vxcopy(nx, ny, nz, w1, w3); Vxcopy(nx, ny, nz, w2, w4); Vxscal(nx, ny, nz, &rho, w3); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, w3, w4); error = Vxnrm2(nx, ny, nz, w4); relerr = VABS(rho - oldrho ) / VABS( rho ); // I/O if (*iinfo > 3) { Vnm_print(2, "POWER: iters =%d\n", *iters); Vnm_print(2, " error =%g\n", error); Vnm_print(2, " relerr =%g\n", relerr); Vnm_print(2, " rho =%g\n", rho); } if( relerr < *tol || *iters == *itmax) break; oldrho = rho; } } // Return some stuff *** *eigmax = rho; fac = VPOW(2.0, *ilev - 1); *eigmax_model = fac * (6.0 - 2.0 * VCOS((*nx - 2) * pi / (*nx - 1)) - 2.0 * VCOS((*ny - 2) * pi / (*ny - 1))); }
VPUBLIC void Vnewton(int *nx, int *ny, int *nz, double *x, int *iz, double *w0, double *w1, double *w2, double *w3, int *istop, int *itmax, int *iters, int *ierror, int *nlev, int *ilev, int *nlev_real, int *mgsolv, int *iok, int *iinfo, double *epsiln, double *errtol, double *omega, int *nu1, int *nu2, int *mgsmoo, double *cprime, double *rhs, double *xtmp, int *ipc, double *rpc, double *pc, double *ac, double *cc, double *fc, double *tru) { int level, lev; int itmax_s, iters_s, ierror_s, iok_s, iinfo_s, istop_s; double errtol_s, ord, bigc; double rsden, rsnrm, orsnrm; double xnorm_old, xnorm_new, damp, xnorm_med, xnorm_den; double rho_max, rho_min, rho_max_mod, rho_min_mod, errtol_p; int iter_d, itmax_d, mode, idamp, ipkey; int itmax_p, iters_p, iok_p, iinfo_p; // Utility and temproary parameters double alpha; MAT2(iz, 50, 1); // Recover level information level = 1; lev = (*ilev - 1) + level; // Do some i/o if requested if (*iinfo > 1) { VMESSAGE3("Starting: (%d, %d, %d)", *nx, *ny, *nz); } if (*iok != 0) { Vprtstp(*iok, -1, 0.0, 0.0, 0.0); } /************************************************************** *** note: if (iok!=0) then: use a stopping test. *** *** else: use just the itmax to stop iteration. *** ************************************************************** *** istop=0 most efficient (whatever it is) *** *** istop=1 relative residual *** *** istop=2 rms difference of successive iterates *** *** istop=3 relative true error (provided for testing) *** **************************************************************/ // Compute denominator for stopping criterion if (*istop == 0) { rsden = 1.0; } else if (*istop == 1) { // Compute initial residual with zero initial guess // this is analogous to the linear case where one can // simply take norm of rhs for a zero initial guess Vazeros(nx, ny, nz, w1); Vnmresid(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT( fc, VAT2(iz, 1, lev)), w1, w2, w3); rsden = Vxnrm1(nx, ny, nz, w2); } else if (*istop == 2) { rsden = VSQRT( *nx * *ny * *nz); } else if (*istop == 3) { rsden = Vxnrm2(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev))); } else if (*istop == 4) { rsden = Vxnrm2(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev))); } else if (*istop == 5) { Vnmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT(tru, VAT2(iz, 1, lev)), w1, w2); rsden = VSQRT(Vxdot(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev)), w1)); } else { VABORT_MSG1("Bad istop value: %d\n", *istop); } if (rsden == 0.0) { rsden = 1.0; VWARN_MSG0(rsden != 0, "rhs is zero"); } rsnrm = rsden; orsnrm = rsnrm; if (*iok != 0) { Vprtstp(*iok, 0, rsnrm, rsden, orsnrm); } /********************************************************************* *** begin newton iteration *********************************************************************/ // Now compute residual with the initial guess Vnmresid(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT( fc, VAT2(iz, 1, lev)), RAT( x, VAT2(iz, 1, lev)), w0, w2); xnorm_old = Vxnrm1(nx, ny, nz, w0); if (*iok != 0) { xnorm_den = rsden; } else { xnorm_den = xnorm_old; } /********************************************************************* *** begin the loop *********************************************************************/ // Setup for the looping VMESSAGE0("Damping enabled"); idamp = 1; *iters = 0; //30 while(1) { (*iters)++; // Save iterate if stop test will use it on next iter if (*istop == 2) { Vxcopy(nx, ny, nz, RAT(x, VAT2(iz, 1, lev)), RAT(tru, VAT2(iz, 1, lev))); } // Compute the current jacobian system and rhs ipkey = VAT(ipc, 10); Vgetjac(nx, ny, nz, nlev_real, iz, ilev, &ipkey, x, w0, cprime, rhs, cc, pc); // Determine number of correct digits in current residual // Algorithm 5.3 in the thesis, test version (1') // Global-superlinear convergence bigc = 1.0; ord = 2.0; /* NAB 06-18-01: If complex problems are not converging, set this to * machine epsilon. This makes it use the exact jacobian rather than * the appropriate form (as here) */ errtol_s = VMIN2((0.9 * xnorm_old), (bigc * VPOW(xnorm_old, ord))); VMESSAGE1("Using errtol_s: %f", errtol_s); // Do a linear multigrid solve of the newton equations Vazeros(nx, ny, nz, RAT(xtmp, VAT2(iz, 1, lev))); itmax_s = 1000; istop_s = 0; iters_s = 0; ierror_s = 0; // NAB 06-18-01 -- What this used to be: iok_s = 0; iinfo_s = 0; if ((*iinfo >= 2) && (*ilev == 1)) iok_s = 2; // What it's changed to: if (*iinfo >= 2) iinfo_s = *iinfo; iok_s = 2; // End of NAB hack. Vmvcs(nx, ny, nz, xtmp, iz, w0, w1, w2, w3, &istop_s, &itmax_s, &iters_s, &ierror_s, nlev, ilev, nlev_real, mgsolv, &iok_s, &iinfo_s, epsiln, &errtol_s, omega, nu1, nu2, mgsmoo, ipc, rpc, pc, ac, cprime, rhs, tru); /************************************************************** *** note: rhs and cprime are now available as temp vectors *** **************************************************************/ // If damping is still enabled -- doit if (idamp == 1) { // Try the correction Vxcopy(nx, ny, nz, RAT(x, VAT2(iz, 1, lev)), w1); damp = 1.0; Vxaxpy(nx, ny, nz, &damp, RAT(xtmp, VAT2(iz, 1, lev)), w1); Vnmresid(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT( fc, VAT2(iz, 1, lev)), w1, w0, RAT(rhs, VAT2(iz, 1, lev))); xnorm_new = Vxnrm1(nx, ny, nz, w0); // Damping is still enabled -- doit damp = 1.0; iter_d = 0; itmax_d = 10; mode = 0; VMESSAGE1("Attempting damping, relres = %f", xnorm_new / xnorm_den); while(iter_d < itmax_d) { if (mode == 0) { if (xnorm_new < xnorm_old) { mode = 1; } } else if (xnorm_new > xnorm_med) { break; } // Keep old soln and residual around, and its norm Vxcopy(nx, ny, nz, w1, w2); Vxcopy(nx, ny, nz, w0, w3); xnorm_med = xnorm_new; // New damped correction, residual, and its norm Vxcopy(nx, ny, nz, RAT(x, VAT2(iz, 1, lev)), w1); damp = damp / 2.0; Vxaxpy(nx, ny, nz, &damp, RAT(xtmp, VAT2(iz, 1, lev)), w1); Vnmresid(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT( fc, VAT2(iz, 1, lev)), w1, w0, RAT(rhs, VAT2(iz, 1, lev))); xnorm_new = Vxnrm1(nx, ny, nz, w0); // Next iter... iter_d = iter_d + 1; VMESSAGE1("Attempting damping, relres = %f", xnorm_new / xnorm_den); } Vxcopy(nx, ny, nz, w2, RAT(x, VAT2(iz, 1, lev))); Vxcopy(nx, ny, nz, w3, w0); xnorm_new = xnorm_med; xnorm_old = xnorm_new; VMESSAGE1("Damping accepted, relres = %f", xnorm_new / xnorm_den); // Determine whether or not to disable damping if ((iter_d - 1) == 0) { VMESSAGE0("Damping disabled"); idamp = 0; } } else { // Damping is disabled -- accept the newton step damp = 1.0; Vxaxpy(nx, ny, nz, &damp, RAT(xtmp, VAT2(iz, 1, lev)), RAT(x, VAT2(iz, 1, lev))); Vnmresid(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), RAT( fc, VAT2(iz, 1, lev)), RAT( x, VAT2(iz, 1, lev)), w0, RAT(rhs, VAT2(iz, 1, lev))); xnorm_new = Vxnrm1(nx, ny, nz, w0); xnorm_old = xnorm_new; } // Compute/check the current stopping test *** if (iok != 0) { orsnrm = rsnrm; if (*istop == 0) { rsnrm = xnorm_new; } else if (*istop == 1) { rsnrm = xnorm_new; } else if (*istop == 2) { Vxcopy(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev)), w1); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, RAT(x, VAT2(iz, 1, lev)), w1); rsnrm = Vxnrm1(nx, ny, nz, w1); } else if (*istop == 3) { Vxcopy(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev)), w1); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, RAT(x, VAT2(iz, 1, lev)), w1); rsnrm = Vxnrm2(nx, ny, nz, w1); } else if (*istop == 4) { Vxcopy(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev)), w1); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, RAT(x, VAT2(iz, 1, lev)), w1); rsnrm = Vxnrm2(nx, ny, nz, w1); } else if (*istop == 5) { Vxcopy(nx, ny, nz, RAT(tru, VAT2(iz, 1, lev)), w1); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, RAT(x, VAT2(iz, 1, lev)), w1); Vnmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), w1, w2, w3); rsnrm = VSQRT(Vxdot(nx, ny, nz, w1, w2)); } else { VABORT_MSG1("Bad istop value: %d", *istop); } Vprtstp(*iok, *iters, rsnrm, rsden, orsnrm); if ((rsnrm/rsden) <= *errtol) break; } // Check iteration count *** if (*iters >= *itmax) break; } // Condition estimate of final jacobian if (*iinfo > 2) { Vnm_print(2, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); Vnm_print(2, "% Vnewton: JACOBIAN ANALYSIS ==> (%d, %d, %d)\n", *nx, *ny, *nz ); // Largest eigenvalue of the jacobian matrix Vnm_print(2, "% Vnewton: Power calculating rho(JAC)\n"); itmax_p = 1000; errtol_p = 1.0e-4; iters_p = 0; iinfo_p = *iinfo; Vpower(nx, ny, nz, iz, ilev, ipc, rpc, ac, cprime, w0, w1, w2, w3, &rho_max, &rho_max_mod, &errtol_p, &itmax_p, &iters_p, &iinfo_p); Vnm_print(2, "% Vnewton: power iters = %d\n", iters_p); Vnm_print(2, "% Vnewton: power eigmax = %d\n", rho_max); Vnm_print(2, "% Vnewton: power (MODEL) = %d\n", rho_max_mod); // Smallest eigenvalue of the system matrix A *** Vnm_print(2, "% Vnewton: ipower calculating lambda_min(JAC)...\n"); itmax_p = 1000; errtol_p = 1.0e-4; iters_p = 0; iinfo_p = *iinfo; Vazeros(nx, ny, nz, xtmp); Vipower(nx, ny, nz, xtmp, iz, w0, w1, w2, w3, rhs, &rho_min, &rho_min_mod, &errtol_p, &itmax_p, &iters_p, nlev, ilev, nlev_real, mgsolv, &iok_p, &iinfo_p, epsiln, errtol, omega, nu1, nu2, mgsmoo, ipc, rpc, pc, ac, cprime, tru); Vnm_print(2, "% Vnewton: ipower iters = %d\n", iters_p); Vnm_print(2, "% Vnewton: ipower eigmin = %d\n", rho_min); Vnm_print(2, "% Vnewton: ipower (MODEL) = %d\n", rho_min_mod); // Condition number estimate Vnm_print(2, "% Vnewton: condition number = %f\n", (double)rho_max / rho_min); Vnm_print(2, "% Vnewton: condition (MODEL) = %f\n", (double)rho_max_mod / rho_min_mod); Vnm_print(2, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); } }
VPUBLIC void Vipower(int *nx,int *ny,int *nz, double *u, int *iz, double *w0, double *w1, double *w2, double *w3, double *w4, double *eigmin, double *eigmin_model, double *tol, int *itmax, int *iters, int *nlev, int *ilev, int *nlev_real, int *mgsolv, int *iok, int *iinfo, double *epsiln, double *errtol, double *omega, int *nu1, int *nu2, int *mgsmoo, int *ipc, double *rpc, double *pc, double *ac, double *cc, double *tru) { int level, lev; double denom, fac, rho, oldrho; double error, relerr, errtol_s; int itmax_s, iters_s, ierror_s, iok_s, iinfo_s, istop_s; int nu1_s, nu2_s, mgsmoo_s; /// @todo Just use a constant definition of PI here double pi = 4.0 * atan( 1.0 ); // Utility variables double alpha; MAT2(iz, 50, 1); WARN_UNTESTED; // Recover level information level = 1; lev = (*ilev - 1) + level; // Seed vector: random to contain all components Vaxrand(nx, ny, nz, w1); Vazeros(nx, ny, nz, w2); Vazeros(nx, ny, nz, w3); Vazeros(nx, ny, nz, w4); Vazeros(nx, ny, nz, RAT(w0, VAT2(iz, 1, lev))); Vazeros(nx, ny, nz, RAT( u, VAT2(iz, 1, lev))); // Compute raleigh quotient with the seed vector *** denom = Vxnrm2(nx, ny, nz, w1); fac = 1.0 / denom; Vxscal(nx, ny, nz, &fac, w1); Vmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT( ac, VAT2(iz, 7, lev)), RAT( cc, VAT2(iz, 1, lev)), w1, w2); oldrho = Vxdot(nx, ny, nz, w1, w2); // I/O if (oldrho == 0.0) { if (*iinfo > 3) { Vnm_print(2, "Vipower: iters=%d\n", *iters); Vnm_print(2, " estimate=%f\n", oldrho); } rho = oldrho; } else { //main iteration *iters = 0; while (1) { (*iters)++; // Apply the matrix A^{-1} (using MG solver) itmax_s = 100; iters_s = 0; ierror_s = 0; iok_s = 0; iinfo_s = 0; istop_s = 0; mgsmoo_s = 1; nu1_s = 1; nu2_s = 1; errtol_s = *epsiln; Vxcopy(nx, ny, nz, w1, RAT(w0, VAT2(iz, 1,lev))); Vmvcs(nx, ny, nz, u, iz, w1, w2, w3, w4, &istop_s, &itmax_s, &iters_s, &ierror_s, nlev, ilev, nlev_real, mgsolv, &iok_s, &iinfo_s, epsiln, &errtol_s, omega, &nu1_s, &nu2_s, &mgsmoo_s, ipc, rpc, pc, ac, cc, w0, tru); Vxcopy(nx, ny, nz, RAT(u, VAT2(iz, 1, lev)), w1); // Normalize the new vector denom = Vxnrm2(nx, ny, nz, w1); fac = 1.0 / denom; Vxscal(nx, ny, nz, &fac, w1); // Compute the new raleigh quotient Vmatvec(nx, ny, nz, RAT(ipc, VAT2(iz, 5, lev)), RAT(rpc, VAT2(iz, 6, lev)), RAT(ac, VAT2(iz, 7,lev)), RAT(cc, VAT2(iz, 1, lev)), w1, w2); rho = Vxdot(nx, ny, nz, w1, w2); // Stopping test // w2=A*x, w1=x, stop = 2-norm(A*x-lamda*x) *** Vxcopy(nx, ny, nz, w1, w3); Vxcopy(nx, ny, nz, w2, w4); Vxscal(nx, ny, nz, &rho, w3); alpha = -1.0; Vxaxpy(nx, ny, nz, &alpha, w3, w4); error = Vxnrm2(nx, ny, nz, w4); relerr = VABS(rho - oldrho ) / VABS( rho ); // I/O if (*iinfo > 3) { Vnm_print(2, "POWER: iters =%d\n", *iters); Vnm_print(2, " error =%g\n", error); Vnm_print(2, " relerr =%g\n", relerr); Vnm_print(2, " rho =%g\n", rho); } if (relerr < *tol || *iters == *itmax) break; oldrho = rho; } } // Return some stuff *eigmin = rho; fac = VPOW(2.0, *ilev - 1); *eigmin_model = fac * (6.0 - 2.0 * VCOS(pi / (*nx - 1)) - 2.0 * VCOS(pi / (*ny - 1)) - 2.0 * VCOS(pi / (*nz - 1))); }