Actual source code: matnull.c

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

 5:  #include src/mat/matimpl.h
 6:  #include petscsys.h

  8: PetscCookie MAT_NULLSPACE_COOKIE = 0;

 12: /*@C
 13:    MatNullSpaceCreate - Creates a data structure used to project vectors 
 14:    out of null spaces.

 16:    Collective on MPI_Comm

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

 26:    Output Parameter:
 27: .  SP - the null space context

 29:    Level: advanced

 31:   Users manual sections:
 32: .   Section 4.15 Solving Singular Systems

 34: .keywords: PC, null space, create

 36: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace
 37: @*/
 38: PetscErrorCode MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
 39: {
 40:   MatNullSpace   sp;
 42:   PetscInt       i;

 45:   PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);
 46:   PetscLogObjectCreate(sp);
 47:   PetscLogObjectMemory(sp,sizeof(struct _p_MatNullSpace));

 49:   sp->has_cnst = has_cnst;
 50:   sp->n        = n;
 51:   sp->vec      = PETSC_NULL;
 52:   if (n) {
 53:     PetscMalloc(n*sizeof(Vec),&sp->vecs);
 54:     for (i=0; i<n; i++) sp->vecs[i] = vecs[i];
 55:   } else {
 56:     sp->vecs = 0;
 57:   }

 59:   for (i=0; i<n; i++) {
 60:     PetscObjectReference((PetscObject)sp->vecs[i]);
 61:   }
 62:   *SP          = sp;
 63:   return(0);
 64: }

 68: /*@
 69:    MatNullSpaceDestroy - Destroys a data structure used to project vectors 
 70:    out of null spaces.

 72:    Collective on MatNullSpace

 74:    Input Parameter:
 75: .  sp - the null space context to be destroyed

 77:    Level: advanced

 79: .keywords: PC, null space, destroy

 81: .seealso: MatNullSpaceCreate(), MatNullSpaceRemove()
 82: @*/
 83: PetscErrorCode MatNullSpaceDestroy(MatNullSpace sp)
 84: {

 88:   if (--sp->refct > 0) return(0);

 90:   if (sp->vec) {VecDestroy(sp->vec);}
 91:   if (sp->vecs) {
 92:     VecDestroyVecs(sp->vecs,sp->n);
 93:   }
 94:   PetscLogObjectDestroy(sp);
 95:   PetscHeaderDestroy(sp);
 96:   return(0);
 97: }

101: /*@
102:    MatNullSpaceRemove - Removes all the components of a null space from a vector.

104:    Collective on MatNullSpace

106:    Input Parameters:
107: +  sp - the null space context
108: .  vec - the vector from which the null space is to be removed 
109: -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
110:          the removal is done in-place (in vec)



114:    Level: advanced

116: .keywords: PC, null space, remove

118: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy()
119: @*/
120: PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
121: {
122:   PetscScalar    sum;
124:   PetscInt       j,n = sp->n,N;
125:   Vec            l = vec;

128:   if (out) {
129:     if (!sp->vec) {
130:       VecDuplicate(vec,&sp->vec);
131:     }
132:     *out = sp->vec;
133:     VecCopy(vec,*out);
134:     l    = *out;
135:   }

137:   if (sp->has_cnst) {
138:     VecSum(l,&sum);
139:     VecGetSize(l,&N);
140:     sum  = sum/(-1.0*N);
141:     VecShift(&sum,l);
142:   }

144:   for (j=0; j<n; j++) {
145:     VecDot(l,sp->vecs[j],&sum);
146:     sum  = -sum;
147:     VecAXPY(&sum,sp->vecs[j],l);
148:   }
149: 
150:   return(0);
151: }

155: /*@
156:    MatNullSpaceTest  - Tests if the claimed null space is really a
157:      null space of a matrix

159:    Collective on MatNullSpace

161:    Input Parameters:
162: +  sp - the null space context
163: -  mat - the matrix

165:    Level: advanced

167: .keywords: PC, null space, remove

169: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy()
170: @*/
171: PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat)
172: {
173:   PetscScalar    sum;
174:   PetscReal      nrm;
175:   PetscInt       j,n = sp->n,N,m;
177:   Vec            l,r;
178:   MPI_Comm       comm = sp->comm;
179:   PetscTruth     flg1,flg2;

182:   PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);
183:   PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);

185:   if (!sp->vec) {
186:     if (n) {
187:       VecDuplicate(sp->vecs[0],&sp->vec);
188:     } else {
189:       MatGetLocalSize(mat,&m,PETSC_NULL);
190:       VecCreateMPI(sp->comm,m,PETSC_DETERMINE,&sp->vec);
191:     }
192:   }
193:   l    = sp->vec;

195:   if (sp->has_cnst) {
196:     VecDuplicate(l,&r);
197:     VecGetSize(l,&N);
198:     sum  = 1.0/N;
199:     VecSet(&sum,l);
200:     MatMult(mat,l,r);
201:     VecNorm(r,NORM_2,&nrm);
202:     if (nrm < 1.e-7) {PetscPrintf(comm,"Constants are likely null vector");}
203:     else {PetscPrintf(comm,"Constants are unlikely null vector ");}
204:     PetscPrintf(comm,"|| A * 1 || = %g\n",nrm);
205:     if (nrm > 1.e-7 && flg1) {VecView(r,PETSC_VIEWER_STDOUT_(comm));}
206:     if (nrm > 1.e-7 && flg2) {VecView(r,PETSC_VIEWER_DRAW_(comm));}
207:     VecDestroy(r);
208:   }

210:   for (j=0; j<n; j++) {
211:     (*mat->ops->mult)(mat,sp->vecs[j],l);
212:     VecNorm(l,NORM_2,&nrm);
213:     if (nrm < 1.e-7) {PetscPrintf(comm,"Null vector %D is likely null vector",j);}
214:     else {PetscPrintf(comm,"Null vector %D unlikely null vector ",j);}
215:     PetscPrintf(comm,"|| A * v[%D] || = %g\n",j,nrm);
216:     if (nrm > 1.e-7 && flg1) {VecView(l,PETSC_VIEWER_STDOUT_(comm));}
217:     if (nrm > 1.e-7 && flg2) {VecView(l,PETSC_VIEWER_DRAW_(comm));}
218:   }
219: 
220:   return(0);
221: }