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