Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
4.9 KiB

/*
* 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 "defs.h"
#include <math.h>
#include <stdio.h>
/* Finds needed eigenvalues of tridiagonal T using either the QL algorithm
or Sturm sequence bisection, whichever is predicted to be faster based
on a simple complexity model. If one fails (which is rare), the other
is tried. The return value is 0 if one of the routines succeeds. If they
both fail, the return value is 1, and Lanczos should compute the best
approximation it can based on previous iterations. */
int get_ritzvals(double *alpha, /* vector of Lanczos scalars */
double *beta, /* vector of Lanczos scalars */
int j, /* number of Lanczos iterations taken */
double Anorm, /* Gershgorin estimate */
double *workj, /* work vector for Sturm sequence */
double *ritz, /* array holding evals */
int d, /* problem dimension = num. eigenpairs needed */
int left_goodlim, /* number of ritz pairs checked on left end */
int right_goodlim, /* number of ritz pairs checked on right end */
double eigtol, /* tolerance on eigenpair */
double bis_safety /* bisection tolerance function divisor */
)
{
extern int DEBUG_EVECS; /* debug flag for eigen computation */
extern int WARNING_EVECS; /* warning flag for eigen computation */
int nvals_left; /* numb. evals to find on left end of spectrum */
int nvals_right; /* numb. evals to find on right end of spectrum */
double bisection_tol; /* width of interval bisection should converge to */
int pred_steps; /* predicts # of required bisection steps per eval */
int tot_pred_steps; /* predicts total # of required bisection steps */
double *ritz_sav = NULL; /* copy of ritzvals for debugging */
int bisect_flag; /* return status of bisect() */
int ql_flag; /* return status of ql() */
int local_debug; /* whether to check bisection results with ql */
/* Determine number of ritzvals to find on left and right ends */
nvals_left = max(d, left_goodlim);
nvals_right = min(j - nvals_left, right_goodlim);
/* Estimate work for bisection vs. ql assuming bisection takes 5j flops per
step, ql takes 30j^2 flops per call. (Ignore sorts, copies, addressing.) */
bisection_tol = eigtol * eigtol / bis_safety;
pred_steps = (log10(Anorm / bisection_tol) / log10(2.0)) + 1;
tot_pred_steps = (nvals_left + nvals_right) * pred_steps;
bisect_flag = ql_flag = 0;
if (5 * tot_pred_steps < 30 * j) {
if (DEBUG_EVECS > 2) {
printf(" tridiagonal solver: bisection\n");
}
/* Set local_debug = TRUE for a table checking bisection against QL. */
local_debug = FALSE;
if (local_debug) {
ritz_sav = mkvec(1, j);
cpvec(ritz_sav, 1, j, alpha);
cpvec(workj, 0, j, beta);
ql_flag = ql(ritz_sav, workj, j);
if (ql_flag != 0) {
bail("Aborting debugging procedure in get_ritzvals().\n", 1);
}
shell_sort(j, &ritz_sav[1]);
}
bisect_flag = bisect(alpha, beta, j, Anorm, workj, ritz, nvals_left, nvals_right, bisection_tol,
ritz_sav, pred_steps + 10);
if (local_debug) {
frvec(ritz_sav, 1);
}
}
else {
if (DEBUG_EVECS > 2) {
printf(" tridiagonal solver: ql\n");
}
cpvec(ritz, 1, j, alpha);
cpvec(workj, 0, j, beta);
ql_flag = ql(ritz, workj, j);
shell_sort(j, &ritz[1]);
}
if (bisect_flag != 0 && ql_flag == 0) {
if (DEBUG_EVECS > 0 || WARNING_EVECS > 0) {
strout("WARNING: Sturm bisection of T failed; switching to QL.\n");
}
if (DEBUG_EVECS > 1 || WARNING_EVECS > 1) {
if (bisect_flag == 1) {
strout(" - failure detected in sturmcnt().\n");
}
if (bisect_flag == 2) {
strout(" - maximum number of bisection steps reached.\n");
}
}
cpvec(ritz, 1, j, alpha);
cpvec(workj, 0, j, beta);
ql_flag = ql(ritz, workj, j);
shell_sort(j, &ritz[1]);
}
if (ql_flag != 0 && bisect_flag == 0) {
if (DEBUG_EVECS > 0 || WARNING_EVECS > 0) {
strout("WARNING: QL failed for T; switching to Sturm bisection.\n");
}
bisect_flag = bisect(alpha, beta, j, Anorm, workj, ritz, nvals_left, nvals_right, bisection_tol,
ritz_sav, pred_steps + 3);
}
if (bisect_flag != 0 && ql_flag != 0) {
if (DEBUG_EVECS > 0 || WARNING_EVECS > 0) {
return (1); /* can't recover; bail out with error code */
}
}
return (0); /* ... things seem ok. */
}