Actual source code: matnull.c

  1: #define PETSCMAT_DLL

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

 7:  #include private/matimpl.h
 8:  #include petscsys.h

 10: PetscCookie  MAT_NULLSPACE_COOKIE;

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

 18:    Collective on MatNullSpace

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

 25:    Level: advanced

 27: .keywords: PC, null space, create

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

 42: /*@
 43:    MatNullSpaceCreate - Creates a data structure used to project vectors 
 44:    out of null spaces.

 46:    Collective on MPI_Comm

 48:    Input Parameters:
 49: +  comm - the MPI communicator associated with the object
 50: .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
 51: .  n - number of vectors (excluding constant vector) in null space
 52: -  vecs - the vectors that span the null space (excluding the constant vector);
 53:           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
 54:           after this call. You should free the array that you pass in.

 56:    Output Parameter:
 57: .  SP - the null space context

 59:    Level: advanced

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

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

 66:   Users manual sections:
 67: .   Section 4.15 Solving Singular Systems

 69: .keywords: PC, null space, create

 71: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
 72: @*/
 73: PetscErrorCode  MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
 74: {
 75:   MatNullSpace   sp;
 77:   PetscInt       i;

 80:   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
 84: 
 85:   *SP = PETSC_NULL;
 86: #ifndef PETSC_USE_DYNAMIC_LIBRARIES 
 87:   MatInitializePackage(PETSC_NULL);
 88: #endif 

 90:   PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);

 92:   sp->has_cnst = has_cnst;
 93:   sp->n        = n;
 94:   sp->vecs     = 0;
 95:   sp->alpha    = 0;
 96:   sp->vec      = 0;
 97:   sp->remove   = 0;
 98:   sp->rmctx    = 0;

100:   if (n) {
101:     PetscMalloc(n*sizeof(Vec),&sp->vecs);
102:     PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);
103:     PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));
104:     for (i=0; i<n; i++) {
105:       PetscObjectReference((PetscObject)vecs[i]);
106:       sp->vecs[i] = vecs[i];
107:     }
108:   }

110:   *SP          = sp;
111:   return(0);
112: }

116: /*@
117:    MatNullSpaceDestroy - Destroys a data structure used to project vectors 
118:    out of null spaces.

120:    Collective on MatNullSpace

122:    Input Parameter:
123: .  sp - the null space context to be destroyed

125:    Level: advanced

127: .keywords: PC, null space, destroy

129: .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
130: @*/
131: PetscErrorCode  MatNullSpaceDestroy(MatNullSpace sp)
132: {

137:   if (--((PetscObject)sp)->refct > 0) return(0);

139:   if (sp->vec)  { VecDestroy(sp->vec); }
140:   if (sp->vecs) { VecDestroyVecs(sp->vecs,sp->n); }
141:   PetscFree(sp->alpha);
142:   PetscHeaderDestroy(sp);
143:   return(0);
144: }

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

151:    Collective on MatNullSpace

153:    Input Parameters:
154: +  sp - the null space context
155: .  vec - the vector from which the null space is to be removed 
156: -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
157:          the removal is done in-place (in vec)

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

161:    Level: advanced

163: .keywords: PC, null space, remove

165: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
166: @*/
167: PetscErrorCode  MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
168: {
169:   PetscScalar    sum;
170:   PetscInt       i,N;


177:   if (out) {
179:     if (!sp->vec) {
180:       VecDuplicate(vec,&sp->vec);
181:       PetscLogObjectParent(sp,sp->vec);
182:     }
183:     VecCopy(vec,sp->vec);
184:     vec = *out = sp->vec;
185:   }
186: 
187:   if (sp->has_cnst) {
188:     VecGetSize(vec,&N);
189:     if (N > 0) {
190:       VecSum(vec,&sum);
191:       sum  = sum/(-1.0*N);
192:       VecShift(vec,sum);
193:     }
194:   }
195: 
196:   if (sp->n) {
197:     VecMDot(vec,sp->n,sp->vecs,sp->alpha);
198:     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
199:     VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);
200:   }

202:   if (sp->remove){
203:     (*sp->remove)(vec,sp->rmctx);
204:   }
205:   return(0);
206: }

210: /*@
211:    MatNullSpaceTest  - Tests if the claimed null space is really a
212:      null space of a matrix

214:    Collective on MatNullSpace

216:    Input Parameters:
217: +  sp - the null space context
218: -  mat - the matrix

220:    Output Parameters:
221: .  isNull - PETSC_TRUE if the nullspace is valid for this matrix

223:    Level: advanced

225: .keywords: PC, null space, remove

227: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
228: @*/
229: PetscErrorCode  MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscTruth *isNull)
230: {
231:   PetscScalar    sum;
232:   PetscReal      nrm;
233:   PetscInt       j,n,N,m;
235:   Vec            l,r;
236:   PetscTruth     flg1,flg2,consistent = PETSC_TRUE;
237:   PetscViewer    viewer;

242:   n = sp->n;
243:   PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);
244:   PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);

246:   if (!sp->vec) {
247:     if (n) {
248:       VecDuplicate(sp->vecs[0],&sp->vec);
249:     } else {
250:       MatGetLocalSize(mat,&m,PETSC_NULL);
251:       VecCreateMPI(((PetscObject)sp)->comm,m,PETSC_DETERMINE,&sp->vec);
252:     }
253:   }
254:   l    = sp->vec;

256:   PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);
257:   if (sp->has_cnst) {
258:     VecDuplicate(l,&r);
259:     VecGetSize(l,&N);
260:     sum  = 1.0/N;
261:     VecSet(l,sum);
262:     MatMult(mat,l,r);
263:     VecNorm(r,NORM_2,&nrm);
264:     if (nrm < 1.e-7) {
265:       PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");
266:     } else {
267:       PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");
268:       consistent = PETSC_FALSE;
269:     }
270:     PetscPrintf(((PetscObject)sp)->comm,"|| A * 1 || = %G\n",nrm);
271:     if (nrm > 1.e-7 && flg1) {VecView(r,viewer);}
272:     if (nrm > 1.e-7 && flg2) {VecView(r,viewer);}
273:     VecDestroy(r);
274:   }

276:   for (j=0; j<n; j++) {
277:     (*mat->ops->mult)(mat,sp->vecs[j],l);
278:     VecNorm(l,NORM_2,&nrm);
279:     if (nrm < 1.e-7) {
280:       PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);
281:     } else {
282:       PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);
283:       consistent = PETSC_FALSE;
284:     }
285:     PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);
286:     if (nrm > 1.e-7 && flg1) {VecView(l,viewer);}
287:     if (nrm > 1.e-7 && flg2) {VecView(l,viewer);}
288:   }

290:   if (sp->remove){
291:     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
292:   }
293:   *isNull = consistent;
294:   return(0);
295: }