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