Date: 2013-07-02T14:41:12+00:00

Actual source code: matnull.c
petsc-3.4.2 2013-07-02

      2: /*
      3:     Routines to project vectors out of null spaces.
      4: */

      6: #include <petsc-private/matimpl.h>      /*I "petscmat.h" I*/

      8: PetscClassId MAT_NULLSPACE_CLASSID;

     12: /*@C
     13:    MatNullSpaceSetFunction - set a function that removes a null space from a vector
     14:    out of null spaces.

     16:    Logically Collective on MatNullSpace

     18:    Input Parameters:
     19: +  sp - the null space object
     20: .  rem - the function that removes the null space
     21: -  ctx - context for the remove function

     23:    Level: advanced

     25: .keywords: PC, null space, create

     27: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
     28: @*/
     29: PetscErrorCode  MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx)
     30: {
     33:   sp->remove = rem;
     34:   sp->rmctx  = ctx;
     35:   return(0);
     36: }

     40: /*@C
     41:    MatNullSpaceGetVecs - get vectors defining the null space

     43:    Not Collective

     45:    Input Arguments:
     46: .  sp - null space object

     48:    Output Arguments:
     49: +  has_cnst - PETSC_TRUE if the null space contains the constant vector, otherwise PETSC_FALSE
     50: .  n - number of vectors (excluding constant vector) in null space
     51: -  vecs - orthonormal vectors that span the null space (excluding the constant vector)

     53:    Level: developer

     55: .seealso: MatNullSpaceCreate(), MatGetNullSpace(), MatGetNearNullSpace()
     56: @*/
     57: PetscErrorCode MatNullSpaceGetVecs(MatNullSpace sp,PetscBool *has_const,PetscInt *n,const Vec **vecs)
     58: {

     62:   if (has_const) *has_const = sp->has_cnst;
     63:   if (n) *n = sp->n;
     64:   if (vecs) *vecs = sp->vecs;
     65:   return(0);
     66: }

     70: /*@
     71:    MatNullSpaceCreateRigidBody - create rigid body modes from coordinates

     73:    Collective on Vec

     75:    Input Argument:
     76: .  coords - block of coordinates of each node, must have block size set

     78:    Output Argument:
     79: .  sp - the null space

     81:    Level: advanced

     83: .seealso: MatNullSpaceCreate()
     84: @*/
     85: PetscErrorCode MatNullSpaceCreateRigidBody(Vec coords,MatNullSpace *sp)
     86: {
     87:   PetscErrorCode    ierr;
     88:   const PetscScalar *x;
     89:   PetscScalar       *v[6],dots[3];
     90:   Vec               vec[6];
     91:   PetscInt          n,N,dim,nmodes,i,j;

     94:   VecGetBlockSize(coords,&dim);
     95:   VecGetLocalSize(coords,&n);
     96:   VecGetSize(coords,&N);
     97:   n   /= dim;
     98:   N   /= dim;
     99:   switch (dim) {
    100:   case 1:
    101:     MatNullSpaceCreate(PetscObjectComm((PetscObject)coords),PETSC_TRUE,0,NULL,sp);
    102:     break;
    103:   case 2:
    104:   case 3:
    105:     nmodes = (dim == 2) ? 3 : 6;
    106:     VecCreate(PetscObjectComm((PetscObject)coords),&vec[0]);
    107:     VecSetSizes(vec[0],dim*n,dim*N);
    108:     VecSetBlockSize(vec[0],dim);
    109:     VecSetUp(vec[0]);
    110:     for (i=1; i<nmodes; i++) {VecDuplicate(vec[0],&vec[i]);}
    111:     for (i=0; i<nmodes; i++) {VecGetArray(vec[i],&v[i]);}
    112:     VecGetArrayRead(coords,&x);
    113:     for (i=0; i<n; i++) {
    114:       if (dim == 2) {
    115:         v[0][i*2+0] = 1./N;
    116:         v[0][i*2+1] = 0.;
    117:         v[1][i*2+0] = 0.;
    118:         v[1][i*2+1] = 1./N;
    119:         /* Rotations */
    120:         v[2][i*2+0] = -x[i*2+1];
    121:         v[2][i*2+1] = x[i*2+0];
    122:       } else {
    123:         v[0][i*3+0] = 1./N;
    124:         v[0][i*3+1] = 0.;
    125:         v[0][i*3+2] = 0.;
    126:         v[1][i*3+0] = 0.;
    127:         v[1][i*3+1] = 1./N;
    128:         v[1][i*3+2] = 0.;
    129:         v[2][i*3+0] = 0.;
    130:         v[2][i*3+1] = 0.;
    131:         v[2][i*3+2] = 1./N;

    133:         v[3][i*3+0] = x[i*3+1];
    134:         v[3][i*3+1] = -x[i*3+0];
    135:         v[3][i*3+2] = 0.;
    136:         v[4][i*3+0] = 0.;
    137:         v[4][i*3+1] = -x[i*3+2];
    138:         v[4][i*3+2] = x[i*3+1];
    139:         v[5][i*3+0] = x[i*3+2];
    140:         v[5][i*3+1] = 0.;
    141:         v[5][i*3+2] = -x[i*3+0];
    142:       }
    143:     }
    144:     for (i=0; i<nmodes; i++) {VecRestoreArray(vec[i],&v[i]);}
    145:     VecRestoreArrayRead(coords,&x);
    146:     for (i=dim; i<nmodes; i++) {
    147:       /* Orthonormalize vec[i] against vec[0:dim] */
    148:       VecMDot(vec[i],i,vec,dots);
    149:       for (j=0; j<i; j++) dots[j] *= -1.;
    150:       VecMAXPY(vec[i],i,dots,vec);
    151:       VecNormalize(vec[i],NULL);
    152:     }
    153:     MatNullSpaceCreate(PetscObjectComm((PetscObject)coords),PETSC_FALSE,nmodes,vec,sp);
    154:     for (i=0; i<nmodes; i++) {VecDestroy(&vec[i]);}
    155:   }
    156:   return(0);
    157: }

    161: /*@C
    162:    MatNullSpaceView - Visualizes a null space object.

    164:    Collective on MatNullSpace

    166:    Input Parameters:
    167: +  matnull - the null space
    168: -  viewer - visualization context

    170:    Level: advanced

    172:    Fortran Note:
    173:    This routine is not supported in Fortran.

    175: .seealso: MatNullSpaceCreate(), PetscViewerASCIIOpen()
    176: @*/
    177: PetscErrorCode MatNullSpaceView(MatNullSpace sp,PetscViewer viewer)
    178: {
    180:   PetscBool      iascii;

    184:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)sp));

    188:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    189:   if (iascii) {
    190:     PetscViewerFormat format;
    191:     PetscInt          i;
    192:     PetscViewerGetFormat(viewer,&format);
    193:     PetscObjectPrintClassNamePrefixType((PetscObject)sp,viewer,"MatNullSpace Object");
    194:     PetscViewerASCIIPushTab(viewer);
    195:     PetscViewerASCIIPrintf(viewer,"Contains %D vector%s%s\n",sp->n,sp->n==1 ? "" : "s",sp->has_cnst ? " and the constant" : "");
    196:     if (sp->remove) {PetscViewerASCIIPrintf(viewer,"Has user-provided removal function\n");}
    197:     if (!(format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) {
    198:       for (i=0; i<sp->n; i++) {
    199:         VecView(sp->vecs[i],viewer);
    200:       }
    201:     }
    202:     PetscViewerASCIIPopTab(viewer);
    203:   }
    204:   return(0);
    205: }

    209: /*@
    210:    MatNullSpaceCreate - Creates a data structure used to project vectors
    211:    out of null spaces.

    213:    Collective on MPI_Comm

    215:    Input Parameters:
    216: +  comm - the MPI communicator associated with the object
    217: .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
    218: .  n - number of vectors (excluding constant vector) in null space
    219: -  vecs - the vectors that span the null space (excluding the constant vector);
    220:           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
    221:           after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count
    222:           for them by one).

    224:    Output Parameter:
    225: .  SP - the null space context

    227:    Level: advanced

    229:    Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs.

    231:       If has_cnst is PETSC_TRUE you do not need to pass a constant vector in as a fourth argument to this routine, nor do you
    232:        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().

    234:   Users manual sections:
    235: .   Section 4.17 Solving Singular Systems

    237: .keywords: PC, null space, create

    239: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
    240: @*/
    241: PetscErrorCode  MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
    242: {
    243:   MatNullSpace   sp;
    245:   PetscInt       i;

    248:   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);

    253:   *SP = NULL;
    254: #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
    255:   MatInitializePackage();
    256: #endif

    258:   PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,"MatNullSpace","Null space","Mat",comm,MatNullSpaceDestroy,MatNullSpaceView);

    260:   sp->has_cnst = has_cnst;
    261:   sp->n        = n;
    262:   sp->vecs     = 0;
    263:   sp->alpha    = 0;
    264:   sp->vec      = 0;
    265:   sp->remove   = 0;
    266:   sp->rmctx    = 0;

    268:   if (n) {
    269:     PetscMalloc(n*sizeof(Vec),&sp->vecs);
    270:     PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);
    271:     PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));
    272:     for (i=0; i<n; i++) {
    273:       PetscObjectReference((PetscObject)vecs[i]);
    274:       sp->vecs[i] = vecs[i];
    275:     }
    276:   }

    278:   *SP = sp;
    279:   return(0);
    280: }

    284: /*@
    285:    MatNullSpaceDestroy - Destroys a data structure used to project vectors
    286:    out of null spaces.

    288:    Collective on MatNullSpace

    290:    Input Parameter:
    291: .  sp - the null space context to be destroyed

    293:    Level: advanced

    295: .keywords: PC, null space, destroy

    297: .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
    298: @*/
    299: PetscErrorCode  MatNullSpaceDestroy(MatNullSpace *sp)
    300: {

    304:   if (!*sp) return(0);
    306:   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; return(0);}

    308:   VecDestroy(&(*sp)->vec);
    309:   VecDestroyVecs((*sp)->n,&(*sp)->vecs);
    310:   PetscFree((*sp)->alpha);
    311:   PetscHeaderDestroy(sp);
    312:   return(0);
    313: }

    317: /*@C
    318:    MatNullSpaceRemove - Removes all the components of a null space from a vector.

    320:    Collective on MatNullSpace

    322:    Input Parameters:
    323: +  sp - the null space context
    324: .  vec - the vector from which the null space is to be removed
    325: -  out - if this is requested (not NULL) then this is a vector with the null space removed otherwise
    326:          the removal is done in-place (in vec)

    328:    Note: The user is not responsible for the vector returned and should not destroy it.

    330:    Level: advanced

    332: .keywords: PC, null space, remove

    334: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
    335: @*/
    336: PetscErrorCode  MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
    337: {
    338:   PetscScalar    sum;
    339:   PetscInt       i,N;

    346:   if (out) {
    348:     if (!sp->vec) {
    349:       VecDuplicate(vec,&sp->vec);
    350:       PetscLogObjectParent(sp,sp->vec);
    351:     }
    352:     VecCopy(vec,sp->vec);
    353:     vec  = *out = sp->vec;
    354:   }

    356:   if (sp->has_cnst) {
    357:     VecGetSize(vec,&N);
    358:     if (N > 0) {
    359:       VecSum(vec,&sum);
    360:       sum  = sum/((PetscScalar)(-1.0*N));
    361:       VecShift(vec,sum);
    362:     }
    363:   }

    365:   if (sp->n) {
    366:     VecMDot(vec,sp->n,sp->vecs,sp->alpha);
    367:     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
    368:     VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);
    369:   }

    371:   if (sp->remove) {
    372:     (*sp->remove)(sp,vec,sp->rmctx);
    373:   }
    374:   return(0);
    375: }

    379: /*@
    380:    MatNullSpaceTest  - Tests if the claimed null space is really a
    381:      null space of a matrix

    383:    Collective on MatNullSpace

    385:    Input Parameters:
    386: +  sp - the null space context
    387: -  mat - the matrix

    389:    Output Parameters:
    390: .  isNull - PETSC_TRUE if the nullspace is valid for this matrix

    392:    Level: advanced

    394: .keywords: PC, null space, remove

    396: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
    397: @*/
    398: PetscErrorCode  MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool  *isNull)
    399: {
    400:   PetscScalar    sum;
    401:   PetscReal      nrm;
    402:   PetscInt       j,n,N;
    404:   Vec            l,r;
    405:   PetscBool      flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
    406:   PetscViewer    viewer;

    411:   n    = sp->n;
    412:   PetscOptionsGetBool(NULL,"-mat_null_space_test_view",&flg1,NULL);
    413:   PetscOptionsGetBool(NULL,"-mat_null_space_test_view_draw",&flg2,NULL);

    415:   if (!sp->vec) {
    416:     if (n) {
    417:       VecDuplicate(sp->vecs[0],&sp->vec);
    418:     } else {
    419:       MatGetVecs(mat,&sp->vec,NULL);
    420:     }
    421:   }
    422:   l = sp->vec;

    424:   PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);
    425:   if (sp->has_cnst) {
    426:     VecDuplicate(l,&r);
    427:     VecGetSize(l,&N);
    428:     sum  = 1.0/N;
    429:     VecSet(l,sum);
    430:     MatMult(mat,l,r);
    431:     VecNorm(r,NORM_2,&nrm);
    432:     if (nrm >= 1.e-7) consistent = PETSC_FALSE;
    433:     if (flg1) {
    434:       if (consistent) {
    435:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are likely null vector");
    436:       } else {
    437:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are unlikely null vector ");
    438:       }
    439:       PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * 1/N || = %G\n",nrm);
    440:     }
    441:     if (!consistent && flg1) {VecView(r,viewer);}
    442:     if (!consistent && flg2) {VecView(r,viewer);}
    443:     VecDestroy(&r);
    444:   }

    446:   for (j=0; j<n; j++) {
    447:     (*mat->ops->mult)(mat,sp->vecs[j],l);
    448:     VecNorm(l,NORM_2,&nrm);
    449:     if (nrm >= 1.e-7) consistent = PETSC_FALSE;
    450:     if (flg1) {
    451:       if (consistent) {
    452:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D is likely null vector",j);
    453:       } else {
    454:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D unlikely null vector ",j);
    455:         consistent = PETSC_FALSE;
    456:       }
    457:       PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * v[%D] || = %G\n",j,nrm);
    458:     }
    459:     if (!consistent && flg1) {VecView(l,viewer);}
    460:     if (!consistent && flg2) {VecView(l,viewer);}
    461:   }

    463:   if (sp->remove) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
    464:   if (isNull) *isNull = consistent;
    465:   return(0);
    466: }