/* * Copyright(C) 1999-2020, 2023 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * * See packages/seacas/LICENSE for details */ #include "prototypes.h" #include #include /* Finds first extended eigenpair of system corresponding to tridiagonal T using using Rafael's bisection technique. */ void get_extval(double *alpha, /* j-vector of Lanczos scalars (using elements 1 to j) */ double *beta, /* (j+1)-vector of " " (has 0 element but using 1 to j-1) */ int j, /* number of Lanczos iterations taken */ double ritzval, /* Ritz value */ double *s, /* Ritz vector (length n, re-computed in this routine) */ double eigtol, /* tolerance on eigenpair */ double wnorm_g, /* W-norm of n-vector g, the rhs in the extended eig. problem */ double sigma, /* the norm constraint on the extended eigenvector */ double *extval, /* the extended eigenvalue this routine computes */ double *v, /* the j-vector solving the extended eig problem in T */ double *work1, /* j-vector of workspace */ double *work2 /* j-vector of workspace */ ) { extern int DEBUG_EVECS; /* debug flag for eigen computation */ double lambda_low; /* lower bound on extended eval */ double lambda_high; /* upper bound on extended eval */ double tol; /* bisection tolerance */ double norm_v; /* norm of the extended T eigenvector v */ double lambda; /* the parameter that iterates to extval */ int cnt; /* debug iteration counter */ double diff; /* distance between lambda limits */ /* Compute the Ritz vector */ Tevec(alpha, beta - 1, j, ritzval, s); /* Shouldn't happen, but just in case ... */ if (wnorm_g == 0.0) { *extval = ritzval; cpvec(v, 1, j, s); if (DEBUG_EVECS > 0) { printf("Degenerate extended eigenvector problem (g = 0).\n"); } return; /* ... not really an extended eigenproblem; just return Ritz pair */ } /* Set up the bisection parameters */ lambda_low = ritzval - wnorm_g / sigma; lambda_high = ritzval - (wnorm_g / sigma) * s[1]; lambda = 0.5 * (lambda_low + lambda_high); tol = eigtol * eigtol * (1 + fabs(lambda_low) + fabs(lambda_high)); if (DEBUG_EVECS > 2) { printf("Computing extended eigenpairs of T\n"); printf(" target norm_v (= sigma) %g\n", sigma); printf(" bisection tolerance %g\n", tol); } if (DEBUG_EVECS > 3) { printf(" lambda iterates to the extended eigenvalue\n"); printf(" lambda_low lambda lambda_high norm_v\n"); } /* Bisection loop - iterate until norm constraint is satisfied */ cnt = 1; diff = 2 * tol; while (diff > tol) { lambda = 0.5 * (lambda_low + lambda_high); tri_solve(alpha, beta, j, lambda, v, wnorm_g, work1, work2); norm_v = ch_norm(v, 1, j); if (DEBUG_EVECS > 3) { printf("%2i %18.16f %18.16f %18.16f %g\n", cnt++, lambda_low, lambda, lambda_high, norm_v); } if (norm_v <= sigma) { lambda_low = lambda; } if (norm_v >= sigma) { lambda_high = lambda; } diff = lambda_high - lambda_low; } /* Return the extended eigenvalue (eigvec is automatically returned) */ *extval = lambda; }