xref: /petsc/src/mat/impls/composite/mcomposite.c (revision 1cc06b555e92f8ec64db10330b8bbd830e5bc876)
1793850ffSBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
3793850ffSBarry Smith 
4f4259b30SLisandro Dalcin const char *const MatCompositeMergeTypes[] = {"left", "right", "MatCompositeMergeType", "MAT_COMPOSITE_", NULL};
58c8613bfSJakub Kruzik 
6793850ffSBarry Smith typedef struct _Mat_CompositeLink *Mat_CompositeLink;
7793850ffSBarry Smith struct _Mat_CompositeLink {
8793850ffSBarry Smith   Mat               mat;
96d7c1e57SBarry Smith   Vec               work;
106d7c1e57SBarry Smith   Mat_CompositeLink next, prev;
11793850ffSBarry Smith };
12793850ffSBarry Smith 
13793850ffSBarry Smith typedef struct {
146d7c1e57SBarry Smith   MatCompositeType      type;
156d7c1e57SBarry Smith   Mat_CompositeLink     head, tail;
16793850ffSBarry Smith   Vec                   work;
17e4fc5df0SBarry Smith   PetscScalar           scale;                                      /* scale factor supplied with MatScale() */
18e4fc5df0SBarry Smith   Vec                   left, right;                                /* left and right diagonal scaling provided with MatDiagonalScale() */
1903049c21SJunchao Zhang   Vec                   leftwork, rightwork, leftwork2, rightwork2; /* Two pairs of working vectors */
206a7ede75SJakub Kruzik   PetscInt              nmat;
214b2558d6SJakub Kruzik   PetscBool             merge;
228c8613bfSJakub Kruzik   MatCompositeMergeType mergetype;
233b35acafSJakub Kruzik   MatStructure          structure;
2403049c21SJunchao Zhang 
2503049c21SJunchao Zhang   PetscScalar *scalings;
2603049c21SJunchao Zhang   PetscBool    merge_mvctx; /* Whether need to merge mvctx of component matrices */
2703049c21SJunchao Zhang   Vec         *lvecs;       /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
2803049c21SJunchao Zhang   PetscScalar *larray;      /* [len] Data arrays of lvecs[] are stored consecutively in larray */
2903049c21SJunchao Zhang   PetscInt     len;         /* Length of larray[] */
3003049c21SJunchao Zhang   Vec          gvec;        /* Union of lvecs[] without duplicated entries */
3103049c21SJunchao Zhang   PetscInt    *location;    /* A map that maps entries in garray[] to larray[] */
3203049c21SJunchao Zhang   VecScatter   Mvctx;
33793850ffSBarry Smith } Mat_Composite;
34793850ffSBarry Smith 
35d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_Composite(Mat mat)
36d71ae5a4SJacob Faibussowitsch {
372c33bbaeSSatish Balay   Mat_Composite    *shell = (Mat_Composite *)mat->data;
386d7c1e57SBarry Smith   Mat_CompositeLink next  = shell->head, oldnext;
3903049c21SJunchao Zhang   PetscInt          i;
40793850ffSBarry Smith 
41793850ffSBarry Smith   PetscFunctionBegin;
42793850ffSBarry Smith   while (next) {
439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&next->mat));
4448a46eb9SPierre Jolivet     if (next->work && (!next->next || next->work != next->next->work)) PetscCall(VecDestroy(&next->work));
456d7c1e57SBarry Smith     oldnext = next;
46793850ffSBarry Smith     next    = next->next;
479566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldnext));
48793850ffSBarry Smith   }
499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->work));
509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->leftwork));
539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->rightwork));
549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->leftwork2));
559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->rightwork2));
5603049c21SJunchao Zhang 
5703049c21SJunchao Zhang   if (shell->Mvctx) {
589566063dSJacob Faibussowitsch     for (i = 0; i < shell->nmat; i++) PetscCall(VecDestroy(&shell->lvecs[i]));
599566063dSJacob Faibussowitsch     PetscCall(PetscFree3(shell->location, shell->larray, shell->lvecs));
609566063dSJacob Faibussowitsch     PetscCall(PetscFree(shell->larray));
619566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->gvec));
629566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->Mvctx));
6303049c21SJunchao Zhang   }
6403049c21SJunchao Zhang 
659566063dSJacob Faibussowitsch   PetscCall(PetscFree(shell->scalings));
662e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeAddMat_C", NULL));
672e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetType_C", NULL));
682e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetType_C", NULL));
692e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMergeType_C", NULL));
702e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMatStructure_C", NULL));
712e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMatStructure_C", NULL));
722e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeMerge_C", NULL));
732e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetNumberMat_C", NULL));
742e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMat_C", NULL));
752e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetScalings_C", NULL));
769566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
78793850ffSBarry Smith }
79793850ffSBarry Smith 
80d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_Composite_Multiplicative(Mat A, Vec x, Vec y)
81d71ae5a4SJacob Faibussowitsch {
826d7c1e57SBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
836d7c1e57SBarry Smith   Mat_CompositeLink next  = shell->head;
846d7c1e57SBarry Smith   Vec               in, out;
8503049c21SJunchao Zhang   PetscScalar       scale;
8603049c21SJunchao Zhang   PetscInt          i;
876d7c1e57SBarry Smith 
886d7c1e57SBarry Smith   PetscFunctionBegin;
8928b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
906d7c1e57SBarry Smith   in = x;
91e4fc5df0SBarry Smith   if (shell->right) {
9248a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
939566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
94e4fc5df0SBarry Smith     in = shell->rightwork;
95e4fc5df0SBarry Smith   }
966d7c1e57SBarry Smith   while (next->next) {
976d7c1e57SBarry Smith     if (!next->work) { /* should reuse previous work if the same size */
989566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(next->mat, NULL, &next->work));
996d7c1e57SBarry Smith     }
1006d7c1e57SBarry Smith     out = next->work;
1019566063dSJacob Faibussowitsch     PetscCall(MatMult(next->mat, in, out));
1026d7c1e57SBarry Smith     in   = out;
1036d7c1e57SBarry Smith     next = next->next;
1046d7c1e57SBarry Smith   }
1059566063dSJacob Faibussowitsch   PetscCall(MatMult(next->mat, in, y));
1061baa6e33SBarry Smith   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
10703049c21SJunchao Zhang   scale = shell->scale;
1089371c9d4SSatish Balay   if (shell->scalings) {
1099371c9d4SSatish Balay     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
1109371c9d4SSatish Balay   }
1119566063dSJacob Faibussowitsch   PetscCall(VecScale(y, scale));
1123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1136d7c1e57SBarry Smith }
1146d7c1e57SBarry Smith 
115d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A, Vec x, Vec y)
116d71ae5a4SJacob Faibussowitsch {
1176d7c1e57SBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
1186d7c1e57SBarry Smith   Mat_CompositeLink tail  = shell->tail;
1196d7c1e57SBarry Smith   Vec               in, out;
12003049c21SJunchao Zhang   PetscScalar       scale;
12103049c21SJunchao Zhang   PetscInt          i;
1226d7c1e57SBarry Smith 
1236d7c1e57SBarry Smith   PetscFunctionBegin;
12428b400f6SJacob Faibussowitsch   PetscCheck(tail, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
1256d7c1e57SBarry Smith   in = x;
126e4fc5df0SBarry Smith   if (shell->left) {
12748a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
1289566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
129e4fc5df0SBarry Smith     in = shell->leftwork;
130e4fc5df0SBarry Smith   }
1316d7c1e57SBarry Smith   while (tail->prev) {
1326d7c1e57SBarry Smith     if (!tail->prev->work) { /* should reuse previous work if the same size */
1339566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(tail->mat, NULL, &tail->prev->work));
1346d7c1e57SBarry Smith     }
1356d7c1e57SBarry Smith     out = tail->prev->work;
1369566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(tail->mat, in, out));
1376d7c1e57SBarry Smith     in   = out;
1386d7c1e57SBarry Smith     tail = tail->prev;
1396d7c1e57SBarry Smith   }
1409566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(tail->mat, in, y));
1411baa6e33SBarry Smith   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
14203049c21SJunchao Zhang 
14303049c21SJunchao Zhang   scale = shell->scale;
1449371c9d4SSatish Balay   if (shell->scalings) {
1459371c9d4SSatish Balay     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
1469371c9d4SSatish Balay   }
1479566063dSJacob Faibussowitsch   PetscCall(VecScale(y, scale));
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1496d7c1e57SBarry Smith }
1506d7c1e57SBarry Smith 
151d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_Composite(Mat mat, Vec x, Vec y)
152d71ae5a4SJacob Faibussowitsch {
15303049c21SJunchao Zhang   Mat_Composite     *shell = (Mat_Composite *)mat->data;
15403049c21SJunchao Zhang   Mat_CompositeLink  cur   = shell->head;
15503049c21SJunchao Zhang   Vec                in, y2, xin;
15603049c21SJunchao Zhang   Mat                A, B;
15703049c21SJunchao Zhang   PetscInt           i, j, k, n, nuniq, lo, hi, mid, *gindices, *buf, *tmp, tot;
15803049c21SJunchao Zhang   const PetscScalar *vals;
15903049c21SJunchao Zhang   const PetscInt    *garray;
16003049c21SJunchao Zhang   IS                 ix, iy;
16103049c21SJunchao Zhang   PetscBool          match;
162793850ffSBarry Smith 
163793850ffSBarry Smith   PetscFunctionBegin;
16428b400f6SJacob Faibussowitsch   PetscCheck(cur, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
165e4fc5df0SBarry Smith   in = x;
166e4fc5df0SBarry Smith   if (shell->right) {
16748a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
1689566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
169e4fc5df0SBarry Smith     in = shell->rightwork;
170e4fc5df0SBarry Smith   }
17103049c21SJunchao Zhang 
17203049c21SJunchao Zhang   /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
17303049c21SJunchao Zhang      we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
17403049c21SJunchao Zhang      it is legal to merge Mvctx, because all component matrices have the same size.
17503049c21SJunchao Zhang    */
17603049c21SJunchao Zhang   if (shell->merge_mvctx && !shell->Mvctx) {
17703049c21SJunchao Zhang     /* Currently only implemented for MATMPIAIJ */
17803049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
1799566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)cur->mat, MATMPIAIJ, &match));
18003049c21SJunchao Zhang       if (!match) {
18103049c21SJunchao Zhang         shell->merge_mvctx = PETSC_FALSE;
18203049c21SJunchao Zhang         goto skip_merge_mvctx;
183e4fc5df0SBarry Smith       }
184e4fc5df0SBarry Smith     }
18503049c21SJunchao Zhang 
18603049c21SJunchao Zhang     /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
18703049c21SJunchao Zhang     tot = 0;
18803049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
1899566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, NULL));
1909566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
19103049c21SJunchao Zhang       tot += n;
19203049c21SJunchao Zhang     }
1939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(tot, &shell->location, tot, &shell->larray, shell->nmat, &shell->lvecs));
19403049c21SJunchao Zhang     shell->len = tot;
19503049c21SJunchao Zhang 
19603049c21SJunchao Zhang     /* Go through matrices second time to sort off-diag columns and remove dups */
1979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(tot, &gindices)); /* No Malloc2() since we will give one to petsc and free the other */
1989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(tot, &buf));
19903049c21SJunchao Zhang     nuniq = 0; /* Number of unique nonzero columns */
20003049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
2019566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
2029566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
20303049c21SJunchao Zhang       /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
20403049c21SJunchao Zhang       i = j = k = 0;
20503049c21SJunchao Zhang       while (i < n && j < nuniq) {
20603049c21SJunchao Zhang         if (garray[i] < gindices[j]) buf[k++] = garray[i++];
20703049c21SJunchao Zhang         else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
2089371c9d4SSatish Balay         else {
2099371c9d4SSatish Balay           buf[k++] = garray[i++];
2109371c9d4SSatish Balay           j++;
2119371c9d4SSatish Balay         }
21203049c21SJunchao Zhang       }
21303049c21SJunchao Zhang       /* Copy leftover in garray[] or gindices[] */
21403049c21SJunchao Zhang       if (i < n) {
2159566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(buf + k, garray + i, n - i));
21603049c21SJunchao Zhang         nuniq = k + n - i;
21703049c21SJunchao Zhang       } else if (j < nuniq) {
2189566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(buf + k, gindices + j, nuniq - j));
21903049c21SJunchao Zhang         nuniq = k + nuniq - j;
22003049c21SJunchao Zhang       } else nuniq = k;
22103049c21SJunchao Zhang       /* Swap gindices and buf to merge garray of the next matrix */
22203049c21SJunchao Zhang       tmp      = gindices;
22303049c21SJunchao Zhang       gindices = buf;
22403049c21SJunchao Zhang       buf      = tmp;
22503049c21SJunchao Zhang     }
2269566063dSJacob Faibussowitsch     PetscCall(PetscFree(buf));
22703049c21SJunchao Zhang 
22803049c21SJunchao Zhang     /* Go through matrices third time to build a map from gindices[] to garray[] */
22903049c21SJunchao Zhang     tot = 0;
23003049c21SJunchao Zhang     for (cur = shell->head, j = 0; cur; cur = cur->next, j++) { /* j-th matrix */
2319566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
2329566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
2339566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, n, NULL, &shell->lvecs[j]));
23403049c21SJunchao Zhang       /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
23503049c21SJunchao Zhang       lo = 0;
23603049c21SJunchao Zhang       for (i = 0; i < n; i++) {
23703049c21SJunchao Zhang         hi = nuniq;
23803049c21SJunchao Zhang         while (hi - lo > 1) {
23903049c21SJunchao Zhang           mid = lo + (hi - lo) / 2;
24003049c21SJunchao Zhang           if (garray[i] < gindices[mid]) hi = mid;
24103049c21SJunchao Zhang           else lo = mid;
24203049c21SJunchao Zhang         }
24303049c21SJunchao Zhang         shell->location[tot + i] = lo; /* gindices[lo] = garray[i] */
24403049c21SJunchao Zhang         lo++;                          /* Since garray[i+1] > garray[i], we can safely advance lo */
24503049c21SJunchao Zhang       }
24603049c21SJunchao Zhang       tot += n;
24703049c21SJunchao Zhang     }
24803049c21SJunchao Zhang 
24903049c21SJunchao Zhang     /* Build merged Mvctx */
2509566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nuniq, gindices, PETSC_OWN_POINTER, &ix));
2519566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, nuniq, 0, 1, &iy));
2529566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &xin));
2539566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, nuniq, &shell->gvec));
2549566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(xin, ix, shell->gvec, iy, &shell->Mvctx));
2559566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xin));
2569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ix));
2579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&iy));
25803049c21SJunchao Zhang   }
25903049c21SJunchao Zhang 
26003049c21SJunchao Zhang skip_merge_mvctx:
2619566063dSJacob Faibussowitsch   PetscCall(VecSet(y, 0));
2629566063dSJacob Faibussowitsch   if (!shell->leftwork2) PetscCall(VecDuplicate(y, &shell->leftwork2));
26303049c21SJunchao Zhang   y2 = shell->leftwork2;
26403049c21SJunchao Zhang 
26503049c21SJunchao Zhang   if (shell->Mvctx) { /* Have a merged Mvctx */
26603049c21SJunchao Zhang     /* Suppose we want to compute y = sMx, where s is the scaling factor and A, B are matrix M's diagonal/off-diagonal part. We could do
267da81f932SPierre Jolivet        in y = s(Ax1 + Bx2) or y = sAx1 + sBx2. The former incurs less FLOPS than the latter, but the latter provides an opportunity to
26803049c21SJunchao Zhang        overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
26903049c21SJunchao Zhang      */
2709566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
2719566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
27203049c21SJunchao Zhang 
2739566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->gvec, &vals));
27403049c21SJunchao Zhang     for (i = 0; i < shell->len; i++) shell->larray[i] = vals[shell->location[i]];
2759566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->gvec, &vals));
27603049c21SJunchao Zhang 
27703049c21SJunchao Zhang     for (cur = shell->head, tot = i = 0; cur; cur = cur->next, i++) { /* i-th matrix */
2789566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, &A, &B, NULL));
279dbbe0bcdSBarry Smith       PetscUseTypeMethod(A, mult, in, y2);
2809566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
2819566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(shell->lvecs[i], &shell->larray[tot]));
2829566063dSJacob Faibussowitsch       PetscCall((*B->ops->multadd)(B, shell->lvecs[i], y2, y2));
2839566063dSJacob Faibussowitsch       PetscCall(VecResetArray(shell->lvecs[i]));
2849566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, (shell->scalings ? shell->scalings[i] : 1.0), y2));
28503049c21SJunchao Zhang       tot += n;
28603049c21SJunchao Zhang     }
28703049c21SJunchao Zhang   } else {
28803049c21SJunchao Zhang     if (shell->scalings) {
28903049c21SJunchao Zhang       for (cur = shell->head, i = 0; cur; cur = cur->next, i++) {
2909566063dSJacob Faibussowitsch         PetscCall(MatMult(cur->mat, in, y2));
2919566063dSJacob Faibussowitsch         PetscCall(VecAXPY(y, shell->scalings[i], y2));
29203049c21SJunchao Zhang       }
29303049c21SJunchao Zhang     } else {
2949566063dSJacob Faibussowitsch       for (cur = shell->head; cur; cur = cur->next) PetscCall(MatMultAdd(cur->mat, in, y, y));
29503049c21SJunchao Zhang     }
29603049c21SJunchao Zhang   }
29703049c21SJunchao Zhang 
2989566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
2999566063dSJacob Faibussowitsch   PetscCall(VecScale(y, shell->scale));
3003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
301793850ffSBarry Smith }
302793850ffSBarry Smith 
303d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultTranspose_Composite(Mat A, Vec x, Vec y)
304d71ae5a4SJacob Faibussowitsch {
305793850ffSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
306793850ffSBarry Smith   Mat_CompositeLink next  = shell->head;
30703049c21SJunchao Zhang   Vec               in, y2 = NULL;
30803049c21SJunchao Zhang   PetscInt          i;
309793850ffSBarry Smith 
310793850ffSBarry Smith   PetscFunctionBegin;
31128b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
312e4fc5df0SBarry Smith   in = x;
313e4fc5df0SBarry Smith   if (shell->left) {
31448a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
3159566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
316e4fc5df0SBarry Smith     in = shell->leftwork;
317e4fc5df0SBarry Smith   }
31803049c21SJunchao Zhang 
3199566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(next->mat, in, y));
32003049c21SJunchao Zhang   if (shell->scalings) {
3219566063dSJacob Faibussowitsch     PetscCall(VecScale(y, shell->scalings[0]));
3229566063dSJacob Faibussowitsch     if (!shell->rightwork2) PetscCall(VecDuplicate(y, &shell->rightwork2));
32303049c21SJunchao Zhang     y2 = shell->rightwork2;
32403049c21SJunchao Zhang   }
32503049c21SJunchao Zhang   i = 1;
326e4fc5df0SBarry Smith   while ((next = next->next)) {
3279566063dSJacob Faibussowitsch     if (!shell->scalings) PetscCall(MatMultTransposeAdd(next->mat, in, y, y));
32803049c21SJunchao Zhang     else {
3299566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(next->mat, in, y2));
3309566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, shell->scalings[i++], y2));
33103049c21SJunchao Zhang     }
332e4fc5df0SBarry Smith   }
3331baa6e33SBarry Smith   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
3349566063dSJacob Faibussowitsch   PetscCall(VecScale(y, shell->scale));
3353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
336793850ffSBarry Smith }
337793850ffSBarry Smith 
338d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultAdd_Composite(Mat A, Vec x, Vec y, Vec z)
339d71ae5a4SJacob Faibussowitsch {
3407bf3a71bSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)A->data;
3417bf3a71bSJakub Kruzik 
3427bf3a71bSJakub Kruzik   PetscFunctionBegin;
3437bf3a71bSJakub Kruzik   if (y != z) {
3449566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
3459566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
3467bf3a71bSJakub Kruzik   } else {
34748a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(z, &shell->leftwork));
3489566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->leftwork));
3499566063dSJacob Faibussowitsch     PetscCall(VecCopy(y, z));
3509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->leftwork));
3517bf3a71bSJakub Kruzik   }
3523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3537bf3a71bSJakub Kruzik }
3547bf3a71bSJakub Kruzik 
355d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultTransposeAdd_Composite(Mat A, Vec x, Vec y, Vec z)
356d71ae5a4SJacob Faibussowitsch {
3577bf3a71bSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)A->data;
3587bf3a71bSJakub Kruzik 
3597bf3a71bSJakub Kruzik   PetscFunctionBegin;
3607bf3a71bSJakub Kruzik   if (y != z) {
3619566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
3629566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
3637bf3a71bSJakub Kruzik   } else {
36448a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(z, &shell->rightwork));
3659566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->rightwork));
3669566063dSJacob Faibussowitsch     PetscCall(VecCopy(y, z));
3679566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->rightwork));
3687bf3a71bSJakub Kruzik   }
3693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3707bf3a71bSJakub Kruzik }
3717bf3a71bSJakub Kruzik 
372d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetDiagonal_Composite(Mat A, Vec v)
373d71ae5a4SJacob Faibussowitsch {
374793850ffSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
375793850ffSBarry Smith   Mat_CompositeLink next  = shell->head;
37603049c21SJunchao Zhang   PetscInt          i;
377793850ffSBarry Smith 
378793850ffSBarry Smith   PetscFunctionBegin;
37928b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
38008401ef6SPierre Jolivet   PetscCheck(!shell->right && !shell->left, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get diagonal if left or right scaling");
381e4fc5df0SBarry Smith 
3829566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(next->mat, v));
3839566063dSJacob Faibussowitsch   if (shell->scalings) PetscCall(VecScale(v, shell->scalings[0]));
38403049c21SJunchao Zhang 
38548a46eb9SPierre Jolivet   if (next->next && !shell->work) PetscCall(VecDuplicate(v, &shell->work));
38603049c21SJunchao Zhang   i = 1;
387793850ffSBarry Smith   while ((next = next->next)) {
3889566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(next->mat, shell->work));
3899566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, (shell->scalings ? shell->scalings[i++] : 1.0), shell->work));
390793850ffSBarry Smith   }
3919566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->scale));
3923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
393793850ffSBarry Smith }
394793850ffSBarry Smith 
395d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_Composite(Mat Y, MatAssemblyType t)
396d71ae5a4SJacob Faibussowitsch {
3974b2558d6SJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)Y->data;
398b52f573bSBarry Smith 
399793850ffSBarry Smith   PetscFunctionBegin;
4001baa6e33SBarry Smith   if (shell->merge) PetscCall(MatCompositeMerge(Y));
4013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
402793850ffSBarry Smith }
403793850ffSBarry Smith 
404d71ae5a4SJacob Faibussowitsch PetscErrorCode MatScale_Composite(Mat inA, PetscScalar alpha)
405d71ae5a4SJacob Faibussowitsch {
406e4fc5df0SBarry Smith   Mat_Composite *a = (Mat_Composite *)inA->data;
407e4fc5df0SBarry Smith 
408e4fc5df0SBarry Smith   PetscFunctionBegin;
409321429dbSBarry Smith   a->scale *= alpha;
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
411e4fc5df0SBarry Smith }
412e4fc5df0SBarry Smith 
413d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalScale_Composite(Mat inA, Vec left, Vec right)
414d71ae5a4SJacob Faibussowitsch {
415e4fc5df0SBarry Smith   Mat_Composite *a = (Mat_Composite *)inA->data;
416e4fc5df0SBarry Smith 
417e4fc5df0SBarry Smith   PetscFunctionBegin;
418e4fc5df0SBarry Smith   if (left) {
419321429dbSBarry Smith     if (!a->left) {
4209566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &a->left));
4219566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, a->left));
422321429dbSBarry Smith     } else {
4239566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(a->left, left, a->left));
424321429dbSBarry Smith     }
425e4fc5df0SBarry Smith   }
426e4fc5df0SBarry Smith   if (right) {
427321429dbSBarry Smith     if (!a->right) {
4289566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &a->right));
4299566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, a->right));
430321429dbSBarry Smith     } else {
4319566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(a->right, right, a->right));
432321429dbSBarry Smith     }
433e4fc5df0SBarry Smith   }
4343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
435e4fc5df0SBarry Smith }
436793850ffSBarry Smith 
437d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetFromOptions_Composite(Mat A, PetscOptionItems *PetscOptionsObject)
438d71ae5a4SJacob Faibussowitsch {
4394b2558d6SJakub Kruzik   Mat_Composite *a = (Mat_Composite *)A->data;
4404b2558d6SJakub Kruzik 
4414b2558d6SJakub Kruzik   PetscFunctionBegin;
442d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATCOMPOSITE options");
4439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_composite_merge", "Merge at MatAssemblyEnd", "MatCompositeMerge", a->merge, &a->merge, NULL));
4449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-mat_composite_merge_type", "Set composite merge direction", "MatCompositeSetMergeType", MatCompositeMergeTypes, (PetscEnum)a->mergetype, (PetscEnum *)&a->mergetype, NULL));
4459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_composite_merge_mvctx", "Merge MatMult() vecscat contexts", "MatCreateComposite", a->merge_mvctx, &a->merge_mvctx, NULL));
446d0609cedSBarry Smith   PetscOptionsHeadEnd();
4473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4484b2558d6SJakub Kruzik }
4494b2558d6SJakub Kruzik 
4502c0821f3SBarry Smith /*@
4518bd739bdSJakub Kruzik    MatCreateComposite - Creates a matrix as the sum or product of one or more matrices
452793850ffSBarry Smith 
453d083f849SBarry Smith   Collective
454793850ffSBarry Smith 
455793850ffSBarry Smith    Input Parameters:
456793850ffSBarry Smith +  comm - MPI communicator
457793850ffSBarry Smith .  nmat - number of matrices to put in
458793850ffSBarry Smith -  mats - the matrices
459793850ffSBarry Smith 
460793850ffSBarry Smith    Output Parameter:
461db36af27SMatthew G. Knepley .  mat - the matrix
462793850ffSBarry Smith 
4634b2558d6SJakub Kruzik    Options Database Keys:
46411a5261eSBarry Smith +  -mat_composite_merge         - merge in `MatAssemblyEnd()`
46511a5261eSBarry Smith .  -mat_composite_merge_mvctx   - merge Mvctx of component matrices to optimize communication in `MatMult()` for ADDITIVE matrices
466b28d0daaSJakub Kruzik -  -mat_composite_merge_type    - set merge direction
4674b2558d6SJakub Kruzik 
468793850ffSBarry Smith    Level: advanced
469793850ffSBarry Smith 
47011a5261eSBarry Smith    Note:
471793850ffSBarry Smith      Alternative construction
4722ef1f0ffSBarry Smith .vb
4732ef1f0ffSBarry Smith        MatCreate(comm,&mat);
4742ef1f0ffSBarry Smith        MatSetSizes(mat,m,n,M,N);
4752ef1f0ffSBarry Smith        MatSetType(mat,MATCOMPOSITE);
4762ef1f0ffSBarry Smith        MatCompositeAddMat(mat,mats[0]);
4772ef1f0ffSBarry Smith        ....
4782ef1f0ffSBarry Smith        MatCompositeAddMat(mat,mats[nmat-1]);
4792ef1f0ffSBarry Smith        MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
4802ef1f0ffSBarry Smith        MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
4812ef1f0ffSBarry Smith .ve
482793850ffSBarry Smith 
4836d7c1e57SBarry Smith      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
4846d7c1e57SBarry Smith 
485*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCompositeGetMat()`, `MatCompositeMerge()`, `MatCompositeSetType()`,
48620f4b53cSBarry Smith           `MATCOMPOSITE`, `MatCompositeType`
487793850ffSBarry Smith @*/
488d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateComposite(MPI_Comm comm, PetscInt nmat, const Mat *mats, Mat *mat)
489d71ae5a4SJacob Faibussowitsch {
490793850ffSBarry Smith   PetscInt m, n, M, N, i;
491793850ffSBarry Smith 
492793850ffSBarry Smith   PetscFunctionBegin;
49308401ef6SPierre Jolivet   PetscCheck(nmat >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must pass in at least one matrix");
494064a246eSJacob Faibussowitsch   PetscValidPointer(mat, 4);
495793850ffSBarry Smith 
4969566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mats[0], PETSC_IGNORE, &n));
4979566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mats[nmat - 1], &m, PETSC_IGNORE));
4989566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mats[0], PETSC_IGNORE, &N));
4999566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mats[nmat - 1], &M, PETSC_IGNORE));
5009566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, mat));
5019566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mat, m, n, M, N));
5029566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mat, MATCOMPOSITE));
50348a46eb9SPierre Jolivet   for (i = 0; i < nmat; i++) PetscCall(MatCompositeAddMat(*mat, mats[i]));
5049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5059566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
507793850ffSBarry Smith }
508793850ffSBarry Smith 
509d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeAddMat_Composite(Mat mat, Mat smat)
510d71ae5a4SJacob Faibussowitsch {
511d7f81bf2SJakub Kruzik   Mat_Composite    *shell = (Mat_Composite *)mat->data;
512d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink, next = shell->head;
513d7f81bf2SJakub Kruzik 
514d7f81bf2SJakub Kruzik   PetscFunctionBegin;
5154dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
516f4259b30SLisandro Dalcin   ilink->next = NULL;
5179566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)smat));
518d7f81bf2SJakub Kruzik   ilink->mat = smat;
519d7f81bf2SJakub Kruzik 
520d7f81bf2SJakub Kruzik   if (!next) shell->head = ilink;
521d7f81bf2SJakub Kruzik   else {
522ad540459SPierre Jolivet     while (next->next) next = next->next;
523d7f81bf2SJakub Kruzik     next->next  = ilink;
524d7f81bf2SJakub Kruzik     ilink->prev = next;
525d7f81bf2SJakub Kruzik   }
526d7f81bf2SJakub Kruzik   shell->tail = ilink;
527d7f81bf2SJakub Kruzik   shell->nmat += 1;
52803049c21SJunchao Zhang 
52903049c21SJunchao Zhang   /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
53003049c21SJunchao Zhang   if (shell->scalings) {
5319566063dSJacob Faibussowitsch     PetscCall(PetscRealloc(sizeof(PetscScalar) * shell->nmat, &shell->scalings));
53203049c21SJunchao Zhang     shell->scalings[shell->nmat - 1] = 1.0;
53303049c21SJunchao Zhang   }
5343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
535d7f81bf2SJakub Kruzik }
536d7f81bf2SJakub Kruzik 
537793850ffSBarry Smith /*@
5388bd739bdSJakub Kruzik     MatCompositeAddMat - Add another matrix to a composite matrix.
539793850ffSBarry Smith 
540c3339decSBarry Smith    Collective
541793850ffSBarry Smith 
542793850ffSBarry Smith     Input Parameters:
543793850ffSBarry Smith +   mat - the composite matrix
544793850ffSBarry Smith -   smat - the partial matrix
545793850ffSBarry Smith 
546793850ffSBarry Smith    Level: advanced
547793850ffSBarry Smith 
548*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
549793850ffSBarry Smith @*/
550d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeAddMat(Mat mat, Mat smat)
551d71ae5a4SJacob Faibussowitsch {
552793850ffSBarry Smith   PetscFunctionBegin;
5530700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5540700a824SBarry Smith   PetscValidHeaderSpecific(smat, MAT_CLASSID, 2);
555cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeAddMat_C", (Mat, Mat), (mat, smat));
5563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
557d7f81bf2SJakub Kruzik }
558793850ffSBarry Smith 
559d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetType_Composite(Mat mat, MatCompositeType type)
560d71ae5a4SJacob Faibussowitsch {
561d7f81bf2SJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
562d7f81bf2SJakub Kruzik 
563d7f81bf2SJakub Kruzik   PetscFunctionBegin;
564ced1ac25SJakub Kruzik   b->type = type;
565d7f81bf2SJakub Kruzik   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
566f4259b30SLisandro Dalcin     mat->ops->getdiagonal   = NULL;
567d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite_Multiplicative;
568d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
56903049c21SJunchao Zhang     b->merge_mvctx          = PETSC_FALSE;
570d7f81bf2SJakub Kruzik   } else {
571d7f81bf2SJakub Kruzik     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
572d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite;
573d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite;
574793850ffSBarry Smith   }
5753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5766d7c1e57SBarry Smith }
5776d7c1e57SBarry Smith 
5782c0821f3SBarry Smith /*@
5798bd739bdSJakub Kruzik    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.
5806d7c1e57SBarry Smith 
581c3339decSBarry Smith    Logically Collective
5826d7c1e57SBarry Smith 
5836d7c1e57SBarry Smith    Input Parameters:
58420f4b53cSBarry Smith +  mat - the composite matrix
58520f4b53cSBarry Smith -  type - the `MatCompositeType` to use for the matrix
5866d7c1e57SBarry Smith 
5876d7c1e57SBarry Smith    Level: advanced
5886d7c1e57SBarry Smith 
589*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeGetType()`, `MATCOMPOSITE`,
59020f4b53cSBarry Smith           `MatCompositeType`
5916d7c1e57SBarry Smith @*/
592d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetType(Mat mat, MatCompositeType type)
593d71ae5a4SJacob Faibussowitsch {
5946d7c1e57SBarry Smith   PetscFunctionBegin;
595d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
596b2b245abSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat, type, 2);
597cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetType_C", (Mat, MatCompositeType), (mat, type));
5983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
599793850ffSBarry Smith }
600793850ffSBarry Smith 
601d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetType_Composite(Mat mat, MatCompositeType *type)
602d71ae5a4SJacob Faibussowitsch {
6036dbc55e5SJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6046dbc55e5SJakub Kruzik 
6056dbc55e5SJakub Kruzik   PetscFunctionBegin;
6066dbc55e5SJakub Kruzik   *type = b->type;
6073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6086dbc55e5SJakub Kruzik }
6096dbc55e5SJakub Kruzik 
6106dbc55e5SJakub Kruzik /*@
6116dbc55e5SJakub Kruzik    MatCompositeGetType - Returns type of composite.
6126dbc55e5SJakub Kruzik 
6136dbc55e5SJakub Kruzik    Not Collective
6146dbc55e5SJakub Kruzik 
6156dbc55e5SJakub Kruzik    Input Parameter:
6166dbc55e5SJakub Kruzik .  mat - the composite matrix
6176dbc55e5SJakub Kruzik 
6186dbc55e5SJakub Kruzik    Output Parameter:
6196dbc55e5SJakub Kruzik .  type - type of composite
6206dbc55e5SJakub Kruzik 
6216dbc55e5SJakub Kruzik    Level: advanced
6226dbc55e5SJakub Kruzik 
623*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetType()`, `MATCOMPOSITE`, `MatCompositeType`
6246dbc55e5SJakub Kruzik @*/
625d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetType(Mat mat, MatCompositeType *type)
626d71ae5a4SJacob Faibussowitsch {
6276dbc55e5SJakub Kruzik   PetscFunctionBegin;
6286dbc55e5SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6296dbc55e5SJakub Kruzik   PetscValidPointer(type, 2);
630cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetType_C", (Mat, MatCompositeType *), (mat, type));
6313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6326dbc55e5SJakub Kruzik }
6336dbc55e5SJakub Kruzik 
634d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat, MatStructure str)
635d71ae5a4SJacob Faibussowitsch {
6363b35acafSJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6373b35acafSJakub Kruzik 
6383b35acafSJakub Kruzik   PetscFunctionBegin;
6393b35acafSJakub Kruzik   b->structure = str;
6403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6413b35acafSJakub Kruzik }
6423b35acafSJakub Kruzik 
6433b35acafSJakub Kruzik /*@
6443b35acafSJakub Kruzik    MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.
6453b35acafSJakub Kruzik 
6463b35acafSJakub Kruzik    Not Collective
6473b35acafSJakub Kruzik 
6483b35acafSJakub Kruzik    Input Parameters:
6493b35acafSJakub Kruzik +  mat - the composite matrix
65011a5261eSBarry Smith -  str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN` (default) or `SUBSET_NONZERO_PATTERN`
6513b35acafSJakub Kruzik 
6523b35acafSJakub Kruzik    Level: advanced
6533b35acafSJakub Kruzik 
65411a5261eSBarry Smith    Note:
65511a5261eSBarry Smith     Information about the matrices structure is used in `MatCompositeMerge()` for additive composite matrix.
6563b35acafSJakub Kruzik 
657*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAXPY()`, `MatCreateComposite()`, `MatCompositeMerge()` `MatCompositeGetMatStructure()`, `MATCOMPOSITE`
6583b35acafSJakub Kruzik @*/
659d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetMatStructure(Mat mat, MatStructure str)
660d71ae5a4SJacob Faibussowitsch {
6613b35acafSJakub Kruzik   PetscFunctionBegin;
6623b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
663cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetMatStructure_C", (Mat, MatStructure), (mat, str));
6643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6653b35acafSJakub Kruzik }
6663b35acafSJakub Kruzik 
667d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat, MatStructure *str)
668d71ae5a4SJacob Faibussowitsch {
6693b35acafSJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6703b35acafSJakub Kruzik 
6713b35acafSJakub Kruzik   PetscFunctionBegin;
6723b35acafSJakub Kruzik   *str = b->structure;
6733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6743b35acafSJakub Kruzik }
6753b35acafSJakub Kruzik 
6763b35acafSJakub Kruzik /*@
6773b35acafSJakub Kruzik    MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.
6783b35acafSJakub Kruzik 
6793b35acafSJakub Kruzik    Not Collective
6803b35acafSJakub Kruzik 
6813b35acafSJakub Kruzik    Input Parameter:
6823b35acafSJakub Kruzik .  mat - the composite matrix
6833b35acafSJakub Kruzik 
6843b35acafSJakub Kruzik    Output Parameter:
6853b35acafSJakub Kruzik .  str - structure of the matrices
6863b35acafSJakub Kruzik 
6873b35acafSJakub Kruzik    Level: advanced
6883b35acafSJakub Kruzik 
689*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MATCOMPOSITE`
6903b35acafSJakub Kruzik @*/
691d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetMatStructure(Mat mat, MatStructure *str)
692d71ae5a4SJacob Faibussowitsch {
6933b35acafSJakub Kruzik   PetscFunctionBegin;
6943b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6953b35acafSJakub Kruzik   PetscValidPointer(str, 2);
696cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetMatStructure_C", (Mat, MatStructure *), (mat, str));
6973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6983b35acafSJakub Kruzik }
6993b35acafSJakub Kruzik 
700d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat, MatCompositeMergeType type)
701d71ae5a4SJacob Faibussowitsch {
7028c8613bfSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)mat->data;
7038c8613bfSJakub Kruzik 
7048c8613bfSJakub Kruzik   PetscFunctionBegin;
7058c8613bfSJakub Kruzik   shell->mergetype = type;
7063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7078c8613bfSJakub Kruzik }
7088c8613bfSJakub Kruzik 
7098c8613bfSJakub Kruzik /*@
71011a5261eSBarry Smith    MatCompositeSetMergeType - Sets order of `MatCompositeMerge()`.
7118c8613bfSJakub Kruzik 
712c3339decSBarry Smith    Logically Collective
7138c8613bfSJakub Kruzik 
714d8d19677SJose E. Roman    Input Parameters:
7158c8613bfSJakub Kruzik +  mat - the composite matrix
71611a5261eSBarry Smith -  type - `MAT_COMPOSITE_MERGE RIGHT` (default) to start merge from right with the first added matrix (mat[0]),
71711a5261eSBarry Smith           `MAT_COMPOSITE_MERGE_LEFT` to start merge from left with the last added matrix (mat[nmat-1])
7188c8613bfSJakub Kruzik 
7198c8613bfSJakub Kruzik    Level: advanced
7208c8613bfSJakub Kruzik 
72111a5261eSBarry Smith    Note:
722da81f932SPierre Jolivet     The resulting matrix is the same regardless of the `MatCompositeMergeType`. Only the order of operation is changed.
72311a5261eSBarry Smith     If set to `MAT_COMPOSITE_MERGE_RIGHT` the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
7248c8613bfSJakub Kruzik     otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].
7258c8613bfSJakub Kruzik 
726*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeMerge()`, `MATCOMPOSITE`
7278c8613bfSJakub Kruzik @*/
728d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetMergeType(Mat mat, MatCompositeMergeType type)
729d71ae5a4SJacob Faibussowitsch {
7308c8613bfSJakub Kruzik   PetscFunctionBegin;
7318c8613bfSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7328c8613bfSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat, type, 2);
733cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetMergeType_C", (Mat, MatCompositeMergeType), (mat, type));
7343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7358c8613bfSJakub Kruzik }
7368c8613bfSJakub Kruzik 
737d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
738d71ae5a4SJacob Faibussowitsch {
739b52f573bSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)mat->data;
7406d7c1e57SBarry Smith   Mat_CompositeLink next = shell->head, prev = shell->tail;
7416d7c1e57SBarry Smith   Mat               tmat, newmat;
7421ba60692SJed Brown   Vec               left, right;
7431ba60692SJed Brown   PetscScalar       scale;
74403049c21SJunchao Zhang   PetscInt          i;
745b52f573bSBarry Smith 
746b52f573bSBarry Smith   PetscFunctionBegin;
74728b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
74803049c21SJunchao Zhang   scale = shell->scale;
7496d7c1e57SBarry Smith   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
7508c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
75103049c21SJunchao Zhang       i = 0;
7529566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
7539566063dSJacob Faibussowitsch       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i++]));
75448a46eb9SPierre Jolivet       while ((next = next->next)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i++] : 1.0), next->mat, shell->structure));
7556d7c1e57SBarry Smith     } else {
75603049c21SJunchao Zhang       i = shell->nmat - 1;
7579566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
7589566063dSJacob Faibussowitsch       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i--]));
75948a46eb9SPierre Jolivet       while ((prev = prev->prev)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i--] : 1.0), prev->mat, shell->structure));
7608c8613bfSJakub Kruzik     }
7618c8613bfSJakub Kruzik   } else {
7628c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
7639566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
764b6cfcaf5SJakub Kruzik       while ((next = next->next)) {
7659566063dSJacob Faibussowitsch         PetscCall(MatMatMult(next->mat, tmat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
7669566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tmat));
7676d7c1e57SBarry Smith         tmat = newmat;
7686d7c1e57SBarry Smith       }
76904d534ceSJakub Kruzik     } else {
7709566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
77104d534ceSJakub Kruzik       while ((prev = prev->prev)) {
7729566063dSJacob Faibussowitsch         PetscCall(MatMatMult(tmat, prev->mat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
7739566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tmat));
77404d534ceSJakub Kruzik         tmat = newmat;
77504d534ceSJakub Kruzik       }
77604d534ceSJakub Kruzik     }
7779371c9d4SSatish Balay     if (shell->scalings) {
7789371c9d4SSatish Balay       for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
7799371c9d4SSatish Balay     }
7806d7c1e57SBarry Smith   }
7811ba60692SJed Brown 
7829566063dSJacob Faibussowitsch   if ((left = shell->left)) PetscCall(PetscObjectReference((PetscObject)left));
7839566063dSJacob Faibussowitsch   if ((right = shell->right)) PetscCall(PetscObjectReference((PetscObject)right));
7841ba60692SJed Brown 
7859566063dSJacob Faibussowitsch   PetscCall(MatHeaderReplace(mat, &tmat));
7861ba60692SJed Brown 
7879566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(mat, left, right));
7889566063dSJacob Faibussowitsch   PetscCall(MatScale(mat, scale));
7899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&left));
7909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&right));
7913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
792b52f573bSBarry Smith }
7936a7ede75SJakub Kruzik 
7946a7ede75SJakub Kruzik /*@
795d7f81bf2SJakub Kruzik    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
7968bd739bdSJakub Kruzik      by summing or computing the product of all the matrices inside the composite matrix.
797d7f81bf2SJakub Kruzik 
798b2b245abSJakub Kruzik   Collective
799d7f81bf2SJakub Kruzik 
800f899ff85SJose E. Roman    Input Parameter:
801d7f81bf2SJakub Kruzik .  mat - the composite matrix
802d7f81bf2SJakub Kruzik 
8034b2558d6SJakub Kruzik    Options Database Keys:
80411a5261eSBarry Smith +  -mat_composite_merge - merge in `MatAssemblyEnd()`
805b28d0daaSJakub Kruzik -  -mat_composite_merge_type - set merge direction
806d7f81bf2SJakub Kruzik 
807d7f81bf2SJakub Kruzik    Level: advanced
808d7f81bf2SJakub Kruzik 
80911a5261eSBarry Smith    Note:
81011a5261eSBarry Smith       The `MatType` of the resulting matrix will be the same as the `MatType` of the FIRST matrix in the composite matrix.
811d7f81bf2SJakub Kruzik 
812*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MatCompositeSetMergeType()`, `MATCOMPOSITE`
813d7f81bf2SJakub Kruzik @*/
814d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeMerge(Mat mat)
815d71ae5a4SJacob Faibussowitsch {
816d7f81bf2SJakub Kruzik   PetscFunctionBegin;
817d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
818cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeMerge_C", (Mat), (mat));
8193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
820d7f81bf2SJakub Kruzik }
821d7f81bf2SJakub Kruzik 
822d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat, PetscInt *nmat)
823d71ae5a4SJacob Faibussowitsch {
824d7f81bf2SJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)mat->data;
825d7f81bf2SJakub Kruzik 
826d7f81bf2SJakub Kruzik   PetscFunctionBegin;
827d7f81bf2SJakub Kruzik   *nmat = shell->nmat;
8283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
829d7f81bf2SJakub Kruzik }
830d7f81bf2SJakub Kruzik 
831d7f81bf2SJakub Kruzik /*@
8326d0add67SJakub Kruzik    MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.
8336a7ede75SJakub Kruzik 
8346a7ede75SJakub Kruzik    Not Collective
8356a7ede75SJakub Kruzik 
8366a7ede75SJakub Kruzik    Input Parameter:
837d7f81bf2SJakub Kruzik .  mat - the composite matrix
8386a7ede75SJakub Kruzik 
8396a7ede75SJakub Kruzik    Output Parameter:
8406d0add67SJakub Kruzik .  nmat - number of matrices in the composite matrix
8416a7ede75SJakub Kruzik 
8428b5c3584SJakub Kruzik    Level: advanced
8436a7ede75SJakub Kruzik 
844*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
8456a7ede75SJakub Kruzik @*/
846d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetNumberMat(Mat mat, PetscInt *nmat)
847d71ae5a4SJacob Faibussowitsch {
8486a7ede75SJakub Kruzik   PetscFunctionBegin;
849d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
850dadcf809SJacob Faibussowitsch   PetscValidIntPointer(nmat, 2);
851cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetNumberMat_C", (Mat, PetscInt *), (mat, nmat));
8523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
853d7f81bf2SJakub Kruzik }
854d7f81bf2SJakub Kruzik 
855d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetMat_Composite(Mat mat, PetscInt i, Mat *Ai)
856d71ae5a4SJacob Faibussowitsch {
857d7f81bf2SJakub Kruzik   Mat_Composite    *shell = (Mat_Composite *)mat->data;
858d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink;
859d7f81bf2SJakub Kruzik   PetscInt          k;
860d7f81bf2SJakub Kruzik 
861d7f81bf2SJakub Kruzik   PetscFunctionBegin;
86208401ef6SPierre Jolivet   PetscCheck(i < shell->nmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "index out of range: %" PetscInt_FMT " >= %" PetscInt_FMT, i, shell->nmat);
863d7f81bf2SJakub Kruzik   ilink = shell->head;
864ad540459SPierre Jolivet   for (k = 0; k < i; k++) ilink = ilink->next;
865d7f81bf2SJakub Kruzik   *Ai = ilink->mat;
8663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8676a7ede75SJakub Kruzik }
8686a7ede75SJakub Kruzik 
8698b5c3584SJakub Kruzik /*@
8708bd739bdSJakub Kruzik    MatCompositeGetMat - Returns the ith matrix from the composite matrix.
8718b5c3584SJakub Kruzik 
872c3339decSBarry Smith    Logically Collective
8738b5c3584SJakub Kruzik 
874d8d19677SJose E. Roman    Input Parameters:
875d7f81bf2SJakub Kruzik +  mat - the composite matrix
8768b5c3584SJakub Kruzik -  i - the number of requested matrix
8778b5c3584SJakub Kruzik 
8788b5c3584SJakub Kruzik    Output Parameter:
8798b5c3584SJakub Kruzik .  Ai - ith matrix in composite
8808b5c3584SJakub Kruzik 
8818b5c3584SJakub Kruzik    Level: advanced
8828b5c3584SJakub Kruzik 
883*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetNumberMat()`, `MatCompositeAddMat()`, `MATCOMPOSITE`
8848b5c3584SJakub Kruzik @*/
885d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetMat(Mat mat, PetscInt i, Mat *Ai)
886d71ae5a4SJacob Faibussowitsch {
8878b5c3584SJakub Kruzik   PetscFunctionBegin;
888d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
889d7f81bf2SJakub Kruzik   PetscValidLogicalCollectiveInt(mat, i, 2);
8908b5c3584SJakub Kruzik   PetscValidPointer(Ai, 3);
891cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetMat_C", (Mat, PetscInt, Mat *), (mat, i, Ai));
8923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8938b5c3584SJakub Kruzik }
8948b5c3584SJakub Kruzik 
895d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetScalings_Composite(Mat mat, const PetscScalar *scalings)
896d71ae5a4SJacob Faibussowitsch {
89703049c21SJunchao Zhang   Mat_Composite *shell = (Mat_Composite *)mat->data;
89803049c21SJunchao Zhang   PetscInt       nmat;
89903049c21SJunchao Zhang 
90003049c21SJunchao Zhang   PetscFunctionBegin;
9019566063dSJacob Faibussowitsch   PetscCall(MatCompositeGetNumberMat(mat, &nmat));
9029566063dSJacob Faibussowitsch   if (!shell->scalings) PetscCall(PetscMalloc1(nmat, &shell->scalings));
9039566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(shell->scalings, scalings, nmat));
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
90503049c21SJunchao Zhang }
90603049c21SJunchao Zhang 
90703049c21SJunchao Zhang /*@
90803049c21SJunchao Zhang    MatCompositeSetScalings - Sets separate scaling factors for component matrices.
90903049c21SJunchao Zhang 
910c3339decSBarry Smith    Logically Collective
91103049c21SJunchao Zhang 
912d8d19677SJose E. Roman    Input Parameters:
91303049c21SJunchao Zhang +  mat      - the composite matrix
91403049c21SJunchao Zhang -  scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)
91503049c21SJunchao Zhang 
91603049c21SJunchao Zhang    Level: advanced
91703049c21SJunchao Zhang 
918*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatDiagonalScale()`, `MATCOMPOSITE`
91903049c21SJunchao Zhang @*/
920d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetScalings(Mat mat, const PetscScalar *scalings)
921d71ae5a4SJacob Faibussowitsch {
92203049c21SJunchao Zhang   PetscFunctionBegin;
92303049c21SJunchao Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
924dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(scalings, 2);
92503049c21SJunchao Zhang   PetscValidLogicalCollectiveScalar(mat, *scalings, 2);
926cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetScalings_C", (Mat, const PetscScalar *), (mat, scalings));
9273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92803049c21SJunchao Zhang }
92903049c21SJunchao Zhang 
930f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
931f4259b30SLisandro Dalcin                                        NULL,
932f4259b30SLisandro Dalcin                                        NULL,
93341cd0125SJakub Kruzik                                        MatMult_Composite,
9347bf3a71bSJakub Kruzik                                        MatMultAdd_Composite,
93541cd0125SJakub Kruzik                                        /*  5*/ MatMultTranspose_Composite,
9367bf3a71bSJakub Kruzik                                        MatMultTransposeAdd_Composite,
937f4259b30SLisandro Dalcin                                        NULL,
938f4259b30SLisandro Dalcin                                        NULL,
939f4259b30SLisandro Dalcin                                        NULL,
940f4259b30SLisandro Dalcin                                        /* 10*/ NULL,
941f4259b30SLisandro Dalcin                                        NULL,
942f4259b30SLisandro Dalcin                                        NULL,
943f4259b30SLisandro Dalcin                                        NULL,
944f4259b30SLisandro Dalcin                                        NULL,
945f4259b30SLisandro Dalcin                                        /* 15*/ NULL,
946f4259b30SLisandro Dalcin                                        NULL,
94741cd0125SJakub Kruzik                                        MatGetDiagonal_Composite,
94841cd0125SJakub Kruzik                                        MatDiagonalScale_Composite,
949f4259b30SLisandro Dalcin                                        NULL,
950f4259b30SLisandro Dalcin                                        /* 20*/ NULL,
95141cd0125SJakub Kruzik                                        MatAssemblyEnd_Composite,
952f4259b30SLisandro Dalcin                                        NULL,
953f4259b30SLisandro Dalcin                                        NULL,
954f4259b30SLisandro Dalcin                                        /* 24*/ NULL,
955f4259b30SLisandro Dalcin                                        NULL,
956f4259b30SLisandro Dalcin                                        NULL,
957f4259b30SLisandro Dalcin                                        NULL,
958f4259b30SLisandro Dalcin                                        NULL,
959f4259b30SLisandro Dalcin                                        /* 29*/ NULL,
960f4259b30SLisandro Dalcin                                        NULL,
961f4259b30SLisandro Dalcin                                        NULL,
962f4259b30SLisandro Dalcin                                        NULL,
963f4259b30SLisandro Dalcin                                        NULL,
964f4259b30SLisandro Dalcin                                        /* 34*/ NULL,
965f4259b30SLisandro Dalcin                                        NULL,
966f4259b30SLisandro Dalcin                                        NULL,
967f4259b30SLisandro Dalcin                                        NULL,
968f4259b30SLisandro Dalcin                                        NULL,
969f4259b30SLisandro Dalcin                                        /* 39*/ NULL,
970f4259b30SLisandro Dalcin                                        NULL,
971f4259b30SLisandro Dalcin                                        NULL,
972f4259b30SLisandro Dalcin                                        NULL,
973f4259b30SLisandro Dalcin                                        NULL,
974f4259b30SLisandro Dalcin                                        /* 44*/ NULL,
97541cd0125SJakub Kruzik                                        MatScale_Composite,
97641cd0125SJakub Kruzik                                        MatShift_Basic,
977f4259b30SLisandro Dalcin                                        NULL,
978f4259b30SLisandro Dalcin                                        NULL,
979f4259b30SLisandro Dalcin                                        /* 49*/ NULL,
980f4259b30SLisandro Dalcin                                        NULL,
981f4259b30SLisandro Dalcin                                        NULL,
982f4259b30SLisandro Dalcin                                        NULL,
983f4259b30SLisandro Dalcin                                        NULL,
984f4259b30SLisandro Dalcin                                        /* 54*/ NULL,
985f4259b30SLisandro Dalcin                                        NULL,
986f4259b30SLisandro Dalcin                                        NULL,
987f4259b30SLisandro Dalcin                                        NULL,
988f4259b30SLisandro Dalcin                                        NULL,
989f4259b30SLisandro Dalcin                                        /* 59*/ NULL,
99041cd0125SJakub Kruzik                                        MatDestroy_Composite,
991f4259b30SLisandro Dalcin                                        NULL,
992f4259b30SLisandro Dalcin                                        NULL,
993f4259b30SLisandro Dalcin                                        NULL,
994f4259b30SLisandro Dalcin                                        /* 64*/ NULL,
995f4259b30SLisandro Dalcin                                        NULL,
996f4259b30SLisandro Dalcin                                        NULL,
997f4259b30SLisandro Dalcin                                        NULL,
998f4259b30SLisandro Dalcin                                        NULL,
999f4259b30SLisandro Dalcin                                        /* 69*/ NULL,
1000f4259b30SLisandro Dalcin                                        NULL,
1001f4259b30SLisandro Dalcin                                        NULL,
1002f4259b30SLisandro Dalcin                                        NULL,
1003f4259b30SLisandro Dalcin                                        NULL,
1004f4259b30SLisandro Dalcin                                        /* 74*/ NULL,
1005f4259b30SLisandro Dalcin                                        NULL,
10064b2558d6SJakub Kruzik                                        MatSetFromOptions_Composite,
1007f4259b30SLisandro Dalcin                                        NULL,
1008f4259b30SLisandro Dalcin                                        NULL,
1009f4259b30SLisandro Dalcin                                        /* 79*/ NULL,
1010f4259b30SLisandro Dalcin                                        NULL,
1011f4259b30SLisandro Dalcin                                        NULL,
1012f4259b30SLisandro Dalcin                                        NULL,
1013f4259b30SLisandro Dalcin                                        NULL,
1014f4259b30SLisandro Dalcin                                        /* 84*/ NULL,
1015f4259b30SLisandro Dalcin                                        NULL,
1016f4259b30SLisandro Dalcin                                        NULL,
1017f4259b30SLisandro Dalcin                                        NULL,
1018f4259b30SLisandro Dalcin                                        NULL,
1019f4259b30SLisandro Dalcin                                        /* 89*/ NULL,
1020f4259b30SLisandro Dalcin                                        NULL,
1021f4259b30SLisandro Dalcin                                        NULL,
1022f4259b30SLisandro Dalcin                                        NULL,
1023f4259b30SLisandro Dalcin                                        NULL,
1024f4259b30SLisandro Dalcin                                        /* 94*/ NULL,
1025f4259b30SLisandro Dalcin                                        NULL,
1026f4259b30SLisandro Dalcin                                        NULL,
1027f4259b30SLisandro Dalcin                                        NULL,
1028f4259b30SLisandro Dalcin                                        NULL,
1029f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1030f4259b30SLisandro Dalcin                                        NULL,
1031f4259b30SLisandro Dalcin                                        NULL,
1032f4259b30SLisandro Dalcin                                        NULL,
1033f4259b30SLisandro Dalcin                                        NULL,
1034f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1035f4259b30SLisandro Dalcin                                        NULL,
1036f4259b30SLisandro Dalcin                                        NULL,
1037f4259b30SLisandro Dalcin                                        NULL,
1038f4259b30SLisandro Dalcin                                        NULL,
1039f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1040f4259b30SLisandro Dalcin                                        NULL,
1041f4259b30SLisandro Dalcin                                        NULL,
1042f4259b30SLisandro Dalcin                                        NULL,
1043f4259b30SLisandro Dalcin                                        NULL,
1044f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1045f4259b30SLisandro Dalcin                                        NULL,
1046f4259b30SLisandro Dalcin                                        NULL,
1047f4259b30SLisandro Dalcin                                        NULL,
1048f4259b30SLisandro Dalcin                                        NULL,
1049f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1050f4259b30SLisandro Dalcin                                        NULL,
1051f4259b30SLisandro Dalcin                                        NULL,
1052f4259b30SLisandro Dalcin                                        NULL,
1053f4259b30SLisandro Dalcin                                        NULL,
1054f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1055f4259b30SLisandro Dalcin                                        NULL,
1056f4259b30SLisandro Dalcin                                        NULL,
1057f4259b30SLisandro Dalcin                                        NULL,
1058f4259b30SLisandro Dalcin                                        NULL,
1059f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1060f4259b30SLisandro Dalcin                                        NULL,
1061f4259b30SLisandro Dalcin                                        NULL,
1062f4259b30SLisandro Dalcin                                        NULL,
1063f4259b30SLisandro Dalcin                                        NULL,
1064f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1065f4259b30SLisandro Dalcin                                        NULL,
1066f4259b30SLisandro Dalcin                                        NULL,
1067f4259b30SLisandro Dalcin                                        NULL,
1068f4259b30SLisandro Dalcin                                        NULL,
1069f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1070f4259b30SLisandro Dalcin                                        NULL,
1071d70f29a3SPierre Jolivet                                        NULL,
1072d70f29a3SPierre Jolivet                                        NULL,
1073d70f29a3SPierre Jolivet                                        NULL,
1074d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1075d70f29a3SPierre Jolivet                                        NULL,
1076d70f29a3SPierre Jolivet                                        NULL,
107799a7f59eSMark Adams                                        NULL,
107899a7f59eSMark Adams                                        NULL,
10797fb60732SBarry Smith                                        NULL,
1080dec0b466SHong Zhang                                        /*150*/ NULL,
1081dec0b466SHong Zhang                                        NULL};
108241cd0125SJakub Kruzik 
108341cd0125SJakub Kruzik /*MC
108441cd0125SJakub Kruzik    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
108541cd0125SJakub Kruzik     The matrices need to have a correct size and parallel layout for the sum or product to be valid.
108641cd0125SJakub Kruzik 
10872ef1f0ffSBarry Smith   Level: advanced
10882ef1f0ffSBarry Smith 
108911a5261eSBarry Smith    Note:
109011a5261eSBarry Smith    To use the product of the matrices call `MatCompositeSetType`(mat,`MAT_COMPOSITE_MULTIPLICATIVE`);
109141cd0125SJakub Kruzik 
1092*1cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetScalings()`, `MatCompositeAddMat()`, `MatSetType()`, `MatCompositeSetType()`, `MatCompositeGetType()`,
109311a5261eSBarry Smith           `MatCompositeSetMatStructure()`, `MatCompositeGetMatStructure()`, `MatCompositeMerge()`, `MatCompositeSetMergeType()`, `MatCompositeGetNumberMat()`, `MatCompositeGetMat()`
109441cd0125SJakub Kruzik M*/
109541cd0125SJakub Kruzik 
1096d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
1097d71ae5a4SJacob Faibussowitsch {
109841cd0125SJakub Kruzik   Mat_Composite *b;
109941cd0125SJakub Kruzik 
110041cd0125SJakub Kruzik   PetscFunctionBegin;
11014dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
110241cd0125SJakub Kruzik   A->data = (void *)b;
11039566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));
110441cd0125SJakub Kruzik 
11059566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
11069566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
110741cd0125SJakub Kruzik 
110841cd0125SJakub Kruzik   A->assembled    = PETSC_TRUE;
110941cd0125SJakub Kruzik   A->preallocated = PETSC_TRUE;
111041cd0125SJakub Kruzik   b->type         = MAT_COMPOSITE_ADDITIVE;
111141cd0125SJakub Kruzik   b->scale        = 1.0;
111241cd0125SJakub Kruzik   b->nmat         = 0;
11134b2558d6SJakub Kruzik   b->merge        = PETSC_FALSE;
11148c8613bfSJakub Kruzik   b->mergetype    = MAT_COMPOSITE_MERGE_RIGHT;
11153b35acafSJakub Kruzik   b->structure    = DIFFERENT_NONZERO_PATTERN;
111603049c21SJunchao Zhang   b->merge_mvctx  = PETSC_TRUE;
111703049c21SJunchao Zhang 
11189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeAddMat_C", MatCompositeAddMat_Composite));
11199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetType_C", MatCompositeSetType_Composite));
11209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetType_C", MatCompositeGetType_Composite));
11219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMergeType_C", MatCompositeSetMergeType_Composite));
11229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMatStructure_C", MatCompositeSetMatStructure_Composite));
11239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMatStructure_C", MatCompositeGetMatStructure_Composite));
11249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeMerge_C", MatCompositeMerge_Composite));
11259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetNumberMat_C", MatCompositeGetNumberMat_Composite));
11269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMat_C", MatCompositeGetMat_Composite));
11279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetScalings_C", MatCompositeSetScalings_Composite));
112841cd0125SJakub Kruzik 
11299566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATCOMPOSITE));
11303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
113141cd0125SJakub Kruzik }
1132