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