xref: /petsc/src/ksp/pc/impls/spai/ispai.c (revision 562efe2ef922487c6beae96ba39e19afd4eefbe6)
101a81e61SBarry Smith /*
201a81e61SBarry Smith    3/99 Modified by Stephen Barnard to support SPAI version 3.0
301a81e61SBarry Smith */
401a81e61SBarry Smith 
501a81e61SBarry Smith /*
601a81e61SBarry Smith       Provides an interface to the SPAI Sparse Approximate Inverse Preconditioner
701a81e61SBarry Smith    Code written by Stephen Barnard.
801a81e61SBarry Smith 
901a81e61SBarry Smith       Note: there is some BAD memory bleeding below!
1001a81e61SBarry Smith 
1101a81e61SBarry Smith       This code needs work
1201a81e61SBarry Smith 
1301a81e61SBarry Smith    1) get rid of all memory bleeding
1401a81e61SBarry Smith    2) fix PETSc/interface so that it gets if the matrix is symmetric from the matrix
1501a81e61SBarry Smith       rather than having the sp flag for PC_SPAI
162a4967abSBarry Smith    3) fix to set the block size based on the matrix block size
1701a81e61SBarry Smith 
1801a81e61SBarry Smith */
1974c01ffaSSatish Balay #if !defined(PETSC_SKIP_COMPLEX)
20762360ffSBarry Smith   #define PETSC_SKIP_COMPLEX /* since spai uses I which conflicts with some complex implementations */
2174c01ffaSSatish Balay #endif
2201a81e61SBarry Smith 
23af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
241c7d2463SJed Brown #include <../src/ksp/pc/impls/spai/petscspai.h>
2501a81e61SBarry Smith 
2601a81e61SBarry Smith /*
2701a81e61SBarry Smith     These are the SPAI include files
2801a81e61SBarry Smith */
2901a81e61SBarry Smith EXTERN_C_BEGIN
30b1bda85cSSatish Balay #define SPAI_USE_MPI /* required for setting SPAI_Comm correctly in basics.h */
31c6db04a5SJed Brown #include <spai.h>
32c6db04a5SJed Brown #include <matrix.h>
3301a81e61SBarry Smith EXTERN_C_END
3401a81e61SBarry Smith 
35ba38deedSJacob Faibussowitsch static PetscErrorCode ConvertMatToMatrix(MPI_Comm, Mat, Mat, matrix **);
36ba38deedSJacob Faibussowitsch static PetscErrorCode ConvertMatrixToMat(MPI_Comm, matrix *, Mat *);
3701a81e61SBarry Smith 
3801a81e61SBarry Smith typedef struct {
3901a81e61SBarry Smith   matrix *B;  /* matrix in SPAI format */
4001a81e61SBarry Smith   matrix *BT; /* transpose of matrix in SPAI format */
4101a81e61SBarry Smith   matrix *M;  /* the approximate inverse in SPAI format */
4201a81e61SBarry Smith 
4301a81e61SBarry Smith   Mat PM; /* the approximate inverse PETSc format */
4401a81e61SBarry Smith 
4501a81e61SBarry Smith   double epsilon;    /* tolerance */
4601a81e61SBarry Smith   int    nbsteps;    /* max number of "improvement" steps per line */
4701a81e61SBarry Smith   int    max;        /* max dimensions of is_I, q, etc. */
4801a81e61SBarry Smith   int    maxnew;     /* max number of new entries per step */
4901a81e61SBarry Smith   int    block_size; /* constant block size */
5001a81e61SBarry Smith   int    cache_size; /* one of (1,2,3,4,5,6) indicting size of cache */
5101a81e61SBarry Smith   int    verbose;    /* SPAI prints timing and statistics */
5201a81e61SBarry Smith 
5301a81e61SBarry Smith   int      sp;        /* symmetric nonzero pattern */
5401a81e61SBarry Smith   MPI_Comm comm_spai; /* communicator to be used with spai */
5501a81e61SBarry Smith } PC_SPAI;
5601a81e61SBarry Smith 
57d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_SPAI(PC pc)
58d71ae5a4SJacob Faibussowitsch {
5901a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
6001a81e61SBarry Smith   Mat      AT;
6101a81e61SBarry Smith 
6201a81e61SBarry Smith   PetscFunctionBegin;
6301a81e61SBarry Smith   init_SPAI();
6401a81e61SBarry Smith 
6501a81e61SBarry Smith   if (ispai->sp) {
669566063dSJacob Faibussowitsch     PetscCall(ConvertMatToMatrix(ispai->comm_spai, pc->pmat, pc->pmat, &ispai->B));
6701a81e61SBarry Smith   } else {
6801a81e61SBarry Smith     /* Use the transpose to get the column nonzero structure. */
699566063dSJacob Faibussowitsch     PetscCall(MatTranspose(pc->pmat, MAT_INITIAL_MATRIX, &AT));
709566063dSJacob Faibussowitsch     PetscCall(ConvertMatToMatrix(ispai->comm_spai, pc->pmat, AT, &ispai->B));
719566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&AT));
7201a81e61SBarry Smith   }
7301a81e61SBarry Smith 
7401a81e61SBarry Smith   /* Destroy the transpose */
7501a81e61SBarry Smith   /* Don't know how to do it. PETSc developers? */
7601a81e61SBarry Smith 
7701a81e61SBarry Smith   /* construct SPAI preconditioner */
7801a81e61SBarry Smith   /* FILE *messages */    /* file for warning messages */
7901a81e61SBarry Smith   /* double epsilon */    /* tolerance */
8001a81e61SBarry Smith   /* int nbsteps */       /* max number of "improvement" steps per line */
8101a81e61SBarry Smith   /* int max */           /* max dimensions of is_I, q, etc. */
8201a81e61SBarry Smith   /* int maxnew */        /* max number of new entries per step */
83d5b43468SJose E. Roman   /* int block_size */    /* block_size == 1 specifies scalar elements
8401a81e61SBarry Smith                               block_size == n specifies nxn constant-block elements
8501a81e61SBarry Smith                               block_size == 0 specifies variable-block elements */
862fa5cd67SKarl Rupp   /* int cache_size */    /* one of (1,2,3,4,5,6) indicting size of cache. cache_size == 0 indicates no caching */
8701a81e61SBarry Smith   /* int    verbose    */ /* verbose == 0 specifies that SPAI is silent
8801a81e61SBarry Smith                               verbose == 1 prints timing and matrix statistics */
8901a81e61SBarry Smith 
903ba16761SJacob Faibussowitsch   PetscCallExternal(bspai, ispai->B, &ispai->M, stdout, ispai->epsilon, ispai->nbsteps, ispai->max, ispai->maxnew, ispai->block_size, ispai->cache_size, ispai->verbose);
9101a81e61SBarry Smith 
929566063dSJacob Faibussowitsch   PetscCall(ConvertMatrixToMat(PetscObjectComm((PetscObject)pc), ispai->M, &ispai->PM));
9301a81e61SBarry Smith 
9401a81e61SBarry Smith   /* free the SPAI matrices */
9501a81e61SBarry Smith   sp_free_matrix(ispai->B);
9601a81e61SBarry Smith   sp_free_matrix(ispai->M);
973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9801a81e61SBarry Smith }
9901a81e61SBarry Smith 
100d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_SPAI(PC pc, Vec xx, Vec y)
101d71ae5a4SJacob Faibussowitsch {
10201a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
10301a81e61SBarry Smith 
10401a81e61SBarry Smith   PetscFunctionBegin;
10501a81e61SBarry Smith   /* Now using PETSc's multiply */
1069566063dSJacob Faibussowitsch   PetscCall(MatMult(ispai->PM, xx, y));
1073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10801a81e61SBarry Smith }
10901a81e61SBarry Smith 
110d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCMatApply_SPAI(PC pc, Mat X, Mat Y)
111d71ae5a4SJacob Faibussowitsch {
11248e38a8aSPierre Jolivet   PC_SPAI *ispai = (PC_SPAI *)pc->data;
11348e38a8aSPierre Jolivet 
11448e38a8aSPierre Jolivet   PetscFunctionBegin;
11548e38a8aSPierre Jolivet   /* Now using PETSc's multiply */
1169566063dSJacob Faibussowitsch   PetscCall(MatMatMult(ispai->PM, X, MAT_REUSE_MATRIX, PETSC_DEFAULT, &Y));
1173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11848e38a8aSPierre Jolivet }
11948e38a8aSPierre Jolivet 
120d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_SPAI(PC pc)
121d71ae5a4SJacob Faibussowitsch {
12201a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
12301a81e61SBarry Smith 
12401a81e61SBarry Smith   PetscFunctionBegin;
1259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&ispai->PM));
1269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_free(&(ispai->comm_spai)));
1279566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
1282e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetEpsilon_C", NULL));
1292e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetNBSteps_C", NULL));
1302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetMax_C", NULL));
1312e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetMaxNew_C", NULL));
1322e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetBlockSize_C", NULL));
1332e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetCacheSize_C", NULL));
1342e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetVerbose_C", NULL));
1352e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetSp_C", NULL));
1363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13701a81e61SBarry Smith }
13801a81e61SBarry Smith 
139d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_SPAI(PC pc, PetscViewer viewer)
140d71ae5a4SJacob Faibussowitsch {
14101a81e61SBarry Smith   PC_SPAI  *ispai = (PC_SPAI *)pc->data;
142ace3abfcSBarry Smith   PetscBool iascii;
14301a81e61SBarry Smith 
14401a81e61SBarry Smith   PetscFunctionBegin;
1459566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
14601a81e61SBarry Smith   if (iascii) {
147b03515a0SUmberto Zerbinati     PetscCall(PetscViewerASCIIPrintf(viewer, "    epsilon %g\n", ispai->epsilon));
1489566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    nbsteps %d\n", ispai->nbsteps));
1499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    max %d\n", ispai->max));
1509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    maxnew %d\n", ispai->maxnew));
1519566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    block_size %d\n", ispai->block_size));
1529566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    cache_size %d\n", ispai->cache_size));
1539566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    verbose %d\n", ispai->verbose));
1549566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "    sp %d\n", ispai->sp));
15501a81e61SBarry Smith   }
1563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15701a81e61SBarry Smith }
15801a81e61SBarry Smith 
159d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetEpsilon_SPAI(PC pc, PetscReal epsilon1)
160d71ae5a4SJacob Faibussowitsch {
16101a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
1625fd66863SKarl Rupp 
16301a81e61SBarry Smith   PetscFunctionBegin;
164b03515a0SUmberto Zerbinati   ispai->epsilon = (double)epsilon1;
1653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16601a81e61SBarry Smith }
16701a81e61SBarry Smith 
168d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetNBSteps_SPAI(PC pc, PetscInt nbsteps1)
169d71ae5a4SJacob Faibussowitsch {
17001a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
1715fd66863SKarl Rupp 
17201a81e61SBarry Smith   PetscFunctionBegin;
173b03515a0SUmberto Zerbinati   ispai->nbsteps = (int)nbsteps1;
1743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17501a81e61SBarry Smith }
17601a81e61SBarry Smith 
17701a81e61SBarry Smith /* added 1/7/99 g.h. */
178d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetMax_SPAI(PC pc, PetscInt max1)
179d71ae5a4SJacob Faibussowitsch {
18001a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
1815fd66863SKarl Rupp 
18201a81e61SBarry Smith   PetscFunctionBegin;
183b03515a0SUmberto Zerbinati   ispai->max = (int)max1;
1843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18501a81e61SBarry Smith }
18601a81e61SBarry Smith 
187d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetMaxNew_SPAI(PC pc, PetscInt maxnew1)
188d71ae5a4SJacob Faibussowitsch {
18901a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
1905fd66863SKarl Rupp 
19101a81e61SBarry Smith   PetscFunctionBegin;
192b03515a0SUmberto Zerbinati   ispai->maxnew = (int)maxnew1;
1933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19401a81e61SBarry Smith }
19501a81e61SBarry Smith 
196d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetBlockSize_SPAI(PC pc, PetscInt block_size1)
197d71ae5a4SJacob Faibussowitsch {
19801a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
1995fd66863SKarl Rupp 
20001a81e61SBarry Smith   PetscFunctionBegin;
201b03515a0SUmberto Zerbinati   ispai->block_size = (int)block_size1;
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20301a81e61SBarry Smith }
20401a81e61SBarry Smith 
205d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetCacheSize_SPAI(PC pc, PetscInt cache_size)
206d71ae5a4SJacob Faibussowitsch {
20701a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
2085fd66863SKarl Rupp 
20901a81e61SBarry Smith   PetscFunctionBegin;
210b03515a0SUmberto Zerbinati   ispai->cache_size = (int)cache_size;
2113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21201a81e61SBarry Smith }
21301a81e61SBarry Smith 
214d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetVerbose_SPAI(PC pc, PetscInt verbose)
215d71ae5a4SJacob Faibussowitsch {
21601a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
2175fd66863SKarl Rupp 
21801a81e61SBarry Smith   PetscFunctionBegin;
219b03515a0SUmberto Zerbinati   ispai->verbose = (int)verbose;
2203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22101a81e61SBarry Smith }
22201a81e61SBarry Smith 
223d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSPAISetSp_SPAI(PC pc, PetscInt sp)
224d71ae5a4SJacob Faibussowitsch {
22501a81e61SBarry Smith   PC_SPAI *ispai = (PC_SPAI *)pc->data;
2265fd66863SKarl Rupp 
22701a81e61SBarry Smith   PetscFunctionBegin;
228b03515a0SUmberto Zerbinati   ispai->sp = (int)sp;
2293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23001a81e61SBarry Smith }
23101a81e61SBarry Smith 
23201a81e61SBarry Smith /*@
233f1580f4eSBarry Smith   PCSPAISetEpsilon -- Set the tolerance for the `PCSPAI` preconditioner
23401a81e61SBarry Smith 
23501a81e61SBarry Smith   Input Parameters:
23601a81e61SBarry Smith + pc       - the preconditioner
237feefa0e1SJacob Faibussowitsch - epsilon1 - epsilon (default .4)
23801a81e61SBarry Smith 
239f1580f4eSBarry Smith   Note:
24095452b02SPatrick Sanan   Espilon must be between 0 and 1. It controls the
24101a81e61SBarry Smith   quality of the approximation of M to the inverse of
24201a81e61SBarry Smith   A. Higher values of epsilon lead to more work, more
24301a81e61SBarry Smith   fill, and usually better preconditioners. In many
24401a81e61SBarry Smith   cases the best choice of epsilon is the one that
24501a81e61SBarry Smith   divides the total solution time equally between the
24601a81e61SBarry Smith   preconditioner and the solver.
24701a81e61SBarry Smith 
24801a81e61SBarry Smith   Level: intermediate
24901a81e61SBarry Smith 
250*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
25101a81e61SBarry Smith   @*/
252d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetEpsilon(PC pc, PetscReal epsilon1)
253d71ae5a4SJacob Faibussowitsch {
25401a81e61SBarry Smith   PetscFunctionBegin;
255b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetEpsilon_C", (PC, PetscReal), (pc, epsilon1));
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25701a81e61SBarry Smith }
25801a81e61SBarry Smith 
25901a81e61SBarry Smith /*@
26001a81e61SBarry Smith   PCSPAISetNBSteps - set maximum number of improvement steps per row in
261f1580f4eSBarry Smith   the `PCSPAI` preconditioner
26201a81e61SBarry Smith 
26301a81e61SBarry Smith   Input Parameters:
26401a81e61SBarry Smith + pc       - the preconditioner
265feefa0e1SJacob Faibussowitsch - nbsteps1 - number of steps (default 5)
26601a81e61SBarry Smith 
267f1580f4eSBarry Smith   Note:
268f1580f4eSBarry Smith   `PCSPAI` constructs to approximation to every column of
26901a81e61SBarry Smith   the exact inverse of A in a series of improvement
27001a81e61SBarry Smith   steps. The quality of the approximation is determined
27101a81e61SBarry Smith   by epsilon. If an approximation achieving an accuracy
27201a81e61SBarry Smith   of epsilon is not obtained after ns steps, SPAI simply
27301a81e61SBarry Smith   uses the best approximation constructed so far.
27401a81e61SBarry Smith 
27501a81e61SBarry Smith   Level: intermediate
27601a81e61SBarry Smith 
277*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`, `PCSPAISetMaxNew()`
27801a81e61SBarry Smith @*/
279d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetNBSteps(PC pc, PetscInt nbsteps1)
280d71ae5a4SJacob Faibussowitsch {
28101a81e61SBarry Smith   PetscFunctionBegin;
282b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetNBSteps_C", (PC, PetscInt), (pc, nbsteps1));
2833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28401a81e61SBarry Smith }
28501a81e61SBarry Smith 
28601a81e61SBarry Smith /* added 1/7/99 g.h. */
28701a81e61SBarry Smith /*@
28801a81e61SBarry Smith   PCSPAISetMax - set the size of various working buffers in
289f1580f4eSBarry Smith   the `PCSPAI` preconditioner
29001a81e61SBarry Smith 
29101a81e61SBarry Smith   Input Parameters:
29201a81e61SBarry Smith + pc   - the preconditioner
293feefa0e1SJacob Faibussowitsch - max1 - size (default is 5000)
29401a81e61SBarry Smith 
29501a81e61SBarry Smith   Level: intermediate
29601a81e61SBarry Smith 
297*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
29801a81e61SBarry Smith @*/
299d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetMax(PC pc, PetscInt max1)
300d71ae5a4SJacob Faibussowitsch {
30101a81e61SBarry Smith   PetscFunctionBegin;
302b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetMax_C", (PC, PetscInt), (pc, max1));
3033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30401a81e61SBarry Smith }
30501a81e61SBarry Smith 
30601a81e61SBarry Smith /*@
30701a81e61SBarry Smith   PCSPAISetMaxNew - set maximum number of new nonzero candidates per step
308f1580f4eSBarry Smith   in `PCSPAI` preconditioner
30901a81e61SBarry Smith 
31001a81e61SBarry Smith   Input Parameters:
31101a81e61SBarry Smith + pc      - the preconditioner
312feefa0e1SJacob Faibussowitsch - maxnew1 - maximum number (default 5)
31301a81e61SBarry Smith 
31401a81e61SBarry Smith   Level: intermediate
31501a81e61SBarry Smith 
316*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`, `PCSPAISetNBSteps()`
31701a81e61SBarry Smith @*/
318d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetMaxNew(PC pc, PetscInt maxnew1)
319d71ae5a4SJacob Faibussowitsch {
32001a81e61SBarry Smith   PetscFunctionBegin;
321b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetMaxNew_C", (PC, PetscInt), (pc, maxnew1));
3223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32301a81e61SBarry Smith }
32401a81e61SBarry Smith 
32501a81e61SBarry Smith /*@
326f1580f4eSBarry Smith   PCSPAISetBlockSize - set the block size for the `PCSPAI` preconditioner
32701a81e61SBarry Smith 
32801a81e61SBarry Smith   Input Parameters:
32901a81e61SBarry Smith + pc          - the preconditioner
330feefa0e1SJacob Faibussowitsch - block_size1 - block size (default 1)
33101a81e61SBarry Smith 
33295452b02SPatrick Sanan   Notes:
33395452b02SPatrick Sanan   A block
33401a81e61SBarry Smith   size of 1 treats A as a matrix of scalar elements. A
33501a81e61SBarry Smith   block size of s > 1 treats A as a matrix of sxs
33601a81e61SBarry Smith   blocks. A block size of 0 treats A as a matrix with
33701a81e61SBarry Smith   variable sized blocks, which are determined by
33801a81e61SBarry Smith   searching for dense square diagonal blocks in A.
33901a81e61SBarry Smith   This can be very effective for finite-element
34001a81e61SBarry Smith   matrices.
34101a81e61SBarry Smith 
34201a81e61SBarry Smith   SPAI will convert A to block form, use a block
34301a81e61SBarry Smith   version of the preconditioner algorithm, and then
34401a81e61SBarry Smith   convert the result back to scalar form.
34501a81e61SBarry Smith 
34601a81e61SBarry Smith   In many cases the a block-size parameter other than 1
34701a81e61SBarry Smith   can lead to very significant improvement in
34801a81e61SBarry Smith   performance.
34901a81e61SBarry Smith 
35001a81e61SBarry Smith   Level: intermediate
35101a81e61SBarry Smith 
352*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
35301a81e61SBarry Smith @*/
354d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetBlockSize(PC pc, PetscInt block_size1)
355d71ae5a4SJacob Faibussowitsch {
35601a81e61SBarry Smith   PetscFunctionBegin;
357b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetBlockSize_C", (PC, PetscInt), (pc, block_size1));
3583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35901a81e61SBarry Smith }
36001a81e61SBarry Smith 
36101a81e61SBarry Smith /*@
362f1580f4eSBarry Smith   PCSPAISetCacheSize - specify cache size in the `PCSPAI` preconditioner
36301a81e61SBarry Smith 
36401a81e61SBarry Smith   Input Parameters:
36501a81e61SBarry Smith + pc         - the preconditioner
366feefa0e1SJacob Faibussowitsch - cache_size - cache size {0,1,2,3,4,5} (default 5)
36701a81e61SBarry Smith 
368f1580f4eSBarry Smith   Note:
369f1580f4eSBarry Smith   `PCSPAI` uses a hash table to cache messages and avoid
37001a81e61SBarry Smith   redundant communication. If suggest always using
37101a81e61SBarry Smith   5. This parameter is irrelevant in the serial
37201a81e61SBarry Smith   version.
37301a81e61SBarry Smith 
37401a81e61SBarry Smith   Level: intermediate
37501a81e61SBarry Smith 
376*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
37701a81e61SBarry Smith @*/
378d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetCacheSize(PC pc, PetscInt cache_size)
379d71ae5a4SJacob Faibussowitsch {
38001a81e61SBarry Smith   PetscFunctionBegin;
381b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetCacheSize_C", (PC, PetscInt), (pc, cache_size));
3823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38301a81e61SBarry Smith }
38401a81e61SBarry Smith 
38501a81e61SBarry Smith /*@
386f1580f4eSBarry Smith   PCSPAISetVerbose - verbosity level for the `PCSPAI` preconditioner
38701a81e61SBarry Smith 
38801a81e61SBarry Smith   Input Parameters:
38901a81e61SBarry Smith + pc      - the preconditioner
390feefa0e1SJacob Faibussowitsch - verbose - level (default 1)
39101a81e61SBarry Smith 
392f1580f4eSBarry Smith   Note:
39395452b02SPatrick Sanan   print parameters, timings and matrix statistics
39401a81e61SBarry Smith 
39501a81e61SBarry Smith   Level: intermediate
39601a81e61SBarry Smith 
397*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
39801a81e61SBarry Smith @*/
399d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetVerbose(PC pc, PetscInt verbose)
400d71ae5a4SJacob Faibussowitsch {
40101a81e61SBarry Smith   PetscFunctionBegin;
402b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetVerbose_C", (PC, PetscInt), (pc, verbose));
4033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40401a81e61SBarry Smith }
40501a81e61SBarry Smith 
40601a81e61SBarry Smith /*@
407f1580f4eSBarry Smith   PCSPAISetSp - specify a symmetric matrix sparsity pattern in the `PCSPAI` preconditioner
40801a81e61SBarry Smith 
40901a81e61SBarry Smith   Input Parameters:
41001a81e61SBarry Smith + pc - the preconditioner
411feefa0e1SJacob Faibussowitsch - sp - 0 or 1
41201a81e61SBarry Smith 
413f1580f4eSBarry Smith   Note:
41495452b02SPatrick Sanan   If A has a symmetric nonzero pattern use -sp 1 to
41501a81e61SBarry Smith   improve performance by eliminating some communication
41601a81e61SBarry Smith   in the parallel version. Even if A does not have a
41701a81e61SBarry Smith   symmetric nonzero pattern -sp 1 may well lead to good
41801a81e61SBarry Smith   results, but the code will not follow the published
41901a81e61SBarry Smith   SPAI algorithm exactly.
42001a81e61SBarry Smith 
42101a81e61SBarry Smith   Level: intermediate
42201a81e61SBarry Smith 
423*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCSPAI`, `PCSetType()`
42401a81e61SBarry Smith @*/
425d71ae5a4SJacob Faibussowitsch PetscErrorCode PCSPAISetSp(PC pc, PetscInt sp)
426d71ae5a4SJacob Faibussowitsch {
42701a81e61SBarry Smith   PetscFunctionBegin;
428b03515a0SUmberto Zerbinati   PetscTryMethod(pc, "PCSPAISetSp_C", (PC, PetscInt), (pc, sp));
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43001a81e61SBarry Smith }
43101a81e61SBarry Smith 
432d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_SPAI(PC pc, PetscOptionItems *PetscOptionsObject)
433d71ae5a4SJacob Faibussowitsch {
43401a81e61SBarry Smith   PC_SPAI  *ispai = (PC_SPAI *)pc->data;
43501a81e61SBarry Smith   int       nbsteps1, max1, maxnew1, block_size1, cache_size, verbose, sp;
43601a81e61SBarry Smith   double    epsilon1;
437ace3abfcSBarry Smith   PetscBool flg;
43801a81e61SBarry Smith 
43901a81e61SBarry Smith   PetscFunctionBegin;
440d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "SPAI options");
4419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_spai_epsilon", "", "PCSPAISetEpsilon", ispai->epsilon, &epsilon1, &flg));
4421baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetEpsilon(pc, epsilon1));
4439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_nbsteps", "", "PCSPAISetNBSteps", ispai->nbsteps, &nbsteps1, &flg));
4441baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetNBSteps(pc, nbsteps1));
44501a81e61SBarry Smith   /* added 1/7/99 g.h. */
4469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_max", "", "PCSPAISetMax", ispai->max, &max1, &flg));
4471baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetMax(pc, max1));
4489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_maxnew", "", "PCSPAISetMaxNew", ispai->maxnew, &maxnew1, &flg));
4491baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetMaxNew(pc, maxnew1));
4509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_block_size", "", "PCSPAISetBlockSize", ispai->block_size, &block_size1, &flg));
4511baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetBlockSize(pc, block_size1));
4529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_cache_size", "", "PCSPAISetCacheSize", ispai->cache_size, &cache_size, &flg));
4531baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetCacheSize(pc, cache_size));
4549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_verbose", "", "PCSPAISetVerbose", ispai->verbose, &verbose, &flg));
4551baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetVerbose(pc, verbose));
4569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_spai_sp", "", "PCSPAISetSp", ispai->sp, &sp, &flg));
4571baa6e33SBarry Smith   if (flg) PetscCall(PCSPAISetSp(pc, sp));
458d0609cedSBarry Smith   PetscOptionsHeadEnd();
4593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46001a81e61SBarry Smith }
46101a81e61SBarry Smith 
46201a81e61SBarry Smith /*MC
463f1580f4eSBarry Smith    PCSPAI - Use the Sparse Approximate Inverse method
46401a81e61SBarry Smith 
46501a81e61SBarry Smith    Options Database Keys:
466c5ae99e3SSatish Balay +  -pc_spai_epsilon <eps> - set tolerance
46701a81e61SBarry Smith .  -pc_spai_nbstep <n> - set nbsteps
46801a81e61SBarry Smith .  -pc_spai_max <m> - set max
46901a81e61SBarry Smith .  -pc_spai_max_new <m> - set maxnew
47001a81e61SBarry Smith .  -pc_spai_block_size <n> - set block size
47101a81e61SBarry Smith .  -pc_spai_cache_size <n> - set cache size
47201a81e61SBarry Smith .  -pc_spai_sp <m> - set sp
47301a81e61SBarry Smith -  -pc_spai_set_verbose <true,false> - verbose output
47401a81e61SBarry Smith 
47501a81e61SBarry Smith    Level: beginner
47601a81e61SBarry Smith 
477f1580f4eSBarry Smith    Note:
478f1580f4eSBarry Smith     This only works with `MATAIJ` matrices.
479f1580f4eSBarry Smith 
480f1580f4eSBarry Smith    References:
481f1580f4eSBarry Smith  . * -  Grote and Barnard (SIAM J. Sci. Comput.; vol 18, nr 3)
482f1580f4eSBarry Smith 
483*562efe2eSBarry Smith .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
484db781477SPatrick Sanan           `PCSPAISetEpsilon()`, `PCSPAISetMax()`, `PCSPAISetMaxNew()`, `PCSPAISetBlockSize()`,
485f1580f4eSBarry Smith           `PCSPAISetVerbose()`, `PCSPAISetSp()`, `PCSPAISetNBSteps()`, `PCSPAISetCacheSize()`
48601a81e61SBarry Smith M*/
48701a81e61SBarry Smith 
488d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_SPAI(PC pc)
489d71ae5a4SJacob Faibussowitsch {
49001a81e61SBarry Smith   PC_SPAI *ispai;
49101a81e61SBarry Smith 
49201a81e61SBarry Smith   PetscFunctionBegin;
4934dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&ispai));
4942a4967abSBarry Smith   pc->data = ispai;
49501a81e61SBarry Smith 
49601a81e61SBarry Smith   pc->ops->destroy         = PCDestroy_SPAI;
49701a81e61SBarry Smith   pc->ops->apply           = PCApply_SPAI;
49848e38a8aSPierre Jolivet   pc->ops->matapply        = PCMatApply_SPAI;
49901a81e61SBarry Smith   pc->ops->applyrichardson = 0;
50001a81e61SBarry Smith   pc->ops->setup           = PCSetUp_SPAI;
50101a81e61SBarry Smith   pc->ops->view            = PCView_SPAI;
50201a81e61SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_SPAI;
50301a81e61SBarry Smith 
50401a81e61SBarry Smith   ispai->epsilon    = .4;
50501a81e61SBarry Smith   ispai->nbsteps    = 5;
50601a81e61SBarry Smith   ispai->max        = 5000;
50701a81e61SBarry Smith   ispai->maxnew     = 5;
50801a81e61SBarry Smith   ispai->block_size = 1;
50901a81e61SBarry Smith   ispai->cache_size = 5;
51001a81e61SBarry Smith   ispai->verbose    = 0;
51101a81e61SBarry Smith 
51201a81e61SBarry Smith   ispai->sp = 1;
5139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)pc), &(ispai->comm_spai)));
51401a81e61SBarry Smith 
5159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetEpsilon_C", PCSPAISetEpsilon_SPAI));
5169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetNBSteps_C", PCSPAISetNBSteps_SPAI));
5179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetMax_C", PCSPAISetMax_SPAI));
5189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetMaxNew_C", PCSPAISetMaxNew_SPAI));
5199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetBlockSize_C", PCSPAISetBlockSize_SPAI));
5209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetCacheSize_C", PCSPAISetCacheSize_SPAI));
5219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetVerbose_C", PCSPAISetVerbose_SPAI));
5229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSPAISetSp_C", PCSPAISetSp_SPAI));
5233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52401a81e61SBarry Smith }
52501a81e61SBarry Smith 
52601a81e61SBarry Smith /*
52701a81e61SBarry Smith    Converts from a PETSc matrix to an SPAI matrix
52801a81e61SBarry Smith */
529ba38deedSJacob Faibussowitsch static PetscErrorCode ConvertMatToMatrix(MPI_Comm comm, Mat A, Mat AT, matrix **B)
530d71ae5a4SJacob Faibussowitsch {
53101a81e61SBarry Smith   matrix                  *M;
53201a81e61SBarry Smith   int                      i, j, col;
53301a81e61SBarry Smith   int                      row_indx;
53401a81e61SBarry Smith   int                      len, pe, local_indx, start_indx;
53501a81e61SBarry Smith   int                     *mapping;
53601a81e61SBarry Smith   const int               *cols;
53701a81e61SBarry Smith   const double            *vals;
5382122902bSSatish Balay   int                      n, mnl, nnl, nz, rstart, rend;
5392a4967abSBarry Smith   PetscMPIInt              size, rank;
54001a81e61SBarry Smith   struct compressed_lines *rows;
54101a81e61SBarry Smith 
54201a81e61SBarry Smith   PetscFunctionBegin;
5439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
5449566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5459566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A, &n, &n));
5469566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A, &mnl, &nnl));
54701a81e61SBarry Smith 
54801a81e61SBarry Smith   /*
54901a81e61SBarry Smith     not sure why a barrier is required. commenting out
5509566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Barrier(comm));
55101a81e61SBarry Smith   */
55201a81e61SBarry Smith 
55329b2f704SSatish Balay   M = new_matrix((SPAI_Comm)comm);
55401a81e61SBarry Smith 
55501a81e61SBarry Smith   M->n              = n;
55601a81e61SBarry Smith   M->bs             = 1;
55701a81e61SBarry Smith   M->max_block_size = 1;
55801a81e61SBarry Smith 
55901a81e61SBarry Smith   M->mnls          = (int *)malloc(sizeof(int) * size);
56001a81e61SBarry Smith   M->start_indices = (int *)malloc(sizeof(int) * size);
56101a81e61SBarry Smith   M->pe            = (int *)malloc(sizeof(int) * n);
56201a81e61SBarry Smith   M->block_sizes   = (int *)malloc(sizeof(int) * n);
56301a81e61SBarry Smith   for (i = 0; i < n; i++) M->block_sizes[i] = 1;
56401a81e61SBarry Smith 
5659566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allgather(&mnl, 1, MPI_INT, M->mnls, 1, MPI_INT, comm));
56601a81e61SBarry Smith 
56701a81e61SBarry Smith   M->start_indices[0] = 0;
5682fa5cd67SKarl Rupp   for (i = 1; i < size; i++) M->start_indices[i] = M->start_indices[i - 1] + M->mnls[i - 1];
56901a81e61SBarry Smith 
57001a81e61SBarry Smith   M->mnl            = M->mnls[M->myid];
57101a81e61SBarry Smith   M->my_start_index = M->start_indices[M->myid];
57201a81e61SBarry Smith 
57301a81e61SBarry Smith   for (i = 0; i < size; i++) {
57401a81e61SBarry Smith     start_indx = M->start_indices[i];
5752fa5cd67SKarl Rupp     for (j = 0; j < M->mnls[i]; j++) M->pe[start_indx + j] = i;
57601a81e61SBarry Smith   }
57701a81e61SBarry Smith 
57801a81e61SBarry Smith   if (AT) {
5792f613bf5SBarry Smith     M->lines = new_compressed_lines(M->mnls[rank], 1);
58001a81e61SBarry Smith   } else {
5812f613bf5SBarry Smith     M->lines = new_compressed_lines(M->mnls[rank], 0);
58201a81e61SBarry Smith   }
58301a81e61SBarry Smith 
58401a81e61SBarry Smith   rows = M->lines;
58501a81e61SBarry Smith 
58601a81e61SBarry Smith   /* Determine the mapping from global indices to pointers */
5879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(M->n, &mapping));
58801a81e61SBarry Smith   pe         = 0;
58901a81e61SBarry Smith   local_indx = 0;
59001a81e61SBarry Smith   for (i = 0; i < M->n; i++) {
59101a81e61SBarry Smith     if (local_indx >= M->mnls[pe]) {
59201a81e61SBarry Smith       pe++;
59301a81e61SBarry Smith       local_indx = 0;
59401a81e61SBarry Smith     }
59501a81e61SBarry Smith     mapping[i] = local_indx + M->start_indices[pe];
59601a81e61SBarry Smith     local_indx++;
59701a81e61SBarry Smith   }
59801a81e61SBarry Smith 
59901a81e61SBarry Smith   /************** Set up the row structure *****************/
60001a81e61SBarry Smith 
6019566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
60201a81e61SBarry Smith   for (i = rstart; i < rend; i++) {
60301a81e61SBarry Smith     row_indx = i - rstart;
6049566063dSJacob Faibussowitsch     PetscCall(MatGetRow(A, i, &nz, &cols, &vals));
6052122902bSSatish Balay     /* allocate buffers */
6062122902bSSatish Balay     rows->ptrs[row_indx] = (int *)malloc(nz * sizeof(int));
6072122902bSSatish Balay     rows->A[row_indx]    = (double *)malloc(nz * sizeof(double));
6082122902bSSatish Balay     /* copy the matrix */
60901a81e61SBarry Smith     for (j = 0; j < nz; j++) {
61001a81e61SBarry Smith       col = cols[j];
61101a81e61SBarry Smith       len = rows->len[row_indx]++;
6122fa5cd67SKarl Rupp 
61301a81e61SBarry Smith       rows->ptrs[row_indx][len] = mapping[col];
61401a81e61SBarry Smith       rows->A[row_indx][len]    = vals[j];
61501a81e61SBarry Smith     }
61601a81e61SBarry Smith     rows->slen[row_indx] = rows->len[row_indx];
6172fa5cd67SKarl Rupp 
6189566063dSJacob Faibussowitsch     PetscCall(MatRestoreRow(A, i, &nz, &cols, &vals));
61901a81e61SBarry Smith   }
62001a81e61SBarry Smith 
62101a81e61SBarry Smith   /************** Set up the column structure *****************/
62201a81e61SBarry Smith 
62301a81e61SBarry Smith   if (AT) {
62401a81e61SBarry Smith     for (i = rstart; i < rend; i++) {
62501a81e61SBarry Smith       row_indx = i - rstart;
6269566063dSJacob Faibussowitsch       PetscCall(MatGetRow(AT, i, &nz, &cols, &vals));
6272122902bSSatish Balay       /* allocate buffers */
6282122902bSSatish Balay       rows->rptrs[row_indx] = (int *)malloc(nz * sizeof(int));
6292122902bSSatish Balay       /* copy the matrix (i.e., the structure) */
63001a81e61SBarry Smith       for (j = 0; j < nz; j++) {
63101a81e61SBarry Smith         col = cols[j];
63201a81e61SBarry Smith         len = rows->rlen[row_indx]++;
6332fa5cd67SKarl Rupp 
63401a81e61SBarry Smith         rows->rptrs[row_indx][len] = mapping[col];
63501a81e61SBarry Smith       }
6369566063dSJacob Faibussowitsch       PetscCall(MatRestoreRow(AT, i, &nz, &cols, &vals));
63701a81e61SBarry Smith     }
63801a81e61SBarry Smith   }
63901a81e61SBarry Smith 
6409566063dSJacob Faibussowitsch   PetscCall(PetscFree(mapping));
64101a81e61SBarry Smith 
64201a81e61SBarry Smith   order_pointers(M);
64301a81e61SBarry Smith   M->maxnz = calc_maxnz(M);
64401a81e61SBarry Smith   *B       = M;
6453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64601a81e61SBarry Smith }
64701a81e61SBarry Smith 
64801a81e61SBarry Smith /*
64901a81e61SBarry Smith    Converts from an SPAI matrix B  to a PETSc matrix PB.
650df3898eeSBarry Smith    This assumes that the SPAI matrix B is stored in
65101a81e61SBarry Smith    COMPRESSED-ROW format.
65201a81e61SBarry Smith */
653ba38deedSJacob Faibussowitsch static PetscErrorCode ConvertMatrixToMat(MPI_Comm comm, matrix *B, Mat *PB)
654d71ae5a4SJacob Faibussowitsch {
6554b6b5fe1SBarry Smith   PetscMPIInt size, rank;
65601a81e61SBarry Smith   int         m, n, M, N;
65701a81e61SBarry Smith   int         d_nz, o_nz;
65801a81e61SBarry Smith   int        *d_nnz, *o_nnz;
65901a81e61SBarry Smith   int         i, k, global_row, global_col, first_diag_col, last_diag_col;
66001a81e61SBarry Smith   PetscScalar val;
66101a81e61SBarry Smith 
66201a81e61SBarry Smith   PetscFunctionBegin;
6639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
6649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
66501a81e61SBarry Smith 
66601a81e61SBarry Smith   m = n = B->mnls[rank];
66701a81e61SBarry Smith   d_nz = o_nz = 0;
66801a81e61SBarry Smith 
66906946f3aSJose E. Roman   /* Determine preallocation for MatCreateAIJ */
6709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &d_nnz));
6719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &o_nnz));
67201a81e61SBarry Smith   for (i = 0; i < m; i++) d_nnz[i] = o_nnz[i] = 0;
67301a81e61SBarry Smith   first_diag_col = B->start_indices[rank];
67401a81e61SBarry Smith   last_diag_col  = first_diag_col + B->mnls[rank];
67501a81e61SBarry Smith   for (i = 0; i < B->mnls[rank]; i++) {
67601a81e61SBarry Smith     for (k = 0; k < B->lines->len[i]; k++) {
67701a81e61SBarry Smith       global_col = B->lines->ptrs[i][k];
678db4deed7SKarl Rupp       if ((global_col >= first_diag_col) && (global_col < last_diag_col)) d_nnz[i]++;
679db4deed7SKarl Rupp       else o_nnz[i]++;
68001a81e61SBarry Smith     }
68101a81e61SBarry Smith   }
68201a81e61SBarry Smith 
68301a81e61SBarry Smith   M = N = B->n;
68401a81e61SBarry Smith   /* Here we only know how to create AIJ format */
6859566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, PB));
6869566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*PB, m, n, M, N));
6879566063dSJacob Faibussowitsch   PetscCall(MatSetType(*PB, MATAIJ));
6889566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*PB, d_nz, d_nnz));
6899566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*PB, d_nz, d_nnz, o_nz, o_nnz));
69001a81e61SBarry Smith 
69101a81e61SBarry Smith   for (i = 0; i < B->mnls[rank]; i++) {
69201a81e61SBarry Smith     global_row = B->start_indices[rank] + i;
69301a81e61SBarry Smith     for (k = 0; k < B->lines->len[i]; k++) {
69401a81e61SBarry Smith       global_col = B->lines->ptrs[i][k];
6952fa5cd67SKarl Rupp 
69601a81e61SBarry Smith       val = B->lines->A[i][k];
6979566063dSJacob Faibussowitsch       PetscCall(MatSetValues(*PB, 1, &global_row, 1, &global_col, &val, ADD_VALUES));
69801a81e61SBarry Smith     }
69901a81e61SBarry Smith   }
70001a81e61SBarry Smith 
7019566063dSJacob Faibussowitsch   PetscCall(PetscFree(d_nnz));
7029566063dSJacob Faibussowitsch   PetscCall(PetscFree(o_nnz));
70301a81e61SBarry Smith 
7049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*PB, MAT_FINAL_ASSEMBLY));
7059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*PB, MAT_FINAL_ASSEMBLY));
7063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70701a81e61SBarry Smith }
708