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