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