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