xref: /petsc/src/ksp/pc/impls/cp/cp.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
124c02a0fSBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/
3c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/aij.h>
424c02a0fSBarry Smith 
524c02a0fSBarry Smith /*
624c02a0fSBarry Smith    Private context (data structure) for the CP preconditioner.
724c02a0fSBarry Smith */
824c02a0fSBarry Smith typedef struct {
924c02a0fSBarry Smith   PetscInt     n, m;
1024c02a0fSBarry Smith   Vec          work;
1124c02a0fSBarry Smith   PetscScalar *d;     /* sum of squares of each column */
1224c02a0fSBarry Smith   PetscScalar *a;     /* non-zeros by column */
1324c02a0fSBarry Smith   PetscInt    *i, *j; /* offsets of nonzeros by column, non-zero indices by column */
1424c02a0fSBarry Smith } PC_CP;
1524c02a0fSBarry Smith 
169371c9d4SSatish Balay static PetscErrorCode PCSetUp_CP(PC pc) {
1724c02a0fSBarry Smith   PC_CP      *cp = (PC_CP *)pc->data;
1824c02a0fSBarry Smith   PetscInt    i, j, *colcnt;
19ace3abfcSBarry Smith   PetscBool   flg;
2024c02a0fSBarry Smith   Mat_SeqAIJ *aij = (Mat_SeqAIJ *)pc->pmat->data;
2124c02a0fSBarry Smith 
2224c02a0fSBarry Smith   PetscFunctionBegin;
239566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATSEQAIJ, &flg));
2428b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Currently only handles SeqAIJ matrices");
2524c02a0fSBarry Smith 
269566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(pc->pmat, &cp->m, &cp->n));
2708401ef6SPierre Jolivet   PetscCheck(cp->m == cp->n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Currently only for square matrices");
2824c02a0fSBarry Smith 
299566063dSJacob Faibussowitsch   if (!cp->work) PetscCall(MatCreateVecs(pc->pmat, &cp->work, NULL));
309566063dSJacob Faibussowitsch   if (!cp->d) PetscCall(PetscMalloc1(cp->n, &cp->d));
3124c02a0fSBarry Smith   if (cp->a && pc->flag != SAME_NONZERO_PATTERN) {
329566063dSJacob Faibussowitsch     PetscCall(PetscFree3(cp->a, cp->i, cp->j));
330a545947SLisandro Dalcin     cp->a = NULL;
3424c02a0fSBarry Smith   }
3524c02a0fSBarry Smith 
3624c02a0fSBarry Smith   /* convert to column format */
37*48a46eb9SPierre Jolivet   if (!cp->a) PetscCall(PetscMalloc3(aij->nz, &cp->a, cp->n + 1, &cp->i, aij->nz, &cp->j));
389566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(cp->n, &colcnt));
3924c02a0fSBarry Smith 
402fa5cd67SKarl Rupp   for (i = 0; i < aij->nz; i++) colcnt[aij->j[i]]++;
41e60cf9a0SBarry Smith   cp->i[0] = 0;
422fa5cd67SKarl Rupp   for (i = 0; i < cp->n; i++) cp->i[i + 1] = cp->i[i] + colcnt[i];
439566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(colcnt, cp->n));
4424c02a0fSBarry Smith   for (i = 0; i < cp->m; i++) {                   /* over rows */
4524c02a0fSBarry Smith     for (j = aij->i[i]; j < aij->i[i + 1]; j++) { /* over columns in row */
4624c02a0fSBarry Smith       cp->j[cp->i[aij->j[j]] + colcnt[aij->j[j]]]   = i;
4724c02a0fSBarry Smith       cp->a[cp->i[aij->j[j]] + colcnt[aij->j[j]]++] = aij->a[j];
4824c02a0fSBarry Smith     }
4924c02a0fSBarry Smith   }
509566063dSJacob Faibussowitsch   PetscCall(PetscFree(colcnt));
5124c02a0fSBarry Smith 
5224c02a0fSBarry Smith   /* compute sum of squares of each column d[] */
5324c02a0fSBarry Smith   for (i = 0; i < cp->n; i++) { /* over columns */
5475567043SBarry Smith     cp->d[i] = 0.;
552fa5cd67SKarl Rupp     for (j = cp->i[i]; j < cp->i[i + 1]; j++) cp->d[i] += cp->a[j] * cp->a[j]; /* over rows in column */
5624c02a0fSBarry Smith     cp->d[i] = 1.0 / cp->d[i];
5724c02a0fSBarry Smith   }
5824c02a0fSBarry Smith   PetscFunctionReturn(0);
5924c02a0fSBarry Smith }
6024c02a0fSBarry Smith /* -------------------------------------------------------------------------- */
619371c9d4SSatish Balay static PetscErrorCode PCApply_CP(PC pc, Vec bb, Vec xx) {
6224c02a0fSBarry Smith   PC_CP       *cp = (PC_CP *)pc->data;
6324c02a0fSBarry Smith   PetscScalar *b, *x, xt;
6424c02a0fSBarry Smith   PetscInt     i, j;
6524c02a0fSBarry Smith 
6624c02a0fSBarry Smith   PetscFunctionBegin;
679566063dSJacob Faibussowitsch   PetscCall(VecCopy(bb, cp->work));
689566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cp->work, &b));
699566063dSJacob Faibussowitsch   PetscCall(VecGetArray(xx, &x));
7024c02a0fSBarry Smith 
7124c02a0fSBarry Smith   for (i = 0; i < cp->n; i++) { /* over columns */
7275567043SBarry Smith     xt = 0.;
732fa5cd67SKarl Rupp     for (j = cp->i[i]; j < cp->i[i + 1]; j++) xt += cp->a[j] * b[cp->j[j]]; /* over rows in column */
7424c02a0fSBarry Smith     xt *= cp->d[i];
7524c02a0fSBarry Smith     x[i] = xt;
762fa5cd67SKarl Rupp     for (j = cp->i[i]; j < cp->i[i + 1]; j++) b[cp->j[j]] -= xt * cp->a[j]; /* over rows in column updating b*/
7724c02a0fSBarry Smith   }
7824c02a0fSBarry Smith   for (i = cp->n - 1; i > -1; i--) { /* over columns */
7975567043SBarry Smith     xt = 0.;
802fa5cd67SKarl Rupp     for (j = cp->i[i]; j < cp->i[i + 1]; j++) xt += cp->a[j] * b[cp->j[j]]; /* over rows in column */
8124c02a0fSBarry Smith     xt *= cp->d[i];
8224c02a0fSBarry Smith     x[i] = xt;
832fa5cd67SKarl Rupp     for (j = cp->i[i]; j < cp->i[i + 1]; j++) b[cp->j[j]] -= xt * cp->a[j]; /* over rows in column updating b*/
8424c02a0fSBarry Smith   }
8524c02a0fSBarry Smith 
869566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cp->work, &b));
879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(xx, &x));
8824c02a0fSBarry Smith   PetscFunctionReturn(0);
8924c02a0fSBarry Smith }
9024c02a0fSBarry Smith /* -------------------------------------------------------------------------- */
919371c9d4SSatish Balay static PetscErrorCode PCReset_CP(PC pc) {
9224c02a0fSBarry Smith   PC_CP *cp = (PC_CP *)pc->data;
9324c02a0fSBarry Smith 
9424c02a0fSBarry Smith   PetscFunctionBegin;
959566063dSJacob Faibussowitsch   PetscCall(PetscFree(cp->d));
969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cp->work));
979566063dSJacob Faibussowitsch   PetscCall(PetscFree3(cp->a, cp->i, cp->j));
9869d2c0f9SBarry Smith   PetscFunctionReturn(0);
9969d2c0f9SBarry Smith }
10069d2c0f9SBarry Smith 
1019371c9d4SSatish Balay static PetscErrorCode PCDestroy_CP(PC pc) {
10269d2c0f9SBarry Smith   PC_CP *cp = (PC_CP *)pc->data;
10369d2c0f9SBarry Smith 
10469d2c0f9SBarry Smith   PetscFunctionBegin;
1059566063dSJacob Faibussowitsch   PetscCall(PCReset_CP(pc));
1069566063dSJacob Faibussowitsch   PetscCall(PetscFree(cp->d));
1079566063dSJacob Faibussowitsch   PetscCall(PetscFree3(cp->a, cp->i, cp->j));
1089566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
10924c02a0fSBarry Smith   PetscFunctionReturn(0);
11024c02a0fSBarry Smith }
11124c02a0fSBarry Smith 
1129371c9d4SSatish Balay static PetscErrorCode PCSetFromOptions_CP(PC pc, PetscOptionItems *PetscOptionsObject) {
11324c02a0fSBarry Smith   PetscFunctionBegin;
11424c02a0fSBarry Smith   PetscFunctionReturn(0);
11524c02a0fSBarry Smith }
11624c02a0fSBarry Smith 
11724c02a0fSBarry Smith /*MC
11824c02a0fSBarry Smith      PCCP - a "column-projection" preconditioner
11924c02a0fSBarry Smith 
12024c02a0fSBarry Smith      This is a terrible preconditioner and is not recommended, ever!
12124c02a0fSBarry Smith 
12273a58da7SBarry Smith      Loops over the entries of x computing dx_i (e_i is the unit vector in the ith direction) to
12324c02a0fSBarry Smith $
12424c02a0fSBarry Smith $        min || b - A(x + dx_i e_i ||_2
12524c02a0fSBarry Smith $        dx_i
12624c02a0fSBarry Smith $
12773a58da7SBarry Smith $    That is, it changes a single entry of x to minimize the new residual norm.
12824c02a0fSBarry Smith $   Let A_i represent the ith column of A, then the minimization can be written as
12924c02a0fSBarry Smith $
13024c02a0fSBarry Smith $       min || r - (dx_i) A e_i ||_2
13124c02a0fSBarry Smith $       dx_i
13224c02a0fSBarry Smith $   or   min || r - (dx_i) A_i ||_2
13324c02a0fSBarry Smith $        dx_i
13424c02a0fSBarry Smith $
13524c02a0fSBarry Smith $    take the derivative with respect to dx_i to obtain
13624c02a0fSBarry Smith $        dx_i = (A_i^T A_i)^(-1) A_i^T r
13724c02a0fSBarry Smith $
13824c02a0fSBarry Smith $    This algorithm can be thought of as Gauss-Seidel on the normal equations
13924c02a0fSBarry Smith 
14095452b02SPatrick Sanan     Notes:
14195452b02SPatrick Sanan     This proceedure can also be done with block columns or any groups of columns
14224c02a0fSBarry Smith         but this is not coded.
14324c02a0fSBarry Smith 
14424c02a0fSBarry Smith       These "projections" can be done simultaneously for all columns (similar to Jacobi)
14524c02a0fSBarry Smith          or sequentially (similar to Gauss-Seidel/SOR). This is only coded for SOR type.
14624c02a0fSBarry Smith 
14724c02a0fSBarry Smith       This is related to, but not the same as "row projection" methods.
14824c02a0fSBarry Smith 
14924c02a0fSBarry Smith       This is currently coded only for SeqAIJ matrices in sequential (SOR) form.
15028529972SSatish Balay 
15128529972SSatish Balay   Level: intermediate
15224c02a0fSBarry Smith 
153db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PCJACOBI`, `PCSOR`
15424c02a0fSBarry Smith 
15524c02a0fSBarry Smith M*/
15624c02a0fSBarry Smith 
1579371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_CP(PC pc) {
15824c02a0fSBarry Smith   PC_CP *cp;
15924c02a0fSBarry Smith 
16024c02a0fSBarry Smith   PetscFunctionBegin;
1619566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &cp));
16224c02a0fSBarry Smith   pc->data = (void *)cp;
16324c02a0fSBarry Smith 
16424c02a0fSBarry Smith   pc->ops->apply           = PCApply_CP;
16524c02a0fSBarry Smith   pc->ops->applytranspose  = PCApply_CP;
16624c02a0fSBarry Smith   pc->ops->setup           = PCSetUp_CP;
16769d2c0f9SBarry Smith   pc->ops->reset           = PCReset_CP;
16824c02a0fSBarry Smith   pc->ops->destroy         = PCDestroy_CP;
16924c02a0fSBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_CP;
1700a545947SLisandro Dalcin   pc->ops->view            = NULL;
1710a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
17224c02a0fSBarry Smith   PetscFunctionReturn(0);
17324c02a0fSBarry Smith }
174