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 /* cannot use MatNullSpaceDestroy() as generic destroy function because it takes pointer to the object */ 90 ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,0,"MatNullSpace",comm,0,0);CHKERRQ(ierr); 91 92 sp->has_cnst = has_cnst; 93 sp->n = n; 94 sp->vecs = 0; 95 sp->alpha = 0; 96 sp->vec = 0; 97 sp->remove = 0; 98 sp->rmctx = 0; 99 100 if (n) { 101 ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr); 102 ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr); 103 ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 104 for (i=0; i<n; i++) { 105 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 106 sp->vecs[i] = vecs[i]; 107 } 108 } 109 110 *SP = sp; 111 PetscFunctionReturn(0); 112 } 113 114 #undef __FUNCT__ 115 #define __FUNCT__ "MatNullSpaceDestroy" 116 /*@ 117 MatNullSpaceDestroy - Destroys a data structure used to project vectors 118 out of null spaces. 119 120 Collective on MatNullSpace 121 122 Input Parameter: 123 . sp - the null space context to be destroyed 124 125 Level: advanced 126 127 .keywords: PC, null space, destroy 128 129 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 130 @*/ 131 PetscErrorCode MatNullSpaceDestroy(MatNullSpace *sp) 132 { 133 PetscErrorCode ierr; 134 135 PetscFunctionBegin; 136 PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1); 137 if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} 138 139 if ((*sp)->vec) { ierr = VecDestroy((*sp)->vec);CHKERRQ(ierr); } 140 if ((*sp)->vecs) { ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr); } 141 ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr); 142 ierr = PetscHeaderDestroy((*sp));CHKERRQ(ierr); 143 (*sp) = 0; 144 PetscFunctionReturn(0); 145 } 146 147 #undef __FUNCT__ 148 #define __FUNCT__ "MatNullSpaceRemove" 149 /*@C 150 MatNullSpaceRemove - Removes all the components of a null space from a vector. 151 152 Collective on MatNullSpace 153 154 Input Parameters: 155 + sp - the null space context 156 . vec - the vector from which the null space is to be removed 157 - out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise 158 the removal is done in-place (in vec) 159 160 Note: The user is not responsible for the vector returned and should not destroy it. 161 162 Level: advanced 163 164 .keywords: PC, null space, remove 165 166 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 167 @*/ 168 PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out) 169 { 170 PetscScalar sum; 171 PetscInt i,N; 172 PetscErrorCode ierr; 173 174 PetscFunctionBegin; 175 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 176 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 177 178 if (out) { 179 PetscValidPointer(out,3); 180 if (!sp->vec) { 181 ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr); 182 ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr); 183 } 184 ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr); 185 vec = *out = sp->vec; 186 } 187 188 if (sp->has_cnst) { 189 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 190 if (N > 0) { 191 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 192 sum = sum/(-1.0*N); 193 ierr = VecShift(vec,sum);CHKERRQ(ierr); 194 } 195 } 196 197 if (sp->n) { 198 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 199 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 200 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 201 } 202 203 if (sp->remove){ 204 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 205 } 206 PetscFunctionReturn(0); 207 } 208 209 #undef __FUNCT__ 210 #define __FUNCT__ "MatNullSpaceTest" 211 /*@ 212 MatNullSpaceTest - Tests if the claimed null space is really a 213 null space of a matrix 214 215 Collective on MatNullSpace 216 217 Input Parameters: 218 + sp - the null space context 219 - mat - the matrix 220 221 Output Parameters: 222 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 223 224 Level: advanced 225 226 .keywords: PC, null space, remove 227 228 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 229 @*/ 230 PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 231 { 232 PetscScalar sum; 233 PetscReal nrm; 234 PetscInt j,n,N; 235 PetscErrorCode ierr; 236 Vec l,r; 237 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 238 PetscViewer viewer; 239 240 PetscFunctionBegin; 241 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 242 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 243 n = sp->n; 244 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr); 245 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr); 246 247 if (!sp->vec) { 248 if (n) { 249 ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr); 250 } else { 251 ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr); 252 } 253 } 254 l = sp->vec; 255 256 ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr); 257 if (sp->has_cnst) { 258 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 259 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 260 sum = 1.0/N; 261 ierr = VecSet(l,sum);CHKERRQ(ierr); 262 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 263 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 264 if (nrm < 1.e-7) { 265 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr); 266 } else { 267 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr); 268 consistent = PETSC_FALSE; 269 } 270 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1/N || = %G\n",nrm);CHKERRQ(ierr); 271 if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 272 if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 273 ierr = VecDestroy(r);CHKERRQ(ierr); 274 } 275 276 for (j=0; j<n; j++) { 277 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 278 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 279 if (nrm < 1.e-7) { 280 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr); 281 } else { 282 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 283 consistent = PETSC_FALSE; 284 } 285 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr); 286 if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 287 if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 288 } 289 290 if (sp->remove) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 291 if (isNull) *isNull = consistent; 292 PetscFunctionReturn(0); 293 } 294 295