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