xref: /petsc/src/mat/interface/matnull.c (revision e32f2f54e699d0aa6e733466c00da7e34666fe5e)
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 
9 PetscClassId PETSCMAT_DLLEXPORT MAT_NULLSPACE_CLASSID;
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "MatNullSpaceSetFunction"
13 /*@C
14    MatNullSpaceSetFunction - set a function that removes a null space from a vector
15    out of null spaces.
16 
17    Collective on MatNullSpace
18 
19    Input Parameters:
20 +  sp - the null space object
21 .  rem - the function that removes the null space
22 -  ctx - context for the remove function
23 
24    Level: advanced
25 
26 .keywords: PC, null space, create
27 
28 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
29 @*/
30 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx)
31 {
32   PetscFunctionBegin;
33   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
34   sp->remove = rem;
35   sp->rmctx  = ctx;
36   PetscFunctionReturn(0);
37 }
38 
39 #undef __FUNCT__
40 #define __FUNCT__ "MatNullSpaceCreate"
41 /*@
42    MatNullSpaceCreate - Creates a data structure used to project vectors
43    out of null spaces.
44 
45    Collective on MPI_Comm
46 
47    Input Parameters:
48 +  comm - the MPI communicator associated with the object
49 .  has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE
50 .  n - number of vectors (excluding constant vector) in null space
51 -  vecs - the vectors that span the null space (excluding the constant vector);
52           these vectors must be orthonormal. These vectors are NOT copied, so do not change them
53           after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count
54           for them by one).
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_COMM_SELF,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_CLASSID,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_CLASSID,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_CLASSID,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_CLASSID,1);
175   PetscValidHeaderSpecific(vec,VEC_CLASSID,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)(sp,vec,sp->rmctx);CHKERRQ(ierr);
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;
234   PetscErrorCode ierr;
235   Vec            l,r;
236   PetscTruth     flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE;
237   PetscViewer    viewer;
238 
239   PetscFunctionBegin;
240   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1);
241   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
242   n = sp->n;
243   ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr);
244   ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr);
245 
246   if (!sp->vec) {
247     if (n) {
248       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
249     } else {
250       ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr);
251     }
252   }
253   l    = sp->vec;
254 
255   ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr);
256   if (sp->has_cnst) {
257     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
258     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
259     sum  = 1.0/N;
260     ierr = VecSet(l,sum);CHKERRQ(ierr);
261     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
262     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
263     if (nrm < 1.e-7) {
264       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr);
265     } else {
266       ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);
267       consistent = PETSC_FALSE;
268     }
269     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1 || = %G\n",nrm);CHKERRQ(ierr);
270     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
271     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
272     ierr = VecDestroy(r);CHKERRQ(ierr);
273   }
274 
275   for (j=0; j<n; j++) {
276     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
277     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
278     if (nrm < 1.e-7) {
279       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);
280     } else {
281       ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);
282       consistent = PETSC_FALSE;
283     }
284     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
285     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
286     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
287   }
288 
289   if (sp->remove){
290     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
291   }
292   *isNull = consistent;
293   PetscFunctionReturn(0);
294 }
295 
296