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