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) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)sp)); 190 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 191 PetscCheckSameComm(sp,1,viewer,2); 192 193 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 194 if (iascii) { 195 PetscViewerFormat format; 196 PetscInt i; 197 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 198 ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sp,viewer);CHKERRQ(ierr); 199 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 200 ierr = PetscViewerASCIIPrintf(viewer,"Contains %D vector%s%s\n",sp->n,sp->n==1 ? "" : "s",sp->has_cnst ? " and the constant" : "");CHKERRQ(ierr); 201 if (sp->remove) {ierr = PetscViewerASCIIPrintf(viewer,"Has user-provided removal function\n");CHKERRQ(ierr);} 202 if (!(format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) { 203 for (i=0; i<sp->n; i++) { 204 ierr = VecView(sp->vecs[i],viewer);CHKERRQ(ierr); 205 } 206 } 207 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 208 } 209 PetscFunctionReturn(0); 210 } 211 212 #undef __FUNCT__ 213 #define __FUNCT__ "MatNullSpaceCreate" 214 /*@ 215 MatNullSpaceCreate - Creates a data structure used to project vectors 216 out of null spaces. 217 218 Collective on MPI_Comm 219 220 Input Parameters: 221 + comm - the MPI communicator associated with the object 222 . has_cnst - PETSC_TRUE if the null space contains the constant vector; otherwise PETSC_FALSE 223 . n - number of vectors (excluding constant vector) in null space 224 - vecs - the vectors that span the null space (excluding the constant vector); 225 these vectors must be orthonormal. These vectors are NOT copied, so do not change them 226 after this call. You should free the array that you pass in and destroy the vectors (this will reduce the reference count 227 for them by one). 228 229 Output Parameter: 230 . SP - the null space context 231 232 Level: advanced 233 234 Notes: See MatNullSpaceSetFunction() as an alternative way of providing the null space information instead of setting vecs. 235 236 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 237 need to pass in a function that eliminates the constant function into MatNullSpaceSetFunction(). 238 239 Users manual sections: 240 . sec_singular 241 242 .keywords: PC, null space, create 243 244 .seealso: MatNullSpaceDestroy(), MatNullSpaceRemove(), MatSetNullSpace(), MatNullSpace, MatNullSpaceSetFunction() 245 @*/ 246 PetscErrorCode MatNullSpaceCreate(MPI_Comm comm,PetscBool has_cnst,PetscInt n,const Vec vecs[],MatNullSpace *SP) 247 { 248 MatNullSpace sp; 249 PetscErrorCode ierr; 250 PetscInt i; 251 252 PetscFunctionBegin; 253 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of vectors (given %D) cannot be negative",n); 254 if (n) PetscValidPointer(vecs,4); 255 for (i=0; i<n; i++) PetscValidHeaderSpecific(vecs[i],VEC_CLASSID,4); 256 PetscValidPointer(SP,5); 257 258 *SP = NULL; 259 ierr = MatInitializePackage();CHKERRQ(ierr); 260 261 ierr = PetscHeaderCreate(sp,MAT_NULLSPACE_CLASSID,"MatNullSpace","Null space","Mat",comm,MatNullSpaceDestroy,MatNullSpaceView);CHKERRQ(ierr); 262 263 sp->has_cnst = has_cnst; 264 sp->n = n; 265 sp->vecs = 0; 266 sp->alpha = 0; 267 sp->remove = 0; 268 sp->rmctx = 0; 269 270 if (n) { 271 ierr = PetscMalloc1(n,&sp->vecs);CHKERRQ(ierr); 272 ierr = PetscMalloc1(n,&sp->alpha);CHKERRQ(ierr); 273 ierr = PetscLogObjectMemory((PetscObject)sp,n*(sizeof(Vec)+sizeof(PetscScalar)));CHKERRQ(ierr); 274 for (i=0; i<n; i++) { 275 ierr = PetscObjectReference((PetscObject)vecs[i]);CHKERRQ(ierr); 276 sp->vecs[i] = vecs[i]; 277 } 278 } 279 280 *SP = sp; 281 PetscFunctionReturn(0); 282 } 283 284 #undef __FUNCT__ 285 #define __FUNCT__ "MatNullSpaceDestroy" 286 /*@ 287 MatNullSpaceDestroy - Destroys a data structure used to project vectors 288 out of null spaces. 289 290 Collective on MatNullSpace 291 292 Input Parameter: 293 . sp - the null space context to be destroyed 294 295 Level: advanced 296 297 .keywords: PC, null space, destroy 298 299 .seealso: MatNullSpaceCreate(), MatNullSpaceRemove(), MatNullSpaceSetFunction() 300 @*/ 301 PetscErrorCode MatNullSpaceDestroy(MatNullSpace *sp) 302 { 303 PetscErrorCode ierr; 304 305 PetscFunctionBegin; 306 if (!*sp) PetscFunctionReturn(0); 307 PetscValidHeaderSpecific((*sp),MAT_NULLSPACE_CLASSID,1); 308 if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} 309 310 ierr = VecDestroyVecs((*sp)->n,&(*sp)->vecs);CHKERRQ(ierr); 311 ierr = PetscFree((*sp)->alpha);CHKERRQ(ierr); 312 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 313 PetscFunctionReturn(0); 314 } 315 316 #undef __FUNCT__ 317 #define __FUNCT__ "MatNullSpaceRemove" 318 /*@C 319 MatNullSpaceRemove - Removes all the components of a null space from a vector. 320 321 Collective on MatNullSpace 322 323 Input Parameters: 324 + sp - the null space context 325 - vec - the vector from which the null space is to be removed 326 327 Level: advanced 328 329 .keywords: PC, null space, remove 330 331 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 332 @*/ 333 PetscErrorCode MatNullSpaceRemove(MatNullSpace sp,Vec vec) 334 { 335 PetscScalar sum; 336 PetscInt i,N; 337 PetscErrorCode ierr; 338 339 PetscFunctionBegin; 340 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 341 PetscValidHeaderSpecific(vec,VEC_CLASSID,2); 342 343 if (sp->has_cnst) { 344 ierr = VecGetSize(vec,&N);CHKERRQ(ierr); 345 if (N > 0) { 346 ierr = VecSum(vec,&sum);CHKERRQ(ierr); 347 sum = sum/((PetscScalar)(-1.0*N)); 348 ierr = VecShift(vec,sum);CHKERRQ(ierr); 349 } 350 } 351 352 if (sp->n) { 353 ierr = VecMDot(vec,sp->n,sp->vecs,sp->alpha);CHKERRQ(ierr); 354 for (i=0; i<sp->n; i++) sp->alpha[i] = -sp->alpha[i]; 355 ierr = VecMAXPY(vec,sp->n,sp->alpha,sp->vecs);CHKERRQ(ierr); 356 } 357 358 if (sp->remove) { 359 ierr = (*sp->remove)(sp,vec,sp->rmctx);CHKERRQ(ierr); 360 } 361 PetscFunctionReturn(0); 362 } 363 364 #undef __FUNCT__ 365 #define __FUNCT__ "MatNullSpaceTest" 366 /*@ 367 MatNullSpaceTest - Tests if the claimed null space is really a 368 null space of a matrix 369 370 Collective on MatNullSpace 371 372 Input Parameters: 373 + sp - the null space context 374 - mat - the matrix 375 376 Output Parameters: 377 . isNull - PETSC_TRUE if the nullspace is valid for this matrix 378 379 Level: advanced 380 381 .keywords: PC, null space, remove 382 383 .seealso: MatNullSpaceCreate(), MatNullSpaceDestroy(), MatNullSpaceSetFunction() 384 @*/ 385 PetscErrorCode MatNullSpaceTest(MatNullSpace sp,Mat mat,PetscBool *isNull) 386 { 387 PetscScalar sum; 388 PetscReal nrm; 389 PetscInt j,n,N; 390 PetscErrorCode ierr; 391 Vec l,r; 392 PetscBool flg1 = PETSC_FALSE,flg2 = PETSC_FALSE,consistent = PETSC_TRUE; 393 PetscViewer viewer; 394 395 PetscFunctionBegin; 396 PetscValidHeaderSpecific(sp,MAT_NULLSPACE_CLASSID,1); 397 PetscValidHeaderSpecific(mat,MAT_CLASSID,2); 398 n = sp->n; 399 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view",&flg1,NULL);CHKERRQ(ierr); 400 ierr = PetscOptionsGetBool(NULL,"-mat_null_space_test_view_draw",&flg2,NULL);CHKERRQ(ierr); 401 402 if (n) { 403 ierr = VecDuplicate(sp->vecs[0],&l);CHKERRQ(ierr); 404 } else { 405 ierr = MatCreateVecs(mat,&l,NULL);CHKERRQ(ierr); 406 } 407 408 ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp),&viewer);CHKERRQ(ierr); 409 if (sp->has_cnst) { 410 ierr = VecDuplicate(l,&r);CHKERRQ(ierr); 411 ierr = VecGetSize(l,&N);CHKERRQ(ierr); 412 sum = 1.0/N; 413 ierr = VecSet(l,sum);CHKERRQ(ierr); 414 ierr = MatMult(mat,l,r);CHKERRQ(ierr); 415 ierr = VecNorm(r,NORM_2,&nrm);CHKERRQ(ierr); 416 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 417 if (flg1) { 418 if (consistent) { 419 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are likely null vector");CHKERRQ(ierr); 420 } else { 421 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Constants are unlikely null vector ");CHKERRQ(ierr); 422 } 423 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * 1/N || = %g\n",(double)nrm);CHKERRQ(ierr); 424 } 425 if (!consistent && flg1) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 426 if (!consistent && flg2) {ierr = VecView(r,viewer);CHKERRQ(ierr);} 427 ierr = VecDestroy(&r);CHKERRQ(ierr); 428 } 429 430 for (j=0; j<n; j++) { 431 ierr = (*mat->ops->mult)(mat,sp->vecs[j],l);CHKERRQ(ierr); 432 ierr = VecNorm(l,NORM_2,&nrm);CHKERRQ(ierr); 433 if (nrm >= 1.e-7) consistent = PETSC_FALSE; 434 if (flg1) { 435 if (consistent) { 436 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D is likely null vector",j);CHKERRQ(ierr); 437 } else { 438 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"Null vector %D unlikely null vector ",j);CHKERRQ(ierr); 439 consistent = PETSC_FALSE; 440 } 441 ierr = PetscPrintf(PetscObjectComm((PetscObject)sp),"|| A * v[%D] || = %g\n",j,(double)nrm);CHKERRQ(ierr); 442 } 443 if (!consistent && flg1) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 444 if (!consistent && flg2) {ierr = VecView(l,viewer);CHKERRQ(ierr);} 445 } 446 447 if (sp->remove) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot test a null space provided as a function with MatNullSpaceSetFunction()"); 448 ierr = VecDestroy(&l);CHKERRQ(ierr); 449 if (isNull) *isNull = consistent; 450 PetscFunctionReturn(0); 451 } 452 453