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