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