int DiracOp::Ritz(Vector **psi_all, int N_eig, Float &lambda, Float RsdR_a, Float RsdR_r, Float Rsdlam, Float Cutl_zero, int n_renorm, int Kalk_Sim, int N_min, int N_max, Float Cv_fact, int MaxCG, int ProjApsiP) { /* Local Variables */ int n_count; Complex xp; Float mu; // Double Float p2; // Double Float g2; // Double Float a; // Double Float d; // Double Float s1; // Double Float s2; // Double Float s3; // Double Float g2_0; Float del_lam; Float rsd; Float rsda_sq; Float rsdr_sq; Float ct; Float st; Float b; Float acc; int k; int nn; char *fname = "Ritz(V*,F,...)"; // Flash the LED and then turn it off //------------------------------------------------------------------ VRB.LedFlash(cname,fname,3); VRB.LedOff(cname,fname); VRB.Func(cname,fname); // Set the node checkerboard size of the fermion field //------------------------------------------------------------------ int f_size = RitzLatSize(); // Set the node checkerboard size of the fermion field //------------------------------------------------------------------ Vector *psi = (Vector *) smalloc(cname,fname, "psi", f_size * sizeof(Float)); Vector *p = (Vector *) smalloc(cname,fname, "p", f_size * sizeof(Float)); Vector *Apsi = (Vector *) smalloc(cname,fname, "Apsi", f_size * sizeof(Float)); Vector *Ap = (Vector *) smalloc(cname,fname, "Ap", f_size * sizeof(Float)); VRB.Input(cname,fname,"RsdR_a=%e RsdR_r=%e Rsdlam=%e Cv_fact=%e\n", RsdR_a,RsdR_r,Rsdlam,Cv_fact); //TIZB acc = 2.0e-6; acc = 2.0e-24; acc *= acc; rsda_sq = RsdR_a * RsdR_a; rsdr_sq = RsdR_r * RsdR_r; rsda_sq = (rsda_sq > acc) ? rsda_sq : acc; /* Make Psi_all(N_eig-1) orthogonal to the previous eigenvectors */ nn = N_eig - 1; /* First copy it into a the local psi */ psi->CopyVec(psi_all[nn], f_size); GramSchm(&psi, 1, psi_all, nn, f_size); /* Normalize */ d = sqrt(psi->NormSqGlbSum(f_size)); ct = 1.0 / d; psi->VecTimesEquFloat(ct, f_size); /* Now we can start */ /* Apsi[0] := A . Psi[0] */ RitzMat(Apsi, psi); xp = psi->CompDotProductGlbSum(Apsi, f_size); mu = psi->ReDotProductGlbSum(Apsi, f_size); /* Project to orthogonal subspace, if wanted */ /** Should not be necessary, following Kalkreuter-Simma **/ if (ProjApsiP == 1) GramSchm(&Apsi, 1, psi_all, nn, f_size); /* mu := < Psi[0] | A Psi[0] > */ mu = psi->ReDotProductGlbSum(Apsi, f_size); /* p[0] = g[0] := ( A - mu[0] ) Psi[0] = Apsi - mu psi */ lambda = mu; p->FTimesV1PlusV2(-lambda, psi, Apsi, f_size); /* g2 = p2 = |g[0]|^2 = |p[0]|^2 */ g2 = p->NormSqGlbSum(f_size); p2 = g2; g2_0 = g2; g2_0 *= Cv_fact; g2_0 = (g2_0 > acc) ? g2_0 : acc; if (ProjApsiP == 1) VRB.Result(cname,fname,"nn = %d, lambda=%g, g2=%g, g2_0=%g\n", nn, (IFloat)mu, (IFloat)g2, (IFloat)g2_0); /* IF |g[0]| <= min(RsdR_a, RsdR_r |mu[0]|) THEN RETURN; */ rsd = rsdr_sq * lambda * lambda; rsd = (rsda_sq > rsd) ? rsda_sq : rsd; if ( Kalk_Sim == 0 && N_min <= 0 && g2 <= rsd ) { /* Copy psi back into psi_all(N_eig-1) */ psi_all[nn]->CopyVec(psi, f_size); sfree(cname,fname, "Ap", Ap); sfree(cname,fname, "Apsi", Apsi); sfree(cname,fname, "p", p); sfree(cname,fname, "psi", psi); n_count = 0; return n_count; } del_lam = mu; /* FOR k FROM 1 TO MaxCG DO */ for(k = 1; k <= MaxCG; ++k) { if (k % 100 == 0){ VRB.Result(cname,fname,"nn = %d, iter=%d, lambda=%e, del_lam=%e\n", nn, k, (IFloat)mu, del_lam); VRB.Result(cname,fname, "g2/g2_0=%e/%e=Cv_fact=%e > %e\n", (IFloat)g2, (IFloat)g2_0, (IFloat)g2/g2_0, (IFloat)Cv_fact); } // if (k % 100 == 0) // VRB.Result(cname,fname,"nn = %d, lambda=%g, g2=%g, g2_0=%g\n", // nn, (IFloat)mu, (IFloat)g2, (IFloat)g2_0); /* Ap = A * p */ RitzMat(Ap, p); /* Project to orthogonal subspace, if wanted */ /** Should not be necessary, following Kalkreuter-Simma **/ if (ProjApsiP == 1) GramSchm(&Ap, 1, psi_all, nn, f_size); /* d = < p | A p > */ d = p->ReDotProductGlbSum(Ap, f_size); d = d / p2; s1 = 0.5 * (mu+d); s2 = 0.5 * (mu-d); p2 = sqrt(p2); p2 = 1.0 / p2; s3 = g2 * p2; a = (s2 > 0.0) ? s2 : -s2; if( a >= s3 ) { d = s3 / s2; d = sqrt(1.0 + d*d); a = a * d; } else { d = s2 / s3; d = sqrt(1.0 + d*d); a = s3 * d; } s2 /= a; /* Now s2 is cos(delta) */ s3 /= a; /* Now s3 is sin(delta) */ if( s2 > 0 ) { s2 = 0.5 * (1.0+s2); d = sqrt(s2); d = - d; /* Now d is sin(theta) */ s2 = -0.5 * s3 / d; /* Now s2 is cos(theta) */ } else { s2 = 0.5 * (1.0-s2); s2 = sqrt(s2); /* Now s2 is cos(theta) */ d = -0.5 * s3 / s2; /* Now d is sin(theta) */ } /* mu[k] = mu[k-1] - 2 a d^2 */ s1 = 2.0 * a * d * d; mu -= s1; lambda = mu; del_lam = s1; st = d*p2; /* Now st is sin(theta)/|p| */ ct = s2; /* Now ct is cos(theta) */ /* Psi[k] = ct Psi[k-1] + st p[k-1] */ /* Apsi[k] = ct Apsi[k-1] + st Ap */ psi->VecTimesEquFloat(ct, f_size); psi->FTimesV1PlusV2(st, p, psi, f_size); Apsi->VecTimesEquFloat(ct, f_size); Apsi->FTimesV1PlusV2(st, Ap, Apsi, f_size); /* Ap = g[k] = Apsi[k] - mu[k] Psi[k] */ Ap->FTimesV1PlusV2(-lambda, psi, Apsi, f_size); /* g2 = |g[k]|**2 = |Ap|**2 */ s1 = g2; /* Now s1 is |g[k-1]|^2 */ g2 = Ap->NormSqGlbSum(f_size); /*+ */ /* IF |g[k]| <= min(RsdR_a, RsdR_r |mu[k]|) && |del_lam| <= Rsdlam*|lambda| THEN RETURN; */ rsd = rsdr_sq * lambda * lambda; rsd = (rsda_sq > rsd) ? rsda_sq : rsd; st = Rsdlam * fabs(mu); /* old value of st is no longer needed */ /* if ( TO_REAL(g2) <= rsd && del_lam <= st ) */ if ( (Kalk_Sim == 0 && k >= N_min && (fabs(mu) < Cutl_zero || (g2 <= rsd && del_lam <= st ) ) ) || (Kalk_Sim == 1 && ( del_lam <= st || fabs(mu) < Cutl_zero || (k >= N_min && (g2 < g2_0 || k >= N_max ) ) ) ) ) { VRB.Result(cname, fname, "Converged at iter %d, lambda = %g, del_lam = %g\n", k, (IFloat)lambda, (IFloat)del_lam); VRB.Result(cname, fname, " rsd = %g, g2 = %g, g2_0 = %g\n", (IFloat)rsd, (IFloat)g2, (IFloat)g2_0); n_count = k; /* Renormalize and recompute lambda */ /* Project to orthogonal subspace */ GramSchm(&psi, 1, psi_all, nn, f_size); d = sqrt(psi->NormSqGlbSum(f_size)); ct = 1.0 / d; psi->VecTimesEquFloat(ct, f_size); d -= 1.0; VRB.Result(cname, fname, "Deviation at convergence: %g\n", (IFloat)d); /* Apsi := A . Psi */ RitzMat(Apsi, psi); /* mu := < Psi | A Psi > */ s1 = mu; mu = psi->ReDotProductGlbSum(Apsi, f_size); lambda = mu; VRB.Result(cname, fname, "Mu-s at convergence: old %g vs. nn %g\n", (IFloat)s1, (IFloat)mu); /* Copy psi back into psi_all(N_eig-1) */ psi_all[nn]->CopyVec(psi, f_size); VRB.Sfree(cname,fname, "Ap", Ap); sfree(Ap); VRB.Sfree(cname,fname, "Apsi", Apsi); sfree(Apsi); VRB.Sfree(cname,fname, "p", p); sfree(p); VRB.Sfree(cname,fname, "psi", psi); sfree(psi); // Flash the LED and then turn it on //------------------------------------------------------------------ VRB.FuncEnd(cname,fname); VRB.LedFlash(cname,fname,2); VRB.LedOn(cname,fname); return k; } /* b = beta[k] = cos(theta) |g[k]|^2 / |g[k-1]|^2 */ b = ct * g2 / s1; ct *= 0.05 * b; d = sqrt(g2); ct /= (p2*d); if( ct > 1.0 ) { /* Restart: p[k] = g[k] = Ap */ VRB.Result(cname, fname, "Restart at iter %d since beta = %g\n", k, (IFloat)b); p->CopyVec(Ap, f_size); } else { /* xp = < Psi[k] | p[k-1] > */ xp = psi->CompDotProductGlbSum(p, f_size); /* p[k] = g[k] + b (p[k-1] - xp psi[k]) */ p->CTimesV1PlusV2(-xp, psi, p, f_size); p->FTimesV1PlusV2(b, p, Ap, f_size); } if( k%n_renorm == 0 ) { /* Renormalize, and re-orthogonalize */ /* Project to orthogonal subspace */ GramSchm(&psi, 1, psi_all, nn, f_size); /* Normalize */ d = sqrt(psi->NormSqGlbSum(f_size)); ct = 1.0 / d; psi->VecTimesEquFloat(ct, f_size); d -= 1.0; if (ProjApsiP == 1) VRB.Result(cname,fname,"Deviation at iter %d: %g\n", k, (IFloat)d); /* Apsi := A . Psi */ RitzMat(Apsi, psi); /* Project to orthogonal subspace, if wanted */ /** Should not be necessary, following Kalkreuter-Simma **/ if (ProjApsiP == 1) GramSchm(&Apsi, 1, psi_all, nn, f_size); /* mu := < Psi | A Psi > */ s1 = mu; mu = psi->ReDotProductGlbSum(Apsi, f_size); if (ProjApsiP == 1) VRB.Result(cname,fname,"Mu-s at iter %d: old %g vs. new %g\n", k, (IFloat)s1, (IFloat)mu); /* g[k] = Ap = ( A - mu ) Psi */ lambda = mu; Ap->FTimesV1PlusV2(-lambda, psi, Apsi, f_size); /* g2 = |g[k]|**2 = |Ap|**2 */ g2 = Ap->NormSqGlbSum(f_size); VRB.Result(cname,fname,"g2 at iter %d: %g\n", k, (IFloat)g2); /* Project p[k] to orthogonal subspace */ GramSchm(&p, 1, psi_all, nn, f_size); /* Make p[k] orthogonal to Psi[k] */ GramSchm(&p, 1, &psi, 1, f_size); /* Make < g[k] | p[k] > = |g[k]|**2: p[k] = p_old[k] + xp g[k], xp = (g2 - < g | p_old >) / g2; g[k] = Ap */ xp = g2 - Ap->CompDotProductGlbSum(p, f_size); ct = 1.0 / g2; xp *= ct; p->CTimesV1PlusV2(xp, Ap, p, f_size); } else if (ProjApsiP == 1 && nn > 0) { /* Project psi and p to orthogonal subspace */ GramSchm(&psi, 1, psi_all, nn, f_size); GramSchm(&p, 1, psi_all, nn, f_size); } /* p2 = |p[k]|**2 */ p2 = p->NormSqGlbSum(f_size); //TIZB #if 1 if (ProjApsiP == 1) VRB.Result(cname,fname,"At iter %d, lambda = %g, del_lam = %g, g2 = %g\n", k, (IFloat)lambda, (IFloat)del_lam, (IFloat)g2); #endif } /* Copy psi back into psi_all(N_eig-1) */ psi_all[nn]->CopyVec(psi, f_size); n_count = MaxCG; VRB.Sfree(cname,fname, "Ap", Ap); sfree(Ap); VRB.Sfree(cname,fname, "Apsi", Apsi); sfree(Apsi); VRB.Sfree(cname,fname, "p", p); sfree(p); VRB.Sfree(cname,fname, "psi", psi); sfree(psi); ERR.General(cname,fname, "too many CG/Ritz iterations: %d\n",n_count); return n_count; }