Actual source code: mcomposite.c


  2: #include <petsc/private/matimpl.h>

  4: const char *const MatCompositeMergeTypes[] = {"left", "right", "MatCompositeMergeType", "MAT_COMPOSITE_", NULL};

  6: typedef struct _Mat_CompositeLink *Mat_CompositeLink;
  7: struct _Mat_CompositeLink {
  8:   Mat               mat;
  9:   Vec               work;
 10:   Mat_CompositeLink next, prev;
 11: };

 13: typedef struct {
 14:   MatCompositeType      type;
 15:   Mat_CompositeLink     head, tail;
 16:   Vec                   work;
 17:   PetscScalar           scale;                                      /* scale factor supplied with MatScale() */
 18:   Vec                   left, right;                                /* left and right diagonal scaling provided with MatDiagonalScale() */
 19:   Vec                   leftwork, rightwork, leftwork2, rightwork2; /* Two pairs of working vectors */
 20:   PetscInt              nmat;
 21:   PetscBool             merge;
 22:   MatCompositeMergeType mergetype;
 23:   MatStructure          structure;

 25:   PetscScalar *scalings;
 26:   PetscBool    merge_mvctx; /* Whether need to merge mvctx of component matrices */
 27:   Vec         *lvecs;       /* [nmat] Basically, they are Mvctx->lvec of each component matrix */
 28:   PetscScalar *larray;      /* [len] Data arrays of lvecs[] are stored consecutively in larray */
 29:   PetscInt     len;         /* Length of larray[] */
 30:   Vec          gvec;        /* Union of lvecs[] without duplicated entries */
 31:   PetscInt    *location;    /* A map that maps entries in garray[] to larray[] */
 32:   VecScatter   Mvctx;
 33: } Mat_Composite;

 35: PetscErrorCode MatDestroy_Composite(Mat mat)
 36: {
 37:   Mat_Composite    *shell = (Mat_Composite *)mat->data;
 38:   Mat_CompositeLink next  = shell->head, oldnext;
 39:   PetscInt          i;

 41:   PetscFunctionBegin;
 42:   while (next) {
 43:     PetscCall(MatDestroy(&next->mat));
 44:     if (next->work && (!next->next || next->work != next->next->work)) PetscCall(VecDestroy(&next->work));
 45:     oldnext = next;
 46:     next    = next->next;
 47:     PetscCall(PetscFree(oldnext));
 48:   }
 49:   PetscCall(VecDestroy(&shell->work));
 50:   PetscCall(VecDestroy(&shell->left));
 51:   PetscCall(VecDestroy(&shell->right));
 52:   PetscCall(VecDestroy(&shell->leftwork));
 53:   PetscCall(VecDestroy(&shell->rightwork));
 54:   PetscCall(VecDestroy(&shell->leftwork2));
 55:   PetscCall(VecDestroy(&shell->rightwork2));

 57:   if (shell->Mvctx) {
 58:     for (i = 0; i < shell->nmat; i++) PetscCall(VecDestroy(&shell->lvecs[i]));
 59:     PetscCall(PetscFree3(shell->location, shell->larray, shell->lvecs));
 60:     PetscCall(PetscFree(shell->larray));
 61:     PetscCall(VecDestroy(&shell->gvec));
 62:     PetscCall(VecScatterDestroy(&shell->Mvctx));
 63:   }

 65:   PetscCall(PetscFree(shell->scalings));
 66:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeAddMat_C", NULL));
 67:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetType_C", NULL));
 68:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetType_C", NULL));
 69:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMergeType_C", NULL));
 70:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetMatStructure_C", NULL));
 71:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMatStructure_C", NULL));
 72:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeMerge_C", NULL));
 73:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetNumberMat_C", NULL));
 74:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeGetMat_C", NULL));
 75:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatCompositeSetScalings_C", NULL));
 76:   PetscCall(PetscFree(mat->data));
 77:   PetscFunctionReturn(PETSC_SUCCESS);
 78: }

 80: PetscErrorCode MatMult_Composite_Multiplicative(Mat A, Vec x, Vec y)
 81: {
 82:   Mat_Composite    *shell = (Mat_Composite *)A->data;
 83:   Mat_CompositeLink next  = shell->head;
 84:   Vec               in, out;
 85:   PetscScalar       scale;
 86:   PetscInt          i;

 88:   PetscFunctionBegin;
 89:   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
 90:   in = x;
 91:   if (shell->right) {
 92:     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
 93:     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
 94:     in = shell->rightwork;
 95:   }
 96:   while (next->next) {
 97:     if (!next->work) { /* should reuse previous work if the same size */
 98:       PetscCall(MatCreateVecs(next->mat, NULL, &next->work));
 99:     }
100:     out = next->work;
101:     PetscCall(MatMult(next->mat, in, out));
102:     in   = out;
103:     next = next->next;
104:   }
105:   PetscCall(MatMult(next->mat, in, y));
106:   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
107:   scale = shell->scale;
108:   if (shell->scalings) {
109:     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
110:   }
111:   PetscCall(VecScale(y, scale));
112:   PetscFunctionReturn(PETSC_SUCCESS);
113: }

115: PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A, Vec x, Vec y)
116: {
117:   Mat_Composite    *shell = (Mat_Composite *)A->data;
118:   Mat_CompositeLink tail  = shell->tail;
119:   Vec               in, out;
120:   PetscScalar       scale;
121:   PetscInt          i;

123:   PetscFunctionBegin;
124:   PetscCheck(tail, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
125:   in = x;
126:   if (shell->left) {
127:     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
128:     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
129:     in = shell->leftwork;
130:   }
131:   while (tail->prev) {
132:     if (!tail->prev->work) { /* should reuse previous work if the same size */
133:       PetscCall(MatCreateVecs(tail->mat, NULL, &tail->prev->work));
134:     }
135:     out = tail->prev->work;
136:     PetscCall(MatMultTranspose(tail->mat, in, out));
137:     in   = out;
138:     tail = tail->prev;
139:   }
140:   PetscCall(MatMultTranspose(tail->mat, in, y));
141:   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));

143:   scale = shell->scale;
144:   if (shell->scalings) {
145:     for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
146:   }
147:   PetscCall(VecScale(y, scale));
148:   PetscFunctionReturn(PETSC_SUCCESS);
149: }

151: PetscErrorCode MatMult_Composite(Mat mat, Vec x, Vec y)
152: {
153:   Mat_Composite     *shell = (Mat_Composite *)mat->data;
154:   Mat_CompositeLink  cur   = shell->head;
155:   Vec                in, y2, xin;
156:   Mat                A, B;
157:   PetscInt           i, j, k, n, nuniq, lo, hi, mid, *gindices, *buf, *tmp, tot;
158:   const PetscScalar *vals;
159:   const PetscInt    *garray;
160:   IS                 ix, iy;
161:   PetscBool          match;

163:   PetscFunctionBegin;
164:   PetscCheck(cur, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
165:   in = x;
166:   if (shell->right) {
167:     if (!shell->rightwork) PetscCall(VecDuplicate(shell->right, &shell->rightwork));
168:     PetscCall(VecPointwiseMult(shell->rightwork, shell->right, in));
169:     in = shell->rightwork;
170:   }

172:   /* Try to merge Mvctx when instructed but not yet done. We did not do it in MatAssemblyEnd() since at that time
173:      we did not know whether mat is ADDITIVE or MULTIPLICATIVE. Only now we are assured mat is ADDITIVE and
174:      it is legal to merge Mvctx, because all component matrices have the same size.
175:    */
176:   if (shell->merge_mvctx && !shell->Mvctx) {
177:     /* Currently only implemented for MATMPIAIJ */
178:     for (cur = shell->head; cur; cur = cur->next) {
179:       PetscCall(PetscObjectTypeCompare((PetscObject)cur->mat, MATMPIAIJ, &match));
180:       if (!match) {
181:         shell->merge_mvctx = PETSC_FALSE;
182:         goto skip_merge_mvctx;
183:       }
184:     }

186:     /* Go through matrices first time to count total number of nonzero off-diag columns (may have dups) */
187:     tot = 0;
188:     for (cur = shell->head; cur; cur = cur->next) {
189:       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, NULL));
190:       PetscCall(MatGetLocalSize(B, NULL, &n));
191:       tot += n;
192:     }
193:     PetscCall(PetscMalloc3(tot, &shell->location, tot, &shell->larray, shell->nmat, &shell->lvecs));
194:     shell->len = tot;

196:     /* Go through matrices second time to sort off-diag columns and remove dups */
197:     PetscCall(PetscMalloc1(tot, &gindices)); /* No Malloc2() since we will give one to petsc and free the other */
198:     PetscCall(PetscMalloc1(tot, &buf));
199:     nuniq = 0; /* Number of unique nonzero columns */
200:     for (cur = shell->head; cur; cur = cur->next) {
201:       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
202:       PetscCall(MatGetLocalSize(B, NULL, &n));
203:       /* Merge pre-sorted garray[0,n) and gindices[0,nuniq) to buf[] */
204:       i = j = k = 0;
205:       while (i < n && j < nuniq) {
206:         if (garray[i] < gindices[j]) buf[k++] = garray[i++];
207:         else if (garray[i] > gindices[j]) buf[k++] = gindices[j++];
208:         else {
209:           buf[k++] = garray[i++];
210:           j++;
211:         }
212:       }
213:       /* Copy leftover in garray[] or gindices[] */
214:       if (i < n) {
215:         PetscCall(PetscArraycpy(buf + k, garray + i, n - i));
216:         nuniq = k + n - i;
217:       } else if (j < nuniq) {
218:         PetscCall(PetscArraycpy(buf + k, gindices + j, nuniq - j));
219:         nuniq = k + nuniq - j;
220:       } else nuniq = k;
221:       /* Swap gindices and buf to merge garray of the next matrix */
222:       tmp      = gindices;
223:       gindices = buf;
224:       buf      = tmp;
225:     }
226:     PetscCall(PetscFree(buf));

228:     /* Go through matrices third time to build a map from gindices[] to garray[] */
229:     tot = 0;
230:     for (cur = shell->head, j = 0; cur; cur = cur->next, j++) { /* j-th matrix */
231:       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, NULL, &B, &garray));
232:       PetscCall(MatGetLocalSize(B, NULL, &n));
233:       PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, n, NULL, &shell->lvecs[j]));
234:       /* This is an optimized PetscFindInt(garray[i],nuniq,gindices,&shell->location[tot+i]), using the fact that garray[] is also sorted */
235:       lo = 0;
236:       for (i = 0; i < n; i++) {
237:         hi = nuniq;
238:         while (hi - lo > 1) {
239:           mid = lo + (hi - lo) / 2;
240:           if (garray[i] < gindices[mid]) hi = mid;
241:           else lo = mid;
242:         }
243:         shell->location[tot + i] = lo; /* gindices[lo] = garray[i] */
244:         lo++;                          /* Since garray[i+1] > garray[i], we can safely advance lo */
245:       }
246:       tot += n;
247:     }

249:     /* Build merged Mvctx */
250:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nuniq, gindices, PETSC_OWN_POINTER, &ix));
251:     PetscCall(ISCreateStride(PETSC_COMM_SELF, nuniq, 0, 1, &iy));
252:     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &xin));
253:     PetscCall(VecCreateSeq(PETSC_COMM_SELF, nuniq, &shell->gvec));
254:     PetscCall(VecScatterCreate(xin, ix, shell->gvec, iy, &shell->Mvctx));
255:     PetscCall(VecDestroy(&xin));
256:     PetscCall(ISDestroy(&ix));
257:     PetscCall(ISDestroy(&iy));
258:   }

260: skip_merge_mvctx:
261:   PetscCall(VecSet(y, 0));
262:   if (!shell->leftwork2) PetscCall(VecDuplicate(y, &shell->leftwork2));
263:   y2 = shell->leftwork2;

265:   if (shell->Mvctx) { /* Have a merged Mvctx */
266:     /* 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
267:        in y = s(Ax1 + Bx2) or y = sAx1 + sBx2. The former incurs less FLOPS than the latter, but the latter provides an opportunity to
268:        overlap communication/computation since we can do sAx1 while communicating x2. Here, we use the former approach.
269:      */
270:     PetscCall(VecScatterBegin(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));
271:     PetscCall(VecScatterEnd(shell->Mvctx, in, shell->gvec, INSERT_VALUES, SCATTER_FORWARD));

273:     PetscCall(VecGetArrayRead(shell->gvec, &vals));
274:     for (i = 0; i < shell->len; i++) shell->larray[i] = vals[shell->location[i]];
275:     PetscCall(VecRestoreArrayRead(shell->gvec, &vals));

277:     for (cur = shell->head, tot = i = 0; cur; cur = cur->next, i++) { /* i-th matrix */
278:       PetscCall(MatMPIAIJGetSeqAIJ(cur->mat, &A, &B, NULL));
279:       PetscUseTypeMethod(A, mult, in, y2);
280:       PetscCall(MatGetLocalSize(B, NULL, &n));
281:       PetscCall(VecPlaceArray(shell->lvecs[i], &shell->larray[tot]));
282:       PetscCall((*B->ops->multadd)(B, shell->lvecs[i], y2, y2));
283:       PetscCall(VecResetArray(shell->lvecs[i]));
284:       PetscCall(VecAXPY(y, (shell->scalings ? shell->scalings[i] : 1.0), y2));
285:       tot += n;
286:     }
287:   } else {
288:     if (shell->scalings) {
289:       for (cur = shell->head, i = 0; cur; cur = cur->next, i++) {
290:         PetscCall(MatMult(cur->mat, in, y2));
291:         PetscCall(VecAXPY(y, shell->scalings[i], y2));
292:       }
293:     } else {
294:       for (cur = shell->head; cur; cur = cur->next) PetscCall(MatMultAdd(cur->mat, in, y, y));
295:     }
296:   }

298:   if (shell->left) PetscCall(VecPointwiseMult(y, shell->left, y));
299:   PetscCall(VecScale(y, shell->scale));
300:   PetscFunctionReturn(PETSC_SUCCESS);
301: }

303: PetscErrorCode MatMultTranspose_Composite(Mat A, Vec x, Vec y)
304: {
305:   Mat_Composite    *shell = (Mat_Composite *)A->data;
306:   Mat_CompositeLink next  = shell->head;
307:   Vec               in, y2 = NULL;
308:   PetscInt          i;

310:   PetscFunctionBegin;
311:   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
312:   in = x;
313:   if (shell->left) {
314:     if (!shell->leftwork) PetscCall(VecDuplicate(shell->left, &shell->leftwork));
315:     PetscCall(VecPointwiseMult(shell->leftwork, shell->left, in));
316:     in = shell->leftwork;
317:   }

319:   PetscCall(MatMultTranspose(next->mat, in, y));
320:   if (shell->scalings) {
321:     PetscCall(VecScale(y, shell->scalings[0]));
322:     if (!shell->rightwork2) PetscCall(VecDuplicate(y, &shell->rightwork2));
323:     y2 = shell->rightwork2;
324:   }
325:   i = 1;
326:   while ((next = next->next)) {
327:     if (!shell->scalings) PetscCall(MatMultTransposeAdd(next->mat, in, y, y));
328:     else {
329:       PetscCall(MatMultTranspose(next->mat, in, y2));
330:       PetscCall(VecAXPY(y, shell->scalings[i++], y2));
331:     }
332:   }
333:   if (shell->right) PetscCall(VecPointwiseMult(y, shell->right, y));
334:   PetscCall(VecScale(y, shell->scale));
335:   PetscFunctionReturn(PETSC_SUCCESS);
336: }

338: PetscErrorCode MatMultAdd_Composite(Mat A, Vec x, Vec y, Vec z)
339: {
340:   Mat_Composite *shell = (Mat_Composite *)A->data;

342:   PetscFunctionBegin;
343:   if (y != z) {
344:     PetscCall(MatMult(A, x, z));
345:     PetscCall(VecAXPY(z, 1.0, y));
346:   } else {
347:     if (!shell->leftwork) PetscCall(VecDuplicate(z, &shell->leftwork));
348:     PetscCall(MatMult(A, x, shell->leftwork));
349:     PetscCall(VecCopy(y, z));
350:     PetscCall(VecAXPY(z, 1.0, shell->leftwork));
351:   }
352:   PetscFunctionReturn(PETSC_SUCCESS);
353: }

355: PetscErrorCode MatMultTransposeAdd_Composite(Mat A, Vec x, Vec y, Vec z)
356: {
357:   Mat_Composite *shell = (Mat_Composite *)A->data;

359:   PetscFunctionBegin;
360:   if (y != z) {
361:     PetscCall(MatMultTranspose(A, x, z));
362:     PetscCall(VecAXPY(z, 1.0, y));
363:   } else {
364:     if (!shell->rightwork) PetscCall(VecDuplicate(z, &shell->rightwork));
365:     PetscCall(MatMultTranspose(A, x, shell->rightwork));
366:     PetscCall(VecCopy(y, z));
367:     PetscCall(VecAXPY(z, 1.0, shell->rightwork));
368:   }
369:   PetscFunctionReturn(PETSC_SUCCESS);
370: }

372: PetscErrorCode MatGetDiagonal_Composite(Mat A, Vec v)
373: {
374:   Mat_Composite    *shell = (Mat_Composite *)A->data;
375:   Mat_CompositeLink next  = shell->head;
376:   PetscInt          i;

378:   PetscFunctionBegin;
379:   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
380:   PetscCheck(!shell->right && !shell->left, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get diagonal if left or right scaling");

382:   PetscCall(MatGetDiagonal(next->mat, v));
383:   if (shell->scalings) PetscCall(VecScale(v, shell->scalings[0]));

385:   if (next->next && !shell->work) PetscCall(VecDuplicate(v, &shell->work));
386:   i = 1;
387:   while ((next = next->next)) {
388:     PetscCall(MatGetDiagonal(next->mat, shell->work));
389:     PetscCall(VecAXPY(v, (shell->scalings ? shell->scalings[i++] : 1.0), shell->work));
390:   }
391:   PetscCall(VecScale(v, shell->scale));
392:   PetscFunctionReturn(PETSC_SUCCESS);
393: }

395: PetscErrorCode MatAssemblyEnd_Composite(Mat Y, MatAssemblyType t)
396: {
397:   Mat_Composite *shell = (Mat_Composite *)Y->data;

399:   PetscFunctionBegin;
400:   if (shell->merge) PetscCall(MatCompositeMerge(Y));
401:   PetscFunctionReturn(PETSC_SUCCESS);
402: }

404: PetscErrorCode MatScale_Composite(Mat inA, PetscScalar alpha)
405: {
406:   Mat_Composite *a = (Mat_Composite *)inA->data;

408:   PetscFunctionBegin;
409:   a->scale *= alpha;
410:   PetscFunctionReturn(PETSC_SUCCESS);
411: }

413: PetscErrorCode MatDiagonalScale_Composite(Mat inA, Vec left, Vec right)
414: {
415:   Mat_Composite *a = (Mat_Composite *)inA->data;

417:   PetscFunctionBegin;
418:   if (left) {
419:     if (!a->left) {
420:       PetscCall(VecDuplicate(left, &a->left));
421:       PetscCall(VecCopy(left, a->left));
422:     } else {
423:       PetscCall(VecPointwiseMult(a->left, left, a->left));
424:     }
425:   }
426:   if (right) {
427:     if (!a->right) {
428:       PetscCall(VecDuplicate(right, &a->right));
429:       PetscCall(VecCopy(right, a->right));
430:     } else {
431:       PetscCall(VecPointwiseMult(a->right, right, a->right));
432:     }
433:   }
434:   PetscFunctionReturn(PETSC_SUCCESS);
435: }

437: PetscErrorCode MatSetFromOptions_Composite(Mat A, PetscOptionItems *PetscOptionsObject)
438: {
439:   Mat_Composite *a = (Mat_Composite *)A->data;

441:   PetscFunctionBegin;
442:   PetscOptionsHeadBegin(PetscOptionsObject, "MATCOMPOSITE options");
443:   PetscCall(PetscOptionsBool("-mat_composite_merge", "Merge at MatAssemblyEnd", "MatCompositeMerge", a->merge, &a->merge, NULL));
444:   PetscCall(PetscOptionsEnum("-mat_composite_merge_type", "Set composite merge direction", "MatCompositeSetMergeType", MatCompositeMergeTypes, (PetscEnum)a->mergetype, (PetscEnum *)&a->mergetype, NULL));
445:   PetscCall(PetscOptionsBool("-mat_composite_merge_mvctx", "Merge MatMult() vecscat contexts", "MatCreateComposite", a->merge_mvctx, &a->merge_mvctx, NULL));
446:   PetscOptionsHeadEnd();
447:   PetscFunctionReturn(PETSC_SUCCESS);
448: }

450: /*@
451:    MatCreateComposite - Creates a matrix as the sum or product of one or more matrices

453:   Collective

455:    Input Parameters:
456: +  comm - MPI communicator
457: .  nmat - number of matrices to put in
458: -  mats - the matrices

460:    Output Parameter:
461: .  mat - the matrix

463:    Options Database Keys:
464: +  -mat_composite_merge         - merge in `MatAssemblyEnd()`
465: .  -mat_composite_merge_mvctx   - merge Mvctx of component matrices to optimize communication in `MatMult()` for ADDITIVE matrices
466: -  -mat_composite_merge_type    - set merge direction

468:    Level: advanced

470:    Note:
471:      Alternative construction
472: .vb
473:        MatCreate(comm,&mat);
474:        MatSetSizes(mat,m,n,M,N);
475:        MatSetType(mat,MATCOMPOSITE);
476:        MatCompositeAddMat(mat,mats[0]);
477:        ....
478:        MatCompositeAddMat(mat,mats[nmat-1]);
479:        MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
480:        MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
481: .ve

483:      For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0]

485: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCompositeGetMat()`, `MatCompositeMerge()`, `MatCompositeSetType()`, `MATCOMPOSITE`
486: @*/
487: PetscErrorCode MatCreateComposite(MPI_Comm comm, PetscInt nmat, const Mat *mats, Mat *mat)
488: {
489:   PetscInt m, n, M, N, i;

491:   PetscFunctionBegin;
492:   PetscCheck(nmat >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must pass in at least one matrix");

495:   PetscCall(MatGetLocalSize(mats[0], PETSC_IGNORE, &n));
496:   PetscCall(MatGetLocalSize(mats[nmat - 1], &m, PETSC_IGNORE));
497:   PetscCall(MatGetSize(mats[0], PETSC_IGNORE, &N));
498:   PetscCall(MatGetSize(mats[nmat - 1], &M, PETSC_IGNORE));
499:   PetscCall(MatCreate(comm, mat));
500:   PetscCall(MatSetSizes(*mat, m, n, M, N));
501:   PetscCall(MatSetType(*mat, MATCOMPOSITE));
502:   for (i = 0; i < nmat; i++) PetscCall(MatCompositeAddMat(*mat, mats[i]));
503:   PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY));
504:   PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY));
505:   PetscFunctionReturn(PETSC_SUCCESS);
506: }

508: static PetscErrorCode MatCompositeAddMat_Composite(Mat mat, Mat smat)
509: {
510:   Mat_Composite    *shell = (Mat_Composite *)mat->data;
511:   Mat_CompositeLink ilink, next = shell->head;

513:   PetscFunctionBegin;
514:   PetscCall(PetscNew(&ilink));
515:   ilink->next = NULL;
516:   PetscCall(PetscObjectReference((PetscObject)smat));
517:   ilink->mat = smat;

519:   if (!next) shell->head = ilink;
520:   else {
521:     while (next->next) next = next->next;
522:     next->next  = ilink;
523:     ilink->prev = next;
524:   }
525:   shell->tail = ilink;
526:   shell->nmat += 1;

528:   /* Retain the old scalings (if any) and expand it with a 1.0 for the newly added matrix */
529:   if (shell->scalings) {
530:     PetscCall(PetscRealloc(sizeof(PetscScalar) * shell->nmat, &shell->scalings));
531:     shell->scalings[shell->nmat - 1] = 1.0;
532:   }
533:   PetscFunctionReturn(PETSC_SUCCESS);
534: }

536: /*@
537:     MatCompositeAddMat - Add another matrix to a composite matrix.

539:    Collective

541:     Input Parameters:
542: +   mat - the composite matrix
543: -   smat - the partial matrix

545:    Level: advanced

547: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
548: @*/
549: PetscErrorCode MatCompositeAddMat(Mat mat, Mat smat)
550: {
551:   PetscFunctionBegin;
554:   PetscUseMethod(mat, "MatCompositeAddMat_C", (Mat, Mat), (mat, smat));
555:   PetscFunctionReturn(PETSC_SUCCESS);
556: }

558: static PetscErrorCode MatCompositeSetType_Composite(Mat mat, MatCompositeType type)
559: {
560:   Mat_Composite *b = (Mat_Composite *)mat->data;

562:   PetscFunctionBegin;
563:   b->type = type;
564:   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
565:     mat->ops->getdiagonal   = NULL;
566:     mat->ops->mult          = MatMult_Composite_Multiplicative;
567:     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
568:     b->merge_mvctx          = PETSC_FALSE;
569:   } else {
570:     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
571:     mat->ops->mult          = MatMult_Composite;
572:     mat->ops->multtranspose = MatMultTranspose_Composite;
573:   }
574:   PetscFunctionReturn(PETSC_SUCCESS);
575: }

577: /*@
578:    MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product.

580:    Logically Collective

582:    Input Parameters:
583: .  mat - the composite matrix

585:    Level: advanced

587: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeGetType()`, `MATCOMPOSITE`
588: @*/
589: PetscErrorCode MatCompositeSetType(Mat mat, MatCompositeType type)
590: {
591:   PetscFunctionBegin;
594:   PetscUseMethod(mat, "MatCompositeSetType_C", (Mat, MatCompositeType), (mat, type));
595:   PetscFunctionReturn(PETSC_SUCCESS);
596: }

598: static PetscErrorCode MatCompositeGetType_Composite(Mat mat, MatCompositeType *type)
599: {
600:   Mat_Composite *b = (Mat_Composite *)mat->data;

602:   PetscFunctionBegin;
603:   *type = b->type;
604:   PetscFunctionReturn(PETSC_SUCCESS);
605: }

607: /*@
608:    MatCompositeGetType - Returns type of composite.

610:    Not Collective

612:    Input Parameter:
613: .  mat - the composite matrix

615:    Output Parameter:
616: .  type - type of composite

618:    Level: advanced

620: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetType()`, `MATCOMPOSITE`, `MatCompositeType`
621: @*/
622: PetscErrorCode MatCompositeGetType(Mat mat, MatCompositeType *type)
623: {
624:   PetscFunctionBegin;
627:   PetscUseMethod(mat, "MatCompositeGetType_C", (Mat, MatCompositeType *), (mat, type));
628:   PetscFunctionReturn(PETSC_SUCCESS);
629: }

631: static PetscErrorCode MatCompositeSetMatStructure_Composite(Mat mat, MatStructure str)
632: {
633:   Mat_Composite *b = (Mat_Composite *)mat->data;

635:   PetscFunctionBegin;
636:   b->structure = str;
637:   PetscFunctionReturn(PETSC_SUCCESS);
638: }

640: /*@
641:    MatCompositeSetMatStructure - Indicates structure of matrices in the composite matrix.

643:    Not Collective

645:    Input Parameters:
646: +  mat - the composite matrix
647: -  str - either `SAME_NONZERO_PATTERN`, `DIFFERENT_NONZERO_PATTERN` (default) or `SUBSET_NONZERO_PATTERN`

649:    Level: advanced

651:    Note:
652:     Information about the matrices structure is used in `MatCompositeMerge()` for additive composite matrix.

654: .seealso: [](chapter_matrices), `Mat`, `MatAXPY()`, `MatCreateComposite()`, `MatCompositeMerge()` `MatCompositeGetMatStructure()`, `MATCOMPOSITE`
655: @*/
656: PetscErrorCode MatCompositeSetMatStructure(Mat mat, MatStructure str)
657: {
658:   PetscFunctionBegin;
660:   PetscUseMethod(mat, "MatCompositeSetMatStructure_C", (Mat, MatStructure), (mat, str));
661:   PetscFunctionReturn(PETSC_SUCCESS);
662: }

664: static PetscErrorCode MatCompositeGetMatStructure_Composite(Mat mat, MatStructure *str)
665: {
666:   Mat_Composite *b = (Mat_Composite *)mat->data;

668:   PetscFunctionBegin;
669:   *str = b->structure;
670:   PetscFunctionReturn(PETSC_SUCCESS);
671: }

673: /*@
674:    MatCompositeGetMatStructure - Returns the structure of matrices in the composite matrix.

676:    Not Collective

678:    Input Parameter:
679: .  mat - the composite matrix

681:    Output Parameter:
682: .  str - structure of the matrices

684:    Level: advanced

686: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MATCOMPOSITE`
687: @*/
688: PetscErrorCode MatCompositeGetMatStructure(Mat mat, MatStructure *str)
689: {
690:   PetscFunctionBegin;
693:   PetscUseMethod(mat, "MatCompositeGetMatStructure_C", (Mat, MatStructure *), (mat, str));
694:   PetscFunctionReturn(PETSC_SUCCESS);
695: }

697: static PetscErrorCode MatCompositeSetMergeType_Composite(Mat mat, MatCompositeMergeType type)
698: {
699:   Mat_Composite *shell = (Mat_Composite *)mat->data;

701:   PetscFunctionBegin;
702:   shell->mergetype = type;
703:   PetscFunctionReturn(PETSC_SUCCESS);
704: }

706: /*@
707:    MatCompositeSetMergeType - Sets order of `MatCompositeMerge()`.

709:    Logically Collective

711:    Input Parameters:
712: +  mat - the composite matrix
713: -  type - `MAT_COMPOSITE_MERGE RIGHT` (default) to start merge from right with the first added matrix (mat[0]),
714:           `MAT_COMPOSITE_MERGE_LEFT` to start merge from left with the last added matrix (mat[nmat-1])

716:    Level: advanced

718:    Note:
719:     The resulting matrix is the same regardless of the `MatCompositeMergeType`. Only the order of operation is changed.
720:     If set to `MAT_COMPOSITE_MERGE_RIGHT` the order of the merge is mat[nmat-1]*(mat[nmat-2]*(...*(mat[1]*mat[0])))
721:     otherwise the order is (((mat[nmat-1]*mat[nmat-2])*mat[nmat-3])*...)*mat[0].

723: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeMerge()`, `MATCOMPOSITE`
724: @*/
725: PetscErrorCode MatCompositeSetMergeType(Mat mat, MatCompositeMergeType type)
726: {
727:   PetscFunctionBegin;
730:   PetscUseMethod(mat, "MatCompositeSetMergeType_C", (Mat, MatCompositeMergeType), (mat, type));
731:   PetscFunctionReturn(PETSC_SUCCESS);
732: }

734: static PetscErrorCode MatCompositeMerge_Composite(Mat mat)
735: {
736:   Mat_Composite    *shell = (Mat_Composite *)mat->data;
737:   Mat_CompositeLink next = shell->head, prev = shell->tail;
738:   Mat               tmat, newmat;
739:   Vec               left, right;
740:   PetscScalar       scale;
741:   PetscInt          i;

743:   PetscFunctionBegin;
744:   PetscCheck(next, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least one matrix with MatCompositeAddMat()");
745:   scale = shell->scale;
746:   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
747:     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
748:       i = 0;
749:       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
750:       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i++]));
751:       while ((next = next->next)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i++] : 1.0), next->mat, shell->structure));
752:     } else {
753:       i = shell->nmat - 1;
754:       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
755:       if (shell->scalings) PetscCall(MatScale(tmat, shell->scalings[i--]));
756:       while ((prev = prev->prev)) PetscCall(MatAXPY(tmat, (shell->scalings ? shell->scalings[i--] : 1.0), prev->mat, shell->structure));
757:     }
758:   } else {
759:     if (shell->mergetype == MAT_COMPOSITE_MERGE_RIGHT) {
760:       PetscCall(MatDuplicate(next->mat, MAT_COPY_VALUES, &tmat));
761:       while ((next = next->next)) {
762:         PetscCall(MatMatMult(next->mat, tmat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
763:         PetscCall(MatDestroy(&tmat));
764:         tmat = newmat;
765:       }
766:     } else {
767:       PetscCall(MatDuplicate(prev->mat, MAT_COPY_VALUES, &tmat));
768:       while ((prev = prev->prev)) {
769:         PetscCall(MatMatMult(tmat, prev->mat, MAT_INITIAL_MATRIX, PETSC_DECIDE, &newmat));
770:         PetscCall(MatDestroy(&tmat));
771:         tmat = newmat;
772:       }
773:     }
774:     if (shell->scalings) {
775:       for (i = 0; i < shell->nmat; i++) scale *= shell->scalings[i];
776:     }
777:   }

779:   if ((left = shell->left)) PetscCall(PetscObjectReference((PetscObject)left));
780:   if ((right = shell->right)) PetscCall(PetscObjectReference((PetscObject)right));

782:   PetscCall(MatHeaderReplace(mat, &tmat));

784:   PetscCall(MatDiagonalScale(mat, left, right));
785:   PetscCall(MatScale(mat, scale));
786:   PetscCall(VecDestroy(&left));
787:   PetscCall(VecDestroy(&right));
788:   PetscFunctionReturn(PETSC_SUCCESS);
789: }

791: /*@
792:    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
793:      by summing or computing the product of all the matrices inside the composite matrix.

795:   Collective

797:    Input Parameter:
798: .  mat - the composite matrix

800:    Options Database Keys:
801: +  -mat_composite_merge - merge in `MatAssemblyEnd()`
802: -  -mat_composite_merge_type - set merge direction

804:    Level: advanced

806:    Note:
807:       The `MatType` of the resulting matrix will be the same as the `MatType` of the FIRST matrix in the composite matrix.

809: .seealso: [](chapter_matrices), `Mat`, `MatDestroy()`, `MatMult()`, `MatCompositeAddMat()`, `MatCreateComposite()`, `MatCompositeSetMatStructure()`, `MatCompositeSetMergeType()`, `MATCOMPOSITE`
810: @*/
811: PetscErrorCode MatCompositeMerge(Mat mat)
812: {
813:   PetscFunctionBegin;
815:   PetscUseMethod(mat, "MatCompositeMerge_C", (Mat), (mat));
816:   PetscFunctionReturn(PETSC_SUCCESS);
817: }

819: static PetscErrorCode MatCompositeGetNumberMat_Composite(Mat mat, PetscInt *nmat)
820: {
821:   Mat_Composite *shell = (Mat_Composite *)mat->data;

823:   PetscFunctionBegin;
824:   *nmat = shell->nmat;
825:   PetscFunctionReturn(PETSC_SUCCESS);
826: }

828: /*@
829:    MatCompositeGetNumberMat - Returns the number of matrices in the composite matrix.

831:    Not Collective

833:    Input Parameter:
834: .  mat - the composite matrix

836:    Output Parameter:
837: .  nmat - number of matrices in the composite matrix

839:    Level: advanced

841: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetMat()`, `MATCOMPOSITE`
842: @*/
843: PetscErrorCode MatCompositeGetNumberMat(Mat mat, PetscInt *nmat)
844: {
845:   PetscFunctionBegin;
848:   PetscUseMethod(mat, "MatCompositeGetNumberMat_C", (Mat, PetscInt *), (mat, nmat));
849:   PetscFunctionReturn(PETSC_SUCCESS);
850: }

852: static PetscErrorCode MatCompositeGetMat_Composite(Mat mat, PetscInt i, Mat *Ai)
853: {
854:   Mat_Composite    *shell = (Mat_Composite *)mat->data;
855:   Mat_CompositeLink ilink;
856:   PetscInt          k;

858:   PetscFunctionBegin;
859:   PetscCheck(i < shell->nmat, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "index out of range: %" PetscInt_FMT " >= %" PetscInt_FMT, i, shell->nmat);
860:   ilink = shell->head;
861:   for (k = 0; k < i; k++) ilink = ilink->next;
862:   *Ai = ilink->mat;
863:   PetscFunctionReturn(PETSC_SUCCESS);
864: }

866: /*@
867:    MatCompositeGetMat - Returns the ith matrix from the composite matrix.

869:    Logically Collective

871:    Input Parameters:
872: +  mat - the composite matrix
873: -  i - the number of requested matrix

875:    Output Parameter:
876: .  Ai - ith matrix in composite

878:    Level: advanced

880: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeGetNumberMat()`, `MatCompositeAddMat()`, `MATCOMPOSITE`
881: @*/
882: PetscErrorCode MatCompositeGetMat(Mat mat, PetscInt i, Mat *Ai)
883: {
884:   PetscFunctionBegin;
888:   PetscUseMethod(mat, "MatCompositeGetMat_C", (Mat, PetscInt, Mat *), (mat, i, Ai));
889:   PetscFunctionReturn(PETSC_SUCCESS);
890: }

892: PetscErrorCode MatCompositeSetScalings_Composite(Mat mat, const PetscScalar *scalings)
893: {
894:   Mat_Composite *shell = (Mat_Composite *)mat->data;
895:   PetscInt       nmat;

897:   PetscFunctionBegin;
898:   PetscCall(MatCompositeGetNumberMat(mat, &nmat));
899:   if (!shell->scalings) PetscCall(PetscMalloc1(nmat, &shell->scalings));
900:   PetscCall(PetscArraycpy(shell->scalings, scalings, nmat));
901:   PetscFunctionReturn(PETSC_SUCCESS);
902: }

904: /*@
905:    MatCompositeSetScalings - Sets separate scaling factors for component matrices.

907:    Logically Collective

909:    Input Parameters:
910: +  mat      - the composite matrix
911: -  scalings - array of scaling factors with scalings[i] being factor of i-th matrix, for i in [0, nmat)

913:    Level: advanced

915: .seealso: [](chapter_matrices), `Mat`, `MatScale()`, `MatDiagonalScale()`, `MATCOMPOSITE`
916: @*/
917: PetscErrorCode MatCompositeSetScalings(Mat mat, const PetscScalar *scalings)
918: {
919:   PetscFunctionBegin;
923:   PetscUseMethod(mat, "MatCompositeSetScalings_C", (Mat, const PetscScalar *), (mat, scalings));
924:   PetscFunctionReturn(PETSC_SUCCESS);
925: }

927: static struct _MatOps MatOps_Values = {NULL,
928:                                        NULL,
929:                                        NULL,
930:                                        MatMult_Composite,
931:                                        MatMultAdd_Composite,
932:                                        /*  5*/ MatMultTranspose_Composite,
933:                                        MatMultTransposeAdd_Composite,
934:                                        NULL,
935:                                        NULL,
936:                                        NULL,
937:                                        /* 10*/ NULL,
938:                                        NULL,
939:                                        NULL,
940:                                        NULL,
941:                                        NULL,
942:                                        /* 15*/ NULL,
943:                                        NULL,
944:                                        MatGetDiagonal_Composite,
945:                                        MatDiagonalScale_Composite,
946:                                        NULL,
947:                                        /* 20*/ NULL,
948:                                        MatAssemblyEnd_Composite,
949:                                        NULL,
950:                                        NULL,
951:                                        /* 24*/ NULL,
952:                                        NULL,
953:                                        NULL,
954:                                        NULL,
955:                                        NULL,
956:                                        /* 29*/ NULL,
957:                                        NULL,
958:                                        NULL,
959:                                        NULL,
960:                                        NULL,
961:                                        /* 34*/ NULL,
962:                                        NULL,
963:                                        NULL,
964:                                        NULL,
965:                                        NULL,
966:                                        /* 39*/ NULL,
967:                                        NULL,
968:                                        NULL,
969:                                        NULL,
970:                                        NULL,
971:                                        /* 44*/ NULL,
972:                                        MatScale_Composite,
973:                                        MatShift_Basic,
974:                                        NULL,
975:                                        NULL,
976:                                        /* 49*/ NULL,
977:                                        NULL,
978:                                        NULL,
979:                                        NULL,
980:                                        NULL,
981:                                        /* 54*/ NULL,
982:                                        NULL,
983:                                        NULL,
984:                                        NULL,
985:                                        NULL,
986:                                        /* 59*/ NULL,
987:                                        MatDestroy_Composite,
988:                                        NULL,
989:                                        NULL,
990:                                        NULL,
991:                                        /* 64*/ NULL,
992:                                        NULL,
993:                                        NULL,
994:                                        NULL,
995:                                        NULL,
996:                                        /* 69*/ NULL,
997:                                        NULL,
998:                                        NULL,
999:                                        NULL,
1000:                                        NULL,
1001:                                        /* 74*/ NULL,
1002:                                        NULL,
1003:                                        MatSetFromOptions_Composite,
1004:                                        NULL,
1005:                                        NULL,
1006:                                        /* 79*/ NULL,
1007:                                        NULL,
1008:                                        NULL,
1009:                                        NULL,
1010:                                        NULL,
1011:                                        /* 84*/ NULL,
1012:                                        NULL,
1013:                                        NULL,
1014:                                        NULL,
1015:                                        NULL,
1016:                                        /* 89*/ NULL,
1017:                                        NULL,
1018:                                        NULL,
1019:                                        NULL,
1020:                                        NULL,
1021:                                        /* 94*/ NULL,
1022:                                        NULL,
1023:                                        NULL,
1024:                                        NULL,
1025:                                        NULL,
1026:                                        /*99*/ NULL,
1027:                                        NULL,
1028:                                        NULL,
1029:                                        NULL,
1030:                                        NULL,
1031:                                        /*104*/ NULL,
1032:                                        NULL,
1033:                                        NULL,
1034:                                        NULL,
1035:                                        NULL,
1036:                                        /*109*/ NULL,
1037:                                        NULL,
1038:                                        NULL,
1039:                                        NULL,
1040:                                        NULL,
1041:                                        /*114*/ NULL,
1042:                                        NULL,
1043:                                        NULL,
1044:                                        NULL,
1045:                                        NULL,
1046:                                        /*119*/ NULL,
1047:                                        NULL,
1048:                                        NULL,
1049:                                        NULL,
1050:                                        NULL,
1051:                                        /*124*/ NULL,
1052:                                        NULL,
1053:                                        NULL,
1054:                                        NULL,
1055:                                        NULL,
1056:                                        /*129*/ NULL,
1057:                                        NULL,
1058:                                        NULL,
1059:                                        NULL,
1060:                                        NULL,
1061:                                        /*134*/ NULL,
1062:                                        NULL,
1063:                                        NULL,
1064:                                        NULL,
1065:                                        NULL,
1066:                                        /*139*/ NULL,
1067:                                        NULL,
1068:                                        NULL,
1069:                                        NULL,
1070:                                        NULL,
1071:                                        /*144*/ NULL,
1072:                                        NULL,
1073:                                        NULL,
1074:                                        NULL,
1075:                                        NULL,
1076:                                        NULL,
1077:                                        /*150*/ NULL,
1078:                                        NULL};

1080: /*MC
1081:    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices.
1082:     The matrices need to have a correct size and parallel layout for the sum or product to be valid.

1084:   Level: advanced

1086:    Note:
1087:    To use the product of the matrices call `MatCompositeSetType`(mat,`MAT_COMPOSITE_MULTIPLICATIVE`);

1089: .seealso: [](chapter_matrices), `Mat`, `MatCreateComposite()`, `MatCompositeSetScalings()`, `MatCompositeAddMat()`, `MatSetType()`, `MatCompositeSetType()`, `MatCompositeGetType()`,
1090:           `MatCompositeSetMatStructure()`, `MatCompositeGetMatStructure()`, `MatCompositeMerge()`, `MatCompositeSetMergeType()`, `MatCompositeGetNumberMat()`, `MatCompositeGetMat()`
1091: M*/

1093: PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
1094: {
1095:   Mat_Composite *b;

1097:   PetscFunctionBegin;
1098:   PetscCall(PetscNew(&b));
1099:   A->data = (void *)b;
1100:   PetscCall(PetscMemcpy(A->ops, &MatOps_Values, sizeof(struct _MatOps)));

1102:   PetscCall(PetscLayoutSetUp(A->rmap));
1103:   PetscCall(PetscLayoutSetUp(A->cmap));

1105:   A->assembled    = PETSC_TRUE;
1106:   A->preallocated = PETSC_TRUE;
1107:   b->type         = MAT_COMPOSITE_ADDITIVE;
1108:   b->scale        = 1.0;
1109:   b->nmat         = 0;
1110:   b->merge        = PETSC_FALSE;
1111:   b->mergetype    = MAT_COMPOSITE_MERGE_RIGHT;
1112:   b->structure    = DIFFERENT_NONZERO_PATTERN;
1113:   b->merge_mvctx  = PETSC_TRUE;

1115:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeAddMat_C", MatCompositeAddMat_Composite));
1116:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetType_C", MatCompositeSetType_Composite));
1117:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetType_C", MatCompositeGetType_Composite));
1118:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMergeType_C", MatCompositeSetMergeType_Composite));
1119:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetMatStructure_C", MatCompositeSetMatStructure_Composite));
1120:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMatStructure_C", MatCompositeGetMatStructure_Composite));
1121:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeMerge_C", MatCompositeMerge_Composite));
1122:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetNumberMat_C", MatCompositeGetNumberMat_Composite));
1123:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeGetMat_C", MatCompositeGetMat_Composite));
1124:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatCompositeSetScalings_C", MatCompositeSetScalings_Composite));

1126:   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATCOMPOSITE));
1127:   PetscFunctionReturn(PETSC_SUCCESS);
1128: }