1 2 /* 3 Routines to project vectors out of null spaces. 4 */ 5 6 #include "private/matimpl.h" /*I "petscmat.h" I*/ 7 8 PetscClassId MAT_NULLSPACE_CLASSID; 9 10 #undef __FUNCT__ 11 #define __FUNCT__ "MatNullSpaceSetFunction" 12 /*@C 13 MatNullSpaceSetFunction - set a function that removes a null space from a vector 14 out of null spaces. 15 16 Logically Collective on MatNullSpace 17 18 Input Parameters: 19 + sp - the null space object 20 . rem - the function that removes the null space 21 - ctx - context for the remove function 22 23 Level: advanced 24 25 .keywords: PC, null space, create 26 27 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate() 28 @*/ 29 PetscErrorCode MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx) 30 { 31 PetscFunctionBegin; 32 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 33 sp->remove = rem; 34 sp->rmctx = ctx; 35 PetscFunctionReturn(0); 36 } 37 38 #undef __FUNCT__ 39 #define __FUNCT__ "MatNullSpaceCreate" 40 /*@ 41 MatNullSpaceCreate - Creates a data structure used to project vectors 42 out of null spaces. 43 44 Collective on MPI_Comm 45 46 Input Parameters: 47 + comm - the MPI communicator associated with the object 48 . has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE 49 . n - number of vectors (excluding constant vector) in null space 50 - vecs - the vectors that span the null space (excluding the constant vector); 51 these vectors must be orthonormal. These vectors are NOT copied, so do not change them 52 after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count 53 for them by one). 54 55 Output Parameter: 56 . SP - the null space context 57 58 Level: advanced 59 60 Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs. 61 62 If has_cnst is PETSC_TRUE you do not need to pass a constant vector in as a fourth argument to this routine, nor do you 63 need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction(). 64 65 Users manual sections: 66 . sec_singular 67 68 .keywords: PC, null space, create 69 70 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction() 71 @*/ 72 PetscErrorCode MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP) 73 { 74 MatNullSpace sp; 75 PetscErrorCode ierr; 76 PetscInt i; 77 78 PetscFunctionBegin; 79 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n); 80 if (n) PetscValidPointer(vecs,4); 81 for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_CLASSID,4); 82 PetscValidPointer(SP,5); 83 84 *SP = PETSC_NULL; 85 #ifndef PETSC_USE_DYNAMIC_LIBRARIES 86 ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr); 87 #endif 88 89 ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);CHKERRQ(ierr); 90 91 sp->has_cnst = has_cnst; 92 sp->n = n; 93 sp->vecs = 0; 94 sp->alpha = 0; 95 sp->vec = 0; 96 sp->remove = 0; 97 sp->rmctx = 0; 98 99 if (n) { 100 ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr); 101 ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr); 102 ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 103 for (i=0; i<n; i++) { 104 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 105 sp->vecs[i] = vecs[i]; 106 } 107 } 108 109 *SP = sp; 110 PetscFunctionReturn(0); 111 } 112 113 #undef __FUNCT__ 114 #define __FUNCT__ "MatNullSpaceDestroy" 115 /*@ 116 MatNullSpaceDestroy - Destroys a data structure used to project vectors 117 out of null spaces. 118 119 Collective on MatNullSpace 120 121 Input Parameter: 122 . sp - the null space context to be destroyed 123 124 Level: advanced 125 126 .keywords: PC, null space, destroy 127 128 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 129 @*/ 130 PetscErrorCode MatNullSpaceDestroy(MatNullSpace sp) 131 { 132 PetscErrorCode ierr; 133 134 PetscFunctionBegin; 135 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 136 if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0); 137 138 if (sp->vec) { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); } 139 if (sp->vecs) { ierr = VecDestroyVecs(sp->n,&sp->vecs);CHKERRQ(ierr); } 140 ierr = PetscFree(sp->alpha);CHKERRQ(ierr); 141 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 142 PetscFunctionReturn(0); 143 } 144 145 #undef __FUNCT__ 146 #define __FUNCT__ "MatNullSpaceRemove" 147 /*@C 148 MatNullSpaceRemove - Removes all the components of a null space from a vector. 149 150 Collective on MatNullSpace 151 152 Input Parameters: 153 + sp - the null space context 154 . vec - the vector from which the null space is to be removed 155 - out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise 156 the removal is done in-place (in vec) 157 158 Note: The user is not responsible for the vector returned and should not destroy it. 159 160 Level: advanced 161 162 .keywords: PC, null space, remove 163 164 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 165 @*/ 166 PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out) 167 { 168 PetscScalar sum; 169 PetscInt i,N; 170 PetscErrorCode ierr; 171 172 PetscFunctionBegin; 173 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 174 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 175 176 if (out) { 177 PetscValidPointer(out,3); 178 if (!sp->vec) { 179 ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr); 180 ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr); 181 } 182 ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr); 183 vec = *out = sp->vec; 184 } 185 186 if (sp->has_cnst) { 187 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 188 if (N > 0) { 189 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 190 sum = sum/(-1.0*N); 191 ierr = VecShift(vec,sum);CHKERRQ(ierr); 192 } 193 } 194 195 if (sp->n) { 196 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 197 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 198 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 199 } 200 201 if (sp->remove){ 202 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 203 } 204 PetscFunctionReturn(0); 205 } 206 207 #undef __FUNCT__ 208 #define __FUNCT__ "MatNullSpaceTest" 209 /*@ 210 MatNullSpaceTest - Tests if the claimed null space is really a 211 null space of a matrix 212 213 Collective on MatNullSpace 214 215 Input Parameters: 216 + sp - the null space context 217 - mat - the matrix 218 219 Output Parameters: 220 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 221 222 Level: advanced 223 224 .keywords: PC, null space, remove 225 226 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 227 @*/ 228 PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 229 { 230 PetscScalar sum; 231 PetscReal nrm; 232 PetscInt j,n,N; 233 PetscErrorCode ierr; 234 Vec l,r; 235 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 236 PetscViewer viewer; 237 238 PetscFunctionBegin; 239 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 240 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 241 n = sp->n; 242 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr); 243 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr); 244 245 if (!sp->vec) { 246 if (n) { 247 ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr); 248 } else { 249 ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr); 250 } 251 } 252 l = sp->vec; 253 254 ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr); 255 if (sp->has_cnst) { 256 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 257 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 258 sum = 1.0/N; 259 ierr = VecSet(l,sum);CHKERRQ(ierr); 260 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 261 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 262 if (nrm < 1.e-7) { 263 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr); 264 } else { 265 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr); 266 consistent = PETSC_FALSE; 267 } 268 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1/N || = %G\n",nrm);CHKERRQ(ierr); 269 if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 270 if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 271 ierr = VecDestroy(r);CHKERRQ(ierr); 272 } 273 274 for (j=0; j<n; j++) { 275 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 276 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 277 if (nrm < 1.e-7) { 278 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr); 279 } else { 280 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 281 consistent = PETSC_FALSE; 282 } 283 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr); 284 if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 285 if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 286 } 287 288 if (sp->remove) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 289 if (isNull) *isNull = consistent; 290 PetscFunctionReturn(0); 291 } 292 293