xref: /petsc/src/mat/impls/composite/mcomposite.c (revision 5c8dc79e014d2b2d09dddb7840736ab21fbd1dc2)
1af0996ceSBarry Smith #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
2793850ffSBarry Smith 
3f4259b30SLisandro Dalcin const char *const MatCompositeMergeTypes[] = {"left", "right", "MatCompositeMergeType", "MAT_COMPOSITE_", NULL};
48c8613bfSJakub Kruzik 
5793850ffSBarry Smith typedef struct _Mat_CompositeLink *Mat_CompositeLink;
6793850ffSBarry Smith struct _Mat_CompositeLink {
7793850ffSBarry Smith   Mat               mat;
86d7c1e57SBarry Smith   Vec               work;
96d7c1e57SBarry Smith   Mat_CompositeLink next, prev;
10793850ffSBarry Smith };
11793850ffSBarry Smith 
12793850ffSBarry Smith typedef struct {
136d7c1e57SBarry Smith   MatCompositeType      type;
146d7c1e57SBarry Smith   Mat_CompositeLink     head, tail;
15793850ffSBarry Smith   Vec                   work;
16e4fc5df0SBarry Smith   PetscScalar           scale;                                      /* scale factor supplied with MatScale() */
17e4fc5df0SBarry Smith   Vec                   left, right;                                /* left and right diagonal scaling provided with MatDiagonalScale() */
1803049c21SJunchao Zhang   Vec                   leftwork, rightwork, leftwork2, rightwork2; /* Two pairs of working vectors */
196a7ede75SJakub Kruzik   PetscInt              nmat;
204b2558d6SJakub Kruzik   PetscBool             merge;
218c8613bfSJakub Kruzik   MatCompositeMergeType mergetype;
223b35acafSJakub Kruzik   MatStructure          structure;
2303049c21SJunchao Zhang 
2403049c21SJunchao Zhang   PetscScalar *scalings;
2503049c21SJunchao Zhang   PetscBool    merge_mvctx; /* Whether need to merge mvctx of component matrices */
2603049c21SJunchao Zhang   Vec         *lvecs;       /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
2703049c21SJunchao Zhang   PetscScalar *larray;      /* [len] Data arrays of lvecs[] are stored consecutively in larray */
2803049c21SJunchao Zhang   PetscInt     len;         /* Length of larray[] */
2903049c21SJunchao Zhang   Vec          gvec;        /* Union of lvecs[] without duplicated entries */
3003049c21SJunchao Zhang   PetscInt    *location;    /* A map that maps entries in garray[] to larray[] */
3103049c21SJunchao Zhang   VecScatter   Mvctx;
32793850ffSBarry Smith } Mat_Composite;
33793850ffSBarry Smith 
3466976f2fSJacob Faibussowitsch static PetscErrorCode MatDestroy_Composite(Mat mat)
35d71ae5a4SJacob Faibussowitsch {
362c33bbaeSSatish Balay   Mat_Composite    *shell = (Mat_Composite *)mat->data;
376d7c1e57SBarry Smith   Mat_CompositeLink next  = shell->head, oldnext;
3803049c21SJunchao Zhang   PetscInt          i;
39793850ffSBarry Smith 
40793850ffSBarry Smith   PetscFunctionBegin;
41793850ffSBarry Smith   while (next) {
429566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&next->mat));
4348a46eb9SPierre Jolivet     if (next->work && (!next->next || next->work != next->next->work)) PetscCall(VecDestroy(&next->work));
446d7c1e57SBarry Smith     oldnext = next;
45793850ffSBarry Smith     next    = next->next;
469566063dSJacob Faibussowitsch     PetscCall(PetscFree(oldnext));
47793850ffSBarry Smith   }
489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->work));
499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->left));
509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->right));
519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->leftwork));
529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->rightwork));
539566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->leftwork2));
549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&shell->rightwork2));
5503049c21SJunchao Zhang 
5603049c21SJunchao Zhang   if (shell->Mvctx) {
579566063dSJacob Faibussowitsch     for (i = 0; i < shell->nmat; i++) PetscCall(VecDestroy(&shell->lvecs[i]));
589566063dSJacob Faibussowitsch     PetscCall(PetscFree3(shell->location, shell->larray, shell->lvecs));
599566063dSJacob Faibussowitsch     PetscCall(PetscFree(shell->larray));
609566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&shell->gvec));
619566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&shell->Mvctx));
6203049c21SJunchao Zhang   }
6303049c21SJunchao Zhang 
649566063dSJacob Faibussowitsch   PetscCall(PetscFree(shell->scalings));
652e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeAddMat_C", NULL));
662e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetType_C", NULL));
672e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetType_C", NULL));
682e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMergeType_C", NULL));
692e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMatStructure_C", NULL));
702e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMatStructure_C", NULL));
712e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeMerge_C", NULL));
722e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetNumberMat_C", NULL));
732e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMat_C", NULL));
742e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetScalings_C", NULL));
759566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
77793850ffSBarry Smith }
78793850ffSBarry Smith 
7966976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Composite_Multiplicative(Mat A, Vec x, Vec y)
80d71ae5a4SJacob Faibussowitsch {
816d7c1e57SBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
826d7c1e57SBarry Smith   Mat_CompositeLink next  = shell->head;
836d7c1e57SBarry Smith   Vec               in, out;
8403049c21SJunchao Zhang   PetscScalar       scale;
8503049c21SJunchao Zhang   PetscInt          i;
866d7c1e57SBarry Smith 
876d7c1e57SBarry Smith   PetscFunctionBegin;
8828b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
896d7c1e57SBarry Smith   in = x;
90e4fc5df0SBarry Smith   if (shell->right) {
9148a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
929566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
93e4fc5df0SBarry Smith     in = shell->rightwork;
94e4fc5df0SBarry Smith   }
956d7c1e57SBarry Smith   while (next->next) {
966d7c1e57SBarry Smith     if (!next->work) { /* should reuse previous work if the same size */
979566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(next->mat, NULL, &next->work));
986d7c1e57SBarry Smith     }
996d7c1e57SBarry Smith     out = next->work;
1009566063dSJacob Faibussowitsch     PetscCall(MatMult(next->mat, in, out));
1016d7c1e57SBarry Smith     in   = out;
1026d7c1e57SBarry Smith     next = next->next;
1036d7c1e57SBarry Smith   }
1049566063dSJacob Faibussowitsch   PetscCall(MatMult(next->mat, in, y));
1051baa6e33SBarry Smith   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
10603049c21SJunchao Zhang   scale = shell->scale;
1079371c9d4SSatish Balay   if (shell->scalings) {
1089371c9d4SSatish Balay     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
1099371c9d4SSatish Balay   }
1109566063dSJacob Faibussowitsch   PetscCall(VecScale(y, scale));
1113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1126d7c1e57SBarry Smith }
1136d7c1e57SBarry Smith 
11466976f2fSJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A, Vec x, Vec y)
115d71ae5a4SJacob Faibussowitsch {
1166d7c1e57SBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
1176d7c1e57SBarry Smith   Mat_CompositeLink tail  = shell->tail;
1186d7c1e57SBarry Smith   Vec               in, out;
11903049c21SJunchao Zhang   PetscScalar       scale;
12003049c21SJunchao Zhang   PetscInt          i;
1216d7c1e57SBarry Smith 
1226d7c1e57SBarry Smith   PetscFunctionBegin;
12328b400f6SJacob Faibussowitsch   PetscCheck(tail, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
1246d7c1e57SBarry Smith   in = x;
125e4fc5df0SBarry Smith   if (shell->left) {
12648a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
1279566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
128e4fc5df0SBarry Smith     in = shell->leftwork;
129e4fc5df0SBarry Smith   }
1306d7c1e57SBarry Smith   while (tail->prev) {
1316d7c1e57SBarry Smith     if (!tail->prev->work) { /* should reuse previous work if the same size */
1329566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(tail->mat, NULL, &tail->prev->work));
1336d7c1e57SBarry Smith     }
1346d7c1e57SBarry Smith     out = tail->prev->work;
1359566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(tail->mat, in, out));
1366d7c1e57SBarry Smith     in   = out;
1376d7c1e57SBarry Smith     tail = tail->prev;
1386d7c1e57SBarry Smith   }
1399566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(tail->mat, in, y));
1401baa6e33SBarry Smith   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
14103049c21SJunchao Zhang 
14203049c21SJunchao Zhang   scale = shell->scale;
1439371c9d4SSatish Balay   if (shell->scalings) {
1449371c9d4SSatish Balay     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
1459371c9d4SSatish Balay   }
1469566063dSJacob Faibussowitsch   PetscCall(VecScale(y, scale));
1473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1486d7c1e57SBarry Smith }
1496d7c1e57SBarry Smith 
15066976f2fSJacob Faibussowitsch static PetscErrorCode MatMult_Composite(Mat mat, Vec x, Vec y)
151d71ae5a4SJacob Faibussowitsch {
15203049c21SJunchao Zhang   Mat_Composite     *shell = (Mat_Composite *)mat->data;
15303049c21SJunchao Zhang   Mat_CompositeLink  cur   = shell->head;
15403049c21SJunchao Zhang   Vec                in, y2, xin;
15503049c21SJunchao Zhang   Mat                A, B;
15603049c21SJunchao Zhang   PetscInt           i, j, k, n, nuniq, lo, hi, mid, *gindices, *buf, *tmp, tot;
15703049c21SJunchao Zhang   const PetscScalar *vals;
15803049c21SJunchao Zhang   const PetscInt    *garray;
15903049c21SJunchao Zhang   IS                 ix, iy;
16003049c21SJunchao Zhang   PetscBool          match;
161793850ffSBarry Smith 
162793850ffSBarry Smith   PetscFunctionBegin;
16328b400f6SJacob Faibussowitsch   PetscCheck(cur, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
164e4fc5df0SBarry Smith   in = x;
165e4fc5df0SBarry Smith   if (shell->right) {
16648a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
1679566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
168e4fc5df0SBarry Smith     in = shell->rightwork;
169e4fc5df0SBarry Smith   }
17003049c21SJunchao Zhang 
17103049c21SJunchao Zhang   /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
17203049c21SJunchao Zhang      we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
17303049c21SJunchao Zhang      it is legal to merge Mvctx, because all component matrices have the same size.
17403049c21SJunchao Zhang    */
17503049c21SJunchao Zhang   if (shell->merge_mvctx && !shell->Mvctx) {
17603049c21SJunchao Zhang     /* Currently only implemented for MATMPIAIJ */
17703049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
1789566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)cur->mat, MATMPIAIJ, &match));
17903049c21SJunchao Zhang       if (!match) {
18003049c21SJunchao Zhang         shell->merge_mvctx = PETSC_FALSE;
18103049c21SJunchao Zhang         goto skip_merge_mvctx;
182e4fc5df0SBarry Smith       }
183e4fc5df0SBarry Smith     }
18403049c21SJunchao Zhang 
18503049c21SJunchao Zhang     /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
18603049c21SJunchao Zhang     tot = 0;
18703049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
1889566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, NULL));
1899566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
19003049c21SJunchao Zhang       tot += n;
19103049c21SJunchao Zhang     }
1929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc3(tot, &shell->location, tot, &shell->larray, shell->nmat, &shell->lvecs));
19303049c21SJunchao Zhang     shell->len = tot;
19403049c21SJunchao Zhang 
19503049c21SJunchao Zhang     /* Go through matrices second time to sort off-diag columns and remove dups */
1969566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(tot, &gindices)); /* No Malloc2() since we will give one to petsc and free the other */
1979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(tot, &buf));
19803049c21SJunchao Zhang     nuniq = 0; /* Number of unique nonzero columns */
19903049c21SJunchao Zhang     for (cur = shell->head; cur; cur = cur->next) {
2009566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
2019566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
20203049c21SJunchao Zhang       /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
20303049c21SJunchao Zhang       i = j = k = 0;
20403049c21SJunchao Zhang       while (i < n && j < nuniq) {
20503049c21SJunchao Zhang         if (garray[i] < gindices[j]) buf[k++] = garray[i++];
20603049c21SJunchao Zhang         else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
2079371c9d4SSatish Balay         else {
2089371c9d4SSatish Balay           buf[k++] = garray[i++];
2099371c9d4SSatish Balay           j++;
2109371c9d4SSatish Balay         }
21103049c21SJunchao Zhang       }
21203049c21SJunchao Zhang       /* Copy leftover in garray[] or gindices[] */
21303049c21SJunchao Zhang       if (i < n) {
2149566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(buf + k, garray + i, n - i));
21503049c21SJunchao Zhang         nuniq = k + n - i;
21603049c21SJunchao Zhang       } else if (j < nuniq) {
2179566063dSJacob Faibussowitsch         PetscCall(PetscArraycpy(buf + k, gindices + j, nuniq - j));
21803049c21SJunchao Zhang         nuniq = k + nuniq - j;
21903049c21SJunchao Zhang       } else nuniq = k;
22003049c21SJunchao Zhang       /* Swap gindices and buf to merge garray of the next matrix */
22103049c21SJunchao Zhang       tmp      = gindices;
22203049c21SJunchao Zhang       gindices = buf;
22303049c21SJunchao Zhang       buf      = tmp;
22403049c21SJunchao Zhang     }
2259566063dSJacob Faibussowitsch     PetscCall(PetscFree(buf));
22603049c21SJunchao Zhang 
22703049c21SJunchao Zhang     /* Go through matrices third time to build a map from gindices[] to garray[] */
22803049c21SJunchao Zhang     tot = 0;
22903049c21SJunchao Zhang     for (cur = shell->head, j = 0; cur; cur = cur->next, j++) { /* j-th matrix */
2309566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
2319566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
2329566063dSJacob Faibussowitsch       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, n, NULL, &shell->lvecs[j]));
23303049c21SJunchao Zhang       /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
23403049c21SJunchao Zhang       lo = 0;
23503049c21SJunchao Zhang       for (i = 0; i < n; i++) {
23603049c21SJunchao Zhang         hi = nuniq;
23703049c21SJunchao Zhang         while (hi - lo > 1) {
23803049c21SJunchao Zhang           mid = lo + (hi - lo) / 2;
23903049c21SJunchao Zhang           if (garray[i] < gindices[mid]) hi = mid;
24003049c21SJunchao Zhang           else lo = mid;
24103049c21SJunchao Zhang         }
24203049c21SJunchao Zhang         shell->location[tot + i] = lo; /* gindices[lo] = garray[i] */
24303049c21SJunchao Zhang         lo++;                          /* Since garray[i+1] > garray[i], we can safely advance lo */
24403049c21SJunchao Zhang       }
24503049c21SJunchao Zhang       tot += n;
24603049c21SJunchao Zhang     }
24703049c21SJunchao Zhang 
24803049c21SJunchao Zhang     /* Build merged Mvctx */
2499566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nuniq, gindices, PETSC_OWN_POINTER, &ix));
2509566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, nuniq, 0, 1, &iy));
2519566063dSJacob Faibussowitsch     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &xin));
2529566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_SELF, nuniq, &shell->gvec));
2539566063dSJacob Faibussowitsch     PetscCall(VecScatterCreate(xin, ix, shell->gvec, iy, &shell->Mvctx));
2549566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xin));
2559566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ix));
2569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&iy));
25703049c21SJunchao Zhang   }
25803049c21SJunchao Zhang 
25903049c21SJunchao Zhang skip_merge_mvctx:
2609566063dSJacob Faibussowitsch   PetscCall(VecSet(y, 0));
2619566063dSJacob Faibussowitsch   if (!shell->leftwork2) PetscCall(VecDuplicate(y, &shell->leftwork2));
26203049c21SJunchao Zhang   y2 = shell->leftwork2;
26303049c21SJunchao Zhang 
26403049c21SJunchao Zhang   if (shell->Mvctx) { /* Have a merged Mvctx */
26503049c21SJunchao 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
266da81f932SPierre 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
26703049c21SJunchao Zhang        overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
26803049c21SJunchao Zhang      */
2699566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
2709566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
27103049c21SJunchao Zhang 
2729566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(shell->gvec, &vals));
27303049c21SJunchao Zhang     for (i = 0; i < shell->len; i++) shell->larray[i] = vals[shell->location[i]];
2749566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(shell->gvec, &vals));
27503049c21SJunchao Zhang 
27603049c21SJunchao Zhang     for (cur = shell->head, tot = i = 0; cur; cur = cur->next, i++) { /* i-th matrix */
2779566063dSJacob Faibussowitsch       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, &A, &B, NULL));
278dbbe0bcdSBarry Smith       PetscUseTypeMethod(A, mult, in, y2);
2799566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(B, NULL, &n));
2809566063dSJacob Faibussowitsch       PetscCall(VecPlaceArray(shell->lvecs[i], &shell->larray[tot]));
2819566063dSJacob Faibussowitsch       PetscCall((*B->ops->multadd)(B, shell->lvecs[i], y2, y2));
2829566063dSJacob Faibussowitsch       PetscCall(VecResetArray(shell->lvecs[i]));
2839566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, (shell->scalings ? shell->scalings[i] : 1.0), y2));
28403049c21SJunchao Zhang       tot += n;
28503049c21SJunchao Zhang     }
28603049c21SJunchao Zhang   } else {
28703049c21SJunchao Zhang     if (shell->scalings) {
28803049c21SJunchao Zhang       for (cur = shell->head, i = 0; cur; cur = cur->next, i++) {
2899566063dSJacob Faibussowitsch         PetscCall(MatMult(cur->mat, in, y2));
2909566063dSJacob Faibussowitsch         PetscCall(VecAXPY(y, shell->scalings[i], y2));
29103049c21SJunchao Zhang       }
29203049c21SJunchao Zhang     } else {
2939566063dSJacob Faibussowitsch       for (cur = shell->head; cur; cur = cur->next) PetscCall(MatMultAdd(cur->mat, in, y, y));
29403049c21SJunchao Zhang     }
29503049c21SJunchao Zhang   }
29603049c21SJunchao Zhang 
2979566063dSJacob Faibussowitsch   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
2989566063dSJacob Faibussowitsch   PetscCall(VecScale(y, shell->scale));
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300793850ffSBarry Smith }
301793850ffSBarry Smith 
30266976f2fSJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Composite(Mat A, Vec x, Vec y)
303d71ae5a4SJacob Faibussowitsch {
304793850ffSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
305793850ffSBarry Smith   Mat_CompositeLink next  = shell->head;
30603049c21SJunchao Zhang   Vec               in, y2 = NULL;
30703049c21SJunchao Zhang   PetscInt          i;
308793850ffSBarry Smith 
309793850ffSBarry Smith   PetscFunctionBegin;
31028b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
311e4fc5df0SBarry Smith   in = x;
312e4fc5df0SBarry Smith   if (shell->left) {
31348a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
3149566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
315e4fc5df0SBarry Smith     in = shell->leftwork;
316e4fc5df0SBarry Smith   }
31703049c21SJunchao Zhang 
3189566063dSJacob Faibussowitsch   PetscCall(MatMultTranspose(next->mat, in, y));
31903049c21SJunchao Zhang   if (shell->scalings) {
3209566063dSJacob Faibussowitsch     PetscCall(VecScale(y, shell->scalings[0]));
3219566063dSJacob Faibussowitsch     if (!shell->rightwork2) PetscCall(VecDuplicate(y, &shell->rightwork2));
32203049c21SJunchao Zhang     y2 = shell->rightwork2;
32303049c21SJunchao Zhang   }
32403049c21SJunchao Zhang   i = 1;
325e4fc5df0SBarry Smith   while ((next = next->next)) {
3269566063dSJacob Faibussowitsch     if (!shell->scalings) PetscCall(MatMultTransposeAdd(next->mat, in, y, y));
32703049c21SJunchao Zhang     else {
3289566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(next->mat, in, y2));
3299566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, shell->scalings[i++], y2));
33003049c21SJunchao Zhang     }
331e4fc5df0SBarry Smith   }
3321baa6e33SBarry Smith   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
3339566063dSJacob Faibussowitsch   PetscCall(VecScale(y, shell->scale));
3343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
335793850ffSBarry Smith }
336793850ffSBarry Smith 
33766976f2fSJacob Faibussowitsch static PetscErrorCode MatMultAdd_Composite(Mat A, Vec x, Vec y, Vec z)
338d71ae5a4SJacob Faibussowitsch {
3397bf3a71bSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)A->data;
3407bf3a71bSJakub Kruzik 
3417bf3a71bSJakub Kruzik   PetscFunctionBegin;
3427bf3a71bSJakub Kruzik   if (y != z) {
3439566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, z));
3449566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
3457bf3a71bSJakub Kruzik   } else {
34648a46eb9SPierre Jolivet     if (!shell->leftwork) PetscCall(VecDuplicate(z, &shell->leftwork));
3479566063dSJacob Faibussowitsch     PetscCall(MatMult(A, x, shell->leftwork));
3489566063dSJacob Faibussowitsch     PetscCall(VecCopy(y, z));
3499566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->leftwork));
3507bf3a71bSJakub Kruzik   }
3513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3527bf3a71bSJakub Kruzik }
3537bf3a71bSJakub Kruzik 
35466976f2fSJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Composite(Mat A, Vec x, Vec y, Vec z)
355d71ae5a4SJacob Faibussowitsch {
3567bf3a71bSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)A->data;
3577bf3a71bSJakub Kruzik 
3587bf3a71bSJakub Kruzik   PetscFunctionBegin;
3597bf3a71bSJakub Kruzik   if (y != z) {
3609566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, z));
3619566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, y));
3627bf3a71bSJakub Kruzik   } else {
36348a46eb9SPierre Jolivet     if (!shell->rightwork) PetscCall(VecDuplicate(z, &shell->rightwork));
3649566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(A, x, shell->rightwork));
3659566063dSJacob Faibussowitsch     PetscCall(VecCopy(y, z));
3669566063dSJacob Faibussowitsch     PetscCall(VecAXPY(z, 1.0, shell->rightwork));
3677bf3a71bSJakub Kruzik   }
3683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3697bf3a71bSJakub Kruzik }
3707bf3a71bSJakub Kruzik 
37166976f2fSJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Composite(Mat A, Vec v)
372d71ae5a4SJacob Faibussowitsch {
373793850ffSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)A->data;
374793850ffSBarry Smith   Mat_CompositeLink next  = shell->head;
37503049c21SJunchao Zhang   PetscInt          i;
376793850ffSBarry Smith 
377793850ffSBarry Smith   PetscFunctionBegin;
37828b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
37908401ef6SPierre Jolivet   PetscCheck(!shell->right && !shell->left, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get diagonal if left or right scaling");
380e4fc5df0SBarry Smith 
3819566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(next->mat, v));
3829566063dSJacob Faibussowitsch   if (shell->scalings) PetscCall(VecScale(v, shell->scalings[0]));
38303049c21SJunchao Zhang 
38448a46eb9SPierre Jolivet   if (next->next && !shell->work) PetscCall(VecDuplicate(v, &shell->work));
38503049c21SJunchao Zhang   i = 1;
386793850ffSBarry Smith   while ((next = next->next)) {
3879566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(next->mat, shell->work));
3889566063dSJacob Faibussowitsch     PetscCall(VecAXPY(v, (shell->scalings ? shell->scalings[i++] : 1.0), shell->work));
389793850ffSBarry Smith   }
3909566063dSJacob Faibussowitsch   PetscCall(VecScale(v, shell->scale));
3913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
392793850ffSBarry Smith }
393793850ffSBarry Smith 
39466976f2fSJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Composite(Mat Y, MatAssemblyType t)
395d71ae5a4SJacob Faibussowitsch {
3964b2558d6SJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)Y->data;
397b52f573bSBarry Smith 
398793850ffSBarry Smith   PetscFunctionBegin;
3991baa6e33SBarry Smith   if (shell->merge) PetscCall(MatCompositeMerge(Y));
4003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
401793850ffSBarry Smith }
402793850ffSBarry Smith 
40366976f2fSJacob Faibussowitsch static PetscErrorCode MatScale_Composite(Mat inA, PetscScalar alpha)
404d71ae5a4SJacob Faibussowitsch {
405e4fc5df0SBarry Smith   Mat_Composite *a = (Mat_Composite *)inA->data;
406e4fc5df0SBarry Smith 
407e4fc5df0SBarry Smith   PetscFunctionBegin;
408321429dbSBarry Smith   a->scale *= alpha;
4093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
410e4fc5df0SBarry Smith }
411e4fc5df0SBarry Smith 
41266976f2fSJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Composite(Mat inA, Vec left, Vec right)
413d71ae5a4SJacob Faibussowitsch {
414e4fc5df0SBarry Smith   Mat_Composite *a = (Mat_Composite *)inA->data;
415e4fc5df0SBarry Smith 
416e4fc5df0SBarry Smith   PetscFunctionBegin;
417e4fc5df0SBarry Smith   if (left) {
418321429dbSBarry Smith     if (!a->left) {
4199566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(left, &a->left));
4209566063dSJacob Faibussowitsch       PetscCall(VecCopy(left, a->left));
421321429dbSBarry Smith     } else {
4229566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(a->left, left, a->left));
423321429dbSBarry Smith     }
424e4fc5df0SBarry Smith   }
425e4fc5df0SBarry Smith   if (right) {
426321429dbSBarry Smith     if (!a->right) {
4279566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(right, &a->right));
4289566063dSJacob Faibussowitsch       PetscCall(VecCopy(right, a->right));
429321429dbSBarry Smith     } else {
4309566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(a->right, right, a->right));
431321429dbSBarry Smith     }
432e4fc5df0SBarry Smith   }
4333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
434e4fc5df0SBarry Smith }
435793850ffSBarry Smith 
43666976f2fSJacob Faibussowitsch static PetscErrorCode MatSetFromOptions_Composite(Mat A, PetscOptionItems *PetscOptionsObject)
437d71ae5a4SJacob Faibussowitsch {
4384b2558d6SJakub Kruzik   Mat_Composite *a = (Mat_Composite *)A->data;
4394b2558d6SJakub Kruzik 
4404b2558d6SJakub Kruzik   PetscFunctionBegin;
441d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MATCOMPOSITE options");
4429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_composite_merge", "Merge at MatAssemblyEnd", "MatCompositeMerge", a->merge, &a->merge, NULL));
4439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-mat_composite_merge_type", "Set composite merge direction", "MatCompositeSetMergeType", MatCompositeMergeTypes, (PetscEnum)a->mergetype, (PetscEnum *)&a->mergetype, NULL));
4449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-mat_composite_merge_mvctx", "Merge MatMult() vecscat contexts", "MatCreateComposite", a->merge_mvctx, &a->merge_mvctx, NULL));
445d0609cedSBarry Smith   PetscOptionsHeadEnd();
4463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4474b2558d6SJakub Kruzik }
4484b2558d6SJakub Kruzik 
4492c0821f3SBarry Smith /*@
4508bd739bdSJakub Kruzik   MatCreateComposite - Creates a matrix as the sum or product of one or more matrices
451793850ffSBarry Smith 
452d083f849SBarry Smith   Collective
453793850ffSBarry Smith 
454793850ffSBarry Smith   Input Parameters:
455793850ffSBarry Smith + comm - MPI communicator
456793850ffSBarry Smith . nmat - number of matrices to put in
457793850ffSBarry Smith - mats - the matrices
458793850ffSBarry Smith 
459793850ffSBarry Smith   Output Parameter:
460db36af27SMatthew G. Knepley . mat - the matrix
461793850ffSBarry Smith 
4624b2558d6SJakub Kruzik   Options Database Keys:
46311a5261eSBarry Smith + -mat_composite_merge       - merge in `MatAssemblyEnd()`
46411a5261eSBarry Smith . -mat_composite_merge_mvctx - merge Mvctx of component matrices to optimize communication in `MatMult()` for ADDITIVE matrices
465b28d0daaSJakub Kruzik - -mat_composite_merge_type  - set merge direction
4664b2558d6SJakub Kruzik 
467793850ffSBarry Smith   Level: advanced
468793850ffSBarry Smith 
46911a5261eSBarry Smith   Note:
470793850ffSBarry Smith   Alternative construction
4712ef1f0ffSBarry Smith .vb
4722ef1f0ffSBarry Smith        MatCreate(comm,&mat);
4732ef1f0ffSBarry Smith        MatSetSizes(mat,m,n,M,N);
4742ef1f0ffSBarry Smith        MatSetType(mat,MATCOMPOSITE);
4752ef1f0ffSBarry Smith        MatCompositeAddMat(mat,mats[0]);
4762ef1f0ffSBarry Smith        ....
4772ef1f0ffSBarry Smith        MatCompositeAddMat(mat,mats[nmat-1]);
4782ef1f0ffSBarry Smith        MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
4792ef1f0ffSBarry Smith        MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
4802ef1f0ffSBarry Smith .ve
481793850ffSBarry Smith 
4826d7c1e57SBarry Smith   For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
4836d7c1e57SBarry Smith 
4841cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCompositeGetMat()`, `MatCompositeMerge()`, `MatCompositeSetType()`,
48520f4b53cSBarry Smith           `MATCOMPOSITE`, `MatCompositeType`
486793850ffSBarry Smith @*/
487d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateComposite(MPI_Comm comm, PetscInt nmat, const Mat *mats, Mat *mat)
488d71ae5a4SJacob Faibussowitsch {
489793850ffSBarry Smith   PetscInt m, n, M, N, i;
490793850ffSBarry Smith 
491793850ffSBarry Smith   PetscFunctionBegin;
49208401ef6SPierre Jolivet   PetscCheck(nmat >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must pass in at least one matrix");
4934f572ea9SToby Isaac   PetscAssertPointer(mat, 4);
494793850ffSBarry Smith 
4959566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mats[0], PETSC_IGNORE, &n));
4969566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mats[nmat - 1], &m, PETSC_IGNORE));
4979566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mats[0], PETSC_IGNORE, &N));
4989566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mats[nmat - 1], &M, PETSC_IGNORE));
4999566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, mat));
5009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*mat, m, n, M, N));
5019566063dSJacob Faibussowitsch   PetscCall(MatSetType(*mat, MATCOMPOSITE));
50248a46eb9SPierre Jolivet   for (i = 0; i < nmat; i++) PetscCall(MatCompositeAddMat(*mat, mats[i]));
5039566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
5049566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
5053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
506793850ffSBarry Smith }
507793850ffSBarry Smith 
508d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeAddMat_Composite(Mat mat, Mat smat)
509d71ae5a4SJacob Faibussowitsch {
510d7f81bf2SJakub Kruzik   Mat_Composite    *shell = (Mat_Composite *)mat->data;
511d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink, next = shell->head;
512*5c8dc79eSRichard Tran Mills   VecType           vtype_mat, vtype_smat;
513*5c8dc79eSRichard Tran Mills   PetscBool         match;
514d7f81bf2SJakub Kruzik 
515d7f81bf2SJakub Kruzik   PetscFunctionBegin;
5164dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
517f4259b30SLisandro Dalcin   ilink->next = NULL;
5189566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)smat));
519d7f81bf2SJakub Kruzik   ilink->mat = smat;
520d7f81bf2SJakub Kruzik 
521d7f81bf2SJakub Kruzik   if (!next) shell->head = ilink;
522d7f81bf2SJakub Kruzik   else {
523ad540459SPierre Jolivet     while (next->next) next = next->next;
524d7f81bf2SJakub Kruzik     next->next  = ilink;
525d7f81bf2SJakub Kruzik     ilink->prev = next;
526d7f81bf2SJakub Kruzik   }
527d7f81bf2SJakub Kruzik   shell->tail = ilink;
528d7f81bf2SJakub Kruzik   shell->nmat += 1;
52903049c21SJunchao Zhang 
530*5c8dc79eSRichard Tran Mills   /* If all of the partial matrices have the same default vector type, then the composite matrix should also have this default type.
531*5c8dc79eSRichard Tran Mills      Otherwise, the default type should be "standard". */
532*5c8dc79eSRichard Tran Mills   PetscCall(MatGetVecType(smat, &vtype_smat));
533*5c8dc79eSRichard Tran Mills   if (shell->nmat == 1) PetscCall(MatSetVecType(mat, vtype_smat));
534*5c8dc79eSRichard Tran Mills   else {
535*5c8dc79eSRichard Tran Mills     PetscCall(MatGetVecType(mat, &vtype_mat));
536*5c8dc79eSRichard Tran Mills     PetscCall(PetscStrcmp(vtype_smat, vtype_mat, &match));
537*5c8dc79eSRichard Tran Mills     if (!match) PetscCall(MatSetVecType(mat, VECSTANDARD));
538*5c8dc79eSRichard Tran Mills   }
539*5c8dc79eSRichard Tran Mills 
54003049c21SJunchao Zhang   /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
54103049c21SJunchao Zhang   if (shell->scalings) {
5429566063dSJacob Faibussowitsch     PetscCall(PetscRealloc(sizeof(PetscScalar) * shell->nmat, &shell->scalings));
54303049c21SJunchao Zhang     shell->scalings[shell->nmat - 1] = 1.0;
54403049c21SJunchao Zhang   }
5453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
546d7f81bf2SJakub Kruzik }
547d7f81bf2SJakub Kruzik 
548793850ffSBarry Smith /*@
5498bd739bdSJakub Kruzik   MatCompositeAddMat - Add another matrix to a composite matrix.
550793850ffSBarry Smith 
551c3339decSBarry Smith   Collective
552793850ffSBarry Smith 
553793850ffSBarry Smith   Input Parameters:
554793850ffSBarry Smith + mat  - the composite matrix
555793850ffSBarry Smith - smat - the partial matrix
556793850ffSBarry Smith 
557793850ffSBarry Smith   Level: advanced
558793850ffSBarry Smith 
5591cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
560793850ffSBarry Smith @*/
561d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeAddMat(Mat mat, Mat smat)
562d71ae5a4SJacob Faibussowitsch {
563793850ffSBarry Smith   PetscFunctionBegin;
5640700a824SBarry Smith   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5650700a824SBarry Smith   PetscValidHeaderSpecific(smat, MAT_CLASSID, 2);
566cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeAddMat_C", (Mat, Mat), (mat, smat));
5673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
568d7f81bf2SJakub Kruzik }
569793850ffSBarry Smith 
570d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetType_Composite(Mat mat, MatCompositeType type)
571d71ae5a4SJacob Faibussowitsch {
572d7f81bf2SJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
573d7f81bf2SJakub Kruzik 
574d7f81bf2SJakub Kruzik   PetscFunctionBegin;
575ced1ac25SJakub Kruzik   b->type = type;
576d7f81bf2SJakub Kruzik   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
577f4259b30SLisandro Dalcin     mat->ops->getdiagonal   = NULL;
578d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite_Multiplicative;
579d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
58003049c21SJunchao Zhang     b->merge_mvctx          = PETSC_FALSE;
581d7f81bf2SJakub Kruzik   } else {
582d7f81bf2SJakub Kruzik     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
583d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite;
584d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite;
585793850ffSBarry Smith   }
5863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5876d7c1e57SBarry Smith }
5886d7c1e57SBarry Smith 
5892c0821f3SBarry Smith /*@
5908bd739bdSJakub Kruzik   MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.
5916d7c1e57SBarry Smith 
592c3339decSBarry Smith   Logically Collective
5936d7c1e57SBarry Smith 
5946d7c1e57SBarry Smith   Input Parameters:
59520f4b53cSBarry Smith + mat  - the composite matrix
59620f4b53cSBarry Smith - type - the `MatCompositeType` to use for the matrix
5976d7c1e57SBarry Smith 
5986d7c1e57SBarry Smith   Level: advanced
5996d7c1e57SBarry Smith 
6001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeGetType()`, `MATCOMPOSITE`,
60120f4b53cSBarry Smith           `MatCompositeType`
6026d7c1e57SBarry Smith @*/
603d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetType(Mat mat, MatCompositeType type)
604d71ae5a4SJacob Faibussowitsch {
6056d7c1e57SBarry Smith   PetscFunctionBegin;
606d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
607b2b245abSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat, type, 2);
608cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetType_C", (Mat, MatCompositeType), (mat, type));
6093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
610793850ffSBarry Smith }
611793850ffSBarry Smith 
612d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetType_Composite(Mat mat, MatCompositeType *type)
613d71ae5a4SJacob Faibussowitsch {
6146dbc55e5SJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6156dbc55e5SJakub Kruzik 
6166dbc55e5SJakub Kruzik   PetscFunctionBegin;
6176dbc55e5SJakub Kruzik   *type = b->type;
6183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6196dbc55e5SJakub Kruzik }
6206dbc55e5SJakub Kruzik 
6216dbc55e5SJakub Kruzik /*@
6226dbc55e5SJakub Kruzik   MatCompositeGetType - Returns type of composite.
6236dbc55e5SJakub Kruzik 
6246dbc55e5SJakub Kruzik   Not Collective
6256dbc55e5SJakub Kruzik 
6266dbc55e5SJakub Kruzik   Input Parameter:
6276dbc55e5SJakub Kruzik . mat - the composite matrix
6286dbc55e5SJakub Kruzik 
6296dbc55e5SJakub Kruzik   Output Parameter:
6306dbc55e5SJakub Kruzik . type - type of composite
6316dbc55e5SJakub Kruzik 
6326dbc55e5SJakub Kruzik   Level: advanced
6336dbc55e5SJakub Kruzik 
6341cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetType()`, `MATCOMPOSITE`, `MatCompositeType`
6356dbc55e5SJakub Kruzik @*/
636d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetType(Mat mat, MatCompositeType *type)
637d71ae5a4SJacob Faibussowitsch {
6386dbc55e5SJakub Kruzik   PetscFunctionBegin;
6396dbc55e5SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6404f572ea9SToby Isaac   PetscAssertPointer(type, 2);
641cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetType_C", (Mat, MatCompositeType *), (mat, type));
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6436dbc55e5SJakub Kruzik }
6446dbc55e5SJakub Kruzik 
645d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat, MatStructure str)
646d71ae5a4SJacob Faibussowitsch {
6473b35acafSJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6483b35acafSJakub Kruzik 
6493b35acafSJakub Kruzik   PetscFunctionBegin;
6503b35acafSJakub Kruzik   b->structure = str;
6513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6523b35acafSJakub Kruzik }
6533b35acafSJakub Kruzik 
6543b35acafSJakub Kruzik /*@
6553b35acafSJakub Kruzik   MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.
6563b35acafSJakub Kruzik 
6573b35acafSJakub Kruzik   Not Collective
6583b35acafSJakub Kruzik 
6593b35acafSJakub Kruzik   Input Parameters:
6603b35acafSJakub Kruzik + mat - the composite matrix
66111a5261eSBarry Smith - str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN` (default) or `SUBSET_NONZERO_PATTERN`
6623b35acafSJakub Kruzik 
6633b35acafSJakub Kruzik   Level: advanced
6643b35acafSJakub Kruzik 
66511a5261eSBarry Smith   Note:
66611a5261eSBarry Smith   Information about the matrices structure is used in `MatCompositeMerge()` for additive composite matrix.
6673b35acafSJakub Kruzik 
6681cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatAXPY()`, `MatCreateComposite()`, `MatCompositeMerge()` `MatCompositeGetMatStructure()`, `MATCOMPOSITE`
6693b35acafSJakub Kruzik @*/
670d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetMatStructure(Mat mat, MatStructure str)
671d71ae5a4SJacob Faibussowitsch {
6723b35acafSJakub Kruzik   PetscFunctionBegin;
6733b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
674cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetMatStructure_C", (Mat, MatStructure), (mat, str));
6753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6763b35acafSJakub Kruzik }
6773b35acafSJakub Kruzik 
678d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat, MatStructure *str)
679d71ae5a4SJacob Faibussowitsch {
6803b35acafSJakub Kruzik   Mat_Composite *b = (Mat_Composite *)mat->data;
6813b35acafSJakub Kruzik 
6823b35acafSJakub Kruzik   PetscFunctionBegin;
6833b35acafSJakub Kruzik   *str = b->structure;
6843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6853b35acafSJakub Kruzik }
6863b35acafSJakub Kruzik 
6873b35acafSJakub Kruzik /*@
6883b35acafSJakub Kruzik   MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.
6893b35acafSJakub Kruzik 
6903b35acafSJakub Kruzik   Not Collective
6913b35acafSJakub Kruzik 
6923b35acafSJakub Kruzik   Input Parameter:
6933b35acafSJakub Kruzik . mat - the composite matrix
6943b35acafSJakub Kruzik 
6953b35acafSJakub Kruzik   Output Parameter:
6963b35acafSJakub Kruzik . str - structure of the matrices
6973b35acafSJakub Kruzik 
6983b35acafSJakub Kruzik   Level: advanced
6993b35acafSJakub Kruzik 
7001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MATCOMPOSITE`
7013b35acafSJakub Kruzik @*/
702d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetMatStructure(Mat mat, MatStructure *str)
703d71ae5a4SJacob Faibussowitsch {
7043b35acafSJakub Kruzik   PetscFunctionBegin;
7053b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7064f572ea9SToby Isaac   PetscAssertPointer(str, 2);
707cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetMatStructure_C", (Mat, MatStructure *), (mat, str));
7083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7093b35acafSJakub Kruzik }
7103b35acafSJakub Kruzik 
711d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat, MatCompositeMergeType type)
712d71ae5a4SJacob Faibussowitsch {
7138c8613bfSJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)mat->data;
7148c8613bfSJakub Kruzik 
7158c8613bfSJakub Kruzik   PetscFunctionBegin;
7168c8613bfSJakub Kruzik   shell->mergetype = type;
7173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7188c8613bfSJakub Kruzik }
7198c8613bfSJakub Kruzik 
7208c8613bfSJakub Kruzik /*@
72111a5261eSBarry Smith   MatCompositeSetMergeType - Sets order of `MatCompositeMerge()`.
7228c8613bfSJakub Kruzik 
723c3339decSBarry Smith   Logically Collective
7248c8613bfSJakub Kruzik 
725d8d19677SJose E. Roman   Input Parameters:
7268c8613bfSJakub Kruzik + mat  - the composite matrix
72711a5261eSBarry Smith - type - `MAT_COMPOSITE_MERGE RIGHT` (default) to start merge from right with the first added matrix (mat[0]),
72811a5261eSBarry Smith           `MAT_COMPOSITE_MERGE_LEFT` to start merge from left with the last added matrix (mat[nmat-1])
7298c8613bfSJakub Kruzik 
7308c8613bfSJakub Kruzik   Level: advanced
7318c8613bfSJakub Kruzik 
73211a5261eSBarry Smith   Note:
733da81f932SPierre Jolivet   The resulting matrix is the same regardless of the `MatCompositeMergeType`. Only the order of operation is changed.
73411a5261eSBarry Smith   If set to `MAT_COMPOSITE_MERGE_RIGHT` the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
7358c8613bfSJakub Kruzik   otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].
7368c8613bfSJakub Kruzik 
7371cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeMerge()`, `MATCOMPOSITE`
7388c8613bfSJakub Kruzik @*/
739d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetMergeType(Mat mat, MatCompositeMergeType type)
740d71ae5a4SJacob Faibussowitsch {
7418c8613bfSJakub Kruzik   PetscFunctionBegin;
7428c8613bfSJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7438c8613bfSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat, type, 2);
744cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetMergeType_C", (Mat, MatCompositeMergeType), (mat, type));
7453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7468c8613bfSJakub Kruzik }
7478c8613bfSJakub Kruzik 
748d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
749d71ae5a4SJacob Faibussowitsch {
750b52f573bSBarry Smith   Mat_Composite    *shell = (Mat_Composite *)mat->data;
7516d7c1e57SBarry Smith   Mat_CompositeLink next = shell->head, prev = shell->tail;
7526d7c1e57SBarry Smith   Mat               tmat, newmat;
7531ba60692SJed Brown   Vec               left, right;
7541ba60692SJed Brown   PetscScalar       scale;
75503049c21SJunchao Zhang   PetscInt          i;
756b52f573bSBarry Smith 
757b52f573bSBarry Smith   PetscFunctionBegin;
75828b400f6SJacob Faibussowitsch   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
75903049c21SJunchao Zhang   scale = shell->scale;
7606d7c1e57SBarry Smith   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
7618c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
76203049c21SJunchao Zhang       i = 0;
7639566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
7649566063dSJacob Faibussowitsch       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i++]));
76548a46eb9SPierre Jolivet       while ((next = next->next)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i++] : 1.0), next->mat, shell->structure));
7666d7c1e57SBarry Smith     } else {
76703049c21SJunchao Zhang       i = shell->nmat - 1;
7689566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
7699566063dSJacob Faibussowitsch       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i--]));
77048a46eb9SPierre Jolivet       while ((prev = prev->prev)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i--] : 1.0), prev->mat, shell->structure));
7718c8613bfSJakub Kruzik     }
7728c8613bfSJakub Kruzik   } else {
7738c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
7749566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
775b6cfcaf5SJakub Kruzik       while ((next = next->next)) {
7769566063dSJacob Faibussowitsch         PetscCall(MatMatMult(next->mat, tmat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
7779566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tmat));
7786d7c1e57SBarry Smith         tmat = newmat;
7796d7c1e57SBarry Smith       }
78004d534ceSJakub Kruzik     } else {
7819566063dSJacob Faibussowitsch       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
78204d534ceSJakub Kruzik       while ((prev = prev->prev)) {
7839566063dSJacob Faibussowitsch         PetscCall(MatMatMult(tmat, prev->mat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
7849566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tmat));
78504d534ceSJakub Kruzik         tmat = newmat;
78604d534ceSJakub Kruzik       }
78704d534ceSJakub Kruzik     }
7889371c9d4SSatish Balay     if (shell->scalings) {
7899371c9d4SSatish Balay       for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
7909371c9d4SSatish Balay     }
7916d7c1e57SBarry Smith   }
7921ba60692SJed Brown 
7939566063dSJacob Faibussowitsch   if ((left = shell->left)) PetscCall(PetscObjectReference((PetscObject)left));
7949566063dSJacob Faibussowitsch   if ((right = shell->right)) PetscCall(PetscObjectReference((PetscObject)right));
7951ba60692SJed Brown 
7969566063dSJacob Faibussowitsch   PetscCall(MatHeaderReplace(mat, &tmat));
7971ba60692SJed Brown 
7989566063dSJacob Faibussowitsch   PetscCall(MatDiagonalScale(mat, left, right));
7999566063dSJacob Faibussowitsch   PetscCall(MatScale(mat, scale));
8009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&left));
8019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&right));
8023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
803b52f573bSBarry Smith }
8046a7ede75SJakub Kruzik 
8056a7ede75SJakub Kruzik /*@
806d7f81bf2SJakub Kruzik   MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
8078bd739bdSJakub Kruzik   by summing or computing the product of all the matrices inside the composite matrix.
808d7f81bf2SJakub Kruzik 
809b2b245abSJakub Kruzik   Collective
810d7f81bf2SJakub Kruzik 
811f899ff85SJose E. Roman   Input Parameter:
812d7f81bf2SJakub Kruzik . mat - the composite matrix
813d7f81bf2SJakub Kruzik 
8144b2558d6SJakub Kruzik   Options Database Keys:
81511a5261eSBarry Smith + -mat_composite_merge      - merge in `MatAssemblyEnd()`
816b28d0daaSJakub Kruzik - -mat_composite_merge_type - set merge direction
817d7f81bf2SJakub Kruzik 
818d7f81bf2SJakub Kruzik   Level: advanced
819d7f81bf2SJakub Kruzik 
82011a5261eSBarry Smith   Note:
82111a5261eSBarry Smith   The `MatType` of the resulting matrix will be the same as the `MatType` of the FIRST matrix in the composite matrix.
822d7f81bf2SJakub Kruzik 
8231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MatCompositeSetMergeType()`, `MATCOMPOSITE`
824d7f81bf2SJakub Kruzik @*/
825d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeMerge(Mat mat)
826d71ae5a4SJacob Faibussowitsch {
827d7f81bf2SJakub Kruzik   PetscFunctionBegin;
828d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
829cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeMerge_C", (Mat), (mat));
8303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
831d7f81bf2SJakub Kruzik }
832d7f81bf2SJakub Kruzik 
833d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat, PetscInt *nmat)
834d71ae5a4SJacob Faibussowitsch {
835d7f81bf2SJakub Kruzik   Mat_Composite *shell = (Mat_Composite *)mat->data;
836d7f81bf2SJakub Kruzik 
837d7f81bf2SJakub Kruzik   PetscFunctionBegin;
838d7f81bf2SJakub Kruzik   *nmat = shell->nmat;
8393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
840d7f81bf2SJakub Kruzik }
841d7f81bf2SJakub Kruzik 
842d7f81bf2SJakub Kruzik /*@
8436d0add67SJakub Kruzik   MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.
8446a7ede75SJakub Kruzik 
8456a7ede75SJakub Kruzik   Not Collective
8466a7ede75SJakub Kruzik 
8476a7ede75SJakub Kruzik   Input Parameter:
848d7f81bf2SJakub Kruzik . mat - the composite matrix
8496a7ede75SJakub Kruzik 
8506a7ede75SJakub Kruzik   Output Parameter:
8516d0add67SJakub Kruzik . nmat - number of matrices in the composite matrix
8526a7ede75SJakub Kruzik 
8538b5c3584SJakub Kruzik   Level: advanced
8546a7ede75SJakub Kruzik 
8551cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
8566a7ede75SJakub Kruzik @*/
857d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetNumberMat(Mat mat, PetscInt *nmat)
858d71ae5a4SJacob Faibussowitsch {
8596a7ede75SJakub Kruzik   PetscFunctionBegin;
860d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8614f572ea9SToby Isaac   PetscAssertPointer(nmat, 2);
862cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetNumberMat_C", (Mat, PetscInt *), (mat, nmat));
8633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
864d7f81bf2SJakub Kruzik }
865d7f81bf2SJakub Kruzik 
866d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCompositeGetMat_Composite(Mat mat, PetscInt i, Mat *Ai)
867d71ae5a4SJacob Faibussowitsch {
868d7f81bf2SJakub Kruzik   Mat_Composite    *shell = (Mat_Composite *)mat->data;
869d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink;
870d7f81bf2SJakub Kruzik   PetscInt          k;
871d7f81bf2SJakub Kruzik 
872d7f81bf2SJakub Kruzik   PetscFunctionBegin;
87308401ef6SPierre Jolivet   PetscCheck(i < shell->nmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "index out of range: %" PetscInt_FMT " >= %" PetscInt_FMT, i, shell->nmat);
874d7f81bf2SJakub Kruzik   ilink = shell->head;
875ad540459SPierre Jolivet   for (k = 0; k < i; k++) ilink = ilink->next;
876d7f81bf2SJakub Kruzik   *Ai = ilink->mat;
8773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8786a7ede75SJakub Kruzik }
8796a7ede75SJakub Kruzik 
8808b5c3584SJakub Kruzik /*@
8818bd739bdSJakub Kruzik   MatCompositeGetMat - Returns the ith matrix from the composite matrix.
8828b5c3584SJakub Kruzik 
883c3339decSBarry Smith   Logically Collective
8848b5c3584SJakub Kruzik 
885d8d19677SJose E. Roman   Input Parameters:
886d7f81bf2SJakub Kruzik + mat - the composite matrix
8878b5c3584SJakub Kruzik - i   - the number of requested matrix
8888b5c3584SJakub Kruzik 
8898b5c3584SJakub Kruzik   Output Parameter:
8908b5c3584SJakub Kruzik . Ai - ith matrix in composite
8918b5c3584SJakub Kruzik 
8928b5c3584SJakub Kruzik   Level: advanced
8938b5c3584SJakub Kruzik 
8941cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetNumberMat()`, `MatCompositeAddMat()`, `MATCOMPOSITE`
8958b5c3584SJakub Kruzik @*/
896d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeGetMat(Mat mat, PetscInt i, Mat *Ai)
897d71ae5a4SJacob Faibussowitsch {
8988b5c3584SJakub Kruzik   PetscFunctionBegin;
899d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
900d7f81bf2SJakub Kruzik   PetscValidLogicalCollectiveInt(mat, i, 2);
9014f572ea9SToby Isaac   PetscAssertPointer(Ai, 3);
902cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeGetMat_C", (Mat, PetscInt, Mat *), (mat, i, Ai));
9033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9048b5c3584SJakub Kruzik }
9058b5c3584SJakub Kruzik 
90666976f2fSJacob Faibussowitsch static PetscErrorCode MatCompositeSetScalings_Composite(Mat mat, const PetscScalar *scalings)
907d71ae5a4SJacob Faibussowitsch {
90803049c21SJunchao Zhang   Mat_Composite *shell = (Mat_Composite *)mat->data;
90903049c21SJunchao Zhang   PetscInt       nmat;
91003049c21SJunchao Zhang 
91103049c21SJunchao Zhang   PetscFunctionBegin;
9129566063dSJacob Faibussowitsch   PetscCall(MatCompositeGetNumberMat(mat, &nmat));
9139566063dSJacob Faibussowitsch   if (!shell->scalings) PetscCall(PetscMalloc1(nmat, &shell->scalings));
9149566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(shell->scalings, scalings, nmat));
9153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
91603049c21SJunchao Zhang }
91703049c21SJunchao Zhang 
91803049c21SJunchao Zhang /*@
91903049c21SJunchao Zhang   MatCompositeSetScalings - Sets separate scaling factors for component matrices.
92003049c21SJunchao Zhang 
921c3339decSBarry Smith   Logically Collective
92203049c21SJunchao Zhang 
923d8d19677SJose E. Roman   Input Parameters:
92403049c21SJunchao Zhang + mat      - the composite matrix
92503049c21SJunchao Zhang - scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)
92603049c21SJunchao Zhang 
92703049c21SJunchao Zhang   Level: advanced
92803049c21SJunchao Zhang 
9291cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatDiagonalScale()`, `MATCOMPOSITE`
93003049c21SJunchao Zhang @*/
931d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCompositeSetScalings(Mat mat, const PetscScalar *scalings)
932d71ae5a4SJacob Faibussowitsch {
93303049c21SJunchao Zhang   PetscFunctionBegin;
93403049c21SJunchao Zhang   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9354f572ea9SToby Isaac   PetscAssertPointer(scalings, 2);
93603049c21SJunchao Zhang   PetscValidLogicalCollectiveScalar(mat, *scalings, 2);
937cac4c232SBarry Smith   PetscUseMethod(mat, "MatCompositeSetScalings_C", (Mat, const PetscScalar *), (mat, scalings));
9383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
93903049c21SJunchao Zhang }
94003049c21SJunchao Zhang 
941f4259b30SLisandro Dalcin static struct _MatOps MatOps_Values = {NULL,
942f4259b30SLisandro Dalcin                                        NULL,
943f4259b30SLisandro Dalcin                                        NULL,
94441cd0125SJakub Kruzik                                        MatMult_Composite,
9457bf3a71bSJakub Kruzik                                        MatMultAdd_Composite,
94641cd0125SJakub Kruzik                                        /*  5*/ MatMultTranspose_Composite,
9477bf3a71bSJakub Kruzik                                        MatMultTransposeAdd_Composite,
948f4259b30SLisandro Dalcin                                        NULL,
949f4259b30SLisandro Dalcin                                        NULL,
950f4259b30SLisandro Dalcin                                        NULL,
951f4259b30SLisandro Dalcin                                        /* 10*/ NULL,
952f4259b30SLisandro Dalcin                                        NULL,
953f4259b30SLisandro Dalcin                                        NULL,
954f4259b30SLisandro Dalcin                                        NULL,
955f4259b30SLisandro Dalcin                                        NULL,
956f4259b30SLisandro Dalcin                                        /* 15*/ NULL,
957f4259b30SLisandro Dalcin                                        NULL,
95841cd0125SJakub Kruzik                                        MatGetDiagonal_Composite,
95941cd0125SJakub Kruzik                                        MatDiagonalScale_Composite,
960f4259b30SLisandro Dalcin                                        NULL,
961f4259b30SLisandro Dalcin                                        /* 20*/ NULL,
96241cd0125SJakub Kruzik                                        MatAssemblyEnd_Composite,
963f4259b30SLisandro Dalcin                                        NULL,
964f4259b30SLisandro Dalcin                                        NULL,
965f4259b30SLisandro Dalcin                                        /* 24*/ NULL,
966f4259b30SLisandro Dalcin                                        NULL,
967f4259b30SLisandro Dalcin                                        NULL,
968f4259b30SLisandro Dalcin                                        NULL,
969f4259b30SLisandro Dalcin                                        NULL,
970f4259b30SLisandro Dalcin                                        /* 29*/ NULL,
971f4259b30SLisandro Dalcin                                        NULL,
972f4259b30SLisandro Dalcin                                        NULL,
973f4259b30SLisandro Dalcin                                        NULL,
974f4259b30SLisandro Dalcin                                        NULL,
975f4259b30SLisandro Dalcin                                        /* 34*/ NULL,
976f4259b30SLisandro Dalcin                                        NULL,
977f4259b30SLisandro Dalcin                                        NULL,
978f4259b30SLisandro Dalcin                                        NULL,
979f4259b30SLisandro Dalcin                                        NULL,
980f4259b30SLisandro Dalcin                                        /* 39*/ NULL,
981f4259b30SLisandro Dalcin                                        NULL,
982f4259b30SLisandro Dalcin                                        NULL,
983f4259b30SLisandro Dalcin                                        NULL,
984f4259b30SLisandro Dalcin                                        NULL,
985f4259b30SLisandro Dalcin                                        /* 44*/ NULL,
98641cd0125SJakub Kruzik                                        MatScale_Composite,
98741cd0125SJakub Kruzik                                        MatShift_Basic,
988f4259b30SLisandro Dalcin                                        NULL,
989f4259b30SLisandro Dalcin                                        NULL,
990f4259b30SLisandro Dalcin                                        /* 49*/ NULL,
991f4259b30SLisandro Dalcin                                        NULL,
992f4259b30SLisandro Dalcin                                        NULL,
993f4259b30SLisandro Dalcin                                        NULL,
994f4259b30SLisandro Dalcin                                        NULL,
995f4259b30SLisandro Dalcin                                        /* 54*/ NULL,
996f4259b30SLisandro Dalcin                                        NULL,
997f4259b30SLisandro Dalcin                                        NULL,
998f4259b30SLisandro Dalcin                                        NULL,
999f4259b30SLisandro Dalcin                                        NULL,
1000f4259b30SLisandro Dalcin                                        /* 59*/ NULL,
100141cd0125SJakub Kruzik                                        MatDestroy_Composite,
1002f4259b30SLisandro Dalcin                                        NULL,
1003f4259b30SLisandro Dalcin                                        NULL,
1004f4259b30SLisandro Dalcin                                        NULL,
1005f4259b30SLisandro Dalcin                                        /* 64*/ NULL,
1006f4259b30SLisandro Dalcin                                        NULL,
1007f4259b30SLisandro Dalcin                                        NULL,
1008f4259b30SLisandro Dalcin                                        NULL,
1009f4259b30SLisandro Dalcin                                        NULL,
1010f4259b30SLisandro Dalcin                                        /* 69*/ NULL,
1011f4259b30SLisandro Dalcin                                        NULL,
1012f4259b30SLisandro Dalcin                                        NULL,
1013f4259b30SLisandro Dalcin                                        NULL,
1014f4259b30SLisandro Dalcin                                        NULL,
1015f4259b30SLisandro Dalcin                                        /* 74*/ NULL,
1016f4259b30SLisandro Dalcin                                        NULL,
10174b2558d6SJakub Kruzik                                        MatSetFromOptions_Composite,
1018f4259b30SLisandro Dalcin                                        NULL,
1019f4259b30SLisandro Dalcin                                        NULL,
1020f4259b30SLisandro Dalcin                                        /* 79*/ NULL,
1021f4259b30SLisandro Dalcin                                        NULL,
1022f4259b30SLisandro Dalcin                                        NULL,
1023f4259b30SLisandro Dalcin                                        NULL,
1024f4259b30SLisandro Dalcin                                        NULL,
1025f4259b30SLisandro Dalcin                                        /* 84*/ NULL,
1026f4259b30SLisandro Dalcin                                        NULL,
1027f4259b30SLisandro Dalcin                                        NULL,
1028f4259b30SLisandro Dalcin                                        NULL,
1029f4259b30SLisandro Dalcin                                        NULL,
1030f4259b30SLisandro Dalcin                                        /* 89*/ NULL,
1031f4259b30SLisandro Dalcin                                        NULL,
1032f4259b30SLisandro Dalcin                                        NULL,
1033f4259b30SLisandro Dalcin                                        NULL,
1034f4259b30SLisandro Dalcin                                        NULL,
1035f4259b30SLisandro Dalcin                                        /* 94*/ NULL,
1036f4259b30SLisandro Dalcin                                        NULL,
1037f4259b30SLisandro Dalcin                                        NULL,
1038f4259b30SLisandro Dalcin                                        NULL,
1039f4259b30SLisandro Dalcin                                        NULL,
1040f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1041f4259b30SLisandro Dalcin                                        NULL,
1042f4259b30SLisandro Dalcin                                        NULL,
1043f4259b30SLisandro Dalcin                                        NULL,
1044f4259b30SLisandro Dalcin                                        NULL,
1045f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1046f4259b30SLisandro Dalcin                                        NULL,
1047f4259b30SLisandro Dalcin                                        NULL,
1048f4259b30SLisandro Dalcin                                        NULL,
1049f4259b30SLisandro Dalcin                                        NULL,
1050f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1051f4259b30SLisandro Dalcin                                        NULL,
1052f4259b30SLisandro Dalcin                                        NULL,
1053f4259b30SLisandro Dalcin                                        NULL,
1054f4259b30SLisandro Dalcin                                        NULL,
1055f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1056f4259b30SLisandro Dalcin                                        NULL,
1057f4259b30SLisandro Dalcin                                        NULL,
1058f4259b30SLisandro Dalcin                                        NULL,
1059f4259b30SLisandro Dalcin                                        NULL,
1060f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1061f4259b30SLisandro Dalcin                                        NULL,
1062f4259b30SLisandro Dalcin                                        NULL,
1063f4259b30SLisandro Dalcin                                        NULL,
1064f4259b30SLisandro Dalcin                                        NULL,
1065f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1066f4259b30SLisandro Dalcin                                        NULL,
1067f4259b30SLisandro Dalcin                                        NULL,
1068f4259b30SLisandro Dalcin                                        NULL,
1069f4259b30SLisandro Dalcin                                        NULL,
1070f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1071f4259b30SLisandro Dalcin                                        NULL,
1072f4259b30SLisandro Dalcin                                        NULL,
1073f4259b30SLisandro Dalcin                                        NULL,
1074f4259b30SLisandro Dalcin                                        NULL,
1075f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1076f4259b30SLisandro Dalcin                                        NULL,
1077f4259b30SLisandro Dalcin                                        NULL,
1078f4259b30SLisandro Dalcin                                        NULL,
1079f4259b30SLisandro Dalcin                                        NULL,
1080f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1081f4259b30SLisandro Dalcin                                        NULL,
1082d70f29a3SPierre Jolivet                                        NULL,
1083d70f29a3SPierre Jolivet                                        NULL,
1084d70f29a3SPierre Jolivet                                        NULL,
1085d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1086d70f29a3SPierre Jolivet                                        NULL,
1087d70f29a3SPierre Jolivet                                        NULL,
108899a7f59eSMark Adams                                        NULL,
108999a7f59eSMark Adams                                        NULL,
10907fb60732SBarry Smith                                        NULL,
1091dec0b466SHong Zhang                                        /*150*/ NULL,
1092dec0b466SHong Zhang                                        NULL};
109341cd0125SJakub Kruzik 
109441cd0125SJakub Kruzik /*MC
109541cd0125SJakub Kruzik    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
109641cd0125SJakub Kruzik     The matrices need to have a correct size and parallel layout for the sum or product to be valid.
109741cd0125SJakub Kruzik 
10982ef1f0ffSBarry Smith   Level: advanced
10992ef1f0ffSBarry Smith 
110011a5261eSBarry Smith    Note:
110111a5261eSBarry Smith    To use the product of the matrices call `MatCompositeSetType`(mat,`MAT_COMPOSITE_MULTIPLICATIVE`);
110241cd0125SJakub Kruzik 
11031cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetScalings()`, `MatCompositeAddMat()`, `MatSetType()`, `MatCompositeSetType()`, `MatCompositeGetType()`,
110411a5261eSBarry Smith           `MatCompositeSetMatStructure()`, `MatCompositeGetMatStructure()`, `MatCompositeMerge()`, `MatCompositeSetMergeType()`, `MatCompositeGetNumberMat()`, `MatCompositeGetMat()`
110541cd0125SJakub Kruzik M*/
110641cd0125SJakub Kruzik 
1107d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
1108d71ae5a4SJacob Faibussowitsch {
110941cd0125SJakub Kruzik   Mat_Composite *b;
111041cd0125SJakub Kruzik 
111141cd0125SJakub Kruzik   PetscFunctionBegin;
11124dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
111341cd0125SJakub Kruzik   A->data   = (void *)b;
1114aea10558SJacob Faibussowitsch   A->ops[0] = MatOps_Values;
111541cd0125SJakub Kruzik 
11169566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
11179566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
111841cd0125SJakub Kruzik 
111941cd0125SJakub Kruzik   A->assembled    = PETSC_TRUE;
112041cd0125SJakub Kruzik   A->preallocated = PETSC_TRUE;
112141cd0125SJakub Kruzik   b->type         = MAT_COMPOSITE_ADDITIVE;
112241cd0125SJakub Kruzik   b->scale        = 1.0;
112341cd0125SJakub Kruzik   b->nmat         = 0;
11244b2558d6SJakub Kruzik   b->merge        = PETSC_FALSE;
11258c8613bfSJakub Kruzik   b->mergetype    = MAT_COMPOSITE_MERGE_RIGHT;
11263b35acafSJakub Kruzik   b->structure    = DIFFERENT_NONZERO_PATTERN;
112703049c21SJunchao Zhang   b->merge_mvctx  = PETSC_TRUE;
112803049c21SJunchao Zhang 
11299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeAddMat_C", MatCompositeAddMat_Composite));
11309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetType_C", MatCompositeSetType_Composite));
11319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetType_C", MatCompositeGetType_Composite));
11329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMergeType_C", MatCompositeSetMergeType_Composite));
11339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMatStructure_C", MatCompositeSetMatStructure_Composite));
11349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMatStructure_C", MatCompositeGetMatStructure_Composite));
11359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeMerge_C", MatCompositeMerge_Composite));
11369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetNumberMat_C", MatCompositeGetNumberMat_Composite));
11379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMat_C", MatCompositeGetMat_Composite));
11389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetScalings_C", MatCompositeSetScalings_Composite));
113941cd0125SJakub Kruzik 
11409566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATCOMPOSITE));
11413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114241cd0125SJakub Kruzik }
1143