Actual source code: primmes.c

  1: /*
  2:        This file implements a wrapper to the PRIMME library

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2009, Universidad Politecnica de Valencia, Spain

  8:    This file is part of SLEPc.
  9:       
 10:    SLEPc is free software: you can redistribute it and/or modify it under  the
 11:    terms of version 3 of the GNU Lesser General Public License as published by
 12:    the Free Software Foundation.

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

 19:    You  should have received a copy of the GNU Lesser General  Public  License
 20:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 21:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 22: */

 24:  #include private/epsimpl.h
 25:  #include private/stimpl.h

 28: #include "primme.h"

 31: typedef struct {
 32:   primme_params primme;           /* param struc */
 33:   primme_preset_method method;    /* primme method */
 34:   Mat A;                          /* problem matrix */
 35:   Vec w;                          /* store reciprocal A diagonal */
 36:   Vec x,y;                        /* auxiliar vectors */
 37: } EPS_PRIMME;

 39: const char *methodList[] = {
 40:   "dynamic",
 41:   "default_min_time",
 42:   "default_min_matvecs",
 43:   "arnoldi",
 44:   "gd",
 45:   "gd_plusk",
 46:   "gd_olsen_plusk",
 47:   "jd_olsen_plusk",
 48:   "rqi",
 49:   "jdqr",
 50:   "jdqmr",
 51:   "jdqmr_etol",
 52:   "subspace_iteration",
 53:   "lobpcg_orthobasis",
 54:   "lobpcg_orthobasis_window"
 55: };
 56: const char *precondList[] = {"none", "diagonal"};
 57: EPSPRIMMEMethod methodN[] = {
 58:   EPSPRIMME_DYNAMIC,
 59:   EPSPRIMME_DEFAULT_MIN_TIME,
 60:   EPSPRIMME_DEFAULT_MIN_MATVECS,
 61:   EPSPRIMME_ARNOLDI,
 62:   EPSPRIMME_GD,
 63:   EPSPRIMME_GD_PLUSK,
 64:   EPSPRIMME_GD_OLSEN_PLUSK,
 65:   EPSPRIMME_JD_OLSEN_PLUSK,
 66:   EPSPRIMME_RQI,
 67:   EPSPRIMME_JDQR,
 68:   EPSPRIMME_JDQMR,
 69:   EPSPRIMME_JDQMR_ETOL,
 70:   EPSPRIMME_SUBSPACE_ITERATION,
 71:   EPSPRIMME_LOBPCG_ORTHOBASIS,
 72:   EPSPRIMME_LOBPCG_ORTHOBASISW
 73: };
 74: EPSPRIMMEPrecond precondN[] = {EPSPRIMME_NONE, EPSPRIMME_DIAGONAL};

 76: static void multMatvec_PRIMME(void *in, void *out, int *blockSize, primme_params *primme);
 77: static void applyPreconditioner_PRIMME(void *in, void *out, int *blockSize, struct primme_params *primme);

 79: void par_GlobalSumDouble(void *sendBuf, void *recvBuf, int *count, primme_params *primme) {
 81:   MPI_Allreduce((double*)sendBuf, (double*)recvBuf, *count, MPI_DOUBLE, MPI_SUM, ((PetscObject)(primme->commInfo))->comm);CHKERRABORT(((PetscObject)(primme->commInfo))->comm,ierr);
 82: }

 86: PetscErrorCode EPSSetUp_PRIMME(EPS eps)
 87: {
 89:   PetscInt       N, n;
 90:   PetscMPIInt    numProcs, procID;
 91:   EPS_PRIMME     *ops = (EPS_PRIMME *)eps->data;
 92:   primme_params  *primme = &(((EPS_PRIMME *)eps->data)->primme);


 96:   MPI_Comm_size(((PetscObject)eps)->comm,&numProcs);
 97:   MPI_Comm_rank(((PetscObject)eps)->comm,&procID);
 98: 
 99:   /* Check some constraints and set some default values */
100:   VecGetSize(eps->vec_initial,&N);
101:   VecGetLocalSize(eps->vec_initial,&n);

103:   if (!eps->max_it) eps->max_it = PetscMax(1000,N);
104:   STGetOperators(eps->OP, &ops->A, PETSC_NULL);
105:   if (!ops->A) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"The problem matrix has to be specified first");
106:   if (!eps->ishermitian)
107:     SETERRQ(PETSC_ERR_SUP,"PRIMME is only available for Hermitian problems");
108:   if (eps->isgeneralized)
109:     SETERRQ(PETSC_ERR_SUP,"PRIMME is not available for generalized problems");

111:   /* Transfer SLEPc options to PRIMME options */
112:   primme->n = N;
113:   primme->nLocal = n;
114:   primme->numEvals = eps->nev;
115:   primme->matrix = ops;
116:   primme->commInfo = eps;
117:   primme->maxMatvecs = eps->max_it;
118:   primme->eps = eps->tol;
119:   primme->numProcs = numProcs;
120:   primme->procID = procID;
121:   primme->printLevel = 5;

123:   switch(eps->which) {
124:     case EPS_LARGEST_REAL:
125:       primme->target = primme_largest;
126:       break;

128:     case EPS_SMALLEST_REAL:
129:       primme->target = primme_smallest;
130:       break;
131: 
132:     default:
133:       SETERRQ(PETSC_ERR_SUP,"PRIMME only allows EPS_LARGEST_REAL and EPS_SMALLEST_REAL for 'which' value");
134:       break;
135:   }
136: 
137:   if (primme_set_method(ops->method, primme) < 0)
138:     SETERRQ(PETSC_ERR_SUP,"PRIMME method not valid");
139: 
140:   /* If user sets ncv, maxBasisSize is modified. If not, ncv is set as maxBasisSize */
141:   if (eps->ncv) primme->maxBasisSize = eps->ncv;
142:   else eps->ncv = primme->maxBasisSize;
143:   if (eps->ncv < eps->nev+primme->maxBlockSize)
144:     SETERRQ(PETSC_ERR_SUP,"PRIMME needs ncv >= nev+maxBlockSize");
145:   if (eps->mpd) PetscInfo(eps,"Warning: parameter mpd ignored\n");

147:   if (eps->extraction) {
148:      PetscInfo(eps,"Warning: extraction type ignored\n");
149:   }

151:   /* Set workspace */
152:   EPSAllocateSolution(eps);

154:   if (primme->correctionParams.precondition) {
155:     /* Calc reciprocal A diagonal */
156:     VecDuplicate(eps->vec_initial, &ops->w);
157:     MatGetDiagonal(ops->A, ops->w);
158:     VecReciprocal(ops->w);
159:     primme->preconditioner = PETSC_NULL;
160:     primme->applyPreconditioner = applyPreconditioner_PRIMME;
161:   }

163:   /* Prepare auxiliary vectors */
164:   VecCreateMPIWithArray(PETSC_COMM_WORLD,n,N,PETSC_NULL,&ops->x);
165:   VecCreateMPIWithArray(PETSC_COMM_WORLD,n,N,PETSC_NULL,&ops->y);
166: 
167:   return(0);
168: }

172: PetscErrorCode EPSSolve_PRIMME(EPS eps)
173: {
175:   EPS_PRIMME     *ops = (EPS_PRIMME *)eps->data;
176:   PetscScalar    *a;
177: #ifdef PETSC_USE_COMPLEX
178:   PetscInt       i;
179:   PetscReal      *evals;
180: #endif


184:   /* Reset some parameters left from previous runs */
185:   ops->primme.aNorm    = 0.0;
186:   ops->primme.initSize = 1;
187:   ops->primme.iseed[0] = -1;

189:   /* Copy vec_initial to V[0] vector */
190:   VecCopy(eps->vec_initial, eps->V[0]);
191: 
192:   /* Call PRIMME solver */
193:   VecGetArray(eps->V[0], &a);
194: #ifndef PETSC_USE_COMPLEX
195:   dprimme(eps->eigr, a, eps->errest, &ops->primme);
196: #else
197:   /* PRIMME returns real eigenvalues, but SLEPc works with complex ones */
198:   PetscMalloc(eps->ncv*sizeof(PetscReal),&evals);
199:   zprimme(evals, (Complex_Z*)a, eps->errest, &ops->primme);
200:   for (i=0;i<eps->ncv;i++)
201:     eps->eigr[i] = evals[i];
202:   PetscFree(evals);
203: #endif
204:   VecRestoreArray(eps->V[0], &a);
205: 
206:   switch(ierr) {
207:     case 0: /* Successful */
208:       break;

210:     case -1:
211:       SETERRQ(PETSC_ERR_SUP,"PRIMME: Failed to open output file");
212:       break;

214:     case -2:
215:       SETERRQ(PETSC_ERR_SUP,"PRIMME: Insufficient integer or real workspace allocated");
216:       break;

218:     case -3:
219:       SETERRQ(PETSC_ERR_SUP,"PRIMME: main_iter encountered a problem");
220:       break;

222:     default:
223:       SETERRQ(PETSC_ERR_SUP,"PRIMME: some parameters wrong configured");
224:       break;
225:   }

227:   eps->nconv = ops->primme.initSize >= 0 ? ops->primme.initSize : 0;
228:   eps->reason = eps->ncv >= eps->nev ? EPS_CONVERGED_TOL : EPS_DIVERGED_ITS;
229:   eps->its = ops->primme.stats.numOuterIterations;
230:   eps->OP->applys = ops->primme.stats.numMatvecs;

232:   return(0);
233: }

237: static void multMatvec_PRIMME(void *in, void *out, int *blockSize, primme_params *primme)
238: {
240:   PetscInt       i, N = primme->n;
241:   EPS_PRIMME     *ops = (EPS_PRIMME *)primme->matrix;
242:   Vec            x = ops->x;
243:   Vec            y = ops->y;
244:   Mat            A = ops->A;

247:   for (i=0;i<*blockSize;i++) {
248:     /* build vectors using 'in' an 'out' workspace */
249:     VecPlaceArray(x, (PetscScalar*)in+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);
250:     VecPlaceArray(y, (PetscScalar*)out+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);

252:     MatMult(A, x, y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
253: 
254:     VecResetArray(x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
255:     VecResetArray(y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
256:   }
257:   PetscFunctionReturnVoid();
258: }

262: static void applyPreconditioner_PRIMME(void *in, void *out, int *blockSize, struct primme_params *primme)
263: {
265:   PetscInt       i, N = primme->n;
266:   EPS_PRIMME     *ops = (EPS_PRIMME *)primme->matrix;
267:   Vec            x = ops->x;
268:   Vec            y = ops->y;
269:   Vec            w = ops->w;
270: 
272:   for (i=0;i<*blockSize;i++) {
273:     /* build vectors using 'in' an 'out' workspace */
274:     VecPlaceArray(x, (PetscScalar*)in+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);
275:     VecPlaceArray(y, (PetscScalar*)out+N*i ); CHKERRABORT(PETSC_COMM_WORLD,ierr);

277:     VecPointwiseMult(y, w, x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
278: 
279:     VecResetArray(x); CHKERRABORT(PETSC_COMM_WORLD,ierr);
280:     VecResetArray(y); CHKERRABORT(PETSC_COMM_WORLD,ierr);
281:   }
282:   PetscFunctionReturnVoid();
283: }


288: PetscErrorCode EPSDestroy_PRIMME(EPS eps)
289: {
291:   EPS_PRIMME    *ops = (EPS_PRIMME *)eps->data;

295: 
296:   if (ops->primme.correctionParams.precondition) {
297:     VecDestroy(ops->w);
298:   }
299:   primme_Free(&ops->primme);
300:   VecDestroy(ops->x);
301:   VecDestroy(ops->y);
302:   PetscFree(eps->data);
303:   EPSFreeSolution(eps);
304: 
305:   return(0);
306: }

310: PetscErrorCode EPSView_PRIMME(EPS eps,PetscViewer viewer)
311: {
313:   PetscTruth isascii;
314:   primme_params *primme = &((EPS_PRIMME *)eps->data)->primme;
315:   EPSPRIMMEMethod methodn;
316:   EPSPRIMMEPrecond precondn;

319:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);
320:   if (!isascii) {
321:     SETERRQ1(1,"Viewer type %s not supported for EPSPRIMME",((PetscObject)viewer)->type_name);
322:   }
323: 
324:   PetscViewerASCIIPrintf(viewer,"PRIMME solver block size: %d\n",primme->maxBlockSize);
325:   EPSPRIMMEGetMethod(eps, &methodn);
326:   PetscViewerASCIIPrintf(viewer,"PRIMME solver method: %s\n", methodList[methodn]);
327:   EPSPRIMMEGetPrecond(eps, &precondn);
328:   PetscViewerASCIIPrintf(viewer,"PRIMME solver preconditioning: %s\n", precondList[precondn]);

330:   primme_display_params(*primme);
331:   return(0);
332: }

336: PetscErrorCode EPSSetFromOptions_PRIMME(EPS eps)
337: {
339:   EPS_PRIMME    *ops = (EPS_PRIMME *)eps->data;
340:   PetscInt       op;
341:   PetscTruth     flg;

344: 
345:   PetscOptionsHead("PRIMME options");

347:   op = ops->primme.maxBlockSize;
348:   PetscOptionsInt("-eps_primme_block_size"," maximum block size","EPSPRIMMESetBlockSize",op,&op,&flg);
349:   if (flg) {EPSPRIMMESetBlockSize(eps,op);}
350:   op = 0;
351:   PetscOptionsEList("-eps_primme_method","set method for solving the eigenproblem",
352:                            "EPSPRIMMESetMethod",methodList,15,methodList[1],&op,&flg);
353:   if (flg) {EPSPRIMMESetMethod(eps, methodN[op]);}
354:   PetscOptionsEList("-eps_primme_precond","set preconditioner type",
355:                            "EPSPRIMMESetPrecond",precondList,2,precondList[0],&op,&flg);
356:   if (flg) {EPSPRIMMESetPrecond(eps, precondN[op]);}
357: 
358:   PetscOptionsTail();
359: 
360:   return(0);
361: }

366: PetscErrorCode EPSPRIMMESetBlockSize_PRIMME(EPS eps,PetscInt bs)
367: {
368:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


372:   if (bs == PETSC_DEFAULT) ops->primme.maxBlockSize = 1;
373:   else if (bs <= 0) {
374:     SETERRQ(1, "PRIMME: wrong block size");
375:   } else ops->primme.maxBlockSize = bs;
376: 
377:   return(0);
378: }

383: /*@
384:     EPSPRIMMESetBlockSize - The maximum block size the code will try to use. 
385:     The user should set
386:     this based on the architecture specifics of the target computer, 
387:     as well as any a priori knowledge of multiplicities. The code does 
388:     NOT require BlockSize > 1 to find multiple eigenvalues.  For some 
389:     methods, keeping BlockSize = 1 yields the best overall performance.

391:    Collective on EPS

393:    Input Parameters:
394: +  eps - the eigenproblem solver context
395: -  bs - block size

397:    Options Database Key:
398: .  -eps_primme_block_size - Sets the max allowed block size value

400:    Notes:
401:    If the block size is not set, the value established by primme_initialize
402:    is used.

404:    Level: advanced
405: .seealso: EPSPRIMMEGetBlockSize()
406: @*/
407: PetscErrorCode EPSPRIMMESetBlockSize(EPS eps,PetscInt bs)
408: {
409:   PetscErrorCode ierr, (*f)(EPS,PetscInt);

412: 
414:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetBlockSize_C",(void (**)())&f);
415:   if (f) {
416:     (*f)(eps,bs);
417:   }
418: 
419:   return(0);
420: }

425: PetscErrorCode EPSPRIMMEGetBlockSize_PRIMME(EPS eps,PetscInt *bs)
426: {
427:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


431:   if (bs) *bs = ops->primme.maxBlockSize;
432: 
433:   return(0);
434: }

439: /*@
440:     EPSPRIMMEGetBlockSize - Get the maximum block size the code will try to use. 
441:     
442:     Collective on EPS

444:    Input Parameters:
445: .  eps - the eigenproblem solver context
446:     
447:    Output Parameters:  
448: .  bs - returned block size 

450:    Level: advanced
451: .seealso: EPSPRIMMESetBlockSize()
452: @*/
453: PetscErrorCode EPSPRIMMEGetBlockSize(EPS eps,PetscInt *bs)
454: {
455:   PetscErrorCode ierr, (*f)(EPS,PetscInt*);

458: 
460:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetBlockSize_C",(void (**)())&f);
461:   if (f) {
462:     (*f)(eps,bs);
463:   }
464: 
465:   return(0);
466: }

471: PetscErrorCode EPSPRIMMESetMethod_PRIMME(EPS eps, EPSPRIMMEMethod method)
472: {
473:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


477:   if (method == PETSC_DEFAULT) ops->method = DEFAULT_MIN_TIME;
478:   else ops->method = (primme_preset_method)method;

480:   return(0);
481: }

486: /*@
487:    EPSPRIMMESetMethod - Sets the method for the PRIMME library.

489:    Collective on EPS

491:    Input Parameters:
492: +  eps - the eigenproblem solver context
493: -  method - method that will be used by PRIMME. It must be one of:
494:     EPSPRIMME_DYNAMIC, EPSPRIMME_DEFAULT_MIN_TIME(EPSPRIMME_JDQMR_ETOL),
495:     EPSPRIMME_DEFAULT_MIN_MATVECS(EPSPRIMME_GD_OLSEN_PLUSK), EPSPRIMME_ARNOLDI,
496:     EPSPRIMME_GD, EPSPRIMME_GD_PLUSK, EPSPRIMME_GD_OLSEN_PLUSK, 
497:     EPSPRIMME_JD_OLSEN_PLUSK, EPSPRIMME_RQI, EPSPRIMME_JDQR, EPSPRIMME_JDQMR, 
498:     EPSPRIMME_JDQMR_ETOL, EPSPRIMME_SUBSPACE_ITERATION,
499:     EPSPRIMME_LOBPCG_ORTHOBASIS, EPSPRIMME_LOBPCG_ORTHOBASISW

501:    Options Database Key:
502: .  -eps_primme_set_method - Sets the method for the PRIMME library.

504:    Note:
505:    If not set, the method defaults to EPSPRIMME_DEFAULT_MIN_TIME.

507:    Level: advanced

509: .seealso: EPSPRIMMEGetMethod(), EPSPRIMMEMethod
510: @*/
511: PetscErrorCode EPSPRIMMESetMethod(EPS eps, EPSPRIMMEMethod method)
512: {
513:   PetscErrorCode ierr, (*f)(EPS,EPSPRIMMEMethod);

516: 
518:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetMethod_C",(void (**)())&f);
519:   if (f) {
520:     (*f)(eps,method);
521:   }
522: 
523:   return(0);
524: }

529: PetscErrorCode EPSPRIMMEGetMethod_PRIMME(EPS eps, EPSPRIMMEMethod *method)
530: {
531:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


535:   if (method)
536:     *method = (EPSPRIMMEMethod)ops->method;

538:   return(0);
539: }

544: /*@C
545:     EPSPRIMMEGetMethod - Gets the method for the PRIMME library.

547:     Mon Collective on EPS

549:    Input Parameters:
550: .  eps - the eigenproblem solver context
551:     
552:    Output Parameters: 
553: .  method - method that will be used by PRIMME. It must be one of:
554:     EPSPRIMME_DYNAMIC, EPSPRIMME_DEFAULT_MIN_TIME(EPSPRIMME_JDQMR_ETOL),
555:     EPSPRIMME_DEFAULT_MIN_MATVECS(EPSPRIMME_GD_OLSEN_PLUSK), EPSPRIMME_ARNOLDI,
556:     EPSPRIMME_GD, EPSPRIMME_GD_PLUSK, EPSPRIMME_GD_OLSEN_PLUSK, 
557:     EPSPRIMME_JD_OLSEN_PLUSK, EPSPRIMME_RQI, EPSPRIMME_JDQR, EPSPRIMME_JDQMR, 
558:     EPSPRIMME_JDQMR_ETOL, EPSPRIMME_SUBSPACE_ITERATION,
559:     EPSPRIMME_LOBPCG_ORTHOBASIS, EPSPRIMME_LOBPCG_ORTHOBASISW

561:     Level: advanced

563: .seealso: EPSPRIMMESetMethod(), EPSPRIMMEMethod
564: @*/
565: PetscErrorCode EPSPRIMMEGetMethod(EPS eps, EPSPRIMMEMethod *method)
566: {
567:   PetscErrorCode ierr, (*f)(EPS,EPSPRIMMEMethod*);

570: 
572:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetMethod_C",(void (**)())&f);
573:   if (f) {
574:     (*f)(eps,method);
575:   }
576: 
577:   return(0);
578: }


584:     PetscErrorCode EPSPRIMMESetPrecond_PRIMME(EPS eps, EPSPRIMMEPrecond precond)
585: {
586:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


590:   if (precond == EPSPRIMME_NONE) ops->primme.correctionParams.precondition = 0;
591:   else ops->primme.correctionParams.precondition = 1;
592: 
593:   return(0);
594: }

599: /*@
600:     EPSPRIMMESetPrecond - Sets the preconditioner to be used in the PRIMME
601:     library. Currently, only diagonal preconditioning is supported.

603:     Collective on EPS

605:    Input Parameters:
606: +  eps - the eigenproblem solver context
607: -  precond - either EPSPRIMME_NONE (no preconditioning) or EPSPRIMME_DIAGONAL
608:    (diagonal preconditioning)

610:    Options Database Key:
611: .  -eps_primme_precond - Sets either 'none' or 'diagonal' preconditioner

613:     Note:
614:     The default is no preconditioning.
615:     
616:     Level: advanced

618: .seealso: EPSPRIMMEGetPrecond(), EPSPRIMMEPrecond
619: @*/
620: PetscErrorCode EPSPRIMMESetPrecond(EPS eps, EPSPRIMMEPrecond precond)
621: {
622:   PetscErrorCode ierr, (*f)(EPS, EPSPRIMMEPrecond);

625: 
627:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMESetPrecond_C",(void (**)())&f);
628:   if (f) {
629:     (*f)(eps, precond);
630:   }
631: 
632:   return(0);
633: }


639:     PetscErrorCode EPSPRIMMEGetPrecond_PRIMME(EPS eps, EPSPRIMMEPrecond *precond)
640: {
641:   EPS_PRIMME *ops = (EPS_PRIMME *) eps->data;


645:   if (precond)
646:     *precond = ops->primme.correctionParams.precondition ? EPSPRIMME_DIAGONAL : EPSPRIMME_NONE;
647: 
648:   return(0);
649: }

654: /*@C
655:     EPSPRIMMEGetPrecond - Gets the preconditioner to be used in the PRIMME
656:     library.

658:     Collective on EPS

660:    Input Parameters:
661: .  eps - the eigenproblem solver context
662:     
663:   Output Parameters:
664: .  precond - either EPSPRIMME_NONE (no preconditioning) or EPSPRIMME_DIAGONAL
665:    (diagonal preconditioning)

667:     Level: advanced

669: .seealso: EPSPRIMMESetPrecond(), EPSPRIMMEPrecond
670: @*/
671: PetscErrorCode EPSPRIMMEGetPrecond(EPS eps, EPSPRIMMEPrecond *precond)
672: {
673:   PetscErrorCode ierr, (*f)(EPS, EPSPRIMMEPrecond*);

676: 
678:   PetscObjectQueryFunction((PetscObject)eps,"EPSPRIMMEGetPrecond_C",(void (**)())&f);
679:   if (f) {
680:     (*f)(eps, precond);
681:   }
682: 
683:   return(0);
684: }


690: PetscErrorCode EPSCreate_PRIMME(EPS eps)
691: {
693:   EPS_PRIMME     *primme;

696: 
697:   PetscNew(EPS_PRIMME,&primme);
698:   PetscLogObjectMemory(eps,sizeof(EPS_PRIMME));
699:   eps->data                      = (void *) primme;
700:   eps->ops->solve                = EPSSolve_PRIMME;
701:   eps->ops->setup                = EPSSetUp_PRIMME;
702:   eps->ops->setfromoptions       = EPSSetFromOptions_PRIMME;
703:   eps->ops->destroy              = EPSDestroy_PRIMME;
704:   eps->ops->view                 = EPSView_PRIMME;
705:   eps->ops->backtransform        = EPSBackTransform_Default;
706:   eps->ops->computevectors       = EPSComputeVectors_Default;

708:   primme_initialize(&primme->primme);
709:   primme->primme.matrixMatvec = multMatvec_PRIMME;
710:   primme->primme.globalSumDouble = par_GlobalSumDouble;
711:   primme->method = (primme_preset_method)EPSPRIMME_DEFAULT_MIN_TIME;
712:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetBlockSize_C","EPSPRIMMESetBlockSize_PRIMME",EPSPRIMMESetBlockSize_PRIMME);
713:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetMethod_C","EPSPRIMMESetMethod_PRIMME",EPSPRIMMESetMethod_PRIMME);
714:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMESetPrecond_C","EPSPRIMMESetPrecond_PRIMME",EPSPRIMMESetPrecond_PRIMME);
715: 
716:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetBlockSize_C","EPSPRIMMEGetBlockSize_PRIMME",EPSPRIMMEGetBlockSize_PRIMME);
717:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetMethod_C","EPSPRIMMEGetMethod_PRIMME",EPSPRIMMEGetMethod_PRIMME);
718:   PetscObjectComposeFunctionDynamic((PetscObject)eps,"EPSPRIMMEGetPrecond_C","EPSPRIMMEGetPrecond_PRIMME",EPSPRIMMEGetPrecond_PRIMME);

720:   eps->which = EPS_LARGEST_REAL;

722:   return(0);
723: }