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