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 260 *SP = NULL; 261 ierr = MatInitializePackage();CHKERRQ(ierr); 262 263 ierr = PetscHeaderCreate(sp,MAT_NULLSPACE_CLASSID,"MatNullSpace","Null space","Mat",comm,MatNullSpaceDestroy,MatNullSpaceView);CHKERRQ(ierr); 264 265 sp->has_cnst = has_cnst; 266 sp->n = n; 267 sp->vecs = 0; 268 sp->alpha = 0; 269 sp->remove = 0; 270 sp->rmctx = 0; 271 272 if (n) { 273 ierr = PetscMalloc1(n,&sp->vecs);CHKERRQ(ierr); 274 ierr = PetscMalloc1(n,&sp->alpha);CHKERRQ(ierr); 275 ierr = PetscLogObjectMemory((PetscObject)sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 276 for (i=0; i<n; i++) { 277 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 278 sp->vecs[i] = vecs[i]; 279 } 280 } 281 282 *SP = sp; 283 PetscFunctionReturn(0); 284 } 285 286 #undef __FUNCT__ 287 #define __FUNCT__ "MatNullSpaceDestroy" 288 /*@ 289 MatNullSpaceDestroy - Destroys a data structure used to project vectors 290 out of null spaces. 291 292 Collective on MatNullSpace 293 294 Input Parameter: 295 . sp - the null space context to be destroyed 296 297 Level: advanced 298 299 .keywords: PC, null space, destroy 300 301 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 302 @*/ 303 PetscErrorCode MatNullSpaceDestroy(MatNullSpace *sp) 304 { 305 PetscErrorCode ierr; 306 307 PetscFunctionBegin; 308 if (!*sp) PetscFunctionReturn(0); 309 PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1); 310 if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} 311 312 ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr); 313 ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr); 314 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 315 PetscFunctionReturn(0); 316 } 317 318 #undef __FUNCT__ 319 #define __FUNCT__ "MatNullSpaceRemove" 320 /*@C 321 MatNullSpaceRemove - Removes all the components of a null space from a vector. 322 323 Collective on MatNullSpace 324 325 Input Parameters: 326 + sp - the null space context 327 - vec - the vector from which the null space is to be removed 328 329 Level: advanced 330 331 .keywords: PC, null space, remove 332 333 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 334 @*/ 335 PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec) 336 { 337 PetscScalar sum; 338 PetscInt i,N; 339 PetscErrorCode ierr; 340 341 PetscFunctionBegin; 342 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 343 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 344 345 if (sp->has_cnst) { 346 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 347 if (N > 0) { 348 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 349 sum = sum/((PetscScalar)(-1.0*N)); 350 ierr = VecShift(vec,sum);CHKERRQ(ierr); 351 } 352 } 353 354 if (sp->n) { 355 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 356 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 357 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 358 } 359 360 if (sp->remove) { 361 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 362 } 363 PetscFunctionReturn(0); 364 } 365 366 #undef __FUNCT__ 367 #define __FUNCT__ "MatNullSpaceTest" 368 /*@ 369 MatNullSpaceTest - Tests if the claimed null space is really a 370 null space of a matrix 371 372 Collective on MatNullSpace 373 374 Input Parameters: 375 + sp - the null space context 376 - mat - the matrix 377 378 Output Parameters: 379 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 380 381 Level: advanced 382 383 .keywords: PC, null space, remove 384 385 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 386 @*/ 387 PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 388 { 389 PetscScalar sum; 390 PetscReal nrm; 391 PetscInt j,n,N; 392 PetscErrorCode ierr; 393 Vec l,r; 394 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 395 PetscViewer viewer; 396 397 PetscFunctionBegin; 398 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 399 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 400 n = sp->n; 401 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view",&flg1,NULL);CHKERRQ(ierr); 402 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view_draw",&flg2,NULL);CHKERRQ(ierr); 403 404 if (n) { 405 ierr = VecDuplicate(sp->vecs[0],&l);CHKERRQ(ierr); 406 } else { 407 ierr = MatCreateVecs(mat,&l,NULL);CHKERRQ(ierr); 408 } 409 410 ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);CHKERRQ(ierr); 411 if (sp->has_cnst) { 412 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 413 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 414 sum = 1.0/N; 415 ierr = VecSet(l,sum);CHKERRQ(ierr); 416 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 417 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 418 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 419 if (flg1) { 420 if (consistent) { 421 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are likely null vector");CHKERRQ(ierr); 422 } else { 423 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are unlikely null vector ");CHKERRQ(ierr); 424 } 425 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * 1/N || = %g\n",(double)nrm);CHKERRQ(ierr); 426 } 427 if (!consistent && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 428 if (!consistent && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 429 ierr = VecDestroy(&r);CHKERRQ(ierr); 430 } 431 432 for (j=0; j<n; j++) { 433 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 434 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 435 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 436 if (flg1) { 437 if (consistent) { 438 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D is likely null vector",j);CHKERRQ(ierr); 439 } else { 440 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 441 consistent = PETSC_FALSE; 442 } 443 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * v[%D] || = %g\n",j,(double)nrm);CHKERRQ(ierr); 444 } 445 if (!consistent && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 446 if (!consistent && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 447 } 448 449 if (sp->remove) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 450 ierr = VecDestroy(&l);CHKERRQ(ierr); 451 if (isNull) *isNull = consistent; 452 PetscFunctionReturn(0); 453 } 454 455