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