xref: /petsc/src/mat/interface/matnull.c (revision d0f46423f772d871f92d805d83c5bf0c050e33b4)
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    Level: advanced
221 
222 .keywords: PC, null space, remove
223 
224 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
225 @*/
226 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat)
227 {
228   PetscScalar    sum;
229   PetscReal      nrm;
230   PetscInt       j,n,N,m;
231   PetscErrorCode ierr;
232   Vec            l,r;
233   PetscTruth     flg1,flg2;
234   PetscViewer    viewer;
235 
236   PetscFunctionBegin;
237   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
238   PetscValidHeaderSpecific(mat,MAT_COOKIE,2);
239   n = sp->n;
240   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);CHKERRQ(ierr);
241   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);CHKERRQ(ierr);
242 
243   if (!sp->vec) {
244     if (n) {
245       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
246     } else {
247       ierr = MatGetLocalSize(mat,&m,PETSC_NULL);CHKERRQ(ierr);
248       ierr = VecCreateMPI(((PetscObject)sp)->comm,m,PETSC_DETERMINE,&sp->vec);CHKERRQ(ierr);
249     }
250   }
251   l    = sp->vec;
252 
253   ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr);
254   if (sp->has_cnst) {
255     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
256     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
257     sum  = 1.0/N;
258     ierr = VecSet(l,sum);CHKERRQ(ierr);
259     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
260     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
261     if (nrm < 1.e-7) {ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr);}
262     else {ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);}
263     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1 || = %G\n",nrm);CHKERRQ(ierr);
264     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
265     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
266     ierr = VecDestroy(r);CHKERRQ(ierr);
267   }
268 
269   for (j=0; j<n; j++) {
270     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
271     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
272     if (nrm < 1.e-7) {ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);}
273     else {ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);}
274     ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
275     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
276     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
277   }
278 
279   if (sp->remove){
280     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
281   }
282 
283   PetscFunctionReturn(0);
284 }
285 
286