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