Actual source code: primmes.c

  2: /*                       
  3:        This file implements a wrapper to the PRIMME library
  4:        Contributed by Eloy Romero
  5: */

 7:  #include src/eps/epsimpl.h

 10: #include "primme.h"

 13: #ifndef PETSC_USE_COMPLEX
 14: typedef double PRIMMEScalar;
 15: #else
 16: typedef Complex_Z PRIMMEScalar;
 17: #endif

 19: typedef struct {
 20:   primme_params primme;           /* param struc */
 21:   primme_preset_method method;    /* primme method */
 22:   Mat A;                          /* problem matrix */
 23:   Vec w;                          /* store reciprocal A diagonal */
 24:   Vec x,y;                        /* auxiliar vectors */
 25: } EPS_PRIMME;

 27: static void multMatvec_PRIMME(PRIMMEScalar *in, PRIMMEScalar *out, int *blockSize, primme_params *primme);
 28: static void applyPreconditioner_PRIMME(PRIMMEScalar *in, PRIMMEScalar *out, int *blockSize, struct primme_params *primme);

 30: static void par_GlobalSumDouble(void *sendBuf, void *recvBuf, int *count, primme_params *primme) {
 31:   MPI_Allreduce((double*)sendBuf, (double*)recvBuf, *count, MPI_DOUBLE, MPI_SUM, ((EPS)(primme->commInfo))->comm);
 32: }

 36: PetscErrorCode EPSSetUp_PRIMME(EPS eps)
 37: {
 39:   PetscInt       N, n;
 40:   int            numProcs, procID;
 41:   EPS_PRIMME     *ops = (EPS_PRIMME *)eps->data;
 42:   primme_params  *primme = &(((EPS_PRIMME *)eps->data)->primme);


 46:   MPI_Comm_size(eps->comm,&numProcs);
 47:   MPI_Comm_rank(eps->comm,&procID);
 48: 
 49:   /* Check some constraints and set some default values */
 50:   VecGetSize(eps->vec_initial,&N);
 51:   VecGetLocalSize(eps->vec_initial,&n);

 53:   if (!eps->max_it) eps->max_it = PetscMax(1000,N);
 54:   STGetOperators(eps->OP, &ops->A, PETSC_NULL);
 55:   if (!ops->A) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"The problem matrix has to be specified first");
 56:   if (!eps->ishermitian)
 57:     SETERRQ(PETSC_ERR_SUP,"PRIMME is only available for Hermitian problems");
 58:   if (eps->isgeneralized)
 59:     SETERRQ(PETSC_ERR_SUP,"PRIMME is not available for generalized problems");

 61:   /* Transfer SLEPc options to PRIMME options */
 62:   primme->n = N;
 63:   primme->nLocal = n;
 64:   primme->numEvals = eps->nev;
 65:   primme->matrix = ops;
 66:   primme->commInfo = eps;
 67:   primme->initSize = 1;
 68:   primme->maxMatvecs = eps->max_it;
 69:   primme->eps = eps->tol;
 70:   primme->numProcs = numProcs;
 71:   primme->procID = procID;
 72:   primme->globalSumDouble = par_GlobalSumDouble;

 74:   switch(eps->which) {
 75:     case EPS_LARGEST_REAL:
 76:       primme->target = primme_largest;
 77:       break;

 79:     case EPS_SMALLEST_REAL:
 80:       primme->target = primme_smallest;
 81:       break;
 82: 
 83:     default:
 84:       SETERRQ(PETSC_ERR_SUP,"PRIMME only allows EPS_LARGEST_REAL and EPS_SMALLEST_REAL for 'which' value");
 85:       break;
 86:   }
 87: 
 88:   primme_set_method(ops->method, primme);
 89: 
 90:   /* If user sets ncv, maxBasisSize is modified. If not, ncv is set as maxBasisSize */
 91:   if (eps->ncv) primme->maxBasisSize = eps->ncv;
 92:   else eps->ncv = primme->maxBasisSize;
 93:   if (eps->ncv < eps->nev+primme->maxBlockSize)
 94:     SETERRQ(PETSC_ERR_SUP,"PRIMME needs ncv >= nev+maxBlockSize");

 96:   /* Set workspace */
 97:   EPSAllocateSolutionContiguous(eps);

 99:   /* Copy vec_initial to V[0] vector */
100:   VecCopy(eps->vec_initial, eps->V[0]);
101: 
102:   if (primme->correctionParams.precondition) {
103:     /* Calc reciprocal A diagonal */
104:     VecDuplicate(eps->vec_initial, &ops->w);
105:     MatGetDiagonal(ops->A, ops->w);
106:     VecReciprocal(ops->w);
107:     primme->preconditioner = PETSC_NULL;
108:     primme->applyPreconditioner = applyPreconditioner_PRIMME;
109:   }

111:   /* Prepare auxiliary vectors */
112:   VecCreateMPIWithArray(PETSC_COMM_WORLD,n,N,PETSC_NULL,&ops->x);
113:   VecCreateMPIWithArray(PETSC_COMM_WORLD,n,N,PETSC_NULL,&ops->y);
114: 
115:   return(0);
116: }

120: PetscErrorCode EPSSolve_PRIMME(EPS eps)
121: {
123:   EPS_PRIMME     *ops = (EPS_PRIMME *)eps->data;
124:   PetscScalar    *a;
125: #ifdef PETSC_USE_COMPLEX
126:   int            i;
127:   PetscReal      *evals;
128: #endif


132:   /* Call PRIMME solver */
133:   VecGetArray(eps->V[0], &a);
134: #ifndef PETSC_USE_COMPLEX
135:   dprimme(eps->eigr, a, eps->errest, &ops->primme);
136: #else
137:   /* PRIMME returns real eigenvalues, but SLEPc works with complex ones */
138:   PetscMalloc(eps->ncv*sizeof(PetscReal),&evals);
139:   zprimme(evals, (Complex_Z*)a, eps->errest, &ops->primme);
140:   for (i=0;i<eps->ncv;i++)
141:     eps->eigr[i] = evals[i];
142:   PetscFree(evals);
143: #endif
144:   VecRestoreArray(eps->V[0], &a);
145: 
146:   switch(ierr) {
147:     case 0: /* Successful */
148:       break;

150:     case -1:
151:       SETERRQ(PETSC_ERR_SUP,"PRIMME: Failed to open output file");
152:       break;

154:     case -2:
155:       SETERRQ(PETSC_ERR_SUP,"PRIMME: Insufficient integer or real workspace allocated");
156:       break;

158:     case -3:
159:       SETERRQ(PETSC_ERR_SUP,"PRIMME: main_iter encountered a problem");
160:       break;

162:     default:
163:       SETERRQ(PETSC_ERR_SUP,"PRIMME: some parameters wrong configured");
164:       break;
165:   }

167:   eps->nconv = ops->primme.initSize>=0?ops->primme.initSize:0;
168:   eps->reason = EPS_CONVERGED_TOL;
169:   eps->its = ops->primme.stats.numMatvecs;

171: #ifndef PETSC_USE_COMPLEX
172:   PetscMemzero(eps->eigi, eps->nconv*sizeof(double));
173: #endif
174:   return(0);
175: }

179: static void multMatvec_PRIMME(PRIMMEScalar *in, PRIMMEScalar *out, int *blockSize, primme_params *primme)
180: {
182:   int            i, N = primme->n;
183:   EPS_PRIMME     *ops = (EPS_PRIMME *)primme->matrix;
184:   Vec            x = ops->x;
185:   Vec            y = ops->y;
186:   Mat            A = ops->A;

189:   for (i=0;i<*blockSize;i++) {
190:     /* build vectors using 'in' an 'out' workspace */
191:     VecPlaceArray(x, (PetscScalar*)in+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);
192:     VecPlaceArray(y, (PetscScalar*)out+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);

194:     MatMult(A, x, y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
195: 
196:     VecResetArray(x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
197:     VecResetArray(y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
198:   }
199:   PetscFunctionReturnVoid();
200: }

204: static void applyPreconditioner_PRIMME(PRIMMEScalar *in, PRIMMEScalar *out, int *blockSize, struct primme_params *primme)
205: {
207:   int            i, N = primme->n;
208:   EPS_PRIMME     *ops = (EPS_PRIMME *)primme->matrix;
209:   Vec            x = ops->x;
210:   Vec            y = ops->y;
211:   Vec            w = ops->w;
212: 
214:   for (i=0;i<*blockSize;i++) {
215:     /* build vectors using 'in' an 'out' workspace */
216:     VecPlaceArray(x, (PetscScalar*)in+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);
217:     VecPlaceArray(y, (PetscScalar*)out+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);

219:     VecPointwiseMult(y, w, x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
220: 
221:     VecResetArray(x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
222:     VecResetArray(y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
223:   }
224:   PetscFunctionReturnVoid();
225: }


230: PetscErrorCode EPSDestroy_PRIMME(EPS eps)
231: {
233:   EPS_PRIMME    *ops = (EPS_PRIMME *)eps->data;

237: 
238:   if (ops->primme.correctionParams.precondition) {
239:     VecDestroy(ops->w);
240:   }
241:   primme_Free(&ops->primme);
242:   VecDestroy(ops->x);
243:   VecDestroy(ops->y);
244:   PetscFree(eps->data);
245:   EPSFreeSolutionContiguous(eps);
246: 
247:   return(0);
248: }

252: PetscErrorCode EPSView_PRIMME(EPS eps,PetscViewer viewer)
253: {
255:   PetscTruth isascii;
256:   primme_params *primme = &((EPS_PRIMME *)eps->data)->primme;
257:   const char *methodList[] = {
258:     "default_min_time",
259:     "default_min_matvecs",
260:     "arnoldi",
261:     "gd",
262:     "gd_plusk",
263:     "gd_olsen_plusk",
264:     "jd_olsen_plusk",
265:     "rqi",
266:     "jdqr",
267:     "jdqmr",
268:     "jdqmr_etol",
269:     "subspace_iteration",
270:     "lobpcg_orthobasis",
271:     "lobpcg_orthobasis_window"
272:   };
273:   const char *precondList[] = {"none", "diagonal"};
274:   EPSPRIMMEMethod methodN;
275:   EPSPRIMMEPrecond precondN;
276: 
278:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
279:   if (!isascii) {
280:     SETERRQ1(1,"Viewer type %s not supported for EPSPRIMME",((PetscObject)viewer)->type_name);
281:   }
282: 
283:   PetscViewerASCIIPrintf(viewer,"PRIMME solver block size: %d\n",primme->maxBlockSize);
284:   EPSPRIMMEGetMethod(eps, &methodN);
285:   PetscViewerASCIIPrintf(viewer,"PRIMME solver method: %s\n", methodList[methodN]);
286:   EPSPRIMMEGetPrecond(eps, &precondN);
287:   PetscViewerASCIIPrintf(viewer,"PRIMME solver preconditioning: %s\n", precondList[precondN]);

289:   return(0);
290: }

294: PetscErrorCode EPSSetFromOptions_PRIMME(EPS eps)
295: {
297:   EPS_PRIMME    *ops = (EPS_PRIMME *)eps->data;
298:   PetscInt       op;
299:   PetscTruth     flg;
300:   const char *methodList[] = {
301:     "default_min_time",
302:     "default_min_matvecs",
303:     "arnoldi",
304:     "gd",
305:     "gd_plusk",
306:     "gd_olsen_plusk",
307:     "jd_olsen_plusk",
308:     "rqi",
309:     "jdqr",
310:     "jdqmr",
311:     "jdqmr_etol",
312:     "subspace_iteration",
313:     "lobpcg_orthobasis",
314:     "lobpcg_orthobasis_window"
315:   };
316:   const char *precondList[] = {"none", "diagonal"};
317:   EPSPRIMMEMethod methodN[] = {
318:     EPSPRIMME_DEFAULT_MIN_TIME,
319:     EPSPRIMME_DEFAULT_MIN_MATVECS,
320:     EPSPRIMME_ARNOLDI,
321:     EPSPRIMME_GD,
322:     EPSPRIMME_GD_PLUSK,
323:     EPSPRIMME_GD_OLSEN_PLUSK,
324:     EPSPRIMME_JD_OlSEN_PLUSK,
325:     EPSPRIMME_RQI,
326:     EPSPRIMME_JDQR,
327:     EPSPRIMME_JDQMR,
328:     EPSPRIMME_JDQMR_ETOL,
329:     EPSPRIMME_SUBSPACE_ITERATION,
330:     EPSPRIMME_LOBPCG_ORTHOBASIS,
331:     EPSPRIMME_LOBPCG_ORTHOBASIS_WINDOW
332:   };
333:   EPSPRIMMEPrecond precondN[] = {EPSPRIMME_NONE, EPSPRIMME_DIAGONAL};

336: 
337:   PetscOptionsHead("PRIMME options");

339:   op = ops->primme.maxBlockSize;
340:   PetscOptionsInt("-eps_primme_block_size"," maximum block size","EPSPRIMMESetBlockSize",op,&op,&flg);
341:   if (flg) {EPSPRIMMESetBlockSize(eps,op);}
342:   op = 0;
343:   PetscOptionsEList("-eps_primme_method","set method for solving the eigenproblem",
344:                            "EPSPRIMMESetMethod",methodList,14,methodList[0],&op,&flg);
345:   if (flg) {EPSPRIMMESetMethod(eps, methodN[op]);}
346:   PetscOptionsEList("-eps_primme_precond","set preconditioner type",
347:                            "EPSPRIMMESetPrecond",precondList,2,precondList[0],&op,&flg);
348:   if (flg) {EPSPRIMMESetPrecond(eps, precondN[op]);}
349: 
350:   PetscOptionsTail();
351: 
352:   return(0);
353: }

358: PetscErrorCode EPSPRIMMESetBlockSize_PRIMME(EPS eps,int bs)
359: {
360:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


364:   if (bs == PETSC_DEFAULT) ops->primme.maxBlockSize = 1;
365:   else if (bs <= 0) {
366:     SETERRQ(1, "PRIMME: wrong block size");
367:   } else ops->primme.maxBlockSize = bs;
368: 
369:   return(0);
370: }

375: /*@
376:     EPSPRIMMESetBlockSize - The maximum block size the code will try to use. 
377:     The user should set
378:     this based on the architecture specifics of the target computer, 
379:     as well as any a priori knowledge of multiplicities. The code does 
380:     NOT require BlockSize > 1 to find multiple eigenvalues.  For some 
381:     methods, keeping BlockSize = 1 yields the best overall performance.

383:    Collective on EPS

385:    Input Parameters:
386: +  eps - the eigenproblem solver context
387: -  bs - block size

389:    Options Database Key:
390: .  -eps_primme_block_size - Sets the max allowed block size value

392:    Notes:
393:    If the block size is not set, the value established by primme_initialize
394:    is used.

396:    Level: advanced
397: .seealso: EPSPRIMMEGetBlockSize()
398: @*/
399: PetscErrorCode EPSPRIMMESetBlockSize(EPS eps,int bs)
400: {
401:   PetscErrorCode ierr, (*f)(EPS,int);

404: 
406:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetBlockSize_C",(void (**)())&f);
407:   if (f) {
408:     (*f)(eps,bs);
409:   }
410: 
411:   return(0);
412: }

417: PetscErrorCode EPSPRIMMEGetBlockSize_PRIMME(EPS eps,int *bs)
418: {
419:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


423:   if (bs) *bs = ops->primme.maxBlockSize;
424: 
425:   return(0);
426: }

431: /*@
432:     EPSPRIMMEGetBlockSize - Get the maximum block size the code will try to use. 
433:     
434:     Collective on EPS

436:    Input Parameters:
437: .  eps - the eigenproblem solver context
438:     
439:    Output Parameters:  
440: .  bs - returned block size 

442:    Level: advanced
443: .seealso: EPSPRIMMESetBlockSize()
444: @*/
445: PetscErrorCode EPSPRIMMEGetBlockSize(EPS eps,int *bs)
446: {
447:   PetscErrorCode ierr, (*f)(EPS,int*);

450: 
452:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetBlockSize_C",(void (**)())&f);
453:   if (f) {
454:     (*f)(eps,bs);
455:   }
456: 
457:   return(0);
458: }

463: PetscErrorCode EPSPRIMMESetMethod_PRIMME(EPS eps, EPSPRIMMEMethod method)
464: {
465:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


469:   if (method == PETSC_DEFAULT) ops->method = DEFAULT_MIN_TIME;
470:   else ops->method = (primme_preset_method)method;
471: 
472:   return(0);
473: }

478: /*@
479:    EPSPRIMMESetMethod - Sets the method for the PRIMME library.

481:    Collective on EPS

483:    Input Parameters:
484: +  eps - the eigenproblem solver context
485: -  method - method that will be used by PRIMME. It must be one of:
486:     EPSPRIMME_DEFAULT_MIN_TIME(EPSPRIMME_JDQMR_ETOL),
487:     EPSPRIMME_DEFAULT_MIN_MATVECS(EPSPRIMME_GD_OLSEN_PLUSK), EPSPRIMME_ARNOLDI,
488:     EPSPRIMME_GD, EPSPRIMME_GD_PLUSK, EPSPRIMME_GD_OLSEN_PLUSK, 
489:     EPSPRIMME_JD_OlSEN_PLUSK, EPSPRIMME_RQI, EPSPRIMME_JDQR, EPSPRIMME_JDQMR, 
490:     EPSPRIMME_JDQMR_ETOL, EPSPRIMME_SUBSPACE_ITERATION,
491:     EPSPRIMME_LOBPCG_ORTHOBASIS, EPSPRIMME_LOBPCG_ORTHOBASIS_WINDOW

493:    Options Database Key:
494: .  -eps_primme_set_method - Sets the method for the PRIMME library.

496:    Note:
497:    If not set, the method defaults to EPSPRIMME_DEFAULT_MIN_TIME.

499:    Level: advanced
500: .seealso: EPSPRIMMEGetMethod()  
501: @*/
502: PetscErrorCode EPSPRIMMESetMethod(EPS eps, EPSPRIMMEMethod method)
503: {
504:   PetscErrorCode ierr, (*f)(EPS,EPSPRIMMEMethod);

507: 
509:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetMethod_C",(void (**)())&f);
510:   if (f) {
511:     (*f)(eps,method);
512:   }
513: 
514:   return(0);
515: }

520: PetscErrorCode EPSPRIMMEGetMethod_PRIMME(EPS eps, EPSPRIMMEMethod *method)
521: {
522:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


526:   if (method) *method = (EPSPRIMMEMethod)ops->method;
527: 
528:   return(0);
529: }

534: /*@C
535:     EPSPRIMMEGetMethod - Gets the method for the PRIMME library.

537:     Mon Collective on EPS

539:    Input Parameters:
540: .  eps - the eigenproblem solver context
541:     
542:    Output Parameters: 
543: .  method - method that will be used by PRIMME. It must be one of:
544:     EPSPRIMME_DEFAULT_MIN_TIME(EPSPRIMME_JDQMR_ETOL),
545:     EPSPRIMME_DEFAULT_MIN_MATVECS(EPSPRIMME_GD_OLSEN_PLUSK), EPSPRIMME_ARNOLDI,
546:     EPSPRIMME_GD, EPSPRIMME_GD_PLUSK, EPSPRIMME_GD_OLSEN_PLUSK, 
547:     EPSPRIMME_JD_OlSEN_PLUSK, EPSPRIMME_RQI, EPSPRIMME_JDQR, EPSPRIMME_JDQMR, 
548:     EPSPRIMME_JDQMR_ETOL, EPSPRIMME_SUBSPACE_ITERATION,
549:     EPSPRIMME_LOBPCG_ORTHOBASIS, EPSPRIMME_LOBPCG_ORTHOBASIS_WINDOW

551:     Level: advanced
552: .seealso: EPSPRIMMESetMethod()
553: @*/
554: PetscErrorCode EPSPRIMMEGetMethod(EPS eps, EPSPRIMMEMethod *method)
555: {
556:   PetscErrorCode ierr, (*f)(EPS,EPSPRIMMEMethod*);

559: 
561:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetMethod_C",(void (**)())&f);
562:   if (f) {
563:     (*f)(eps,method);
564:   }
565: 
566:   return(0);
567: }


573:     PetscErrorCode EPSPRIMMESetPrecond_PRIMME(EPS eps, EPSPRIMMEPrecond precond)
574: {
575:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


579:   if (precond == EPSPRIMME_NONE) ops->primme.correctionParams.precondition = 0;
580:   else ops->primme.correctionParams.precondition = 1;
581: 
582:   return(0);
583: }

588: /*@
589:     EPSPRIMMESetPrecond - Sets the preconditioner to be used in the PRIMME
590:     library. Currently, only diagonal preconditioning is supported.

592:     Collective on EPS

594:    Input Parameters:
595: +  eps - the eigenproblem solver context
596: -  precond - either EPSPRIMME_NONE (no preconditioning) or EPSPRIMME_DIAGONAL
597:    (diagonal preconditioning)

599:    Options Database Key:
600: .  -eps_primme_precond - Sets either 'none' or 'diagonal' preconditioner

602:     Note:
603:     The default is no preconditioning.
604:     
605:     Level: advanced
606: .seealso: EPSPRIMMEGetPrecond()
607: @*/
608: PetscErrorCode EPSPRIMMESetPrecond(EPS eps, EPSPRIMMEPrecond precond)
609: {
610:   PetscErrorCode ierr, (*f)(EPS, EPSPRIMMEPrecond);

613: 
615:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetPrecond_C",(void (**)())&f);
616:   if (f) {
617:     (*f)(eps, precond);
618:   }
619: 
620:   return(0);
621: }


627:     PetscErrorCode EPSPRIMMEGetPrecond_PRIMME(EPS eps, EPSPRIMMEPrecond *precond)
628: {
629:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


633:   if (precond)
634:     *precond = ops->primme.correctionParams.precondition ? EPSPRIMME_DIAGONAL : EPSPRIMME_NONE;
635: 
636:   return(0);
637: }

642: /*@C
643:     EPSPRIMMEGetPrecond - Gets the preconditioner to be used in the PRIMME
644:     library.

646:     Collective on EPS

648:    Input Parameters:
649: .  eps - the eigenproblem solver context
650:     
651:   Output Parameters:
652: .  precond - either EPSPRIMME_NONE (no preconditioning) or EPSPRIMME_DIAGONAL
653:    (diagonal preconditioning)

655:     Level: advanced
656: .seealso: EPSPRIMMESetPrecond()
657: @*/
658: PetscErrorCode EPSPRIMMEGetPrecond(EPS eps, EPSPRIMMEPrecond *precond)
659: {
660:   PetscErrorCode ierr, (*f)(EPS, EPSPRIMMEPrecond*);

663: 
665:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetPrecond_C",(void (**)())&f);
666:   if (f) {
667:     (*f)(eps, precond);
668:   }
669: 
670:   return(0);
671: }


677: PetscErrorCode EPSCreate_PRIMME(EPS eps)
678: {
680:   EPS_PRIMME     *primme;

683: 
684:   PetscNew(EPS_PRIMME,&primme);
685:   PetscLogObjectMemory(eps,sizeof(EPS_PRIMME));
686:   eps->data                      = (void *) primme;
687:   eps->ops->solve                = EPSSolve_PRIMME;
688:   eps->ops->setup                = EPSSetUp_PRIMME;
689:   eps->ops->setfromoptions       = EPSSetFromOptions_PRIMME;
690:   eps->ops->destroy              = EPSDestroy_PRIMME;
691:   eps->ops->view                 = EPSView_PRIMME;
692:   eps->ops->backtransform        = EPSBackTransform_Default;
693:   eps->ops->computevectors       = EPSComputeVectors_Default;

695:   primme_initialize(&primme->primme);
696:   primme->primme.matrixMatvec = multMatvec_PRIMME;
697:   primme->method = DEFAULT_MIN_TIME;
698: 
699:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetBlockSize_C","EPSPRIMMESetBlockSize_PRIMME",EPSPRIMMESetBlockSize_PRIMME);
700:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetMethod_C","EPSPRIMMESetMethod_PRIMME",EPSPRIMMESetMethod_PRIMME);
701:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetPrecond_C","EPSPRIMMESetPrecond_PRIMME",EPSPRIMMESetPrecond_PRIMME);
702: 
703:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetBlockSize_C","EPSPRIMMEGetBlockSize_PRIMME",EPSPRIMMEGetBlockSize_PRIMME);
704:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetMethod_C","EPSPRIMMEGetMethod_PRIMME",EPSPRIMMEGetMethod_PRIMME);
705:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetPrecond_C","EPSPRIMMEGetPrecond_PRIMME",EPSPRIMMEGetPrecond_PRIMME);

707:   eps->which = EPS_LARGEST_REAL;

709:   return(0);
710: }