1 2 /* 3 3/99 Modified by Stephen Barnard to support SPAI version 3.0 4 */ 5 6 /* 7 Provides an interface to the SPAI Sparse Approximate Inverse Preconditioner 8 Code written by Stephen Barnard. 9 10 Note: there is some BAD memory bleeding below! 11 12 This code needs work 13 14 1) get rid of all memory bleeding 15 2) fix PETSc/interface so that it gets if the matrix is symmetric from the matrix 16 rather than having the sp flag for PC_SPAI 17 3) fix to set the block size based on the matrix block size 18 19 */ 20 #define PETSC_SKIP_COMPLEX /* since spai uses I which conflicts with some complex implementations */ 21 22 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 23 #include <../src/ksp/pc/impls/spai/petscspai.h> 24 25 /* 26 These are the SPAI include files 27 */ 28 EXTERN_C_BEGIN 29 #define SPAI_USE_MPI /* required for setting SPAI_Comm correctly in basics.h */ 30 #include <spai.h> 31 #include <matrix.h> 32 EXTERN_C_END 33 34 extern PetscErrorCode ConvertMatToMatrix(MPI_Comm,Mat,Mat,matrix**); 35 extern PetscErrorCode ConvertMatrixToMat(MPI_Comm,matrix*,Mat*); 36 extern PetscErrorCode ConvertVectorToVec(MPI_Comm,vector*,Vec*); 37 extern PetscErrorCode MM_to_PETSC(char*,char*,char*); 38 39 typedef struct { 40 41 matrix *B; /* matrix in SPAI format */ 42 matrix *BT; /* transpose of matrix in SPAI format */ 43 matrix *M; /* the approximate inverse in SPAI format */ 44 45 Mat PM; /* the approximate inverse PETSc format */ 46 47 double epsilon; /* tolerance */ 48 int nbsteps; /* max number of "improvement" steps per line */ 49 int max; /* max dimensions of is_I, q, etc. */ 50 int maxnew; /* max number of new entries per step */ 51 int block_size; /* constant block size */ 52 int cache_size; /* one of (1,2,3,4,5,6) indicting size of cache */ 53 int verbose; /* SPAI prints timing and statistics */ 54 55 int sp; /* symmetric nonzero pattern */ 56 MPI_Comm comm_spai; /* communicator to be used with spai */ 57 } PC_SPAI; 58 59 /**********************************************************************/ 60 61 static PetscErrorCode PCSetUp_SPAI(PC pc) 62 { 63 PC_SPAI *ispai = (PC_SPAI*)pc->data; 64 Mat AT; 65 66 PetscFunctionBegin; 67 init_SPAI(); 68 69 if (ispai->sp) { 70 PetscCall(ConvertMatToMatrix(ispai->comm_spai,pc->pmat,pc->pmat,&ispai->B)); 71 } else { 72 /* Use the transpose to get the column nonzero structure. */ 73 PetscCall(MatTranspose(pc->pmat,MAT_INITIAL_MATRIX,&AT)); 74 PetscCall(ConvertMatToMatrix(ispai->comm_spai,pc->pmat,AT,&ispai->B)); 75 PetscCall(MatDestroy(&AT)); 76 } 77 78 /* Destroy the transpose */ 79 /* Don't know how to do it. PETSc developers? */ 80 81 /* construct SPAI preconditioner */ 82 /* FILE *messages */ /* file for warning messages */ 83 /* double epsilon */ /* tolerance */ 84 /* int nbsteps */ /* max number of "improvement" steps per line */ 85 /* int max */ /* max dimensions of is_I, q, etc. */ 86 /* int maxnew */ /* max number of new entries per step */ 87 /* int block_size */ /* block_size == 1 specifies scalar elments 88 block_size == n specifies nxn constant-block elements 89 block_size == 0 specifies variable-block elements */ 90 /* int cache_size */ /* one of (1,2,3,4,5,6) indicting size of cache. cache_size == 0 indicates no caching */ 91 /* int verbose */ /* verbose == 0 specifies that SPAI is silent 92 verbose == 1 prints timing and matrix statistics */ 93 94 PetscCall(bspai(ispai->B,&ispai->M, 95 stdout, 96 ispai->epsilon, 97 ispai->nbsteps, 98 ispai->max, 99 ispai->maxnew, 100 ispai->block_size, 101 ispai->cache_size, 102 ispai->verbose)); 103 104 PetscCall(ConvertMatrixToMat(PetscObjectComm((PetscObject)pc),ispai->M,&ispai->PM)); 105 106 /* free the SPAI matrices */ 107 sp_free_matrix(ispai->B); 108 sp_free_matrix(ispai->M); 109 PetscFunctionReturn(0); 110 } 111 112 /**********************************************************************/ 113 114 static PetscErrorCode PCApply_SPAI(PC pc,Vec xx,Vec y) 115 { 116 PC_SPAI *ispai = (PC_SPAI*)pc->data; 117 118 PetscFunctionBegin; 119 /* Now using PETSc's multiply */ 120 PetscCall(MatMult(ispai->PM,xx,y)); 121 PetscFunctionReturn(0); 122 } 123 124 static PetscErrorCode PCMatApply_SPAI(PC pc,Mat X,Mat Y) 125 { 126 PC_SPAI *ispai = (PC_SPAI*)pc->data; 127 128 PetscFunctionBegin; 129 /* Now using PETSc's multiply */ 130 PetscCall(MatMatMult(ispai->PM,X,MAT_REUSE_MATRIX,PETSC_DEFAULT,&Y)); 131 PetscFunctionReturn(0); 132 } 133 134 /**********************************************************************/ 135 136 static PetscErrorCode PCDestroy_SPAI(PC pc) 137 { 138 PC_SPAI *ispai = (PC_SPAI*)pc->data; 139 140 PetscFunctionBegin; 141 PetscCall(MatDestroy(&ispai->PM)); 142 PetscCallMPI(MPI_Comm_free(&(ispai->comm_spai))); 143 PetscCall(PetscFree(pc->data)); 144 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetEpsilon_C",NULL)); 145 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetNBSteps_C",NULL)); 146 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetMax_C",NULL)); 147 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetMaxNew_C",NULL)); 148 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetBlockSize_C",NULL)); 149 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetCacheSize_C",NULL)); 150 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetVerbose_C",NULL)); 151 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetSp_C",NULL)); 152 PetscFunctionReturn(0); 153 } 154 155 /**********************************************************************/ 156 157 static PetscErrorCode PCView_SPAI(PC pc,PetscViewer viewer) 158 { 159 PC_SPAI *ispai = (PC_SPAI*)pc->data; 160 PetscBool iascii; 161 162 PetscFunctionBegin; 163 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 164 if (iascii) { 165 PetscCall(PetscViewerASCIIPrintf(viewer," epsilon %g\n", ispai->epsilon)); 166 PetscCall(PetscViewerASCIIPrintf(viewer," nbsteps %d\n", ispai->nbsteps)); 167 PetscCall(PetscViewerASCIIPrintf(viewer," max %d\n", ispai->max)); 168 PetscCall(PetscViewerASCIIPrintf(viewer," maxnew %d\n", ispai->maxnew)); 169 PetscCall(PetscViewerASCIIPrintf(viewer," block_size %d\n",ispai->block_size)); 170 PetscCall(PetscViewerASCIIPrintf(viewer," cache_size %d\n",ispai->cache_size)); 171 PetscCall(PetscViewerASCIIPrintf(viewer," verbose %d\n", ispai->verbose)); 172 PetscCall(PetscViewerASCIIPrintf(viewer," sp %d\n", ispai->sp)); 173 } 174 PetscFunctionReturn(0); 175 } 176 177 static PetscErrorCode PCSPAISetEpsilon_SPAI(PC pc, PetscReal epsilon1) 178 { 179 PC_SPAI *ispai = (PC_SPAI*)pc->data; 180 181 PetscFunctionBegin; 182 ispai->epsilon = (double)epsilon1; 183 PetscFunctionReturn(0); 184 } 185 186 /**********************************************************************/ 187 188 static PetscErrorCode PCSPAISetNBSteps_SPAI(PC pc,PetscInt nbsteps1) 189 { 190 PC_SPAI *ispai = (PC_SPAI*)pc->data; 191 192 PetscFunctionBegin; 193 ispai->nbsteps = (int)nbsteps1; 194 PetscFunctionReturn(0); 195 } 196 197 /**********************************************************************/ 198 199 /* added 1/7/99 g.h. */ 200 static PetscErrorCode PCSPAISetMax_SPAI(PC pc,PetscInt max1) 201 { 202 PC_SPAI *ispai = (PC_SPAI*)pc->data; 203 204 PetscFunctionBegin; 205 ispai->max = (int)max1; 206 PetscFunctionReturn(0); 207 } 208 209 /**********************************************************************/ 210 211 static PetscErrorCode PCSPAISetMaxNew_SPAI(PC pc,PetscInt maxnew1) 212 { 213 PC_SPAI *ispai = (PC_SPAI*)pc->data; 214 215 PetscFunctionBegin; 216 ispai->maxnew = (int)maxnew1; 217 PetscFunctionReturn(0); 218 } 219 220 /**********************************************************************/ 221 222 static PetscErrorCode PCSPAISetBlockSize_SPAI(PC pc,PetscInt block_size1) 223 { 224 PC_SPAI *ispai = (PC_SPAI*)pc->data; 225 226 PetscFunctionBegin; 227 ispai->block_size = (int)block_size1; 228 PetscFunctionReturn(0); 229 } 230 231 /**********************************************************************/ 232 233 static PetscErrorCode PCSPAISetCacheSize_SPAI(PC pc,PetscInt cache_size) 234 { 235 PC_SPAI *ispai = (PC_SPAI*)pc->data; 236 237 PetscFunctionBegin; 238 ispai->cache_size = (int)cache_size; 239 PetscFunctionReturn(0); 240 } 241 242 /**********************************************************************/ 243 244 static PetscErrorCode PCSPAISetVerbose_SPAI(PC pc,PetscInt verbose) 245 { 246 PC_SPAI *ispai = (PC_SPAI*)pc->data; 247 248 PetscFunctionBegin; 249 ispai->verbose = (int)verbose; 250 PetscFunctionReturn(0); 251 } 252 253 /**********************************************************************/ 254 255 static PetscErrorCode PCSPAISetSp_SPAI(PC pc,PetscInt sp) 256 { 257 PC_SPAI *ispai = (PC_SPAI*)pc->data; 258 259 PetscFunctionBegin; 260 ispai->sp = (int)sp; 261 PetscFunctionReturn(0); 262 } 263 264 /* -------------------------------------------------------------------*/ 265 266 /*@ 267 PCSPAISetEpsilon -- Set the tolerance for the SPAI preconditioner 268 269 Input Parameters: 270 + pc - the preconditioner 271 - eps - epsilon (default .4) 272 273 Notes: 274 Espilon must be between 0 and 1. It controls the 275 quality of the approximation of M to the inverse of 276 A. Higher values of epsilon lead to more work, more 277 fill, and usually better preconditioners. In many 278 cases the best choice of epsilon is the one that 279 divides the total solution time equally between the 280 preconditioner and the solver. 281 282 Level: intermediate 283 284 .seealso: `PCSPAI`, `PCSetType()` 285 @*/ 286 PetscErrorCode PCSPAISetEpsilon(PC pc,PetscReal epsilon1) 287 { 288 PetscFunctionBegin; 289 PetscTryMethod(pc,"PCSPAISetEpsilon_C",(PC,PetscReal),(pc,epsilon1)); 290 PetscFunctionReturn(0); 291 } 292 293 /**********************************************************************/ 294 295 /*@ 296 PCSPAISetNBSteps - set maximum number of improvement steps per row in 297 the SPAI preconditioner 298 299 Input Parameters: 300 + pc - the preconditioner 301 - n - number of steps (default 5) 302 303 Notes: 304 SPAI constructs to approximation to every column of 305 the exact inverse of A in a series of improvement 306 steps. The quality of the approximation is determined 307 by epsilon. If an approximation achieving an accuracy 308 of epsilon is not obtained after ns steps, SPAI simply 309 uses the best approximation constructed so far. 310 311 Level: intermediate 312 313 .seealso: `PCSPAI`, `PCSetType()`, `PCSPAISetMaxNew()` 314 @*/ 315 PetscErrorCode PCSPAISetNBSteps(PC pc,PetscInt nbsteps1) 316 { 317 PetscFunctionBegin; 318 PetscTryMethod(pc,"PCSPAISetNBSteps_C",(PC,PetscInt),(pc,nbsteps1)); 319 PetscFunctionReturn(0); 320 } 321 322 /**********************************************************************/ 323 324 /* added 1/7/99 g.h. */ 325 /*@ 326 PCSPAISetMax - set the size of various working buffers in 327 the SPAI preconditioner 328 329 Input Parameters: 330 + pc - the preconditioner 331 - n - size (default is 5000) 332 333 Level: intermediate 334 335 .seealso: `PCSPAI`, `PCSetType()` 336 @*/ 337 PetscErrorCode PCSPAISetMax(PC pc,PetscInt max1) 338 { 339 PetscFunctionBegin; 340 PetscTryMethod(pc,"PCSPAISetMax_C",(PC,PetscInt),(pc,max1)); 341 PetscFunctionReturn(0); 342 } 343 344 /**********************************************************************/ 345 346 /*@ 347 PCSPAISetMaxNew - set maximum number of new nonzero candidates per step 348 in SPAI preconditioner 349 350 Input Parameters: 351 + pc - the preconditioner 352 - n - maximum number (default 5) 353 354 Level: intermediate 355 356 .seealso: `PCSPAI`, `PCSetType()`, `PCSPAISetNBSteps()` 357 @*/ 358 PetscErrorCode PCSPAISetMaxNew(PC pc,PetscInt maxnew1) 359 { 360 PetscFunctionBegin; 361 PetscTryMethod(pc,"PCSPAISetMaxNew_C",(PC,PetscInt),(pc,maxnew1)); 362 PetscFunctionReturn(0); 363 } 364 365 /**********************************************************************/ 366 367 /*@ 368 PCSPAISetBlockSize - set the block size for the SPAI preconditioner 369 370 Input Parameters: 371 + pc - the preconditioner 372 - n - block size (default 1) 373 374 Notes: 375 A block 376 size of 1 treats A as a matrix of scalar elements. A 377 block size of s > 1 treats A as a matrix of sxs 378 blocks. A block size of 0 treats A as a matrix with 379 variable sized blocks, which are determined by 380 searching for dense square diagonal blocks in A. 381 This can be very effective for finite-element 382 matrices. 383 384 SPAI will convert A to block form, use a block 385 version of the preconditioner algorithm, and then 386 convert the result back to scalar form. 387 388 In many cases the a block-size parameter other than 1 389 can lead to very significant improvement in 390 performance. 391 392 Level: intermediate 393 394 .seealso: `PCSPAI`, `PCSetType()` 395 @*/ 396 PetscErrorCode PCSPAISetBlockSize(PC pc,PetscInt block_size1) 397 { 398 PetscFunctionBegin; 399 PetscTryMethod(pc,"PCSPAISetBlockSize_C",(PC,PetscInt),(pc,block_size1)); 400 PetscFunctionReturn(0); 401 } 402 403 /**********************************************************************/ 404 405 /*@ 406 PCSPAISetCacheSize - specify cache size in the SPAI preconditioner 407 408 Input Parameters: 409 + pc - the preconditioner 410 - n - cache size {0,1,2,3,4,5} (default 5) 411 412 Notes: 413 SPAI uses a hash table to cache messages and avoid 414 redundant communication. If suggest always using 415 5. This parameter is irrelevant in the serial 416 version. 417 418 Level: intermediate 419 420 .seealso: `PCSPAI`, `PCSetType()` 421 @*/ 422 PetscErrorCode PCSPAISetCacheSize(PC pc,PetscInt cache_size) 423 { 424 PetscFunctionBegin; 425 PetscTryMethod(pc,"PCSPAISetCacheSize_C",(PC,PetscInt),(pc,cache_size)); 426 PetscFunctionReturn(0); 427 } 428 429 /**********************************************************************/ 430 431 /*@ 432 PCSPAISetVerbose - verbosity level for the SPAI preconditioner 433 434 Input Parameters: 435 + pc - the preconditioner 436 - n - level (default 1) 437 438 Notes: 439 print parameters, timings and matrix statistics 440 441 Level: intermediate 442 443 .seealso: `PCSPAI`, `PCSetType()` 444 @*/ 445 PetscErrorCode PCSPAISetVerbose(PC pc,PetscInt verbose) 446 { 447 PetscFunctionBegin; 448 PetscTryMethod(pc,"PCSPAISetVerbose_C",(PC,PetscInt),(pc,verbose)); 449 PetscFunctionReturn(0); 450 } 451 452 /**********************************************************************/ 453 454 /*@ 455 PCSPAISetSp - specify a symmetric matrix sparsity pattern in the SPAI preconditioner 456 457 Input Parameters: 458 + pc - the preconditioner 459 - n - 0 or 1 460 461 Notes: 462 If A has a symmetric nonzero pattern use -sp 1 to 463 improve performance by eliminating some communication 464 in the parallel version. Even if A does not have a 465 symmetric nonzero pattern -sp 1 may well lead to good 466 results, but the code will not follow the published 467 SPAI algorithm exactly. 468 469 Level: intermediate 470 471 .seealso: `PCSPAI`, `PCSetType()` 472 @*/ 473 PetscErrorCode PCSPAISetSp(PC pc,PetscInt sp) 474 { 475 PetscFunctionBegin; 476 PetscTryMethod(pc,"PCSPAISetSp_C",(PC,PetscInt),(pc,sp)); 477 PetscFunctionReturn(0); 478 } 479 480 /**********************************************************************/ 481 482 /**********************************************************************/ 483 484 static PetscErrorCode PCSetFromOptions_SPAI(PetscOptionItems *PetscOptionsObject,PC pc) 485 { 486 PC_SPAI *ispai = (PC_SPAI*)pc->data; 487 int nbsteps1,max1,maxnew1,block_size1,cache_size,verbose,sp; 488 double epsilon1; 489 PetscBool flg; 490 491 PetscFunctionBegin; 492 PetscOptionsHeadBegin(PetscOptionsObject,"SPAI options"); 493 PetscCall(PetscOptionsReal("-pc_spai_epsilon","","PCSPAISetEpsilon",ispai->epsilon,&epsilon1,&flg)); 494 if (flg) PetscCall(PCSPAISetEpsilon(pc,epsilon1)); 495 PetscCall(PetscOptionsInt("-pc_spai_nbsteps","","PCSPAISetNBSteps",ispai->nbsteps,&nbsteps1,&flg)); 496 if (flg) PetscCall(PCSPAISetNBSteps(pc,nbsteps1)); 497 /* added 1/7/99 g.h. */ 498 PetscCall(PetscOptionsInt("-pc_spai_max","","PCSPAISetMax",ispai->max,&max1,&flg)); 499 if (flg) PetscCall(PCSPAISetMax(pc,max1)); 500 PetscCall(PetscOptionsInt("-pc_spai_maxnew","","PCSPAISetMaxNew",ispai->maxnew,&maxnew1,&flg)); 501 if (flg) PetscCall(PCSPAISetMaxNew(pc,maxnew1)); 502 PetscCall(PetscOptionsInt("-pc_spai_block_size","","PCSPAISetBlockSize",ispai->block_size,&block_size1,&flg)); 503 if (flg) PetscCall(PCSPAISetBlockSize(pc,block_size1)); 504 PetscCall(PetscOptionsInt("-pc_spai_cache_size","","PCSPAISetCacheSize",ispai->cache_size,&cache_size,&flg)); 505 if (flg) PetscCall(PCSPAISetCacheSize(pc,cache_size)); 506 PetscCall(PetscOptionsInt("-pc_spai_verbose","","PCSPAISetVerbose",ispai->verbose,&verbose,&flg)); 507 if (flg) PetscCall(PCSPAISetVerbose(pc,verbose)); 508 PetscCall(PetscOptionsInt("-pc_spai_sp","","PCSPAISetSp",ispai->sp,&sp,&flg)); 509 if (flg) PetscCall(PCSPAISetSp(pc,sp)); 510 PetscOptionsHeadEnd(); 511 PetscFunctionReturn(0); 512 } 513 514 /**********************************************************************/ 515 516 /*MC 517 PCSPAI - Use the Sparse Approximate Inverse method of Grote and Barnard 518 as a preconditioner (SIAM J. Sci. Comput.; vol 18, nr 3) 519 520 Options Database Keys: 521 + -pc_spai_epsilon <eps> - set tolerance 522 . -pc_spai_nbstep <n> - set nbsteps 523 . -pc_spai_max <m> - set max 524 . -pc_spai_max_new <m> - set maxnew 525 . -pc_spai_block_size <n> - set block size 526 . -pc_spai_cache_size <n> - set cache size 527 . -pc_spai_sp <m> - set sp 528 - -pc_spai_set_verbose <true,false> - verbose output 529 530 Notes: 531 This only works with AIJ matrices. 532 533 Level: beginner 534 535 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, 536 `PCSPAISetEpsilon()`, `PCSPAISetMax()`, `PCSPAISetMaxNew()`, `PCSPAISetBlockSize()`, 537 `PCSPAISetVerbose()`, `PCSPAISetSp()` 538 M*/ 539 540 PETSC_EXTERN PetscErrorCode PCCreate_SPAI(PC pc) 541 { 542 PC_SPAI *ispai; 543 544 PetscFunctionBegin; 545 PetscCall(PetscNewLog(pc,&ispai)); 546 pc->data = ispai; 547 548 pc->ops->destroy = PCDestroy_SPAI; 549 pc->ops->apply = PCApply_SPAI; 550 pc->ops->matapply = PCMatApply_SPAI; 551 pc->ops->applyrichardson = 0; 552 pc->ops->setup = PCSetUp_SPAI; 553 pc->ops->view = PCView_SPAI; 554 pc->ops->setfromoptions = PCSetFromOptions_SPAI; 555 556 ispai->epsilon = .4; 557 ispai->nbsteps = 5; 558 ispai->max = 5000; 559 ispai->maxnew = 5; 560 ispai->block_size = 1; 561 ispai->cache_size = 5; 562 ispai->verbose = 0; 563 564 ispai->sp = 1; 565 PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(ispai->comm_spai))); 566 567 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetEpsilon_C",PCSPAISetEpsilon_SPAI)); 568 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetNBSteps_C",PCSPAISetNBSteps_SPAI)); 569 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetMax_C",PCSPAISetMax_SPAI)); 570 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetMaxNew_C",PCSPAISetMaxNew_SPAI)); 571 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetBlockSize_C",PCSPAISetBlockSize_SPAI)); 572 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetCacheSize_C",PCSPAISetCacheSize_SPAI)); 573 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetVerbose_C",PCSPAISetVerbose_SPAI)); 574 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSPAISetSp_C",PCSPAISetSp_SPAI)); 575 PetscFunctionReturn(0); 576 } 577 578 /**********************************************************************/ 579 580 /* 581 Converts from a PETSc matrix to an SPAI matrix 582 */ 583 PetscErrorCode ConvertMatToMatrix(MPI_Comm comm, Mat A,Mat AT,matrix **B) 584 { 585 matrix *M; 586 int i,j,col; 587 int row_indx; 588 int len,pe,local_indx,start_indx; 589 int *mapping; 590 const int *cols; 591 const double *vals; 592 int n,mnl,nnl,nz,rstart,rend; 593 PetscMPIInt size,rank; 594 struct compressed_lines *rows; 595 596 PetscFunctionBegin; 597 PetscCallMPI(MPI_Comm_size(comm,&size)); 598 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 599 PetscCall(MatGetSize(A,&n,&n)); 600 PetscCall(MatGetLocalSize(A,&mnl,&nnl)); 601 602 /* 603 not sure why a barrier is required. commenting out 604 PetscCallMPI(MPI_Barrier(comm)); 605 */ 606 607 M = new_matrix((SPAI_Comm)comm); 608 609 M->n = n; 610 M->bs = 1; 611 M->max_block_size = 1; 612 613 M->mnls = (int*)malloc(sizeof(int)*size); 614 M->start_indices = (int*)malloc(sizeof(int)*size); 615 M->pe = (int*)malloc(sizeof(int)*n); 616 M->block_sizes = (int*)malloc(sizeof(int)*n); 617 for (i=0; i<n; i++) M->block_sizes[i] = 1; 618 619 PetscCallMPI(MPI_Allgather(&mnl,1,MPI_INT,M->mnls,1,MPI_INT,comm)); 620 621 M->start_indices[0] = 0; 622 for (i=1; i<size; i++) M->start_indices[i] = M->start_indices[i-1] + M->mnls[i-1]; 623 624 M->mnl = M->mnls[M->myid]; 625 M->my_start_index = M->start_indices[M->myid]; 626 627 for (i=0; i<size; i++) { 628 start_indx = M->start_indices[i]; 629 for (j=0; j<M->mnls[i]; j++) M->pe[start_indx+j] = i; 630 } 631 632 if (AT) { 633 M->lines = new_compressed_lines(M->mnls[rank],1); 634 } else { 635 M->lines = new_compressed_lines(M->mnls[rank],0); 636 } 637 638 rows = M->lines; 639 640 /* Determine the mapping from global indices to pointers */ 641 PetscCall(PetscMalloc1(M->n,&mapping)); 642 pe = 0; 643 local_indx = 0; 644 for (i=0; i<M->n; i++) { 645 if (local_indx >= M->mnls[pe]) { 646 pe++; 647 local_indx = 0; 648 } 649 mapping[i] = local_indx + M->start_indices[pe]; 650 local_indx++; 651 } 652 653 /*********************************************************/ 654 /************** Set up the row structure *****************/ 655 /*********************************************************/ 656 657 PetscCall(MatGetOwnershipRange(A,&rstart,&rend)); 658 for (i=rstart; i<rend; i++) { 659 row_indx = i - rstart; 660 PetscCall(MatGetRow(A,i,&nz,&cols,&vals)); 661 /* allocate buffers */ 662 rows->ptrs[row_indx] = (int*)malloc(nz*sizeof(int)); 663 rows->A[row_indx] = (double*)malloc(nz*sizeof(double)); 664 /* copy the matrix */ 665 for (j=0; j<nz; j++) { 666 col = cols[j]; 667 len = rows->len[row_indx]++; 668 669 rows->ptrs[row_indx][len] = mapping[col]; 670 rows->A[row_indx][len] = vals[j]; 671 } 672 rows->slen[row_indx] = rows->len[row_indx]; 673 674 PetscCall(MatRestoreRow(A,i,&nz,&cols,&vals)); 675 } 676 677 /************************************************************/ 678 /************** Set up the column structure *****************/ 679 /*********************************************************/ 680 681 if (AT) { 682 683 for (i=rstart; i<rend; i++) { 684 row_indx = i - rstart; 685 PetscCall(MatGetRow(AT,i,&nz,&cols,&vals)); 686 /* allocate buffers */ 687 rows->rptrs[row_indx] = (int*)malloc(nz*sizeof(int)); 688 /* copy the matrix (i.e., the structure) */ 689 for (j=0; j<nz; j++) { 690 col = cols[j]; 691 len = rows->rlen[row_indx]++; 692 693 rows->rptrs[row_indx][len] = mapping[col]; 694 } 695 PetscCall(MatRestoreRow(AT,i,&nz,&cols,&vals)); 696 } 697 } 698 699 PetscCall(PetscFree(mapping)); 700 701 order_pointers(M); 702 M->maxnz = calc_maxnz(M); 703 *B = M; 704 PetscFunctionReturn(0); 705 } 706 707 /**********************************************************************/ 708 709 /* 710 Converts from an SPAI matrix B to a PETSc matrix PB. 711 This assumes that the SPAI matrix B is stored in 712 COMPRESSED-ROW format. 713 */ 714 PetscErrorCode ConvertMatrixToMat(MPI_Comm comm,matrix *B,Mat *PB) 715 { 716 PetscMPIInt size,rank; 717 int m,n,M,N; 718 int d_nz,o_nz; 719 int *d_nnz,*o_nnz; 720 int i,k,global_row,global_col,first_diag_col,last_diag_col; 721 PetscScalar val; 722 723 PetscFunctionBegin; 724 PetscCallMPI(MPI_Comm_size(comm,&size)); 725 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 726 727 m = n = B->mnls[rank]; 728 d_nz = o_nz = 0; 729 730 /* Determine preallocation for MatCreateAIJ */ 731 PetscCall(PetscMalloc1(m,&d_nnz)); 732 PetscCall(PetscMalloc1(m,&o_nnz)); 733 for (i=0; i<m; i++) d_nnz[i] = o_nnz[i] = 0; 734 first_diag_col = B->start_indices[rank]; 735 last_diag_col = first_diag_col + B->mnls[rank]; 736 for (i=0; i<B->mnls[rank]; i++) { 737 for (k=0; k<B->lines->len[i]; k++) { 738 global_col = B->lines->ptrs[i][k]; 739 if ((global_col >= first_diag_col) && (global_col < last_diag_col)) d_nnz[i]++; 740 else o_nnz[i]++; 741 } 742 } 743 744 M = N = B->n; 745 /* Here we only know how to create AIJ format */ 746 PetscCall(MatCreate(comm,PB)); 747 PetscCall(MatSetSizes(*PB,m,n,M,N)); 748 PetscCall(MatSetType(*PB,MATAIJ)); 749 PetscCall(MatSeqAIJSetPreallocation(*PB,d_nz,d_nnz)); 750 PetscCall(MatMPIAIJSetPreallocation(*PB,d_nz,d_nnz,o_nz,o_nnz)); 751 752 for (i=0; i<B->mnls[rank]; i++) { 753 global_row = B->start_indices[rank]+i; 754 for (k=0; k<B->lines->len[i]; k++) { 755 global_col = B->lines->ptrs[i][k]; 756 757 val = B->lines->A[i][k]; 758 PetscCall(MatSetValues(*PB,1,&global_row,1,&global_col,&val,ADD_VALUES)); 759 } 760 } 761 762 PetscCall(PetscFree(d_nnz)); 763 PetscCall(PetscFree(o_nnz)); 764 765 PetscCall(MatAssemblyBegin(*PB,MAT_FINAL_ASSEMBLY)); 766 PetscCall(MatAssemblyEnd(*PB,MAT_FINAL_ASSEMBLY)); 767 PetscFunctionReturn(0); 768 } 769 770 /**********************************************************************/ 771 772 /* 773 Converts from an SPAI vector v to a PETSc vec Pv. 774 */ 775 PetscErrorCode ConvertVectorToVec(MPI_Comm comm,vector *v,Vec *Pv) 776 { 777 PetscMPIInt size,rank; 778 int m,M,i,*mnls,*start_indices,*global_indices; 779 780 PetscFunctionBegin; 781 PetscCallMPI(MPI_Comm_size(comm,&size)); 782 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 783 784 m = v->mnl; 785 M = v->n; 786 787 PetscCall(VecCreateMPI(comm,m,M,Pv)); 788 789 PetscCall(PetscMalloc1(size,&mnls)); 790 PetscCallMPI(MPI_Allgather(&v->mnl,1,MPI_INT,mnls,1,MPI_INT,comm)); 791 792 PetscCall(PetscMalloc1(size,&start_indices)); 793 794 start_indices[0] = 0; 795 for (i=1; i<size; i++) start_indices[i] = start_indices[i-1] +mnls[i-1]; 796 797 PetscCall(PetscMalloc1(v->mnl,&global_indices)); 798 for (i=0; i<v->mnl; i++) global_indices[i] = start_indices[rank] + i; 799 800 PetscCall(PetscFree(mnls)); 801 PetscCall(PetscFree(start_indices)); 802 803 PetscCall(VecSetValues(*Pv,v->mnl,global_indices,v->v,INSERT_VALUES)); 804 PetscCall(VecAssemblyBegin(*Pv)); 805 PetscCall(VecAssemblyEnd(*Pv)); 806 807 PetscCall(PetscFree(global_indices)); 808 PetscFunctionReturn(0); 809 } 810