xref: /petsc/src/mat/interface/matnull.c (revision da93591f59bc1e95f467c6fc21a755040df0b8f3)
1 #define PETSCMAT_DLL
2 
3 /*
4     Routines to project vectors out of null spaces.
5 */
6 
7 #include "private/matimpl.h"      /*I "petscmat.h" I*/
8 #include "petscsys.h"
9 
10 PetscCookie PETSCMAT_DLLEXPORT MAT_NULLSPACE_COOKIE;
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "MatNullSpaceSetFunction"
14 /*@C
15    MatNullSpaceSetFunction - set a function that removes a null space from a vector
16    out of null spaces.
17 
18    Collective on MatNullSpace
19 
20    Input Parameters:
21 +  sp - the null space object
22 .  rem - the function that removes the null space
23 -  ctx - context for the remove function
24 
25    Level: advanced
26 
27 .keywords: PC, null space, create
28 
29 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
30 @*/
31 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx)
32 {
33   PetscFunctionBegin;
34   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
35   sp->remove = rem;
36   sp->rmctx  = ctx;
37   PetscFunctionReturn(0);
38 }
39 
40 #undef __FUNCT__
41 #define __FUNCT__ "MatNullSpaceCreate"
42 /*@
43    MatNullSpaceCreate - Creates a data structure used to project vectors
44    out of null spaces.
45 
46    Collective on MPI_Comm
47 
48    Input Parameters:
49 +  comm - the MPI communicator associated with the object
50 .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
51 .  n - number of vectors (excluding constant vector) in null space
52 -  vecs - the vectors that span the null space (excluding the constant vector);
53           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
54           after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count
55           for them by one).
56 
57    Output Parameter:
58 .  SP - the null space context
59 
60    Level: advanced
61 
62    Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs.
63 
64       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
65        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().
66 
67   Users manual sections:
68 .   sec_singular
69 
70 .keywords: PC, null space, create
71 
72 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
73 @*/
74 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
75 {
76   MatNullSpace   sp;
77   PetscErrorCode ierr;
78   PetscInt       i;
79 
80   PetscFunctionBegin;
81   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
82   if (n) PetscValidPointer(vecs,4);
83   for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_COOKIE,4);
84   PetscValidPointer(SP,5);
85 
86   *SP = PETSC_NULL;
87 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
88   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
89 #endif
90 
91   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);CHKERRQ(ierr);
92 
93   sp->has_cnst = has_cnst;
94   sp->n        = n;
95   sp->vecs     = 0;
96   sp->alpha    = 0;
97   sp->vec      = 0;
98   sp->remove   = 0;
99   sp->rmctx    = 0;
100 
101   if (n) {
102     ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr);
103     ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr);
104     ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr);
105     for (i=0; i<n; i++) {
106       ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr);
107       sp->vecs[i] = vecs[i];
108     }
109   }
110 
111   *SP          = sp;
112   PetscFunctionReturn(0);
113 }
114 
115 #undef __FUNCT__
116 #define __FUNCT__ "MatNullSpaceDestroy"
117 /*@
118    MatNullSpaceDestroy - Destroys a data structure used to project vectors
119    out of null spaces.
120 
121    Collective on MatNullSpace
122 
123    Input Parameter:
124 .  sp - the null space context to be destroyed
125 
126    Level: advanced
127 
128 .keywords: PC, null space, destroy
129 
130 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
131 @*/
132 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp)
133 {
134   PetscErrorCode ierr;
135 
136   PetscFunctionBegin;
137   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
138   if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0);
139 
140   if (sp->vec)  { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); }
141   if (sp->vecs) { ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr); }
142   ierr = PetscFree(sp->alpha);CHKERRQ(ierr);
143   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
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 PETSCMAT_DLLEXPORT 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_COOKIE,1);
176   PetscValidHeaderSpecific(vec,VEC_COOKIE,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 PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscTruth *isNull)
231 {
232   PetscScalar    sum;
233   PetscReal      nrm;
234   PetscInt       j,n,N;
235   PetscErrorCode ierr;
236   Vec            l,r;
237   PetscTruth     flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
238   PetscViewer    viewer;
239 
240   PetscFunctionBegin;
241   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
242   PetscValidHeaderSpecific(mat,MAT_COOKIE,2);
243   n = sp->n;
244   ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr);
245   ierr = PetscOptionsGetTruth(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 || = %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){
291     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
292   }
293   *isNull = consistent;
294   PetscFunctionReturn(0);
295 }
296 
297