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