xref: /petsc/src/mat/interface/matnull.c (revision c87e5d42f888a3a565cbd99898d986425684792c)
1 #define PETSCMAT_DLL
2 
3 /*
4     Routines to project vectors out of null spaces.
5 */
6 
7 #include "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)(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.
55 
56    Output Parameter:
57 .  SP - the null space context
58 
59    Level: advanced
60 
61    Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs.
62 
63       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
64        need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction().
65 
66   Users manual sections:
67 .   sec_singular
68 
69 .keywords: PC, null space, create
70 
71 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
72 @*/
73 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
74 {
75   MatNullSpace   sp;
76   PetscErrorCode ierr;
77   PetscInt       i;
78 
79   PetscFunctionBegin;
80   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
81   if (n) PetscValidPointer(vecs,4);
82   for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_COOKIE,4);
83   PetscValidPointer(SP,5);
84 
85   *SP = PETSC_NULL;
86 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
87   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
88 #endif
89 
90   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,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 PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp)
132 {
133   PetscErrorCode ierr;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
137   if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0);
138 
139   if (sp->vec)  { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); }
140   if (sp->vecs) { ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr); }
141   ierr = PetscFree(sp->alpha);CHKERRQ(ierr);
142   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
143   PetscFunctionReturn(0);
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "MatNullSpaceRemove"
148 /*@C
149    MatNullSpaceRemove - Removes all the components of a null space from a vector.
150 
151    Collective on MatNullSpace
152 
153    Input Parameters:
154 +  sp - the null space context
155 .  vec - the vector from which the null space is to be removed
156 -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
157          the removal is done in-place (in vec)
158 
159    Note: The user is not responsible for the vector returned and should not destroy it.
160 
161    Level: advanced
162 
163 .keywords: PC, null space, remove
164 
165 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
166 @*/
167 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
168 {
169   PetscScalar    sum;
170   PetscInt       i,N;
171   PetscErrorCode ierr;
172 
173   PetscFunctionBegin;
174   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
175   PetscValidHeaderSpecific(vec,VEC_COOKIE,2);
176 
177   if (out) {
178     PetscValidPointer(out,3);
179     if (!sp->vec) {
180       ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr);
181       ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr);
182     }
183     ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr);
184     vec = *out = sp->vec;
185   }
186 
187   if (sp->has_cnst) {
188     ierr = VecGetSize(vec,&N);CHKERRQ(ierr);
189     if (N > 0) {
190       ierr = VecSum(vec,&sum);CHKERRQ(ierr);
191       sum  = sum/(-1.0*N);
192       ierr = VecShift(vec,sum);CHKERRQ(ierr);
193     }
194   }
195 
196   if (sp->n) {
197     ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr);
198     for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
199     ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr);
200   }
201 
202   if (sp->remove){
203     ierr = (*sp->remove)(vec,sp->rmctx);
204   }
205   PetscFunctionReturn(0);
206 }
207 
208 #undef __FUNCT__
209 #define __FUNCT__ "MatNullSpaceTest"
210 /*@
211    MatNullSpaceTest  - Tests if the claimed null space is really a
212      null space of a matrix
213 
214    Collective on MatNullSpace
215 
216    Input Parameters:
217 +  sp - the null space context
218 -  mat - the matrix
219 
220    Output Parameters:
221 .  isNull - PETSC_TRUE if the nullspace is valid for this matrix
222 
223    Level: advanced
224 
225 .keywords: PC, null space, remove
226 
227 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
228 @*/
229 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscTruth *isNull)
230 {
231   PetscScalar    sum;
232   PetscReal      nrm;
233   PetscInt       j,n,N,m;
234   PetscErrorCode ierr;
235   Vec            l,r;
236   PetscTruth     flg1,flg2,consistent = PETSC_TRUE;
237   PetscViewer    viewer;
238 
239   PetscFunctionBegin;
240   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
241   PetscValidHeaderSpecific(mat,MAT_COOKIE,2);
242   n = sp->n;
243   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);CHKERRQ(ierr);
244   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);CHKERRQ(ierr);
245 
246   if (!sp->vec) {
247     if (n) {
248       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
249     } else {
250       ierr = MatGetLocalSize(mat,&m,PETSC_NULL);CHKERRQ(ierr);
251       ierr = VecCreateMPI(((PetscObject)sp)->comm,m,PETSC_DETERMINE,&sp->vec);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