xref: /petsc/src/mat/interface/matnull.c (revision d34fcf5f3c1110c5dc2577f606d52f97e4a96ba3)
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   /* cannot use MatNullSpaceDestroy() as generic destroy function because it takes pointer to the object */
90   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,0,"MatNullSpace",comm,0,0);CHKERRQ(ierr);
91 
92   sp->has_cnst = has_cnst;
93   sp->n        = n;
94   sp->vecs     = 0;
95   sp->alpha    = 0;
96   sp->vec      = 0;
97   sp->remove   = 0;
98   sp->rmctx    = 0;
99 
100   if (n) {
101     ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr);
102     ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr);
103     ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr);
104     for (i=0; i<n; i++) {
105       ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr);
106       sp->vecs[i] = vecs[i];
107     }
108   }
109 
110   *SP          = sp;
111   PetscFunctionReturn(0);
112 }
113 
114 #undef __FUNCT__
115 #define __FUNCT__ "MatNullSpaceDestroy"
116 /*@
117    MatNullSpaceDestroy - Destroys a data structure used to project vectors
118    out of null spaces.
119 
120    Collective on MatNullSpace
121 
122    Input Parameter:
123 .  sp - the null space context to be destroyed
124 
125    Level: advanced
126 
127 .keywords: PC, null space, destroy
128 
129 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
130 @*/
131 PetscErrorCode  MatNullSpaceDestroy(MatNullSpace *sp)
132 {
133   PetscErrorCode ierr;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1);
137   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);}
138 
139   if ((*sp)->vec)  { ierr = VecDestroy((*sp)->vec);CHKERRQ(ierr); }
140   if ((*sp)->vecs) { ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr); }
141   ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr);
142   ierr = PetscHeaderDestroy((*sp));CHKERRQ(ierr);
143   (*sp)  = 0;
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNCT__
148 #define __FUNCT__ "MatNullSpaceRemove"
149 /*@C
150    MatNullSpaceRemove - Removes all the components of a null space from a vector.
151 
152    Collective on MatNullSpace
153 
154    Input Parameters:
155 +  sp - the null space context
156 .  vec - the vector from which the null space is to be removed
157 -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
158          the removal is done in-place (in vec)
159 
160    Note: The user is not responsible for the vector returned and should not destroy it.
161 
162    Level: advanced
163 
164 .keywords: PC, null space, remove
165 
166 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
167 @*/
168 PetscErrorCode  MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
169 {
170   PetscScalar    sum;
171   PetscInt       i,N;
172   PetscErrorCode ierr;
173 
174   PetscFunctionBegin;
175   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
176   PetscValidHeaderSpecific(vec,VEC_CLASSID,2);
177 
178   if (out) {
179     PetscValidPointer(out,3);
180     if (!sp->vec) {
181       ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr);
182       ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr);
183     }
184     ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr);
185     vec = *out = sp->vec;
186   }
187 
188   if (sp->has_cnst) {
189     ierr = VecGetSize(vec,&N);CHKERRQ(ierr);
190     if (N > 0) {
191       ierr = VecSum(vec,&sum);CHKERRQ(ierr);
192       sum  = sum/(-1.0*N);
193       ierr = VecShift(vec,sum);CHKERRQ(ierr);
194     }
195   }
196 
197   if (sp->n) {
198     ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr);
199     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
200     ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr);
201   }
202 
203   if (sp->remove){
204     ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr);
205   }
206   PetscFunctionReturn(0);
207 }
208 
209 #undef __FUNCT__
210 #define __FUNCT__ "MatNullSpaceTest"
211 /*@
212    MatNullSpaceTest  - Tests if the claimed null space is really a
213      null space of a matrix
214 
215    Collective on MatNullSpace
216 
217    Input Parameters:
218 +  sp - the null space context
219 -  mat - the matrix
220 
221    Output Parameters:
222 .  isNull - PETSC_TRUE if the nullspace is valid for this matrix
223 
224    Level: advanced
225 
226 .keywords: PC, null space, remove
227 
228 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
229 @*/
230 PetscErrorCode  MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool  *isNull)
231 {
232   PetscScalar    sum;
233   PetscReal      nrm;
234   PetscInt       j,n,N;
235   PetscErrorCode ierr;
236   Vec            l,r;
237   PetscBool      flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
238   PetscViewer    viewer;
239 
240   PetscFunctionBegin;
241   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
242   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
243   n = sp->n;
244   ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr);
245   ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr);
246 
247   if (!sp->vec) {
248     if (n) {
249       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
250     } else {
251       ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr);
252     }
253   }
254   l    = sp->vec;
255 
256   ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr);
257   if (sp->has_cnst) {
258     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
259     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
260     sum  = 1.0/N;
261     ierr = VecSet(l,sum);CHKERRQ(ierr);
262     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
263     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
264     if (nrm < 1.e-7) {
265       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr);
266     } else {
267       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);
268       consistent = PETSC_FALSE;
269     }
270     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1/N || = %G\n",nrm);CHKERRQ(ierr);
271     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
272     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
273     ierr = VecDestroy(r);CHKERRQ(ierr);
274   }
275 
276   for (j=0; j<n; j++) {
277     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
278     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
279     if (nrm < 1.e-7) {
280       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);
281     } else {
282       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);
283       consistent = PETSC_FALSE;
284     }
285     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
286     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
287     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
288   }
289 
290   if (sp->remove) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
291   if (isNull) *isNull = consistent;
292   PetscFunctionReturn(0);
293 }
294 
295