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