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