xref: /petsc/src/mat/interface/matnull.c (revision 3cfa868005f9094c013e5a0923a816520f5fe8a6)
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 = 0;
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   Users manual sections:
62 .   sec_singular
63 
64 .keywords: PC, null space, create
65 
66 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
67 @*/
68 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
69 {
70   MatNullSpace   sp;
71   PetscErrorCode ierr;
72   PetscInt       i;
73 
74   PetscFunctionBegin;
75   if (n) PetscValidPointer(vecs,4);
76   for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_COOKIE,4);
77   PetscValidPointer(SP,5);
78 
79   *SP = PETSC_NULL;
80 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
81   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
82 #endif
83 
84   ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);CHKERRQ(ierr);
85   ierr = PetscLogObjectMemory(sp,sizeof(struct _p_MatNullSpace));CHKERRQ(ierr);
86 
87   sp->has_cnst = has_cnst;
88   sp->n        = n;
89   sp->vec      = PETSC_NULL;
90   if (n) {
91     ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr);
92     for (i=0; i<n; i++) sp->vecs[i] = vecs[i];
93   } else {
94     sp->vecs = 0;
95   }
96 
97   for (i=0; i<n; i++) {
98     ierr = PetscObjectReference((PetscObject)sp->vecs[i]);CHKERRQ(ierr);
99   }
100   *SP          = sp;
101   PetscFunctionReturn(0);
102 }
103 
104 #undef __FUNCT__
105 #define __FUNCT__ "MatNullSpaceDestroy"
106 /*@
107    MatNullSpaceDestroy - Destroys a data structure used to project vectors
108    out of null spaces.
109 
110    Collective on MatNullSpace
111 
112    Input Parameter:
113 .  sp - the null space context to be destroyed
114 
115    Level: advanced
116 
117 .keywords: PC, null space, destroy
118 
119 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
120 @*/
121 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp)
122 {
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
127   if (--sp->refct > 0) PetscFunctionReturn(0);
128 
129   if (sp->vec) {ierr = VecDestroy(sp->vec);CHKERRQ(ierr);}
130   if (sp->vecs) {
131     ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr);
132   }
133   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
134   PetscFunctionReturn(0);
135 }
136 
137 #undef __FUNCT__
138 #define __FUNCT__ "MatNullSpaceRemove"
139 /*@
140    MatNullSpaceRemove - Removes all the components of a null space from a vector.
141 
142    Collective on MatNullSpace
143 
144    Input Parameters:
145 +  sp - the null space context
146 .  vec - the vector from which the null space is to be removed
147 -  out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise
148          the removal is done in-place (in vec)
149 
150    Note: The user is not responsible for the vector returned and should not destroy it.
151 
152    Level: advanced
153 
154 .keywords: PC, null space, remove
155 
156 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
157 @*/
158 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
159 {
160   PetscScalar    sum;
161   PetscErrorCode ierr;
162   PetscInt       j,n = sp->n,N;
163   Vec            l = vec;
164 
165   PetscFunctionBegin;
166   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
167   PetscValidHeaderSpecific(vec,VEC_COOKIE,2);
168 
169   if (out) {
170     PetscValidPointer(out,3);
171     if (!sp->vec) {
172       ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr);
173     }
174     *out = sp->vec;
175     ierr = VecCopy(vec,*out);CHKERRQ(ierr);
176     l    = *out;
177   }
178 
179   if (sp->has_cnst) {
180     ierr = VecSum(l,&sum);CHKERRQ(ierr);
181     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
182     sum  = sum/(-1.0*N);
183     ierr = VecShift(l,sum);CHKERRQ(ierr);
184   }
185 
186   for (j=0; j<n; j++) {
187     ierr = VecDot(l,sp->vecs[j],&sum);CHKERRQ(ierr);
188     ierr = VecAXPY(l,-sum,sp->vecs[j]);CHKERRQ(ierr);
189   }
190 
191   if (sp->remove){
192     ierr = (*sp->remove)(l,sp->rmctx);
193   }
194   PetscFunctionReturn(0);
195 }
196 
197 #undef __FUNCT__
198 #define __FUNCT__ "MatNullSpaceTest"
199 /*@
200    MatNullSpaceTest  - Tests if the claimed null space is really a
201      null space of a matrix
202 
203    Collective on MatNullSpace
204 
205    Input Parameters:
206 +  sp - the null space context
207 -  mat - the matrix
208 
209    Level: advanced
210 
211 .keywords: PC, null space, remove
212 
213 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
214 @*/
215 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat)
216 {
217   PetscScalar    sum;
218   PetscReal      nrm;
219   PetscInt       j,n,N,m;
220   PetscErrorCode ierr;
221   Vec            l,r;
222   PetscTruth     flg1,flg2;
223   PetscViewer    viewer;
224 
225   PetscFunctionBegin;
226   PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1);
227   PetscValidHeaderSpecific(mat,MAT_COOKIE,2);
228   n = sp->n;
229   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);CHKERRQ(ierr);
230   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);CHKERRQ(ierr);
231 
232   if (!sp->vec) {
233     if (n) {
234       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
235     } else {
236       ierr = MatGetLocalSize(mat,&m,PETSC_NULL);CHKERRQ(ierr);
237       ierr = VecCreateMPI(sp->comm,m,PETSC_DETERMINE,&sp->vec);CHKERRQ(ierr);
238     }
239   }
240   l    = sp->vec;
241 
242   ierr = PetscViewerASCIIGetStdout(sp->comm,&viewer);CHKERRQ(ierr);
243   if (sp->has_cnst) {
244     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
245     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
246     sum  = 1.0/N;
247     ierr = VecSet(l,sum);CHKERRQ(ierr);
248     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
249     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
250     if (nrm < 1.e-7) {ierr = PetscPrintf(sp->comm,"Constants are likely null vector");CHKERRQ(ierr);}
251     else {ierr = PetscPrintf(sp->comm,"Constants are unlikely null vector ");CHKERRQ(ierr);}
252     ierr = PetscPrintf(sp->comm,"|| A * 1 || = %G\n",nrm);CHKERRQ(ierr);
253     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
254     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
255     ierr = VecDestroy(r);CHKERRQ(ierr);
256   }
257 
258   for (j=0; j<n; j++) {
259     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
260     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
261     if (nrm < 1.e-7) {ierr = PetscPrintf(sp->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);}
262     else {ierr = PetscPrintf(sp->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);}
263     ierr = PetscPrintf(sp->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
264     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
265     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
266   }
267 
268   if (sp->remove){
269     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
270   }
271 
272   PetscFunctionReturn(0);
273 }
274 
275