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