1. Arpack++ classesExamples
2. Interface classes between Melina++ and Arpack++
3. Link between classes
4. Usage
5. Warning
1. Test program
2. Guidelines to create classes
Standard eigenvalue problem of prototype Mass u = l u3. Post-processing
Generalized eigenvalue problem of prototype Stiff u = l Mass u
The classTermMatrixAR
is an interface class between Melina++ and Arpack++ designed to enable the use of Arpack++'s own classes to solve eigenvalue problems in the context of a Melina++ program. This class is derived from Melina++ classTermMatrix
and holds informations related to matrices.
It is used along with its companion class TermVectorAR.This class is an abstract base class so that the classes to be used in the program are the classes that are derived from this one (see 2. below).
1. Arpack++ classes
The Arpack++ classes intended to be used are those that require user-defined matrix-vector products (see documentation filearpack++/doc/arpackpp.doc.gz
in the archive available at http://www.ime.unicamp.br/~chico/arpack++/).
They are : ARSymStdEig, ARNonSymStdEig, ARCompStdEig, ARSymGenEig, ARNonSymGenEig and ARCompGenEig.Thus, several public functions
MultXXX
are provided to compute the different matrix-vector products needed by the Arpack++ classes. For that, some Melina++ own functions are used.
2. Interface classes between Melina++ and Arpack++
Several user interface classes have been created, allowing to use Arpack++ classes in a rather straightforward way. They are :
- TermMatrixStdReg and TermMatrixStdShf for standard eigenvalue problems,
- TermMatrixSymGenReg, TermMatrixGenReg, TermMatrixGenShf, TermMatrixGenBuc, TermMatrixGenCay and TermMatrixGenCsh for generalized eigenvalue problems.
The hierarchy of the classes is the following:
(TermMatrixAR) > 1. TermMatrixStdReg > 2. TermMatrixStdShf > (TermMatrixGen) > 1. TermMatrixSymGenReg > 2. TermMatrixGenReg > 3. TermMatrixGenShf > 4. TermMatrixGenBuc > 5. TermMatrixGenCay > 6. TermMatrixGenCshTermMatrixAR
and TermMatrixGen are abstract classes.Given an Arpack++ class and a computational mode, the user has to:
a. create a TermMatrixXXX object defining the matrices involved,
b. create an Arpack++ object defining the problem and using the previous object to specify the matrix-vector products needed.
The name of the matrix-vector product functions are the generic names used in the Arpack++ documentation so that the user's task reduces nearly to a copy-paste operation. Those names areMultOPx, MultAx
andMultBx
.
3. Link between classes
Here follows the list of the Arpack++ classes along with the name of the matrix-vector product functions and the interface constructor to be used according to the nature of the problem. The arguments of the interface constructors are given under each of them in a short way ; some of them have two forms.Standard eigenvalue problem Au = l u
=================================================================================== Kind of problem Computational Matrix-vector Name of member Interface (Arpack++ class) mode products required functions to use constructor =================================================================================== real symmetric | (ARSymStdEig) | Regular y <- A * x MultOPx TermMatrixStdReg | (1. A_u) real non |----------------------------------------------------------------- symmetric | (ARNonSymStdEig)| Shift | and invert y <- inv(A-sigma I)*x MultOPx TermMatrixStdShf complex | (2. A_u_s, u_AsI) (ARCompStdEig) | ===================================================================================Generalized eigenvalue problem Au = l Bu
The matrix A defines the kind of problem.
If A is real, the matrix B is required to be real symmetric positive semi-definite, except in regular mode where it should be positive definite. In bukling mode, the real symmetric matrix A is required to be positive semi-definite while B is only required to be real symmetric indefinite.
If A is complex, the matrix B is required to be hermitian positive semi-definite, except in regular mode where it should be positive definite. Notice that B may still be real and symmetric.=================================================================================== Kind of problem Computational Matrix-vector Name of member Interface (Arpack++ class) mode products required functions to use constructor =================================================================================== | Regular y <- inv(B)*A * x ; MultOPx TermMatrixSymGenReg | x <- A * x (1. A_B_u) | y <- B * x MultBx |----------------------------------------------------------------- | Shift y <- inv(A-sigma B)*x MultOPx TermMatrixGenShf real symmetric | and invert y <- B * x MultBx (3. A_B_u_s, B_u_AsB) (ARSymGenEig) |----------------------------------------------------------------- | Buckling y <- inv(A-sigma B)*x MultOPx TermMatrixGenBuc | y <- A * x MultBx (4. A_B_u_s) |----------------------------------------------------------------- | y <- inv(A-sigma B)*x MultOPx TermMatrixGenCay | Cayley y <- A * x MultAx (5. A_B_u_s) | y <- B * x MultBx =================================================================================== | Regular y <- inv(B)*A * x MultOPx TermMatrixGenReg | y <- B * x MultBx (2. A_B_u) |----------------------------------------------------------------- real non | Real shift y <- inv(A-sigma B)*x MultOPx TermMatrixGenShf symmetric | and invert y <- B * x MultBx (3. A_B_u_s, B_u_AsB) (ARNonSymGenEig)|----------------------------------------------------------------- | Complex shift y <- Inv(A-sigma B)*x MultOPx TermMatrixGenCsh | and invert y <- A * x MultAx (6. A_B_u_p_sr_si) | y <- B * x MultBx | Nota: Inv(A-sigma B) is real{inv(A-sigma B)} or imag{inv(A-sigma B)} =================================================================================== | Regular y <- inv(B)*A * x MultOPx TermMatrixGenReg | y <- B * x MultBx (2. A_B_u) complex |----------------------------------------------------------------- (ARCompGenEig) | Shift y <- inv(A-sigma B)*x MultOPx TermMatrixGenShf | and invert y <- B * x MultBx (3. A_B_u_s, B_u_AsB) ===================================================================================
4. Usage
In the user program, one should include the fileTermMatrixAR.h++
, which is done by the mean of another header file present in Melina++ distribution:using namespace std; // mandatory here for the moment... // (modification of Melina++ header files still to do) #include "Term_s.h++"and additionally, at least one of the Arpack++ header files:
#include "arssym.h" // for ARSymStdEig #include "argsym.h" // for ARSymGenEig #include "arsnsym.h" // for ARNonSymStdEig #include "argnsym.h" // for ARNonSymGenEig #include "arscomp.h" // for ARCompStdEig #include "argcomp.h" // for ARCompGenEigFor example, if we want to solve a real symmetric generalized problem in buckling mode (Arpack++ class ARSymGenEig), we will have to specify two matrix-vector products. The first product must compute
inv(A-sigma B)*x
and corresponds to the function calledMultOPx
. The second product must computeA * x
and corresponds to the function calledMultBx
(this is not an error, in all other casesMultBx
is supposed to computeB * x
). In the documentation, the description of the constructor in shift and invert and buckling modes is:ARSymGenEig(char InvertMode, int n, int nev, FOP* objOP, TypeOPx MultOPx, FB* objB , TypeBx MultBx , FLOAT sigma, ... + optional parameters ...)
Thus, in our program, once matrices
A
,B
and vectoru
have been defined (see Remark 1), and assumingA
is real symmetric positive semi-definite andB
is symmetric, we'll have to write something like the following:// Define interface objet, choosing Buckling mode: real_t sigma = ...; TermMatrixGenBuc IntMat(A,B,u,sigma); // Define Arpack++ problem: int n = IntMat.GetN(); // Dimension of the problem int nev = ...; // Number of eigenvalues to be computed ARSymGenEig< real_t, TermMatrixGenBuc, TermMatrixGenBuc > ArProb('B', n, nev, &IntMat, &TermMatrixGenBuc::MultOPx, &IntMat, &TermMatrixGenBuc::MultBx, sigma); // Compute eigenvalues and eigenvectors int nconv = ArProb.FindEigenvectors(); // Extract ith eigenvalue and eigenvector, 0 <= i < nconv for (int i = 0; i < nconv; i++) { real_t lambda = ArProb.Eigenvalue(i); TermVectorAR v (u,ArProb.RawEigenvector(i)); // use lambda and v ... }Remark 1:
The vectoru
is a vector associated to the problem. It is typically the right-hand side vector but it may be any vector term compatible with the problem and defined on the same domain. For the computation of the eigenvalues, it is only used to carry the numbering structure of the unknowns.Remark 2:
The member functionGetN()
is better to be used to determine the dimension of the problem. It returnsN*dim
, whereN
is the number of unknowns anddim
the number of components of each unknown.Remark 3:
With the original version of Arpack++, one cannot include Arpack++ header files in more than one single translation unit because at link time, duplicated symbols would be detected. Since this may be a problem, our own installation procedure of the Arpack++ library takes care of this issue by adding an implementation file that should be specified at link time (the scriptmmake
is provided for that).
5. Warning
The interface matrix and the Arpack++ problem are two objects which are tightly linked and thus should remain coherent.Once the Arpack++ problem is fully defined, the parameters describing the problem should not be modified. Thus, in particular, the Arpack++ functions
ChangeShift
andNoShift
MUST NOT BE USED because the matrix-vector product (defined in the interface object) would not reflect the change of the shift. For the same reason, theSetXXXMode
functions, which are intended to define the problem starting from an object built by the default constructor, should not be used in this context. The functionsChangeMultBx
andChangeMultOPx
should not be used either since the matrix-vector product functions are provided by the interface object.If the shift has to be changed, then the user MUST create a new interface object (
TermMatrixXXX
object) and use it to define a new Arpack++ problem.Note however that the
SetXXXMode
functions can be used in the definition phase of the problem. After the Arpack++ problem object has been defined, one can modify all the other non critical parameters by the mean of the functionsChangeMaxit, ChangeNcv, ChangeNev, ChangeTol
andChangeWhich
.
1. Test program
Consider the following test program, given only to show the classes in a plausible environment:#include "MELINA.h++" // this does #include "Term_s.h++" #include "arssym.h" // for ARSymStdEig int main () { init(); // Melina++ initialization Mesh mesh = Square(1,quadrangle,0.,1.); // 1 element in the unit square GeomDomain& Omega(mesh.domain("Omega")); // called Omega // Define Finite Element Space over Omega FESpace V_h (Omega,Lagrange,P1,"H_1(Omega)"); // Define Unknown FEUnknown u_h ("u_h",V_h); // Define Terms to be computed on Mesh's GeomDomains FETermMatrix Mass (Omega, u_h, u_h); NVTermVector uzero (Omega, u_h); Omega.computation(0); /* Standard eigenvalue problem Mass * u = l * u solved in regular mode -------------------------------------------------------------------- */ int nev = 2; // Number of eigenvalues to be computed // 1. create interface object TermMatrixStdReg< real_t > IntMat(Mass, uzero); // 2. create Arpack++ problem object ARSymStdEig< real_t, TermMatrixStdReg< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdReg< real_t >::MultOPx, (char *)"LM"); // 3. compute eigenvalues int nconv = ArProb.FindEigenvalues(); std::cout << std::endl; for (int i = 0; i < nconv; i++) { std::cout << ArProb.Eigenvalue(i) << std::endl; } }This program follows the specifications given in the previous section, in the case of a standard eigenvalue problem. It prints:0.0833333 0.25A matrixMass
and a vectoruzero
related to a finite element spaceV_h
are defined. Their values are computed by the statementOmega.computation(0);
.
The vectoruzero
is defined only to carry the finite element structure enabling correct evaluations of matrix-vector products inside the interface class TermMatrixStdReg. Its value is not significant.
2. Guidelines to create classes
In the following, we just give the statements needed to create the interface and Arpack++ objects in all cases, assuming the matrices have the correct type and properties.
The standard eigenvalue problem is always Mass * u = l * u.
The generalized eigenvalue problem is always Stiff * u = l * Mass * u, provided a finite element matrixStiff
has been defined, for example by writing:FETermMatrix Stiff (Omega, grad(u_h), grad(u_h));The tool vectoruzero
is assumed to be created as shown above. The user just has to adapt his program by replacing these names by his own ones.In all the cases, the requested eigenvalues are those of Largest Magnitude (argument
(char *)"LM"
). The interface object is called IntMat and the Arpack++ object is called ArProb.Standard eigenvalue problem of prototype Mass u = l u
Real symmetric case{// Regular mode TermMatrixStdReg< real_t > IntMat(Mass, uzero); ARSymStdEig< real_t, TermMatrixStdReg< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdReg< real_t >::MultOPx, (char *)"LM"); } {// Shift and invert mode. 1st constructor real_t sigma = 0.2; // for example TermMatrixStdShf< real_t > IntMat(Mass, uzero, sigma); ARSymStdEig< real_t, TermMatrixStdShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< real_t >::MultOPx, sigma, (char *)"LM"); } {// Shift and invert mode. 2nd constructor real_t sigma = 0.2; // for example TermMatrix MsI(Mass-sigma*identity(Mass)); TermMatrixStdShf< real_t > IntMat(uzero, MsI); ARSymStdEig< real_t, TermMatrixStdShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< real_t >::MultOPx, sigma, (char *)"LM"); }Real non symmetric case{// Regular mode TermMatrixStdReg< real_t > IntMat(Mass, uzero); ARNonSymStdEig< real_t, TermMatrixStdReg< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdReg< real_t >::MultOPx, (char *)"LM"); } {// Shift and invert mode. 1st constructor real_t sigma = 0.2; // for example TermMatrixStdShf< real_t > IntMat(Mass, uzero, sigma); ARNonSymStdEig< real_t, TermMatrixStdShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< real_t >::MultOPx, sigma, (char *)"LM"); } {// Shift and invert mode. 2nd constructor real_t sigma = 0.2; // for example TermMatrix MsI(Mass-sigma*identity(Mass)); TermMatrixStdShf< real_t > IntMat(uzero, MsI); ARNonSymStdEig< real_t, TermMatrixStdShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< real_t >::MultOPx, sigma, (char *)"LM"); }Complex case{// Regular mode TermMatrixStdReg< complex_t > IntMat(Mass, uzero); ARCompStdEig< real_t, TermMatrixStdReg< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdReg< complex_t >::MultOPx, (char *)"LM"); } {// Shift and invert mode. 1st constructor complex_t sigmac = 0.2; // for example TermMatrixStdShf< complex_t > IntMat(Mass, uzero, sigmac); ARCompStdEig< real_t, TermMatrixStdShf< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< complex_t >::MultOPx, sigmac, (char *)"LM"); } {// Shift and invert mode. 2nd constructor complex_t sigmac = 0.2; // for example TermMatrix MsI(Mass-sigmac*identity(Mass)); TermMatrixStdShf< complex_t > IntMat(uzero, MsI); ARCompStdEig< real_t, TermMatrixStdShf< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixStdShf< complex_t >::MultOPx, sigmac, (char *)"LM"); }Generalized eigenvalue problem of prototype Stiff u = l Mass u
Real symmetric case{// Regular mode TermMatrixSymGenReg IntMat(Stiff, Mass, uzero); ARSymGenEig< real_t, TermMatrixSymGenReg, TermMatrixSymGenReg > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixSymGenReg::MultOPx, &IntMat, &TermMatrixSymGenReg::MultBx, (char *)"LM"); } {// Shift and invert mode. 1st constructor real_t sigma = 2.2; // for example TermMatrixGenShf< real_t > IntMat(Stiff, Mass, uzero, sigma); ARSymGenEig< real_t, TermMatrixGenShf< real_t >, TermMatrixGenShf< real_t > > ArProb('S', IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< real_t >::MultOPx, &IntMat, &TermMatrixGenShf< real_t >::MultBx, sigma, (char *)"LM"); } {// Shift and invert mode. 2nd constructor real_t sigma = 2.2; // for example TermMatrix SsM(Stiff-sigma*Mass); TermMatrixGenShf< real_t > IntMat(Mass, uzero, SsM); ARSymGenEig< real_t, TermMatrixGenShf< real_t >, TermMatrixGenShf< real_t > > ArProb('S', IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< real_t >::MultOPx, &IntMat, &TermMatrixGenShf< real_t >::MultBx, sigma, (char *)"LM"); } {// Buckling mode. real_t sigma = 2.2; // for example TermMatrixGenBuc IntMat(Stiff,Mass, uzero, sigma); ARSymGenEig< real_t, TermMatrixGenBuc, TermMatrixGenBuc > ArProb('B', IntMat.GetN(), nev, &IntMat, &TermMatrixGenBuc::MultOPx, &IntMat, &TermMatrixGenBuc::MultBx, sigma, (char *)"LM"); } {// Cayley mode. real_t sigma = 2.2; // for example TermMatrixGenCay IntMat(Stiff,Mass, uzero, sigma); ARSymGenEig< real_t, TermMatrixGenCay, TermMatrixGenCay > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenCay::MultOPx, &IntMat, &TermMatrixGenCay::MultAx, &IntMat, &TermMatrixGenCay::MultBx, sigma, (char *)"LM"); }Real non symmetric case{// Regular mode TermMatrixGenReg< real_t > IntMat(Stiff, Mass, uzero); ARNonSymGenEig< real_t, TermMatrixGenReg< real_t >, TermMatrixGenReg< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenReg< real_t >::MultOPx, &IntMat, &TermMatrixGenReg< real_t >::MultBx, (char *)"LM"); } {// Real shift and invert mode. 1st constructor real_t sigma = 2.2; // for example TermMatrixGenShf< real_t > IntMat(Stiff, Mass, uzero, sigma); ARNonSymGenEig< real_t, TermMatrixGenShf< real_t >, TermMatrixGenShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< real_t >::MultOPx, &IntMat, &TermMatrixGenShf< real_t >::MultBx, sigma, (char *)"LM"); } {// Real shift and invert mode. 2nd constructor real_t sigma = 2.2; // for example TermMatrix SsM(Stiff-sigma*Mass); TermMatrixGenShf< real_t > IntMat(Mass, uzero, SsM); ARNonSymGenEig< real_t, TermMatrixGenShf< real_t >, TermMatrixGenShf< real_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< real_t >::MultOPx, &IntMat, &TermMatrixGenShf< real_t >::MultBx, sigma, (char *)"LM"); } {// Complex shift and invert mode. Using real part real_t sigma = 2.2; // for example real_t sigmaI = 0.; TermMatrixGenCsh IntMat(Stiff, Mass, uzero, 'R', sigma, sigmaI); ARNonSymGenEig< real_t, TermMatrixGenCsh, TermMatrixGenCsh > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenCsh::MultOPx, &IntMat, &TermMatrixGenCsh::MultAx, &IntMat, &TermMatrixGenCsh::MultBx, 'R', sigma, sigmaI, (char *)"LM"); } {// Complex shift and invert mode. Using imaginary part real_t sigma = 2.2; // for example real_t sigmaI = 0.5; // should not be 0 here TermMatrixGenCsh IntMat(Stiff, Mass, uzero, 'I', sigma, sigmaI); ARNonSymGenEig< real_t, TermMatrixGenCsh, TermMatrixGenCsh > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenCsh::MultOPx, &IntMat, &TermMatrixGenCsh::MultAx, &IntMat, &TermMatrixGenCsh::MultBx, 'I', sigma, sigmaI, (char *)"LM"); }Complex case{// Regular mode TermMatrixGenReg< complex_t > IntMat(Stiff, Mass, uzero); ARCompGenEig< real_t, TermMatrixGenReg< complex_t >, TermMatrixGenReg< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenReg< complex_t >::MultOPx, &IntMat, &TermMatrixGenReg< complex_t >::MultBx, (char *)"LM"); } {// Shift and invert mode. 1st constructor complex_t sigmac = 0.2; // for example TermMatrixGenShf< complex_t > IntMat(Stiff, Mass, uzero, sigmac); ARCompGenEig< real_t, TermMatrixGenShf< complex_t >, TermMatrixGenShf< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< complex_t >::MultOPx, &IntMat, &TermMatrixGenShf< complex_t >::MultBx, sigmac, (char *)"LM"); } {// Shift and invert mode. 2nd constructor complex_t sigmac = 0.2; // for example TermMatrix SsM(Stiff-sigmac*Mass); TermMatrixGenShf< complex_t > IntMat(Mass, uzero, SsM); ARCompGenEig< real_t, TermMatrixGenShf< complex_t >, TermMatrixGenShf< complex_t > > ArProb(IntMat.GetN(), nev, &IntMat, &TermMatrixGenShf< complex_t >::MultOPx, &IntMat, &TermMatrixGenShf< complex_t >::MultBx, sigmac, (char *)"LM"); }
3. Post-processing
Once the Arpack++ problem has been defined, the computation is ready to be carried on, using member functions of the ArProb object.
In order to make the computation converge, one may tune beforehand the computational process, which is done by altering the default parameters of the Arpack++ problem. Several parameters can be changed as explained in the Arpack++ documentation (see paragraph "Functions that allow changes in problem parameters"). See also the warning written in the previous section Warning.
• If the eigenvalues only are wanted, then the following code can typically be used.// Eventually, change critical parameters to allow convergence ArProb.ChangeNcv(min(2*nev+1,IntMat.GetN()-1)); ArProb.ChangeTol(1.e-6); // Compute eigenvalues int nconv = ArProb.FindEigenvalues(); // Extract ith eigenvalue, 0 <= i < nconv for (int i = 0; i < nconv; i++) { real_t lambda = ArProb.Eigenvalue(i); // use lambda ... }• If the eigenvectors are also wanted, then the following code can typically be used:// Compute eigenvalues and eigenvectors int nconv = ArProb.FindEigenvectors(); // Extract ith eigenvalue and eigenvector, 0 <= i < nconv for (int i = 0; i < nconv; i++) { real_t lambda = ArProb.Eigenvalue(i); TermVectorAR v (uzero,ArProb.RawEigenvector(i)); // use lambda and v ... }In this case, one may want to write the eigenvectors for a graphical post-processing using medit. This can be achieved in the following way:// Compute eigenvalues and eigenvectors int nconv = ArProb.FindEigenvectors(); // Extract ith eigenvalue and eigenvector, 0 <= i < nconv for (int i = 0; i < nconv; i++) { real_t lambda = ArProb.Eigenvalue(i); stringstream ss; ss << i+1 << "_" << lambda; string OutputFile ("EigVec" + ss.str()); // Root filename is 'EigVecN_lambda' TermVectorAR v (uzero,ArProb.RawEigenvector(i)); meditFormat(OutputFile, v, u_h, Omega); // Creation of 2 files : 'EigVecN_lambda.mesh' (geometry) // and 'EigVecN_lambda.bb' (values) }