Actual source code: mcomposite.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  2: #include <petsc/private/matimpl.h>        /*I "petscmat.h" I*/

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

 11: typedef struct {
 12:   MatCompositeType  type;
 13:   Mat_CompositeLink head,tail;
 14:   Vec               work;
 15:   PetscScalar       scale;        /* scale factor supplied with MatScale() */
 16:   Vec               left,right;   /* left and right diagonal scaling provided with MatDiagonalScale() */
 17:   Vec               leftwork,rightwork;
 18: } Mat_Composite;

 22: PetscErrorCode MatDestroy_Composite(Mat mat)
 23: {
 24:   PetscErrorCode    ierr;
 25:   Mat_Composite     *shell = (Mat_Composite*)mat->data;
 26:   Mat_CompositeLink next   = shell->head,oldnext;

 29:   while (next) {
 30:     MatDestroy(&next->mat);
 31:     if (next->work && (!next->next || next->work != next->next->work)) {
 32:       VecDestroy(&next->work);
 33:     }
 34:     oldnext = next;
 35:     next    = next->next;
 36:     PetscFree(oldnext);
 37:   }
 38:   VecDestroy(&shell->work);
 39:   VecDestroy(&shell->left);
 40:   VecDestroy(&shell->right);
 41:   VecDestroy(&shell->leftwork);
 42:   VecDestroy(&shell->rightwork);
 43:   PetscFree(mat->data);
 44:   return(0);
 45: }

 49: PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y)
 50: {
 51:   Mat_Composite     *shell = (Mat_Composite*)A->data;
 52:   Mat_CompositeLink next   = shell->head;
 53:   PetscErrorCode    ierr;
 54:   Vec               in,out;

 57:   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
 58:   in = x;
 59:   if (shell->right) {
 60:     if (!shell->rightwork) {
 61:       VecDuplicate(shell->right,&shell->rightwork);
 62:     }
 63:     VecPointwiseMult(shell->rightwork,shell->right,in);
 64:     in   = shell->rightwork;
 65:   }
 66:   while (next->next) {
 67:     if (!next->work) { /* should reuse previous work if the same size */
 68:       MatCreateVecs(next->mat,NULL,&next->work);
 69:     }
 70:     out  = next->work;
 71:     MatMult(next->mat,in,out);
 72:     in   = out;
 73:     next = next->next;
 74:   }
 75:   MatMult(next->mat,in,y);
 76:   if (shell->left) {
 77:     VecPointwiseMult(y,shell->left,y);
 78:   }
 79:   VecScale(y,shell->scale);
 80:   return(0);
 81: }

 85: PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y)
 86: {
 87:   Mat_Composite     *shell = (Mat_Composite*)A->data;
 88:   Mat_CompositeLink tail   = shell->tail;
 89:   PetscErrorCode    ierr;
 90:   Vec               in,out;

 93:   if (!tail) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
 94:   in = x;
 95:   if (shell->left) {
 96:     if (!shell->leftwork) {
 97:       VecDuplicate(shell->left,&shell->leftwork);
 98:     }
 99:     VecPointwiseMult(shell->leftwork,shell->left,in);
100:     in   = shell->leftwork;
101:   }
102:   while (tail->prev) {
103:     if (!tail->prev->work) { /* should reuse previous work if the same size */
104:       MatCreateVecs(tail->mat,NULL,&tail->prev->work);
105:     }
106:     out  = tail->prev->work;
107:     MatMultTranspose(tail->mat,in,out);
108:     in   = out;
109:     tail = tail->prev;
110:   }
111:   MatMultTranspose(tail->mat,in,y);
112:   if (shell->right) {
113:     VecPointwiseMult(y,shell->right,y);
114:   }
115:   VecScale(y,shell->scale);
116:   return(0);
117: }

121: PetscErrorCode MatMult_Composite(Mat A,Vec x,Vec y)
122: {
123:   Mat_Composite     *shell = (Mat_Composite*)A->data;
124:   Mat_CompositeLink next   = shell->head;
125:   PetscErrorCode    ierr;
126:   Vec               in;

129:   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
130:   in = x;
131:   if (shell->right) {
132:     if (!shell->rightwork) {
133:       VecDuplicate(shell->right,&shell->rightwork);
134:     }
135:     VecPointwiseMult(shell->rightwork,shell->right,in);
136:     in   = shell->rightwork;
137:   }
138:   MatMult(next->mat,in,y);
139:   while ((next = next->next)) {
140:     MatMultAdd(next->mat,in,y,y);
141:   }
142:   if (shell->left) {
143:     VecPointwiseMult(y,shell->left,y);
144:   }
145:   VecScale(y,shell->scale);
146:   return(0);
147: }

151: PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y)
152: {
153:   Mat_Composite     *shell = (Mat_Composite*)A->data;
154:   Mat_CompositeLink next   = shell->head;
155:   PetscErrorCode    ierr;
156:   Vec               in;

159:   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
160:   in = x;
161:   if (shell->left) {
162:     if (!shell->leftwork) {
163:       VecDuplicate(shell->left,&shell->leftwork);
164:     }
165:     VecPointwiseMult(shell->leftwork,shell->left,in);
166:     in   = shell->leftwork;
167:   }
168:   MatMultTranspose(next->mat,in,y);
169:   while ((next = next->next)) {
170:     MatMultTransposeAdd(next->mat,in,y,y);
171:   }
172:   if (shell->right) {
173:     VecPointwiseMult(y,shell->right,y);
174:   }
175:   VecScale(y,shell->scale);
176:   return(0);
177: }

181: PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v)
182: {
183:   Mat_Composite     *shell = (Mat_Composite*)A->data;
184:   Mat_CompositeLink next   = shell->head;
185:   PetscErrorCode    ierr;

188:   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");
189:   if (shell->right || shell->left) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get diagonal if left or right scaling");

191:   MatGetDiagonal(next->mat,v);
192:   if (next->next && !shell->work) {
193:     VecDuplicate(v,&shell->work);
194:   }
195:   while ((next = next->next)) {
196:     MatGetDiagonal(next->mat,shell->work);
197:     VecAXPY(v,1.0,shell->work);
198:   }
199:   VecScale(v,shell->scale);
200:   return(0);
201: }

205: PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t)
206: {
208:   PetscBool      flg = PETSC_FALSE;

211:   PetscOptionsGetBool(((PetscObject)Y)->options,((PetscObject)Y)->prefix,"-mat_composite_merge",&flg,NULL);
212:   if (flg) {
213:     MatCompositeMerge(Y);
214:   }
215:   return(0);
216: }

220: PetscErrorCode MatScale_Composite(Mat inA,PetscScalar alpha)
221: {
222:   Mat_Composite *a = (Mat_Composite*)inA->data;

225:   a->scale *= alpha;
226:   return(0);
227: }

231: PetscErrorCode MatDiagonalScale_Composite(Mat inA,Vec left,Vec right)
232: {
233:   Mat_Composite  *a = (Mat_Composite*)inA->data;

237:   if (left) {
238:     if (!a->left) {
239:       VecDuplicate(left,&a->left);
240:       VecCopy(left,a->left);
241:     } else {
242:       VecPointwiseMult(a->left,left,a->left);
243:     }
244:   }
245:   if (right) {
246:     if (!a->right) {
247:       VecDuplicate(right,&a->right);
248:       VecCopy(right,a->right);
249:     } else {
250:       VecPointwiseMult(a->right,right,a->right);
251:     }
252:   }
253:   return(0);
254: }

256: static struct _MatOps MatOps_Values = {0,
257:                                        0,
258:                                        0,
259:                                        MatMult_Composite,
260:                                        0,
261:                                 /*  5*/ MatMultTranspose_Composite,
262:                                        0,
263:                                        0,
264:                                        0,
265:                                        0,
266:                                 /* 10*/ 0,
267:                                        0,
268:                                        0,
269:                                        0,
270:                                        0,
271:                                 /* 15*/ 0,
272:                                        0,
273:                                        MatGetDiagonal_Composite,
274:                                        MatDiagonalScale_Composite,
275:                                        0,
276:                                 /* 20*/ 0,
277:                                        MatAssemblyEnd_Composite,
278:                                        0,
279:                                        0,
280:                                /* 24*/ 0,
281:                                        0,
282:                                        0,
283:                                        0,
284:                                        0,
285:                                /* 29*/ 0,
286:                                        0,
287:                                        0,
288:                                        0,
289:                                        0,
290:                                /* 34*/ 0,
291:                                        0,
292:                                        0,
293:                                        0,
294:                                        0,
295:                                /* 39*/ 0,
296:                                        0,
297:                                        0,
298:                                        0,
299:                                        0,
300:                                /* 44*/ 0,
301:                                        MatScale_Composite,
302:                                        MatShift_Basic,
303:                                        0,
304:                                        0,
305:                                /* 49*/ 0,
306:                                        0,
307:                                        0,
308:                                        0,
309:                                        0,
310:                                /* 54*/ 0,
311:                                        0,
312:                                        0,
313:                                        0,
314:                                        0,
315:                                /* 59*/ 0,
316:                                        MatDestroy_Composite,
317:                                        0,
318:                                        0,
319:                                        0,
320:                                /* 64*/ 0,
321:                                        0,
322:                                        0,
323:                                        0,
324:                                        0,
325:                                /* 69*/ 0,
326:                                        0,
327:                                        0,
328:                                        0,
329:                                        0,
330:                                /* 74*/ 0,
331:                                        0,
332:                                        0,
333:                                        0,
334:                                        0,
335:                                /* 79*/ 0,
336:                                        0,
337:                                        0,
338:                                        0,
339:                                        0,
340:                                /* 84*/ 0,
341:                                        0,
342:                                        0,
343:                                        0,
344:                                        0,
345:                                /* 89*/ 0,
346:                                        0,
347:                                        0,
348:                                        0,
349:                                        0,
350:                                /* 94*/ 0,
351:                                        0,
352:                                        0,
353:                                        0,
354:                                        0,
355:                                 /*99*/ 0,
356:                                        0,
357:                                        0,
358:                                        0,
359:                                        0,
360:                                /*104*/ 0,
361:                                        0,
362:                                        0,
363:                                        0,
364:                                        0,
365:                                /*109*/ 0,
366:                                        0,
367:                                        0,
368:                                        0,
369:                                        0,
370:                                /*114*/ 0,
371:                                        0,
372:                                        0,
373:                                        0,
374:                                        0,
375:                                /*119*/ 0,
376:                                        0,
377:                                        0,
378:                                        0,
379:                                        0,
380:                                /*124*/ 0,
381:                                        0,
382:                                        0,
383:                                        0,
384:                                        0,
385:                                /*129*/ 0,
386:                                        0,
387:                                        0,
388:                                        0,
389:                                        0,
390:                                /*134*/ 0,
391:                                        0,
392:                                        0,
393:                                        0,
394:                                        0,
395:                                /*139*/ 0,
396:                                        0,
397:                                        0
398: };

400: /*MC
401:    MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices (all matrices are of same size and parallel layout).

403:    Notes: to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE);

405:   Level: advanced

407: .seealso: MatCreateComposite(), MatCompositeAddMat(), MatSetType(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType
408: M*/

412: PETSC_EXTERN PetscErrorCode MatCreate_Composite(Mat A)
413: {
414:   Mat_Composite  *b;

418:   PetscNewLog(A,&b);
419:   A->data = (void*)b;
420:   PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));

422:   PetscLayoutSetUp(A->rmap);
423:   PetscLayoutSetUp(A->cmap);

425:   A->assembled    = PETSC_TRUE;
426:   A->preallocated = PETSC_TRUE;
427:   b->type         = MAT_COMPOSITE_ADDITIVE;
428:   b->scale        = 1.0;
429:   PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);
430:   return(0);
431: }

435: /*@
436:    MatCreateComposite - Creates a matrix as the sum of zero or more matrices

438:   Collective on MPI_Comm

440:    Input Parameters:
441: +  comm - MPI communicator
442: .  nmat - number of matrices to put in
443: -  mats - the matrices

445:    Output Parameter:
446: .  A - the matrix

448:    Level: advanced

450:    Notes:
451:      Alternative construction
452: $       MatCreate(comm,&mat);
453: $       MatSetSizes(mat,m,n,M,N);
454: $       MatSetType(mat,MATCOMPOSITE);
455: $       MatCompositeAddMat(mat,mats[0]);
456: $       ....
457: $       MatCompositeAddMat(mat,mats[nmat-1]);
458: $       MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
459: $       MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);

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

463: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType

465: @*/
466: PetscErrorCode  MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat)
467: {
469:   PetscInt       m,n,M,N,i;

472:   if (nmat < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix");

475:   MatGetLocalSize(mats[0],&m,&n);
476:   MatGetSize(mats[0],&M,&N);
477:   MatCreate(comm,mat);
478:   MatSetSizes(*mat,m,n,M,N);
479:   MatSetType(*mat,MATCOMPOSITE);
480:   for (i=0; i<nmat; i++) {
481:     MatCompositeAddMat(*mat,mats[i]);
482:   }
483:   MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);
484:   MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);
485:   return(0);
486: }

490: /*@
491:     MatCompositeAddMat - add another matrix to a composite matrix

493:    Collective on Mat

495:     Input Parameters:
496: +   mat - the composite matrix
497: -   smat - the partial matrix

499:    Level: advanced

501: .seealso: MatCreateComposite()
502: @*/
503: PetscErrorCode  MatCompositeAddMat(Mat mat,Mat smat)
504: {
505:   Mat_Composite     *shell;
506:   PetscErrorCode    ierr;
507:   Mat_CompositeLink ilink,next;

512:   PetscNewLog(mat,&ilink);
513:   ilink->next = 0;
514:   PetscObjectReference((PetscObject)smat);
515:   ilink->mat  = smat;

517:   shell = (Mat_Composite*)mat->data;
518:   next  = shell->head;
519:   if (!next) shell->head = ilink;
520:   else {
521:     while (next->next) {
522:       next = next->next;
523:     }
524:     next->next  = ilink;
525:     ilink->prev = next;
526:   }
527:   shell->tail = ilink;
528:   return(0);
529: }

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

536:   Collective on MPI_Comm

538:    Input Parameters:
539: .  mat - the composite matrix


542:    Level: advanced

544:    Notes:
545:       The MatType of the resulting matrix will be the same as the MatType of the FIRST
546:     matrix in the composite matrix.

548: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE

550: @*/
551: PetscErrorCode  MatCompositeSetType(Mat mat,MatCompositeType type)
552: {
553:   Mat_Composite  *b = (Mat_Composite*)mat->data;
554:   PetscBool      flg;

558:   PetscObjectTypeCompare((PetscObject)mat,MATCOMPOSITE,&flg);
559:   if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Can only use with composite matrix");
560:   if (type == MAT_COMPOSITE_MULTIPLICATIVE) {
561:     mat->ops->getdiagonal   = 0;
562:     mat->ops->mult          = MatMult_Composite_Multiplicative;
563:     mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative;
564:     b->type                 = MAT_COMPOSITE_MULTIPLICATIVE;
565:   } else {
566:     mat->ops->getdiagonal   = MatGetDiagonal_Composite;
567:     mat->ops->mult          = MatMult_Composite;
568:     mat->ops->multtranspose = MatMultTranspose_Composite;
569:     b->type                 = MAT_COMPOSITE_ADDITIVE;
570:   }
571:   return(0);
572: }


577: /*@
578:    MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix
579:      by summing all the matrices inside the composite matrix.

581:   Collective on MPI_Comm

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


587:    Options Database:
588: .  -mat_composite_merge  (you must call MatAssemblyBegin()/MatAssemblyEnd() to have this checked)

590:    Level: advanced

592:    Notes:
593:       The MatType of the resulting matrix will be the same as the MatType of the FIRST
594:     matrix in the composite matrix.

596: .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE

598: @*/
599: PetscErrorCode  MatCompositeMerge(Mat mat)
600: {
601:   Mat_Composite     *shell = (Mat_Composite*)mat->data;
602:   Mat_CompositeLink next   = shell->head, prev = shell->tail;
603:   PetscErrorCode    ierr;
604:   Mat               tmat,newmat;
605:   Vec               left,right;
606:   PetscScalar       scale;

609:   if (!next) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()");

612:   if (shell->type == MAT_COMPOSITE_ADDITIVE) {
613:     MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
614:     while ((next = next->next)) {
615:       MatAXPY(tmat,1.0,next->mat,DIFFERENT_NONZERO_PATTERN);
616:     }
617:   } else {
618:     MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);
619:     while ((prev = prev->prev)) {
620:       MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);
621:       MatDestroy(&tmat);
622:       tmat = newmat;
623:     }
624:   }

626:   scale = shell->scale;
627:   if ((left = shell->left)) {PetscObjectReference((PetscObject)left);}
628:   if ((right = shell->right)) {PetscObjectReference((PetscObject)right);}

630:   MatHeaderReplace(mat,&tmat);

632:   MatDiagonalScale(mat,left,right);
633:   MatScale(mat,scale);
634:   VecDestroy(&left);
635:   VecDestroy(&right);
636:   return(0);
637: }