54 Compute_eigenvectors(true)
75 Vector<std::complex<double>>& eigenvalue,
77 const bool& do_adjoint_problem)
79 if (do_adjoint_problem)
81 throw OomphLibError(
"Solving an adjoint eigenproblem is not currently "
82 "implemented for ARPACK.",
83 OOMPH_CURRENT_FUNCTION,
84 OOMPH_EXCEPTION_LOCATION);
100 int iparam[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
102 int ipntr[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
108 n = problem_pt->
ndof();
118 std::ostringstream warning_stream;
119 warning_stream <<
"Number of requested eigenvalues " << nev <<
"\n"
120 <<
"is greater than the number of Arnoldi vectors:" << ncv
129 warning_stream <<
"Increasing number of Arnoldi vectors to " << ncv
130 <<
"\n but you may want to increase further using\n"
131 <<
"ARPACK::narnoldi()\n"
132 <<
"which will also get rid of this warning.\n";
135 warning_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
139 int lworkl = 3 * ncv * ncv + 6 * ncv;
142 double** v =
new double*;
143 *v =
new double[ncv * n];
148 double* resid =
new double[n];
150 double* workd =
new double[3 * n];
152 double* workl =
new double[lworkl];
185 std::ostringstream error_stream;
187 <<
"Spectrum is set to an invalid value. It must be 0, 1 or -1\n"
191 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
234 bool LOOP_FLAG =
true;
284 for (
int i = 0;
i < n;
i++)
286 x[
i] = workd[ipntr[0] - 1 +
i];
304 for (
int i = 0;
i < n;
i++)
306 workd[ipntr[1] - 1 +
i] = rhs[
i];
315 for (
int i = 0;
i < n;
i++)
317 rhs[
i] = workd[ipntr[2] - 1 +
i];
332 for (
int i = 0;
i < n;
i++)
334 workd[ipntr[1] - 1 +
i] = rhs[
i];
342 for (
int i = 0;
i < n;
i++)
344 x[
i] = workd[ipntr[0] - 1 +
i];
348 for (
int i = 0;
i < n;
i++)
350 workd[ipntr[1] - 1 +
i] = rhs[
i];
358 oomph_info <<
"Error with _naupd, info = '" << info << std::endl;
361 oomph_info <<
"Not enough memory " << std::endl;
381 oomph_info <<
"Maximum number of iterations reached." << std::endl;
385 oomph_info <<
"No shifts could be applied during implicit Arnoldi "
386 <<
"update, try increasing NCV. " << std::endl;
398 int nconv = iparam[4];
413 double* eval_real =
new double[nconv + 1];
415 double* eval_imag =
new double[nconv + 1];
418 double* workev =
new double[3 * ncv];
420 double** z =
new double*;
421 *z =
new double[(nconv + 1) * n];
466 oomph_info <<
"Error with _neupd, info = " << ierr << std::endl;
472 eigenvalue.resize(nconv);
473 for (
int j = 0; j < nconv; j++)
476 std::complex<double> eigen(eval_real[j], eval_imag[j]);
478 eigenvalue[j] = eigen;
484 eigenvector.resize(nconv);
485 for (
int j = 0; j < nconv; j++)
488 for (
int i = 0;
i < n;
i++)
490 eigenvector[j][
i] = z[0][j * n +
i];
496 eigenvector.resize(0);
504 oomph_info <<
" Size of the matrix is " << n << std::endl;
505 oomph_info <<
" The number of Ritz values requested is " << nev
507 oomph_info <<
" The number of Arnoldi vectors generated (NCV) is "
509 oomph_info <<
" What portion of the spectrum: " << which << std::endl;
510 oomph_info <<
" The number of converged Ritz values is " << nconv
513 <<
" The number of Implicit Arnoldi update iterations taken is "
514 << iparam[2] << std::endl;
515 oomph_info <<
" The number of OP*x is " << iparam[8] << std::endl;
516 oomph_info <<
" The convergence criterion is " << tol << std::endl;
569 Vector<std::complex<double>>& alpha_eval,
575 char no_eigvecs[2] =
"N";
578 char eigvecs[2] =
"V";
581 int n = problem_pt->
ndof();
584 bool use_padding =
false;
599 double* M =
new double[padded_n * padded_n];
600 double* A =
new double[padded_n * padded_n];
619 for (
int i = 0;
i < n; ++
i)
621 for (
int j = 0; j < n; ++j)
623 M[index] = temp_M(j,
i);
624 A[index] = temp_AsigmaM(j,
i);
640 double* alpha_r =
new double[n];
641 double* alpha_i =
new double[n];
642 double* beta =
new double[n];
644 double* vec_left =
new double[1];
645 const int leading_dimension_vec_left = 1;
646 double* vec_right =
new double[n * n];
647 const int leading_dimension_vec_right = n;
650 std::vector<double> work(1, 0.0);
654 const int query_workspace = -1;
660 LAPACK_DGGEV(no_eigvecs,
671 leading_dimension_vec_left,
673 leading_dimension_vec_right,
685 int required_workspace = (int)work[0];
687 work.resize(required_workspace);
690 LAPACK_DGGEV(no_eigvecs,
701 leading_dimension_vec_left,
703 leading_dimension_vec_right,
716 alpha_eval.resize(n);
718 eigenvector_aux.resize(n);
721 for (
int i = 0;
i < n; ++
i)
724 alpha_eval[
i] = std::complex<double>(
Sigma_real + alpha_r[
i], alpha_i[
i]);
725 beta_eval[
i] = beta[
i];
736 for (
int k = 0; k < n; ++k)
738 eigenvector_aux[
i][k] = vec_right[
i * n + k];
766 Vector<std::complex<double>>& eigenvalue,
768 const bool& do_adjoint_problem)
770 if (do_adjoint_problem)
772 throw OomphLibError(
"Solving an adjoint eigenproblem is not currently "
773 "implemented for LAPACK_QZ.",
774 OOMPH_CURRENT_FUNCTION,
775 OOMPH_EXCEPTION_LOCATION);
782 problem_pt, n_eval, alpha_eval, beta_eval, eigenvector_aux);
785 unsigned n = problem_pt->
ndof();
786 eigenvalue.resize(n);
787 for (
unsigned i = 0;
i < n; ++
i)
792 eigenvalue[
i] = std::complex<double>(alpha_eval[
i].real() / beta_eval[
i],
793 alpha_eval[
i].imag() / beta_eval[
i]);
813 Vector<std::complex<double>>& alpha_eval,
817 const bool& do_adjoint_problem)
819 if (do_adjoint_problem)
821 throw OomphLibError(
"Solving an adjoint eigenproblem is not currently "
822 "implemented for LAPACK_QZ.",
823 OOMPH_CURRENT_FUNCTION,
824 OOMPH_EXCEPTION_LOCATION);
830 problem_pt, n_eval, alpha_eval, beta_eval, eigenvector_aux);
843 unsigned n = problem_pt->
ndof();
844 eigenvector_real.resize(n);
845 eigenvector_imag.resize(n);
846 unsigned eval_count = 0;
847 while (eval_count < n)
850 if (alpha_eval[eval_count].imag() == 0.0)
856 for (
unsigned j = 0; j < n; ++j)
858 eigenvector_real[eval_count][j] = eigenvector_aux[eval_count][j];
859 eigenvector_imag[eval_count][j] = 0.0;
871 if ((beta_eval[eval_count] != 0.0) &&
872 (beta_eval[eval_count + 1] != 0.0))
874 std::complex<double> lambda_this =
875 alpha_eval[eval_count] / beta_eval[eval_count];
877 std::complex<double> lambda_next =
878 alpha_eval[eval_count + 1] / beta_eval[eval_count + 1];
881 if (fabs(lambda_this.imag() + lambda_next.imag()) >
884 std::ostringstream error_stream;
885 error_stream <<
"Non-zero imaginary part of eigenvalue "
886 << eval_count <<
" : " << lambda_this.imag()
889 <<
"isn't the negative of its subsequent value : "
890 << lambda_next.imag() << std::endl
891 <<
"Their sum " << (lambda_this.imag() + lambda_next.imag())
892 <<
" is greater than Tolerance_for_ccness_check = "
895 OOMPH_CURRENT_FUNCTION,
896 OOMPH_EXCEPTION_LOCATION);
898 if (fabs(lambda_this.real() - lambda_next.real()) >
901 std::ostringstream error_stream;
902 error_stream <<
"Real parts of complex eigenvalue " << eval_count
903 <<
" : " << lambda_this.real() << std::endl;
905 <<
" doesn't agree with its supposed-to-be cc counterpart : "
906 << lambda_next.real() << std::endl
907 <<
"Their difference "
908 << (lambda_this.real() - lambda_next.real())
909 <<
" is greater than Tolerance_for_ccness_check = "
912 OOMPH_CURRENT_FUNCTION,
913 OOMPH_EXCEPTION_LOCATION);
926 for (
unsigned j = 0; j < n; ++j)
928 eigenvector_real[eval_count][j] = eigenvector_aux[eval_count][j];
929 eigenvector_imag[eval_count][j] = eigenvector_aux[eval_count + 1][j];
931 eigenvector_real[eval_count + 1][j] = eigenvector_aux[eval_count][j];
932 eigenvector_imag[eval_count + 1][j] =
933 -eigenvector_aux[eval_count + 1][j];
949 Vector<std::complex<double>>& eigenvalue,
955 std::stringstream error_stream;
956 error_stream <<
"Non-zero shift Sigma_real = " <<
Sigma_real
957 <<
" ignored in LAPACK_QZ::find_eigenvalues\n";
959 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
965 char no_eigvecs[2] =
"N";
968 char eigvecs[2] =
"V";
975 double* M_linear =
new double[2 * n * n];
976 double* A_linear =
new double[2 * n * n];
980 for (
int i = 0;
i < n; ++
i)
982 for (
int j = 0; j < n; ++j)
984 M_linear[index] = M(j,
i).real();
985 A_linear[index] = A(j,
i).real();
987 M_linear[index] = M(j,
i).imag();
988 A_linear[index] = A(j,
i).imag();
994 double* alpha =
new double[2 * n];
995 double* beta =
new double[2 * n];
997 double* vec_left =
new double[2];
998 const int leading_dimension_vec_left = 1;
999 double* vec_right =
new double[2 * n * n];
1000 const int leading_dimension_vec_right = n;
1003 std::vector<double> work(2, 0.0);
1007 const int query_workspace = -1;
1008 std::vector<double> rwork(8 * n, 0.0);
1014 LAPACK_ZGGEV(no_eigvecs,
1024 leading_dimension_vec_left,
1026 leading_dimension_vec_right,
1040 int required_workspace = (int)work[0];
1042 work.resize(2 * required_workspace);
1045 LAPACK_ZGGEV(no_eigvecs,
1071 eigenvalue.resize(n);
1072 eigenvector.resize(n);
1075 for (
int i = 0;
i < n; ++
i)
1078 std::complex<double> num(alpha[2 *
i], alpha[2 *
i + 1]);
1079 std::complex<double> den(beta[2 *
i], beta[2 *
i + 1]);
1083 eigenvalue[
i] = num / den;
1086 eigenvector[
i].resize(n);
1089 for (
int k = 0; k < n; ++k)
1091 eigenvector[
i][k] = std::complex<double>(
1092 vec_right[2 *
i * n + 2 * k], vec_right[2 *
i * n + 2 * k + 1]);
int Spectrum
Integer to set whether the real, imaginary or magnitude is required to be small or large.
int NArnoldi
Number of Arnoldi vectors to compute.
void solve_eigenproblem_legacy(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &do_adjoint_problem=false)
Solve the eigen problem.
LinearSolver * Linear_solver_pt
Pointer to a linear solver.
virtual ~ARPACK()
Destructor, delete the linear solver.
bool Small
Boolean to set which part of the spectrum left (default) or right of the shifted value.
LinearSolver * Default_linear_solver_pt
Pointer to a default linear solver.
bool Compute_eigenvectors
Boolean to indicate whether or not to compute the eigenvectors.
A class for compressed row matrices. This is a distributable object.
Abstract base class for matrices of complex doubles – adds abstract interfaces for solving,...
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
A vector in the mathematical sense, initially developed for linear algebra type applications....
void clear()
wipes the DoubleVector
Base class for all EigenProblem solves. This simply defines standard interfaces so that different sol...
double Sigma_real
Double value that represents the real part of the shift in shifted eigensolvers.
void ZGGEV_error(const int &info, const int &n)
Provide diagonstic for ZGGEV error return.
void solve_eigenproblem_helper(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &alpha, Vector< double > &beta, Vector< DoubleVector > &eigenvector)
Helper function called from legacy and updated version from "raw" lapack code.
void find_eigenvalues(const ComplexMatrixBase &A, const ComplexMatrixBase &M, Vector< std::complex< double >> &eigenvalue, Vector< Vector< std::complex< double >>> &eigenvector)
Find the eigenvalues of a complex generalised eigenvalue problem specified by . Note: the (real) shif...
void solve_eigenproblem(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &alpha, Vector< double > &beta, Vector< DoubleVector > &eigenvector_real, Vector< DoubleVector > &eigenvector_imag, const bool &do_adjoint_problem=false)
Solve the real eigenproblem that is assembled by elements in a mesh in a Problem object....
void DGGEV_error(const int &info, const int &n)
Provide diagonstic for DGGEV error return.
double Tolerance_for_ccness_check
Tolerance for checking complex conjugateness of eigenvalues.
void solve_eigenproblem_legacy(Problem *const &problem_pt, const int &n_eval, Vector< std::complex< double >> &eigenvalue, Vector< DoubleVector > &eigenvector, const bool &do_adjoint_problem=false)
Use LAPACK QZ to solve the real eigenproblem that is assembled by elements in a mesh in a Problem obj...
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
Solver: Takes pointer to problem and returns the results vector which contains the solution of the li...
virtual void enable_resolve()
Enable resolve (i.e. store matrix and/or LU decomposition, say) Virtual so it can be overloaded to pe...
virtual void resolve(const DoubleVector &rhs, DoubleVector &result)
Resolve the system defined by the last assembled jacobian and the rhs vector. Solution is returned in...
void disable_doc_time()
Disable documentation of solve times.
virtual void disable_resolve()
Disable resolve (i.e. store matrix and/or LU decomposition, say) This function simply resets an inter...
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
virtual void get_eigenproblem_matrices(CRDoubleMatrix &mass_matrix, CRDoubleMatrix &main_matrix, const double &shift=0.0)
Get the matrices required by a eigensolver. If the shift parameter is non-zero the second matrix will...
unsigned long ndof() const
Return the number of dofs.
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
//////////////////////////////////////////////////////////////////////////// ////////////////////////...
A slight extension to the standard template vector class so that we can include "graceful" array rang...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...