Skip to content

wpoely86/PRIMME

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

-----------------------------------------------------------------------------
        PRIMME: PReconditioned Iterative MultiMethod Eigensolver
   
      Copyright (C) 2005  James R. McCombs,  Andreas Stathopoulos
-----------------------------------------------------------------------------
 
   This file is part of PRIMME.

   PRIMME is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   PRIMME is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


-----------------------------------------------------------------------------
Contact Information (reporting bugs or questions about functionality)
-----------------------------------------------------------------------------
Andreas Stathopoulos                          
College of William and Mary                   E-mail: andreas@cs.wm.edu
Department of Computer Science                Phone:  757-221-3483
P.O. Box 8795                                 Fax:    757-221-1717
Williamsburg, VA 23187-8795                   http://www.cs.wm.edu/~andreas
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
PRIMME Version 1.1   (October 18, 2006)
Purpose:

Finds a number of eigenvalues and their corresponding eigenvectors of a 
real symmetric, or complex hermitian matrix A. Largest, smallest and interior 
eigenvalues are supported. Preconditioning can be used to accelarate 
convergence. 
PRIMME is written in C, but a complete Fortran77 interface is provided.

Pronounced as "prime"
-----------------------------------------------------------------------------
How to cite this code. 
-----------------------------------------------------------------------------
A software paper describing the code does not exist yet. The code includes
techniques and algorithms that have or will appear in the following papers.
For the moment, please cite the following two papers.

[1]  A. Stathopoulos, Nearly optimal preconditioned methods for hermitian
     eigenproblems under limited memory. Part I: Seeking one eigenvalue,
     Tech Report: WM-CS-2005-03, July, 2005. To appear in SIAM J. Sci. Comput.
[2]  A. Stathopoulos and J. R. McCombs, Nearly optimal preconditioned methods
     for hermitian eigenproblems under limited memory. Part II: Seeking many
     eigenvalues, Tech Report: WM-CS-2006-02, June, 2006.

Additional information on the algorithms appears in:
[3]  J. R. McCombs and A. Stathopoulos, Iterative Validation of Eigensolvers:
     A Scheme for Improving the Reliability of Hermitian Eigenvalue Solvers
     Tech Report: WM-CS-2005-02, July, 2005, to appear in SISC.
[4]  A. Stathopoulos, Locking issues for finding a large number of eigenvectors
     of hermitian matrices, Tech Report: WM-CS-2005-03, July, 2005.

-----------------------------------------------------------------------------
What this file contains beyond this point:

	Directory structure
	Making & Linking
	C Library interface
	  Running 
	  Preset Parameter Setting
	  Displaying the primme configuration
	  Customized parameter setting
	Fortran interface to library
	  Running from Fortran
	List of error codes returned by d/zprimme()
-----------------------------------------------------------------------------
Directory structure 
-------------------

PRIMME/

> ls -F
COPYING.txt  	<- LGPL License
Make_flags	<- flags to be used by makefiles to compile library and tests
Link_flags	<- flags needed in making and linking the test programs
PRIMMESRC/	<- Directory with source code in the following subdirectories:
   COMMONSRC/   <- Interface and oommon functions used by all precision versions
   DSRC/   	<- The source code for the double precision dprimme
   ZSRC/   	<- The source code for the double complex precision zprimme
DTEST/	        <- dprimme sample C and F77 drivers, both seq and parallel 
ZTEST/	        <- zprimme sample C and F77 drivers, sequential only
libprimme.a	<- The PRIMME library (to be made)
makefile        <- makes the libraries, and the sequential/parallel tests
readme.txt      <- this file

-----------------------------------------------------------------------------
Making & Linking
-----------------------------------------------------------------------------
Users must customize Make_flags to create the library. 
Users may customize Link_flags to create the test programs

Make_flags: has the flags and compilers used by the makefiles in PRIMMESRC 
  to make the libprimme.a library (or the stand alone double or complex 
  precision libraries, libdprimme.a, libzprimme.a). Make_flags is also used 
  in the DTEST and ZTEST directories to build the sequential test executables.
  The parallel test is built with DTEST/Makefile_par using flags and compilers 
  for parallelism.
  At minimum, the user must specify the path where the PRIMME dir is located.

Link_flags: has paths for external libraries and linking loaders needed to 
  link the executables of the test programs. To run PRIMME:
  *** BLAS and LAPACK libraries should be available 
  *** Users must include primme.h in their C programs, or primme_f77.h in 
      their fortran programs. For the double complex data struct see Complex.h.
      These header files are located in PRIMMESRC/COMMONSRC/

makefile can perform the following functions:

make all  		builds: lib depends seqs pars
 make lib 		builds libprimme.a in PRIMME/. Alternatively:
 make libd 		  if only dprimme is of interest build libdprimme.a
 make libz 		  if only zprimme is of interest build libzprimme.a
 make depends		builds the dependencies files in (D)ZTEST/
   make ddepends_seq       builds only the ddependencies_seq in DTEST
   make zdepends_seq       builds only the zdependencies_seq in ZTEST
   make ddepends_par       builds only the ddependencies_par in DTEST
 make seqs		builds all sequential executables in (D)ZTEST
   make seq_dprimme 	   builds only the seq real C executable in DTEST
   make seqf77_dprimme 	   builds only the seq real F77 executable in DTEST
   make seq_zprimme 	   builds only the seq herm C executable in ZTEST
   make seqf77_zprimme	   builds only the seq herm F77 executable in ZTEST
 make pars		builds all the parallel executables in DTEST
   make par_dprimme	   currently the only parallel C executable in DTEST
 make clean             removes all *.o, a.out, and core files from all dirs
 make backup		makes a tar.gz dated archive of entire PRIMME directory

The dependencies in (D)ZTEST need not be built unless the test code has changed,
or the d/zdependencies_* files have been deleted. 

The sequential and parallel versions of d/zprimme (the front-ends to PRIMME)
are the same, compiled with any sequential compiler. Parallel programs
can just link with and call dprimme (see below).

In DTEST/
The driver_seq.c is the driver for the sequential test. It fairly well 
structured and reads all or any of the parameters from two configuration files.
It should be the best starting point. Makefile_seq is used for this.
** The provided sample preconditioner and matvec are from SPARSKIT:
   See http://www-users.cs.umn.edu/~saad/software/SPARSKIT/sparskit.html

The driver_par.c is the driver for the parallel test. It follows closely the 
structure of driver_seq.c. It uses MPI for communication and performs matrix-
vector multiplications and Sparse Approximate Inverse preconditioning using 
the ParaSails library. Makefile_par specifies parallel compilation/linking.
** ParaSails is NOT provided, but can be freely downloaded at
   http://www.llnl.gov/CASC/parasails/

The driver_f77seq.f is a sample f77 program made with Makefile_f77seq.
It calls the Fortran interface provided by PRIMME. This interface includes 
a set of wrapper functions that are callable from Fortran to manipulate the 
structure and evoke the eigensolver. For a description of the F77 interface 
see at the end of this file.

In ZTEST/
We provide driver_seq.c and driver_f77seq.f as in the real case, 
with Makefile_seq and Makefile_f77seq respectively. Two different diagonal 
preconditioners can be used, but no ILUT or Parasails.

        --------------------------------------------------------------
	The comments in the sample drivers show how to run executables
        --------------------------------------------------------------

  Systems where the code has been tested.
  --------------------------------------------------------------------------
  SUSE Linux 2.6.13-15.12-smp SMP (64 bit) dual core, dual Intel Xeon 3.73GHz
  SUSE Linux 2.6.13-15.12-default (32 bit) Intel Pentium 4, 2.40GHz
  CentOS Linux 2.6.9-22.ELsmp (64 bit) dual processor AMD Opteron 250
  Darwin 8.8.0 Darwin Kernel Version 8.8.0 PowerPC dual Mac G5, 2 GHz
  Darwin 8.8.0 Darwin Kernel Version 8.8.0 PowerPC Mac G4, 1.67 GHz
  SunOS 5.9, quad processor Sun-Fire-280R, and several other UltraSparcs
  AIX 5.2 IBM SP POWER 3+, 16-way SMP, 375 MHz nodes (seaborg at nersc.gov)

-----------------------------------------------------------------------------
C Library Interface
-----------------------------------------------------------------------------
To solve real symmetric standard eigenproblems call:

    int dprimme(double *evals, double *evecs, double *resNorms, 
		primme_params *primme);

To solve hermitian standard eigenproblems call:

    int zprimme(double *evals, Complex_Z *evecs, double *resNorms, 
		primme_params *primme);

The following interface functions are available in COMMONSRC/primme_interface.c

    void primme_initialize(primme_params *primme);

    int primme_set_method(primme_preset_method method, primme_params *params);

    void primme_display_params(primme_params primme);

    void *primme_calloc(size_t nelem, size_t elsize, const char *target);
    void *primme_valloc(size_t numBytes, const char *target);

    void primme_Free(primme_params primme);

-----------------------------------------------------------------------------
Running
-----------------------------------------------------------------------------

To call dprimme, look at DTEST/driver_seq.c. Also read below.
Basic steps:

* Include "primme.h"
* initialize a primme structure for default settings:

   primme_params primme;

   primme_initialize(&primme);

* Then, for a given eigenproblem, set the various structure members, and/or 
  set it as one of the preset methods (see below and COMMONSRC/primme.h)

* Then call dprimme:

   ret = dprimme(evals, evecs, rnorms, &primme);

evals  a double array of size primme.numEvals                      OUTPUT
evecs  a double array of size primme.nLocal*primme.n       INPUT / OUTPUT
rNorms a double array of size primme.numEvals 		           OUTPUT
primme the above struct. Some members return values	   INPUT / OUTPUT
ret    error return code 					   OUTPUT

--------------------------------------------------------------------------------
Preset parameter setting
--------------------------------------------------------------------------------
To use one of the default methods call 

   ret = primme_set_method(method, &primme);

with method one of the following:
primme_preset_method method;

typedef enum {
   DYNAMIC,  		    // Switches to the best method dynamically 
   DEFAULT_MIN_TIME,        // Currently set as JDQMR_ETol
   DEFAULT_MIN_MATVECS,     // Currently set as GD_Olsen_plusK
   Arnoldi,      	    // Anoldi implented a la Generalized Davidson
   GD,       	    	    // Generalized Davidson 
   GD_plusK,      	    // GD+k with locally optimal restarting for k evals
   GD_Olsen_plusK,          // GD+k, preconditioner applied to (r+deltaeps*x)
   JD_Olsen_plusK,     	    // As above, only deltaeps computed as in JD
   RQI,      	     	    // (accelerated) Rayleigh Quotient Iteration
   JDQR,      	     	    // Jacobi-Davidson with const number of inner steps
   JDQMR,      	    	    // JDQMR adaptive stopping criterion for inner QMR
   JDQMR_ETol,      	    // JDQMR + stops after resid reduces by a 0.1 factor
   SUBSPACE_ITERATION,      // Subspace iteration
   LOBPCG_OrthoBasis,       // A LOBPCG implementation with orthogonal basis
   LOBPCG_OrthoBasis_Window // As above, only finds evals a Window at a time
} primme_preset_method;     

See primme_set_method in COMMONSRC/primme_interface.c for exact description of
how each method sets the members of the primme structure. If the chosen method 
does not exist, the function tries to give reasonable values to the parameters.

PRIMME requires the user to set at least the following members of the primme 
struct, as they define the problem to be solved:

 	n      			(the dimension of the matrix)
	nLocal 			(only if it is parallel program)
   	void (*matrixMatvec)
        (void *x, void *y, int *blockSize, struct primme_params *primme);

In addition, most users would want to specify how many eigenpairs to find, 
and provide a preconditioner (if available), a mass matrix matvec function 
(if a generalized eigenproblem), and a globalSum operation (if parallel).

	numEvals  
   	void (*applyPreconditioner)
        (void *x, void *y, int *blockSize, struct primme_params *primme);
   	void (*massMatrixMatvec)
        (void *x, void *y, int *blockSize, struct primme_params *primme);
        void (*globalSumDouble)		(only if it is parallel program)
	(double *sendBuf, double *recvBuf, int *count, primme_params *primme);

It is useful to have set all these before calling primme_set_method. 
Also, if users have a preference on basisSize, blockSize, etc, they should 
also provide them into primme prior to the primme_set_method() call.
This helps primme_set_method make the right choice on other parameters.

--------------------------------------------------------------------------------
Displaying the primme configuration
--------------------------------------------------------------------------------
The user can call 
	primme_display_params(primme);

to display all the settings of primme variables. This is done in a format 
similar to the input format required by our (D)ZTEST drivers.
Note that in some cases, a couple of primme variables may change internally 
in dprimme(). Calling primme_display_params() after dprimme() shows 
the actual values used.

--------------------------------------------------------------------------------
Customized parameter setting
--------------------------------------------------------------------------------
primme is the following structure: (indicating also OUTPUT members)

   ********************************************************
   * The user must input at least the following arguments *
   ********************************************************
   int n;
  	This is the dimension of the matrix.

   void (*matrixMatvec)
   (void *x, void *y, int *blockSize, struct primme_params *primme); 

	Block matrix-Multivector multiplication. y = A*x.
	x is one dimensional array containing the input blockSize vectors 
	packed one after the other, each of size primme.nLocal. 
	y contains the output blockSize vectors in the same fashion.
	BlockSize is by reference to facilitate a possible Fortran interface.
	x, y are void* arrays. Thus, the user must cast them before use:
		xvec = (double *) x     for dprimme
		xvec = (Complex_Z *) x  for zprimme.

   ********************************************************
   *  The following operators are for preconditioning and *
   *    the mass matrix in generalized eigenproblems      *
   ********************************************************

   void (*applyPreconditioner)
   (void *x, void *y, int *blockSize, struct primme_params *primme);

	Block preconditioner-multivector application. y = applyPreconditioner(x)
	BlockSize is by reference to facilitate a possible Fortran interface.
	x, y are void* arrays, that must be cast accordingly before use.

   void (*massMatrixMatvec)
   (void *x, void *y, int *blockSize, struct primme_params *primme);
	*** Generalized eigenproblems not implemented in current version  ***
	*** This member is included for future compatibility 		  ***

	Block matrix-Multivector multiplication. y = B*x. B is the mass matrix 
	in generalized eigenvalue problems.
	BlockSize is by reference to facilitate a possible Fortran interface.
	x, y are void* arrays, that must be cast accordingly before use.

   ******************************************************************
   * input for the following is only required for parallel programs *
   ******************************************************************

   int numProcs;    [default = 1]

	Only needed if pnumProcs == 1 to set the nLocal by default to n.
	The user might possibly need this info in matvec or precond.

   int procID;      [default = 0]

	ProcessID. Only procID == 0 prints information.

   int nLocal;

	Number of local rows on this processor. nLocal = n if sequential.

   void *commInfo;

	A pointer to whatever parallel environment structures needed.
	For example, with MPI, it could be set to point to the MPI communicator.
	PRIMME does not use this. It is available for possible use in 
	matrixMatvec, applyPreconditioner, massMatrixMatvec and globalSumDouble.

   void (*globalSumDouble)(double *sendBuf, double *recvBuf, int *count,
			   primme_params *primme);

	Global sum function for parallel programs. No need to set for sequential
	recvBuf(i) = sum_over_all_processors( sendBuf(i) ), for all i=1,count
	When MPI is used this is simply a wrapper to MPI_Allereduce()
	primme is needed only for primme->commInfo (eg, MPI communicator)
	Count is by reference to facilitate a possible Fortran interface.
	The data type is always double (even for zprimme).

   *************************************************************************
   * primme_initialize will assign defaults for all the rest of parameters *
   * Yet most users will set these: 					   *
   *************************************************************************

   int numEvals;           [default = 1]

	Number of eigenvalues wanted

   primme_target target    [default = primme_smallest]

	Which eigenpairs to find.  target can can be any of the following enum:

        primme_smallest    Smallest algebraic eigenvalues. Target shifts ignored
        primme_largest     Largest  algebraic eigenvalues. Target shifts ignored
        primme_closest_geq Closest to, but greater or equal than a set of shifts
        primme_closest_leq Closest to, but less or equal than a set of shifts
        primme_closest_abs Closest in absolute value to a set of shifts

  int numTargetShifts;     [default = 0]
	
	Number of shifts around which interior eigenvalues 
        will be targeted. Used only when interior eigenvalues are saught.

  double *targetShifts;    [default = NULL]

	If numTargetShifts > 0, it should point to an array of shifts.
        At least one shift is required.
        Not used with primme_smallest or primme_largest.
        
      *---------------------------------------------------------------------*
        Given shifts [tau1, tau2, ..., tauk] the code finds numEvals eigenpairs
	according to the three modes as follows:       
        Find e1 closest to tau1 AND geq/leq or closest in abs value to tau1
        Find e2 closest to tau2 AND geq/leq or closest in abs value to tau2
                                ...
        Find e(k:numEvals) closest to tauk AND geq/leq/abs to tauk
   
        Notes:
        * For code efficiency and robustness, the shifts should be ordered.
                Order taus in ascending (descending) order for shifts closer
                to the lower (higher) end of the spectrum.
        * When tau_k is closer to the lower end of the spectrum of A,
              primme_closest_leq is not very robust. Use either geq or abs.
        * Similarly, for tau_k in the higher end of the spectrum,
              primme_closest_geq is not very robust. Use either leq or abs.
        * closest_leq and closest_geq are more efficient than closest_abs.
        * For interior eigenvalues use larger maxBasisSize than usual.
      *---------------------------------------------------------------------*

   int printLevel;    	   [default = 1]

	The level of message reporting from the code. 
	  0 	silent
	  1     print some error messages when these occur
	  2  	Level 1 AND info about targeted eigenpairs when they converge

		       	#Converged $1 eval[ $2 ]= $3 norm $4 Mvecs $5 Time $7

		  or with locking:
		       	#Lock epair[ $1 ]= $3 norm $4 Mvecs $5 Time $7
		
	  3  	Level 2 AND info about targeted eigenpairs every outer iteration

			OUT $6 conv $1 blk $8 MV $5 Sec $7 EV $3 |r| $4

                Also, if method=DYNAMIC, show JDQMR/GDk ratio and current method 
	  4  	Level 3 AND info about targeted eigenpairs every inner iteration

			INN MV $5 Sec $7 Eval $3 Lin|r| $9 EV|r| $4

	  5  	Level 4 AND verbose info about certain choices of the algorithm

	    	   output key:
			$1: num of converged pairs up to now
			$2: The index of the pair currently converged
			$3: The eigenvalue
			$4: Its residual norm
			$5: The current number of matvecs 
			$6: The current number of outer iterations
			$7: The current elapsed time
			$8: Index within the block of the targeted pair 
			$9: QMR norm of the linear system residual

	Convergence history for plotting may be produced simply by:
	   grep OUT outpufile | awk '{print $8" "$14}' > out
	   grep INN outpufile | awk '{print $3" "$11}' > inn
	Then in Matlab:
	   plot(out(:,1),out(:,2),'bo');hold; plot(inn(:,1),inn(:,2),'r');


   double aNorm;           [default = 0.0]			(OUTPUT)
	
	An estimate of norm of the matrix A given by the user (usu Frobenious)

        If aNorm  > 0.0, convergence tolerance = primme.eps * primme.aNorm
                         (set aNorm = 1.0 to achieve exactly primme.eps)
	If aNorm <= 0.0, convergence tolerance = 
				   primme.eps * Computed_Estimate_of_A_norm,
          the Computed_Estimate_of_A_norm = largest absolute Ritz value seen
          ON RETURN, aNorm also is replaced with the Computed_Estimate_of_A_norm

   double eps;             [default = 1e-12]
	
	Convergence is declared when the 2-norm of the residual satisfies:

		||r|| < primme.eps * primme.aNorm
   
   FILE *outputFile;       [default = stdout]

	An optional output file that has been opened opened by the user.
   
   **********************************************************************
   * the following will be given default values depending on the method *
   *********************************************************************/
   int dynamicMethodSwitch; [default = 0]			(OUTPUT)

	Setting the primme_method to DYNAMIC, sets dynamicMethodSwitch = 1 
	PRIMME alternates dynamically between DEFAULT_MIN_TIME (JDQMR_ETol) 
 	and DEFAULT_MIN_MATVECS (GD+k), trying to identify the fastest method.
	On exit, it holds a recommended method for future runs on this problem:
           dynamicMethodSwitch = -1   use DEFAULT_MIN_MATVECS next time
           dynamicMethodSwitch = -2   use DEFAULT_MIN_TIME next time
           dynamicMethodSwitch = -3   Close call. Use again dynamic next time

	Even for expert users we do not recommend setting dynamicMethodSwitch
	by hand, but only through primme_set_method(DYNAMIC).
	We obtain timings by the gettimeofday Unix utility. If a cheaper, more
	accurate timer is available, modify the PRIMMESRC/COMMONSRC/wtime.c

   int locking;							(OUTPUT)

	If set to 1, hard locking will be used (locking converged eigenvectors
	out of the search basis). Otherwise the code will try to use soft
	locking (a la ARPACK), when large enough minRestartSize is available.
	
   int initSize;	   [default = 0]			(OUTPUT)

	On INPUT, the number of initial guesses provided in evecs array.
	ON OUTPUT, the number of converged eigenpairs.
	DURING execution, holds the current number of converged eigenpairs.
	If in addition locking is used, these are accessible in evals & evecs.

   int numOrthoConst;      [default = 0]

	Number of external orthogonalization constraints provided in the first 
	numOrthoConst vectors of evecs. THen eigenvectors are found orthogonal 
	to those constraints (equivalent to solving (I-YY')A(I-YY') for given Y)
	This is a handy feature if some eigenvectors are already known, or 
	for finding some eigenvalues, exiting primme, and then calling it 
	again (possibly with different parameters) to find some more.

   int maxBasisSize;	   

	The maximum basis size allowed in the main iteration. This has memory
	implications. The default depends on method.

   int minRestartSize;     

	The code will try to keep at least as many Ritz vectors every time 
	it needs to restart after the maxBasisSize has been reached.
	The default depends on maxBasisSize, blockSize and method.

   int maxBlockSize; 	   [default = 1]
	
	The maximum block size the code will try to use. The user should set
	this based on the architecture specifics of the target computer, 
	as well as any a priori knowledge of multiplicities. The code does 
	NOT require maxBlockSize > 1 to find multiple eigenvalues.  For some 
	methods, keeping maxBlockSize = 1 yields the best overall performance.
	NOTE: Inner iterations of QMR are not performed in a block fashion.
	Every correction equation from a block is solved independently.

   int maxMatvecs;         [default = INT_MAX]

	Maximum number of matrix vector multiplications (approximately equal to 
	the number of preconditioning operations) that the code is allowed to 
	perform before it exits.
	
   int maxOuterIterations; [default = INT_MAX]
	Maximum number of outer iterations that the code is allowed to perform 
	before it exits. NOTE: Currently we do not check this.

   int intWorkSize;						(INPUT/OUTPUT)

	Size of the integer work array IN BYTES. The user provides it if 
   	the user provides also the work array. After a call to dprimme/zprimme
	with (NULL,NULL,NULL,&primme), intWorkSize has the size of integer
	workspace that will be required by the parameters set in primme.

   long int realWorkSize;					(INPUT/OUTPUT)

	Size of the real/complex work array IN BYTES. The user provides it if 
	the user provides also the work array. After a call to dprimme/zprimme
	with (NULL,NULL,NULL,&primme), realWorkSize has the size of real
	workspace that will be required by the parameters set in primme.

   int *intWork;           [default = NULL] 			(INPUT/OUTPUT)

	pointer to an integer work array. If NULL, or if its size is not 
	sufficient, the code will free *intWork and allocate its own workspace 
        to match the space requirements of the requested method or the 
	primme parameters. 
	On output, the first numEvals positions contain the convergence flag 
	for each pair. Using locking for large numEvals may, in some rare cases,
	cause some pairs to be practically converged (intWork[i] == 7), in the 
	sense that their components are in the basis of evecs. If required, a 
	Rayleigh Ritz on evecs will provide the accurate eigenvector (see [4]).

   void *realWork;  	   [default = NULL]			(INPUT/OUTPUT)

	pointer to a void* work array. In ZPRIMME used both for Complex_Z and 
	double work. If not given, or if its size is not sufficient the code 
	will free *realWork and allocate its own workspace to match the space 
	requirements of the requested method or the primme parameters.

   int iseed[4];   [default = (1 2 3 5)]

	The seeds needed by the Lapack d/zlarnv.f.

   void *matrix;
   void *preconditioner;

	Unused pointers that the user can use to pass any required information 
	in the matrix-vector and preconditioning operations. See test drivers.

   double *ShiftsForPreconditioner;

	Array provided by d/zprimme() holding the shifts to be used (if needed)
	in the preconditioning operation. For example if the block size is 3,
	there will be an array of three shifts in ShiftsForPreconditioner.
	Then the user can invert a shifted preconditioner for each of the 
	block vectors:
		(M-ShiftsForPreconditioner[i])^{-1} v_i
	Classical Davidson (diagonal) preconditioning is an example of this.

   
   struct restarting_params restartingParams;

        stucture with the following members:

        primme.restartingParams.scheme     	[default = primme_thick]
	   possible values are:
	   primme_thick  Thick restarting. This is the most efficient and robust
			 in the general case.
	   primme_dtr	 Dynamic thick restarting. Helpful without 
			 preconditioning but it is expensive to implement.

        int maxPrevRetain 			[default = 1]
		number of approximations from previous iteration to be retained
		after restart.  This is recurrence based restarting (see GD+1, 
		LOBPCG, etc). If maxPrevRetain > 0, then the restart size will 
		be:  minRestartSize + maxPrevRetain.

   struct correction_params correctionParams;
	
	structure with the following members:
	   int precondition;			[default = 0]

		Set to 1 if preconditioning is to be performed. Make sure the 
		applyPreconditioner is not NULL then!

	   int robustShifts;
	
		Set to 1 to use robustShifting. It helps avoid stagnation and 
		missconvergence some times. 

	   int maxInnerIterations;

		Number of inner QMR iterations:

                        = 0   No inner iterations (GD/JD)
                        = k   Perform at most k inner iterations per outer step
                              (or if convergence < tol)
                        < 0   Perform at most the rest of allowed matvecs
                                  primme.maxMatvecs - primme.stats.numMatvecs
                              so basically do not stop by number of iterations.

	   double relTolBase;

		This is a legacy from classical JDQR. Inner QMR is iterated 
		until linear system residual < relTolBase^(-OuterIterations).
		We recommend STRONGLY against its use.

	   primme_convergencetest convTest;
	
		How to stop the inner QMR method.

        	= primme_full_LTolerance        // stop by iterations only
        	= primme_decreasing_LTolerance  // LinSysResidual < 
						// relTolBase^(-outerIterations)
        	= primme_adaptive               // JDQMR adaptive (like 
						//	        Notay's JDCG)
        	= primme_adaptive_ETolerance    // as in JDQMR adaptive but 
					        // stop also when
					     // Eres_(innerIts) < Eres_(0) * 0.1

		The last scheme simply stops inner iterations when 1 order of 
		magnitude has been achieved for the eigenresidual (NOT the 
		linear system residual)

	   struct JD_projectors projectors;
		Set the following to 1:
   		int LeftQ;    if a projector with Q must be applied on the left
   		int LeftX;    if a projector with X must be applied on the left
   		int RightQ;   if a projector with Q must be applied on the right
   		int RightX;   if a projector with X must be applied on the right
   		int SkewQ;    if the Q right projector must be skew
   		int SkewX;    if the X right projector must be skew

	
 	   (I-QQ')(I-xx')(A-shift I)(I-Kx(x'Kx)^(-1)x')(I-KQ(Q'K Q)^(-1)Q') K 
 	    -----  -----             -----------------  ------------------
 	     Lq     Lx                   Rx  Sx              Rq Sq

  	   see setup_JD_projectors() in inner_solve.c for more information.


   struct primme_stats stats; 					(OUTPUT)

	Struct with the following members to report statistics back. 
	Nothing has to be set. Can be checked also during execution, e.g., 
	in the user provided Matvec or preconditioning function.

   	int numOuterIterations;
   	int numRestarts;
   	int numMatvecs;
   	double elapsedTime;

   struct stackTraceNode *stackTrace;				(OUTPUT)

	Struct with the following members. If an error occurs the function
	primme_PrintStackTrace(primme) prints the calling stack from top to the 
			function that caused the error. Nothing to set.

	int callingFunction;
   	int failedFunction;
   	int errorCode;
   	int lineNumber;
   	char fileName[PRIMME_MAX_NAME_LENGTH];
   	struct stackTraceNode *nextNode;


} primme_params;


   -----------------------------------------------------------------------------
   Some notes on the inner QMR convergence tests: 
   -----------------------------------------------------------------------------

	The following two tests could be combined in all possible ways.
  Eg: maxInnerIterations  convTest
	   0                 -            	GD/JD
	   k            full_LTolerance      JDQR always k
	   k		decreasingTolerance  JDQR With Steinhaug(k)
	   k		adaptive 	     JDQMR( but no more than k)
	   < 0          full_LTolerance      Makes no sense! DO NOT DO!
	   < 0		decreasingTolerance  JDQR With Steinhaug
	   < 0		adaptive 	     JDQMR 
	   < 0		adaptive_ETol 	     JDQMR with only 1 order improvement
			etc...


  Choice of GD projectors:
			
	 (I - (Kinv*x) x') (I - (Kinv*Q) Q') Kinv*r
	 RitzR, RitzSkew   EvecR, EvecSkew
	   1        1        1       1       (this is almost never done)
	   1        1        0       0       Olsen's
	   1        0        0       0       Unnecessary. Ortho follows.
	   0        1        0       0       Does not exist
	   0        0        0       0       GD
	   0        0                        approximate Olsen: Kinv(r-err*x)

  Choice of JD projectors:

	(I-QQ') (I-xx') (A-sI) (I - (Kinv*x) x') (I - (Kinv*Q) Q') Kinv*r
	 EvecL   RitzL          RitzR, RitzSkew   EvecR, EvecSkew
	   1       1               1       1         1       1
	   1       1               1       0         1       0
	   1       1               1       1         1       0
	   1       1               1       0         1       1   meaningless
			...

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Fortran interface to library
-----------------------------------------------------------------------------
The following functions are available for users to call from FORTRAN.
Notice the appendix _f77.

      call dprimme_f77(double *evals, double *evecs, double *rnorms,
	  	    primme_params **primme, int *ierr);

      call zprimme_f77(double *evals, Complex_Z *evecs, double *rnorms,
	  	    primme_params **primme, int *ierr);

      call primme_initialize_f77(primme_params **primme);

      call primme_display_params_f77(primme_params **primme);

      call primme_PrintStackTrace_f77(primme_params **primme);

      call primme_set_method_f77(primme_params **primme, int *method,int *ierr);

      call primme_set_member_f77(primme_params **primme, int *label, void *ptr);

      call primme_get_prec_shift_f77(primme_params *primme, int *i, 
				     double *shift);

      call primme_get_member_f77(primme_params *primme, int *label, void *ptr);

      call primmetop_get_member_f77(primme_params **primme, int *label, 
				    void *ptr);

      call primmetop_get_prec_shift_f77(primme_params **primme, int *i, 
 				        double *shift);

-----------------------------------------------------------------------------
Running from Fortran
-----------------------------------------------------------------------------

To call d/zprimme from Fortran, look at (D)ZTEST/driver_f77seq.c. 
Basic steps:

*----------------------------------
* Include "primme_f77.h"
* initialize a primme structure for default settings:

      integer primme
  (or integer*8 primme if running on a 64 bit operating system)

      call primme_initialize_f77(primme)

*----------------------------------
Then, set the various structure members and possibly the method to be used. 
Individual primme members can be set by calling:

      call primme_set_member_f77(primme, MEMBER_LABEL, variable)

   where
   	MEMBER_LABEL is the name of the primme member prepended with PRIMMEF77_
	and replacing all dots (.) with underscores (_). See primme_f77.h
    	Eg.:
		
 call primme_set_member_f77(primme, PRIMMEF77_correctionParams_precondition, 1)

	sets the primme->correctionParams.precondition = 1 

Matrix-vector and preconditioning fortran function must be declared
external and passed in the same way to primme:

      external MV
 	...
      call primme_set_member_f77(primme, PRIMMEF77_matrixMatvec, MV)

*----------------------------------
A preset method is chosen in a similar way:

      call primme_set_method_f77(primme, METHOD, RealMem)

   where
	METHOD has the name of the preset method as above, prepended 
	by PRIMMEF77_  All these are defined in primme_f77. 

      call primme_set_method_f77(primme, PRIMEF77_JDQMR_ETol, ierr)

*----------------------------------
Then call dprimme:

      call dprimme_f77(evals, evecs, rnorms, primme, ierr)

*----------------------------------
How to obtain the value of a member of the PRIMME structure depends
on whether it is called from an F77 subroutine called directly by the driver, 
or by an F77 function invoked by PRIMME (such as matrixMatvec, 
applyPreconditioner, massMatrixMatvec or globalSumDouble)

 From the driver: primme is really: primme_params **primme

      call primmetop_get_member_f77(primme, MEMBER_LABEL, ResultVariable)

 From matrixMatvec, applyPreconditioner, massMatrixMatvec and globalSumDouble: 
 primme is really: primme_params *primme, so a different function must be used: 

      call primme_get_member_f77(primme, MEMBER_LABEL, ResultVariable)

*----------------------------------
In preconditioning, a PRIMME provided shift may be used. Assuming a block
of blockSize, from which the i-th shift is needed, i = 1,2,3...,blockSize
the user can call from inside the f77 applyPreconditioner() the following 
function:

      call primme_get_prec_shift_f77(primme, i, shift)

-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
List of error codes returned by d/zprimme()
-----------------------------------------------------------------------------
These can be found also in primme_d.c

   0: Success
   1: Reporting only amount of required memory
  -1: Failure to allocate int or real workspace
  -2: Malloc failure in allocating a permutation integer array
  -3: main_iter() encountered problem. PRIMME has printed in STDERR the 
	calling stack of the functions where the error occured
  -4: if (primme == NULL)
  -5: if (primme->n <= 0 || primme->nLocal <= 0)
  -6: if (primme->numProcs < 1)
  -7: if (primme->matrixMatvec == NULL)
  -8: if (primme->applyPreconditioner == NULL && 
	  primme->correctionParams.precondition )
  -9: if (primme->globalSumDouble == NULL)
  -10: if (primme->numEvals > primme->n)
  -11: if (primme->numEvals < 0)
  -12: if (primme->eps > 0.0L && primme->eps < machine precision
  -13: if (primme->target not properly defined)
  -14: if (primme->target == primme_closest_geq/leq/abs (interior needed)
                        && primme->numTargetShifts <= 0 (no shifts)
  -15: if (primme->target == primme_closest_geq/leq/abs (interior needed)
                      && (primme->targetShifts == NULL  (no shifts array)
  -16: if (primme->numOrthoConst < 0 || 
   	   primme->numOrthoConst >=primme->n   (no free dimensions left)
  -17: if (primme->maxBasisSize < 2)
  -18: if (primme->minRestartSize <= 0)
  -19: if (primme->maxBlockSize <= 0)
  -20: if (primme->restartingParams.maxPrevRetain < 0)
  -21: if (primme->restartingParams.scheme != primme_thick or primme_dtr)
  -22: if (primme->initSize < 0)
  -23: if (!primme->locking && primme->initSize > primme->maxBasisSize)
  -24: if (primme->locking && primme->initSize > primme->numEvals)
  -25: if (primme->restartingParams.maxPrevRetain +
          primme->minRestartSize >= primme->maxBasisSize)
  -26: if (primme->minRestartSize >= primme->n)
  -27: if (primme->printLevel < 0 || primme->printLevel > 5)
  -28: if (primme->correctionParams.convTest is not one of the
		primme_full_LTolerance, primme_decreasing_LTolerance,
       		primme_adaptive_ETolerance, primme_adaptive )
  -29: if (primme->correctionParams.convTest == primme_decreasing_LTolerance 
	 primme->correctionParams.relTolBase <= 1.0L )
  -30: if evals == NULL    (but not all evecs, evals and resNorms)
  -31: if evecs == NULL    (but not all evecs, evals and resNorms)
  -32: if resNorms == NULL (but not all evecs, evals and resNorms)

About

My clone of the PRIMME source

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published