1 #define PETSCMAT_DLL 2 3 /* 4 Routines to project vectors out of null spaces. 5 */ 6 7 #include "private/matimpl.h" /*I "petscmat.h" I*/ 8 9 PetscClassId PETSCMAT_DLLEXPORT MAT_NULLSPACE_CLASSID; 10 11 #undef __FUNCT__ 12 #define __FUNCT__ "MatNullSpaceSetFunction" 13 /*@C 14 MatNullSpaceSetFunction - set a function that removes a null space from a vector 15 out of null spaces. 16 17 Logically Collective on MatNullSpace 18 19 Input Parameters: 20 + sp - the null space object 21 . rem - the function that removes the null space 22 - ctx - context for the remove function 23 24 Level: advanced 25 26 .keywords: PC, null space, create 27 28 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate() 29 @*/ 30 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx) 31 { 32 PetscFunctionBegin; 33 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 34 sp->remove = rem; 35 sp->rmctx = ctx; 36 PetscFunctionReturn(0); 37 } 38 39 #undef __FUNCT__ 40 #define __FUNCT__ "MatNullSpaceCreate" 41 /*@ 42 MatNullSpaceCreate - Creates a data structure used to project vectors 43 out of null spaces. 44 45 Collective on MPI_Comm 46 47 Input Parameters: 48 + comm - the MPI communicator associated with the object 49 . has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE 50 . n - number of vectors (excluding constant vector) in null space 51 - vecs - the vectors that span the null space (excluding the constant vector); 52 these vectors must be orthonormal. These vectors are NOT copied, so do not change them 53 after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count 54 for them by one). 55 56 Output Parameter: 57 . SP - the null space context 58 59 Level: advanced 60 61 Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs. 62 63 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 64 need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction(). 65 66 Users manual sections: 67 . sec_singular 68 69 .keywords: PC, null space, create 70 71 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction() 72 @*/ 73 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP) 74 { 75 MatNullSpace sp; 76 PetscErrorCode ierr; 77 PetscInt i; 78 79 PetscFunctionBegin; 80 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n); 81 if (n) PetscValidPointer(vecs,4); 82 for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_CLASSID,4); 83 PetscValidPointer(SP,5); 84 85 *SP = PETSC_NULL; 86 #ifndef PETSC_USE_DYNAMIC_LIBRARIES 87 ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr); 88 #endif 89 90 ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,0,"MatNullSpace",comm,MatNullSpaceDestroy,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 PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp) 132 { 133 PetscErrorCode ierr; 134 135 PetscFunctionBegin; 136 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 137 if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0); 138 139 if (sp->vec) { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); } 140 if (sp->vecs) { ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr); } 141 ierr = PetscFree(sp->alpha);CHKERRQ(ierr); 142 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 143 PetscFunctionReturn(0); 144 } 145 146 #undef __FUNCT__ 147 #define __FUNCT__ "MatNullSpaceRemove" 148 /*@C 149 MatNullSpaceRemove - Removes all the components of a null space from a vector. 150 151 Collective on MatNullSpace 152 153 Input Parameters: 154 + sp - the null space context 155 . vec - the vector from which the null space is to be removed 156 - out - if this is requested (not PETSC_NULL) then this is a vector with the null space removed otherwise 157 the removal is done in-place (in vec) 158 159 Note: The user is not responsible for the vector returned and should not destroy it. 160 161 Level: advanced 162 163 .keywords: PC, null space, remove 164 165 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 166 @*/ 167 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceRemove(MatNullSpace sp,Vec vec,Vec *out) 168 { 169 PetscScalar sum; 170 PetscInt i,N; 171 PetscErrorCode ierr; 172 173 PetscFunctionBegin; 174 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 175 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 176 177 if (out) { 178 PetscValidPointer(out,3); 179 if (!sp->vec) { 180 ierr = VecDuplicate(vec,&sp->vec);CHKERRQ(ierr); 181 ierr = PetscLogObjectParent(sp,sp->vec);CHKERRQ(ierr); 182 } 183 ierr = VecCopy(vec,sp->vec);CHKERRQ(ierr); 184 vec = *out = sp->vec; 185 } 186 187 if (sp->has_cnst) { 188 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 189 if (N > 0) { 190 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 191 sum = sum/(-1.0*N); 192 ierr = VecShift(vec,sum);CHKERRQ(ierr); 193 } 194 } 195 196 if (sp->n) { 197 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 198 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 199 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 200 } 201 202 if (sp->remove){ 203 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 204 } 205 PetscFunctionReturn(0); 206 } 207 208 #undef __FUNCT__ 209 #define __FUNCT__ "MatNullSpaceTest" 210 /*@ 211 MatNullSpaceTest - Tests if the claimed null space is really a 212 null space of a matrix 213 214 Collective on MatNullSpace 215 216 Input Parameters: 217 + sp - the null space context 218 - mat - the matrix 219 220 Output Parameters: 221 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 222 223 Level: advanced 224 225 .keywords: PC, null space, remove 226 227 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 228 @*/ 229 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 230 { 231 PetscScalar sum; 232 PetscReal nrm; 233 PetscInt j,n,N; 234 PetscErrorCode ierr; 235 Vec l,r; 236 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 237 PetscViewer viewer; 238 239 PetscFunctionBegin; 240 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 241 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 242 n = sp->n; 243 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr); 244 ierr = PetscOptionsGetBool(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2,PETSC_NULL);CHKERRQ(ierr); 245 246 if (!sp->vec) { 247 if (n) { 248 ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr); 249 } else { 250 ierr = MatGetVecs(mat,&sp->vec,PETSC_NULL);CHKERRQ(ierr); 251 } 252 } 253 l = sp->vec; 254 255 ierr = PetscViewerASCIIGetStdout(((PetscObject)sp)->comm,&viewer);CHKERRQ(ierr); 256 if (sp->has_cnst) { 257 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 258 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 259 sum = 1.0/N; 260 ierr = VecSet(l,sum);CHKERRQ(ierr); 261 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 262 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 263 if (nrm < 1.e-7) { 264 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are likely null vector");CHKERRQ(ierr); 265 } else { 266 ierr = PetscPrintf(((PetscObject)sp)->comm,"Constants are unlikely null vector ");CHKERRQ(ierr); 267 consistent = PETSC_FALSE; 268 } 269 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * 1/N || = %G\n",nrm);CHKERRQ(ierr); 270 if (nrm > 1.e-7 && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 271 if (nrm > 1.e-7 && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 272 ierr = VecDestroy(r);CHKERRQ(ierr); 273 } 274 275 for (j=0; j<n; j++) { 276 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 277 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 278 if (nrm < 1.e-7) { 279 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D is likely null vector",j);CHKERRQ(ierr); 280 } else { 281 ierr = PetscPrintf(((PetscObject)sp)->comm,"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 282 consistent = PETSC_FALSE; 283 } 284 ierr = PetscPrintf(((PetscObject)sp)->comm,"|| A * v[%D] || = %G\n",j,nrm);CHKERRQ(ierr); 285 if (nrm > 1.e-7 && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 286 if (nrm > 1.e-7 && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 287 } 288 289 if (sp->remove) SETERRQ(((PetscObject)mat)->comm,PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 290 if (isNull) *isNull = consistent; 291 PetscFunctionReturn(0); 292 } 293 294