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