xref: /petsc/src/mat/interface/matnull.c (revision a32ab379bc196903d81f117b153e855bfa447008)
1 
2 /*
3     Routines to project vectors out of null spaces.
4 */
5 
6 #include <private/matimpl.h>      /*I "petscmat.h" I*/
7 
8 PetscClassId  MAT_NULLSPACE_CLASSID;
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "MatNullSpaceSetFunction"
12 /*@C
13    MatNullSpaceSetFunction - set a function that removes a null space from a vector
14    out of null spaces.
15 
16    Logically Collective on MatNullSpace
17 
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
22 
23    Level: advanced
24 
25 .keywords: PC, null space, create
26 
27 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
28 @*/
29 PetscErrorCode  MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx)
30 {
31   PetscFunctionBegin;
32   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
33   sp->remove = rem;
34   sp->rmctx  = ctx;
35   PetscFunctionReturn(0);
36 }
37 
38 #undef __FUNCT__
39 #define __FUNCT__ "MatNullSpaceView"
40 static PetscErrorCode MatNullSpaceView(MatNullSpace sp, PetscViewer viewer)
41 {
42   PetscErrorCode ierr;
43   PetscBool      iascii;
44 
45   PetscFunctionBegin;
46   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
47   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(((PetscObject)sp)->comm);
48   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
49   PetscCheckSameComm(sp,1,viewer,2);
50 
51   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
52   if (iascii) {
53     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sp,viewer,"MatNullSpace Object");CHKERRQ(ierr);
54   }
55   PetscFunctionReturn(0);
56 }
57 
58 #undef __FUNCT__
59 #define __FUNCT__ "MatNullSpaceCreate"
60 /*@
61    MatNullSpaceCreate - Creates a data structure used to project vectors
62    out of null spaces.
63 
64    Collective on MPI_Comm
65 
66    Input Parameters:
67 +  comm - the MPI communicator associated with the object
68 .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
69 .  n - number of vectors (excluding constant vector) in null space
70 -  vecs - the vectors that span the null space (excluding the constant vector);
71           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
72           after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count
73           for them by one).
74 
75    Output Parameter:
76 .  SP - the null space context
77 
78    Level: advanced
79 
80    Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs.
81 
82       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
83        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().
84 
85   Users manual sections:
86 .   sec_singular
87 
88 .keywords: PC, null space, create
89 
90 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
91 @*/
92 PetscErrorCode  MatNullSpaceCreate(MPI_Comm comm,PetscBool  has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
93 {
94   MatNullSpace   sp;
95   PetscErrorCode ierr;
96   PetscInt       i;
97 
98   PetscFunctionBegin;
99   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
100   if (n) PetscValidPointer(vecs,4);
101   for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_CLASSID,4);
102   PetscValidPointer(SP,5);
103 
104   *SP = PETSC_NULL;
105 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
106   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
107 #endif
108 
109   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,0,"MatNullSpace",comm,MatNullSpaceDestroy,MatNullSpaceView);CHKERRQ(ierr);
110 
111   sp->has_cnst = has_cnst;
112   sp->n        = n;
113   sp->vecs     = 0;
114   sp->alpha    = 0;
115   sp->vec      = 0;
116   sp->remove   = 0;
117   sp->rmctx    = 0;
118 
119   if (n) {
120     ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr);
121     ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr);
122     ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr);
123     for (i=0; i<n; i++) {
124       ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr);
125       sp->vecs[i] = vecs[i];
126     }
127   }
128 
129   *SP          = sp;
130   PetscFunctionReturn(0);
131 }
132 
133 #undef __FUNCT__
134 #define __FUNCT__ "MatNullSpaceDestroy"
135 /*@
136    MatNullSpaceDestroy - Destroys a data structure used to project vectors
137    out of null spaces.
138 
139    Collective on MatNullSpace
140 
141    Input Parameter:
142 .  sp - the null space context to be destroyed
143 
144    Level: advanced
145 
146 .keywords: PC, null space, destroy
147 
148 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
149 @*/
150 PetscErrorCode  MatNullSpaceDestroy(MatNullSpace *sp)
151 {
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   if (!*sp) PetscFunctionReturn(0);
156   PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1);
157   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);}
158 
159   ierr = VecDestroy(&(*sp)->vec);CHKERRQ(ierr);
160   ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr);
161   ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr);
162   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "MatNullSpaceRemove"
168 /*@C
169    MatNullSpaceRemove - Removes all the components of a null space from a vector.
170 
171    Collective on MatNullSpace
172 
173    Input Parameters:
174 +  sp - the null space context
175 .  vec - the vector from which the null space is to be removed
176 -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
177          the removal is done in-place (in vec)
178 
179    Note: The user is not responsible for the vector returned and should not destroy it.
180 
181    Level: advanced
182 
183 .keywords: PC, null space, remove
184 
185 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
186 @*/
187 PetscErrorCode  MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
188 {
189   PetscScalar    sum;
190   PetscInt       i,N;
191   PetscErrorCode ierr;
192 
193   PetscFunctionBegin;
194   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
195   PetscValidHeaderSpecific(vec,VEC_CLASSID,2);
196 
197   if (out) {
198     PetscValidPointer(out,3);
199     if (!sp->vec) {
200       ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr);
201       ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr);
202     }
203     ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr);
204     vec = *out = sp->vec;
205   }
206 
207   if (sp->has_cnst) {
208     ierr = VecGetSize(vec,&N);CHKERRQ(ierr);
209     if (N > 0) {
210       ierr = VecSum(vec,&sum);CHKERRQ(ierr);
211       sum  = sum/(-1.0*N);
212       ierr = VecShift(vec,sum);CHKERRQ(ierr);
213     }
214   }
215 
216   if (sp->n) {
217     ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr);
218     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
219     ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr);
220   }
221 
222   if (sp->remove){
223     ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr);
224   }
225   PetscFunctionReturn(0);
226 }
227 
228 #undef __FUNCT__
229 #define __FUNCT__ "MatNullSpaceTest"
230 /*@
231    MatNullSpaceTest  - Tests if the claimed null space is really a
232      null space of a matrix
233 
234    Collective on MatNullSpace
235 
236    Input Parameters:
237 +  sp - the null space context
238 -  mat - the matrix
239 
240    Output Parameters:
241 .  isNull - PETSC_TRUE if the nullspace is valid for this matrix
242 
243    Level: advanced
244 
245 .keywords: PC, null space, remove
246 
247 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
248 @*/
249 PetscErrorCode  MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool  *isNull)
250 {
251   PetscScalar    sum;
252   PetscReal      nrm;
253   PetscInt       j,n,N;
254   PetscErrorCode ierr;
255   Vec            l,r;
256   PetscBool      flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
257   PetscViewer    viewer;
258 
259   PetscFunctionBegin;
260   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
261   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
262   n = sp->n;
263   ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr);
264   ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr);
265 
266   if (!sp->vec) {
267     if (n) {
268       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
269     } else {
270       ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr);
271     }
272   }
273   l    = sp->vec;
274 
275   ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr);
276   if (sp->has_cnst) {
277     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
278     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
279     sum  = 1.0/N;
280     ierr = VecSet(l,sum);CHKERRQ(ierr);
281     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
282     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
283     if (nrm < 1.e-7) {
284       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr);
285     } else {
286       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);
287       consistent = PETSC_FALSE;
288     }
289     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1/N || = %G\n",nrm);CHKERRQ(ierr);
290     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
291     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
292     ierr = VecDestroy(&r);CHKERRQ(ierr);
293   }
294 
295   for (j=0; j<n; j++) {
296     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
297     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
298     if (nrm < 1.e-7) {
299       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);
300     } else {
301       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);
302       consistent = PETSC_FALSE;
303     }
304     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
305     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
306     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
307   }
308 
309   if (sp->remove) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
310   if (isNull) *isNull = consistent;
311   PetscFunctionReturn(0);
312 }
313 
314