Date: 2013-09-02T10:04:08+00:00

Actual source code: dvd_updatev.c

      1: /*
      2:   SLEPc eigensolver: "davidson"

      4:   Step: test for restarting, updateV, restartV

      6:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      7:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      8:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

     10:    This file is part of SLEPc.

     12:    SLEPc is free software: you can redistribute it and/or modify it under  the
     13:    terms of version 3 of the GNU Lesser General Public License as published by
     14:    the Free Software Foundation.

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

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

     26:  #include davidson.h
     27: #include <slepc-private/dsimpl.h>      /*I "slepcds.h" I*/

     29: PetscErrorCode dvd_updateV_start(dvdDashboard *d);
     30: PetscBool dvd_isrestarting_fullV(dvdDashboard *d);
     31: PetscErrorCode dvd_managementV_basic_d(dvdDashboard *d);
     32: PetscErrorCode dvd_updateV_extrapol(dvdDashboard *d);
     33: PetscErrorCode dvd_updateV_conv_gen(dvdDashboard *d);
     34: PetscErrorCode dvd_updateV_restart_gen(dvdDashboard *d);
     35: PetscErrorCode dvd_updateV_update_gen(dvdDashboard *d);
     36: PetscErrorCode dvd_updateV_testConv(dvdDashboard *d,PetscInt s,PetscInt pre,PetscInt e,Vec *auxV,PetscScalar *auxS,PetscInt *nConv);

     38: typedef struct {
     39:   PetscInt
     40:     min_size_V,     /* restart with this number of eigenvectors */
     41:     plusk,          /* when restart, save plusk vectors from last iteration */
     42:     mpd;            /* max size of the searching subspace */
     43:   void
     44:     *old_updateV_data;
     45:                     /* old updateV data */
     46:   isRestarting_type
     47:     old_isRestarting;
     48:                     /* old isRestarting */
     49:   PetscScalar
     50:     *oldU,          /* previous projected right igenvectors */
     51:     *oldV;          /* previous projected left eigenvectors */
     52:   PetscInt
     53:     ldoldU,         /* leading dimension of oldU */
     54:     size_oldU;      /* size of oldU */
     55:   PetscBool
     56:     allResiduals;   /* if computing all the residuals */
     57: } dvdManagV_basic;

     62: PetscErrorCode dvd_managementV_basic(dvdDashboard *d,dvdBlackboard *b,PetscInt bs,PetscInt mpd,PetscInt min_size_V,PetscInt plusk,PetscBool harm,PetscBool allResiduals)
     63: {
     64:   PetscErrorCode  ierr;
     65:   dvdManagV_basic *data;
     66: #if !defined(PETSC_USE_COMPLEX)
     67:   PetscBool       her_probl, std_probl;
     68: #endif

     71:   /* Setting configuration constrains */
     72: #if !defined(PETSC_USE_COMPLEX)
     73:   /* if the last converged eigenvalue is complex its conjugate pair is also
     74:      converged */
     75:   her_probl = DVD_IS(d->sEP, DVD_EP_HERMITIAN)?PETSC_TRUE:PETSC_FALSE;
     76:   std_probl = DVD_IS(d->sEP, DVD_EP_STD)?PETSC_TRUE:PETSC_FALSE;
     77:   b->max_size_X = PetscMax(b->max_size_X, bs+(her_probl && std_probl)?0:1);
     78: #else
     79:   b->max_size_X = PetscMax(b->max_size_X, bs);
     80: #endif

     82:   b->max_size_V = PetscMax(b->max_size_V, mpd);
     83:   min_size_V = PetscMin(min_size_V, mpd-bs);
     84:   b->max_size_auxV = PetscMax(b->max_size_auxV, 1); /* dvd_updateV_testConv */
     85:   b->size_V = PetscMax(b->size_V, b->max_size_V + b->max_size_P + b->max_nev);
     86:   b->own_scalars+= b->size_V*2 /* eigr, eigr */ +
     87:                    b->size_V /* nR */   +
     88:                    b->size_V /* nX */   +
     89:                    b->size_V /* errest */ +
     90:                    b->max_size_V*b->max_size_V*(harm?2:1)*(plusk>0?1:0)
     91:                                                /* oldU,oldV? */;
     92:   b->max_size_oldX = plusk;

     94:   /* Setup the step */
     95:   if (b->state >= DVD_STATE_CONF) {
     96:     PetscMalloc(sizeof(dvdManagV_basic),&data);
     97:     PetscLogObjectMemory(d->eps,sizeof(dvdManagV_basic));
     98:     data->mpd = b->max_size_V;
     99:     data->min_size_V = min_size_V;
    100:     d->bs = bs;
    101:     d->max_size_X = b->max_size_X;
    102:     data->plusk = plusk;
    103:     data->allResiduals = allResiduals;

    105:     d->size_real_eigr = b->size_V;
    106:     d->real_eigr = b->free_scalars; b->free_scalars+= b->size_V;
    107:     d->real_eigi = b->free_scalars; b->free_scalars+= b->size_V;
    108:     d->real_nR = (PetscReal*)b->free_scalars; b->free_scalars+= FromRealToScalar(b->size_V);
    109:     d->real_nX = (PetscReal*)b->free_scalars; b->free_scalars+= FromRealToScalar(b->size_V);
    110:     d->real_errest = (PetscReal*)b->free_scalars; b->free_scalars+= FromRealToScalar(b->size_V);
    111:     if (plusk > 0) {
    112:       data->oldU = b->free_scalars; b->free_scalars+= b->max_size_V*b->max_size_V;
    113:     }
    114:     if (harm) {
    115:       if (plusk > 0) {
    116:         data->oldV = b->free_scalars; b->free_scalars+= b->max_size_V*b->max_size_V;
    117:       }
    118:     } else {
    119:       data->oldV = NULL;
    120:     }

    122:     data->old_updateV_data = d->updateV_data;
    123:     d->updateV_data = data;
    124:     data->old_isRestarting = d->isRestarting;
    125:     d->isRestarting = dvd_isrestarting_fullV;
    126:     d->updateV = dvd_updateV_extrapol;
    127:     d->preTestConv = dvd_updateV_testConv;
    128:     DVD_FL_ADD(d->startList, dvd_updateV_start);
    129:     DVD_FL_ADD(d->destroyList, dvd_managementV_basic_d);
    130:   }
    131:   return(0);
    132: }

    136: PetscErrorCode dvd_updateV_start(dvdDashboard *d)
    137: {
    138:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    139:   PetscInt        i;

    142:   d->size_cX = 0;
    143:   d->eigr = d->ceigr = d->real_eigr;
    144:   d->eigi = d->ceigi = d->real_eigi;
    145:   for (i=0;i<d->size_real_V;i++) d->eigi[i] = 0.0;
    146:   d->nR = d->real_nR;
    147:   for (i=0;i<d->size_real_V;i++) d->nR[i] = PETSC_MAX_REAL;
    148:   d->nX = d->real_nX;
    149:   d->errest = d->real_errest;
    150:   for (i=0;i<d->size_real_V;i++) d->errest[i] = PETSC_MAX_REAL;
    151:   data->ldoldU = 0;
    152:   data->oldV = NULL;
    153:   data->size_oldU = 0;
    154:   d->nconv = 0;
    155:   d->npreconv = 0;
    156:   d->V_tra_s = d->V_tra_e = d->V_new_s = d->V_new_e = 0;
    157:   d->size_D = 0;
    158:   return(0);
    159: }

    163: PetscBool dvd_isrestarting_fullV(dvdDashboard *d)
    164: {
    165:   PetscBool       restart;
    166:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

    169:   restart = (d->size_V + d->max_size_X > PetscMin(data->mpd,d->max_size_V))?
    170:                 PETSC_TRUE:PETSC_FALSE;

    172:   /* Check old isRestarting function */
    173:   if (!restart && data->old_isRestarting)
    174:     restart = data->old_isRestarting(d);
    175:   PetscFunctionReturn(restart);
    176: }

    180: PetscErrorCode dvd_managementV_basic_d(dvdDashboard *d)
    181: {
    182:   PetscErrorCode  ierr;
    183:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

    186:   /* Restore changes in dvdDashboard */
    187:   d->updateV_data = data->old_updateV_data;

    189:   /* Free local data */
    190:   PetscFree(data);
    191:   return(0);
    192: }

    196: PetscErrorCode dvd_updateV_extrapol(dvdDashboard *d)
    197: {
    198:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    199:   PetscInt        i;
    200:   PetscErrorCode  ierr;

    203:   d->calcpairs_selectPairs(d, data->min_size_V);

    205:   /* If the subspaces doesn't need restart, add new vector */
    206:   if (!d->isRestarting(d)) {
    207:     d->size_D = 0;
    208:     dvd_updateV_update_gen(d);

    210:     /* If some vector were add, exit */
    211:     if (d->size_D > 0) return(0);
    212:   }

    214:   /* If some eigenpairs were converged, lock them  */
    215:   if (d->npreconv > 0) {
    216:     i = d->npreconv;
    217:     dvd_updateV_conv_gen(d);

    219:     /* If some eigenpair was locked, exit */
    220:     if (i > d->npreconv) return(0);
    221:   }

    223:   /* Else, a restarting is performed */
    224:   dvd_updateV_restart_gen(d);
    225:   return(0);
    226: }

    230: PetscErrorCode dvd_updateV_conv_gen(dvdDashboard *d)
    231: {
    232:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    233:   PetscInt        npreconv,ld,cMT,cMTX;
    234:   PetscErrorCode  ierr;
    235:   PetscScalar     *pQ,*pZ;
    236: #if !defined(PETSC_USE_COMPLEX)
    237:   PetscInt        i;
    238: #endif

    241:   npreconv = d->npreconv;
    242:   /* Constrains the converged pairs to nev */
    243: #if !defined(PETSC_USE_COMPLEX)
    244:   /* Tries to maintain together conjugate eigenpairs */
    245:   for (i=0; (i + (d->eigi[i]!=0.0?1:0) < npreconv) && (d->nconv + i < d->nev); i+= (d->eigi[i]!=0.0?2:1));
    246:   npreconv = i;
    247: #else
    248:   npreconv = PetscMax(PetscMin(d->nev - d->nconv, npreconv), 0);
    249: #endif
    250:   /* Quick exit */
    251:   if (npreconv == 0) return(0);

    253:   npreconv+= d->cX_in_H;
    254:   DSGetLeadingDimension(d->ps,&ld);
    255:   d->size_MT = d->size_H;
    256:   cMT = d->size_H - npreconv;
    257:   /* Harmonics restarts wiht right eigenvectors, and other with the left ones.
    258:      If the problem is standard or hermitian, left and right vectors are the same */
    259:   if (!(d->W||!d->cY||d->BcX||DVD_IS(d->sEP,DVD_EP_STD)||DVD_IS(d->sEP,DVD_EP_HERMITIAN))) {
    260:     /* ps.Q <- [ps.Q(0:npreconv-1) ps.Z(npreconv:size_H-1)] */
    261:     DSGetArray(d->ps,DS_MAT_Q,&pQ);
    262:     DSGetArray(d->ps,DS_MAT_Z,&pZ);
    263:     SlepcDenseCopy(&pQ[ld*npreconv],ld,&pZ[ld*npreconv],ld,d->size_H,cMT);
    264:     DSRestoreArray(d->ps,DS_MAT_Q,&pQ);
    265:     DSRestoreArray(d->ps,DS_MAT_Z,&pZ);
    266:   }
    267:   if (DVD_IS(d->sEP,DVD_EP_INDEFINITE)) {
    268:     DSPseudoOrthogonalize(d->ps,DS_MAT_Q,d->size_H,d->nBV-d->cX_in_H,&cMTX,d->nBpX);
    269:   } else {
    270:     DSOrthogonalize(d->ps,DS_MAT_Q,d->size_H,&cMTX);
    271:   }
    272:   cMT = cMTX - npreconv;

    274:   if (d->W) {
    275:     DSOrthogonalize(d->ps,DS_MAT_Z,d->size_H,&cMTX);
    276:     cMT = PetscMin(cMT,cMTX - npreconv);
    277:   }

    279:   /* Lock the converged pairs */
    280:   d->eigr+= npreconv-d->cX_in_H;
    281: #if !defined(PETSC_USE_COMPLEX)
    282:   if (d->eigi) d->eigi+= npreconv-d->cX_in_H;
    283: #endif
    284:   d->nconv+= npreconv-d->cX_in_H;
    285:   d->errest+= npreconv-d->cX_in_H;
    286:   /* Notify the changes in V and update the other subspaces */
    287:   d->V_tra_s = npreconv;          d->V_tra_e = d->size_H;
    288:   d->V_new_s = cMT;               d->V_new_e = d->V_new_s;
    289:   /* Remove oldU */
    290:   data->size_oldU = 0;

    292:   d->npreconv-= npreconv-d->cX_in_H;
    293:   return(0);
    294: }

    298: PetscErrorCode dvd_updateV_restart_gen(dvdDashboard *d)
    299: {
    300:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    301:   PetscInt        size_plusk,size_X,i,j,ld,cMTX,cMTY;
    302:   PetscScalar     *pQ,*pZ;
    303:   PetscErrorCode  ierr;

    306:   /* Select size_X desired pairs from V */
    307:   size_X = PetscMin(PetscMin(data->min_size_V,
    308:                              d->size_V),
    309:                              d->max_size_V);

    311:   /* Add plusk eigenvectors from the previous iteration */
    312:   size_plusk = PetscMax(0, PetscMin(PetscMin(data->plusk,
    313:                                     data->size_oldU),
    314:                                     d->max_size_V - size_X));

    316:   DSGetLeadingDimension(d->ps,&ld);
    317:   d->size_MT = d->size_H;
    318:   /* ps.Q <- orth([pX(0:size_X-1) [oldU(0:size_plusk-1); 0] ]) */
    319:   /* Harmonics restarts wiht right eigenvectors, and other with the left ones.
    320:      If the problem is standard or hermitian, left and right vectors are the same */
    321:   DSGetArray(d->ps,DS_MAT_Q,&pQ);
    322:   if (!(d->W||!d->cY||d->BcX||DVD_IS(d->sEP,DVD_EP_STD)||DVD_IS(d->sEP,DVD_EP_HERMITIAN))) {
    323:     DSGetArray(d->ps,DS_MAT_Z,&pZ);
    324:     SlepcDenseCopy(pQ,ld,pZ,ld,d->size_H,size_X);
    325:     DSRestoreArray(d->ps,DS_MAT_Z,&pZ);
    326:   }
    327:   if (size_plusk > 0 && DVD_IS(d->sEP,DVD_EP_INDEFINITE)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported plusk>0 in indefinite eigenvalue problems");
    328:   if (size_plusk > 0) {
    329:     SlepcDenseCopy(&pQ[ld*size_X],ld,data->oldU,data->ldoldU,data->size_oldU,size_plusk);
    330:     for (i=size_X;i<size_X+size_plusk;i++) {
    331:       for (j=data->size_oldU;j<d->size_H;j++) {
    332:         pQ[j*ld+i] = 0.0;
    333:       }
    334:     }
    335:   }
    336:   DSRestoreArray(d->ps,DS_MAT_Q,&pQ);
    337:   if (DVD_IS(d->sEP,DVD_EP_INDEFINITE)) {
    338:     DSPseudoOrthogonalize(d->ps,DS_MAT_Q,size_X,d->nBV-d->cX_in_H,&cMTX,d->nBpX);
    339:   } else {
    340:     DSOrthogonalize(d->ps,DS_MAT_Q,size_X+size_plusk,&cMTX);
    341:   }

    343:   if (d->W && size_plusk > 0) {
    344:     /* ps.Z <- orth([ps.Z(0:size_X-1) [oldV(0:size_plusk-1); 0] ]) */
    345:     DSGetArray(d->ps,DS_MAT_Z,&pZ);
    346:     SlepcDenseCopy(&pZ[ld*size_X],ld,data->oldV,data->ldoldU,data->size_oldU,size_plusk);
    347:     for(i=size_X; i<size_X+size_plusk; i++) {
    348:       for(j=data->size_oldU; j<d->size_H; j++) {
    349:         pZ[j*ld+i] = 0.0;
    350:       }
    351:     }
    352:     DSRestoreArray(d->ps,DS_MAT_Z,&pZ);
    353:     DSOrthogonalize(d->ps,DS_MAT_Z,size_X+size_plusk,&cMTY);
    354:     cMTX = PetscMin(cMTX, cMTY);
    355:   }

    357:   /* Notify the changes in V and update the other subspaces */
    358:   d->V_tra_s = d->cX_in_H;            d->V_tra_e = cMTX;
    359:   d->V_new_s = d->V_tra_e-d->cX_in_H; d->V_new_e = d->V_new_s;

    361:   /* Remove oldU */
    362:   data->size_oldU = 0;

    364:   /* Remove npreconv */
    365:   d->npreconv = 0;
    366:   return(0);
    367: }

    371: PetscErrorCode dvd_updateV_update_gen(dvdDashboard *d)
    372: {
    373:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    374:   PetscInt        size_D,ld,s;
    375:   PetscScalar     *pQ,*pZ;
    376:   PetscErrorCode  ierr;

    379:   /* Select the desired pairs */
    380:   size_D = PetscMin(PetscMin(PetscMin(d->bs,
    381:                                       d->size_V),
    382:                                       d->max_size_V-d->size_V),
    383:                                       d->size_H);
    384:   if (size_D == 0) {
    385:     PetscInfo2(d->eps, "MON: D:%D H:%D\n", size_D, d->size_H);
    386:     d->initV(d);
    387:     d->calcPairs(d);
    388:   }

    390:   /* Fill V with D */
    391:   d->improveX(d, d->V+d->size_V, d->max_size_V-d->size_V, 0, size_D, &size_D);

    393:   /* If D is empty, exit */
    394:   d->size_D = size_D;
    395:   if (size_D == 0) return(0);

    397:   /* Get the residual of all pairs */
    398: #if !defined(PETSC_USE_COMPLEX)
    399:   s = d->eigi[0]!=0.0?2:1;
    400: #else
    401:   s = 1;
    402: #endif
    403:   dvd_updateV_testConv(d,s,s,data->allResiduals?d->size_V:size_D,d->auxV,d->auxS,NULL);

    405:   /* Notify the changes in V */
    406:   d->V_tra_s = 0;                 d->V_tra_e = 0;
    407:   d->V_new_s = d->size_V;         d->V_new_e = d->size_V+size_D;

    409:   /* Save the projected eigenvectors */
    410:   if (data->plusk > 0) {
    411:     data->ldoldU = data->size_oldU = d->size_H;
    412:     DSGetLeadingDimension(d->ps,&ld);
    413:     DSGetArray(d->ps,DS_MAT_Q,&pQ);
    414:     SlepcDenseCopy(data->oldU,data->ldoldU,pQ,ld,d->size_H,d->size_H);
    415:     DSRestoreArray(d->ps,DS_MAT_Q,&pQ);
    416:     if (d->cY) {
    417:       DSGetArray(d->ps,DS_MAT_Z,&pZ);
    418:       SlepcDenseCopy(data->oldV,data->ldoldU,pZ,ld,d->size_H,d->size_H);
    419:       DSRestoreArray(d->ps,DS_MAT_Z,&pZ);
    420:     }
    421:   }
    422:   return(0);
    423: }

    427: /* auxV: (by calcpairs_residual_eig) */
    428: PetscErrorCode dvd_updateV_testConv(dvdDashboard *d,PetscInt s,PetscInt pre,PetscInt e,Vec *auxV,PetscScalar *auxS,PetscInt *nConv)
    429: {
    430:   PetscInt        i,j,b;
    431:   PetscReal       norm;
    432:   PetscErrorCode  ierr;
    433:   PetscBool       conv, c;
    434:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

    437:   if (nConv) *nConv = s;
    438:   for (i=s, conv=PETSC_TRUE;
    439:       (conv || data->allResiduals) && (i < e);
    440:       i+=b) {
    441: #if !defined(PETSC_USE_COMPLEX)
    442:     b = d->eigi[i]!=0.0?2:1;
    443: #else
    444:     b = 1;
    445: #endif
    446:     if (i+b-1 >= pre) {
    447:       d->calcpairs_residual(d, i, i+b, auxV);
    448:     }
    449:     /* Test the Schur vector */
    450:     for (j=0,c=PETSC_TRUE; j<b && c; j++) {
    451:       norm = d->nR[i+j]/d->nX[i+j];
    452:       c = d->testConv(d, d->eigr[i+j], d->eigi[i+j], norm, &d->errest[i+j]);
    453:     }
    454:     /* Test the eigenvector */
    455:     if (d->eps->trueres && conv && c) {
    456:       d->calcpairs_residual_eig(d,i,i+b,auxV);
    457:       for (j=0,c=PETSC_TRUE; j<b && c; j++) {
    458:         norm = d->nR[i+j]/d->nX[i+j];
    459:         c = d->testConv(d, d->eigr[i+j], d->eigi[i+j], norm, &d->errest[i+j]);
    460:       }
    461:     }
    462:     if (conv && c) { if (nConv) *nConv = i+b; }
    463:     else conv = PETSC_FALSE;
    464:   }
    465:   pre = PetscMax(pre, i);

    467: #if !defined(PETSC_USE_COMPLEX)
    468:   /* Enforce converged conjugate complex eigenpairs */
    469:   if (nConv) {
    470:     for (j=0;j<*nConv;j++) if (d->eigi[j] != 0.0) j++;
    471:     if (j>*nConv) (*nConv)--;
    472:   }
    473: #endif
    474:   for (i=pre;i<e;i++) d->errest[i] = d->nR[i] = PETSC_MAX_REAL;
    475:   return(0);
    476: }