1%%%%%%%%%%%%%%%%%%% 2% XLiFE++ is an extended library of finite elements written in C++ 3% Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin 4% 5% This program is free software: you can redistribute it and/or modify 6% it under the terms of the GNU General Public License as published by 7% the Free Software Foundation, either version 3 of the License, or 8% (at your option) any later version. 9% This program is distributed in the hope that it will be useful, 10% but WITHOUT ANY WARRANTY; without even the implied warranty of 11% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12% GNU General Public License for more details. 13% You should have received a copy of the GNU General Public License 14% along with this program. If not, see <http://www.gnu.org/licenses/>. 15%%%%%%%%%%%%%%%%%%% 16 17\subsection{Arpack++} 18 19{\lib Arpack} is a well-known collection of Fortran77 subroutines designed to solve large scale eigenvalue problems. {\lib Arpack} implements a variant of the Arnoldi process for finding eigenvalues called implicit restarted Arnoldi method (IRAM). In most cases only a compressed matrix or a matrix-vector product $y \leftarrow Ax$ must be supplied by the user.\\ 20{\lib Arpack++} is a collection of classes that offers c++ programmers an interface to {\lib Arpack}. Because the main features of {\lib Arpack} are preserved by this C++ version, an interface between {\lib Xlife++} and {\lib Arpack++} is designed to enable the use of classes of {\lib Arpack++} to solve eigen problems.\\ 21In the following section, some instructions are given on how to install Arpack++. The next section discusses briefly how to solve an eigen problem with a basic interface {\lib Xlife++ - Arpack++}. The last one describes some advanced techniques to make use of all features of {\lib Arpack++} 22 23\subsubsection{Basic Usage} 24 25Two goal motivated the development of the interface between {\lib Xlife++} and {\lib Arpack++}: simplicity and homogeneity. The intention of simplicity is to ease the use of {\lib Arpack++} from inside {\lib Xlife++}. To this end, all the complicated parametrization of {\lib Arpack++} are hidden, and solver is invoked to calculate a eigen problem with only the essential parameters. However, user can make use of other parameters of eigen solver totally, which is described in the next section. The concept of homogeneity drives the development of interface to allow users to call {\lib Arpack++} solvers like other iterative solvers. The eigensolver is called with the operator () with similar prototype to other linear solvers. From now on, we call this interface eigensolver Arpack.\\ 26Like iterative solvers, the eigensolver Arpack is initialized with default value 27\vspace{.1cm} 28\begin{lstlisting}[]{} 29// To solve standard eigenproblem A*x=l*x 30EigenSolverStdArpackpp eigenSolverStd; 31// To solve gneralized eigenproblem A*x=l*B*x 32EigenSolverGenArpackpp eigenSolverGen; 33\end{lstlisting} 34\vspace{.1cm} 35or with user-defined parameters 36\vspace{.1cm} 37\begin{lstlisting}[]{} 38// Corresponding parameters 39// EigenSolverStdArpackpp(const String& name, const Number maxOfIt, const Real epsilon) 40// name: Name of Solver; maxOfIt: maximum of iteration number; epsilon: Tolerance 41EigenSolverStdArpackpp eigenSolverStd("Standard",1000, 1e-8); 42EigenSolverGenArpackpp eigenSolverGen("Gen", 1000, 1e-10); 43\end{lstlisting} 44\vspace{.1cm} 45The following examples describe how to use eigensolver Arpack object to solve two specfic eigen problem in different calculation modes.\\ 46Supposed that matrix $A$ and matrix $B$ are {\class LargeMatrix} with size $20\times20$. These two matrices define eigen problem. And we also have vector eigenvalue and vector of eigenvector containing computation results. 47\vspace{.1cm} 48\begin{lstlisting}[]{} 49// Eigen problem size 50const Number size = 20; 51// Number of eigenvalue to retrieve 52const Number nev = 5; 53// Real sigma which is used in shift and invert mode 54Real sigma = 10.0; 55// Complex sigma which is used in shift and invert mode 56Complex csigma(-700, 20.0); 57// Real eigenvalue vector 58Vector<Real> rEigValue(size); 59// Complex eigenvalue vector 60Vector<Complex> cEigValue(size); 61// Real eigenvector vector 62std::vector<Vector<Real> > rEigVector(nev, rEigValue); 63// Complex eigenvector vector 64std::vector<Vector<Complex> > cEigVector(nev, cEigValue); 65// Standard Eigensolver 66EigenSolverStdArpackpp eigenSolverStd("Standard",1000, 1e-8); 67// Generalized Eigensolver 68EigenSolverGenArpackpp eigenSolverGen("Gen", 1000, 1e-10); 69\end{lstlisting} 70\vspace{.1cm} 71 72\paragraph*{The standard eigen problem $AX=\lambda X$} 73 74Real symmetric case: Matrix $A$ is real and symmetric\\ 75Eigenvalues and eigenvectors are always real 76\vspace{.1cm} 77\begin{lstlisting}[]{} 78//Regular mode 79eigenSolverStd(A, rEigValue, rEigVector, nev, _regular, sigma); 80out << rEigValue << std::endl; 81out << rEigVector << std::endl; 82//Shift and invert mode 83eigenSolverStd(A, rEigValue, rEigVector, nev, _shiftInv, sigma); 84out << rEigValue << std::endl; 85out << rEigVector << std::endl; 86\end{lstlisting} 87\vspace{.1cm} 88Real non-symmetric case: Matrix $A$ is real and non-symmetric\\ 89Eigenvalue and eigenvector can be complex, that's why we must use complex vector to get the results. 90\vspace{.1cm} 91\begin{lstlisting}[]{} 92//Regular mode 93eigenSolverStd(A, cEigValue, cEigVector, nev, _regular, sigma); 94out << cEigValue << std::endl; 95out << cEigVector << std::endl; 96//Shift and invert mode 97eigenSolverStd(A, cEigValue, cEigVector, nev, _shiftInv, sigma); 98out << cEigValue << std::endl; 99out <<cEigVector << std::endl; 100\end{lstlisting} 101\vspace{.1cm} 102Real non-symmetric case: Matrix $A$ is complex\\ 103Eigenvalue and eigenvector are always complex, that's why we must use complex vector to get the results. 104\vspace{.1cm} 105\begin{lstlisting}[]{} 106//Regular mode 107eigenSolverStd(A, cEigValue, cEigVector, nev, _regular, sigma); 108out << cEigValue << std::endl; 109out << cEigVector << std::endl; 110//Shift and invert mode 111eigenSolverStd(A, cEigValue, cEigVector, nev, _shiftInv, sigma); 112out << cEigValue << std::endl; 113out << cEigVector << std::endl; 114\end{lstlisting} 115\vspace{.1cm} 116 117\paragraph*{The generalized eigen problem $AX=\lambda BX$} 118 119Real symmetric case: Matrix $A$ is real and symmetric; matrix $B$ is real positive definite.\\ 120Eigenvalues and eigenvectors are always real 121\vspace{.1cm} 122\begin{lstlisting}[]{} 123//Regular mode 124eigenSolverGen(A, B, rEigValue, rEigVector, nev, _regular, sigma); 125out << rEigValue << std::endl; 126out << rEigVector << std::endl; 127//Shift and invert mode 128eigenSolverGen(A, B, rEigValue, rEigVector, nev, _shiftInv, sigma); 129out << rEigValue << std::endl; 130out << rEigVector << std::endl; 131//Buckling mode 132eigenSolverGen(A, B, rEigValue, rEigVector, nev, _buckling, sigma); 133out << rEigValue << std::endl; 134out << rEigVector << std::endl; 135//Cayley mode 136eigenSolverGen(A, B, rEigValue, rEigVector, nev, _cayley, sigma); 137out << rEigValue << std::endl; 138out << rEigVector << std::endl; 139\end{lstlisting} 140\vspace{.1cm} 141Real non-symmetric case: Matrix $A$ is real and non-symmetric; matrix $B$ is real positive definite.\\ 142Eigenvalue and eigenvector can be complex, that's why we must use complex vector to get the results. 143\vspace{.1cm} 144\begin{lstlisting}[]{} 145//Regular mode 146eigenSolverGen(A, B, cEigValue, cEigVector, nev, _regular, sigma); 147out << cEigValue << std::endl; 148out << cEigVector << std::endl; 149//Shift and invert mode using the real part of shift value 150eigenSolverGen(A, B, cEigValue, cEigVector, nev, _cplxShiftInv, 'R', Complex(-700.0, 10)); 151out << cEigValue << std::endl; 152out << cEigVector << std::endl; 153//Shift and invert mode using the imaginary part of shift value 154eigenSolverGen(A, B, cEigValue, cEigVector, nev, _cplxShiftInv, 'I', Complex(-700.0, 10)); 155out << cEigValue << std::endl; 156out << cEigVector << std::endl; 157\end{lstlisting} 158\vspace{.1cm} 159Real non-symmetric case: Matrix $A$ is complex; matrix $B$ is complex positive definite.\\ 160Eigenvalue and eigenvector are always complex, that's why we must use complex vector to get the results. 161\vspace{.1cm} 162\begin{lstlisting}[]{} 163//Regular mode 164eigenSolverGen(A, B, cEigValue, cEigVector, nev, _regular, csigma); 165out << cEigValue << std::endl; 166out << cEigVector << std::endl; 167//Shift and invert mode 168eigenSolverGen(A, B, cEigValue, cEigVector, nev, _shiftInv, csigma); 169out << cEigValue << std::endl; 170out << cEigVector << std::endl; 171\end{lstlisting} 172\vspace{.1cm} 173 174\subsubsection{Advanced Usage} 175 176Besides using the available eigensolver classes: {\class EigenSolverStdArpackpp} and {\class EigenSolverGenArpackpp}, users can also take advantage of other functions of {\lib Arpack++} by using {\lib Arpack++} object directly. 177 178\paragraph*{Interface classes between {\lib Xlife++} and {\lib Arpack++}} 179To use of {\lib Arpack++} directly from {\lib Xlife++}, users must invoke one of these following class, which play the role of interfaces between these two libraries. 180 \begin{itemize} 181\item {\class LargeMatrixArpackppStdReg} for standard eigen problem in regular mode 182\item {\class LargeMatrixArpackppStdShf} for standard eigen problem in shift and invert mode 183\item {\class LargeMatrixArpackppGenReg} for generalized eigen problem in regular mode 184\item {\class LargeMatrixArpackppGenShf} for generalized eigen problem in shift and invert, buckling and cayley mode 185\end{itemize} 186Given an {\lib Arpack++} class and a computational mode, users must 187\begin{itemize} 188\item create a {\class LargeMatrixArpackppXXX} object 189\item create an {\lib Arpack++} object defining an eigen problem and using the previous object to specify the matrix-vector needed. 190\end{itemize} 191Because {\class LargeMatrixArpackppXXX} is templated, users can instantiate it with their own class that specifies matrix-vector product. However, we highly recommend instantiate this class by taking advantage of the available class {\class LargeMatrix} of {\lib Xlife++}! 192 193\paragraph*{Using {\lib Arpack++} object} 194 195In order to use {\lib Arpack++} object, depending on specific problem, users must include at least one of the {\lib Arpack++} headers file 196\begin{lstlisting}[]{} 197#include "arssym.h" // for ARSymStdEig 198#include "argsym.h" // for ARSymGenEig 199 200#include "arsnsym.h" // for ARNonSymStdEig 201#include "argnsym.h" // for ARNonSymGenEig 202 203#include "arscomp.h" // for ARCompStdEig 204#include "argcomp.h" // for ARCompGenEig 205\end{lstlisting} 206After that, they need to define interface object, corresponding to eigen problem and calculation mode then {\lib Arpack++} object. The following example describes how to compute eigenvalue, eigenvector with {\lib Arpack++} object.\\ 207Supposed we'd like to solve a real symmetric standard problem in regular mode (corresponding {\lib Arpack++} class {\class ARSymStdEig}. Real symmetric matrix $rMatSkylineSymSym$ describes the problem is a {\class LargeMatrix}, the class interface is {\class LargeMatrixArpackppStdReg} 208\vspace{.1cm} 209\begin{lstlisting}[]{} 210 //1. Create interface object 211 LargeMatrixArpackppStdReg<Real, LargeMatrix<Real> > intMat(rMatSkylineSymSym, size); 212 213 //2. Create Arpack++ problem object 214 ARSymStdEig<Real, LargeMatrixArpackppStdReg<Real, LargeMatrix<Real> > > arProb(size, nev, &intMat, &LargeMatrixArpackppStdReg<Real, LargeMatrix<Real> >::multOPx, (char *)"LM"); 215 216 //3. Compute eigenvalues 217 Int nconv = arProb.FindEigenvalues(); 218 219 for (Int i = 0; i < nconv; ++i) { 220 out << arProb.Eigenvalue(i) << " "; 221 } 222 out << "\n"; 223 //4. Change some parameters 224 arProb.ChangeNev(nev-2); 225 arProb.ChangeTol(1.e-6); 226 227 nconv = arProb.FindEigenvectors(); 228 229 for (Int i = 0; i < nconv; ++i) { 230 out << arProb.Eigenvalue(i) << " "; 231 } 232 out << "\n"; 233 234 //4. Retrieve eigenVector 235 Real* eigenVec_p = 0; 236 for (Int i = 0; i < nconv; ++i) { 237 eigenVec_p = arProb.RawEigenvector(i); 238 out << "Eigenvector [" << i << "] :" ; 239 for (Int j = 0; j < size; j++) { 240 out << *eigenVec_p << " "; 241 eigenVec_p++; 242 } 243 out << "\n"; 244 } 245 246 out << "\n"; 247\end{lstlisting} 248\vspace{.1cm} 249 250