Actual source code: bdiag.c
1: #define PETSCMAT_DLL
3: /* Block diagonal matrix format */
5: #include src/mat/impls/bdiag/seq/bdiag.h
6: #include src/inline/ilu.h
10: PetscErrorCode MatDestroy_SeqBDiag(Mat A)
11: {
12: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
14: PetscInt i,bs = A->rmap.bs;
17: #if defined(PETSC_USE_LOG)
18: PetscLogObjectState((PetscObject)A,"Rows=%D, Cols=%D, NZ=%D, BSize=%D, NDiag=%D",A->rmap.N,A->cmap.n,a->nz,A->rmap.bs,a->nd);
19: #endif
20: if (!a->user_alloc) { /* Free the actual diagonals */
21: for (i=0; i<a->nd; i++) {
22: if (a->diag[i] > 0) {
23: PetscScalar *dummy = a->diagv[i] + bs*bs*a->diag[i];
24: PetscFree(dummy);
25: } else {
26: PetscFree(a->diagv[i]);
27: }
28: }
29: }
30: PetscFree(a->pivot);
31: PetscFree(a->diagv);
32: PetscFree(a->diag);
33: PetscFree(a->colloc);
34: PetscFree(a->dvalue);
35: PetscFree(a->solvework);
36: PetscFree(a);
37: PetscObjectComposeFunction((PetscObject)A,"MatSeqBDiagSetPreallocation_C","",PETSC_NULL);
38: return(0);
39: }
43: PetscErrorCode MatAssemblyEnd_SeqBDiag(Mat A,MatAssemblyType mode)
44: {
45: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
46: PetscInt i,k,temp,*diag = a->diag,*bdlen = a->bdlen;
47: PetscScalar *dtemp,**dv = a->diagv;
51: if (mode == MAT_FLUSH_ASSEMBLY) return(0);
53: /* Sort diagonals */
54: for (i=0; i<a->nd; i++) {
55: for (k=i+1; k<a->nd; k++) {
56: if (diag[i] < diag[k]) {
57: temp = diag[i];
58: diag[i] = diag[k];
59: diag[k] = temp;
60: temp = bdlen[i];
61: bdlen[i] = bdlen[k];
62: bdlen[k] = temp;
63: dtemp = dv[i];
64: dv[i] = dv[k];
65: dv[k] = dtemp;
66: }
67: }
68: }
70: /* Set location of main diagonal */
71: for (i=0; i<a->nd; i++) {
72: if (!a->diag[i]) {a->mainbd = i; break;}
73: }
74: PetscInfo3(A,"Number diagonals %D,memory used %D, block size %D\n",a->nd,a->maxnz,A->rmap.bs);
75: return(0);
76: }
80: PetscErrorCode MatSetOption_SeqBDiag(Mat A,MatOption op)
81: {
82: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
86: switch (op) {
87: case MAT_NO_NEW_NONZERO_LOCATIONS:
88: a->nonew = 1;
89: break;
90: case MAT_YES_NEW_NONZERO_LOCATIONS:
91: a->nonew = 0;
92: break;
93: case MAT_NO_NEW_DIAGONALS:
94: a->nonew_diag = 1;
95: break;
96: case MAT_YES_NEW_DIAGONALS:
97: a->nonew_diag = 0;
98: break;
99: case MAT_COLUMN_ORIENTED:
100: a->roworiented = PETSC_FALSE;
101: break;
102: case MAT_ROW_ORIENTED:
103: a->roworiented = PETSC_TRUE;
104: break;
105: case MAT_ROWS_SORTED:
106: case MAT_ROWS_UNSORTED:
107: case MAT_COLUMNS_SORTED:
108: case MAT_COLUMNS_UNSORTED:
109: case MAT_IGNORE_OFF_PROC_ENTRIES:
110: case MAT_NEW_NONZERO_LOCATION_ERR:
111: case MAT_NEW_NONZERO_ALLOCATION_ERR:
112: case MAT_USE_HASH_TABLE:
113: PetscInfo(A,"Option ignored\n");
114: break;
115: case MAT_SYMMETRIC:
116: case MAT_STRUCTURALLY_SYMMETRIC:
117: case MAT_NOT_SYMMETRIC:
118: case MAT_NOT_STRUCTURALLY_SYMMETRIC:
119: case MAT_HERMITIAN:
120: case MAT_NOT_HERMITIAN:
121: case MAT_SYMMETRY_ETERNAL:
122: case MAT_NOT_SYMMETRY_ETERNAL:
123: break;
124: default:
125: SETERRQ(PETSC_ERR_SUP,"unknown option");
126: }
127: return(0);
128: }
132: PetscErrorCode MatPrintHelp_SeqBDiag(Mat A)
133: {
134: static PetscTruth called = PETSC_FALSE;
135: MPI_Comm comm = A->comm;
136: PetscErrorCode ierr;
139: if (called) {return(0);} else called = PETSC_TRUE;
140: (*PetscHelpPrintf)(comm," Options for MATSEQBDIAG and MATMPIBDIAG matrix formats:\n");
141: (*PetscHelpPrintf)(comm," -mat_block_size <block_size>\n");
142: (*PetscHelpPrintf)(comm," -mat_bdiag_diags <d1,d2,d3,...> (diagonal numbers)\n");
143: (*PetscHelpPrintf)(comm," (for example) -mat_bdiag_diags -5,-1,0,1,5\n");
144: return(0);
145: }
149: static PetscErrorCode MatGetDiagonal_SeqBDiag_N(Mat A,Vec v)
150: {
151: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
153: PetscInt i,j,n,len,ibase,bs = A->rmap.bs,iloc;
154: PetscScalar *x,*dd,zero = 0.0;
157: if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
158: VecSet(v,zero);
159: VecGetLocalSize(v,&n);
160: if (n != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"Nonconforming mat and vec");
161: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal not set");
162: len = PetscMin(a->mblock,a->nblock);
163: dd = a->diagv[a->mainbd];
164: VecGetArray(v,&x);
165: for (i=0; i<len; i++) {
166: ibase = i*bs*bs; iloc = i*bs;
167: for (j=0; j<bs; j++) x[j + iloc] = dd[ibase + j*(bs+1)];
168: }
169: VecRestoreArray(v,&x);
170: return(0);
171: }
175: static PetscErrorCode MatGetDiagonal_SeqBDiag_1(Mat A,Vec v)
176: {
177: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
179: PetscInt i,n,len;
180: PetscScalar *x,*dd,zero = 0.0;
183: VecSet(v,zero);
184: VecGetLocalSize(v,&n);
185: if (n != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"Nonconforming mat and vec");
186: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal not set");
187: dd = a->diagv[a->mainbd];
188: len = PetscMin(A->rmap.n,A->cmap.n);
189: VecGetArray(v,&x);
190: for (i=0; i<len; i++) x[i] = dd[i];
191: VecRestoreArray(v,&x);
192: return(0);
193: }
197: PetscErrorCode MatZeroEntries_SeqBDiag(Mat A)
198: {
199: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
200: PetscInt d,i,len,bs = A->rmap.bs;
201: PetscScalar *dv;
204: for (d=0; d<a->nd; d++) {
205: dv = a->diagv[d];
206: if (a->diag[d] > 0) {
207: dv += bs*bs*a->diag[d];
208: }
209: len = a->bdlen[d]*bs*bs;
210: for (i=0; i<len; i++) dv[i] = 0.0;
211: }
212: return(0);
213: }
217: PetscErrorCode MatZeroRows_SeqBDiag(Mat A,PetscInt N,const PetscInt rows[],PetscScalar diag)
218: {
219: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
221: PetscInt i,m = A->rmap.N - 1,nz;
222: PetscScalar *dd;
223: PetscScalar *val;
226: for (i=0; i<N; i++) {
227: if (rows[i]<0 || rows[i]>m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"row out of range");
228: MatGetRow_SeqBDiag(A,rows[i],&nz,PETSC_NULL,&val);
229: PetscMemzero((void*)val,nz*sizeof(PetscScalar));
230: MatRestoreRow_SeqBDiag(A,rows[i],&nz,PETSC_NULL,&val);
231: }
232: if (diag != 0.0) {
233: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal does not exist");
234: dd = a->diagv[a->mainbd];
235: for (i=0; i<N; i++) dd[rows[i]] = diag;
236: }
237: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
238: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
239: return(0);
240: }
244: PetscErrorCode MatGetSubMatrix_SeqBDiag(Mat A,IS isrow,IS iscol,MatReuse scall,Mat *submat)
245: {
247: PetscInt nznew,*smap,i,j,oldcols = A->cmap.n;
248: PetscInt *irow,*icol,newr,newc,*cwork,nz,bs;
249: PetscInt *col;
250: PetscScalar *vwork;
251: PetscScalar *val;
252: Mat newmat;
255: if (scall == MAT_REUSE_MATRIX) { /* no support for reuse so simply destroy all */
256: MatDestroy(*submat);
257: }
259: ISGetIndices(isrow,&irow);
260: ISGetIndices(iscol,&icol);
261: ISGetLocalSize(isrow,&newr);
262: ISGetLocalSize(iscol,&newc);
264: PetscMalloc((oldcols+1)*sizeof(PetscInt),&smap);
265: PetscMalloc((newc+1)*sizeof(PetscInt),&cwork);
266: PetscMalloc((newc+1)*sizeof(PetscScalar),&vwork);
267: PetscMemzero((char*)smap,oldcols*sizeof(PetscInt));
268: for (i=0; i<newc; i++) smap[icol[i]] = i+1;
270: /* Determine diagonals; then create submatrix */
271: bs = A->rmap.bs; /* Default block size remains the same */
272: MatCreate(A->comm,&newmat);
273: MatSetSizes(newmat,newr,newc,newr,newc);
274: MatSetType(newmat,A->type_name);
275: MatSeqBDiagSetPreallocation(newmat,0,bs,PETSC_NULL,PETSC_NULL);
277: /* Fill new matrix */
278: for (i=0; i<newr; i++) {
279: MatGetRow_SeqBDiag(A,irow[i],&nz,&col,&val);
280: nznew = 0;
281: for (j=0; j<nz; j++) {
282: if (smap[col[j]]) {
283: cwork[nznew] = smap[col[j]] - 1;
284: vwork[nznew++] = val[j];
285: }
286: }
287: MatSetValues(newmat,1,&i,nznew,cwork,vwork,INSERT_VALUES);
288: MatRestoreRow_SeqBDiag(A,i,&nz,&col,&val);
289: }
290: MatAssemblyBegin(newmat,MAT_FINAL_ASSEMBLY);
291: MatAssemblyEnd(newmat,MAT_FINAL_ASSEMBLY);
293: /* Free work space */
294: PetscFree(smap);
295: PetscFree(cwork);
296: PetscFree(vwork);
297: ISRestoreIndices(isrow,&irow);
298: ISRestoreIndices(iscol,&icol);
299: *submat = newmat;
300: return(0);
301: }
305: PetscErrorCode MatGetSubMatrices_SeqBDiag(Mat A,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat *B[])
306: {
308: PetscInt i;
311: if (scall == MAT_INITIAL_MATRIX) {
312: PetscMalloc((n+1)*sizeof(Mat),B);
313: }
315: for (i=0; i<n; i++) {
316: MatGetSubMatrix_SeqBDiag(A,irow[i],icol[i],scall,&(*B)[i]);
317: }
318: return(0);
319: }
323: PetscErrorCode MatScale_SeqBDiag(Mat inA,PetscScalar alpha)
324: {
325: Mat_SeqBDiag *a = (Mat_SeqBDiag*)inA->data;
326: PetscInt i,bs = inA->rmap.bs;
327: PetscScalar oalpha = alpha;
328: PetscBLASInt one = 1,len;
332: for (i=0; i<a->nd; i++) {
333: len = (PetscBLASInt)bs*bs*a->bdlen[i];
334: if (a->diag[i] > 0) {
335: BLASscal_(&len,&oalpha,a->diagv[i] + bs*bs*a->diag[i],&one);
336: } else {
337: BLASscal_(&len,&oalpha,a->diagv[i],&one);
338: }
339: }
340: PetscLogFlops(a->nz);
341: return(0);
342: }
346: PetscErrorCode MatDiagonalScale_SeqBDiag(Mat A,Vec ll,Vec rr)
347: {
348: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
349: PetscScalar *l,*r,*dv;
351: PetscInt d,j,len;
352: PetscInt nd = a->nd,bs = A->rmap.bs,diag,m,n;
355: if (ll) {
356: VecGetSize(ll,&m);
357: if (m != A->rmap.N) SETERRQ(PETSC_ERR_ARG_SIZ,"Left scaling vector wrong length");
358: if (bs == 1) {
359: VecGetArray(ll,&l);
360: for (d=0; d<nd; d++) {
361: dv = a->diagv[d];
362: diag = a->diag[d];
363: len = a->bdlen[d];
364: if (diag > 0) for (j=0; j<len; j++) dv[j+diag] *= l[j+diag];
365: else for (j=0; j<len; j++) dv[j] *= l[j];
366: }
367: VecRestoreArray(ll,&l);
368: PetscLogFlops(a->nz);
369: } else SETERRQ(PETSC_ERR_SUP,"Not yet done for bs>1");
370: }
371: if (rr) {
372: VecGetSize(rr,&n);
373: if (n != A->cmap.n) SETERRQ(PETSC_ERR_ARG_SIZ,"Right scaling vector wrong length");
374: if (bs == 1) {
375: VecGetArray(rr,&r);
376: for (d=0; d<nd; d++) {
377: dv = a->diagv[d];
378: diag = a->diag[d];
379: len = a->bdlen[d];
380: if (diag > 0) for (j=0; j<len; j++) dv[j+diag] *= r[j];
381: else for (j=0; j<len; j++) dv[j] *= r[j-diag];
382: }
383: VecRestoreArray(rr,&r);
384: PetscLogFlops(a->nz);
385: } else SETERRQ(PETSC_ERR_SUP,"Not yet done for bs>1");
386: }
387: return(0);
388: }
390: static PetscErrorCode MatDuplicate_SeqBDiag(Mat,MatDuplicateOption,Mat *);
394: PetscErrorCode MatSetUpPreallocation_SeqBDiag(Mat A)
395: {
399: MatSeqBDiagSetPreallocation(A,PETSC_DEFAULT,PETSC_DEFAULT,0,0);
400: return(0);
401: }
403: /* -------------------------------------------------------------------*/
404: static struct _MatOps MatOps_Values = {MatSetValues_SeqBDiag_N,
405: MatGetRow_SeqBDiag,
406: MatRestoreRow_SeqBDiag,
407: MatMult_SeqBDiag_N,
408: /* 4*/ MatMultAdd_SeqBDiag_N,
409: MatMultTranspose_SeqBDiag_N,
410: MatMultTransposeAdd_SeqBDiag_N,
411: MatSolve_SeqBDiag_N,
412: 0,
413: 0,
414: /*10*/ 0,
415: 0,
416: 0,
417: MatRelax_SeqBDiag_N,
418: MatTranspose_SeqBDiag,
419: /*15*/ MatGetInfo_SeqBDiag,
420: 0,
421: MatGetDiagonal_SeqBDiag_N,
422: MatDiagonalScale_SeqBDiag,
423: MatNorm_SeqBDiag,
424: /*20*/ 0,
425: MatAssemblyEnd_SeqBDiag,
426: 0,
427: MatSetOption_SeqBDiag,
428: MatZeroEntries_SeqBDiag,
429: /*25*/ MatZeroRows_SeqBDiag,
430: 0,
431: MatLUFactorNumeric_SeqBDiag_N,
432: 0,
433: 0,
434: /*30*/ MatSetUpPreallocation_SeqBDiag,
435: MatILUFactorSymbolic_SeqBDiag,
436: 0,
437: 0,
438: 0,
439: /*35*/ MatDuplicate_SeqBDiag,
440: 0,
441: 0,
442: MatILUFactor_SeqBDiag,
443: 0,
444: /*40*/ 0,
445: MatGetSubMatrices_SeqBDiag,
446: 0,
447: MatGetValues_SeqBDiag_N,
448: 0,
449: /*45*/ MatPrintHelp_SeqBDiag,
450: MatScale_SeqBDiag,
451: 0,
452: 0,
453: 0,
454: /*50*/ 0,
455: 0,
456: 0,
457: 0,
458: 0,
459: /*55*/ 0,
460: 0,
461: 0,
462: 0,
463: 0,
464: /*60*/ 0,
465: MatDestroy_SeqBDiag,
466: MatView_SeqBDiag,
467: 0,
468: 0,
469: /*65*/ 0,
470: 0,
471: 0,
472: 0,
473: 0,
474: /*70*/ 0,
475: 0,
476: 0,
477: 0,
478: 0,
479: /*75*/ 0,
480: 0,
481: 0,
482: 0,
483: 0,
484: /*80*/ 0,
485: 0,
486: 0,
487: 0,
488: MatLoad_SeqBDiag,
489: /*85*/ 0,
490: 0,
491: 0,
492: 0,
493: 0,
494: /*90*/ 0,
495: 0,
496: 0,
497: 0,
498: 0,
499: /*95*/ 0,
500: 0,
501: 0,
502: 0};
506: /*@C
507: MatSeqBDiagSetPreallocation - Sets the nonzero structure and (optionally) arrays.
509: Collective on MPI_Comm
511: Input Parameters:
512: + B - the matrix
513: . nd - number of block diagonals (optional)
514: . bs - each element of a diagonal is an bs x bs dense matrix
515: . diag - optional array of block diagonal numbers (length nd).
516: For a matrix element A[i,j], where i=row and j=column, the
517: diagonal number is
518: $ diag = i/bs - j/bs (integer division)
519: Set diag=PETSC_NULL on input for PETSc to dynamically allocate memory as
520: needed (expensive).
521: - diagv - pointer to actual diagonals (in same order as diag array),
522: if allocated by user. Otherwise, set diagv=PETSC_NULL on input for PETSc
523: to control memory allocation.
525: Options Database Keys:
526: . -mat_block_size <bs> - Sets blocksize
527: . -mat_bdiag_diags <s1,s2,s3,...> - Sets diagonal numbers
529: Notes:
530: See the users manual for further details regarding this storage format.
532: Fortran Note:
533: Fortran programmers cannot set diagv; this value is ignored.
535: Level: intermediate
537: .keywords: matrix, block, diagonal, sparse
539: .seealso: MatCreate(), MatCreateMPIBDiag(), MatSetValues()
540: @*/
541: PetscErrorCode PETSCMAT_DLLEXPORT MatSeqBDiagSetPreallocation(Mat B,PetscInt nd,PetscInt bs,const PetscInt diag[],PetscScalar *diagv[])
542: {
543: PetscErrorCode ierr,(*f)(Mat,PetscInt,PetscInt,const PetscInt[],PetscScalar*[]);
546: PetscObjectQueryFunction((PetscObject)B,"MatSeqBDiagSetPreallocation_C",(void (**)(void))&f);
547: if (f) {
548: (*f)(B,nd,bs,diag,diagv);
549: }
550: return(0);
551: }
556: PetscErrorCode PETSCMAT_DLLEXPORT MatSeqBDiagSetPreallocation_SeqBDiag(Mat B,PetscInt nd,PetscInt bs,PetscInt *diag,PetscScalar **diagv)
557: {
558: Mat_SeqBDiag *b;
560: PetscInt i,nda,sizetot, nd2 = 128,idiag[128];
561: PetscTruth flg1;
565: B->preallocated = PETSC_TRUE;
566: if (bs == PETSC_DEFAULT) bs = 1;
567: if (!bs) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize cannot be zero");
568: if (nd == PETSC_DEFAULT) nd = 0;
569: PetscOptionsGetInt(PETSC_NULL,"-mat_block_size",&bs,PETSC_NULL);
570: PetscOptionsGetIntArray(PETSC_NULL,"-mat_bdiag_diags",idiag,&nd2,&flg1);
571: if (flg1) {
572: diag = idiag;
573: nd = nd2;
574: }
576: B->rmap.bs = B->cmap.bs = bs;
577: PetscMapInitialize(B->comm,&B->rmap);
578: PetscMapInitialize(B->comm,&B->cmap);
580: if ((B->cmap.n%bs) || (B->rmap.N%bs)) SETERRQ(PETSC_ERR_ARG_SIZ,"Invalid block size");
581: if (!nd) nda = nd + 1;
582: else nda = nd;
583: b = (Mat_SeqBDiag*)B->data;
585: PetscOptionsHasName(PETSC_NULL,"-mat_no_unroll",&flg1);
586: if (!flg1) {
587: switch (bs) {
588: case 1:
589: B->ops->setvalues = MatSetValues_SeqBDiag_1;
590: B->ops->getvalues = MatGetValues_SeqBDiag_1;
591: B->ops->getdiagonal = MatGetDiagonal_SeqBDiag_1;
592: B->ops->mult = MatMult_SeqBDiag_1;
593: B->ops->multadd = MatMultAdd_SeqBDiag_1;
594: B->ops->multtranspose = MatMultTranspose_SeqBDiag_1;
595: B->ops->multtransposeadd= MatMultTransposeAdd_SeqBDiag_1;
596: B->ops->relax = MatRelax_SeqBDiag_1;
597: B->ops->solve = MatSolve_SeqBDiag_1;
598: B->ops->lufactornumeric = MatLUFactorNumeric_SeqBDiag_1;
599: break;
600: case 2:
601: B->ops->mult = MatMult_SeqBDiag_2;
602: B->ops->multadd = MatMultAdd_SeqBDiag_2;
603: B->ops->solve = MatSolve_SeqBDiag_2;
604: break;
605: case 3:
606: B->ops->mult = MatMult_SeqBDiag_3;
607: B->ops->multadd = MatMultAdd_SeqBDiag_3;
608: B->ops->solve = MatSolve_SeqBDiag_3;
609: break;
610: case 4:
611: B->ops->mult = MatMult_SeqBDiag_4;
612: B->ops->multadd = MatMultAdd_SeqBDiag_4;
613: B->ops->solve = MatSolve_SeqBDiag_4;
614: break;
615: case 5:
616: B->ops->mult = MatMult_SeqBDiag_5;
617: B->ops->multadd = MatMultAdd_SeqBDiag_5;
618: B->ops->solve = MatSolve_SeqBDiag_5;
619: break;
620: }
621: }
623: b->mblock = B->rmap.N/bs;
624: b->nblock = B->cmap.n/bs;
625: b->nd = nd;
626: B->rmap.bs = bs;
627: b->ndim = 0;
628: b->mainbd = -1;
629: b->pivot = 0;
631: PetscMalloc(2*nda*sizeof(PetscInt),&b->diag);
632: b->bdlen = b->diag + nda;
633: PetscMalloc((B->cmap.n+1)*sizeof(PetscInt),&b->colloc);
634: PetscMalloc(nda*sizeof(PetscScalar*),&b->diagv);
635: sizetot = 0;
637: if (diagv) { /* user allocated space */
638: b->user_alloc = PETSC_TRUE;
639: for (i=0; i<nd; i++) b->diagv[i] = diagv[i];
640: } else b->user_alloc = PETSC_FALSE;
642: for (i=0; i<nd; i++) {
643: b->diag[i] = diag[i];
644: if (diag[i] > 0) { /* lower triangular */
645: b->bdlen[i] = PetscMin(b->nblock,b->mblock - diag[i]);
646: } else { /* upper triangular */
647: b->bdlen[i] = PetscMin(b->mblock,b->nblock + diag[i]);
648: }
649: sizetot += b->bdlen[i];
650: }
651: sizetot *= bs*bs;
652: b->maxnz = sizetot;
653: PetscMalloc((B->cmap.n+1)*sizeof(PetscScalar),&b->dvalue);
654: PetscLogObjectMemory(B,(nda*(bs+2))*sizeof(PetscInt) + bs*nda*sizeof(PetscScalar)
655: + nda*sizeof(PetscScalar*) + sizeof(Mat_SeqBDiag)
656: + sizeof(struct _p_Mat) + sizetot*sizeof(PetscScalar));
658: if (!b->user_alloc) {
659: for (i=0; i<nd; i++) {
660: PetscMalloc(bs*bs*b->bdlen[i]*sizeof(PetscScalar),&b->diagv[i]);
661: PetscMemzero(b->diagv[i],bs*bs*b->bdlen[i]*sizeof(PetscScalar));
662: }
663: b->nonew = 0; b->nonew_diag = 0;
664: } else { /* diagonals are set on input; don't allow dynamic allocation */
665: b->nonew = 1; b->nonew_diag = 1;
666: }
668: /* adjust diagv so one may access rows with diagv[diag][row] for all rows */
669: for (i=0; i<nd; i++) {
670: if (diag[i] > 0) {
671: b->diagv[i] -= bs*bs*diag[i];
672: }
673: }
675: b->nz = b->maxnz; /* Currently not keeping track of exact count */
676: b->roworiented = PETSC_TRUE;
677: B->info.nz_unneeded = (double)b->maxnz;
678: return(0);
679: }
684: static PetscErrorCode MatDuplicate_SeqBDiag(Mat A,MatDuplicateOption cpvalues,Mat *matout)
685: {
686: Mat_SeqBDiag *newmat,*a = (Mat_SeqBDiag*)A->data;
688: PetscInt i,len,diag,bs = A->rmap.bs;
689: Mat mat;
692: MatCreate(A->comm,matout);
693: MatSetSizes(*matout,A->rmap.N,A->cmap.n,A->rmap.N,A->cmap.n);
694: MatSetType(*matout,A->type_name);
695: MatSeqBDiagSetPreallocation(*matout,a->nd,bs,a->diag,PETSC_NULL);
697: /* Copy contents of diagonals */
698: mat = *matout;
699: newmat = (Mat_SeqBDiag*)mat->data;
700: if (cpvalues == MAT_COPY_VALUES) {
701: for (i=0; i<a->nd; i++) {
702: len = a->bdlen[i] * bs * bs * sizeof(PetscScalar);
703: diag = a->diag[i];
704: if (diag > 0) {
705: PetscMemcpy(newmat->diagv[i]+bs*bs*diag,a->diagv[i]+bs*bs*diag,len);
706: } else {
707: PetscMemcpy(newmat->diagv[i],a->diagv[i],len);
708: }
709: }
710: }
711: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
712: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
713: return(0);
714: }
718: PetscErrorCode MatLoad_SeqBDiag(PetscViewer viewer, MatType type,Mat *A)
719: {
720: Mat B;
722: PetscMPIInt size;
723: int fd;
724: PetscInt *scols,i,nz,header[4],nd = 128;
725: PetscInt bs,*rowlengths = 0,M,N,*cols,extra_rows,*diag = 0;
726: PetscInt idiag[128];
727: PetscScalar *vals,*svals;
728: MPI_Comm comm;
729: PetscTruth flg;
730:
732: PetscObjectGetComm((PetscObject)viewer,&comm);
733: MPI_Comm_size(comm,&size);
734: if (size > 1) SETERRQ(PETSC_ERR_ARG_SIZ,"view must have one processor");
735: PetscViewerBinaryGetDescriptor(viewer,&fd);
736: PetscBinaryRead(fd,header,4,PETSC_INT);
737: if (header[0] != MAT_FILE_COOKIE) SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"Not matrix object");
738: M = header[1]; N = header[2]; nz = header[3];
739: if (M != N) SETERRQ(PETSC_ERR_SUP,"Can only load square matrices");
740: if (header[3] < 0) {
741: SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"Matrix stored in special format, cannot load as SeqBDiag");
742: }
744: /*
745: This code adds extra rows to make sure the number of rows is
746: divisible by the blocksize
747: */
748: bs = 1;
749: PetscOptionsGetInt(PETSC_NULL,"-matload_block_size",&bs,PETSC_NULL);
750: extra_rows = bs - M + bs*(M/bs);
751: if (extra_rows == bs) extra_rows = 0;
752: if (extra_rows) {
753: PetscInfo(0,"Padding loaded matrix to match blocksize\n");
754: }
756: /* read row lengths */
757: PetscMalloc((M+extra_rows)*sizeof(PetscInt),&rowlengths);
758: PetscBinaryRead(fd,rowlengths,M,PETSC_INT);
759: for (i=0; i<extra_rows; i++) rowlengths[M+i] = 1;
761: /* load information about diagonals */
762: PetscOptionsGetIntArray(PETSC_NULL,"-matload_bdiag_diags",idiag,&nd,&flg);
763: if (flg) {
764: diag = idiag;
765: }
767: /* create our matrix */
768: MatCreate(comm,A);
769: MatSetSizes(*A,M+extra_rows,M+extra_rows,M+extra_rows,M+extra_rows);
770: MatSetType(*A,type);
771: MatSeqBDiagSetPreallocation(*A,nd,bs,diag,PETSC_NULL);
772: B = *A;
774: /* read column indices and nonzeros */
775: PetscMalloc(nz*sizeof(PetscInt),&scols);
776: cols = scols;
777: PetscBinaryRead(fd,cols,nz,PETSC_INT);
778: PetscMalloc(nz*sizeof(PetscScalar),&svals);
779: vals = svals;
780: PetscBinaryRead(fd,vals,nz,PETSC_SCALAR);
781: /* insert into matrix */
783: for (i=0; i<M; i++) {
784: MatSetValues(B,1,&i,rowlengths[i],scols,svals,INSERT_VALUES);
785: scols += rowlengths[i]; svals += rowlengths[i];
786: }
787: vals[0] = 1.0;
788: for (i=M; i<M+extra_rows; i++) {
789: MatSetValues(B,1,&i,1,&i,vals,INSERT_VALUES);
790: }
792: PetscFree(cols);
793: PetscFree(vals);
794: PetscFree(rowlengths);
796: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
797: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
798: return(0);
799: }
801: /*MC
802: MATSEQBDIAG - MATSEQBDIAG = "seqbdiag" - A matrix type to be used for sequential block diagonal matrices.
804: Options Database Keys:
805: . -mat_type seqbdiag - sets the matrix type to "seqbdiag" during a call to MatSetFromOptions()
807: Level: beginner
809: .seealso: MatCreateSeqBDiag
810: M*/
815: PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_SeqBDiag(Mat B)
816: {
817: Mat_SeqBDiag *b;
819: PetscMPIInt size;
822: MPI_Comm_size(B->comm,&size);
823: if (size > 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Comm must be of size 1");
826: PetscNew(Mat_SeqBDiag,&b);
827: B->data = (void*)b;
828: PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));
829: B->factor = 0;
830: B->mapping = 0;
832: b->ndim = 0;
833: b->mainbd = -1;
834: b->pivot = 0;
836: b->roworiented = PETSC_TRUE;
837: PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSeqBDiagSetPreallocation_C",
838: "MatSeqBDiagSetPreallocation_SeqBDiag",
839: MatSeqBDiagSetPreallocation_SeqBDiag);
841: return(0);
842: }
847: /*@C
848: MatCreateSeqBDiag - Creates a sequential block diagonal matrix.
850: Collective on MPI_Comm
852: Input Parameters:
853: + comm - MPI communicator, set to PETSC_COMM_SELF
854: . m - number of rows
855: . n - number of columns
856: . nd - number of block diagonals (optional)
857: . bs - each element of a diagonal is an bs x bs dense matrix
858: . diag - optional array of block diagonal numbers (length nd).
859: For a matrix element A[i,j], where i=row and j=column, the
860: diagonal number is
861: $ diag = i/bs - j/bs (integer division)
862: Set diag=PETSC_NULL on input for PETSc to dynamically allocate memory as
863: needed (expensive).
864: - diagv - pointer to actual diagonals (in same order as diag array),
865: if allocated by user. Otherwise, set diagv=PETSC_NULL on input for PETSc
866: to control memory allocation.
868: Output Parameters:
869: . A - the matrix
871: Options Database Keys:
872: . -mat_block_size <bs> - Sets blocksize
873: . -mat_bdiag_diags <s1,s2,s3,...> - Sets diagonal numbers
875: Notes:
876: See the users manual for further details regarding this storage format.
878: Fortran Note:
879: Fortran programmers cannot set diagv; this value is ignored.
881: Level: intermediate
883: .keywords: matrix, block, diagonal, sparse
885: .seealso: MatCreate(), MatCreateMPIBDiag(), MatSetValues()
886: @*/
887: PetscErrorCode PETSCMAT_DLLEXPORT MatCreateSeqBDiag(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt nd,PetscInt bs,const PetscInt diag[],PetscScalar *diagv[],Mat *A)
888: {
892: MatCreate(comm,A);
893: MatSetSizes(*A,m,n,m,n);
894: MatSetType(*A,MATSEQBDIAG);
895: MatSeqBDiagSetPreallocation(*A,nd,bs,diag,diagv);
896: return(0);
897: }