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