Actual source code: matis.c
petsc-3.13.1 2020-05-02
1: /*
2: Creates a matrix class for using the Neumann-Neumann type preconditioners.
3: This stores the matrices in globally unassembled form. Each processor
4: assembles only its local Neumann problem and the parallel matrix vector
5: product is handled "implicitly".
7: Currently this allows for only one subdomain per processor.
8: */
10: #include <../src/mat/impls/is/matis.h>
11: #include <petsc/private/sfimpl.h>
12: #include <petsc/private/vecimpl.h>
14: #define MATIS_MAX_ENTRIES_INSERTION 2048
15: static PetscErrorCode MatSetValuesLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
16: static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode);
17: static PetscErrorCode MatISSetUpScatters_Private(Mat);
19: static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr)
20: {
21: MatISPtAP ptap = (MatISPtAP)ptr;
25: MatDestroySubMatrices(ptap->ris1 ? 2 : 1,&ptap->lP);
26: ISDestroy(&ptap->cis0);
27: ISDestroy(&ptap->cis1);
28: ISDestroy(&ptap->ris0);
29: ISDestroy(&ptap->ris1);
30: PetscFree(ptap);
31: return(0);
32: }
34: static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C)
35: {
36: MatISPtAP ptap;
37: Mat_IS *matis = (Mat_IS*)A->data;
38: Mat lA,lC;
39: MatReuse reuse;
40: IS ris[2],cis[2];
41: PetscContainer c;
42: PetscInt n;
46: PetscObjectQuery((PetscObject)C,"_MatIS_PtAP",(PetscObject*)&c);
47: if (!c) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing PtAP information");
48: PetscContainerGetPointer(c,(void**)&ptap);
49: ris[0] = ptap->ris0;
50: ris[1] = ptap->ris1;
51: cis[0] = ptap->cis0;
52: cis[1] = ptap->cis1;
53: n = ptap->ris1 ? 2 : 1;
54: reuse = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX;
55: MatCreateSubMatrices(P,n,ris,cis,reuse,&ptap->lP);
57: MatISGetLocalMat(A,&lA);
58: MatISGetLocalMat(C,&lC);
59: if (ptap->ris1) { /* unsymmetric A mapping */
60: Mat lPt;
62: MatTranspose(ptap->lP[1],MAT_INITIAL_MATRIX,&lPt);
63: MatMatMatMult(lPt,lA,ptap->lP[0],reuse,ptap->fill,&lC);
64: if (matis->storel2l) {
65: PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",(PetscObject)lPt);
66: }
67: MatDestroy(&lPt);
68: } else {
69: MatPtAP(lA,ptap->lP[0],reuse,ptap->fill,&lC);
70: if (matis->storel2l) {
71: PetscObjectCompose((PetscObject)C,"_MatIS_PtAP_l2l",(PetscObject)ptap->lP[0]);
72: }
73: }
74: if (reuse == MAT_INITIAL_MATRIX) {
75: MatISSetLocalMat(C,lC);
76: MatDestroy(&lC);
77: }
78: MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);
79: MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);
80: return(0);
81: }
83: static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT,IS *cis)
84: {
85: Mat Po,Pd;
86: IS zd,zo;
87: const PetscInt *garray;
88: PetscInt *aux,i,bs;
89: PetscInt dc,stc,oc,ctd,cto;
90: PetscBool ismpiaij,ismpibaij,isseqaij,isseqbaij;
91: MPI_Comm comm;
97: PetscObjectGetComm((PetscObject)PT,&comm);
98: bs = 1;
99: PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIAIJ,&ismpiaij);
100: PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIBAIJ,&ismpibaij);
101: PetscObjectBaseTypeCompare((PetscObject)PT,MATSEQAIJ,&isseqaij);
102: PetscObjectTypeCompare((PetscObject)PT,MATSEQBAIJ,&isseqbaij);
103: if (isseqaij || isseqbaij) {
104: Pd = PT;
105: Po = NULL;
106: garray = NULL;
107: } else if (ismpiaij) {
108: MatMPIAIJGetSeqAIJ(PT,&Pd,&Po,&garray);
109: } else if (ismpibaij) {
110: MatMPIBAIJGetSeqBAIJ(PT,&Pd,&Po,&garray);
111: MatGetBlockSize(PT,&bs);
112: } else SETERRQ1(comm,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(PT))->type_name);
114: /* identify any null columns in Pd or Po */
115: /* We use a tolerance comparison since it may happen that, with geometric multigrid,
116: some of the columns are not really zero, but very close to */
117: zo = zd = NULL;
118: if (Po) {
119: MatFindNonzeroRowsOrCols_Basic(Po,PETSC_TRUE,PETSC_SMALL,&zo);
120: }
121: MatFindNonzeroRowsOrCols_Basic(Pd,PETSC_TRUE,PETSC_SMALL,&zd);
123: MatGetLocalSize(PT,NULL,&dc);
124: MatGetOwnershipRangeColumn(PT,&stc,NULL);
125: if (Po) { MatGetLocalSize(Po,NULL,&oc); }
126: else oc = 0;
127: PetscMalloc1((dc+oc)/bs,&aux);
128: if (zd) {
129: const PetscInt *idxs;
130: PetscInt nz;
132: /* this will throw an error if bs is not valid */
133: ISSetBlockSize(zd,bs);
134: ISGetLocalSize(zd,&nz);
135: ISGetIndices(zd,&idxs);
136: ctd = nz/bs;
137: for (i=0; i<ctd; i++) aux[i] = (idxs[bs*i]+stc)/bs;
138: ISRestoreIndices(zd,&idxs);
139: } else {
140: ctd = dc/bs;
141: for (i=0; i<ctd; i++) aux[i] = i+stc/bs;
142: }
143: if (zo) {
144: const PetscInt *idxs;
145: PetscInt nz;
147: /* this will throw an error if bs is not valid */
148: ISSetBlockSize(zo,bs);
149: ISGetLocalSize(zo,&nz);
150: ISGetIndices(zo,&idxs);
151: cto = nz/bs;
152: for (i=0; i<cto; i++) aux[i+ctd] = garray[idxs[bs*i]/bs];
153: ISRestoreIndices(zo,&idxs);
154: } else {
155: cto = oc/bs;
156: for (i=0; i<cto; i++) aux[i+ctd] = garray[i];
157: }
158: ISCreateBlock(comm,bs,ctd+cto,aux,PETSC_OWN_POINTER,cis);
159: ISDestroy(&zd);
160: ISDestroy(&zo);
161: return(0);
162: }
164: static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A,Mat P,PetscReal fill,Mat C)
165: {
166: Mat PT,lA;
167: MatISPtAP ptap;
168: ISLocalToGlobalMapping Crl2g,Ccl2g,rl2g,cl2g;
169: PetscContainer c;
170: MatType lmtype;
171: const PetscInt *garray;
172: PetscInt ibs,N,dc;
173: MPI_Comm comm;
174: PetscErrorCode ierr;
177: PetscObjectGetComm((PetscObject)A,&comm);
178: MatSetType(C,MATIS);
179: MatISGetLocalMat(A,&lA);
180: MatGetType(lA,&lmtype);
181: MatISSetLocalMatType(C,lmtype);
182: MatGetSize(P,NULL,&N);
183: MatGetLocalSize(P,NULL,&dc);
184: MatSetSizes(C,dc,dc,N,N);
185: /* Not sure about this
186: MatGetBlockSizes(P,NULL,&ibs);
187: MatSetBlockSize(*C,ibs);
188: */
190: PetscNew(&ptap);
191: PetscContainerCreate(PETSC_COMM_SELF,&c);
192: PetscContainerSetPointer(c,ptap);
193: PetscContainerSetUserDestroy(c,MatISContainerDestroyPtAP_Private);
194: PetscObjectCompose((PetscObject)C,"_MatIS_PtAP",(PetscObject)c);
195: PetscContainerDestroy(&c);
196: ptap->fill = fill;
198: MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);
200: ISLocalToGlobalMappingGetBlockSize(cl2g,&ibs);
201: ISLocalToGlobalMappingGetSize(cl2g,&N);
202: ISLocalToGlobalMappingGetBlockIndices(cl2g,&garray);
203: ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris0);
204: ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&garray);
206: MatCreateSubMatrix(P,ptap->ris0,NULL,MAT_INITIAL_MATRIX,&PT);
207: MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis0);
208: ISLocalToGlobalMappingCreateIS(ptap->cis0,&Ccl2g);
209: MatDestroy(&PT);
211: Crl2g = NULL;
212: if (rl2g != cl2g) { /* unsymmetric A mapping */
213: PetscBool same,lsame = PETSC_FALSE;
214: PetscInt N1,ibs1;
216: ISLocalToGlobalMappingGetSize(rl2g,&N1);
217: ISLocalToGlobalMappingGetBlockSize(rl2g,&ibs1);
218: ISLocalToGlobalMappingGetBlockIndices(rl2g,&garray);
219: ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris1);
220: ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&garray);
221: if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */
222: const PetscInt *i1,*i2;
224: ISBlockGetIndices(ptap->ris0,&i1);
225: ISBlockGetIndices(ptap->ris1,&i2);
226: PetscArraycmp(i1,i2,N,&lsame);
227: }
228: MPIU_Allreduce(&lsame,&same,1,MPIU_BOOL,MPI_LAND,comm);
229: if (same) {
230: ISDestroy(&ptap->ris1);
231: } else {
232: MatCreateSubMatrix(P,ptap->ris1,NULL,MAT_INITIAL_MATRIX,&PT);
233: MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis1);
234: ISLocalToGlobalMappingCreateIS(ptap->cis1,&Crl2g);
235: MatDestroy(&PT);
236: }
237: }
238: /* Not sure about this
239: if (!Crl2g) {
240: MatGetBlockSize(C,&ibs);
241: ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs);
242: }
243: */
244: MatSetLocalToGlobalMapping(C,Crl2g ? Crl2g : Ccl2g,Ccl2g);
245: ISLocalToGlobalMappingDestroy(&Crl2g);
246: ISLocalToGlobalMappingDestroy(&Ccl2g);
248: C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ;
249: return(0);
250: }
252: /* ----------------------------------------- */
253: static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C)
254: {
256: Mat_Product *product = C->product;
257: Mat A=product->A,P=product->B;
258: PetscReal fill=product->fill;
261: MatPtAPSymbolic_IS_XAIJ(A,P,fill,C);
262: C->ops->productnumeric = MatProductNumeric_PtAP;
263: return(0);
264: }
266: static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C)
267: {
269: C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ;
270: return(0);
271: }
273: PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C)
274: {
276: Mat_Product *product = C->product;
279: MatSetType(C,MATIS);
280: if (product->type == MATPRODUCT_PtAP) {
281: MatProductSetFromOptions_IS_XAIJ_PtAP(C);
282: } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatProduct type %s is not supported for IS and XAIJ matrices",MatProductTypes[product->type]);
283: return(0);
284: }
286: /* ----------------------------------------- */
287: static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr)
288: {
289: MatISLocalFields lf = (MatISLocalFields)ptr;
290: PetscInt i;
291: PetscErrorCode ierr;
294: for (i=0;i<lf->nr;i++) {
295: ISDestroy(&lf->rf[i]);
296: }
297: for (i=0;i<lf->nc;i++) {
298: ISDestroy(&lf->cf[i]);
299: }
300: PetscFree2(lf->rf,lf->cf);
301: PetscFree(lf);
302: return(0);
303: }
305: static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
306: {
307: Mat B,lB;
311: if (reuse != MAT_REUSE_MATRIX) {
312: ISLocalToGlobalMapping rl2g,cl2g;
313: PetscInt bs;
314: IS is;
316: MatGetBlockSize(A,&bs);
317: ISCreateStride(PetscObjectComm((PetscObject)A),A->rmap->n/bs,0,1,&is);
318: if (bs > 1) {
319: IS is2;
320: PetscInt i,*aux;
322: ISGetLocalSize(is,&i);
323: ISGetIndices(is,(const PetscInt**)&aux);
324: ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);
325: ISRestoreIndices(is,(const PetscInt**)&aux);
326: ISDestroy(&is);
327: is = is2;
328: }
329: ISSetIdentity(is);
330: ISLocalToGlobalMappingCreateIS(is,&rl2g);
331: ISDestroy(&is);
332: ISCreateStride(PetscObjectComm((PetscObject)A),A->cmap->n/bs,0,1,&is);
333: if (bs > 1) {
334: IS is2;
335: PetscInt i,*aux;
337: ISGetLocalSize(is,&i);
338: ISGetIndices(is,(const PetscInt**)&aux);
339: ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2);
340: ISRestoreIndices(is,(const PetscInt**)&aux);
341: ISDestroy(&is);
342: is = is2;
343: }
344: ISSetIdentity(is);
345: ISLocalToGlobalMappingCreateIS(is,&cl2g);
346: ISDestroy(&is);
347: MatCreateIS(PetscObjectComm((PetscObject)A),bs,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N,rl2g,cl2g,&B);
348: ISLocalToGlobalMappingDestroy(&rl2g);
349: ISLocalToGlobalMappingDestroy(&cl2g);
350: MatDuplicate(A,MAT_COPY_VALUES,&lB);
351: if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
352: } else {
353: B = *newmat;
354: PetscObjectReference((PetscObject)A);
355: lB = A;
356: }
357: MatISSetLocalMat(B,lB);
358: MatDestroy(&lB);
359: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
360: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
361: if (reuse == MAT_INPLACE_MATRIX) {
362: MatHeaderReplace(A,&B);
363: }
364: return(0);
365: }
367: static PetscErrorCode MatISScaleDisassembling_Private(Mat A)
368: {
369: Mat_IS *matis = (Mat_IS*)(A->data);
370: PetscScalar *aa;
371: const PetscInt *ii,*jj;
372: PetscInt i,n,m;
373: PetscInt *ecount,**eneighs;
374: PetscBool flg;
378: MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);
379: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
380: ISLocalToGlobalMappingGetNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);
381: if (m != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",m,n);
382: MatSeqAIJGetArray(matis->A,&aa);
383: for (i=0;i<n;i++) {
384: if (ecount[i] > 1) {
385: PetscInt j;
387: for (j=ii[i];j<ii[i+1];j++) {
388: PetscInt i2 = jj[j],p,p2;
389: PetscReal scal = 0.0;
391: for (p=0;p<ecount[i];p++) {
392: for (p2=0;p2<ecount[i2];p2++) {
393: if (eneighs[i][p] == eneighs[i2][p2]) { scal += 1.0; break; }
394: }
395: }
396: if (scal) aa[j] /= scal;
397: }
398: }
399: }
400: ISLocalToGlobalMappingRestoreNodeInfo(A->rmap->mapping,&n,&ecount,&eneighs);
401: MatSeqAIJRestoreArray(matis->A,&aa);
402: MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg);
403: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
404: return(0);
405: }
407: typedef enum {MAT_IS_DISASSEMBLE_L2G_NATURAL,MAT_IS_DISASSEMBLE_L2G_MAT, MAT_IS_DISASSEMBLE_L2G_ND} MatISDisassemblel2gType;
409: static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g)
410: {
411: Mat Ad,Ao;
412: IS is,ndmap,ndsub;
413: MPI_Comm comm;
414: const PetscInt *garray,*ndmapi;
415: PetscInt bs,i,cnt,nl,*ncount,*ndmapc;
416: PetscBool ismpiaij,ismpibaij;
417: const char *const MatISDisassemblel2gTypes[] = {"NATURAL","MAT","ND","MatISDisassemblel2gType","MAT_IS_DISASSEMBLE_L2G_",0};
418: MatISDisassemblel2gType mode = MAT_IS_DISASSEMBLE_L2G_NATURAL;
419: MatPartitioning part;
420: PetscSF sf;
421: PetscErrorCode ierr;
424: PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"MatIS l2g disassembling options","Mat");
425: PetscOptionsEnum("-mat_is_disassemble_l2g_type","Type of local-to-global mapping to be used for disassembling","MatISDisassemblel2gType",MatISDisassemblel2gTypes,(PetscEnum)mode,(PetscEnum*)&mode,NULL);
426: PetscOptionsEnd();
427: if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) {
428: MatGetLocalToGlobalMapping(A,l2g,NULL);
429: return(0);
430: }
431: PetscObjectGetComm((PetscObject)A,&comm);
432: PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);
433: PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);
434: MatGetBlockSize(A,&bs);
435: switch (mode) {
436: case MAT_IS_DISASSEMBLE_L2G_ND:
437: MatPartitioningCreate(comm,&part);
438: MatPartitioningSetAdjacency(part,A);
439: PetscObjectSetOptionsPrefix((PetscObject)part,((PetscObject)A)->prefix);
440: MatPartitioningSetFromOptions(part);
441: MatPartitioningApplyND(part,&ndmap);
442: MatPartitioningDestroy(&part);
443: ISBuildTwoSided(ndmap,NULL,&ndsub);
444: MatMPIAIJSetUseScalableIncreaseOverlap(A,PETSC_TRUE);
445: MatIncreaseOverlap(A,1,&ndsub,1);
446: ISLocalToGlobalMappingCreateIS(ndsub,l2g);
448: /* it may happen that a separator node is not properly shared */
449: ISLocalToGlobalMappingGetNodeInfo(*l2g,&nl,&ncount,NULL);
450: PetscSFCreate(comm,&sf);
451: ISLocalToGlobalMappingGetIndices(*l2g,&garray);
452: PetscSFSetGraphLayout(sf,A->rmap,nl,NULL,PETSC_OWN_POINTER,garray);
453: ISLocalToGlobalMappingRestoreIndices(*l2g,&garray);
454: PetscCalloc1(A->rmap->n,&ndmapc);
455: PetscSFReduceBegin(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);
456: PetscSFReduceEnd(sf,MPIU_INT,ncount,ndmapc,MPIU_REPLACE);
457: ISLocalToGlobalMappingRestoreNodeInfo(*l2g,NULL,&ncount,NULL);
458: ISGetIndices(ndmap,&ndmapi);
459: for (i = 0, cnt = 0; i < A->rmap->n; i++)
460: if (ndmapi[i] < 0 && ndmapc[i] < 2)
461: cnt++;
463: MPIU_Allreduce(&cnt,&i,1,MPIU_INT,MPI_MAX,comm);
464: if (i) { /* we detected isolated separator nodes */
465: Mat A2,A3;
466: IS *workis,is2;
467: PetscScalar *vals;
468: PetscInt gcnt = i,*dnz,*onz,j,*lndmapi;
469: ISLocalToGlobalMapping ll2g;
470: PetscBool flg;
471: const PetscInt *ii,*jj;
473: /* communicate global id of separators */
474: MatPreallocateInitialize(comm,A->rmap->n,A->cmap->n,dnz,onz);
475: for (i = 0, cnt = 0; i < A->rmap->n; i++)
476: dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1;
478: PetscMalloc1(nl,&lndmapi);
479: PetscSFBcastBegin(sf,MPIU_INT,dnz,lndmapi);
481: /* compute adjacency of isolated separators node */
482: PetscMalloc1(gcnt,&workis);
483: for (i = 0, cnt = 0; i < A->rmap->n; i++) {
484: if (ndmapi[i] < 0 && ndmapc[i] < 2) {
485: ISCreateStride(comm,1,i+A->rmap->rstart,1,&workis[cnt++]);
486: }
487: }
488: for (i = cnt; i < gcnt; i++) {
489: ISCreateStride(comm,0,0,1,&workis[i]);
490: }
491: for (i = 0; i < gcnt; i++) {
492: PetscObjectSetName((PetscObject)workis[i],"ISOLATED");
493: ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");
494: }
496: /* no communications since all the ISes correspond to locally owned rows */
497: MatIncreaseOverlap(A,gcnt,workis,1);
499: /* end communicate global id of separators */
500: PetscSFBcastEnd(sf,MPIU_INT,dnz,lndmapi);
502: /* communicate new layers : create a matrix and transpose it */
503: PetscArrayzero(dnz,A->rmap->n);
504: PetscArrayzero(onz,A->rmap->n);
505: for (i = 0, j = 0; i < A->rmap->n; i++) {
506: if (ndmapi[i] < 0 && ndmapc[i] < 2) {
507: const PetscInt* idxs;
508: PetscInt s;
510: ISGetLocalSize(workis[j],&s);
511: ISGetIndices(workis[j],&idxs);
512: MatPreallocateSet(i+A->rmap->rstart,s,idxs,dnz,onz);
513: j++;
514: }
515: }
516: if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);
518: for (i = 0; i < gcnt; i++) {
519: PetscObjectSetName((PetscObject)workis[i],"EXTENDED");
520: ISViewFromOptions(workis[i],NULL,"-view_isolated_separators");
521: }
523: for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j,dnz[i]+onz[i]);
524: PetscMalloc1(j,&vals);
525: for (i = 0; i < j; i++) vals[i] = 1.0;
527: MatCreate(comm,&A2);
528: MatSetType(A2,MATMPIAIJ);
529: MatSetSizes(A2,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
530: MatMPIAIJSetPreallocation(A2,0,dnz,0,onz);
531: MatSetOption(A2,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);
532: for (i = 0, j = 0; i < A2->rmap->n; i++) {
533: PetscInt row = i+A2->rmap->rstart,s = dnz[i] + onz[i];
534: const PetscInt* idxs;
536: if (s) {
537: ISGetIndices(workis[j],&idxs);
538: MatSetValues(A2,1,&row,s,idxs,vals,INSERT_VALUES);
539: ISRestoreIndices(workis[j],&idxs);
540: j++;
541: }
542: }
543: if (j != cnt) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %D != %D",j,cnt);
544: PetscFree(vals);
545: MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY);
546: MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY);
547: MatTranspose(A2,MAT_INPLACE_MATRIX,&A2);
549: /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */
550: for (i = 0, j = 0; i < nl; i++)
551: if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i];
552: ISCreateGeneral(comm,j,lndmapi,PETSC_USE_POINTER,&is);
553: MatMPIAIJGetLocalMatCondensed(A2,MAT_INITIAL_MATRIX,&is,NULL,&A3);
554: ISDestroy(&is);
555: MatDestroy(&A2);
557: /* extend local to global map to include connected isolated separators */
558: PetscObjectQuery((PetscObject)A3,"_petsc_GetLocalMatCondensed_iscol",(PetscObject*)&is);
559: if (!is) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing column map");
560: ISLocalToGlobalMappingCreateIS(is,&ll2g);
561: MatGetRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);
562: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
563: ISCreateGeneral(PETSC_COMM_SELF,ii[i],jj,PETSC_COPY_VALUES,&is);
564: MatRestoreRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg);
565: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
566: ISLocalToGlobalMappingApplyIS(ll2g,is,&is2);
567: ISDestroy(&is);
568: ISLocalToGlobalMappingDestroy(&ll2g);
570: /* add new nodes to the local-to-global map */
571: ISLocalToGlobalMappingDestroy(l2g);
572: ISExpand(ndsub,is2,&is);
573: ISDestroy(&is2);
574: ISLocalToGlobalMappingCreateIS(is,l2g);
575: ISDestroy(&is);
577: MatDestroy(&A3);
578: PetscFree(lndmapi);
579: MatPreallocateFinalize(dnz,onz);
580: for (i = 0; i < gcnt; i++) {
581: ISDestroy(&workis[i]);
582: }
583: PetscFree(workis);
584: }
585: ISRestoreIndices(ndmap,&ndmapi);
586: PetscSFDestroy(&sf);
587: PetscFree(ndmapc);
588: ISDestroy(&ndmap);
589: ISDestroy(&ndsub);
590: ISLocalToGlobalMappingSetBlockSize(*l2g,bs);
591: ISLocalToGlobalMappingViewFromOptions(*l2g,NULL,"-matis_nd_l2g_view");
592: break;
593: case MAT_IS_DISASSEMBLE_L2G_NATURAL:
594: if (ismpiaij) {
595: MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);
596: } else if (ismpibaij) {
597: MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);
598: } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
599: if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");
600: if (A->rmap->n) {
601: PetscInt dc,oc,stc,*aux;
603: MatGetLocalSize(A,NULL,&dc);
604: MatGetLocalSize(Ao,NULL,&oc);
605: MatGetOwnershipRangeColumn(A,&stc,NULL);
606: PetscMalloc1((dc+oc)/bs,&aux);
607: for (i=0; i<dc/bs; i++) aux[i] = i+stc/bs;
608: for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
609: ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);
610: } else {
611: ISCreateBlock(comm,1,0,NULL,PETSC_OWN_POINTER,&is);
612: }
613: ISLocalToGlobalMappingCreateIS(is,l2g);
614: ISDestroy(&is);
615: break;
616: default:
617: SETERRQ1(comm,PETSC_ERR_ARG_WRONG,"Unsupported l2g disassembling type %D",mode);
618: }
619: return(0);
620: }
622: PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
623: {
624: Mat lA,Ad,Ao,B = NULL;
625: ISLocalToGlobalMapping rl2g,cl2g;
626: IS is;
627: MPI_Comm comm;
628: void *ptrs[2];
629: const char *names[2] = {"_convert_csr_aux","_convert_csr_data"};
630: const PetscInt *garray;
631: PetscScalar *dd,*od,*aa,*data;
632: const PetscInt *di,*dj,*oi,*oj;
633: const PetscInt *odi,*odj,*ooi,*ooj;
634: PetscInt *aux,*ii,*jj;
635: PetscInt bs,lc,dr,dc,oc,str,stc,nnz,i,jd,jo,cum;
636: PetscBool flg,ismpiaij,ismpibaij,was_inplace = PETSC_FALSE;
637: PetscMPIInt size;
638: PetscErrorCode ierr;
641: PetscObjectGetComm((PetscObject)A,&comm);
642: MPI_Comm_size(comm,&size);
643: if (size == 1) {
644: MatConvert_SeqXAIJ_IS(A,type,reuse,newmat);
645: return(0);
646: }
647: if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) {
648: MatMPIXAIJComputeLocalToGlobalMapping_Private(A,&rl2g);
649: MatCreate(comm,&B);
650: MatSetType(B,MATIS);
651: MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
652: MatSetLocalToGlobalMapping(B,rl2g,rl2g);
653: MatGetBlockSize(A,&bs);
654: MatSetBlockSize(B,bs);
655: ISLocalToGlobalMappingDestroy(&rl2g);
656: if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE;
657: reuse = MAT_REUSE_MATRIX;
658: }
659: if (reuse == MAT_REUSE_MATRIX) {
660: Mat *newlA, lA;
661: IS rows, cols;
662: const PetscInt *ridx, *cidx;
663: PetscInt rbs, cbs, nr, nc;
665: if (!B) B = *newmat;
666: MatGetLocalToGlobalMapping(B,&rl2g,&cl2g);
667: ISLocalToGlobalMappingGetBlockIndices(rl2g,&ridx);
668: ISLocalToGlobalMappingGetBlockIndices(cl2g,&cidx);
669: ISLocalToGlobalMappingGetSize(rl2g,&nr);
670: ISLocalToGlobalMappingGetSize(cl2g,&nc);
671: ISLocalToGlobalMappingGetBlockSize(rl2g,&rbs);
672: ISLocalToGlobalMappingGetBlockSize(cl2g,&cbs);
673: ISCreateBlock(comm,rbs,nr/rbs,ridx,PETSC_USE_POINTER,&rows);
674: if (rl2g != cl2g) {
675: ISCreateBlock(comm,cbs,nc/cbs,cidx,PETSC_USE_POINTER,&cols);
676: } else {
677: PetscObjectReference((PetscObject)rows);
678: cols = rows;
679: }
680: MatISGetLocalMat(B,&lA);
681: MatCreateSubMatrices(A,1,&rows,&cols,MAT_INITIAL_MATRIX,&newlA);
682: MatConvert(newlA[0],MATSEQAIJ,MAT_INPLACE_MATRIX,&newlA[0]);
683: ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&ridx);
684: ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&cidx);
685: ISDestroy(&rows);
686: ISDestroy(&cols);
687: if (!lA->preallocated) { /* first time */
688: MatDuplicate(newlA[0],MAT_COPY_VALUES,&lA);
689: MatISSetLocalMat(B,lA);
690: PetscObjectDereference((PetscObject)lA);
691: }
692: MatCopy(newlA[0],lA,SAME_NONZERO_PATTERN);
693: MatDestroySubMatrices(1,&newlA);
694: MatISScaleDisassembling_Private(B);
695: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
696: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
697: if (was_inplace) { MatHeaderReplace(A,&B); }
698: else *newmat = B;
699: return(0);
700: }
701: /* rectangular case, just compress out the column space */
702: PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij);
703: PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij);
704: if (ismpiaij) {
705: bs = 1;
706: MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray);
707: } else if (ismpibaij) {
708: MatGetBlockSize(A,&bs);
709: MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray);
710: MatConvert(Ad,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ad);
711: MatConvert(Ao,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ao);
712: } else SETERRQ1(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name);
713: MatSeqAIJGetArray(Ad,&dd);
714: MatSeqAIJGetArray(Ao,&od);
715: if (!garray) SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present");
717: /* access relevant information from MPIAIJ */
718: MatGetOwnershipRange(A,&str,NULL);
719: MatGetOwnershipRangeColumn(A,&stc,NULL);
720: MatGetLocalSize(A,&dr,&dc);
721: MatGetLocalSize(Ao,NULL,&oc);
722: MatGetRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&di,&dj,&flg);
723: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
724: MatGetRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&oi,&oj,&flg);
725: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure");
726: nnz = di[dr] + oi[dr];
727: /* store original pointers to be restored later */
728: odi = di; odj = dj; ooi = oi; ooj = oj;
730: /* generate l2g maps for rows and cols */
731: ISCreateStride(comm,dr/bs,str/bs,1,&is);
732: if (bs > 1) {
733: IS is2;
735: ISGetLocalSize(is,&i);
736: ISGetIndices(is,(const PetscInt**)&aux);
737: ISCreateBlock(comm,bs,i,aux,PETSC_COPY_VALUES,&is2);
738: ISRestoreIndices(is,(const PetscInt**)&aux);
739: ISDestroy(&is);
740: is = is2;
741: }
742: ISLocalToGlobalMappingCreateIS(is,&rl2g);
743: ISDestroy(&is);
744: if (dr) {
745: PetscMalloc1((dc+oc)/bs,&aux);
746: for (i=0; i<dc/bs; i++) aux[i] = i+stc/bs;
747: for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i];
748: ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is);
749: lc = dc+oc;
750: } else {
751: ISCreateBlock(comm,bs,0,NULL,PETSC_OWN_POINTER,&is);
752: lc = 0;
753: }
754: ISLocalToGlobalMappingCreateIS(is,&cl2g);
755: ISDestroy(&is);
757: /* create MATIS object */
758: MatCreate(comm,&B);
759: MatSetSizes(B,dr,dc,PETSC_DECIDE,PETSC_DECIDE);
760: MatSetType(B,MATIS);
761: MatSetBlockSize(B,bs);
762: MatSetLocalToGlobalMapping(B,rl2g,cl2g);
763: ISLocalToGlobalMappingDestroy(&rl2g);
764: ISLocalToGlobalMappingDestroy(&cl2g);
766: /* merge local matrices */
767: PetscMalloc1(nnz+dr+1,&aux);
768: PetscMalloc1(nnz,&data);
769: ii = aux;
770: jj = aux+dr+1;
771: aa = data;
772: *ii = *(di++) + *(oi++);
773: for (jd=0,jo=0,cum=0;*ii<nnz;cum++)
774: {
775: for (;jd<*di;jd++) { *jj++ = *dj++; *aa++ = *dd++; }
776: for (;jo<*oi;jo++) { *jj++ = *oj++ + dc; *aa++ = *od++; }
777: *(++ii) = *(di++) + *(oi++);
778: }
779: for (;cum<dr;cum++) *(++ii) = nnz;
781: MatRestoreRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&odi,&odj,&flg);
782: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
783: MatRestoreRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&ooi,&ooj,&flg);
784: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure");
785: MatSeqAIJRestoreArray(Ad,&dd);
786: MatSeqAIJRestoreArray(Ao,&od);
788: ii = aux;
789: jj = aux+dr+1;
790: aa = data;
791: MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,lc,ii,jj,aa,&lA);
793: /* create containers to destroy the data */
794: ptrs[0] = aux;
795: ptrs[1] = data;
796: for (i=0; i<2; i++) {
797: PetscContainer c;
799: PetscContainerCreate(PETSC_COMM_SELF,&c);
800: PetscContainerSetPointer(c,ptrs[i]);
801: PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault);
802: PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);
803: PetscContainerDestroy(&c);
804: }
805: if (ismpibaij) { /* destroy converted local matrices */
806: MatDestroy(&Ad);
807: MatDestroy(&Ao);
808: }
810: /* finalize matrix */
811: MatISSetLocalMat(B,lA);
812: MatDestroy(&lA);
813: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
814: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
815: if (reuse == MAT_INPLACE_MATRIX) {
816: MatHeaderReplace(A,&B);
817: } else *newmat = B;
818: return(0);
819: }
821: PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat)
822: {
823: Mat **nest,*snest,**rnest,lA,B;
824: IS *iscol,*isrow,*islrow,*islcol;
825: ISLocalToGlobalMapping rl2g,cl2g;
826: MPI_Comm comm;
827: PetscInt *lr,*lc,*l2gidxs;
828: PetscInt i,j,nr,nc,rbs,cbs;
829: PetscBool convert,lreuse,*istrans;
830: PetscErrorCode ierr;
833: MatNestGetSubMats(A,&nr,&nc,&nest);
834: lreuse = PETSC_FALSE;
835: rnest = NULL;
836: if (reuse == MAT_REUSE_MATRIX) {
837: PetscBool ismatis,isnest;
839: PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);
840: if (!ismatis) SETERRQ1(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_USER,"Cannot reuse matrix of type %s",((PetscObject)(*newmat))->type_name);
841: MatISGetLocalMat(*newmat,&lA);
842: PetscObjectTypeCompare((PetscObject)lA,MATNEST,&isnest);
843: if (isnest) {
844: MatNestGetSubMats(lA,&i,&j,&rnest);
845: lreuse = (PetscBool)(i == nr && j == nc);
846: if (!lreuse) rnest = NULL;
847: }
848: }
849: PetscObjectGetComm((PetscObject)A,&comm);
850: PetscCalloc2(nr,&lr,nc,&lc);
851: PetscCalloc6(nr,&isrow,nc,&iscol,nr,&islrow,nc,&islcol,nr*nc,&snest,nr*nc,&istrans);
852: MatNestGetISs(A,isrow,iscol);
853: for (i=0;i<nr;i++) {
854: for (j=0;j<nc;j++) {
855: PetscBool ismatis;
856: PetscInt l1,l2,lb1,lb2,ij=i*nc+j;
858: /* Null matrix pointers are allowed in MATNEST */
859: if (!nest[i][j]) continue;
861: /* Nested matrices should be of type MATIS */
862: PetscObjectTypeCompare((PetscObject)nest[i][j],MATTRANSPOSEMAT,&istrans[ij]);
863: if (istrans[ij]) {
864: Mat T,lT;
865: MatTransposeGetMat(nest[i][j],&T);
866: PetscObjectTypeCompare((PetscObject)T,MATIS,&ismatis);
867: if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) (transposed) is not of type MATIS",i,j);
868: MatISGetLocalMat(T,&lT);
869: MatCreateTranspose(lT,&snest[ij]);
870: } else {
871: PetscObjectTypeCompare((PetscObject)nest[i][j],MATIS,&ismatis);
872: if (!ismatis) SETERRQ2(comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) is not of type MATIS",i,j);
873: MatISGetLocalMat(nest[i][j],&snest[ij]);
874: }
876: /* Check compatibility of local sizes */
877: MatGetSize(snest[ij],&l1,&l2);
878: MatGetBlockSizes(snest[ij],&lb1,&lb2);
879: if (!l1 || !l2) continue;
880: if (lr[i] && l1 != lr[i]) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid local size %D != %D",i,j,lr[i],l1);
881: if (lc[j] && l2 != lc[j]) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid local size %D != %D",i,j,lc[j],l2);
882: lr[i] = l1;
883: lc[j] = l2;
885: /* check compatibilty for local matrix reusage */
886: if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE;
887: }
888: }
890: #if defined (PETSC_USE_DEBUG)
891: /* Check compatibility of l2g maps for rows */
892: for (i=0;i<nr;i++) {
893: rl2g = NULL;
894: for (j=0;j<nc;j++) {
895: PetscInt n1,n2;
897: if (!nest[i][j]) continue;
898: if (istrans[i*nc+j]) {
899: Mat T;
901: MatTransposeGetMat(nest[i][j],&T);
902: MatGetLocalToGlobalMapping(T,NULL,&cl2g);
903: } else {
904: MatGetLocalToGlobalMapping(nest[i][j],&cl2g,NULL);
905: }
906: ISLocalToGlobalMappingGetSize(cl2g,&n1);
907: if (!n1) continue;
908: if (!rl2g) {
909: rl2g = cl2g;
910: } else {
911: const PetscInt *idxs1,*idxs2;
912: PetscBool same;
914: ISLocalToGlobalMappingGetSize(rl2g,&n2);
915: if (n1 != n2) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid row l2gmap size %D != %D",i,j,n1,n2);
916: ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);
917: ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);
918: PetscArraycmp(idxs1,idxs2,n1,&same);
919: ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);
920: ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);
921: if (!same) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid row l2gmap",i,j);
922: }
923: }
924: }
925: /* Check compatibility of l2g maps for columns */
926: for (i=0;i<nc;i++) {
927: rl2g = NULL;
928: for (j=0;j<nr;j++) {
929: PetscInt n1,n2;
931: if (!nest[j][i]) continue;
932: if (istrans[j*nc+i]) {
933: Mat T;
935: MatTransposeGetMat(nest[j][i],&T);
936: MatGetLocalToGlobalMapping(T,&cl2g,NULL);
937: } else {
938: MatGetLocalToGlobalMapping(nest[j][i],NULL,&cl2g);
939: }
940: ISLocalToGlobalMappingGetSize(cl2g,&n1);
941: if (!n1) continue;
942: if (!rl2g) {
943: rl2g = cl2g;
944: } else {
945: const PetscInt *idxs1,*idxs2;
946: PetscBool same;
948: ISLocalToGlobalMappingGetSize(rl2g,&n2);
949: if (n1 != n2) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid column l2gmap size %D != %D",j,i,n1,n2);
950: ISLocalToGlobalMappingGetIndices(cl2g,&idxs1);
951: ISLocalToGlobalMappingGetIndices(rl2g,&idxs2);
952: PetscArraycmp(idxs1,idxs2,n1,&same);
953: ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1);
954: ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2);
955: if (!same) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%D,%D) has invalid column l2gmap",j,i);
956: }
957: }
958: }
959: #endif
961: B = NULL;
962: if (reuse != MAT_REUSE_MATRIX) {
963: PetscInt stl;
965: /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */
966: for (i=0,stl=0;i<nr;i++) stl += lr[i];
967: PetscMalloc1(stl,&l2gidxs);
968: for (i=0,stl=0;i<nr;i++) {
969: Mat usedmat;
970: Mat_IS *matis;
971: const PetscInt *idxs;
973: /* local IS for local NEST */
974: ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);
976: /* l2gmap */
977: j = 0;
978: usedmat = nest[i][j];
979: while (!usedmat && j < nc-1) usedmat = nest[i][++j];
980: if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid row mat");
982: if (istrans[i*nc+j]) {
983: Mat T;
984: MatTransposeGetMat(usedmat,&T);
985: usedmat = T;
986: }
987: matis = (Mat_IS*)(usedmat->data);
988: ISGetIndices(isrow[i],&idxs);
989: if (istrans[i*nc+j]) {
990: PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
991: PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
992: } else {
993: PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
994: PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
995: }
996: ISRestoreIndices(isrow[i],&idxs);
997: stl += lr[i];
998: }
999: ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&rl2g);
1001: /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */
1002: for (i=0,stl=0;i<nc;i++) stl += lc[i];
1003: PetscMalloc1(stl,&l2gidxs);
1004: for (i=0,stl=0;i<nc;i++) {
1005: Mat usedmat;
1006: Mat_IS *matis;
1007: const PetscInt *idxs;
1009: /* local IS for local NEST */
1010: ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);
1012: /* l2gmap */
1013: j = 0;
1014: usedmat = nest[j][i];
1015: while (!usedmat && j < nr-1) usedmat = nest[++j][i];
1016: if (!usedmat) SETERRQ(comm,PETSC_ERR_SUP,"Cannot find valid column mat");
1017: if (istrans[j*nc+i]) {
1018: Mat T;
1019: MatTransposeGetMat(usedmat,&T);
1020: usedmat = T;
1021: }
1022: matis = (Mat_IS*)(usedmat->data);
1023: ISGetIndices(iscol[i],&idxs);
1024: if (istrans[j*nc+i]) {
1025: PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
1026: PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl);
1027: } else {
1028: PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
1029: PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl);
1030: }
1031: ISRestoreIndices(iscol[i],&idxs);
1032: stl += lc[i];
1033: }
1034: ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&cl2g);
1036: /* Create MATIS */
1037: MatCreate(comm,&B);
1038: MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N);
1039: MatGetBlockSizes(A,&rbs,&cbs);
1040: MatSetBlockSizes(B,rbs,cbs);
1041: MatSetType(B,MATIS);
1042: MatISSetLocalMatType(B,MATNEST);
1043: { /* hack : avoid setup of scatters */
1044: Mat_IS *matis = (Mat_IS*)(B->data);
1045: matis->islocalref = PETSC_TRUE;
1046: }
1047: MatSetLocalToGlobalMapping(B,rl2g,cl2g);
1048: ISLocalToGlobalMappingDestroy(&rl2g);
1049: ISLocalToGlobalMappingDestroy(&cl2g);
1050: MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);
1051: MatNestSetVecType(lA,VECNEST);
1052: for (i=0;i<nr*nc;i++) {
1053: if (istrans[i]) {
1054: MatDestroy(&snest[i]);
1055: }
1056: }
1057: MatISSetLocalMat(B,lA);
1058: MatDestroy(&lA);
1059: { /* hack : setup of scatters done here */
1060: Mat_IS *matis = (Mat_IS*)(B->data);
1062: matis->islocalref = PETSC_FALSE;
1063: MatISSetUpScatters_Private(B);
1064: }
1065: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
1066: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
1067: if (reuse == MAT_INPLACE_MATRIX) {
1068: MatHeaderReplace(A,&B);
1069: } else {
1070: *newmat = B;
1071: }
1072: } else {
1073: if (lreuse) {
1074: MatISGetLocalMat(*newmat,&lA);
1075: for (i=0;i<nr;i++) {
1076: for (j=0;j<nc;j++) {
1077: if (snest[i*nc+j]) {
1078: MatNestSetSubMat(lA,i,j,snest[i*nc+j]);
1079: if (istrans[i*nc+j]) {
1080: MatDestroy(&snest[i*nc+j]);
1081: }
1082: }
1083: }
1084: }
1085: } else {
1086: PetscInt stl;
1087: for (i=0,stl=0;i<nr;i++) {
1088: ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i]);
1089: stl += lr[i];
1090: }
1091: for (i=0,stl=0;i<nc;i++) {
1092: ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i]);
1093: stl += lc[i];
1094: }
1095: MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA);
1096: for (i=0;i<nr*nc;i++) {
1097: if (istrans[i]) {
1098: MatDestroy(&snest[i]);
1099: }
1100: }
1101: MatISSetLocalMat(*newmat,lA);
1102: MatDestroy(&lA);
1103: }
1104: MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);
1105: MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);
1106: }
1108: /* Create local matrix in MATNEST format */
1109: convert = PETSC_FALSE;
1110: PetscOptionsGetBool(NULL,((PetscObject)A)->prefix,"-matis_convert_local_nest",&convert,NULL);
1111: if (convert) {
1112: Mat M;
1113: MatISLocalFields lf;
1114: PetscContainer c;
1116: MatISGetLocalMat(*newmat,&lA);
1117: MatConvert(lA,MATAIJ,MAT_INITIAL_MATRIX,&M);
1118: MatISSetLocalMat(*newmat,M);
1119: MatDestroy(&M);
1121: /* attach local fields to the matrix */
1122: PetscNew(&lf);
1123: PetscMalloc2(nr,&lf->rf,nc,&lf->cf);
1124: for (i=0;i<nr;i++) {
1125: PetscInt n,st;
1127: ISGetLocalSize(islrow[i],&n);
1128: ISStrideGetInfo(islrow[i],&st,NULL);
1129: ISCreateStride(comm,n,st,1,&lf->rf[i]);
1130: }
1131: for (i=0;i<nc;i++) {
1132: PetscInt n,st;
1134: ISGetLocalSize(islcol[i],&n);
1135: ISStrideGetInfo(islcol[i],&st,NULL);
1136: ISCreateStride(comm,n,st,1,&lf->cf[i]);
1137: }
1138: lf->nr = nr;
1139: lf->nc = nc;
1140: PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)),&c);
1141: PetscContainerSetPointer(c,lf);
1142: PetscContainerSetUserDestroy(c,MatISContainerDestroyFields_Private);
1143: PetscObjectCompose((PetscObject)(*newmat),"_convert_nest_lfields",(PetscObject)c);
1144: PetscContainerDestroy(&c);
1145: }
1147: /* Free workspace */
1148: for (i=0;i<nr;i++) {
1149: ISDestroy(&islrow[i]);
1150: }
1151: for (i=0;i<nc;i++) {
1152: ISDestroy(&islcol[i]);
1153: }
1154: PetscFree6(isrow,iscol,islrow,islcol,snest,istrans);
1155: PetscFree2(lr,lc);
1156: return(0);
1157: }
1159: static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r)
1160: {
1161: Mat_IS *matis = (Mat_IS*)A->data;
1162: Vec ll,rr;
1163: const PetscScalar *Y,*X;
1164: PetscScalar *x,*y;
1165: PetscErrorCode ierr;
1168: if (l) {
1169: ll = matis->y;
1170: VecGetArrayRead(l,&Y);
1171: VecGetArray(ll,&y);
1172: PetscSFBcastBegin(matis->sf,MPIU_SCALAR,Y,y);
1173: } else {
1174: ll = NULL;
1175: }
1176: if (r) {
1177: rr = matis->x;
1178: VecGetArrayRead(r,&X);
1179: VecGetArray(rr,&x);
1180: PetscSFBcastBegin(matis->csf,MPIU_SCALAR,X,x);
1181: } else {
1182: rr = NULL;
1183: }
1184: if (ll) {
1185: PetscSFBcastEnd(matis->sf,MPIU_SCALAR,Y,y);
1186: VecRestoreArrayRead(l,&Y);
1187: VecRestoreArray(ll,&y);
1188: }
1189: if (rr) {
1190: PetscSFBcastEnd(matis->csf,MPIU_SCALAR,X,x);
1191: VecRestoreArrayRead(r,&X);
1192: VecRestoreArray(rr,&x);
1193: }
1194: MatDiagonalScale(matis->A,ll,rr);
1195: return(0);
1196: }
1198: static PetscErrorCode MatGetInfo_IS(Mat A,MatInfoType flag,MatInfo *ginfo)
1199: {
1200: Mat_IS *matis = (Mat_IS*)A->data;
1201: MatInfo info;
1202: PetscLogDouble isend[6],irecv[6];
1203: PetscInt bs;
1207: MatGetBlockSize(A,&bs);
1208: if (matis->A->ops->getinfo) {
1209: MatGetInfo(matis->A,MAT_LOCAL,&info);
1210: isend[0] = info.nz_used;
1211: isend[1] = info.nz_allocated;
1212: isend[2] = info.nz_unneeded;
1213: isend[3] = info.memory;
1214: isend[4] = info.mallocs;
1215: } else {
1216: isend[0] = 0.;
1217: isend[1] = 0.;
1218: isend[2] = 0.;
1219: isend[3] = 0.;
1220: isend[4] = 0.;
1221: }
1222: isend[5] = matis->A->num_ass;
1223: if (flag == MAT_LOCAL) {
1224: ginfo->nz_used = isend[0];
1225: ginfo->nz_allocated = isend[1];
1226: ginfo->nz_unneeded = isend[2];
1227: ginfo->memory = isend[3];
1228: ginfo->mallocs = isend[4];
1229: ginfo->assemblies = isend[5];
1230: } else if (flag == MAT_GLOBAL_MAX) {
1231: MPIU_Allreduce(isend,irecv,6,MPIU_PETSCLOGDOUBLE,MPI_MAX,PetscObjectComm((PetscObject)A));
1233: ginfo->nz_used = irecv[0];
1234: ginfo->nz_allocated = irecv[1];
1235: ginfo->nz_unneeded = irecv[2];
1236: ginfo->memory = irecv[3];
1237: ginfo->mallocs = irecv[4];
1238: ginfo->assemblies = irecv[5];
1239: } else if (flag == MAT_GLOBAL_SUM) {
1240: MPIU_Allreduce(isend,irecv,5,MPIU_PETSCLOGDOUBLE,MPI_SUM,PetscObjectComm((PetscObject)A));
1242: ginfo->nz_used = irecv[0];
1243: ginfo->nz_allocated = irecv[1];
1244: ginfo->nz_unneeded = irecv[2];
1245: ginfo->memory = irecv[3];
1246: ginfo->mallocs = irecv[4];
1247: ginfo->assemblies = A->num_ass;
1248: }
1249: ginfo->block_size = bs;
1250: ginfo->fill_ratio_given = 0;
1251: ginfo->fill_ratio_needed = 0;
1252: ginfo->factor_mallocs = 0;
1253: return(0);
1254: }
1256: PetscErrorCode MatTranspose_IS(Mat A,MatReuse reuse,Mat *B)
1257: {
1258: Mat C,lC,lA;
1259: PetscErrorCode ierr;
1262: if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1263: ISLocalToGlobalMapping rl2g,cl2g;
1264: MatCreate(PetscObjectComm((PetscObject)A),&C);
1265: MatSetSizes(C,A->cmap->n,A->rmap->n,A->cmap->N,A->rmap->N);
1266: MatSetBlockSizes(C,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs));
1267: MatSetType(C,MATIS);
1268: MatGetLocalToGlobalMapping(A,&rl2g,&cl2g);
1269: MatSetLocalToGlobalMapping(C,cl2g,rl2g);
1270: } else {
1271: C = *B;
1272: }
1274: /* perform local transposition */
1275: MatISGetLocalMat(A,&lA);
1276: MatTranspose(lA,MAT_INITIAL_MATRIX,&lC);
1277: MatISSetLocalMat(C,lC);
1278: MatDestroy(&lC);
1280: if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1281: *B = C;
1282: } else {
1283: MatHeaderMerge(A,&C);
1284: }
1285: MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);
1286: MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);
1287: return(0);
1288: }
1290: PetscErrorCode MatDiagonalSet_IS(Mat A,Vec D,InsertMode insmode)
1291: {
1292: Mat_IS *is = (Mat_IS*)A->data;
1296: if (D) { /* MatShift_IS pass D = NULL */
1297: VecScatterBegin(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);
1298: VecScatterEnd(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD);
1299: }
1300: VecPointwiseDivide(is->y,is->y,is->counter);
1301: MatDiagonalSet(is->A,is->y,insmode);
1302: return(0);
1303: }
1305: PetscErrorCode MatShift_IS(Mat A,PetscScalar a)
1306: {
1307: Mat_IS *is = (Mat_IS*)A->data;
1311: VecSet(is->y,a);
1312: MatDiagonalSet_IS(A,NULL,ADD_VALUES);
1313: return(0);
1314: }
1316: static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1317: {
1319: PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1322: #if defined(PETSC_USE_DEBUG)
1323: if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
1324: #endif
1325: ISLocalToGlobalMappingApply(A->rmap->mapping,m,rows,rows_l);
1326: ISLocalToGlobalMappingApply(A->cmap->mapping,n,cols,cols_l);
1327: MatSetValuesLocal_IS(A,m,rows_l,n,cols_l,values,addv);
1328: return(0);
1329: }
1331: static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
1332: {
1334: PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
1337: #if defined(PETSC_USE_DEBUG)
1338: if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column block indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
1339: #endif
1340: ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,m,rows,rows_l);
1341: ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,n,cols,cols_l);
1342: MatSetValuesBlockedLocal_IS(A,m,rows_l,n,cols_l,values,addv);
1343: return(0);
1344: }
1346: static PetscErrorCode MatCreateSubMatrix_IS(Mat mat,IS irow,IS icol,MatReuse scall,Mat *newmat)
1347: {
1348: Mat locmat,newlocmat;
1349: Mat_IS *newmatis;
1350: #if defined(PETSC_USE_DEBUG)
1351: Vec rtest,ltest;
1352: const PetscScalar *array;
1353: #endif
1354: const PetscInt *idxs;
1355: PetscInt i,m,n;
1356: PetscErrorCode ierr;
1359: if (scall == MAT_REUSE_MATRIX) {
1360: PetscBool ismatis;
1362: PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis);
1363: if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Not of MATIS type");
1364: newmatis = (Mat_IS*)(*newmat)->data;
1365: if (!newmatis->getsub_ris) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local row IS");
1366: if (!newmatis->getsub_cis) SETERRQ(PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local col IS");
1367: }
1368: /* irow and icol may not have duplicate entries */
1369: #if defined(PETSC_USE_DEBUG)
1370: MatCreateVecs(mat,<est,&rtest);
1371: ISGetLocalSize(irow,&n);
1372: ISGetIndices(irow,&idxs);
1373: for (i=0;i<n;i++) {
1374: VecSetValue(rtest,idxs[i],1.0,ADD_VALUES);
1375: }
1376: VecAssemblyBegin(rtest);
1377: VecAssemblyEnd(rtest);
1378: VecGetLocalSize(rtest,&n);
1379: VecGetOwnershipRange(rtest,&m,NULL);
1380: VecGetArrayRead(rtest,&array);
1381: for (i=0;i<n;i++) if (array[i] != 0. && array[i] != 1.) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %D counted %D times! Irow may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i]));
1382: VecRestoreArrayRead(rtest,&array);
1383: ISRestoreIndices(irow,&idxs);
1384: ISGetLocalSize(icol,&n);
1385: ISGetIndices(icol,&idxs);
1386: for (i=0;i<n;i++) {
1387: VecSetValue(ltest,idxs[i],1.0,ADD_VALUES);
1388: }
1389: VecAssemblyBegin(ltest);
1390: VecAssemblyEnd(ltest);
1391: VecGetLocalSize(ltest,&n);
1392: VecGetOwnershipRange(ltest,&m,NULL);
1393: VecGetArrayRead(ltest,&array);
1394: for (i=0;i<n;i++) if (array[i] != 0. && array[i] != 1.) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %D counted %D times! Icol may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i]));
1395: VecRestoreArrayRead(ltest,&array);
1396: ISRestoreIndices(icol,&idxs);
1397: VecDestroy(&rtest);
1398: VecDestroy(<est);
1399: #endif
1400: if (scall == MAT_INITIAL_MATRIX) {
1401: Mat_IS *matis = (Mat_IS*)mat->data;
1402: ISLocalToGlobalMapping rl2g;
1403: IS is;
1404: PetscInt *lidxs,*lgidxs,*newgidxs;
1405: PetscInt ll,newloc,irbs,icbs,arbs,acbs,rbs,cbs;
1406: PetscBool cong;
1407: MPI_Comm comm;
1409: PetscObjectGetComm((PetscObject)mat,&comm);
1410: MatGetBlockSizes(mat,&arbs,&acbs);
1411: ISGetBlockSize(irow,&irbs);
1412: ISGetBlockSize(icol,&icbs);
1413: rbs = arbs == irbs ? irbs : 1;
1414: cbs = acbs == icbs ? icbs : 1;
1415: ISGetLocalSize(irow,&m);
1416: ISGetLocalSize(icol,&n);
1417: MatCreate(comm,newmat);
1418: MatSetType(*newmat,MATIS);
1419: MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE);
1420: MatSetBlockSizes(*newmat,rbs,cbs);
1421: /* communicate irow to their owners in the layout */
1422: ISGetIndices(irow,&idxs);
1423: PetscLayoutMapLocal(mat->rmap,m,idxs,&ll,&lidxs,&lgidxs);
1424: ISRestoreIndices(irow,&idxs);
1425: PetscArrayzero(matis->sf_rootdata,matis->sf->nroots);
1426: for (i=0;i<ll;i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i]+1;
1427: PetscFree(lidxs);
1428: PetscFree(lgidxs);
1429: PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1430: PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1431: for (i=0,newloc=0;i<matis->sf->nleaves;i++) if (matis->sf_leafdata[i]) newloc++;
1432: PetscMalloc1(newloc,&newgidxs);
1433: PetscMalloc1(newloc,&lidxs);
1434: for (i=0,newloc=0;i<matis->sf->nleaves;i++)
1435: if (matis->sf_leafdata[i]) {
1436: lidxs[newloc] = i;
1437: newgidxs[newloc++] = matis->sf_leafdata[i]-1;
1438: }
1439: ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);
1440: ISLocalToGlobalMappingCreateIS(is,&rl2g);
1441: ISLocalToGlobalMappingSetBlockSize(rl2g,rbs);
1442: ISDestroy(&is);
1443: /* local is to extract local submatrix */
1444: newmatis = (Mat_IS*)(*newmat)->data;
1445: ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_ris);
1446: MatHasCongruentLayouts(mat,&cong);
1447: if (cong && irow == icol && matis->csf == matis->sf) {
1448: MatSetLocalToGlobalMapping(*newmat,rl2g,rl2g);
1449: PetscObjectReference((PetscObject)newmatis->getsub_ris);
1450: newmatis->getsub_cis = newmatis->getsub_ris;
1451: } else {
1452: ISLocalToGlobalMapping cl2g;
1454: /* communicate icol to their owners in the layout */
1455: ISGetIndices(icol,&idxs);
1456: PetscLayoutMapLocal(mat->cmap,n,idxs,&ll,&lidxs,&lgidxs);
1457: ISRestoreIndices(icol,&idxs);
1458: PetscArrayzero(matis->csf_rootdata,matis->csf->nroots);
1459: for (i=0;i<ll;i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i]+1;
1460: PetscFree(lidxs);
1461: PetscFree(lgidxs);
1462: PetscSFBcastBegin(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);
1463: PetscSFBcastEnd(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata);
1464: for (i=0,newloc=0;i<matis->csf->nleaves;i++) if (matis->csf_leafdata[i]) newloc++;
1465: PetscMalloc1(newloc,&newgidxs);
1466: PetscMalloc1(newloc,&lidxs);
1467: for (i=0,newloc=0;i<matis->csf->nleaves;i++)
1468: if (matis->csf_leafdata[i]) {
1469: lidxs[newloc] = i;
1470: newgidxs[newloc++] = matis->csf_leafdata[i]-1;
1471: }
1472: ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is);
1473: ISLocalToGlobalMappingCreateIS(is,&cl2g);
1474: ISLocalToGlobalMappingSetBlockSize(cl2g,cbs);
1475: ISDestroy(&is);
1476: /* local is to extract local submatrix */
1477: ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_cis);
1478: MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g);
1479: ISLocalToGlobalMappingDestroy(&cl2g);
1480: }
1481: ISLocalToGlobalMappingDestroy(&rl2g);
1482: } else {
1483: MatISGetLocalMat(*newmat,&newlocmat);
1484: }
1485: MatISGetLocalMat(mat,&locmat);
1486: newmatis = (Mat_IS*)(*newmat)->data;
1487: MatCreateSubMatrix(locmat,newmatis->getsub_ris,newmatis->getsub_cis,scall,&newlocmat);
1488: if (scall == MAT_INITIAL_MATRIX) {
1489: MatISSetLocalMat(*newmat,newlocmat);
1490: MatDestroy(&newlocmat);
1491: }
1492: MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);
1493: MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);
1494: return(0);
1495: }
1497: static PetscErrorCode MatCopy_IS(Mat A,Mat B,MatStructure str)
1498: {
1499: Mat_IS *a = (Mat_IS*)A->data,*b;
1500: PetscBool ismatis;
1504: PetscObjectTypeCompare((PetscObject)B,MATIS,&ismatis);
1505: if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Need to be implemented");
1506: b = (Mat_IS*)B->data;
1507: MatCopy(a->A,b->A,str);
1508: PetscObjectStateIncrease((PetscObject)B);
1509: return(0);
1510: }
1512: static PetscErrorCode MatMissingDiagonal_IS(Mat A,PetscBool *missing,PetscInt *d)
1513: {
1514: Vec v;
1515: const PetscScalar *array;
1516: PetscInt i,n;
1517: PetscErrorCode ierr;
1520: *missing = PETSC_FALSE;
1521: MatCreateVecs(A,NULL,&v);
1522: MatGetDiagonal(A,v);
1523: VecGetLocalSize(v,&n);
1524: VecGetArrayRead(v,&array);
1525: for (i=0;i<n;i++) if (array[i] == 0.) break;
1526: VecRestoreArrayRead(v,&array);
1527: VecDestroy(&v);
1528: if (i != n) *missing = PETSC_TRUE;
1529: if (d) {
1530: *d = -1;
1531: if (*missing) {
1532: PetscInt rstart;
1533: MatGetOwnershipRange(A,&rstart,NULL);
1534: *d = i+rstart;
1535: }
1536: }
1537: return(0);
1538: }
1540: static PetscErrorCode MatISSetUpSF_IS(Mat B)
1541: {
1542: Mat_IS *matis = (Mat_IS*)(B->data);
1543: const PetscInt *gidxs;
1544: PetscInt nleaves;
1548: if (matis->sf) return(0);
1549: PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf);
1550: ISLocalToGlobalMappingGetIndices(B->rmap->mapping,&gidxs);
1551: ISLocalToGlobalMappingGetSize(B->rmap->mapping,&nleaves);
1552: PetscSFSetGraphLayout(matis->sf,B->rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);
1553: ISLocalToGlobalMappingRestoreIndices(B->rmap->mapping,&gidxs);
1554: PetscMalloc2(matis->sf->nroots,&matis->sf_rootdata,matis->sf->nleaves,&matis->sf_leafdata);
1555: if (B->rmap->mapping != B->cmap->mapping) { /* setup SF for columns */
1556: ISLocalToGlobalMappingGetSize(B->cmap->mapping,&nleaves);
1557: PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->csf);
1558: ISLocalToGlobalMappingGetIndices(B->cmap->mapping,&gidxs);
1559: PetscSFSetGraphLayout(matis->csf,B->cmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);
1560: ISLocalToGlobalMappingRestoreIndices(B->cmap->mapping,&gidxs);
1561: PetscMalloc2(matis->csf->nroots,&matis->csf_rootdata,matis->csf->nleaves,&matis->csf_leafdata);
1562: } else {
1563: matis->csf = matis->sf;
1564: matis->csf_leafdata = matis->sf_leafdata;
1565: matis->csf_rootdata = matis->sf_rootdata;
1566: }
1567: return(0);
1568: }
1570: /*@
1571: MatISStoreL2L - Store local-to-local operators during the Galerkin process of MatPtAP.
1573: Collective
1575: Input Parameters:
1576: + A - the matrix
1577: - store - the boolean flag
1579: Level: advanced
1581: Notes:
1583: .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatPtAP()
1584: @*/
1585: PetscErrorCode MatISStoreL2L(Mat A, PetscBool store)
1586: {
1593: PetscTryMethod(A,"MatISStoreL2L_C",(Mat,PetscBool),(A,store));
1594: return(0);
1595: }
1597: static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store)
1598: {
1599: Mat_IS *matis = (Mat_IS*)(A->data);
1603: matis->storel2l = store;
1604: if (!store) {
1605: PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",NULL);
1606: }
1607: return(0);
1608: }
1610: /*@
1611: MatISFixLocalEmpty - Compress out zero local rows from the local matrices
1613: Collective
1615: Input Parameters:
1616: + A - the matrix
1617: - fix - the boolean flag
1619: Level: advanced
1621: Notes: When fix is true, new local matrices and l2g maps are generated during the final assembly process.
1623: .seealso: MatCreate(), MatCreateIS(), MatISSetPreallocation(), MatAssemblyEnd(), MAT_FINAL_ASSEMBLY
1624: @*/
1625: PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix)
1626: {
1633: PetscTryMethod(A,"MatISFixLocalEmpty_C",(Mat,PetscBool),(A,fix));
1634: return(0);
1635: }
1637: static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix)
1638: {
1639: Mat_IS *matis = (Mat_IS*)(A->data);
1642: matis->locempty = fix;
1643: return(0);
1644: }
1646: /*@
1647: MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix.
1649: Collective
1651: Input Parameters:
1652: + B - the matrix
1653: . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix
1654: (same value is used for all local rows)
1655: . d_nnz - array containing the number of nonzeros in the various rows of the
1656: DIAGONAL portion of the local submatrix (possibly different for each row)
1657: or NULL, if d_nz is used to specify the nonzero structure.
1658: The size of this array is equal to the number of local rows, i.e 'm'.
1659: For matrices that will be factored, you must leave room for (and set)
1660: the diagonal entry even if it is zero.
1661: . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local
1662: submatrix (same value is used for all local rows).
1663: - o_nnz - array containing the number of nonzeros in the various rows of the
1664: OFF-DIAGONAL portion of the local submatrix (possibly different for
1665: each row) or NULL, if o_nz is used to specify the nonzero
1666: structure. The size of this array is equal to the number
1667: of local rows, i.e 'm'.
1669: If the *_nnz parameter is given then the *_nz parameter is ignored
1671: Level: intermediate
1673: Notes:
1674: This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition
1675: from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local
1676: matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects.
1678: .seealso: MatCreate(), MatCreateIS(), MatMPIAIJSetPreallocation(), MatISGetLocalMat(), MATIS
1679: @*/
1680: PetscErrorCode MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1681: {
1687: PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz));
1688: return(0);
1689: }
1691: /* this is used by DMDA */
1692: PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[])
1693: {
1694: Mat_IS *matis = (Mat_IS*)(B->data);
1695: PetscInt bs,i,nlocalcols;
1699: if (!matis->A) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"You should first call MatSetLocalToGlobalMapping");
1701: if (!d_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nz;
1702: else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nnz[i];
1704: if (!o_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nz;
1705: else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nnz[i];
1707: PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1708: MatGetSize(matis->A,NULL,&nlocalcols);
1709: MatGetBlockSize(matis->A,&bs);
1710: PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
1712: for (i=0;i<matis->sf->nleaves;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols);
1713: MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata);
1714: #if defined(PETSC_HAVE_HYPRE)
1715: MatHYPRESetPreallocation(matis->A,0,matis->sf_leafdata,0,NULL);
1716: #endif
1718: for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs;
1719: MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);
1721: nlocalcols /= bs;
1722: for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols - i);
1723: MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata);
1725: /* for other matrix types */
1726: MatSetUp(matis->A);
1727: return(0);
1728: }
1730: PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce)
1731: {
1732: Mat_IS *matis = (Mat_IS*)(A->data);
1733: PetscInt *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership;
1734: const PetscInt *global_indices_r,*global_indices_c;
1735: PetscInt i,j,bs,rows,cols;
1736: PetscInt lrows,lcols;
1737: PetscInt local_rows,local_cols;
1738: PetscMPIInt size;
1739: PetscBool isdense,issbaij;
1740: PetscErrorCode ierr;
1743: MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
1744: MatGetSize(A,&rows,&cols);
1745: MatGetBlockSize(A,&bs);
1746: MatGetSize(matis->A,&local_rows,&local_cols);
1747: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense);
1748: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);
1749: ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&global_indices_r);
1750: if (A->rmap->mapping != A->cmap->mapping) {
1751: ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&global_indices_c);
1752: } else {
1753: global_indices_c = global_indices_r;
1754: }
1756: if (issbaij) {
1757: MatGetRowUpperTriangular(matis->A);
1758: }
1759: /*
1760: An SF reduce is needed to sum up properly on shared rows.
1761: Note that generally preallocation is not exact, since it overestimates nonzeros
1762: */
1763: MatGetLocalSize(A,&lrows,&lcols);
1764: MatPreallocateInitialize(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz);
1765: /* All processes need to compute entire row ownership */
1766: PetscMalloc1(rows,&row_ownership);
1767: MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges);
1768: for (i=0;i<size;i++) {
1769: for (j=mat_ranges[i];j<mat_ranges[i+1];j++) {
1770: row_ownership[j] = i;
1771: }
1772: }
1773: MatGetOwnershipRangesColumn(A,(const PetscInt**)&mat_ranges);
1775: /*
1776: my_dnz and my_onz contains exact contribution to preallocation from each local mat
1777: then, they will be summed up properly. This way, preallocation is always sufficient
1778: */
1779: PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz);
1780: /* preallocation as a MATAIJ */
1781: if (isdense) { /* special case for dense local matrices */
1782: for (i=0;i<local_rows;i++) {
1783: PetscInt owner = row_ownership[global_indices_r[i]];
1784: for (j=0;j<local_cols;j++) {
1785: PetscInt index_col = global_indices_c[j];
1786: if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1]) { /* diag block */
1787: my_dnz[i] += 1;
1788: } else { /* offdiag block */
1789: my_onz[i] += 1;
1790: }
1791: }
1792: }
1793: } else if (matis->A->ops->getrowij) {
1794: const PetscInt *ii,*jj,*jptr;
1795: PetscBool done;
1796: MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);
1797: if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
1798: jptr = jj;
1799: for (i=0;i<local_rows;i++) {
1800: PetscInt index_row = global_indices_r[i];
1801: for (j=0;j<ii[i+1]-ii[i];j++,jptr++) {
1802: PetscInt owner = row_ownership[index_row];
1803: PetscInt index_col = global_indices_c[*jptr];
1804: if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1805: my_dnz[i] += 1;
1806: } else { /* offdiag block */
1807: my_onz[i] += 1;
1808: }
1809: /* same as before, interchanging rows and cols */
1810: if (issbaij && index_col != index_row) {
1811: owner = row_ownership[index_col];
1812: if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1813: my_dnz[*jptr] += 1;
1814: } else {
1815: my_onz[*jptr] += 1;
1816: }
1817: }
1818: }
1819: }
1820: MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done);
1821: if (!done) SETERRQ(PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
1822: } else { /* loop over rows and use MatGetRow */
1823: for (i=0;i<local_rows;i++) {
1824: const PetscInt *cols;
1825: PetscInt ncols,index_row = global_indices_r[i];
1826: MatGetRow(matis->A,i,&ncols,&cols,NULL);
1827: for (j=0;j<ncols;j++) {
1828: PetscInt owner = row_ownership[index_row];
1829: PetscInt index_col = global_indices_c[cols[j]];
1830: if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1] ) { /* diag block */
1831: my_dnz[i] += 1;
1832: } else { /* offdiag block */
1833: my_onz[i] += 1;
1834: }
1835: /* same as before, interchanging rows and cols */
1836: if (issbaij && index_col != index_row) {
1837: owner = row_ownership[index_col];
1838: if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1] ) {
1839: my_dnz[cols[j]] += 1;
1840: } else {
1841: my_onz[cols[j]] += 1;
1842: }
1843: }
1844: }
1845: MatRestoreRow(matis->A,i,&ncols,&cols,NULL);
1846: }
1847: }
1848: if (global_indices_c != global_indices_r) {
1849: ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&global_indices_c);
1850: }
1851: ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&global_indices_r);
1852: PetscFree(row_ownership);
1854: /* Reduce my_dnz and my_onz */
1855: if (maxreduce) {
1856: PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);
1857: PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);
1858: PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX);
1859: PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX);
1860: } else {
1861: PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);
1862: PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);
1863: PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM);
1864: PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM);
1865: }
1866: PetscFree2(my_dnz,my_onz);
1868: /* Resize preallocation if overestimated */
1869: for (i=0;i<lrows;i++) {
1870: dnz[i] = PetscMin(dnz[i],lcols);
1871: onz[i] = PetscMin(onz[i],cols-lcols);
1872: }
1874: /* Set preallocation */
1875: MatSeqAIJSetPreallocation(B,0,dnz);
1876: MatMPIAIJSetPreallocation(B,0,dnz,0,onz);
1877: for (i=0;i<lrows;i+=bs) {
1878: PetscInt b, d = dnz[i],o = onz[i];
1880: for (b=1;b<bs;b++) {
1881: d = PetscMax(d,dnz[i+b]);
1882: o = PetscMax(o,onz[i+b]);
1883: }
1884: dnz[i/bs] = PetscMin(d/bs + d%bs,lcols/bs);
1885: onz[i/bs] = PetscMin(o/bs + o%bs,(cols-lcols)/bs);
1886: }
1887: MatSeqBAIJSetPreallocation(B,bs,0,dnz);
1888: MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz);
1889: MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz);
1890: MatPreallocateFinalize(dnz,onz);
1891: if (issbaij) {
1892: MatRestoreRowUpperTriangular(matis->A);
1893: }
1894: MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
1895: return(0);
1896: }
1898: PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M)
1899: {
1900: Mat_IS *matis = (Mat_IS*)(mat->data);
1901: Mat local_mat,MT;
1902: PetscInt rbs,cbs,rows,cols,lrows,lcols;
1903: PetscInt local_rows,local_cols;
1904: PetscBool isseqdense,isseqsbaij,isseqaij,isseqbaij;
1905: #if defined (PETSC_USE_DEBUG)
1906: PetscBool lb[4],bb[4];
1907: #endif
1908: PetscMPIInt size;
1909: const PetscScalar *array;
1910: PetscErrorCode ierr;
1913: MPI_Comm_size(PetscObjectComm((PetscObject)mat),&size);
1914: if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) {
1915: Mat B;
1916: IS irows = NULL,icols = NULL;
1917: PetscInt rbs,cbs;
1919: ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
1920: ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
1921: if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */
1922: IS rows,cols;
1923: const PetscInt *ridxs,*cidxs;
1924: PetscInt i,nw,*work;
1926: ISLocalToGlobalMappingGetBlockIndices(mat->rmap->mapping,&ridxs);
1927: ISLocalToGlobalMappingGetSize(mat->rmap->mapping,&nw);
1928: nw = nw/rbs;
1929: PetscCalloc1(nw,&work);
1930: for (i=0;i<nw;i++) work[ridxs[i]] += 1;
1931: for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
1932: if (i == nw) {
1933: ISCreateBlock(PETSC_COMM_SELF,rbs,nw,ridxs,PETSC_USE_POINTER,&rows);
1934: ISSetPermutation(rows);
1935: ISInvertPermutation(rows,PETSC_DECIDE,&irows);
1936: ISDestroy(&rows);
1937: }
1938: ISLocalToGlobalMappingRestoreBlockIndices(mat->rmap->mapping,&ridxs);
1939: PetscFree(work);
1940: if (irows && mat->rmap->mapping != mat->cmap->mapping) {
1941: ISLocalToGlobalMappingGetBlockIndices(mat->cmap->mapping,&cidxs);
1942: ISLocalToGlobalMappingGetSize(mat->cmap->mapping,&nw);
1943: nw = nw/cbs;
1944: PetscCalloc1(nw,&work);
1945: for (i=0;i<nw;i++) work[cidxs[i]] += 1;
1946: for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break;
1947: if (i == nw) {
1948: ISCreateBlock(PETSC_COMM_SELF,cbs,nw,cidxs,PETSC_USE_POINTER,&cols);
1949: ISSetPermutation(cols);
1950: ISInvertPermutation(cols,PETSC_DECIDE,&icols);
1951: ISDestroy(&cols);
1952: }
1953: ISLocalToGlobalMappingRestoreBlockIndices(mat->cmap->mapping,&cidxs);
1954: PetscFree(work);
1955: } else if (irows) {
1956: PetscObjectReference((PetscObject)irows);
1957: icols = irows;
1958: }
1959: } else {
1960: PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject*)&irows);
1961: PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject*)&icols);
1962: if (irows) { PetscObjectReference((PetscObject)irows); }
1963: if (icols) { PetscObjectReference((PetscObject)icols); }
1964: }
1965: if (!irows || !icols) {
1966: ISDestroy(&icols);
1967: ISDestroy(&irows);
1968: goto general_assembly;
1969: }
1970: MatConvert(matis->A,mtype,MAT_INITIAL_MATRIX,&B);
1971: if (reuse != MAT_INPLACE_MATRIX) {
1972: MatCreateSubMatrix(B,irows,icols,reuse,M);
1973: PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject)irows);
1974: PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject)icols);
1975: } else {
1976: Mat C;
1978: MatCreateSubMatrix(B,irows,icols,MAT_INITIAL_MATRIX,&C);
1979: MatHeaderReplace(mat,&C);
1980: }
1981: MatDestroy(&B);
1982: ISDestroy(&icols);
1983: ISDestroy(&irows);
1984: return(0);
1985: }
1986: general_assembly:
1987: MatGetSize(mat,&rows,&cols);
1988: ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
1989: ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
1990: MatGetLocalSize(mat,&lrows,&lcols);
1991: MatGetSize(matis->A,&local_rows,&local_cols);
1992: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isseqdense);
1993: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij);
1994: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQBAIJ,&isseqbaij);
1995: PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&isseqsbaij);
1996: if (!isseqdense && !isseqaij && !isseqbaij && !isseqsbaij) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(matis->A))->type_name);
1997: #if defined (PETSC_USE_DEBUG)
1998: lb[0] = isseqdense;
1999: lb[1] = isseqaij;
2000: lb[2] = isseqbaij;
2001: lb[3] = isseqsbaij;
2002: MPIU_Allreduce(lb,bb,4,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat));
2003: if (!bb[0] && !bb[1] && !bb[2] && !bb[3]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Local matrices must have the same type");
2004: #endif
2006: if (reuse != MAT_REUSE_MATRIX) {
2007: MatCreate(PetscObjectComm((PetscObject)mat),&MT);
2008: MatSetSizes(MT,lrows,lcols,rows,cols);
2009: MatSetType(MT,mtype);
2010: MatSetBlockSizes(MT,rbs,cbs);
2011: MatISSetMPIXAIJPreallocation_Private(mat,MT,PETSC_FALSE);
2012: } else {
2013: PetscInt mrbs,mcbs,mrows,mcols,mlrows,mlcols;
2015: /* some checks */
2016: MT = *M;
2017: MatGetBlockSizes(MT,&mrbs,&mcbs);
2018: MatGetSize(MT,&mrows,&mcols);
2019: MatGetLocalSize(MT,&mlrows,&mlcols);
2020: if (mrows != rows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%d != %d)",rows,mrows);
2021: if (mcols != cols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%d != %d)",cols,mcols);
2022: if (mlrows != lrows) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%d != %d)",lrows,mlrows);
2023: if (mlcols != lcols) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%d != %d)",lcols,mlcols);
2024: if (mrbs != rbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong row block size (%d != %d)",rbs,mrbs);
2025: if (mcbs != cbs) SETERRQ2(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong col block size (%d != %d)",cbs,mcbs);
2026: MatZeroEntries(MT);
2027: }
2029: if (isseqsbaij || isseqbaij) {
2030: MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&local_mat);
2031: isseqaij = PETSC_TRUE;
2032: } else {
2033: PetscObjectReference((PetscObject)matis->A);
2034: local_mat = matis->A;
2035: }
2037: /* Set values */
2038: MatSetLocalToGlobalMapping(MT,mat->rmap->mapping,mat->cmap->mapping);
2039: if (isseqdense) { /* special case for dense local matrices */
2040: PetscInt i,*dummy;
2042: PetscMalloc1(PetscMax(local_rows,local_cols),&dummy);
2043: for (i=0;i<PetscMax(local_rows,local_cols);i++) dummy[i] = i;
2044: MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_FALSE);
2045: MatDenseGetArrayRead(local_mat,&array);
2046: MatSetValuesLocal(MT,local_rows,dummy,local_cols,dummy,array,ADD_VALUES);
2047: MatDenseRestoreArrayRead(local_mat,&array);
2048: PetscFree(dummy);
2049: } else if (isseqaij) {
2050: const PetscInt *blocks;
2051: PetscInt i,nvtxs,*xadj,*adjncy, nb;
2052: PetscBool done;
2053: PetscScalar *sarray;
2055: MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);
2056: if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatGetRowIJ");
2057: MatSeqAIJGetArray(local_mat,&sarray);
2058: MatGetVariableBlockSizes(local_mat,&nb,&blocks);
2059: if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */
2060: PetscInt sum;
2062: for (i=0,sum=0;i<nb;i++) sum += blocks[i];
2063: if (sum == nvtxs) {
2064: PetscInt r;
2066: for (i=0,r=0;i<nb;i++) {
2067: #if defined(PETSC_USE_DEBUG)
2068: if (blocks[i] != xadj[r+1] - xadj[r]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Invalid block sizes prescribed for block %D: expected %D, got %D",i,blocks[i],xadj[r+1] - xadj[r]);
2069: #endif
2070: MatSetValuesLocal(MT,blocks[i],adjncy+xadj[r],blocks[i],adjncy+xadj[r],sarray+xadj[r],ADD_VALUES);
2071: r += blocks[i];
2072: }
2073: } else {
2074: for (i=0;i<nvtxs;i++) {
2075: MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES);
2076: }
2077: }
2078: } else {
2079: for (i=0;i<nvtxs;i++) {
2080: MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES);
2081: }
2082: }
2083: MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done);
2084: if (!done) SETERRQ(PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ");
2085: MatSeqAIJRestoreArray(local_mat,&sarray);
2086: } else { /* very basic values insertion for all other matrix types */
2087: PetscInt i;
2089: for (i=0;i<local_rows;i++) {
2090: PetscInt j;
2091: const PetscInt *local_indices_cols;
2093: MatGetRow(local_mat,i,&j,&local_indices_cols,&array);
2094: MatSetValuesLocal(MT,1,&i,j,local_indices_cols,array,ADD_VALUES);
2095: MatRestoreRow(local_mat,i,&j,&local_indices_cols,&array);
2096: }
2097: }
2098: MatAssemblyBegin(MT,MAT_FINAL_ASSEMBLY);
2099: MatDestroy(&local_mat);
2100: MatAssemblyEnd(MT,MAT_FINAL_ASSEMBLY);
2101: if (isseqdense) {
2102: MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_TRUE);
2103: }
2104: if (reuse == MAT_INPLACE_MATRIX) {
2105: MatHeaderReplace(mat,&MT);
2106: } else if (reuse == MAT_INITIAL_MATRIX) {
2107: *M = MT;
2108: }
2109: return(0);
2110: }
2112: /*@
2113: MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format
2115: Input Parameter:
2116: + mat - the matrix (should be of type MATIS)
2117: - reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX
2119: Output Parameter:
2120: . newmat - the matrix in AIJ format
2122: Level: developer
2124: Notes:
2125: This function has been deprecated and it will be removed in future releases. Update your code to use the MatConvert() interface.
2127: .seealso: MATIS, MatConvert()
2128: @*/
2129: PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat)
2130: {
2137: if (reuse == MAT_REUSE_MATRIX) {
2140: if (mat == *newmat) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix");
2141: }
2142: PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatType,MatReuse,Mat*),(mat,MATAIJ,reuse,newmat));
2143: return(0);
2144: }
2146: PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat)
2147: {
2149: Mat_IS *matis = (Mat_IS*)(mat->data);
2150: PetscInt rbs,cbs,m,n,M,N;
2151: Mat B,localmat;
2154: ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs);
2155: ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs);
2156: MatGetSize(mat,&M,&N);
2157: MatGetLocalSize(mat,&m,&n);
2158: MatCreate(PetscObjectComm((PetscObject)mat),&B);
2159: MatSetSizes(B,m,n,M,N);
2160: MatSetBlockSize(B,rbs == cbs ? rbs : 1);
2161: MatSetType(B,MATIS);
2162: MatISSetLocalMatType(B,matis->lmattype);
2163: MatSetLocalToGlobalMapping(B,mat->rmap->mapping,mat->cmap->mapping);
2164: MatDuplicate(matis->A,op,&localmat);
2165: MatISSetLocalMat(B,localmat);
2166: MatDestroy(&localmat);
2167: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
2168: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
2169: *newmat = B;
2170: return(0);
2171: }
2173: static PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool *flg)
2174: {
2176: Mat_IS *matis = (Mat_IS*)A->data;
2177: PetscBool local_sym;
2180: MatIsHermitian(matis->A,tol,&local_sym);
2181: MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2182: return(0);
2183: }
2185: static PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool *flg)
2186: {
2188: Mat_IS *matis = (Mat_IS*)A->data;
2189: PetscBool local_sym;
2192: MatIsSymmetric(matis->A,tol,&local_sym);
2193: MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2194: return(0);
2195: }
2197: static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A,PetscBool *flg)
2198: {
2200: Mat_IS *matis = (Mat_IS*)A->data;
2201: PetscBool local_sym;
2204: if (A->rmap->mapping != A->cmap->mapping) {
2205: *flg = PETSC_FALSE;
2206: return(0);
2207: }
2208: MatIsStructurallySymmetric(matis->A,&local_sym);
2209: MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2210: return(0);
2211: }
2213: static PetscErrorCode MatDestroy_IS(Mat A)
2214: {
2216: Mat_IS *b = (Mat_IS*)A->data;
2219: PetscFree(b->bdiag);
2220: PetscFree(b->lmattype);
2221: MatDestroy(&b->A);
2222: VecScatterDestroy(&b->cctx);
2223: VecScatterDestroy(&b->rctx);
2224: VecDestroy(&b->x);
2225: VecDestroy(&b->y);
2226: VecDestroy(&b->counter);
2227: ISDestroy(&b->getsub_ris);
2228: ISDestroy(&b->getsub_cis);
2229: if (b->sf != b->csf) {
2230: PetscSFDestroy(&b->csf);
2231: PetscFree2(b->csf_rootdata,b->csf_leafdata);
2232: } else b->csf = NULL;
2233: PetscSFDestroy(&b->sf);
2234: PetscFree2(b->sf_rootdata,b->sf_leafdata);
2235: PetscFree(A->data);
2236: PetscObjectChangeTypeName((PetscObject)A,0);
2237: PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",NULL);
2238: PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL);
2239: PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL);
2240: PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL);
2241: PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL);
2242: PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",NULL);
2243: PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",NULL);
2244: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",NULL);
2245: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",NULL);
2246: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",NULL);
2247: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",NULL);
2248: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",NULL);
2249: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",NULL);
2250: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",NULL);
2251: return(0);
2252: }
2254: static PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y)
2255: {
2257: Mat_IS *is = (Mat_IS*)A->data;
2258: PetscScalar zero = 0.0;
2261: /* scatter the global vector x into the local work vector */
2262: VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);
2263: VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD);
2265: /* multiply the local matrix */
2266: MatMult(is->A,is->x,is->y);
2268: /* scatter product back into global memory */
2269: VecSet(y,zero);
2270: VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);
2271: VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE);
2272: return(0);
2273: }
2275: static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2276: {
2277: Vec temp_vec;
2281: if (v3 != v2) {
2282: MatMult(A,v1,v3);
2283: VecAXPY(v3,1.0,v2);
2284: } else {
2285: VecDuplicate(v2,&temp_vec);
2286: MatMult(A,v1,temp_vec);
2287: VecAXPY(temp_vec,1.0,v2);
2288: VecCopy(temp_vec,v3);
2289: VecDestroy(&temp_vec);
2290: }
2291: return(0);
2292: }
2294: static PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x)
2295: {
2296: Mat_IS *is = (Mat_IS*)A->data;
2300: /* scatter the global vector x into the local work vector */
2301: VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);
2302: VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD);
2304: /* multiply the local matrix */
2305: MatMultTranspose(is->A,is->y,is->x);
2307: /* scatter product back into global vector */
2308: VecSet(x,0);
2309: VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);
2310: VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE);
2311: return(0);
2312: }
2314: static PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3)
2315: {
2316: Vec temp_vec;
2320: if (v3 != v2) {
2321: MatMultTranspose(A,v1,v3);
2322: VecAXPY(v3,1.0,v2);
2323: } else {
2324: VecDuplicate(v2,&temp_vec);
2325: MatMultTranspose(A,v1,temp_vec);
2326: VecAXPY(temp_vec,1.0,v2);
2327: VecCopy(temp_vec,v3);
2328: VecDestroy(&temp_vec);
2329: }
2330: return(0);
2331: }
2333: static PetscErrorCode MatView_IS(Mat A,PetscViewer viewer)
2334: {
2335: Mat_IS *a = (Mat_IS*)A->data;
2337: PetscViewer sviewer;
2338: PetscBool isascii,view = PETSC_TRUE;
2341: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
2342: if (isascii) {
2343: PetscViewerFormat format;
2345: PetscViewerGetFormat(viewer,&format);
2346: if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE;
2347: }
2348: if (!view) return(0);
2349: PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
2350: MatView(a->A,sviewer);
2351: PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
2352: PetscViewerFlush(viewer);
2353: return(0);
2354: }
2356: static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat,const PetscScalar **values)
2357: {
2358: Mat_IS *is = (Mat_IS*)mat->data;
2359: MPI_Datatype nodeType;
2360: const PetscScalar *lv;
2361: PetscInt bs;
2362: PetscErrorCode ierr;
2365: MatGetBlockSize(mat,&bs);
2366: MatSetBlockSize(is->A,bs);
2367: MatInvertBlockDiagonal(is->A,&lv);
2368: if (!is->bdiag) {
2369: PetscMalloc1(bs*mat->rmap->n,&is->bdiag);
2370: }
2371: MPI_Type_contiguous(bs,MPIU_SCALAR,&nodeType);
2372: MPI_Type_commit(&nodeType);
2373: PetscSFReduceBegin(is->sf,nodeType,lv,is->bdiag,MPIU_REPLACE);
2374: PetscSFReduceEnd(is->sf,nodeType,lv,is->bdiag,MPIU_REPLACE);
2375: MPI_Type_free(&nodeType);
2376: if (values) *values = is->bdiag;
2377: return(0);
2378: }
2380: static PetscErrorCode MatISSetUpScatters_Private(Mat A)
2381: {
2382: Vec cglobal,rglobal;
2383: IS from;
2384: Mat_IS *is = (Mat_IS*)A->data;
2385: PetscScalar sum;
2386: const PetscInt *garray;
2387: PetscInt nr,rbs,nc,cbs;
2388: PetscBool iscuda;
2392: ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nr);
2393: ISLocalToGlobalMappingGetBlockSize(A->rmap->mapping,&rbs);
2394: ISLocalToGlobalMappingGetSize(A->cmap->mapping,&nc);
2395: ISLocalToGlobalMappingGetBlockSize(A->cmap->mapping,&cbs);
2396: VecDestroy(&is->x);
2397: VecDestroy(&is->y);
2398: VecDestroy(&is->counter);
2399: VecScatterDestroy(&is->rctx);
2400: VecScatterDestroy(&is->cctx);
2401: MatCreateVecs(is->A,&is->x,&is->y);
2402: VecBindToCPU(is->y,PETSC_TRUE);
2403: PetscObjectTypeCompare((PetscObject)is->y,VECSEQCUDA,&iscuda);
2404: if (iscuda) {
2405: PetscFree(A->defaultvectype);
2406: PetscStrallocpy(VECCUDA,&A->defaultvectype);
2407: }
2408: MatCreateVecs(A,&cglobal,&rglobal);
2409: VecBindToCPU(rglobal,PETSC_TRUE);
2410: ISLocalToGlobalMappingGetBlockIndices(A->rmap->mapping,&garray);
2411: ISCreateBlock(PetscObjectComm((PetscObject)A),rbs,nr/rbs,garray,PETSC_USE_POINTER,&from);
2412: VecScatterCreate(rglobal,from,is->y,NULL,&is->rctx);
2413: ISLocalToGlobalMappingRestoreBlockIndices(A->rmap->mapping,&garray);
2414: ISDestroy(&from);
2415: if (A->rmap->mapping != A->cmap->mapping) {
2416: ISLocalToGlobalMappingGetBlockIndices(A->cmap->mapping,&garray);
2417: ISCreateBlock(PetscObjectComm((PetscObject)A),cbs,nc/cbs,garray,PETSC_USE_POINTER,&from);
2418: VecScatterCreate(cglobal,from,is->x,NULL,&is->cctx);
2419: ISLocalToGlobalMappingRestoreBlockIndices(A->cmap->mapping,&garray);
2420: ISDestroy(&from);
2421: } else {
2422: PetscObjectReference((PetscObject)is->rctx);
2423: is->cctx = is->rctx;
2424: }
2425: VecDestroy(&cglobal);
2427: /* interface counter vector (local) */
2428: VecDuplicate(is->y,&is->counter);
2429: VecBindToCPU(is->counter,PETSC_TRUE);
2430: VecSet(is->y,1.);
2431: VecScatterBegin(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);
2432: VecScatterEnd(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE);
2433: VecScatterBegin(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);
2434: VecScatterEnd(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD);
2435: VecBindToCPU(is->y,PETSC_FALSE);
2436: VecBindToCPU(is->counter,PETSC_FALSE);
2438: /* special functions for block-diagonal matrices */
2439: VecSum(rglobal,&sum);
2440: if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && A->rmap->mapping == A->cmap->mapping) {
2441: A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS;
2442: } else {
2443: A->ops->invertblockdiagonal = NULL;
2444: }
2445: VecDestroy(&rglobal);
2447: /* setup SF for general purpose shared indices based communications */
2448: MatISSetUpSF_IS(A);
2449: return(0);
2450: }
2452: static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping)
2453: {
2455: PetscInt nr,rbs,nc,cbs;
2456: Mat_IS *is = (Mat_IS*)A->data;
2461: MatDestroy(&is->A);
2462: if (is->csf != is->sf) {
2463: PetscSFDestroy(&is->csf);
2464: PetscFree2(is->csf_rootdata,is->csf_leafdata);
2465: } else is->csf = NULL;
2466: PetscSFDestroy(&is->sf);
2467: PetscFree2(is->sf_rootdata,is->sf_leafdata);
2468: PetscFree(is->bdiag);
2470: /* Setup Layout and set local to global maps */
2471: PetscLayoutSetUp(A->rmap);
2472: PetscLayoutSetUp(A->cmap);
2473: ISLocalToGlobalMappingGetSize(rmapping,&nr);
2474: ISLocalToGlobalMappingGetBlockSize(rmapping,&rbs);
2475: ISLocalToGlobalMappingGetSize(cmapping,&nc);
2476: ISLocalToGlobalMappingGetBlockSize(cmapping,&cbs);
2477: /* check if the two mappings are actually the same for square matrices (DOLFIN passes 2 different objects) */
2478: if (rmapping != cmapping && A->rmap->N == A->cmap->N) {
2479: PetscBool same,gsame;
2481: same = PETSC_FALSE;
2482: if (nr == nc && cbs == rbs) {
2483: const PetscInt *idxs1,*idxs2;
2485: ISLocalToGlobalMappingGetBlockIndices(rmapping,&idxs1);
2486: ISLocalToGlobalMappingGetBlockIndices(cmapping,&idxs2);
2487: PetscArraycmp(idxs1,idxs2,nr/rbs,&same);
2488: ISLocalToGlobalMappingRestoreBlockIndices(rmapping,&idxs1);
2489: ISLocalToGlobalMappingRestoreBlockIndices(cmapping,&idxs2);
2490: }
2491: MPIU_Allreduce(&same,&gsame,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A));
2492: if (gsame) cmapping = rmapping;
2493: }
2494: PetscLayoutSetBlockSize(A->rmap,rbs);
2495: PetscLayoutSetBlockSize(A->cmap,cbs);
2496: PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping);
2497: PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping);
2499: /* Create the local matrix A */
2500: MatCreate(PETSC_COMM_SELF,&is->A);
2501: MatSetType(is->A,is->lmattype);
2502: MatSetSizes(is->A,nr,nc,nr,nc);
2503: MatSetBlockSizes(is->A,rbs,cbs);
2504: MatSetOptionsPrefix(is->A,"is_");
2505: MatAppendOptionsPrefix(is->A,((PetscObject)A)->prefix);
2506: PetscLayoutSetUp(is->A->rmap);
2507: PetscLayoutSetUp(is->A->cmap);
2509: if (!is->islocalref) { /* setup scatters and local vectors for MatMult */
2510: MatISSetUpScatters_Private(A);
2511: }
2512: MatSetUp(A);
2513: return(0);
2514: }
2516: static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2517: {
2518: Mat_IS *is = (Mat_IS*)mat->data;
2520: #if defined(PETSC_USE_DEBUG)
2521: PetscInt i,zm,zn;
2522: #endif
2523: PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
2526: #if defined(PETSC_USE_DEBUG)
2527: if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
2528: /* count negative indices */
2529: for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2530: for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2531: #endif
2532: ISGlobalToLocalMappingApply(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);
2533: ISGlobalToLocalMappingApply(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);
2534: #if defined(PETSC_USE_DEBUG)
2535: /* count negative indices (should be the same as before) */
2536: for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2537: for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2538: if (!is->A->rmap->mapping && zm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the row indices can not be mapped! Maybe you should not use MATIS");
2539: if (!is->A->cmap->mapping && zn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the column indices can not be mapped! Maybe you should not use MATIS");
2540: #endif
2541: MatSetValues(is->A,m,rows_l,n,cols_l,values,addv);
2542: return(0);
2543: }
2545: static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv)
2546: {
2547: Mat_IS *is = (Mat_IS*)mat->data;
2549: #if defined(PETSC_USE_DEBUG)
2550: PetscInt i,zm,zn;
2551: #endif
2552: PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION];
2555: #if defined(PETSC_USE_DEBUG)
2556: if (m > MATIS_MAX_ENTRIES_INSERTION || n > MATIS_MAX_ENTRIES_INSERTION) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column block indices must be <= %D: they are %D %D",MATIS_MAX_ENTRIES_INSERTION,m,n);
2557: /* count negative indices */
2558: for (i=0,zm=0;i<m;i++) if (rows[i] < 0) zm++;
2559: for (i=0,zn=0;i<n;i++) if (cols[i] < 0) zn++;
2560: #endif
2561: ISGlobalToLocalMappingApplyBlock(mat->rmap->mapping,IS_GTOLM_MASK,m,rows,&m,rows_l);
2562: ISGlobalToLocalMappingApplyBlock(mat->cmap->mapping,IS_GTOLM_MASK,n,cols,&n,cols_l);
2563: #if defined(PETSC_USE_DEBUG)
2564: /* count negative indices (should be the same as before) */
2565: for (i=0;i<m;i++) if (rows_l[i] < 0) zm--;
2566: for (i=0;i<n;i++) if (cols_l[i] < 0) zn--;
2567: if (!is->A->rmap->mapping && zm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the row indices can not be mapped! Maybe you should not use MATIS");
2568: if (!is->A->cmap->mapping && zn) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Some of the column indices can not be mapped! Maybe you should not use MATIS");
2569: #endif
2570: MatSetValuesBlocked(is->A,m,rows_l,n,cols_l,values,addv);
2571: return(0);
2572: }
2574: static PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2575: {
2577: Mat_IS *is = (Mat_IS*)A->data;
2580: if (is->A->rmap->mapping) {
2581: MatSetValuesLocal(is->A,m,rows,n,cols,values,addv);
2582: } else {
2583: MatSetValues(is->A,m,rows,n,cols,values,addv);
2584: }
2585: return(0);
2586: }
2588: static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv)
2589: {
2591: Mat_IS *is = (Mat_IS*)A->data;
2594: if (is->A->rmap->mapping) {
2595: #if defined(PETSC_USE_DEBUG)
2596: PetscInt ibs,bs;
2598: ISLocalToGlobalMappingGetBlockSize(is->A->rmap->mapping,&ibs);
2599: MatGetBlockSize(is->A,&bs);
2600: if (ibs != bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SUP,"Different block sizes! local mat %D, local l2g map %D",bs,ibs);
2601: #endif
2602: MatSetValuesBlockedLocal(is->A,m,rows,n,cols,values,addv);
2603: } else {
2604: MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv);
2605: }
2606: return(0);
2607: }
2609: static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,PetscBool columns)
2610: {
2611: Mat_IS *is = (Mat_IS*)A->data;
2615: if (!n) {
2616: is->pure_neumann = PETSC_TRUE;
2617: } else {
2618: PetscInt i;
2619: is->pure_neumann = PETSC_FALSE;
2621: if (columns) {
2622: MatZeroRowsColumns(is->A,n,rows,diag,0,0);
2623: } else {
2624: MatZeroRows(is->A,n,rows,diag,0,0);
2625: }
2626: if (diag != 0.) {
2627: const PetscScalar *array;
2628: VecGetArrayRead(is->counter,&array);
2629: for (i=0; i<n; i++) {
2630: MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES);
2631: }
2632: VecRestoreArrayRead(is->counter,&array);
2633: }
2634: MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY);
2635: MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY);
2636: }
2637: return(0);
2638: }
2640: static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b,PetscBool columns)
2641: {
2642: Mat_IS *matis = (Mat_IS*)A->data;
2643: PetscInt nr,nl,len,i;
2644: PetscInt *lrows;
2648: #if defined(PETSC_USE_DEBUG)
2649: if (columns || diag != 0. || (x && b)) {
2650: PetscBool cong;
2652: PetscLayoutCompare(A->rmap,A->cmap,&cong);
2653: cong = (PetscBool)(cong && matis->sf == matis->csf);
2654: if (!cong && columns) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Columns can be zeroed if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2655: if (!cong && diag != 0.) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Nonzero diagonal value supported if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS");
2656: if (!cong && x && b) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"A->rmap and A->cmap need to be congruent, and the l2g maps be the same");
2657: }
2658: #endif
2659: /* get locally owned rows */
2660: PetscLayoutMapLocal(A->rmap,n,rows,&len,&lrows,NULL);
2661: /* fix right hand side if needed */
2662: if (x && b) {
2663: const PetscScalar *xx;
2664: PetscScalar *bb;
2666: VecGetArrayRead(x, &xx);
2667: VecGetArray(b, &bb);
2668: for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]];
2669: VecRestoreArrayRead(x, &xx);
2670: VecRestoreArray(b, &bb);
2671: }
2672: /* get rows associated to the local matrices */
2673: MatGetSize(matis->A,&nl,NULL);
2674: PetscArrayzero(matis->sf_leafdata,nl);
2675: PetscArrayzero(matis->sf_rootdata,A->rmap->n);
2676: for (i=0;i<len;i++) matis->sf_rootdata[lrows[i]] = 1;
2677: PetscFree(lrows);
2678: PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
2679: PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata);
2680: PetscMalloc1(nl,&lrows);
2681: for (i=0,nr=0;i<nl;i++) if (matis->sf_leafdata[i]) lrows[nr++] = i;
2682: MatISZeroRowsColumnsLocal_Private(A,nr,lrows,diag,columns);
2683: PetscFree(lrows);
2684: return(0);
2685: }
2687: static PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2688: {
2692: MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_FALSE);
2693: return(0);
2694: }
2696: static PetscErrorCode MatZeroRowsColumns_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b)
2697: {
2701: MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_TRUE);
2702: return(0);
2703: }
2705: static PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type)
2706: {
2707: Mat_IS *is = (Mat_IS*)A->data;
2711: MatAssemblyBegin(is->A,type);
2712: return(0);
2713: }
2715: static PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type)
2716: {
2717: Mat_IS *is = (Mat_IS*)A->data;
2721: MatAssemblyEnd(is->A,type);
2722: /* fix for local empty rows/cols */
2723: if (is->locempty && type == MAT_FINAL_ASSEMBLY) {
2724: Mat newlA;
2725: ISLocalToGlobalMapping rl2g,cl2g;
2726: IS nzr,nzc;
2727: PetscInt nr,nc,nnzr,nnzc;
2728: PetscBool lnewl2g,newl2g;
2730: MatGetSize(is->A,&nr,&nc);
2731: MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_FALSE,PETSC_SMALL,&nzr);
2732: if (!nzr) {
2733: ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&nzr);
2734: }
2735: MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_TRUE,PETSC_SMALL,&nzc);
2736: if (!nzc) {
2737: ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&nzc);
2738: }
2739: ISGetSize(nzr,&nnzr);
2740: ISGetSize(nzc,&nnzc);
2741: if (nnzr != nr || nnzc != nc) {
2742: ISLocalToGlobalMapping l2g;
2743: IS is1,is2;
2745: /* need new global l2g map */
2746: lnewl2g = PETSC_TRUE;
2747: MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));
2749: /* extract valid submatrix */
2750: MatCreateSubMatrix(is->A,nzr,nzc,MAT_INITIAL_MATRIX,&newlA);
2752: /* attach local l2g maps for successive calls of MatSetValues on the local matrix */
2753: ISLocalToGlobalMappingCreateIS(nzr,&l2g);
2754: ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&is1);
2755: ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);
2756: ISLocalToGlobalMappingDestroy(&l2g);
2757: if (is->A->rmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2758: const PetscInt *idxs1,*idxs2;
2759: PetscInt j,i,nl,*tidxs;
2761: ISLocalToGlobalMappingGetSize(is->A->rmap->mapping,&nl);
2762: ISLocalToGlobalMappingGetIndices(is->A->rmap->mapping,&idxs1);
2763: PetscMalloc1(nl,&tidxs);
2764: ISGetIndices(is2,&idxs2);
2765: for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2766: if (j != nr) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nr);
2767: ISLocalToGlobalMappingRestoreIndices(is->A->rmap->mapping,&idxs1);
2768: ISRestoreIndices(is2,&idxs2);
2769: ISDestroy(&is2);
2770: ISCreateGeneral(PetscObjectComm((PetscObject)is->A->rmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);
2771: }
2772: ISLocalToGlobalMappingCreateIS(is2,&rl2g);
2773: ISDestroy(&is1);
2774: ISDestroy(&is2);
2776: ISLocalToGlobalMappingCreateIS(nzc,&l2g);
2777: ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&is1);
2778: ISGlobalToLocalMappingApplyIS(l2g,IS_GTOLM_MASK,is1,&is2);
2779: ISLocalToGlobalMappingDestroy(&l2g);
2780: if (is->A->cmap->mapping) { /* the matrix has a local-to-local map already attached (probably DMDA generated) */
2781: const PetscInt *idxs1,*idxs2;
2782: PetscInt j,i,nl,*tidxs;
2784: ISLocalToGlobalMappingGetSize(is->A->cmap->mapping,&nl);
2785: ISLocalToGlobalMappingGetIndices(is->A->cmap->mapping,&idxs1);
2786: PetscMalloc1(nl,&tidxs);
2787: ISGetIndices(is2,&idxs2);
2788: for (i=0,j=0;i<nl;i++) tidxs[i] = idxs1[i] < 0 ? -1 : idxs2[j++];
2789: if (j != nc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected count %D != %D",j,nc);
2790: ISLocalToGlobalMappingRestoreIndices(is->A->cmap->mapping,&idxs1);
2791: ISRestoreIndices(is2,&idxs2);
2792: ISDestroy(&is2);
2793: ISCreateGeneral(PetscObjectComm((PetscObject)is->A->cmap->mapping),nl,tidxs,PETSC_OWN_POINTER,&is2);
2794: }
2795: ISLocalToGlobalMappingCreateIS(is2,&cl2g);
2796: ISDestroy(&is1);
2797: ISDestroy(&is2);
2799: MatSetLocalToGlobalMapping(newlA,rl2g,cl2g);
2801: ISLocalToGlobalMappingDestroy(&rl2g);
2802: ISLocalToGlobalMappingDestroy(&cl2g);
2803: } else { /* local matrix fully populated */
2804: lnewl2g = PETSC_FALSE;
2805: MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A));
2806: PetscObjectReference((PetscObject)is->A);
2807: newlA = is->A;
2808: }
2809: /* attach new global l2g map if needed */
2810: if (newl2g) {
2811: IS gnzr,gnzc;
2812: const PetscInt *grid,*gcid;
2814: ISLocalToGlobalMappingApplyIS(A->rmap->mapping,nzr,&gnzr);
2815: ISLocalToGlobalMappingApplyIS(A->cmap->mapping,nzc,&gnzc);
2816: ISGetIndices(gnzr,&grid);
2817: ISGetIndices(gnzc,&gcid);
2818: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzr,grid,PETSC_COPY_VALUES,&rl2g);
2819: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nnzc,gcid,PETSC_COPY_VALUES,&cl2g);
2820: ISRestoreIndices(gnzr,&grid);
2821: ISRestoreIndices(gnzc,&gcid);
2822: ISDestroy(&gnzr);
2823: ISDestroy(&gnzc);
2824: MatSetLocalToGlobalMapping(A,rl2g,cl2g);
2825: ISLocalToGlobalMappingDestroy(&rl2g);
2826: ISLocalToGlobalMappingDestroy(&cl2g);
2827: }
2828: MatISSetLocalMat(A,newlA);
2829: MatDestroy(&newlA);
2830: ISDestroy(&nzr);
2831: ISDestroy(&nzc);
2832: is->locempty = PETSC_FALSE;
2833: }
2834: return(0);
2835: }
2837: static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local)
2838: {
2839: Mat_IS *is = (Mat_IS*)mat->data;
2842: *local = is->A;
2843: return(0);
2844: }
2846: static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local)
2847: {
2849: *local = NULL;
2850: return(0);
2851: }
2853: /*@
2854: MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix.
2856: Input Parameter:
2857: . mat - the matrix
2859: Output Parameter:
2860: . local - the local matrix
2862: Level: advanced
2864: Notes:
2865: This can be called if you have precomputed the nonzero structure of the
2866: matrix and want to provide it to the inner matrix object to improve the performance
2867: of the MatSetValues() operation.
2869: Call MatISRestoreLocalMat() when finished with the local matrix.
2871: .seealso: MATIS
2872: @*/
2873: PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local)
2874: {
2880: PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local));
2881: return(0);
2882: }
2884: /*@
2885: MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat()
2887: Input Parameter:
2888: . mat - the matrix
2890: Output Parameter:
2891: . local - the local matrix
2893: Level: advanced
2895: .seealso: MATIS
2896: @*/
2897: PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local)
2898: {
2904: PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local));
2905: return(0);
2906: }
2908: static PetscErrorCode MatISSetLocalMatType_IS(Mat mat,MatType mtype)
2909: {
2910: Mat_IS *is = (Mat_IS*)mat->data;
2914: if (is->A) {
2915: MatSetType(is->A,mtype);
2916: }
2917: PetscFree(is->lmattype);
2918: PetscStrallocpy(mtype,&is->lmattype);
2919: return(0);
2920: }
2922: /*@
2923: MatISSetLocalMatType - Specifies the type of local matrix
2925: Input Parameter:
2926: + mat - the matrix
2927: - mtype - the local matrix type
2929: Output Parameter:
2931: Level: advanced
2933: .seealso: MATIS, MatSetType(), MatType
2934: @*/
2935: PetscErrorCode MatISSetLocalMatType(Mat mat,MatType mtype)
2936: {
2941: PetscUseMethod(mat,"MatISSetLocalMatType_C",(Mat,MatType),(mat,mtype));
2942: return(0);
2943: }
2945: static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local)
2946: {
2947: Mat_IS *is = (Mat_IS*)mat->data;
2948: PetscInt nrows,ncols,orows,ocols;
2950: MatType mtype,otype;
2951: PetscBool sametype = PETSC_TRUE;
2954: if (is->A) {
2955: MatGetSize(is->A,&orows,&ocols);
2956: MatGetSize(local,&nrows,&ncols);
2957: if (orows != nrows || ocols != ncols) SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local MATIS matrix should be of size %Dx%D (you passed a %Dx%D matrix)",orows,ocols,nrows,ncols);
2958: MatGetType(local,&mtype);
2959: MatGetType(is->A,&otype);
2960: PetscStrcmp(mtype,otype,&sametype);
2961: }
2962: PetscObjectReference((PetscObject)local);
2963: MatDestroy(&is->A);
2964: is->A = local;
2965: MatGetType(is->A,&mtype);
2966: MatISSetLocalMatType(mat,mtype);
2967: if (!sametype && !is->islocalref) {
2968: MatISSetUpScatters_Private(mat);
2969: }
2970: return(0);
2971: }
2973: /*@
2974: MatISSetLocalMat - Replace the local matrix stored inside a MATIS object.
2976: Collective on Mat
2978: Input Parameter:
2979: + mat - the matrix
2980: - local - the local matrix
2982: Output Parameter:
2984: Level: advanced
2986: Notes:
2987: This can be called if you have precomputed the local matrix and
2988: want to provide it to the matrix object MATIS.
2990: .seealso: MATIS
2991: @*/
2992: PetscErrorCode MatISSetLocalMat(Mat mat,Mat local)
2993: {
2999: PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local));
3000: return(0);
3001: }
3003: static PetscErrorCode MatZeroEntries_IS(Mat A)
3004: {
3005: Mat_IS *a = (Mat_IS*)A->data;
3009: MatZeroEntries(a->A);
3010: return(0);
3011: }
3013: static PetscErrorCode MatScale_IS(Mat A,PetscScalar a)
3014: {
3015: Mat_IS *is = (Mat_IS*)A->data;
3019: MatScale(is->A,a);
3020: return(0);
3021: }
3023: static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v)
3024: {
3025: Mat_IS *is = (Mat_IS*)A->data;
3029: /* get diagonal of the local matrix */
3030: MatGetDiagonal(is->A,is->y);
3032: /* scatter diagonal back into global vector */
3033: VecSet(v,0);
3034: VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);
3035: VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE);
3036: return(0);
3037: }
3039: static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg)
3040: {
3041: Mat_IS *a = (Mat_IS*)A->data;
3045: MatSetOption(a->A,op,flg);
3046: return(0);
3047: }
3049: static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str)
3050: {
3051: Mat_IS *y = (Mat_IS*)Y->data;
3052: Mat_IS *x;
3053: #if defined(PETSC_USE_DEBUG)
3054: PetscBool ismatis;
3055: #endif
3059: #if defined(PETSC_USE_DEBUG)
3060: PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis);
3061: if (!ismatis) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS");
3062: #endif
3063: x = (Mat_IS*)X->data;
3064: MatAXPY(y->A,a,x->A,str);
3065: return(0);
3066: }
3068: static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat)
3069: {
3070: Mat lA;
3071: Mat_IS *matis;
3072: ISLocalToGlobalMapping rl2g,cl2g;
3073: IS is;
3074: const PetscInt *rg,*rl;
3075: PetscInt nrg;
3076: PetscInt N,M,nrl,i,*idxs;
3077: PetscErrorCode ierr;
3080: ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg);
3081: ISGetLocalSize(row,&nrl);
3082: ISGetIndices(row,&rl);
3083: ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg);
3084: #if defined(PETSC_USE_DEBUG)
3085: for (i=0;i<nrl;i++) if (rl[i]>=nrg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row index %D -> %D greater then maximum possible %D",i,rl[i],nrg);
3086: #endif
3087: PetscMalloc1(nrg,&idxs);
3088: /* map from [0,nrl) to row */
3089: for (i=0;i<nrl;i++) idxs[i] = rl[i];
3090: for (i=nrl;i<nrg;i++) idxs[i] = -1;
3091: ISRestoreIndices(row,&rl);
3092: ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg);
3093: ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is);
3094: ISLocalToGlobalMappingCreateIS(is,&rl2g);
3095: ISDestroy(&is);
3096: /* compute new l2g map for columns */
3097: if (col != row || A->rmap->mapping != A->cmap->mapping) {
3098: const PetscInt *cg,*cl;
3099: PetscInt ncg;
3100: PetscInt ncl;
3102: ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg);
3103: ISGetLocalSize(col,&ncl);
3104: ISGetIndices(col,&cl);
3105: ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg);
3106: #if defined(PETSC_USE_DEBUG)
3107: for (i=0;i<ncl;i++) if (cl[i]>=ncg) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local column index %D -> %D greater then maximum possible %D",i,cl[i],ncg);
3108: #endif
3109: PetscMalloc1(ncg,&idxs);
3110: /* map from [0,ncl) to col */
3111: for (i=0;i<ncl;i++) idxs[i] = cl[i];
3112: for (i=ncl;i<ncg;i++) idxs[i] = -1;
3113: ISRestoreIndices(col,&cl);
3114: ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg);
3115: ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is);
3116: ISLocalToGlobalMappingCreateIS(is,&cl2g);
3117: ISDestroy(&is);
3118: } else {
3119: PetscObjectReference((PetscObject)rl2g);
3120: cl2g = rl2g;
3121: }
3122: /* create the MATIS submatrix */
3123: MatGetSize(A,&M,&N);
3124: MatCreate(PetscObjectComm((PetscObject)A),submat);
3125: MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N);
3126: MatSetType(*submat,MATIS);
3127: matis = (Mat_IS*)((*submat)->data);
3128: matis->islocalref = PETSC_TRUE;
3129: MatSetLocalToGlobalMapping(*submat,rl2g,cl2g);
3130: MatISGetLocalMat(A,&lA);
3131: MatISSetLocalMat(*submat,lA);
3132: MatSetUp(*submat);
3133: MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY);
3134: MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY);
3135: ISLocalToGlobalMappingDestroy(&rl2g);
3136: ISLocalToGlobalMappingDestroy(&cl2g);
3137: /* remove unsupported ops */
3138: PetscMemzero((*submat)->ops,sizeof(struct _MatOps));
3139: (*submat)->ops->destroy = MatDestroy_IS;
3140: (*submat)->ops->setvalueslocal = MatSetValuesLocal_SubMat_IS;
3141: (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS;
3142: (*submat)->ops->assemblybegin = MatAssemblyBegin_IS;
3143: (*submat)->ops->assemblyend = MatAssemblyEnd_IS;
3144: return(0);
3145: }
3147: static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A)
3148: {
3149: Mat_IS *a = (Mat_IS*)A->data;
3150: char type[256];
3151: PetscBool flg;
3155: PetscOptionsHead(PetscOptionsObject,"MATIS options");
3156: PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns","MatISFixLocalEmpty",a->locempty,&a->locempty,NULL);
3157: PetscOptionsBool("-matis_storel2l","Store local-to-local matrices generated from PtAP operations","MatISStoreL2L",a->storel2l,&a->storel2l,NULL);
3158: PetscOptionsFList("-matis_localmat_type","Matrix type","MatISSetLocalMatType",MatList,a->lmattype,type,256,&flg);
3159: if (flg) {
3160: MatISSetLocalMatType(A,type);
3161: }
3162: if (a->A) {
3163: MatSetFromOptions(a->A);
3164: }
3165: PetscOptionsTail();
3166: return(0);
3167: }
3169: /*@
3170: MatCreateIS - Creates a "process" unassembled matrix, assembled on each
3171: process but not across processes.
3173: Input Parameters:
3174: + comm - MPI communicator that will share the matrix
3175: . bs - block size of the matrix
3176: . m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products
3177: . rmap - local to global map for rows
3178: - cmap - local to global map for cols
3180: Output Parameter:
3181: . A - the resulting matrix
3183: Level: advanced
3185: Notes:
3186: See MATIS for more details.
3187: m and n are NOT related to the size of the map; they represent the size of the local parts of the vectors
3188: used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices.
3189: If either rmap or cmap are NULL, then the matrix is assumed to be square.
3191: .seealso: MATIS, MatSetLocalToGlobalMapping()
3192: @*/
3193: PetscErrorCode MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A)
3194: {
3198: if (!rmap && !cmap) SETERRQ(comm,PETSC_ERR_USER,"You need to provide at least one of the mappings");
3199: MatCreate(comm,A);
3200: MatSetSizes(*A,m,n,M,N);
3201: if (bs > 0) {
3202: MatSetBlockSize(*A,bs);
3203: }
3204: MatSetType(*A,MATIS);
3205: if (rmap && cmap) {
3206: MatSetLocalToGlobalMapping(*A,rmap,cmap);
3207: } else if (!rmap) {
3208: MatSetLocalToGlobalMapping(*A,cmap,cmap);
3209: } else {
3210: MatSetLocalToGlobalMapping(*A,rmap,rmap);
3211: }
3212: return(0);
3213: }
3215: /*MC
3216: MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP).
3217: This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector
3218: product is handled "implicitly".
3220: Options Database Keys:
3221: + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions()
3222: . -matis_fixempty - Fixes local matrices in case of empty local rows/columns.
3223: - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP().
3225: Notes:
3226: Options prefix for the inner matrix are given by -is_mat_xxx
3228: You must call MatSetLocalToGlobalMapping() before using this matrix type.
3230: You can do matrix preallocation on the local matrix after you obtain it with
3231: MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation()
3233: Level: advanced
3235: .seealso: Mat, MatISGetLocalMat(), MatSetLocalToGlobalMapping(), MatISSetPreallocation(), MatCreateIS(), PCBDDC, KSPFETIDP
3237: M*/
3239: PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A)
3240: {
3242: Mat_IS *b;
3245: PetscNewLog(A,&b);
3246: PetscStrallocpy(MATAIJ,&b->lmattype);
3247: A->data = (void*)b;
3249: /* matrix ops */
3250: PetscMemzero(A->ops,sizeof(struct _MatOps));
3251: A->ops->mult = MatMult_IS;
3252: A->ops->multadd = MatMultAdd_IS;
3253: A->ops->multtranspose = MatMultTranspose_IS;
3254: A->ops->multtransposeadd = MatMultTransposeAdd_IS;
3255: A->ops->destroy = MatDestroy_IS;
3256: A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS;
3257: A->ops->setvalues = MatSetValues_IS;
3258: A->ops->setvaluesblocked = MatSetValuesBlocked_IS;
3259: A->ops->setvalueslocal = MatSetValuesLocal_IS;
3260: A->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_IS;
3261: A->ops->zerorows = MatZeroRows_IS;
3262: A->ops->zerorowscolumns = MatZeroRowsColumns_IS;
3263: A->ops->assemblybegin = MatAssemblyBegin_IS;
3264: A->ops->assemblyend = MatAssemblyEnd_IS;
3265: A->ops->view = MatView_IS;
3266: A->ops->zeroentries = MatZeroEntries_IS;
3267: A->ops->scale = MatScale_IS;
3268: A->ops->getdiagonal = MatGetDiagonal_IS;
3269: A->ops->setoption = MatSetOption_IS;
3270: A->ops->ishermitian = MatIsHermitian_IS;
3271: A->ops->issymmetric = MatIsSymmetric_IS;
3272: A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS;
3273: A->ops->duplicate = MatDuplicate_IS;
3274: A->ops->missingdiagonal = MatMissingDiagonal_IS;
3275: A->ops->copy = MatCopy_IS;
3276: A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_IS;
3277: A->ops->createsubmatrix = MatCreateSubMatrix_IS;
3278: A->ops->axpy = MatAXPY_IS;
3279: A->ops->diagonalset = MatDiagonalSet_IS;
3280: A->ops->shift = MatShift_IS;
3281: A->ops->transpose = MatTranspose_IS;
3282: A->ops->getinfo = MatGetInfo_IS;
3283: A->ops->diagonalscale = MatDiagonalScale_IS;
3284: A->ops->setfromoptions = MatSetFromOptions_IS;
3286: /* special MATIS functions */
3287: PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",MatISSetLocalMatType_IS);
3288: PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS);
3289: PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS);
3290: PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS);
3291: PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatConvert_IS_XAIJ);
3292: PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS);
3293: PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",MatISStoreL2L_IS);
3294: PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",MatISFixLocalEmpty_IS);
3295: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",MatConvert_IS_XAIJ);
3296: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",MatConvert_IS_XAIJ);
3297: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",MatConvert_IS_XAIJ);
3298: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",MatConvert_IS_XAIJ);
3299: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",MatConvert_IS_XAIJ);
3300: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",MatConvert_IS_XAIJ);
3301: PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",MatConvert_IS_XAIJ);
3302: PetscObjectChangeTypeName((PetscObject)A,MATIS);
3303: return(0);
3304: }