xref: /petsc/src/mat/interface/matnull.c (revision 3050cee28ff83b093d983d7c5197e87b438ca09b)
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   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   PetscViewer    viewer;
223 
224   PetscFunctionBegin;
225   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);CHKERRQ(ierr);
226   ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);CHKERRQ(ierr);
227 
228   if (!sp->vec) {
229     if (n) {
230       ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr);
231     } else {
232       ierr = MatGetLocalSize(mat,&m,PETSC_NULL);CHKERRQ(ierr);
233       ierr = VecCreateMPI(sp->comm,m,PETSC_DETERMINE,&sp->vec);CHKERRQ(ierr);
234     }
235   }
236   l    = sp->vec;
237 
238   ierr = PetscViewerASCIIGetStdout(comm,&viewer);CHKERRQ(ierr);
239   if (sp->has_cnst) {
240     ierr = VecDuplicate(l,&r);CHKERRQ(ierr);
241     ierr = VecGetSize(l,&N);CHKERRQ(ierr);
242     sum  = 1.0/N;
243     ierr = VecSet(l,sum);CHKERRQ(ierr);
244     ierr = MatMult(mat,l,r);CHKERRQ(ierr);
245     ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr);
246     if (nrm < 1.e-7) {ierr = PetscPrintf(comm,"Constants are likely null vector");CHKERRQ(ierr);}
247     else {ierr = PetscPrintf(comm,"Constants are unlikely null vector ");CHKERRQ(ierr);}
248     ierr = PetscPrintf(comm,"|| A * 1 || = %G\n",nrm);CHKERRQ(ierr);
249     if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
250     if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);}
251     ierr = VecDestroy(r);CHKERRQ(ierr);
252   }
253 
254   for (j=0; j<n; j++) {
255     ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr);
256     ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr);
257     if (nrm < 1.e-7) {ierr = PetscPrintf(comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr);}
258     else {ierr = PetscPrintf(comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr);}
259     ierr = PetscPrintf(comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr);
260     if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
261     if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);}
262   }
263 
264   if (sp->remove){
265     SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
266   }
267 
268   PetscFunctionReturn(0);
269 }
270 
271