Actual source code: matnull.c

petsc-master 2015-08-30
Report Typos and Errors
  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(), MatSetNullSpace(), 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:    Notes:
 56:       These vectors and the array are owned by the MatNullSpace and should not be destroyed or freeded by the caller

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

 65:   if (has_const) *has_const = sp->has_cnst;
 66:   if (n) *n = sp->n;
 67:   if (vecs) *vecs = sp->vecs;
 68:   return(0);
 69: }

 73: /*@
 74:    MatNullSpaceCreateRigidBody - create rigid body modes from coordinates

 76:    Collective on Vec

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

 81:    Output Argument:
 82: .  sp - the null space

 84:    Level: advanced

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

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

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

164: /*@C
165:    MatNullSpaceView - Visualizes a null space object.

167:    Collective on MatNullSpace

169:    Input Parameters:
170: +  matnull - the null space
171: -  viewer - visualization context

173:    Level: advanced

175:    Fortran Note:
176:    This routine is not supported in Fortran.

178: .seealso: MatNullSpaceCreate(), PetscViewerASCIIOpen()
179: @*/
180: PetscErrorCode MatNullSpaceView(MatNullSpace sp,PetscViewer viewer)
181: {
183:   PetscBool      iascii;

187:   if (!viewer) {
188:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);
189:   }

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

214: /*@
215:    MatNullSpaceCreate - Creates a data structure used to project vectors
216:    out of null spaces.

218:    Collective on MPI_Comm

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

229:    Output Parameter:
230: .  SP - the null space context

232:    Level: advanced

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

236:       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
237:        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().

239:   Users manual sections:
240: .   Section 4.19 Solving Singular Systems

242: .keywords: PC, null space, create

244: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), MatSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
245: @*/
246: PetscErrorCode  MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
247: {
248:   MatNullSpace   sp;
250:   PetscInt       i;

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

258:   *SP = NULL;
259:   MatInitializePackage();

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

263:   sp->has_cnst = has_cnst;
264:   sp->n        = n;
265:   sp->vecs     = 0;
266:   sp->alpha    = 0;
267:   sp->remove   = 0;
268:   sp->rmctx    = 0;

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

280:   *SP = sp;
281:   return(0);
282: }

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

290:    Collective on MatNullSpace

292:    Input Parameter:
293: .  sp - the null space context to be destroyed

295:    Level: advanced

297: .keywords: PC, null space, destroy

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

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

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

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

321:    Collective on MatNullSpace

323:    Input Parameters:
324: +  sp - the null space context
325: -  vec - the vector from which the null space is to be removed

327:    Level: advanced

329: .keywords: PC, null space, remove

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


343:   if (sp->has_cnst) {
344:     VecGetSize(vec,&N);
345:     if (N > 0) {
346:       VecSum(vec,&sum);
347:       sum  = sum/((PetscScalar)(-1.0*N));
348:       VecShift(vec,sum);
349:     }
350:   }

352:   if (sp->n) {
353:     VecMDot(vec,sp->n,sp->vecs,sp->alpha);
354:     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
355:     VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);
356:   }

358:   if (sp->remove) {
359:     (*sp->remove)(sp,vec,sp->rmctx);
360:   }
361:   return(0);
362: }

366: /*@
367:    MatNullSpaceTest  - Tests if the claimed null space is really a
368:      null space of a matrix

370:    Collective on MatNullSpace

372:    Input Parameters:
373: +  sp - the null space context
374: -  mat - the matrix

376:    Output Parameters:
377: .  isNull - PETSC_TRUE if the nullspace is valid for this matrix

379:    Level: advanced

381: .keywords: PC, null space, remove

383: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
384: @*/
385: PetscErrorCode  MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool  *isNull)
386: {
387:   PetscScalar    sum;
388:   PetscReal      nrm;
389:   PetscInt       j,n,N;
391:   Vec            l,r;
392:   PetscBool      flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
393:   PetscViewer    viewer;

398:   n    = sp->n;
399:   PetscOptionsGetBool(NULL,"-mat_null_space_test_view",&flg1,NULL);
400:   PetscOptionsGetBool(NULL,"-mat_null_space_test_view_draw",&flg2,NULL);

402:   if (n) {
403:     VecDuplicate(sp->vecs[0],&l);
404:   } else {
405:     MatCreateVecs(mat,&l,NULL);
406:   }

408:   PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);
409:   if (sp->has_cnst) {
410:     VecDuplicate(l,&r);
411:     VecGetSize(l,&N);
412:     sum  = 1.0/N;
413:     VecSet(l,sum);
414:     MatMult(mat,l,r);
415:     VecNorm(r,NORM_2,&nrm);
416:     if (nrm >= 1.e-7) consistent = PETSC_FALSE;
417:     if (flg1) {
418:       if (consistent) {
419:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are likely null vector");
420:       } else {
421:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are unlikely null vector ");
422:       }
423:       PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * 1/N || = %g\n",(double)nrm);
424:     }
425:     if (!consistent && flg1) {VecView(r,viewer);}
426:     if (!consistent && flg2) {VecView(r,viewer);}
427:     VecDestroy(&r);
428:   }

430:   for (j=0; j<n; j++) {
431:     (*mat->ops->mult)(mat,sp->vecs[j],l);
432:     VecNorm(l,NORM_2,&nrm);
433:     if (nrm >= 1.e-7) consistent = PETSC_FALSE;
434:     if (flg1) {
435:       if (consistent) {
436:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D is likely null vector",j);
437:       } else {
438:         PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D unlikely null vector ",j);
439:         consistent = PETSC_FALSE;
440:       }
441:       PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * v[%D] || = %g\n",j,(double)nrm);
442:     }
443:     if (!consistent && flg1) {VecView(l,viewer);}
444:     if (!consistent && flg2) {VecView(l,viewer);}
445:   }

447:   if (sp->remove) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
448:   VecDestroy(&l);
449:   if (isNull) *isNull = consistent;
450:   return(0);
451: }