Actual source code: matnull.c
1: #define PETSCMAT_DLL
3: /*
4: Routines to project vectors out of null spaces.
5: */
7: #include include/private/matimpl.h
8: #include petscsys.h
10: PetscCookie MAT_NULLSPACE_COOKIE = 0;
14: /*@C
15: MatNullSpaceSetFunction - set a function that removes a null space from a vector
16: out of null spaces.
18: Collective on MatNullSpace
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
25: Level: advanced
27: .keywords: PC, null space, create
29: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate()
30: @*/
31: PetscErrorCode MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(Vec,void*),void *ctx)
32: {
35: sp->remove = rem;
36: sp->rmctx = ctx;
37: return(0);
38: }
42: /*@
43: MatNullSpaceCreate - Creates a data structure used to project vectors
44: out of null spaces.
46: Collective on MPI_Comm
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.
56: Output Parameter:
57: . SP - the null space context
59: Level: advanced
61: Users manual sections:
62: . Section 4.15 Solving Singular Systems
64: .keywords: PC, null space, create
66: .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction()
67: @*/
68: PetscErrorCode MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP)
69: {
70: MatNullSpace sp;
72: PetscInt i;
75: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n);
79:
80: *SP = PETSC_NULL;
81: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
82: MatInitializePackage(PETSC_NULL);
83: #endif
85: PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);
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;
95: if (n) {
96: PetscMalloc(n*sizeof(Vec),&sp->vecs);
97: PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);
98: PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));
99: for (i=0; i<n; i++) {
100: PetscObjectReference((PetscObject)vecs[i]);
101: sp->vecs[i] = vecs[i];
102: }
103: }
105: *SP = sp;
106: return(0);
107: }
111: /*@
112: MatNullSpaceDestroy - Destroys a data structure used to project vectors
113: out of null spaces.
115: Collective on MatNullSpace
117: Input Parameter:
118: . sp - the null space context to be destroyed
120: Level: advanced
122: .keywords: PC, null space, destroy
124: .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction()
125: @*/
126: PetscErrorCode MatNullSpaceDestroy(MatNullSpace sp)
127: {
132: if (--((PetscObject)sp)->refct > 0) return(0);
134: if (sp->vec) { VecDestroy(sp->vec); }
135: if (sp->vecs) { VecDestroyVecs(sp->vecs,sp->n); }
136: PetscFree(sp->alpha);
137: PetscHeaderDestroy(sp);
138: return(0);
139: }
143: /*@
144: MatNullSpaceRemove - Removes all the components of a null space from a vector.
146: Collective on MatNullSpace
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)
154: Note: The user is not responsible for the vector returned and should not destroy it.
156: Level: advanced
158: .keywords: PC, null space, remove
160: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
161: @*/
162: PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out)
163: {
164: PetscScalar sum;
165: PetscInt i,N;
172: if (out) {
174: if (!sp->vec) {
175: VecDuplicate(vec,&sp->vec);
176: PetscLogObjectParent(sp,sp->vec);
177: }
178: VecCopy(vec,sp->vec);
179: vec = *out = sp->vec;
180: }
181:
182: if (sp->has_cnst) {
183: VecGetSize(vec,&N);
184: if (N > 0) {
185: VecSum(vec,&sum);
186: sum = sum/(-1.0*N);
187: VecShift(vec,sum);
188: }
189: }
190:
191: if (sp->n) {
192: VecMDot(vec,sp->n,sp->vecs,sp->alpha);
193: for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i];
194: VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);
195: }
197: if (sp->remove){
198: (*sp->remove)(vec,sp->rmctx);
199: }
200: return(0);
201: }
205: /*@
206: MatNullSpaceTest - Tests if the claimed null space is really a
207: null space of a matrix
209: Collective on MatNullSpace
211: Input Parameters:
212: + sp - the null space context
213: - mat - the matrix
215: Level: advanced
217: .keywords: PC, null space, remove
219: .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction()
220: @*/
221: PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat)
222: {
223: PetscScalar sum;
224: PetscReal nrm;
225: PetscInt j,n,N,m;
227: Vec l,r;
228: PetscTruth flg1,flg2;
229: PetscViewer viewer;
234: n = sp->n;
235: PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);
236: PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);
238: if (!sp->vec) {
239: if (n) {
240: VecDuplicate(sp->vecs[0],&sp->vec);
241: } else {
242: MatGetLocalSize(mat,&m,PETSC_NULL);
243: VecCreateMPI(((PetscObject)sp)->comm,m,PETSC_DETERMINE,&sp->vec);
244: }
245: }
246: l = sp->vec;
248: PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);
249: if (sp->has_cnst) {
250: VecDuplicate(l,&r);
251: VecGetSize(l,&N);
252: sum = 1.0/N;
253: VecSet(l,sum);
254: MatMult(mat,l,r);
255: VecNorm(r,NORM_2,&nrm);
256: if (nrm < 1.e-7) {PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");}
257: else {PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");}
258: PetscPrintf(((PetscObject)sp)->comm,"|| A * 1 || = %G\n",nrm);
259: if (nrm > 1.e-7 && flg1) {VecView(r,viewer);}
260: if (nrm > 1.e-7 && flg2) {VecView(r,viewer);}
261: VecDestroy(r);
262: }
264: for (j=0; j<n; j++) {
265: (*mat->ops->mult)(mat,sp->vecs[j],l);
266: VecNorm(l,NORM_2,&nrm);
267: if (nrm < 1.e-7) {PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);}
268: else {PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);}
269: PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);
270: if (nrm > 1.e-7 && flg1) {VecView(l,viewer);}
271: if (nrm > 1.e-7 && flg2) {VecView(l,viewer);}
272: }
274: if (sp->remove){
275: SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()");
276: }
277:
278: return(0);
279: }