xref: /petsc/src/mat/impls/composite/mcomposite.c (revision 03049c21b7788bf1d362e6d868659cfd5a8ea0e4)
1793850ffSBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/
3793850ffSBarry Smith 
48c8613bfSJakub Kruzik const char *const MatCompositeMergeTypes[] = {"left","right","MatCompositeMergeType","MAT_COMPOSITE_",0};
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() */
19*03049c21SJunchao 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;
24*03049c21SJunchao Zhang 
25*03049c21SJunchao Zhang   PetscScalar           *scalings;
26*03049c21SJunchao Zhang   PetscBool             merge_mvctx;  /* Whether need to merge mvctx of component matrices */
27*03049c21SJunchao Zhang   Vec                   *lvecs;       /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
28*03049c21SJunchao Zhang   PetscScalar           *larray;      /* [len] Data arrays of lvecs[] are stored consecutively in larray */
29*03049c21SJunchao Zhang   PetscInt              len;          /* Length of larray[] */
30*03049c21SJunchao Zhang   Vec                   gvec;         /* Union of lvecs[] without duplicated entries */
31*03049c21SJunchao Zhang   PetscInt              *location;    /* A map that maps entries in garray[] to larray[] */
32*03049c21SJunchao Zhang   VecScatter            Mvctx;
33793850ffSBarry Smith } Mat_Composite;
34793850ffSBarry Smith 
35793850ffSBarry Smith PetscErrorCode MatDestroy_Composite(Mat mat)
36793850ffSBarry Smith {
37793850ffSBarry Smith   PetscErrorCode    ierr;
382c33bbaeSSatish Balay   Mat_Composite     *shell = (Mat_Composite*)mat->data;
396d7c1e57SBarry Smith   Mat_CompositeLink next   = shell->head,oldnext;
40*03049c21SJunchao Zhang   PetscInt          i;
41793850ffSBarry Smith 
42793850ffSBarry Smith   PetscFunctionBegin;
43793850ffSBarry Smith   while (next) {
446bf464f9SBarry Smith     ierr = MatDestroy(&next->mat);CHKERRQ(ierr);
456d7c1e57SBarry Smith     if (next->work && (!next->next || next->work != next->next->work)) {
466bf464f9SBarry Smith       ierr = VecDestroy(&next->work);CHKERRQ(ierr);
476d7c1e57SBarry Smith     }
486d7c1e57SBarry Smith     oldnext = next;
49793850ffSBarry Smith     next    = next->next;
506d7c1e57SBarry Smith     ierr    = PetscFree(oldnext);CHKERRQ(ierr);
51793850ffSBarry Smith   }
526bf464f9SBarry Smith   ierr = VecDestroy(&shell->work);CHKERRQ(ierr);
536bf464f9SBarry Smith   ierr = VecDestroy(&shell->left);CHKERRQ(ierr);
546bf464f9SBarry Smith   ierr = VecDestroy(&shell->right);CHKERRQ(ierr);
556bf464f9SBarry Smith   ierr = VecDestroy(&shell->leftwork);CHKERRQ(ierr);
566bf464f9SBarry Smith   ierr = VecDestroy(&shell->rightwork);CHKERRQ(ierr);
57*03049c21SJunchao Zhang   ierr = VecDestroy(&shell->leftwork2);CHKERRQ(ierr);
58*03049c21SJunchao Zhang   ierr = VecDestroy(&shell->rightwork2);CHKERRQ(ierr);
59*03049c21SJunchao Zhang 
60*03049c21SJunchao Zhang   if (shell->Mvctx) {
61*03049c21SJunchao Zhang     for (i=0; i<shell->nmat; i++) {ierr = VecDestroy(&shell->lvecs[i]);CHKERRQ(ierr);}
62*03049c21SJunchao Zhang     ierr = PetscFree3(shell->location,shell->larray,shell->lvecs);CHKERRQ(ierr);
63*03049c21SJunchao Zhang     ierr = PetscFree(shell->larray);CHKERRQ(ierr);
64*03049c21SJunchao Zhang     ierr = VecDestroy(&shell->gvec);CHKERRQ(ierr);
65*03049c21SJunchao Zhang     ierr = VecScatterDestroy(&shell->Mvctx);CHKERRQ(ierr);
66*03049c21SJunchao Zhang   }
67*03049c21SJunchao Zhang 
68*03049c21SJunchao Zhang   ierr = PetscFree(shell->scalings);CHKERRQ(ierr);
696bf464f9SBarry Smith   ierr = PetscFree(mat->data);CHKERRQ(ierr);
70793850ffSBarry Smith   PetscFunctionReturn(0);
71793850ffSBarry Smith }
72793850ffSBarry Smith 
736d7c1e57SBarry Smith PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
746d7c1e57SBarry Smith {
756d7c1e57SBarry Smith   Mat_Composite     *shell = (Mat_Composite*)A->data;
766d7c1e57SBarry Smith   Mat_CompositeLink next   = shell->head;
776d7c1e57SBarry Smith   PetscErrorCode    ierr;
786d7c1e57SBarry Smith   Vec               in,out;
79*03049c21SJunchao Zhang   PetscScalar       scale;
80*03049c21SJunchao Zhang   PetscInt          i;
816d7c1e57SBarry Smith 
826d7c1e57SBarry Smith   PetscFunctionBegin;
83e32f2f54SBarry Smith   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
846d7c1e57SBarry Smith   in = x;
85e4fc5df0SBarry Smith   if (shell->right) {
86e4fc5df0SBarry Smith     if (!shell->rightwork) {
87e4fc5df0SBarry Smith       ierr = VecDuplicate(shell->right,&shell->rightwork);CHKERRQ(ierr);
88e4fc5df0SBarry Smith     }
89e4fc5df0SBarry Smith     ierr = VecPointwiseMult(shell->rightwork,shell->right,in);CHKERRQ(ierr);
90e4fc5df0SBarry Smith     in   = shell->rightwork;
91e4fc5df0SBarry Smith   }
926d7c1e57SBarry Smith   while (next->next) {
936d7c1e57SBarry Smith     if (!next->work) { /* should reuse previous work if the same size */
942a7a6963SBarry Smith       ierr = MatCreateVecs(next->mat,NULL,&next->work);CHKERRQ(ierr);
956d7c1e57SBarry Smith     }
966d7c1e57SBarry Smith     out  = next->work;
976d7c1e57SBarry Smith     ierr = MatMult(next->mat,in,out);CHKERRQ(ierr);
986d7c1e57SBarry Smith     in   = out;
996d7c1e57SBarry Smith     next = next->next;
1006d7c1e57SBarry Smith   }
1016d7c1e57SBarry Smith   ierr = MatMult(next->mat,in,y);CHKERRQ(ierr);
102e4fc5df0SBarry Smith   if (shell->left) {
103e4fc5df0SBarry Smith     ierr = VecPointwiseMult(y,shell->left,y);CHKERRQ(ierr);
104e4fc5df0SBarry Smith   }
105*03049c21SJunchao Zhang   scale = shell->scale;
106*03049c21SJunchao Zhang   if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
107*03049c21SJunchao Zhang   ierr = VecScale(y,scale);CHKERRQ(ierr);
1086d7c1e57SBarry Smith   PetscFunctionReturn(0);
1096d7c1e57SBarry Smith }
1106d7c1e57SBarry Smith 
1116d7c1e57SBarry Smith PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
1126d7c1e57SBarry Smith {
1136d7c1e57SBarry Smith   Mat_Composite     *shell = (Mat_Composite*)A->data;
1146d7c1e57SBarry Smith   Mat_CompositeLink tail   = shell->tail;
1156d7c1e57SBarry Smith   PetscErrorCode    ierr;
1166d7c1e57SBarry Smith   Vec               in,out;
117*03049c21SJunchao Zhang   PetscScalar       scale;
118*03049c21SJunchao Zhang   PetscInt          i;
1196d7c1e57SBarry Smith 
1206d7c1e57SBarry Smith   PetscFunctionBegin;
121e32f2f54SBarry Smith   if (!tail) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
1226d7c1e57SBarry Smith   in = x;
123e4fc5df0SBarry Smith   if (shell->left) {
124e4fc5df0SBarry Smith     if (!shell->leftwork) {
125e4fc5df0SBarry Smith       ierr = VecDuplicate(shell->left,&shell->leftwork);CHKERRQ(ierr);
126e4fc5df0SBarry Smith     }
127e4fc5df0SBarry Smith     ierr = VecPointwiseMult(shell->leftwork,shell->left,in);CHKERRQ(ierr);
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 */
1322a7a6963SBarry Smith       ierr = MatCreateVecs(tail->mat,NULL,&tail->prev->work);CHKERRQ(ierr);
1336d7c1e57SBarry Smith     }
1346d7c1e57SBarry Smith     out  = tail->prev->work;
1356d7c1e57SBarry Smith     ierr = MatMultTranspose(tail->mat,in,out);CHKERRQ(ierr);
1366d7c1e57SBarry Smith     in   = out;
1376d7c1e57SBarry Smith     tail = tail->prev;
1386d7c1e57SBarry Smith   }
1396d7c1e57SBarry Smith   ierr = MatMultTranspose(tail->mat,in,y);CHKERRQ(ierr);
140e4fc5df0SBarry Smith   if (shell->right) {
141e4fc5df0SBarry Smith     ierr = VecPointwiseMult(y,shell->right,y);CHKERRQ(ierr);
142e4fc5df0SBarry Smith   }
143*03049c21SJunchao Zhang 
144*03049c21SJunchao Zhang   scale = shell->scale;
145*03049c21SJunchao Zhang   if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
146*03049c21SJunchao Zhang   ierr = VecScale(y,scale);CHKERRQ(ierr);
1476d7c1e57SBarry Smith   PetscFunctionReturn(0);
1486d7c1e57SBarry Smith }
1496d7c1e57SBarry Smith 
150*03049c21SJunchao Zhang PetscErrorCode MatMult_Composite(Mat mat,Vec x,Vec y)
151793850ffSBarry Smith {
152793850ffSBarry Smith   PetscErrorCode    ierr;
153*03049c21SJunchao Zhang   Mat_Composite     *shell = (Mat_Composite*)mat->data;
154*03049c21SJunchao Zhang   Mat_CompositeLink cur = shell->head;
155*03049c21SJunchao Zhang   Vec               in,y2,xin;
156*03049c21SJunchao Zhang   Mat               A,B;
157*03049c21SJunchao Zhang   PetscInt          i,j,k,n,nuniq,lo,hi,mid,*gindices,*buf,*tmp,tot;
158*03049c21SJunchao Zhang   const PetscScalar *vals;
159*03049c21SJunchao Zhang   const PetscInt    *garray;
160*03049c21SJunchao Zhang   IS                ix,iy;
161*03049c21SJunchao Zhang   PetscBool         match;
162793850ffSBarry Smith 
163793850ffSBarry Smith   PetscFunctionBegin;
164*03049c21SJunchao Zhang   if (!cur) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
165e4fc5df0SBarry Smith   in = x;
166e4fc5df0SBarry Smith   if (shell->right) {
167e4fc5df0SBarry Smith     if (!shell->rightwork) {
168e4fc5df0SBarry Smith       ierr = VecDuplicate(shell->right,&shell->rightwork);CHKERRQ(ierr);
169793850ffSBarry Smith     }
170e4fc5df0SBarry Smith     ierr = VecPointwiseMult(shell->rightwork,shell->right,in);CHKERRQ(ierr);
171e4fc5df0SBarry Smith     in   = shell->rightwork;
172e4fc5df0SBarry Smith   }
173*03049c21SJunchao Zhang 
174*03049c21SJunchao Zhang   /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
175*03049c21SJunchao Zhang      we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
176*03049c21SJunchao Zhang      it is legal to merge Mvctx, because all component matrices have the same size.
177*03049c21SJunchao Zhang    */
178*03049c21SJunchao Zhang   if (shell->merge_mvctx && !shell->Mvctx) {
179*03049c21SJunchao Zhang     /* Currently only implemented for MATMPIAIJ */
180*03049c21SJunchao Zhang     for (cur=shell->head; cur; cur=cur->next) {
181*03049c21SJunchao Zhang       ierr = PetscObjectTypeCompare((PetscObject)cur->mat,MATMPIAIJ,&match);CHKERRQ(ierr);
182*03049c21SJunchao Zhang       if (!match) {
183*03049c21SJunchao Zhang         shell->merge_mvctx = PETSC_FALSE;
184*03049c21SJunchao Zhang         goto skip_merge_mvctx;
185e4fc5df0SBarry Smith       }
186e4fc5df0SBarry Smith     }
187*03049c21SJunchao Zhang 
188*03049c21SJunchao Zhang     /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
189*03049c21SJunchao Zhang     tot = 0;
190*03049c21SJunchao Zhang     for (cur=shell->head; cur; cur=cur->next) {
191*03049c21SJunchao Zhang       ierr = MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,NULL);CHKERRQ(ierr);
192*03049c21SJunchao Zhang       ierr = MatGetLocalSize(B,NULL,&n);CHKERRQ(ierr);
193*03049c21SJunchao Zhang       tot += n;
194*03049c21SJunchao Zhang     }
195*03049c21SJunchao Zhang     ierr = PetscMalloc3(tot,&shell->location,tot,&shell->larray,shell->nmat,&shell->lvecs);CHKERRQ(ierr);
196*03049c21SJunchao Zhang     shell->len = tot;
197*03049c21SJunchao Zhang 
198*03049c21SJunchao Zhang     /* Go through matrices second time to sort off-diag columns and remove dups */
199*03049c21SJunchao Zhang     ierr  = PetscMalloc1(tot,&gindices);CHKERRQ(ierr); /* No Malloc2() since we will give one to petsc and free the other */
200*03049c21SJunchao Zhang     ierr  = PetscMalloc1(tot,&buf);CHKERRQ(ierr);
201*03049c21SJunchao Zhang     nuniq = 0; /* Number of unique nonzero columns */
202*03049c21SJunchao Zhang     for (cur=shell->head; cur; cur=cur->next) {
203*03049c21SJunchao Zhang       ierr = MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,&garray);CHKERRQ(ierr);
204*03049c21SJunchao Zhang       ierr = MatGetLocalSize(B,NULL,&n);CHKERRQ(ierr);
205*03049c21SJunchao Zhang       /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
206*03049c21SJunchao Zhang       i = j = k = 0;
207*03049c21SJunchao Zhang       while (i < n && j < nuniq) {
208*03049c21SJunchao Zhang         if (garray[i] < gindices[j]) buf[k++] = garray[i++];
209*03049c21SJunchao Zhang         else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
210*03049c21SJunchao Zhang         else {buf[k++] = garray[i++]; j++;}
211*03049c21SJunchao Zhang       }
212*03049c21SJunchao Zhang       /* Copy leftover in garray[] or gindices[] */
213*03049c21SJunchao Zhang       if (i < n) {
214*03049c21SJunchao Zhang         ierr  = PetscArraycpy(buf+k,garray+i,n-i);CHKERRQ(ierr);
215*03049c21SJunchao Zhang         nuniq = k + n-i;
216*03049c21SJunchao Zhang       } else if (j < nuniq) {
217*03049c21SJunchao Zhang         ierr  = PetscArraycpy(buf+k,gindices+j,nuniq-j);CHKERRQ(ierr);
218*03049c21SJunchao Zhang         nuniq = k + nuniq-j;
219*03049c21SJunchao Zhang       } else nuniq = k;
220*03049c21SJunchao Zhang       /* Swap gindices and buf to merge garray of the next matrix */
221*03049c21SJunchao Zhang       tmp      = gindices;
222*03049c21SJunchao Zhang       gindices = buf;
223*03049c21SJunchao Zhang       buf      = tmp;
224*03049c21SJunchao Zhang     }
225*03049c21SJunchao Zhang     ierr = PetscFree(buf);CHKERRQ(ierr);
226*03049c21SJunchao Zhang 
227*03049c21SJunchao Zhang     /* Go through matrices third time to build a map from gindices[] to garray[] */
228*03049c21SJunchao Zhang     tot = 0;
229*03049c21SJunchao Zhang     for (cur=shell->head,j=0; cur; cur=cur->next,j++) { /* j-th matrix */
230*03049c21SJunchao Zhang       ierr = MatMPIAIJGetSeqAIJ(cur->mat,NULL,&B,&garray);CHKERRQ(ierr);
231*03049c21SJunchao Zhang       ierr = MatGetLocalSize(B,NULL,&n);CHKERRQ(ierr);
232*03049c21SJunchao Zhang       ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,n,NULL,&shell->lvecs[j]);CHKERRQ(ierr);
233*03049c21SJunchao Zhang       /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
234*03049c21SJunchao Zhang       lo   = 0;
235*03049c21SJunchao Zhang       for (i=0; i<n; i++) {
236*03049c21SJunchao Zhang         hi = nuniq;
237*03049c21SJunchao Zhang         while (hi - lo > 1) {
238*03049c21SJunchao Zhang           mid = lo + (hi - lo)/2;
239*03049c21SJunchao Zhang           if (garray[i] < gindices[mid]) hi = mid;
240*03049c21SJunchao Zhang           else lo = mid;
241*03049c21SJunchao Zhang         }
242*03049c21SJunchao Zhang         shell->location[tot+i] = lo; /* gindices[lo] = garray[i] */
243*03049c21SJunchao Zhang         lo++; /* Since garray[i+1] > garray[i], we can safely advance lo */
244*03049c21SJunchao Zhang       }
245*03049c21SJunchao Zhang       tot += n;
246*03049c21SJunchao Zhang     }
247*03049c21SJunchao Zhang 
248*03049c21SJunchao Zhang     /* Build merged Mvctx */
249*03049c21SJunchao Zhang     ierr = ISCreateGeneral(PETSC_COMM_SELF,nuniq,gindices,PETSC_OWN_POINTER,&ix);CHKERRQ(ierr);
250*03049c21SJunchao Zhang     ierr = ISCreateStride(PETSC_COMM_SELF,nuniq,0,1,&iy);CHKERRQ(ierr);
251*03049c21SJunchao Zhang     ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat),1,mat->cmap->n,mat->cmap->N,NULL,&xin);CHKERRQ(ierr);
252*03049c21SJunchao Zhang     ierr = VecCreateSeq(PETSC_COMM_SELF,nuniq,&shell->gvec);CHKERRQ(ierr);
253*03049c21SJunchao Zhang     ierr = VecScatterCreate(xin,ix,shell->gvec,iy,&shell->Mvctx);CHKERRQ(ierr);
254*03049c21SJunchao Zhang     ierr = VecDestroy(&xin);CHKERRQ(ierr);
255*03049c21SJunchao Zhang     ierr = ISDestroy(&ix);CHKERRQ(ierr);
256*03049c21SJunchao Zhang     ierr = ISDestroy(&iy);CHKERRQ(ierr);
257*03049c21SJunchao Zhang   }
258*03049c21SJunchao Zhang 
259*03049c21SJunchao Zhang skip_merge_mvctx:
260*03049c21SJunchao Zhang   ierr = VecSet(y,0);CHKERRQ(ierr);
261*03049c21SJunchao Zhang   if (!shell->leftwork2) {ierr = VecDuplicate(y,&shell->leftwork2);CHKERRQ(ierr);}
262*03049c21SJunchao Zhang   y2 = shell->leftwork2;
263*03049c21SJunchao Zhang 
264*03049c21SJunchao Zhang   if (shell->Mvctx) { /* Have a merged Mvctx */
265*03049c21SJunchao 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
266*03049c21SJunchao Zhang        in y = s(Ax1 + Bx2) or y = sAx1 + sBx2. The former incurs less FLOPS than the latter, but the latter provides an oppertunity to
267*03049c21SJunchao Zhang        overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
268*03049c21SJunchao Zhang      */
269*03049c21SJunchao Zhang     ierr = VecScatterBegin(shell->Mvctx,in,shell->gvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
270*03049c21SJunchao Zhang     ierr = VecScatterEnd(shell->Mvctx,in,shell->gvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
271*03049c21SJunchao Zhang 
272*03049c21SJunchao Zhang     ierr = VecGetArrayRead(shell->gvec,&vals);CHKERRQ(ierr);
273*03049c21SJunchao Zhang     for (i=0; i<shell->len; i++) shell->larray[i] = vals[shell->location[i]];
274*03049c21SJunchao Zhang     ierr = VecRestoreArrayRead(shell->gvec,&vals);CHKERRQ(ierr);
275*03049c21SJunchao Zhang 
276*03049c21SJunchao Zhang     for (cur=shell->head,tot=i=0; cur; cur=cur->next,i++) { /* i-th matrix */
277*03049c21SJunchao Zhang       ierr = MatMPIAIJGetSeqAIJ(cur->mat,&A,&B,NULL);CHKERRQ(ierr);
278*03049c21SJunchao Zhang       ierr = (*A->ops->mult)(A,in,y2);CHKERRQ(ierr);
279*03049c21SJunchao Zhang       ierr = MatGetLocalSize(B,NULL,&n);CHKERRQ(ierr);
280*03049c21SJunchao Zhang       ierr = VecPlaceArray(shell->lvecs[i],&shell->larray[tot]);CHKERRQ(ierr);
281*03049c21SJunchao Zhang       ierr = (*B->ops->multadd)(B,shell->lvecs[i],y2,y2);CHKERRQ(ierr);
282*03049c21SJunchao Zhang       ierr = VecResetArray(shell->lvecs[i]);CHKERRQ(ierr);
283*03049c21SJunchao Zhang       ierr = VecAXPY(y,(shell->scalings ? shell->scalings[i] : 1.0),y2);CHKERRQ(ierr);
284*03049c21SJunchao Zhang       tot += n;
285*03049c21SJunchao Zhang     }
286*03049c21SJunchao Zhang   } else {
287*03049c21SJunchao Zhang     if (shell->scalings) {
288*03049c21SJunchao Zhang       for (cur=shell->head,i=0; cur; cur=cur->next,i++) {
289*03049c21SJunchao Zhang         ierr = MatMult(cur->mat,in,y2);CHKERRQ(ierr);
290*03049c21SJunchao Zhang         ierr = VecAXPY(y,shell->scalings[i],y2);CHKERRQ(ierr);
291*03049c21SJunchao Zhang       }
292*03049c21SJunchao Zhang     } else {
293*03049c21SJunchao Zhang       for (cur=shell->head; cur; cur=cur->next) {ierr = MatMultAdd(cur->mat,in,y,y);CHKERRQ(ierr);}
294*03049c21SJunchao Zhang     }
295*03049c21SJunchao Zhang   }
296*03049c21SJunchao Zhang 
297*03049c21SJunchao Zhang   if (shell->left) {ierr = VecPointwiseMult(y,shell->left,y);CHKERRQ(ierr);}
298e4fc5df0SBarry Smith   ierr = VecScale(y,shell->scale);CHKERRQ(ierr);
299793850ffSBarry Smith   PetscFunctionReturn(0);
300793850ffSBarry Smith }
301793850ffSBarry Smith 
302793850ffSBarry Smith PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
303793850ffSBarry Smith {
304793850ffSBarry Smith   Mat_Composite     *shell = (Mat_Composite*)A->data;
305793850ffSBarry Smith   Mat_CompositeLink next   = shell->head;
306793850ffSBarry Smith   PetscErrorCode    ierr;
307*03049c21SJunchao Zhang   Vec               in,y2 = NULL;
308*03049c21SJunchao Zhang   PetscInt          i;
309793850ffSBarry Smith 
310793850ffSBarry Smith   PetscFunctionBegin;
311e32f2f54SBarry Smith   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
312e4fc5df0SBarry Smith   in = x;
313e4fc5df0SBarry Smith   if (shell->left) {
314e4fc5df0SBarry Smith     if (!shell->leftwork) {
315e4fc5df0SBarry Smith       ierr = VecDuplicate(shell->left,&shell->leftwork);CHKERRQ(ierr);
316793850ffSBarry Smith     }
317e4fc5df0SBarry Smith     ierr = VecPointwiseMult(shell->leftwork,shell->left,in);CHKERRQ(ierr);
318e4fc5df0SBarry Smith     in   = shell->leftwork;
319e4fc5df0SBarry Smith   }
320*03049c21SJunchao Zhang 
321e4fc5df0SBarry Smith   ierr = MatMultTranspose(next->mat,in,y);CHKERRQ(ierr);
322*03049c21SJunchao Zhang   if (shell->scalings) {
323*03049c21SJunchao Zhang     ierr = VecScale(y,shell->scalings[0]);CHKERRQ(ierr);
324*03049c21SJunchao Zhang     if (!shell->rightwork2) {ierr = VecDuplicate(y,&shell->rightwork2);CHKERRQ(ierr);}
325*03049c21SJunchao Zhang     y2 = shell->rightwork2;
326*03049c21SJunchao Zhang   }
327*03049c21SJunchao Zhang   i = 1;
328e4fc5df0SBarry Smith   while ((next = next->next)) {
329*03049c21SJunchao Zhang     if (!shell->scalings) {ierr = MatMultTransposeAdd(next->mat,in,y,y);CHKERRQ(ierr);}
330*03049c21SJunchao Zhang     else {
331*03049c21SJunchao Zhang       ierr = MatMultTranspose(next->mat,in,y2);CHKERRQ(ierr);
332*03049c21SJunchao Zhang       ierr = VecAXPY(y,shell->scalings[i++],y2);CHKERRQ(ierr);
333*03049c21SJunchao Zhang     }
334e4fc5df0SBarry Smith   }
335e4fc5df0SBarry Smith   if (shell->right) {
336e4fc5df0SBarry Smith     ierr = VecPointwiseMult(y,shell->right,y);CHKERRQ(ierr);
337e4fc5df0SBarry Smith   }
338e4fc5df0SBarry Smith   ierr = VecScale(y,shell->scale);CHKERRQ(ierr);
339793850ffSBarry Smith   PetscFunctionReturn(0);
340793850ffSBarry Smith }
341793850ffSBarry Smith 
3427bf3a71bSJakub Kruzik PetscErrorCode MatMultAdd_Composite(Mat A,Vec x,Vec y,Vec z)
3437bf3a71bSJakub Kruzik {
3447bf3a71bSJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)A->data;
3457bf3a71bSJakub Kruzik   PetscErrorCode    ierr;
3467bf3a71bSJakub Kruzik 
3477bf3a71bSJakub Kruzik   PetscFunctionBegin;
3487bf3a71bSJakub Kruzik   if (y != z) {
3497bf3a71bSJakub Kruzik     ierr = MatMult(A,x,z);CHKERRQ(ierr);
3507bf3a71bSJakub Kruzik     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
3517bf3a71bSJakub Kruzik   } else {
3527bf3a71bSJakub Kruzik     if (!shell->leftwork) {
3537bf3a71bSJakub Kruzik       ierr = VecDuplicate(z,&shell->leftwork);CHKERRQ(ierr);
3547bf3a71bSJakub Kruzik     }
3557bf3a71bSJakub Kruzik     ierr = MatMult(A,x,shell->leftwork);CHKERRQ(ierr);
3567bf3a71bSJakub Kruzik     ierr = VecCopy(y,z);CHKERRQ(ierr);
3577bf3a71bSJakub Kruzik     ierr = VecAXPY(z,1.0,shell->leftwork);CHKERRQ(ierr);
3587bf3a71bSJakub Kruzik   }
3597bf3a71bSJakub Kruzik   PetscFunctionReturn(0);
3607bf3a71bSJakub Kruzik }
3617bf3a71bSJakub Kruzik 
3627bf3a71bSJakub Kruzik PetscErrorCode MatMultTransposeAdd_Composite(Mat A,Vec x,Vec y, Vec z)
3637bf3a71bSJakub Kruzik {
3647bf3a71bSJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)A->data;
3657bf3a71bSJakub Kruzik   PetscErrorCode    ierr;
3667bf3a71bSJakub Kruzik 
3677bf3a71bSJakub Kruzik   PetscFunctionBegin;
3687bf3a71bSJakub Kruzik   if (y != z) {
3697bf3a71bSJakub Kruzik     ierr = MatMultTranspose(A,x,z);CHKERRQ(ierr);
3707bf3a71bSJakub Kruzik     ierr = VecAXPY(z,1.0,y);CHKERRQ(ierr);
3717bf3a71bSJakub Kruzik   } else {
3727bf3a71bSJakub Kruzik     if (!shell->rightwork) {
3737bf3a71bSJakub Kruzik       ierr = VecDuplicate(z,&shell->rightwork);CHKERRQ(ierr);
3747bf3a71bSJakub Kruzik     }
3757bf3a71bSJakub Kruzik     ierr = MatMultTranspose(A,x,shell->rightwork);CHKERRQ(ierr);
3767bf3a71bSJakub Kruzik     ierr = VecCopy(y,z);CHKERRQ(ierr);
3777bf3a71bSJakub Kruzik     ierr = VecAXPY(z,1.0,shell->rightwork);CHKERRQ(ierr);
3787bf3a71bSJakub Kruzik   }
3797bf3a71bSJakub Kruzik   PetscFunctionReturn(0);
3807bf3a71bSJakub Kruzik }
3817bf3a71bSJakub Kruzik 
382793850ffSBarry Smith PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
383793850ffSBarry Smith {
384793850ffSBarry Smith   Mat_Composite     *shell = (Mat_Composite*)A->data;
385793850ffSBarry Smith   Mat_CompositeLink next   = shell->head;
386793850ffSBarry Smith   PetscErrorCode    ierr;
387*03049c21SJunchao Zhang   PetscInt          i;
388793850ffSBarry Smith 
389793850ffSBarry Smith   PetscFunctionBegin;
390e32f2f54SBarry Smith   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
391e32f2f54SBarry Smith   if (shell->right || shell->left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get diagonal if left or right scaling");
392e4fc5df0SBarry Smith 
393793850ffSBarry Smith   ierr = MatGetDiagonal(next->mat,v);CHKERRQ(ierr);
394*03049c21SJunchao Zhang   if (shell->scalings) {ierr = VecScale(v,shell->scalings[0]);CHKERRQ(ierr);}
395*03049c21SJunchao Zhang 
396793850ffSBarry Smith   if (next->next && !shell->work) {
397793850ffSBarry Smith     ierr = VecDuplicate(v,&shell->work);CHKERRQ(ierr);
398793850ffSBarry Smith   }
399*03049c21SJunchao Zhang   i = 1;
400793850ffSBarry Smith   while ((next = next->next)) {
401793850ffSBarry Smith     ierr = MatGetDiagonal(next->mat,shell->work);CHKERRQ(ierr);
402*03049c21SJunchao Zhang     ierr = VecAXPY(v,(shell->scalings ? shell->scalings[i++] : 1.0),shell->work);CHKERRQ(ierr);
403793850ffSBarry Smith   }
404e4fc5df0SBarry Smith   ierr = VecScale(v,shell->scale);CHKERRQ(ierr);
405793850ffSBarry Smith   PetscFunctionReturn(0);
406793850ffSBarry Smith }
407793850ffSBarry Smith 
408793850ffSBarry Smith PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
409793850ffSBarry Smith {
4104b2558d6SJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)Y->data;
411b52f573bSBarry Smith   PetscErrorCode    ierr;
412b52f573bSBarry Smith 
413793850ffSBarry Smith   PetscFunctionBegin;
4144b2558d6SJakub Kruzik   if (shell->merge) {
415b52f573bSBarry Smith     ierr = MatCompositeMerge(Y);CHKERRQ(ierr);
416b52f573bSBarry Smith   }
417*03049c21SJunchao Zhang 
418793850ffSBarry Smith   PetscFunctionReturn(0);
419793850ffSBarry Smith }
420793850ffSBarry Smith 
421e4fc5df0SBarry Smith PetscErrorCode MatScale_Composite(Mat inA,PetscScalar alpha)
422e4fc5df0SBarry Smith {
423e4fc5df0SBarry Smith   Mat_Composite *a = (Mat_Composite*)inA->data;
424e4fc5df0SBarry Smith 
425e4fc5df0SBarry Smith   PetscFunctionBegin;
426321429dbSBarry Smith   a->scale *= alpha;
427e4fc5df0SBarry Smith   PetscFunctionReturn(0);
428e4fc5df0SBarry Smith }
429e4fc5df0SBarry Smith 
430e4fc5df0SBarry Smith PetscErrorCode MatDiagonalScale_Composite(Mat inA,Vec left,Vec right)
431e4fc5df0SBarry Smith {
432e4fc5df0SBarry Smith   Mat_Composite  *a = (Mat_Composite*)inA->data;
433e4fc5df0SBarry Smith   PetscErrorCode ierr;
434e4fc5df0SBarry Smith 
435e4fc5df0SBarry Smith   PetscFunctionBegin;
436e4fc5df0SBarry Smith   if (left) {
437321429dbSBarry Smith     if (!a->left) {
438e4fc5df0SBarry Smith       ierr = VecDuplicate(left,&a->left);CHKERRQ(ierr);
439e4fc5df0SBarry Smith       ierr = VecCopy(left,a->left);CHKERRQ(ierr);
440321429dbSBarry Smith     } else {
441321429dbSBarry Smith       ierr = VecPointwiseMult(a->left,left,a->left);CHKERRQ(ierr);
442321429dbSBarry Smith     }
443e4fc5df0SBarry Smith   }
444e4fc5df0SBarry Smith   if (right) {
445321429dbSBarry Smith     if (!a->right) {
446e4fc5df0SBarry Smith       ierr = VecDuplicate(right,&a->right);CHKERRQ(ierr);
447e4fc5df0SBarry Smith       ierr = VecCopy(right,a->right);CHKERRQ(ierr);
448321429dbSBarry Smith     } else {
449321429dbSBarry Smith       ierr = VecPointwiseMult(a->right,right,a->right);CHKERRQ(ierr);
450321429dbSBarry Smith     }
451e4fc5df0SBarry Smith   }
452e4fc5df0SBarry Smith   PetscFunctionReturn(0);
453e4fc5df0SBarry Smith }
454793850ffSBarry Smith 
4554b2558d6SJakub Kruzik PetscErrorCode MatSetFromOptions_Composite(PetscOptionItems *PetscOptionsObject,Mat A)
4564b2558d6SJakub Kruzik {
4574b2558d6SJakub Kruzik   Mat_Composite  *a = (Mat_Composite*)A->data;
4584b2558d6SJakub Kruzik   PetscErrorCode ierr;
4594b2558d6SJakub Kruzik 
4604b2558d6SJakub Kruzik   PetscFunctionBegin;
4614b2558d6SJakub Kruzik   ierr = PetscOptionsHead(PetscOptionsObject,"MATCOMPOSITE options");CHKERRQ(ierr);
4624b2558d6SJakub Kruzik   ierr = PetscOptionsBool("-mat_composite_merge","Merge at MatAssemblyEnd","MatCompositeMerge",a->merge,&a->merge,NULL);CHKERRQ(ierr);
4638c8613bfSJakub Kruzik   ierr = PetscOptionsEnum("-mat_composite_merge_type","Set composite merge direction","MatCompositeSetMergeType",MatCompositeMergeTypes,(PetscEnum)a->mergetype,(PetscEnum*)&a->mergetype,NULL);CHKERRQ(ierr);
464*03049c21SJunchao Zhang   ierr = PetscOptionsBool("-mat_composite_merge_mvctx","Merge MatMult() vecscat contexts","MatCreateComposite",a->merge_mvctx,&a->merge_mvctx,NULL);CHKERRQ(ierr);
4654b2558d6SJakub Kruzik   ierr = PetscOptionsTail();CHKERRQ(ierr);
4664b2558d6SJakub Kruzik   PetscFunctionReturn(0);
4674b2558d6SJakub Kruzik }
4684b2558d6SJakub Kruzik 
4692c0821f3SBarry Smith /*@
4708bd739bdSJakub Kruzik    MatCreateComposite - Creates a matrix as the sum or product of one or more matrices
471793850ffSBarry Smith 
472d083f849SBarry Smith   Collective
473793850ffSBarry Smith 
474793850ffSBarry Smith    Input Parameters:
475793850ffSBarry Smith +  comm - MPI communicator
476793850ffSBarry Smith .  nmat - number of matrices to put in
477793850ffSBarry Smith -  mats - the matrices
478793850ffSBarry Smith 
479793850ffSBarry Smith    Output Parameter:
480db36af27SMatthew G. Knepley .  mat - the matrix
481793850ffSBarry Smith 
4824b2558d6SJakub Kruzik    Options Database Keys:
4834b2558d6SJakub Kruzik +  -mat_composite_merge         - merge in MatAssemblyEnd()
484*03049c21SJunchao Zhang .  -mat_composite_merge_mvctx   - merge Mvctx of component matrices to optimize communication in MatMult() for ADDITIVE matrices
485b28d0daaSJakub Kruzik -  -mat_composite_merge_type    - set merge direction
4864b2558d6SJakub Kruzik 
487793850ffSBarry Smith    Level: advanced
488793850ffSBarry Smith 
489793850ffSBarry Smith    Notes:
490793850ffSBarry Smith      Alternative construction
491793850ffSBarry Smith $       MatCreate(comm,&mat);
492793850ffSBarry Smith $       MatSetSizes(mat,m,n,M,N);
493793850ffSBarry Smith $       MatSetType(mat,MATCOMPOSITE);
494793850ffSBarry Smith $       MatCompositeAddMat(mat,mats[0]);
495793850ffSBarry Smith $       ....
496793850ffSBarry Smith $       MatCompositeAddMat(mat,mats[nmat-1]);
497b52f573bSBarry Smith $       MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
498b52f573bSBarry Smith $       MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
499793850ffSBarry Smith 
5006d7c1e57SBarry Smith      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]
5016d7c1e57SBarry Smith 
5026dbc55e5SJakub Kruzik .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeGetMat(), MatCompositeMerge(), MatCompositeSetType(), MATCOMPOSITE
503793850ffSBarry Smith 
504793850ffSBarry Smith @*/
5057087cfbeSBarry Smith PetscErrorCode MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
506793850ffSBarry Smith {
507793850ffSBarry Smith   PetscErrorCode ierr;
508793850ffSBarry Smith   PetscInt       m,n,M,N,i;
509793850ffSBarry Smith 
510793850ffSBarry Smith   PetscFunctionBegin;
511e32f2f54SBarry Smith   if (nmat < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");
512f3f84630SBarry Smith   PetscValidPointer(mat,3);
513793850ffSBarry Smith 
514c4f13f43SJakub Kruzik   ierr = MatGetLocalSize(mats[0],PETSC_IGNORE,&n);CHKERRQ(ierr);
515c4f13f43SJakub Kruzik   ierr = MatGetLocalSize(mats[nmat-1],&m,PETSC_IGNORE);CHKERRQ(ierr);
516c4f13f43SJakub Kruzik   ierr = MatGetSize(mats[0],PETSC_IGNORE,&N);CHKERRQ(ierr);
517c4f13f43SJakub Kruzik   ierr = MatGetSize(mats[nmat-1],&M,PETSC_IGNORE);CHKERRQ(ierr);
518793850ffSBarry Smith   ierr = MatCreate(comm,mat);CHKERRQ(ierr);
519793850ffSBarry Smith   ierr = MatSetSizes(*mat,m,n,M,N);CHKERRQ(ierr);
520793850ffSBarry Smith   ierr = MatSetType(*mat,MATCOMPOSITE);CHKERRQ(ierr);
521793850ffSBarry Smith   for (i=0; i<nmat; i++) {
522793850ffSBarry Smith     ierr = MatCompositeAddMat(*mat,mats[i]);CHKERRQ(ierr);
523793850ffSBarry Smith   }
524b52f573bSBarry Smith   ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
525b52f573bSBarry Smith   ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
526793850ffSBarry Smith   PetscFunctionReturn(0);
527793850ffSBarry Smith }
528793850ffSBarry Smith 
529d7f81bf2SJakub Kruzik 
530d7f81bf2SJakub Kruzik static PetscErrorCode MatCompositeAddMat_Composite(Mat mat,Mat smat)
531d7f81bf2SJakub Kruzik {
532d7f81bf2SJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)mat->data;
533d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink,next = shell->head;
534d7f81bf2SJakub Kruzik   PetscErrorCode    ierr;
535d7f81bf2SJakub Kruzik 
536d7f81bf2SJakub Kruzik   PetscFunctionBegin;
537d7f81bf2SJakub Kruzik   ierr        = PetscNewLog(mat,&ilink);CHKERRQ(ierr);
538d7f81bf2SJakub Kruzik   ilink->next = 0;
539d7f81bf2SJakub Kruzik   ierr        = PetscObjectReference((PetscObject)smat);CHKERRQ(ierr);
540d7f81bf2SJakub Kruzik   ilink->mat  = smat;
541d7f81bf2SJakub Kruzik 
542d7f81bf2SJakub Kruzik   if (!next) shell->head = ilink;
543d7f81bf2SJakub Kruzik   else {
544d7f81bf2SJakub Kruzik     while (next->next) {
545d7f81bf2SJakub Kruzik       next = next->next;
546d7f81bf2SJakub Kruzik     }
547d7f81bf2SJakub Kruzik     next->next  = ilink;
548d7f81bf2SJakub Kruzik     ilink->prev = next;
549d7f81bf2SJakub Kruzik   }
550d7f81bf2SJakub Kruzik   shell->tail =  ilink;
551d7f81bf2SJakub Kruzik   shell->nmat += 1;
552*03049c21SJunchao Zhang 
553*03049c21SJunchao Zhang   /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
554*03049c21SJunchao Zhang   if (shell->scalings) {
555*03049c21SJunchao Zhang     ierr = PetscRealloc(sizeof(PetscScalar)*shell->nmat,&shell->scalings);CHKERRQ(ierr);
556*03049c21SJunchao Zhang     shell->scalings[shell->nmat-1] = 1.0;
557*03049c21SJunchao Zhang   }
558d7f81bf2SJakub Kruzik   PetscFunctionReturn(0);
559d7f81bf2SJakub Kruzik }
560d7f81bf2SJakub Kruzik 
561793850ffSBarry Smith /*@
5628bd739bdSJakub Kruzik     MatCompositeAddMat - Add another matrix to a composite matrix.
563793850ffSBarry Smith 
564793850ffSBarry Smith    Collective on Mat
565793850ffSBarry Smith 
566793850ffSBarry Smith     Input Parameters:
567793850ffSBarry Smith +   mat - the composite matrix
568793850ffSBarry Smith -   smat - the partial matrix
569793850ffSBarry Smith 
570793850ffSBarry Smith    Level: advanced
571793850ffSBarry Smith 
5728bd739bdSJakub Kruzik .seealso: MatCreateComposite(), MatCompositeGetMat(), MATCOMPOSITE
573793850ffSBarry Smith @*/
5747087cfbeSBarry Smith PetscErrorCode MatCompositeAddMat(Mat mat,Mat smat)
575793850ffSBarry Smith {
576793850ffSBarry Smith   PetscErrorCode    ierr;
577793850ffSBarry Smith 
578793850ffSBarry Smith   PetscFunctionBegin;
5790700a824SBarry Smith   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
5800700a824SBarry Smith   PetscValidHeaderSpecific(smat,MAT_CLASSID,2);
581d7f81bf2SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeAddMat_C",(Mat,Mat),(mat,smat));CHKERRQ(ierr);
582d7f81bf2SJakub Kruzik   PetscFunctionReturn(0);
583d7f81bf2SJakub Kruzik }
584793850ffSBarry Smith 
585d7f81bf2SJakub Kruzik static PetscErrorCode MatCompositeSetType_Composite(Mat mat,MatCompositeType type)
586d7f81bf2SJakub Kruzik {
587d7f81bf2SJakub Kruzik   Mat_Composite  *b = (Mat_Composite*)mat->data;
588d7f81bf2SJakub Kruzik 
589d7f81bf2SJakub Kruzik   PetscFunctionBegin;
590ced1ac25SJakub Kruzik   b->type = type;
591d7f81bf2SJakub Kruzik   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
592d7f81bf2SJakub Kruzik     mat->ops->getdiagonal   = 0;
593d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite_Multiplicative;
594d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
595*03049c21SJunchao Zhang     b->merge_mvctx          = PETSC_FALSE;
596d7f81bf2SJakub Kruzik   } else {
597d7f81bf2SJakub Kruzik     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
598d7f81bf2SJakub Kruzik     mat->ops->mult          = MatMult_Composite;
599d7f81bf2SJakub Kruzik     mat->ops->multtranspose = MatMultTranspose_Composite;
600793850ffSBarry Smith   }
6016d7c1e57SBarry Smith   PetscFunctionReturn(0);
6026d7c1e57SBarry Smith }
6036d7c1e57SBarry Smith 
6042c0821f3SBarry Smith /*@
6058bd739bdSJakub Kruzik    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.
6066d7c1e57SBarry Smith 
607b2b245abSJakub Kruzik    Logically Collective on Mat
6086d7c1e57SBarry Smith 
6096d7c1e57SBarry Smith    Input Parameters:
6106d7c1e57SBarry Smith .  mat - the composite matrix
6116d7c1e57SBarry Smith 
6126d7c1e57SBarry Smith    Level: advanced
6136d7c1e57SBarry Smith 
6146dbc55e5SJakub Kruzik .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MatCompositeGetType(), MATCOMPOSITE
6156d7c1e57SBarry Smith 
6166d7c1e57SBarry Smith @*/
6177087cfbeSBarry Smith PetscErrorCode MatCompositeSetType(Mat mat,MatCompositeType type)
6186d7c1e57SBarry Smith {
6196d7c1e57SBarry Smith   PetscErrorCode ierr;
6206d7c1e57SBarry Smith 
6216d7c1e57SBarry Smith   PetscFunctionBegin;
622d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
623b2b245abSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat,type,2);
624d7f81bf2SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeSetType_C",(Mat,MatCompositeType),(mat,type));CHKERRQ(ierr);
625793850ffSBarry Smith   PetscFunctionReturn(0);
626793850ffSBarry Smith }
627793850ffSBarry Smith 
6286dbc55e5SJakub Kruzik static PetscErrorCode MatCompositeGetType_Composite(Mat mat,MatCompositeType *type)
6296dbc55e5SJakub Kruzik {
6306dbc55e5SJakub Kruzik   Mat_Composite  *b = (Mat_Composite*)mat->data;
6316dbc55e5SJakub Kruzik 
6326dbc55e5SJakub Kruzik   PetscFunctionBegin;
6336dbc55e5SJakub Kruzik   *type = b->type;
6346dbc55e5SJakub Kruzik   PetscFunctionReturn(0);
6356dbc55e5SJakub Kruzik }
6366dbc55e5SJakub Kruzik 
6376dbc55e5SJakub Kruzik /*@
6386dbc55e5SJakub Kruzik    MatCompositeGetType - Returns type of composite.
6396dbc55e5SJakub Kruzik 
6406dbc55e5SJakub Kruzik    Not Collective
6416dbc55e5SJakub Kruzik 
6426dbc55e5SJakub Kruzik    Input Parameter:
6436dbc55e5SJakub Kruzik .  mat - the composite matrix
6446dbc55e5SJakub Kruzik 
6456dbc55e5SJakub Kruzik    Output Parameter:
6466dbc55e5SJakub Kruzik .  type - type of composite
6476dbc55e5SJakub Kruzik 
6486dbc55e5SJakub Kruzik    Level: advanced
6496dbc55e5SJakub Kruzik 
6506dbc55e5SJakub Kruzik .seealso: MatCreateComposite(), MatCompositeSetType(), MATCOMPOSITE
6516dbc55e5SJakub Kruzik 
6526dbc55e5SJakub Kruzik @*/
6536dbc55e5SJakub Kruzik PetscErrorCode MatCompositeGetType(Mat mat,MatCompositeType *type)
6546dbc55e5SJakub Kruzik {
6556dbc55e5SJakub Kruzik   PetscErrorCode ierr;
6566dbc55e5SJakub Kruzik 
6576dbc55e5SJakub Kruzik   PetscFunctionBegin;
6586dbc55e5SJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
6596dbc55e5SJakub Kruzik   PetscValidPointer(type,2);
6606dbc55e5SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeGetType_C",(Mat,MatCompositeType*),(mat,type));CHKERRQ(ierr);
6616dbc55e5SJakub Kruzik   PetscFunctionReturn(0);
6626dbc55e5SJakub Kruzik }
6636dbc55e5SJakub Kruzik 
6643b35acafSJakub Kruzik static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat,MatStructure str)
6653b35acafSJakub Kruzik {
6663b35acafSJakub Kruzik   Mat_Composite  *b = (Mat_Composite*)mat->data;
6673b35acafSJakub Kruzik 
6683b35acafSJakub Kruzik   PetscFunctionBegin;
6693b35acafSJakub Kruzik   b->structure = str;
6703b35acafSJakub Kruzik   PetscFunctionReturn(0);
6713b35acafSJakub Kruzik }
6723b35acafSJakub Kruzik 
6733b35acafSJakub Kruzik /*@
6743b35acafSJakub Kruzik    MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.
6753b35acafSJakub Kruzik 
6763b35acafSJakub Kruzik    Not Collective
6773b35acafSJakub Kruzik 
6783b35acafSJakub Kruzik    Input Parameters:
6793b35acafSJakub Kruzik +  mat - the composite matrix
6803b35acafSJakub Kruzik -  str - either SAME_NONZERO_PATTERN, DIFFERENT_NONZERO_PATTERN (default) or SUBSET_NONZERO_PATTERN
6813b35acafSJakub Kruzik 
6823b35acafSJakub Kruzik    Level: advanced
6833b35acafSJakub Kruzik 
6843b35acafSJakub Kruzik    Notes:
6853b35acafSJakub Kruzik     Information about the matrices structure is used in MatCompositeMerge() for additive composite matrix.
6863b35acafSJakub Kruzik 
6873b35acafSJakub Kruzik .seealso: MatAXPY(), MatCreateComposite(), MatCompositeMerge() MatCompositeGetMatStructure(), MATCOMPOSITE
6883b35acafSJakub Kruzik 
6893b35acafSJakub Kruzik @*/
6903b35acafSJakub Kruzik PetscErrorCode MatCompositeSetMatStructure(Mat mat,MatStructure str)
6913b35acafSJakub Kruzik {
6923b35acafSJakub Kruzik   PetscErrorCode ierr;
6933b35acafSJakub Kruzik 
6943b35acafSJakub Kruzik   PetscFunctionBegin;
6953b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
6963b35acafSJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeSetMatStructure_C",(Mat,MatStructure),(mat,str));CHKERRQ(ierr);
6973b35acafSJakub Kruzik   PetscFunctionReturn(0);
6983b35acafSJakub Kruzik }
6993b35acafSJakub Kruzik 
7003b35acafSJakub Kruzik static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat,MatStructure *str)
7013b35acafSJakub Kruzik {
7023b35acafSJakub Kruzik   Mat_Composite  *b = (Mat_Composite*)mat->data;
7033b35acafSJakub Kruzik 
7043b35acafSJakub Kruzik   PetscFunctionBegin;
7053b35acafSJakub Kruzik   *str = b->structure;
7063b35acafSJakub Kruzik   PetscFunctionReturn(0);
7073b35acafSJakub Kruzik }
7083b35acafSJakub Kruzik 
7093b35acafSJakub Kruzik /*@
7103b35acafSJakub Kruzik    MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.
7113b35acafSJakub Kruzik 
7123b35acafSJakub Kruzik    Not Collective
7133b35acafSJakub Kruzik 
7143b35acafSJakub Kruzik    Input Parameter:
7153b35acafSJakub Kruzik .  mat - the composite matrix
7163b35acafSJakub Kruzik 
7173b35acafSJakub Kruzik    Output Parameter:
7183b35acafSJakub Kruzik .  str - structure of the matrices
7193b35acafSJakub Kruzik 
7203b35acafSJakub Kruzik    Level: advanced
7213b35acafSJakub Kruzik 
7223b35acafSJakub Kruzik .seealso: MatCreateComposite(), MatCompositeSetMatStructure(), MATCOMPOSITE
7233b35acafSJakub Kruzik 
7243b35acafSJakub Kruzik @*/
7253b35acafSJakub Kruzik PetscErrorCode MatCompositeGetMatStructure(Mat mat,MatStructure *str)
7263b35acafSJakub Kruzik {
7273b35acafSJakub Kruzik   PetscErrorCode ierr;
7283b35acafSJakub Kruzik 
7293b35acafSJakub Kruzik   PetscFunctionBegin;
7303b35acafSJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
7313b35acafSJakub Kruzik   PetscValidPointer(str,2);
7323b35acafSJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeGetMatStructure_C",(Mat,MatStructure*),(mat,str));CHKERRQ(ierr);
7333b35acafSJakub Kruzik   PetscFunctionReturn(0);
7343b35acafSJakub Kruzik }
7353b35acafSJakub Kruzik 
7368c8613bfSJakub Kruzik static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat,MatCompositeMergeType type)
7378c8613bfSJakub Kruzik {
7388c8613bfSJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)mat->data;
7398c8613bfSJakub Kruzik 
7408c8613bfSJakub Kruzik   PetscFunctionBegin;
7418c8613bfSJakub Kruzik   shell->mergetype = type;
7428c8613bfSJakub Kruzik   PetscFunctionReturn(0);
7438c8613bfSJakub Kruzik }
7448c8613bfSJakub Kruzik 
7458c8613bfSJakub Kruzik /*@
7468c8613bfSJakub Kruzik    MatCompositeSetMergeType - Sets order of MatCompositeMerge().
7478c8613bfSJakub Kruzik 
7488c8613bfSJakub Kruzik    Logically Collective on Mat
7498c8613bfSJakub Kruzik 
7508c8613bfSJakub Kruzik    Input Parameter:
7518c8613bfSJakub Kruzik +  mat - the composite matrix
7528c8613bfSJakub Kruzik -  type - MAT_COMPOSITE_MERGE RIGHT (default) to start merge from right with the first added matrix (mat[0]),
7538c8613bfSJakub Kruzik           MAT_COMPOSITE_MERGE_LEFT to start merge from left with the last added matrix (mat[nmat-1])
7548c8613bfSJakub Kruzik 
7558c8613bfSJakub Kruzik    Level: advanced
7568c8613bfSJakub Kruzik 
7578c8613bfSJakub Kruzik    Notes:
7588c8613bfSJakub Kruzik     The resulting matrix is the same regardles of the MergeType. Only the order of operation is changed.
7598c8613bfSJakub Kruzik     If set to MAT_COMPOSITE_MERGE_RIGHT the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
7608c8613bfSJakub Kruzik     otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].
7618c8613bfSJakub Kruzik 
7628c8613bfSJakub Kruzik .seealso: MatCreateComposite(), MatCompositeMerge(), MATCOMPOSITE
7638c8613bfSJakub Kruzik 
7648c8613bfSJakub Kruzik @*/
7658c8613bfSJakub Kruzik PetscErrorCode MatCompositeSetMergeType(Mat mat,MatCompositeMergeType type)
7668c8613bfSJakub Kruzik {
7678c8613bfSJakub Kruzik   PetscErrorCode ierr;
7688c8613bfSJakub Kruzik 
7698c8613bfSJakub Kruzik   PetscFunctionBegin;
7708c8613bfSJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
7718c8613bfSJakub Kruzik   PetscValidLogicalCollectiveEnum(mat,type,2);
7728c8613bfSJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeSetMergeType_C",(Mat,MatCompositeMergeType),(mat,type));CHKERRQ(ierr);
7738c8613bfSJakub Kruzik   PetscFunctionReturn(0);
7748c8613bfSJakub Kruzik }
7758c8613bfSJakub Kruzik 
776d7f81bf2SJakub Kruzik static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
777b52f573bSBarry Smith {
778b52f573bSBarry Smith   Mat_Composite     *shell = (Mat_Composite*)mat->data;
7796d7c1e57SBarry Smith   Mat_CompositeLink next   = shell->head, prev = shell->tail;
780b52f573bSBarry Smith   PetscErrorCode    ierr;
7816d7c1e57SBarry Smith   Mat               tmat,newmat;
7821ba60692SJed Brown   Vec               left,right;
7831ba60692SJed Brown   PetscScalar       scale;
784*03049c21SJunchao Zhang   PetscInt          i;
785b52f573bSBarry Smith 
786b52f573bSBarry Smith   PetscFunctionBegin;
787e32f2f54SBarry Smith   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
788b52f573bSBarry Smith 
789b52f573bSBarry Smith   PetscFunctionBegin;
790*03049c21SJunchao Zhang   scale = shell->scale;
7916d7c1e57SBarry Smith   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
7928c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
793*03049c21SJunchao Zhang       i = 0;
794b52f573bSBarry Smith       ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
795*03049c21SJunchao Zhang       if (shell->scalings) {ierr = MatScale(tmat,shell->scalings[i++]);CHKERRQ(ierr);}
796b52f573bSBarry Smith       while ((next = next->next)) {
797*03049c21SJunchao Zhang         ierr = MatAXPY(tmat,(shell->scalings ? shell->scalings[i++] : 1.0),next->mat,shell->structure);CHKERRQ(ierr);
798b52f573bSBarry Smith       }
7996d7c1e57SBarry Smith     } else {
800*03049c21SJunchao Zhang       i = shell->nmat-1;
8018c8613bfSJakub Kruzik       ierr = MatDuplicate(prev->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
802*03049c21SJunchao Zhang       if (shell->scalings) {ierr = MatScale(tmat,shell->scalings[i--]);CHKERRQ(ierr);}
8038c8613bfSJakub Kruzik       while ((prev = prev->prev)) {
804*03049c21SJunchao Zhang         ierr = MatAXPY(tmat,(shell->scalings ? shell->scalings[i--] : 1.0),prev->mat,shell->structure);CHKERRQ(ierr);
8058c8613bfSJakub Kruzik       }
8068c8613bfSJakub Kruzik     }
8078c8613bfSJakub Kruzik   } else {
8088c8613bfSJakub Kruzik     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
8096d7c1e57SBarry Smith       ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
810b6cfcaf5SJakub Kruzik       while ((next = next->next)) {
811b6cfcaf5SJakub Kruzik         ierr = MatMatMult(next->mat,tmat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);CHKERRQ(ierr);
8126bf464f9SBarry Smith         ierr = MatDestroy(&tmat);CHKERRQ(ierr);
8136d7c1e57SBarry Smith         tmat = newmat;
8146d7c1e57SBarry Smith       }
81504d534ceSJakub Kruzik     } else {
81604d534ceSJakub Kruzik       ierr = MatDuplicate(prev->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr);
81704d534ceSJakub Kruzik       while ((prev = prev->prev)) {
81804d534ceSJakub Kruzik         ierr = MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);CHKERRQ(ierr);
81904d534ceSJakub Kruzik         ierr = MatDestroy(&tmat);CHKERRQ(ierr);
82004d534ceSJakub Kruzik         tmat = newmat;
82104d534ceSJakub Kruzik       }
82204d534ceSJakub Kruzik     }
823*03049c21SJunchao Zhang     if (shell->scalings) {for (i=0; i<shell->nmat; i++) scale *= shell->scalings[i];}
8246d7c1e57SBarry Smith   }
8251ba60692SJed Brown 
8261ba60692SJed Brown   if ((left = shell->left)) {ierr = PetscObjectReference((PetscObject)left);CHKERRQ(ierr);}
8271ba60692SJed Brown   if ((right = shell->right)) {ierr = PetscObjectReference((PetscObject)right);CHKERRQ(ierr);}
8281ba60692SJed Brown 
82928be2f97SBarry Smith   ierr = MatHeaderReplace(mat,&tmat);CHKERRQ(ierr);
8301ba60692SJed Brown 
8311ba60692SJed Brown   ierr = MatDiagonalScale(mat,left,right);CHKERRQ(ierr);
8321ba60692SJed Brown   ierr = MatScale(mat,scale);CHKERRQ(ierr);
8331ba60692SJed Brown   ierr = VecDestroy(&left);CHKERRQ(ierr);
8341ba60692SJed Brown   ierr = VecDestroy(&right);CHKERRQ(ierr);
835b52f573bSBarry Smith   PetscFunctionReturn(0);
836b52f573bSBarry Smith }
8376a7ede75SJakub Kruzik 
8386a7ede75SJakub Kruzik /*@
839d7f81bf2SJakub Kruzik    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
8408bd739bdSJakub Kruzik      by summing or computing the product of all the matrices inside the composite matrix.
841d7f81bf2SJakub Kruzik 
842b2b245abSJakub Kruzik   Collective
843d7f81bf2SJakub Kruzik 
844d7f81bf2SJakub Kruzik    Input Parameters:
845d7f81bf2SJakub Kruzik .  mat - the composite matrix
846d7f81bf2SJakub Kruzik 
847d7f81bf2SJakub Kruzik 
8484b2558d6SJakub Kruzik    Options Database Keys:
849b28d0daaSJakub Kruzik +  -mat_composite_merge - merge in MatAssemblyEnd()
850b28d0daaSJakub Kruzik -  -mat_composite_merge_type - set merge direction
851d7f81bf2SJakub Kruzik 
852d7f81bf2SJakub Kruzik    Level: advanced
853d7f81bf2SJakub Kruzik 
854d7f81bf2SJakub Kruzik    Notes:
855d7f81bf2SJakub Kruzik       The MatType of the resulting matrix will be the same as the MatType of the FIRST
856d7f81bf2SJakub Kruzik     matrix in the composite matrix.
857d7f81bf2SJakub Kruzik 
8583b35acafSJakub Kruzik .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MatCompositeSetMatStructure(), MatCompositeSetMergeType(), MATCOMPOSITE
859d7f81bf2SJakub Kruzik 
860d7f81bf2SJakub Kruzik @*/
861d7f81bf2SJakub Kruzik PetscErrorCode MatCompositeMerge(Mat mat)
862d7f81bf2SJakub Kruzik {
863d7f81bf2SJakub Kruzik   PetscErrorCode ierr;
864d7f81bf2SJakub Kruzik 
865d7f81bf2SJakub Kruzik   PetscFunctionBegin;
866d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
867d7f81bf2SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeMerge_C",(Mat),(mat));CHKERRQ(ierr);
868d7f81bf2SJakub Kruzik   PetscFunctionReturn(0);
869d7f81bf2SJakub Kruzik }
870d7f81bf2SJakub Kruzik 
8716d0add67SJakub Kruzik static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat,PetscInt *nmat)
872d7f81bf2SJakub Kruzik {
873d7f81bf2SJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)mat->data;
874d7f81bf2SJakub Kruzik 
875d7f81bf2SJakub Kruzik   PetscFunctionBegin;
876d7f81bf2SJakub Kruzik   *nmat = shell->nmat;
877d7f81bf2SJakub Kruzik   PetscFunctionReturn(0);
878d7f81bf2SJakub Kruzik }
879d7f81bf2SJakub Kruzik 
880d7f81bf2SJakub Kruzik /*@
8816d0add67SJakub Kruzik    MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.
8826a7ede75SJakub Kruzik 
8836a7ede75SJakub Kruzik    Not Collective
8846a7ede75SJakub Kruzik 
8856a7ede75SJakub Kruzik    Input Parameter:
886d7f81bf2SJakub Kruzik .  mat - the composite matrix
8876a7ede75SJakub Kruzik 
8886a7ede75SJakub Kruzik    Output Parameter:
8896d0add67SJakub Kruzik .  nmat - number of matrices in the composite matrix
8906a7ede75SJakub Kruzik 
8918b5c3584SJakub Kruzik    Level: advanced
8926a7ede75SJakub Kruzik 
8938bd739bdSJakub Kruzik .seealso: MatCreateComposite(), MatCompositeGetMat(), MATCOMPOSITE
8946a7ede75SJakub Kruzik 
8956a7ede75SJakub Kruzik @*/
8966d0add67SJakub Kruzik PetscErrorCode MatCompositeGetNumberMat(Mat mat,PetscInt *nmat)
8976a7ede75SJakub Kruzik {
898d7f81bf2SJakub Kruzik   PetscErrorCode ierr;
8996a7ede75SJakub Kruzik 
9006a7ede75SJakub Kruzik   PetscFunctionBegin;
901d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
9026a7ede75SJakub Kruzik   PetscValidPointer(nmat,2);
9036d0add67SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeGetNumberMat_C",(Mat,PetscInt*),(mat,nmat));CHKERRQ(ierr);
904d7f81bf2SJakub Kruzik   PetscFunctionReturn(0);
905d7f81bf2SJakub Kruzik }
906d7f81bf2SJakub Kruzik 
907d7f81bf2SJakub Kruzik static PetscErrorCode MatCompositeGetMat_Composite(Mat mat,PetscInt i,Mat *Ai)
908d7f81bf2SJakub Kruzik {
909d7f81bf2SJakub Kruzik   Mat_Composite     *shell = (Mat_Composite*)mat->data;
910d7f81bf2SJakub Kruzik   Mat_CompositeLink ilink;
911d7f81bf2SJakub Kruzik   PetscInt          k;
912d7f81bf2SJakub Kruzik 
913d7f81bf2SJakub Kruzik   PetscFunctionBegin;
914d7f81bf2SJakub Kruzik   if (i >= shell->nmat) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_OUTOFRANGE,"index out of range: %d >= %d",i,shell->nmat);
915d7f81bf2SJakub Kruzik   ilink = shell->head;
916d7f81bf2SJakub Kruzik   for (k=0; k<i; k++) {
917d7f81bf2SJakub Kruzik     ilink = ilink->next;
918d7f81bf2SJakub Kruzik   }
919d7f81bf2SJakub Kruzik   *Ai = ilink->mat;
9206a7ede75SJakub Kruzik   PetscFunctionReturn(0);
9216a7ede75SJakub Kruzik }
9226a7ede75SJakub Kruzik 
9238b5c3584SJakub Kruzik /*@
9248bd739bdSJakub Kruzik    MatCompositeGetMat - Returns the ith matrix from the composite matrix.
9258b5c3584SJakub Kruzik 
9268b5c3584SJakub Kruzik    Logically Collective on Mat
9278b5c3584SJakub Kruzik 
9288b5c3584SJakub Kruzik    Input Parameter:
929d7f81bf2SJakub Kruzik +  mat - the composite matrix
9308b5c3584SJakub Kruzik -  i - the number of requested matrix
9318b5c3584SJakub Kruzik 
9328b5c3584SJakub Kruzik    Output Parameter:
9338b5c3584SJakub Kruzik .  Ai - ith matrix in composite
9348b5c3584SJakub Kruzik 
9358b5c3584SJakub Kruzik    Level: advanced
9368b5c3584SJakub Kruzik 
9376d0add67SJakub Kruzik .seealso: MatCreateComposite(), MatCompositeGetNumberMat(), MatCompositeAddMat(), MATCOMPOSITE
9388b5c3584SJakub Kruzik 
9398b5c3584SJakub Kruzik @*/
940d7f81bf2SJakub Kruzik PetscErrorCode MatCompositeGetMat(Mat mat,PetscInt i,Mat *Ai)
9418b5c3584SJakub Kruzik {
942d7f81bf2SJakub Kruzik   PetscErrorCode ierr;
9438b5c3584SJakub Kruzik 
9448b5c3584SJakub Kruzik   PetscFunctionBegin;
945d7f81bf2SJakub Kruzik   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
946d7f81bf2SJakub Kruzik   PetscValidLogicalCollectiveInt(mat,i,2);
9478b5c3584SJakub Kruzik   PetscValidPointer(Ai,3);
948d7f81bf2SJakub Kruzik   ierr = PetscUseMethod(mat,"MatCompositeGetMat_C",(Mat,PetscInt,Mat*),(mat,i,Ai));CHKERRQ(ierr);
9498b5c3584SJakub Kruzik   PetscFunctionReturn(0);
9508b5c3584SJakub Kruzik }
9518b5c3584SJakub Kruzik 
952*03049c21SJunchao Zhang PetscErrorCode MatCompositeSetScalings_Composite(Mat mat,const PetscScalar *scalings)
953*03049c21SJunchao Zhang {
954*03049c21SJunchao Zhang   PetscErrorCode ierr;
955*03049c21SJunchao Zhang   Mat_Composite  *shell = (Mat_Composite*)mat->data;
956*03049c21SJunchao Zhang   PetscInt       nmat;
957*03049c21SJunchao Zhang 
958*03049c21SJunchao Zhang   PetscFunctionBegin;
959*03049c21SJunchao Zhang   ierr = MatCompositeGetNumberMat(mat,&nmat);CHKERRQ(ierr);
960*03049c21SJunchao Zhang   if (!shell->scalings) {ierr = PetscMalloc1(nmat,&shell->scalings);CHKERRQ(ierr);}
961*03049c21SJunchao Zhang   ierr = PetscArraycpy(shell->scalings,scalings,nmat);CHKERRQ(ierr);
962*03049c21SJunchao Zhang   PetscFunctionReturn(0);
963*03049c21SJunchao Zhang }
964*03049c21SJunchao Zhang 
965*03049c21SJunchao Zhang /*@
966*03049c21SJunchao Zhang    MatCompositeSetScalings - Sets separate scaling factors for component matrices.
967*03049c21SJunchao Zhang 
968*03049c21SJunchao Zhang    Logically Collective on Mat
969*03049c21SJunchao Zhang 
970*03049c21SJunchao Zhang    Input Parameter:
971*03049c21SJunchao Zhang +  mat      - the composite matrix
972*03049c21SJunchao Zhang -  scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)
973*03049c21SJunchao Zhang 
974*03049c21SJunchao Zhang    Level: advanced
975*03049c21SJunchao Zhang 
976*03049c21SJunchao Zhang .seealso: MatScale(), MatDiagonalScale(), MATCOMPOSITE
977*03049c21SJunchao Zhang 
978*03049c21SJunchao Zhang @*/
979*03049c21SJunchao Zhang PetscErrorCode MatCompositeSetScalings(Mat mat,const PetscScalar *scalings)
980*03049c21SJunchao Zhang {
981*03049c21SJunchao Zhang   PetscErrorCode ierr;
982*03049c21SJunchao Zhang 
983*03049c21SJunchao Zhang   PetscFunctionBegin;
984*03049c21SJunchao Zhang   PetscValidHeaderSpecific(mat,MAT_CLASSID,1);
985*03049c21SJunchao Zhang   PetscValidPointer(scalings,2);
986*03049c21SJunchao Zhang   PetscValidLogicalCollectiveScalar(mat,*scalings,2);
987*03049c21SJunchao Zhang   ierr = PetscUseMethod(mat,"MatCompositeSetScalings_C",(Mat,const PetscScalar*),(mat,scalings));CHKERRQ(ierr);
988*03049c21SJunchao Zhang   PetscFunctionReturn(0);
989*03049c21SJunchao Zhang }
990*03049c21SJunchao Zhang 
99141cd0125SJakub Kruzik static struct _MatOps MatOps_Values = {0,
99241cd0125SJakub Kruzik                                        0,
99341cd0125SJakub Kruzik                                        0,
99441cd0125SJakub Kruzik                                        MatMult_Composite,
9957bf3a71bSJakub Kruzik                                        MatMultAdd_Composite,
99641cd0125SJakub Kruzik                                 /*  5*/ MatMultTranspose_Composite,
9977bf3a71bSJakub Kruzik                                        MatMultTransposeAdd_Composite,
99841cd0125SJakub Kruzik                                        0,
99941cd0125SJakub Kruzik                                        0,
100041cd0125SJakub Kruzik                                        0,
100141cd0125SJakub Kruzik                                 /* 10*/ 0,
100241cd0125SJakub Kruzik                                        0,
100341cd0125SJakub Kruzik                                        0,
100441cd0125SJakub Kruzik                                        0,
100541cd0125SJakub Kruzik                                        0,
100641cd0125SJakub Kruzik                                 /* 15*/ 0,
100741cd0125SJakub Kruzik                                        0,
100841cd0125SJakub Kruzik                                        MatGetDiagonal_Composite,
100941cd0125SJakub Kruzik                                        MatDiagonalScale_Composite,
101041cd0125SJakub Kruzik                                        0,
101141cd0125SJakub Kruzik                                 /* 20*/ 0,
101241cd0125SJakub Kruzik                                        MatAssemblyEnd_Composite,
101341cd0125SJakub Kruzik                                        0,
101441cd0125SJakub Kruzik                                        0,
101541cd0125SJakub Kruzik                                /* 24*/ 0,
101641cd0125SJakub Kruzik                                        0,
101741cd0125SJakub Kruzik                                        0,
101841cd0125SJakub Kruzik                                        0,
101941cd0125SJakub Kruzik                                        0,
102041cd0125SJakub Kruzik                                /* 29*/ 0,
102141cd0125SJakub Kruzik                                        0,
102241cd0125SJakub Kruzik                                        0,
102341cd0125SJakub Kruzik                                        0,
102441cd0125SJakub Kruzik                                        0,
102541cd0125SJakub Kruzik                                /* 34*/ 0,
102641cd0125SJakub Kruzik                                        0,
102741cd0125SJakub Kruzik                                        0,
102841cd0125SJakub Kruzik                                        0,
102941cd0125SJakub Kruzik                                        0,
103041cd0125SJakub Kruzik                                /* 39*/ 0,
103141cd0125SJakub Kruzik                                        0,
103241cd0125SJakub Kruzik                                        0,
103341cd0125SJakub Kruzik                                        0,
103441cd0125SJakub Kruzik                                        0,
103541cd0125SJakub Kruzik                                /* 44*/ 0,
103641cd0125SJakub Kruzik                                        MatScale_Composite,
103741cd0125SJakub Kruzik                                        MatShift_Basic,
103841cd0125SJakub Kruzik                                        0,
103941cd0125SJakub Kruzik                                        0,
104041cd0125SJakub Kruzik                                /* 49*/ 0,
104141cd0125SJakub Kruzik                                        0,
104241cd0125SJakub Kruzik                                        0,
104341cd0125SJakub Kruzik                                        0,
104441cd0125SJakub Kruzik                                        0,
104541cd0125SJakub Kruzik                                /* 54*/ 0,
104641cd0125SJakub Kruzik                                        0,
104741cd0125SJakub Kruzik                                        0,
104841cd0125SJakub Kruzik                                        0,
104941cd0125SJakub Kruzik                                        0,
105041cd0125SJakub Kruzik                                /* 59*/ 0,
105141cd0125SJakub Kruzik                                        MatDestroy_Composite,
105241cd0125SJakub Kruzik                                        0,
105341cd0125SJakub Kruzik                                        0,
105441cd0125SJakub Kruzik                                        0,
105541cd0125SJakub Kruzik                                /* 64*/ 0,
105641cd0125SJakub Kruzik                                        0,
105741cd0125SJakub Kruzik                                        0,
105841cd0125SJakub Kruzik                                        0,
105941cd0125SJakub Kruzik                                        0,
106041cd0125SJakub Kruzik                                /* 69*/ 0,
106141cd0125SJakub Kruzik                                        0,
106241cd0125SJakub Kruzik                                        0,
106341cd0125SJakub Kruzik                                        0,
106441cd0125SJakub Kruzik                                        0,
106541cd0125SJakub Kruzik                                /* 74*/ 0,
106641cd0125SJakub Kruzik                                        0,
10674b2558d6SJakub Kruzik                                        MatSetFromOptions_Composite,
106841cd0125SJakub Kruzik                                        0,
106941cd0125SJakub Kruzik                                        0,
107041cd0125SJakub Kruzik                                /* 79*/ 0,
107141cd0125SJakub Kruzik                                        0,
107241cd0125SJakub Kruzik                                        0,
107341cd0125SJakub Kruzik                                        0,
107441cd0125SJakub Kruzik                                        0,
107541cd0125SJakub Kruzik                                /* 84*/ 0,
107641cd0125SJakub Kruzik                                        0,
107741cd0125SJakub Kruzik                                        0,
107841cd0125SJakub Kruzik                                        0,
107941cd0125SJakub Kruzik                                        0,
108041cd0125SJakub Kruzik                                /* 89*/ 0,
108141cd0125SJakub Kruzik                                        0,
108241cd0125SJakub Kruzik                                        0,
108341cd0125SJakub Kruzik                                        0,
108441cd0125SJakub Kruzik                                        0,
108541cd0125SJakub Kruzik                                /* 94*/ 0,
108641cd0125SJakub Kruzik                                        0,
108741cd0125SJakub Kruzik                                        0,
108841cd0125SJakub Kruzik                                        0,
108941cd0125SJakub Kruzik                                        0,
109041cd0125SJakub Kruzik                                 /*99*/ 0,
109141cd0125SJakub Kruzik                                        0,
109241cd0125SJakub Kruzik                                        0,
109341cd0125SJakub Kruzik                                        0,
109441cd0125SJakub Kruzik                                        0,
109541cd0125SJakub Kruzik                                /*104*/ 0,
109641cd0125SJakub Kruzik                                        0,
109741cd0125SJakub Kruzik                                        0,
109841cd0125SJakub Kruzik                                        0,
109941cd0125SJakub Kruzik                                        0,
110041cd0125SJakub Kruzik                                /*109*/ 0,
110141cd0125SJakub Kruzik                                        0,
110241cd0125SJakub Kruzik                                        0,
110341cd0125SJakub Kruzik                                        0,
110441cd0125SJakub Kruzik                                        0,
110541cd0125SJakub Kruzik                                /*114*/ 0,
110641cd0125SJakub Kruzik                                        0,
110741cd0125SJakub Kruzik                                        0,
110841cd0125SJakub Kruzik                                        0,
110941cd0125SJakub Kruzik                                        0,
111041cd0125SJakub Kruzik                                /*119*/ 0,
111141cd0125SJakub Kruzik                                        0,
111241cd0125SJakub Kruzik                                        0,
111341cd0125SJakub Kruzik                                        0,
111441cd0125SJakub Kruzik                                        0,
111541cd0125SJakub Kruzik                                /*124*/ 0,
111641cd0125SJakub Kruzik                                        0,
111741cd0125SJakub Kruzik                                        0,
111841cd0125SJakub Kruzik                                        0,
111941cd0125SJakub Kruzik                                        0,
112041cd0125SJakub Kruzik                                /*129*/ 0,
112141cd0125SJakub Kruzik                                        0,
112241cd0125SJakub Kruzik                                        0,
112341cd0125SJakub Kruzik                                        0,
112441cd0125SJakub Kruzik                                        0,
112541cd0125SJakub Kruzik                                /*134*/ 0,
112641cd0125SJakub Kruzik                                        0,
112741cd0125SJakub Kruzik                                        0,
112841cd0125SJakub Kruzik                                        0,
112941cd0125SJakub Kruzik                                        0,
113041cd0125SJakub Kruzik                                /*139*/ 0,
113141cd0125SJakub Kruzik                                        0,
113241cd0125SJakub Kruzik                                        0
113341cd0125SJakub Kruzik };
113441cd0125SJakub Kruzik 
113541cd0125SJakub Kruzik /*MC
113641cd0125SJakub Kruzik    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
113741cd0125SJakub Kruzik     The matrices need to have a correct size and parallel layout for the sum or product to be valid.
113841cd0125SJakub Kruzik 
113941cd0125SJakub Kruzik    Notes:
114041cd0125SJakub Kruzik     to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);
114141cd0125SJakub Kruzik 
114241cd0125SJakub Kruzik   Level: advanced
114341cd0125SJakub Kruzik 
1144*03049c21SJunchao Zhang .seealso: MatCreateComposite(), MatCompositeSetScalings(), MatCompositeAddMat(), MatSetType(), MatCompositeSetType(), MatCompositeGetType(), MatCompositeSetMatStructure(), MatCompositeGetMatStructure(), MatCompositeMerge(), MatCompositeSetMergeType(), MatCompositeGetNumberMat(), MatCompositeGetMat()
114541cd0125SJakub Kruzik M*/
114641cd0125SJakub Kruzik 
114741cd0125SJakub Kruzik PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
114841cd0125SJakub Kruzik {
114941cd0125SJakub Kruzik   Mat_Composite  *b;
115041cd0125SJakub Kruzik   PetscErrorCode ierr;
115141cd0125SJakub Kruzik 
115241cd0125SJakub Kruzik   PetscFunctionBegin;
115341cd0125SJakub Kruzik   ierr    = PetscNewLog(A,&b);CHKERRQ(ierr);
115441cd0125SJakub Kruzik   A->data = (void*)b;
115541cd0125SJakub Kruzik   ierr    = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr);
115641cd0125SJakub Kruzik 
115741cd0125SJakub Kruzik   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
115841cd0125SJakub Kruzik   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
115941cd0125SJakub Kruzik 
116041cd0125SJakub Kruzik   A->assembled    = PETSC_TRUE;
116141cd0125SJakub Kruzik   A->preallocated = PETSC_TRUE;
116241cd0125SJakub Kruzik   b->type         = MAT_COMPOSITE_ADDITIVE;
116341cd0125SJakub Kruzik   b->scale        = 1.0;
116441cd0125SJakub Kruzik   b->nmat         = 0;
11654b2558d6SJakub Kruzik   b->merge        = PETSC_FALSE;
11668c8613bfSJakub Kruzik   b->mergetype    = MAT_COMPOSITE_MERGE_RIGHT;
11673b35acafSJakub Kruzik   b->structure    = DIFFERENT_NONZERO_PATTERN;
1168*03049c21SJunchao Zhang   b->merge_mvctx  = PETSC_TRUE;
1169*03049c21SJunchao Zhang 
1170*03049c21SJunchao Zhang 
117141cd0125SJakub Kruzik 
117241cd0125SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeAddMat_C",MatCompositeAddMat_Composite);CHKERRQ(ierr);
117341cd0125SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetType_C",MatCompositeSetType_Composite);CHKERRQ(ierr);
11746dbc55e5SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetType_C",MatCompositeGetType_Composite);CHKERRQ(ierr);
11758c8613bfSJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetMergeType_C",MatCompositeSetMergeType_Composite);CHKERRQ(ierr);
11763b35acafSJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetMatStructure_C",MatCompositeSetMatStructure_Composite);CHKERRQ(ierr);
11773b35acafSJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetMatStructure_C",MatCompositeGetMatStructure_Composite);CHKERRQ(ierr);
117841cd0125SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeMerge_C",MatCompositeMerge_Composite);CHKERRQ(ierr);
11796d0add67SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetNumberMat_C",MatCompositeGetNumberMat_Composite);CHKERRQ(ierr);
118041cd0125SJakub Kruzik   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeGetMat_C",MatCompositeGetMat_Composite);CHKERRQ(ierr);
1181*03049c21SJunchao Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatCompositeSetScalings_C",MatCompositeSetScalings_Composite);CHKERRQ(ierr);
118241cd0125SJakub Kruzik 
118341cd0125SJakub Kruzik   ierr = PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);CHKERRQ(ierr);
118441cd0125SJakub Kruzik   PetscFunctionReturn(0);
118541cd0125SJakub Kruzik }
118641cd0125SJakub Kruzik 
1187