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