1 #define PETSCMAT_DLL 2 3 /* 4 Routines to project vectors out of null spaces. 5 */ 6 7 #include "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)(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. 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,PetscTruth 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_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_COOKIE,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_COOKIE,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_COOKIE,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_COOKIE,1); 175 PetscValidHeaderSpecific(vec,VEC_COOKIE,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)(vec,sp->rmctx); 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,PetscTruth *isNull) 230 { 231 PetscScalar sum; 232 PetscReal nrm; 233 PetscInt j,n,N,m; 234 PetscErrorCode ierr; 235 Vec l,r; 236 PetscTruth flg1,flg2,consistent = PETSC_TRUE; 237 PetscViewer viewer; 238 239 PetscFunctionBegin; 240 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_COOKIE,1); 241 PetscValidHeaderSpecific(mat,MAT_COOKIE,2); 242 n = sp->n; 243 ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view",&flg1);CHKERRQ(ierr); 244 ierr = PetscOptionsHasName(PETSC_NULL,"-mat_null_space_test_view_draw",&flg2);CHKERRQ(ierr); 245 246 if (!sp->vec) { 247 if (n) { 248 ierr = VecDuplicate(sp->vecs[0],&sp->vec);CHKERRQ(ierr); 249 } else { 250 ierr = MatGetLocalSize(mat,&m,PETSC_NULL);CHKERRQ(ierr); 251 ierr = VecCreateMPI(((PetscObject)sp)->comm,m,PETSC_DETERMINE,&sp->vec);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