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