1 2 /* 3 Routines to project vectors out of null spaces. 4 */ 5 6 #include <petsc-private/matimpl.h> /*I "petscmat.h" I*/ 7 8 PetscClassId MAT_NULLSPACE_CLASSID; 9 10 #undef __FUNCT__ 11 #define __FUNCT__ "MatNullSpaceSetFunction" 12 /*@C 13 MatNullSpaceSetFunction - set a function that removes a null space from a vector 14 out of null spaces. 15 16 Logically Collective on MatNullSpace 17 18 Input Parameters: 19 + sp - the null space object 20 . rem - the function that removes the null space 21 - ctx - context for the remove function 22 23 Level: advanced 24 25 .keywords: PC, null space, create 26 27 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceCreate() 28 @*/ 29 PetscErrorCode MatNullSpaceSetFunction(MatNullSpace sp, PetscErrorCode (*rem)(MatNullSpace,Vec,void*),void *ctx) 30 { 31 PetscFunctionBegin; 32 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 33 sp->remove = rem; 34 sp->rmctx = ctx; 35 PetscFunctionReturn(0); 36 } 37 38 #undef __FUNCT__ 39 #define __FUNCT__ "MatNullSpaceGetVecs" 40 /*@C 41 MatNullSpaceGetVecs - get vectors defining the null space 42 43 Not Collective 44 45 Input Arguments: 46 . sp - null space object 47 48 Output Arguments: 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 - orthonormal vectors that span the null space (excluding the constant vector) 52 53 Level: developer 54 55 .seealso: MatNullSpaceCreate(), MatGetNullSpace(), MatGetNearNullSpace() 56 @*/ 57 PetscErrorCode MatNullSpaceGetVecs(MatNullSpace sp,PetscBool *has_const,PetscInt *n,const Vec **vecs) 58 { 59 60 PetscFunctionBegin; 61 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 62 if (has_const) *has_const = sp->has_cnst; 63 if (n) *n = sp->n; 64 if (vecs) *vecs = sp->vecs; 65 PetscFunctionReturn(0); 66 } 67 68 #undef __FUNCT__ 69 #define __FUNCT__ "MatNullSpaceCreateRigidBody" 70 /*@ 71 MatNullSpaceCreateRigidBody - create rigid body modes from coordinates 72 73 Collective on Vec 74 75 Input Argument: 76 . coords - block of coordinates of each node, must have block size set 77 78 Output Argument: 79 . sp - the null space 80 81 Level: advanced 82 83 .seealso: MatNullSpaceCreate() 84 @*/ 85 PetscErrorCode MatNullSpaceCreateRigidBody(Vec coords,MatNullSpace *sp) 86 { 87 PetscErrorCode ierr; 88 const PetscScalar *x; 89 PetscScalar *v[6],dots[5]; 90 Vec vec[6]; 91 PetscInt n,N,dim,nmodes,i,j; 92 93 PetscFunctionBegin; 94 ierr = VecGetBlockSize(coords,&dim);CHKERRQ(ierr); 95 ierr = VecGetLocalSize(coords,&n);CHKERRQ(ierr); 96 ierr = VecGetSize(coords,&N);CHKERRQ(ierr); 97 n /= dim; 98 N /= dim; 99 switch (dim) { 100 case 1: 101 ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject)coords),PETSC_TRUE,0,NULL,sp);CHKERRQ(ierr); 102 break; 103 case 2: 104 case 3: 105 nmodes = (dim == 2) ? 3 : 6; 106 ierr = VecCreate(PetscObjectComm((PetscObject)coords),&vec[0]);CHKERRQ(ierr); 107 ierr = VecSetSizes(vec[0],dim*n,dim*N);CHKERRQ(ierr); 108 ierr = VecSetBlockSize(vec[0],dim);CHKERRQ(ierr); 109 ierr = VecSetUp(vec[0]);CHKERRQ(ierr); 110 for (i=1; i<nmodes; i++) {ierr = VecDuplicate(vec[0],&vec[i]);CHKERRQ(ierr);} 111 for (i=0; i<nmodes; i++) {ierr = VecGetArray(vec[i],&v[i]);CHKERRQ(ierr);} 112 ierr = VecGetArrayRead(coords,&x);CHKERRQ(ierr); 113 for (i=0; i<n; i++) { 114 if (dim == 2) { 115 v[0][i*2+0] = 1./N; 116 v[0][i*2+1] = 0.; 117 v[1][i*2+0] = 0.; 118 v[1][i*2+1] = 1./N; 119 /* Rotations */ 120 v[2][i*2+0] = -x[i*2+1]; 121 v[2][i*2+1] = x[i*2+0]; 122 } else { 123 v[0][i*3+0] = 1./N; 124 v[0][i*3+1] = 0.; 125 v[0][i*3+2] = 0.; 126 v[1][i*3+0] = 0.; 127 v[1][i*3+1] = 1./N; 128 v[1][i*3+2] = 0.; 129 v[2][i*3+0] = 0.; 130 v[2][i*3+1] = 0.; 131 v[2][i*3+2] = 1./N; 132 133 v[3][i*3+0] = x[i*3+1]; 134 v[3][i*3+1] = -x[i*3+0]; 135 v[3][i*3+2] = 0.; 136 v[4][i*3+0] = 0.; 137 v[4][i*3+1] = -x[i*3+2]; 138 v[4][i*3+2] = x[i*3+1]; 139 v[5][i*3+0] = x[i*3+2]; 140 v[5][i*3+1] = 0.; 141 v[5][i*3+2] = -x[i*3+0]; 142 } 143 } 144 for (i=0; i<nmodes; i++) {ierr = VecRestoreArray(vec[i],&v[i]);CHKERRQ(ierr);} 145 ierr = VecRestoreArrayRead(coords,&x);CHKERRQ(ierr); 146 for (i=dim; i<nmodes; i++) { 147 /* Orthonormalize vec[i] against vec[0:i-1] */ 148 ierr = VecMDot(vec[i],i,vec,dots);CHKERRQ(ierr); 149 for (j=0; j<i; j++) dots[j] *= -1.; 150 ierr = VecMAXPY(vec[i],i,dots,vec);CHKERRQ(ierr); 151 ierr = VecNormalize(vec[i],NULL);CHKERRQ(ierr); 152 } 153 ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject)coords),PETSC_FALSE,nmodes,vec,sp);CHKERRQ(ierr); 154 for (i=0; i<nmodes; i++) {ierr = VecDestroy(&vec[i]);CHKERRQ(ierr);} 155 } 156 PetscFunctionReturn(0); 157 } 158 159 #undef __FUNCT__ 160 #define __FUNCT__ "MatNullSpaceView" 161 /*@C 162 MatNullSpaceView - Visualizes a null space object. 163 164 Collective on MatNullSpace 165 166 Input Parameters: 167 + matnull - the null space 168 - viewer - visualization context 169 170 Level: advanced 171 172 Fortran Note: 173 This routine is not supported in Fortran. 174 175 .seealso: MatNullSpaceCreate(), PetscViewerASCIIOpen() 176 @*/ 177 PetscErrorCode MatNullSpaceView(MatNullSpace sp,PetscViewer viewer) 178 { 179 PetscErrorCode ierr; 180 PetscBool iascii; 181 182 PetscFunctionBegin; 183 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 184 if (!viewer) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)sp)); 185 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 186 PetscCheckSameComm(sp,1,viewer,2); 187 188 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 189 if (iascii) { 190 PetscViewerFormat format; 191 PetscInt i; 192 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 193 ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sp,viewer);CHKERRQ(ierr); 194 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 195 ierr = PetscViewerASCIIPrintf(viewer,"Contains %D vector%s%s\n",sp->n,sp->n==1 ? "" : "s",sp->has_cnst ? " and the constant" : "");CHKERRQ(ierr); 196 if (sp->remove) {ierr = PetscViewerASCIIPrintf(viewer,"Has user-provided removal function\n");CHKERRQ(ierr);} 197 if (!(format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) { 198 for (i=0; i<sp->n; i++) { 199 ierr = VecView(sp->vecs[i],viewer);CHKERRQ(ierr); 200 } 201 } 202 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 203 } 204 PetscFunctionReturn(0); 205 } 206 207 #undef __FUNCT__ 208 #define __FUNCT__ "MatNullSpaceCreate" 209 /*@ 210 MatNullSpaceCreate - Creates a data structure used to project vectors 211 out of null spaces. 212 213 Collective on MPI_Comm 214 215 Input Parameters: 216 + comm - the MPI communicator associated with the object 217 . has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE 218 . n - number of vectors (excluding constant vector) in null space 219 - vecs - the vectors that span the null space (excluding the constant vector); 220 these vectors must be orthonormal. These vectors are NOT copied, so do not change them 221 after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count 222 for them by one). 223 224 Output Parameter: 225 . SP - the null space context 226 227 Level: advanced 228 229 Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs. 230 231 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 232 need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction(). 233 234 Users manual sections: 235 . sec_singular 236 237 .keywords: PC, null space, create 238 239 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), KSPSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction() 240 @*/ 241 PetscErrorCode MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP) 242 { 243 MatNullSpace sp; 244 PetscErrorCode ierr; 245 PetscInt i; 246 247 PetscFunctionBegin; 248 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n); 249 if (n) PetscValidPointer(vecs,4); 250 for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_CLASSID,4); 251 PetscValidPointer(SP,5); 252 253 *SP = NULL; 254 ierr = MatInitializePackage();CHKERRQ(ierr); 255 256 ierr = PetscHeaderCreate(sp,_p_MatNullSpace,int,MAT_NULLSPACE_CLASSID,"MatNullSpace","Null space","Mat",comm,MatNullSpaceDestroy,MatNullSpaceView);CHKERRQ(ierr); 257 258 sp->has_cnst = has_cnst; 259 sp->n = n; 260 sp->vecs = 0; 261 sp->alpha = 0; 262 sp->remove = 0; 263 sp->rmctx = 0; 264 265 if (n) { 266 ierr = PetscMalloc1(n,&sp->vecs);CHKERRQ(ierr); 267 ierr = PetscMalloc1(n,&sp->alpha);CHKERRQ(ierr); 268 ierr = PetscLogObjectMemory((PetscObject)sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 269 for (i=0; i<n; i++) { 270 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 271 sp->vecs[i] = vecs[i]; 272 } 273 } 274 275 *SP = sp; 276 PetscFunctionReturn(0); 277 } 278 279 #undef __FUNCT__ 280 #define __FUNCT__ "MatNullSpaceDestroy" 281 /*@ 282 MatNullSpaceDestroy - Destroys a data structure used to project vectors 283 out of null spaces. 284 285 Collective on MatNullSpace 286 287 Input Parameter: 288 . sp - the null space context to be destroyed 289 290 Level: advanced 291 292 .keywords: PC, null space, destroy 293 294 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 295 @*/ 296 PetscErrorCode MatNullSpaceDestroy(MatNullSpace *sp) 297 { 298 PetscErrorCode ierr; 299 300 PetscFunctionBegin; 301 if (!*sp) PetscFunctionReturn(0); 302 PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1); 303 if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} 304 305 ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr); 306 ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr); 307 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 308 PetscFunctionReturn(0); 309 } 310 311 #undef __FUNCT__ 312 #define __FUNCT__ "MatNullSpaceRemove" 313 /*@C 314 MatNullSpaceRemove - Removes all the components of a null space from a vector. 315 316 Collective on MatNullSpace 317 318 Input Parameters: 319 + sp - the null space context 320 - vec - the vector from which the null space is to be removed 321 322 Level: advanced 323 324 .keywords: PC, null space, remove 325 326 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 327 @*/ 328 PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec) 329 { 330 PetscScalar sum; 331 PetscInt i,N; 332 PetscErrorCode ierr; 333 334 PetscFunctionBegin; 335 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 336 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 337 338 if (sp->has_cnst) { 339 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 340 if (N > 0) { 341 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 342 sum = sum/((PetscScalar)(-1.0*N)); 343 ierr = VecShift(vec,sum);CHKERRQ(ierr); 344 } 345 } 346 347 if (sp->n) { 348 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 349 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 350 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 351 } 352 353 if (sp->remove) { 354 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 355 } 356 PetscFunctionReturn(0); 357 } 358 359 #undef __FUNCT__ 360 #define __FUNCT__ "MatNullSpaceTest" 361 /*@ 362 MatNullSpaceTest - Tests if the claimed null space is really a 363 null space of a matrix 364 365 Collective on MatNullSpace 366 367 Input Parameters: 368 + sp - the null space context 369 - mat - the matrix 370 371 Output Parameters: 372 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 373 374 Level: advanced 375 376 .keywords: PC, null space, remove 377 378 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 379 @*/ 380 PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 381 { 382 PetscScalar sum; 383 PetscReal nrm; 384 PetscInt j,n,N; 385 PetscErrorCode ierr; 386 Vec l,r; 387 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 388 PetscViewer viewer; 389 390 PetscFunctionBegin; 391 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 392 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 393 n = sp->n; 394 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view",&flg1,NULL);CHKERRQ(ierr); 395 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view_draw",&flg2,NULL);CHKERRQ(ierr); 396 397 if (n) { 398 ierr = VecDuplicate(sp->vecs[0],&l);CHKERRQ(ierr); 399 } else { 400 ierr = MatGetVecs(mat,&l,NULL);CHKERRQ(ierr); 401 } 402 403 ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);CHKERRQ(ierr); 404 if (sp->has_cnst) { 405 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 406 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 407 sum = 1.0/N; 408 ierr = VecSet(l,sum);CHKERRQ(ierr); 409 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 410 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 411 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 412 if (flg1) { 413 if (consistent) { 414 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are likely null vector");CHKERRQ(ierr); 415 } else { 416 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are unlikely null vector ");CHKERRQ(ierr); 417 } 418 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * 1/N || = %g\n",(double)nrm);CHKERRQ(ierr); 419 } 420 if (!consistent && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 421 if (!consistent && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 422 ierr = VecDestroy(&r);CHKERRQ(ierr); 423 } 424 425 for (j=0; j<n; j++) { 426 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 427 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 428 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 429 if (flg1) { 430 if (consistent) { 431 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D is likely null vector",j);CHKERRQ(ierr); 432 } else { 433 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 434 consistent = PETSC_FALSE; 435 } 436 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * v[%D] || = %g\n",j,(double)nrm);CHKERRQ(ierr); 437 } 438 if (!consistent && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 439 if (!consistent && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 440 } 441 442 if (sp->remove) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 443 ierr = VecDestroy(&l);CHKERRQ(ierr); 444 if (isNull) *isNull = consistent; 445 PetscFunctionReturn(0); 446 } 447 448