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 #include "petscsys.h" 9 10 PetscCookie PETSCMAT_DLLEXPORT MAT_NULLSPACE_COOKIE; 11 12 #undef __FUNCT__ 13 #define __FUNCT__ "MatNullSpaceSetFunction" 14 /*@C 15 MatNullSpaceSetFunction - set a function that removes a null space from a vector 16 out of null spaces. 17 18 Collective on MatNullSpace 19 20 Input Parameters: 21 + sp - the null space object 22 . rem - the function that removes the null space 23 - ctx - context for the remove function 24 25 Level: advanced 26 27 .keywords: PC, null space, create 28 29 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate() 30 @*/ 31 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx) 32 { 33 PetscFunctionBegin; 34 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1); 35 sp->remove = rem; 36 sp->rmctx = ctx; 37 PetscFunctionReturn(0); 38 } 39 40 #undef __FUNCT__ 41 #define __FUNCT__ "MatNullSpaceCreate" 42 /*@ 43 MatNullSpaceCreate - Creates a data structure used to project vectors 44 out of null spaces. 45 46 Collective on MPI_Comm 47 48 Input Parameters: 49 + comm - the MPI communicator associated with the object 50 . has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE 51 . n - number of vectors (excluding constant vector) in null space 52 - vecs - the vectors that span the null space (excluding the constant vector); 53 these vectors must be orthonormal. These vectors are NOT copied, so do not change them 54 after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count 55 for them by one). 56 57 Output Parameter: 58 . SP - the null space context 59 60 Level: advanced 61 62 Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs. 63 64 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 65 need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction(). 66 67 Users manual sections: 68 . sec_singular 69 70 .keywords: PC, null space, create 71 72 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction() 73 @*/ 74 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceCreate(MPI_Comm comm,PetscTruth has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP) 75 { 76 MatNullSpace sp; 77 PetscErrorCode ierr; 78 PetscInt i; 79 80 PetscFunctionBegin; 81 if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n); 82 if (n) PetscValidPointer(vecs,4); 83 for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_COOKIE,4); 84 PetscValidPointer(SP,5); 85 86 *SP = PETSC_NULL; 87 #ifndef PETSC_USE_DYNAMIC_LIBRARIES 88 ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr); 89 #endif 90 91 ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_COOKIE,0,"MatNullSpace",comm,MatNullSpaceDestroy,0);CHKERRQ(ierr); 92 93 sp->has_cnst = has_cnst; 94 sp->n = n; 95 sp->vecs = 0; 96 sp->alpha = 0; 97 sp->vec = 0; 98 sp->remove = 0; 99 sp->rmctx = 0; 100 101 if (n) { 102 ierr = PetscMalloc(n*sizeof(Vec),&sp->vecs);CHKERRQ(ierr); 103 ierr = PetscMalloc(n*sizeof(PetscScalar),&sp->alpha);CHKERRQ(ierr); 104 ierr = PetscLogObjectMemory(sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 105 for (i=0; i<n; i++) { 106 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 107 sp->vecs[i] = vecs[i]; 108 } 109 } 110 111 *SP = sp; 112 PetscFunctionReturn(0); 113 } 114 115 #undef __FUNCT__ 116 #define __FUNCT__ "MatNullSpaceDestroy" 117 /*@ 118 MatNullSpaceDestroy - Destroys a data structure used to project vectors 119 out of null spaces. 120 121 Collective on MatNullSpace 122 123 Input Parameter: 124 . sp - the null space context to be destroyed 125 126 Level: advanced 127 128 .keywords: PC, null space, destroy 129 130 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 131 @*/ 132 PetscErrorCode PETSCMAT_DLLEXPORT MatNullSpaceDestroy(MatNullSpace sp) 133 { 134 PetscErrorCode ierr; 135 136 PetscFunctionBegin; 137 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1); 138 if (--((PetscObject)sp)->refct > 0) PetscFunctionReturn(0); 139 140 if (sp->vec) { ierr = VecDestroy(sp->vec);CHKERRQ(ierr); } 141 if (sp->vecs) { ierr = VecDestroyVecs(sp->vecs,sp->n);CHKERRQ(ierr); } 142 ierr = PetscFree(sp->alpha);CHKERRQ(ierr); 143 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 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 PETSCMAT_DLLEXPORT 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_COOKIE,1); 176 PetscValidHeaderSpecific(vec,VEC_COOKIE,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 PETSCMAT_DLLEXPORT MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscTruth *isNull) 231 { 232 PetscScalar sum; 233 PetscReal nrm; 234 PetscInt j,n,N; 235 PetscErrorCode ierr; 236 Vec l,r; 237 PetscTruth flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 238 PetscViewer viewer; 239 240 PetscFunctionBegin; 241 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1); 242 PetscValidHeaderSpecific(mat,MAT_COOKIE,2); 243 n = sp->n; 244 ierr = PetscOptionsGetTruth(PETSC_NULL,"-mat_null_space_test_view",&flg1,PETSC_NULL);CHKERRQ(ierr); 245 ierr = PetscOptionsGetTruth(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 || = %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){ 291 SETERRQ(PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 292 } 293 *isNull = consistent; 294 PetscFunctionReturn(0); 295 } 296 297