Actual source code: bdiag.c
2: /* Block diagonal matrix format */
4: #include src/mat/impls/bdiag/seq/bdiag.h
5: #include src/inline/ilu.h
9: PetscErrorCode MatDestroy_SeqBDiag(Mat A)
10: {
11: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
13: PetscInt i,bs = A->bs;
16: #if defined(PETSC_USE_LOG)
17: PetscLogObjectState((PetscObject)A,"Rows=%D, Cols=%D, NZ=%D, BSize=%D, NDiag=%D",A->m,A->n,a->nz,A->bs,a->nd);
18: #endif
19: if (!a->user_alloc) { /* Free the actual diagonals */
20: for (i=0; i<a->nd; i++) {
21: if (a->diag[i] > 0) {
22: PetscScalar *dummy = a->diagv[i] + bs*bs*a->diag[i];
23: PetscFree(dummy);
24: } else {
25: PetscFree(a->diagv[i]);
26: }
27: }
28: }
29: if (a->pivot) {PetscFree(a->pivot);}
30: PetscFree(a->diagv);
31: PetscFree(a->diag);
32: PetscFree(a->colloc);
33: PetscFree(a->dvalue);
34: if (a->solvework) {PetscFree(a->solvework);}
35: PetscFree(a);
36: PetscObjectComposeFunction((PetscObject)A,"MatSeqBDiagSetPreallocation_C","",PETSC_NULL);
37: return(0);
38: }
42: PetscErrorCode MatAssemblyEnd_SeqBDiag(Mat A,MatAssemblyType mode)
43: {
44: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
45: PetscInt i,k,temp,*diag = a->diag,*bdlen = a->bdlen;
46: PetscScalar *dtemp,**dv = a->diagv;
49: if (mode == MAT_FLUSH_ASSEMBLY) return(0);
51: /* Sort diagonals */
52: for (i=0; i<a->nd; i++) {
53: for (k=i+1; k<a->nd; k++) {
54: if (diag[i] < diag[k]) {
55: temp = diag[i];
56: diag[i] = diag[k];
57: diag[k] = temp;
58: temp = bdlen[i];
59: bdlen[i] = bdlen[k];
60: bdlen[k] = temp;
61: dtemp = dv[i];
62: dv[i] = dv[k];
63: dv[k] = dtemp;
64: }
65: }
66: }
68: /* Set location of main diagonal */
69: for (i=0; i<a->nd; i++) {
70: if (!a->diag[i]) {a->mainbd = i; break;}
71: }
72: PetscLogInfo(A,"MatAssemblyEnd_SeqBDiag:Number diagonals %D,memory used %D, block size %D\n",a->nd,a->maxnz,A->bs);
73: return(0);
74: }
78: PetscErrorCode MatSetOption_SeqBDiag(Mat A,MatOption op)
79: {
80: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
83: switch (op) {
84: case MAT_NO_NEW_NONZERO_LOCATIONS:
85: a->nonew = 1;
86: break;
87: case MAT_YES_NEW_NONZERO_LOCATIONS:
88: a->nonew = 0;
89: break;
90: case MAT_NO_NEW_DIAGONALS:
91: a->nonew_diag = 1;
92: break;
93: case MAT_YES_NEW_DIAGONALS:
94: a->nonew_diag = 0;
95: break;
96: case MAT_COLUMN_ORIENTED:
97: a->roworiented = PETSC_FALSE;
98: break;
99: case MAT_ROW_ORIENTED:
100: a->roworiented = PETSC_TRUE;
101: break;
102: case MAT_ROWS_SORTED:
103: case MAT_ROWS_UNSORTED:
104: case MAT_COLUMNS_SORTED:
105: case MAT_COLUMNS_UNSORTED:
106: case MAT_IGNORE_OFF_PROC_ENTRIES:
107: case MAT_NEW_NONZERO_LOCATION_ERR:
108: case MAT_NEW_NONZERO_ALLOCATION_ERR:
109: case MAT_USE_HASH_TABLE:
110: PetscLogInfo(A,"MatSetOption_SeqBDiag:Option ignored\n");
111: break;
112: case MAT_SYMMETRIC:
113: case MAT_STRUCTURALLY_SYMMETRIC:
114: case MAT_NOT_SYMMETRIC:
115: case MAT_NOT_STRUCTURALLY_SYMMETRIC:
116: case MAT_HERMITIAN:
117: case MAT_NOT_HERMITIAN:
118: case MAT_SYMMETRY_ETERNAL:
119: case MAT_NOT_SYMMETRY_ETERNAL:
120: break;
121: default:
122: SETERRQ(PETSC_ERR_SUP,"unknown option");
123: }
124: return(0);
125: }
129: PetscErrorCode MatPrintHelp_SeqBDiag(Mat A)
130: {
131: static PetscTruth called = PETSC_FALSE;
132: MPI_Comm comm = A->comm;
133: PetscErrorCode ierr;
136: if (called) {return(0);} else called = PETSC_TRUE;
137: (*PetscHelpPrintf)(comm," Options for MATSEQBDIAG and MATMPIBDIAG matrix formats:\n");
138: (*PetscHelpPrintf)(comm," -mat_block_size <block_size>\n");
139: (*PetscHelpPrintf)(comm," -mat_bdiag_diags <d1,d2,d3,...> (diagonal numbers)\n");
140: (*PetscHelpPrintf)(comm," (for example) -mat_bdiag_diags -5,-1,0,1,5\n");
141: return(0);
142: }
146: static PetscErrorCode MatGetDiagonal_SeqBDiag_N(Mat A,Vec v)
147: {
148: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
150: PetscInt i,j,n,len,ibase,bs = A->bs,iloc;
151: PetscScalar *x,*dd,zero = 0.0;
154: if (A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Not for factored matrix");
155: VecSet(&zero,v);
156: VecGetLocalSize(v,&n);
157: if (n != A->m) SETERRQ(PETSC_ERR_ARG_SIZ,"Nonconforming mat and vec");
158: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal not set");
159: len = PetscMin(a->mblock,a->nblock);
160: dd = a->diagv[a->mainbd];
161: VecGetArray(v,&x);
162: for (i=0; i<len; i++) {
163: ibase = i*bs*bs; iloc = i*bs;
164: for (j=0; j<bs; j++) x[j + iloc] = dd[ibase + j*(bs+1)];
165: }
166: VecRestoreArray(v,&x);
167: return(0);
168: }
172: static PetscErrorCode MatGetDiagonal_SeqBDiag_1(Mat A,Vec v)
173: {
174: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
176: PetscInt i,n,len;
177: PetscScalar *x,*dd,zero = 0.0;
180: VecSet(&zero,v);
181: VecGetLocalSize(v,&n);
182: if (n != A->m) SETERRQ(PETSC_ERR_ARG_SIZ,"Nonconforming mat and vec");
183: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal not set");
184: dd = a->diagv[a->mainbd];
185: len = PetscMin(A->m,A->n);
186: VecGetArray(v,&x);
187: for (i=0; i<len; i++) x[i] = dd[i];
188: VecRestoreArray(v,&x);
189: return(0);
190: }
194: PetscErrorCode MatZeroEntries_SeqBDiag(Mat A)
195: {
196: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
197: PetscInt d,i,len,bs = A->bs;
198: PetscScalar *dv;
201: for (d=0; d<a->nd; d++) {
202: dv = a->diagv[d];
203: if (a->diag[d] > 0) {
204: dv += bs*bs*a->diag[d];
205: }
206: len = a->bdlen[d]*bs*bs;
207: for (i=0; i<len; i++) dv[i] = 0.0;
208: }
209: return(0);
210: }
214: PetscErrorCode MatZeroRows_SeqBDiag(Mat A,IS is,const PetscScalar *diag)
215: {
216: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
218: PetscInt i,N,*rows,m = A->m - 1,nz;
219: PetscScalar *dd;
220: PetscScalar *val;
223: ISGetLocalSize(is,&N);
224: ISGetIndices(is,&rows);
225: for (i=0; i<N; i++) {
226: if (rows[i]<0 || rows[i]>m) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"row out of range");
227: MatGetRow_SeqBDiag(A,rows[i],&nz,PETSC_NULL,&val);
228: PetscMemzero((void*)val,nz*sizeof(PetscScalar));
229: MatRestoreRow_SeqBDiag(A,rows[i],&nz,PETSC_NULL,&val);
230: }
231: if (diag) {
232: if (a->mainbd == -1) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Main diagonal does not exist");
233: dd = a->diagv[a->mainbd];
234: for (i=0; i<N; i++) dd[rows[i]] = *diag;
235: }
236: ISRestoreIndices(is,&rows);
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->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->bs; /* Default block size remains the same */
272: MatCreate(A->comm,newr,newc,newr,newc,&newmat);
273: MatSetType(newmat,A->type_name);
274: MatSeqBDiagSetPreallocation(newmat,0,bs,PETSC_NULL,PETSC_NULL);
276: /* Fill new matrix */
277: for (i=0; i<newr; i++) {
278: MatGetRow_SeqBDiag(A,irow[i],&nz,&col,&val);
279: nznew = 0;
280: for (j=0; j<nz; j++) {
281: if (smap[col[j]]) {
282: cwork[nznew] = smap[col[j]] - 1;
283: vwork[nznew++] = val[j];
284: }
285: }
286: MatSetValues(newmat,1,&i,nznew,cwork,vwork,INSERT_VALUES);
287: MatRestoreRow_SeqBDiag(A,i,&nz,&col,&val);
288: }
289: MatAssemblyBegin(newmat,MAT_FINAL_ASSEMBLY);
290: MatAssemblyEnd(newmat,MAT_FINAL_ASSEMBLY);
292: /* Free work space */
293: PetscFree(smap);
294: PetscFree(cwork);
295: PetscFree(vwork);
296: ISRestoreIndices(isrow,&irow);
297: ISRestoreIndices(iscol,&icol);
298: *submat = newmat;
299: return(0);
300: }
304: PetscErrorCode MatGetSubMatrices_SeqBDiag(Mat A,PetscInt n,const IS irow[],const IS icol[],MatReuse scall,Mat *B[])
305: {
307: PetscInt i;
310: if (scall == MAT_INITIAL_MATRIX) {
311: PetscMalloc((n+1)*sizeof(Mat),B);
312: }
314: for (i=0; i<n; i++) {
315: MatGetSubMatrix_SeqBDiag(A,irow[i],icol[i],scall,&(*B)[i]);
316: }
317: return(0);
318: }
322: PetscErrorCode MatScale_SeqBDiag(const PetscScalar *alpha,Mat inA)
323: {
324: Mat_SeqBDiag *a = (Mat_SeqBDiag*)inA->data;
325: PetscInt i,bs = inA->bs;
326: PetscBLASInt one = 1,len;
329: for (i=0; i<a->nd; i++) {
330: len = (PetscBLASInt)bs*bs*a->bdlen[i];
331: if (a->diag[i] > 0) {
332: BLscal_(&len,(PetscScalar*)alpha,a->diagv[i] + bs*bs*a->diag[i],&one);
333: } else {
334: BLscal_(&len,(PetscScalar*)alpha,a->diagv[i],&one);
335: }
336: }
337: PetscLogFlops(a->nz);
338: return(0);
339: }
343: PetscErrorCode MatDiagonalScale_SeqBDiag(Mat A,Vec ll,Vec rr)
344: {
345: Mat_SeqBDiag *a = (Mat_SeqBDiag*)A->data;
346: PetscScalar *l,*r,*dv;
348: PetscInt d,j,len;
349: PetscInt nd = a->nd,bs = A->bs,diag,m,n;
352: if (ll) {
353: VecGetSize(ll,&m);
354: if (m != A->m) SETERRQ(PETSC_ERR_ARG_SIZ,"Left scaling vector wrong length");
355: if (bs == 1) {
356: VecGetArray(ll,&l);
357: for (d=0; d<nd; d++) {
358: dv = a->diagv[d];
359: diag = a->diag[d];
360: len = a->bdlen[d];
361: if (diag > 0) for (j=0; j<len; j++) dv[j+diag] *= l[j+diag];
362: else for (j=0; j<len; j++) dv[j] *= l[j];
363: }
364: VecRestoreArray(ll,&l);
365: PetscLogFlops(a->nz);
366: } else SETERRQ(PETSC_ERR_SUP,"Not yet done for bs>1");
367: }
368: if (rr) {
369: VecGetSize(rr,&n);
370: if (n != A->n) SETERRQ(PETSC_ERR_ARG_SIZ,"Right scaling vector wrong length");
371: if (bs == 1) {
372: VecGetArray(rr,&r);
373: for (d=0; d<nd; d++) {
374: dv = a->diagv[d];
375: diag = a->diag[d];
376: len = a->bdlen[d];
377: if (diag > 0) for (j=0; j<len; j++) dv[j+diag] *= r[j];
378: else for (j=0; j<len; j++) dv[j] *= r[j-diag];
379: }
380: VecRestoreArray(rr,&r);
381: PetscLogFlops(a->nz);
382: } else SETERRQ(PETSC_ERR_SUP,"Not yet done for bs>1");
383: }
384: return(0);
385: }
387: static PetscErrorCode MatDuplicate_SeqBDiag(Mat,MatDuplicateOption,Mat *);
391: PetscErrorCode MatSetUpPreallocation_SeqBDiag(Mat A)
392: {
396: MatSeqBDiagSetPreallocation(A,PETSC_DEFAULT,PETSC_DEFAULT,0,0);
397: return(0);
398: }
400: /* -------------------------------------------------------------------*/
401: static struct _MatOps MatOps_Values = {MatSetValues_SeqBDiag_N,
402: MatGetRow_SeqBDiag,
403: MatRestoreRow_SeqBDiag,
404: MatMult_SeqBDiag_N,
405: /* 4*/ MatMultAdd_SeqBDiag_N,
406: MatMultTranspose_SeqBDiag_N,
407: MatMultTransposeAdd_SeqBDiag_N,
408: MatSolve_SeqBDiag_N,
409: 0,
410: 0,
411: /*10*/ 0,
412: 0,
413: 0,
414: MatRelax_SeqBDiag_N,
415: MatTranspose_SeqBDiag,
416: /*15*/ MatGetInfo_SeqBDiag,
417: 0,
418: MatGetDiagonal_SeqBDiag_N,
419: MatDiagonalScale_SeqBDiag,
420: MatNorm_SeqBDiag,
421: /*20*/ 0,
422: MatAssemblyEnd_SeqBDiag,
423: 0,
424: MatSetOption_SeqBDiag,
425: MatZeroEntries_SeqBDiag,
426: /*25*/ MatZeroRows_SeqBDiag,
427: 0,
428: MatLUFactorNumeric_SeqBDiag_N,
429: 0,
430: 0,
431: /*30*/ MatSetUpPreallocation_SeqBDiag,
432: MatILUFactorSymbolic_SeqBDiag,
433: 0,
434: 0,
435: 0,
436: /*35*/ MatDuplicate_SeqBDiag,
437: 0,
438: 0,
439: MatILUFactor_SeqBDiag,
440: 0,
441: /*40*/ 0,
442: MatGetSubMatrices_SeqBDiag,
443: 0,
444: MatGetValues_SeqBDiag_N,
445: 0,
446: /*45*/ MatPrintHelp_SeqBDiag,
447: MatScale_SeqBDiag,
448: 0,
449: 0,
450: 0,
451: /*50*/ 0,
452: 0,
453: 0,
454: 0,
455: 0,
456: /*55*/ 0,
457: 0,
458: 0,
459: 0,
460: 0,
461: /*60*/ 0,
462: MatDestroy_SeqBDiag,
463: MatView_SeqBDiag,
464: MatGetPetscMaps_Petsc,
465: 0,
466: /*65*/ 0,
467: 0,
468: 0,
469: 0,
470: 0,
471: /*70*/ 0,
472: 0,
473: 0,
474: 0,
475: 0,
476: /*75*/ 0,
477: 0,
478: 0,
479: 0,
480: 0,
481: /*80*/ 0,
482: 0,
483: 0,
484: 0,
485: MatLoad_SeqBDiag,
486: /*85*/ 0,
487: 0,
488: 0,
489: 0,
490: 0,
491: /*90*/ 0,
492: 0,
493: 0,
494: 0,
495: 0,
496: /*95*/ 0,
497: 0,
498: 0,
499: 0};
503: /*@C
504: MatSeqBDiagSetPreallocation - Sets the nonzero structure and (optionally) arrays.
506: Collective on MPI_Comm
508: Input Parameters:
509: + B - the matrix
510: . nd - number of block diagonals (optional)
511: . bs - each element of a diagonal is an bs x bs dense matrix
512: . diag - optional array of block diagonal numbers (length nd).
513: For a matrix element A[i,j], where i=row and j=column, the
514: diagonal number is
515: $ diag = i/bs - j/bs (integer division)
516: Set diag=PETSC_NULL on input for PETSc to dynamically allocate memory as
517: needed (expensive).
518: - diagv - pointer to actual diagonals (in same order as diag array),
519: if allocated by user. Otherwise, set diagv=PETSC_NULL on input for PETSc
520: to control memory allocation.
522: Options Database Keys:
523: . -mat_block_size <bs> - Sets blocksize
524: . -mat_bdiag_diags <s1,s2,s3,...> - Sets diagonal numbers
526: Notes:
527: See the users manual for further details regarding this storage format.
529: Fortran Note:
530: Fortran programmers cannot set diagv; this value is ignored.
532: Level: intermediate
534: .keywords: matrix, block, diagonal, sparse
536: .seealso: MatCreate(), MatCreateMPIBDiag(), MatSetValues()
537: @*/
538: PetscErrorCode MatSeqBDiagSetPreallocation(Mat B,PetscInt nd,PetscInt bs,const PetscInt diag[],PetscScalar *diagv[])
539: {
540: PetscErrorCode ierr,(*f)(Mat,PetscInt,PetscInt,const PetscInt[],PetscScalar*[]);
543: PetscObjectQueryFunction((PetscObject)B,"MatSeqBDiagSetPreallocation_C",(void (**)(void))&f);
544: if (f) {
545: (*f)(B,nd,bs,diag,diagv);
546: }
547: return(0);
548: }
553: PetscErrorCode MatSeqBDiagSetPreallocation_SeqBDiag(Mat B,PetscInt nd,PetscInt bs,PetscInt *diag,PetscScalar **diagv)
554: {
555: Mat_SeqBDiag *b;
557: PetscInt i,nda,sizetot, nd2 = 128,idiag[128];
558: PetscTruth flg1;
562: B->preallocated = PETSC_TRUE;
563: if (bs == PETSC_DEFAULT) bs = 1;
564: if (!bs) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize cannot be zero");
565: if (nd == PETSC_DEFAULT) nd = 0;
566: PetscOptionsGetInt(PETSC_NULL,"-mat_block_size",&bs,PETSC_NULL);
567: PetscOptionsGetIntArray(PETSC_NULL,"-mat_bdiag_diags",idiag,&nd2,&flg1);
568: if (flg1) {
569: diag = idiag;
570: nd = nd2;
571: }
573: if ((B->n%bs) || (B->m%bs)) SETERRQ(PETSC_ERR_ARG_SIZ,"Invalid block size");
574: if (!nd) nda = nd + 1;
575: else nda = nd;
576: b = (Mat_SeqBDiag*)B->data;
578: PetscOptionsHasName(PETSC_NULL,"-mat_no_unroll",&flg1);
579: if (!flg1) {
580: switch (bs) {
581: case 1:
582: B->ops->setvalues = MatSetValues_SeqBDiag_1;
583: B->ops->getvalues = MatGetValues_SeqBDiag_1;
584: B->ops->getdiagonal = MatGetDiagonal_SeqBDiag_1;
585: B->ops->mult = MatMult_SeqBDiag_1;
586: B->ops->multadd = MatMultAdd_SeqBDiag_1;
587: B->ops->multtranspose = MatMultTranspose_SeqBDiag_1;
588: B->ops->multtransposeadd= MatMultTransposeAdd_SeqBDiag_1;
589: B->ops->relax = MatRelax_SeqBDiag_1;
590: B->ops->solve = MatSolve_SeqBDiag_1;
591: B->ops->lufactornumeric = MatLUFactorNumeric_SeqBDiag_1;
592: break;
593: case 2:
594: B->ops->mult = MatMult_SeqBDiag_2;
595: B->ops->multadd = MatMultAdd_SeqBDiag_2;
596: B->ops->solve = MatSolve_SeqBDiag_2;
597: break;
598: case 3:
599: B->ops->mult = MatMult_SeqBDiag_3;
600: B->ops->multadd = MatMultAdd_SeqBDiag_3;
601: B->ops->solve = MatSolve_SeqBDiag_3;
602: break;
603: case 4:
604: B->ops->mult = MatMult_SeqBDiag_4;
605: B->ops->multadd = MatMultAdd_SeqBDiag_4;
606: B->ops->solve = MatSolve_SeqBDiag_4;
607: break;
608: case 5:
609: B->ops->mult = MatMult_SeqBDiag_5;
610: B->ops->multadd = MatMultAdd_SeqBDiag_5;
611: B->ops->solve = MatSolve_SeqBDiag_5;
612: break;
613: }
614: }
616: b->mblock = B->m/bs;
617: b->nblock = B->n/bs;
618: b->nd = nd;
619: B->bs = bs;
620: b->ndim = 0;
621: b->mainbd = -1;
622: b->pivot = 0;
624: PetscMalloc(2*nda*sizeof(PetscInt),&b->diag);
625: b->bdlen = b->diag + nda;
626: PetscMalloc((B->n+1)*sizeof(PetscInt),&b->colloc);
627: PetscMalloc(nda*sizeof(PetscScalar*),&b->diagv);
628: sizetot = 0;
630: if (diagv) { /* user allocated space */
631: b->user_alloc = PETSC_TRUE;
632: for (i=0; i<nd; i++) b->diagv[i] = diagv[i];
633: } else b->user_alloc = PETSC_FALSE;
635: for (i=0; i<nd; i++) {
636: b->diag[i] = diag[i];
637: if (diag[i] > 0) { /* lower triangular */
638: b->bdlen[i] = PetscMin(b->nblock,b->mblock - diag[i]);
639: } else { /* upper triangular */
640: b->bdlen[i] = PetscMin(b->mblock,b->nblock + diag[i]);
641: }
642: sizetot += b->bdlen[i];
643: }
644: sizetot *= bs*bs;
645: b->maxnz = sizetot;
646: PetscMalloc((B->n+1)*sizeof(PetscScalar),&b->dvalue);
647: PetscLogObjectMemory(B,(nda*(bs+2))*sizeof(PetscInt) + bs*nda*sizeof(PetscScalar)
648: + nda*sizeof(PetscScalar*) + sizeof(Mat_SeqBDiag)
649: + sizeof(struct _p_Mat) + sizetot*sizeof(PetscScalar));
651: if (!b->user_alloc) {
652: for (i=0; i<nd; i++) {
653: PetscMalloc(bs*bs*b->bdlen[i]*sizeof(PetscScalar),&b->diagv[i]);
654: PetscMemzero(b->diagv[i],bs*bs*b->bdlen[i]*sizeof(PetscScalar));
655: }
656: b->nonew = 0; b->nonew_diag = 0;
657: } else { /* diagonals are set on input; don't allow dynamic allocation */
658: b->nonew = 1; b->nonew_diag = 1;
659: }
661: /* adjust diagv so one may access rows with diagv[diag][row] for all rows */
662: for (i=0; i<nd; i++) {
663: if (diag[i] > 0) {
664: b->diagv[i] -= bs*bs*diag[i];
665: }
666: }
668: b->nz = b->maxnz; /* Currently not keeping track of exact count */
669: b->roworiented = PETSC_TRUE;
670: B->info.nz_unneeded = (double)b->maxnz;
671: return(0);
672: }
677: static PetscErrorCode MatDuplicate_SeqBDiag(Mat A,MatDuplicateOption cpvalues,Mat *matout)
678: {
679: Mat_SeqBDiag *newmat,*a = (Mat_SeqBDiag*)A->data;
681: PetscInt i,len,diag,bs = A->bs;
682: Mat mat;
685: MatCreate(A->comm,A->m,A->n,A->m,A->n,matout);
686: MatSetType(*matout,A->type_name);
687: MatSeqBDiagSetPreallocation(*matout,a->nd,bs,a->diag,PETSC_NULL);
689: /* Copy contents of diagonals */
690: mat = *matout;
691: newmat = (Mat_SeqBDiag*)mat->data;
692: if (cpvalues == MAT_COPY_VALUES) {
693: for (i=0; i<a->nd; i++) {
694: len = a->bdlen[i] * bs * bs * sizeof(PetscScalar);
695: diag = a->diag[i];
696: if (diag > 0) {
697: PetscMemcpy(newmat->diagv[i]+bs*bs*diag,a->diagv[i]+bs*bs*diag,len);
698: } else {
699: PetscMemcpy(newmat->diagv[i],a->diagv[i],len);
700: }
701: }
702: }
703: MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY);
704: MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY);
705: return(0);
706: }
710: PetscErrorCode MatLoad_SeqBDiag(PetscViewer viewer,const MatType type,Mat *A)
711: {
712: Mat B;
714: PetscMPIInt size;
715: int fd;
716: PetscInt *scols,i,nz,header[4],nd = 128;
717: PetscInt bs,*rowlengths = 0,M,N,*cols,extra_rows,*diag = 0;
718: PetscInt idiag[128];
719: PetscScalar *vals,*svals;
720: MPI_Comm comm;
721: PetscTruth flg;
722:
724: PetscObjectGetComm((PetscObject)viewer,&comm);
725: MPI_Comm_size(comm,&size);
726: if (size > 1) SETERRQ(PETSC_ERR_ARG_SIZ,"view must have one processor");
727: PetscViewerBinaryGetDescriptor(viewer,&fd);
728: PetscBinaryRead(fd,header,4,PETSC_INT);
729: if (header[0] != MAT_FILE_COOKIE) SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"Not matrix object");
730: M = header[1]; N = header[2]; nz = header[3];
731: if (M != N) SETERRQ(PETSC_ERR_SUP,"Can only load square matrices");
732: if (header[3] < 0) {
733: SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"Matrix stored in special format, cannot load as SeqBDiag");
734: }
736: /*
737: This code adds extra rows to make sure the number of rows is
738: divisible by the blocksize
739: */
740: bs = 1;
741: PetscOptionsGetInt(PETSC_NULL,"-matload_block_size",&bs,PETSC_NULL);
742: extra_rows = bs - M + bs*(M/bs);
743: if (extra_rows == bs) extra_rows = 0;
744: if (extra_rows) {
745: PetscLogInfo(0,"MatLoad_SeqBDiag:Padding loaded matrix to match blocksize\n");
746: }
748: /* read row lengths */
749: PetscMalloc((M+extra_rows)*sizeof(PetscInt),&rowlengths);
750: PetscBinaryRead(fd,rowlengths,M,PETSC_INT);
751: for (i=0; i<extra_rows; i++) rowlengths[M+i] = 1;
753: /* load information about diagonals */
754: PetscOptionsGetIntArray(PETSC_NULL,"-matload_bdiag_diags",idiag,&nd,&flg);
755: if (flg) {
756: diag = idiag;
757: }
759: /* create our matrix */
760: MatCreate(comm,M+extra_rows,M+extra_rows,M+extra_rows,M+extra_rows,A);
761: MatSetType(*A,type);
762: MatSeqBDiagSetPreallocation(*A,nd,bs,diag,PETSC_NULL);
763: B = *A;
765: /* read column indices and nonzeros */
766: PetscMalloc(nz*sizeof(PetscInt),&scols);
767: cols = scols;
768: PetscBinaryRead(fd,cols,nz,PETSC_INT);
769: PetscMalloc(nz*sizeof(PetscScalar),&svals);
770: vals = svals;
771: PetscBinaryRead(fd,vals,nz,PETSC_SCALAR);
772: /* insert into matrix */
774: for (i=0; i<M; i++) {
775: MatSetValues(B,1,&i,rowlengths[i],scols,svals,INSERT_VALUES);
776: scols += rowlengths[i]; svals += rowlengths[i];
777: }
778: vals[0] = 1.0;
779: for (i=M; i<M+extra_rows; i++) {
780: MatSetValues(B,1,&i,1,&i,vals,INSERT_VALUES);
781: }
783: PetscFree(cols);
784: PetscFree(vals);
785: PetscFree(rowlengths);
787: MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
788: MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
789: return(0);
790: }
792: /*MC
793: MATSEQBDIAG - MATSEQBDIAG = "seqbdiag" - A matrix type to be used for sequential block diagonal matrices.
795: Options Database Keys:
796: . -mat_type seqbdiag - sets the matrix type to "seqbdiag" during a call to MatSetFromOptions()
798: Level: beginner
800: .seealso: MatCreateSeqBDiag
801: M*/
806: PetscErrorCode MatCreate_SeqBDiag(Mat B)
807: {
808: Mat_SeqBDiag *b;
810: PetscMPIInt size;
813: MPI_Comm_size(B->comm,&size);
814: if (size > 1) SETERRQ(PETSC_ERR_ARG_WRONG,"Comm must be of size 1");
816: B->m = B->M = PetscMax(B->m,B->M);
817: B->n = B->N = PetscMax(B->n,B->N);
819: PetscNew(Mat_SeqBDiag,&b);
820: B->data = (void*)b;
821: PetscMemzero(b,sizeof(Mat_SeqBDiag));
822: PetscMemcpy(B->ops,&MatOps_Values,sizeof(struct _MatOps));
823: B->factor = 0;
824: B->mapping = 0;
826: PetscMapCreateMPI(B->comm,B->m,B->m,&B->rmap);
827: PetscMapCreateMPI(B->comm,B->n,B->n,&B->cmap);
829: b->ndim = 0;
830: b->mainbd = -1;
831: b->pivot = 0;
833: b->roworiented = PETSC_TRUE;
834: PetscObjectComposeFunctionDynamic((PetscObject)B,"MatSeqBDiagSetPreallocation_C",
835: "MatSeqBDiagSetPreallocation_SeqBDiag",
836: MatSeqBDiagSetPreallocation_SeqBDiag);
838: return(0);
839: }
844: /*@C
845: MatCreateSeqBDiag - Creates a sequential block diagonal matrix.
847: Collective on MPI_Comm
849: Input Parameters:
850: + comm - MPI communicator, set to PETSC_COMM_SELF
851: . m - number of rows
852: . n - number of columns
853: . nd - number of block diagonals (optional)
854: . bs - each element of a diagonal is an bs x bs dense matrix
855: . diag - optional array of block diagonal numbers (length nd).
856: For a matrix element A[i,j], where i=row and j=column, the
857: diagonal number is
858: $ diag = i/bs - j/bs (integer division)
859: Set diag=PETSC_NULL on input for PETSc to dynamically allocate memory as
860: needed (expensive).
861: - diagv - pointer to actual diagonals (in same order as diag array),
862: if allocated by user. Otherwise, set diagv=PETSC_NULL on input for PETSc
863: to control memory allocation.
865: Output Parameters:
866: . A - the matrix
868: Options Database Keys:
869: . -mat_block_size <bs> - Sets blocksize
870: . -mat_bdiag_diags <s1,s2,s3,...> - Sets diagonal numbers
872: Notes:
873: See the users manual for further details regarding this storage format.
875: Fortran Note:
876: Fortran programmers cannot set diagv; this value is ignored.
878: Level: intermediate
880: .keywords: matrix, block, diagonal, sparse
882: .seealso: MatCreate(), MatCreateMPIBDiag(), MatSetValues()
883: @*/
884: PetscErrorCode MatCreateSeqBDiag(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt nd,PetscInt bs,const PetscInt diag[],PetscScalar *diagv[],Mat *A)
885: {
889: MatCreate(comm,m,n,m,n,A);
890: MatSetType(*A,MATSEQBDIAG);
891: MatSeqBDiagSetPreallocation(*A,nd,bs,diag,diagv);
892: return(0);
893: }