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