Actual source code: inode.c
petsc-3.7.3 2016-08-01
2: /*
3: This file provides high performance routines for the Inode format (compressed sparse row)
4: by taking advantage of rows with identical nonzero structure (I-nodes).
5: */
6: #include <../src/mat/impls/aij/seq/aij.h>
10: static PetscErrorCode Mat_CreateColInode(Mat A,PetscInt *size,PetscInt **ns)
11: {
12: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
14: PetscInt i,count,m,n,min_mn,*ns_row,*ns_col;
17: n = A->cmap->n;
18: m = A->rmap->n;
19: ns_row = a->inode.size;
21: min_mn = (m < n) ? m : n;
22: if (!ns) {
23: for (count=0,i=0; count<min_mn; count+=ns_row[i],i++) ;
24: for (; count+1 < n; count++,i++) ;
25: if (count < n) {
26: i++;
27: }
28: *size = i;
29: return(0);
30: }
31: PetscMalloc1(n+1,&ns_col);
33: /* Use the same row structure wherever feasible. */
34: for (count=0,i=0; count<min_mn; count+=ns_row[i],i++) {
35: ns_col[i] = ns_row[i];
36: }
38: /* if m < n; pad up the remainder with inode_limit */
39: for (; count+1 < n; count++,i++) {
40: ns_col[i] = 1;
41: }
42: /* The last node is the odd ball. padd it up with the remaining rows; */
43: if (count < n) {
44: ns_col[i] = n - count;
45: i++;
46: } else if (count > n) {
47: /* Adjust for the over estimation */
48: ns_col[i-1] += n - count;
49: }
50: *size = i;
51: *ns = ns_col;
52: return(0);
53: }
56: /*
57: This builds symmetric version of nonzero structure,
58: */
61: static PetscErrorCode MatGetRowIJ_SeqAIJ_Inode_Symmetric(Mat A,const PetscInt *iia[],const PetscInt *jja[],PetscInt ishift,PetscInt oshift)
62: {
63: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
65: PetscInt *work,*ia,*ja,nz,nslim_row,nslim_col,m,row,col,n;
66: PetscInt *tns,*tvc,*ns_row = a->inode.size,*ns_col,nsz,i1,i2;
67: const PetscInt *j,*jmax,*ai= a->i,*aj = a->j;
70: nslim_row = a->inode.node_count;
71: m = A->rmap->n;
72: n = A->cmap->n;
73: if (m != n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatGetRowIJ_SeqAIJ_Inode_Symmetric: Matrix should be square");
75: /* Use the row_inode as column_inode */
76: nslim_col = nslim_row;
77: ns_col = ns_row;
79: /* allocate space for reformated inode structure */
80: PetscMalloc1(nslim_col+1,&tns);
81: PetscMalloc1(n+1,&tvc);
82: for (i1=0,tns[0]=0; i1<nslim_col; ++i1) tns[i1+1] = tns[i1]+ ns_row[i1];
84: for (i1=0,col=0; i1<nslim_col; ++i1) {
85: nsz = ns_col[i1];
86: for (i2=0; i2<nsz; ++i2,++col) tvc[col] = i1;
87: }
88: /* allocate space for row pointers */
89: PetscMalloc1(nslim_row+1,&ia);
90: *iia = ia;
91: PetscMemzero(ia,(nslim_row+1)*sizeof(PetscInt));
92: PetscMalloc1(nslim_row+1,&work);
94: /* determine the number of columns in each row */
95: ia[0] = oshift;
96: for (i1=0,row=0; i1<nslim_row; row+=ns_row[i1],i1++) {
98: j = aj + ai[row] + ishift;
99: jmax = aj + ai[row+1] + ishift;
100: if (j==jmax) continue; /* empty row */
101: col = *j++ + ishift;
102: i2 = tvc[col];
103: while (i2<i1 && j<jmax) { /* 1.[-xx-d-xx--] 2.[-xx-------],off-diagonal elemets */
104: ia[i1+1]++;
105: ia[i2+1]++;
106: i2++; /* Start col of next node */
107: while ((j<jmax) && ((col=*j+ishift)<tns[i2])) ++j;
108: i2 = tvc[col];
109: }
110: if (i2 == i1) ia[i2+1]++; /* now the diagonal element */
111: }
113: /* shift ia[i] to point to next row */
114: for (i1=1; i1<nslim_row+1; i1++) {
115: row = ia[i1-1];
116: ia[i1] += row;
117: work[i1-1] = row - oshift;
118: }
120: /* allocate space for column pointers */
121: nz = ia[nslim_row] + (!ishift);
122: PetscMalloc1(nz,&ja);
123: *jja = ja;
125: /* loop over lower triangular part putting into ja */
126: for (i1=0,row=0; i1<nslim_row; row += ns_row[i1],i1++) {
127: j = aj + ai[row] + ishift;
128: jmax = aj + ai[row+1] + ishift;
129: if (j==jmax) continue; /* empty row */
130: col = *j++ + ishift;
131: i2 = tvc[col];
132: while (i2<i1 && j<jmax) {
133: ja[work[i2]++] = i1 + oshift;
134: ja[work[i1]++] = i2 + oshift;
135: ++i2;
136: while ((j<jmax) && ((col=*j+ishift)< tns[i2])) ++j; /* Skip rest col indices in this node */
137: i2 = tvc[col];
138: }
139: if (i2 == i1) ja[work[i1]++] = i2 + oshift;
141: }
142: PetscFree(work);
143: PetscFree(tns);
144: PetscFree(tvc);
145: return(0);
146: }
148: /*
149: This builds nonsymmetric version of nonzero structure,
150: */
153: static PetscErrorCode MatGetRowIJ_SeqAIJ_Inode_Nonsymmetric(Mat A,const PetscInt *iia[],const PetscInt *jja[],PetscInt ishift,PetscInt oshift)
154: {
155: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
157: PetscInt *work,*ia,*ja,nz,nslim_row,n,row,col,*ns_col,nslim_col;
158: PetscInt *tns,*tvc,nsz,i1,i2;
159: const PetscInt *j,*ai= a->i,*aj = a->j,*ns_row = a->inode.size;
162: nslim_row = a->inode.node_count;
163: n = A->cmap->n;
165: /* Create The column_inode for this matrix */
166: Mat_CreateColInode(A,&nslim_col,&ns_col);
168: /* allocate space for reformated column_inode structure */
169: PetscMalloc1(nslim_col +1,&tns);
170: PetscMalloc1(n + 1,&tvc);
171: for (i1=0,tns[0]=0; i1<nslim_col; ++i1) tns[i1+1] = tns[i1] + ns_col[i1];
173: for (i1=0,col=0; i1<nslim_col; ++i1) {
174: nsz = ns_col[i1];
175: for (i2=0; i2<nsz; ++i2,++col) tvc[col] = i1;
176: }
177: /* allocate space for row pointers */
178: PetscMalloc1(nslim_row+1,&ia);
179: *iia = ia;
180: PetscMemzero(ia,(nslim_row+1)*sizeof(PetscInt));
181: PetscMalloc1(nslim_row+1,&work);
183: /* determine the number of columns in each row */
184: ia[0] = oshift;
185: for (i1=0,row=0; i1<nslim_row; row+=ns_row[i1],i1++) {
186: j = aj + ai[row] + ishift;
187: nz = ai[row+1] - ai[row];
188: if (!nz) continue; /* empty row */
189: col = *j++ + ishift;
190: i2 = tvc[col];
191: while (nz-- > 0) { /* off-diagonal elemets */
192: ia[i1+1]++;
193: i2++; /* Start col of next node */
194: while (nz > 0 && ((col = *j++ + ishift) < tns[i2])) nz--;
195: if (nz > 0) i2 = tvc[col];
196: }
197: }
199: /* shift ia[i] to point to next row */
200: for (i1=1; i1<nslim_row+1; i1++) {
201: row = ia[i1-1];
202: ia[i1] += row;
203: work[i1-1] = row - oshift;
204: }
206: /* allocate space for column pointers */
207: nz = ia[nslim_row] + (!ishift);
208: PetscMalloc1(nz,&ja);
209: *jja = ja;
211: /* loop over matrix putting into ja */
212: for (i1=0,row=0; i1<nslim_row; row+=ns_row[i1],i1++) {
213: j = aj + ai[row] + ishift;
214: nz = ai[row+1] - ai[row];
215: if (!nz) continue; /* empty row */
216: col = *j++ + ishift;
217: i2 = tvc[col];
218: while (nz-- > 0) {
219: ja[work[i1]++] = i2 + oshift;
220: ++i2;
221: while (nz > 0 && ((col = *j++ + ishift) < tns[i2])) nz--;
222: if (nz > 0) i2 = tvc[col];
223: }
224: }
225: PetscFree(ns_col);
226: PetscFree(work);
227: PetscFree(tns);
228: PetscFree(tvc);
229: return(0);
230: }
234: static PetscErrorCode MatGetRowIJ_SeqAIJ_Inode(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *n,const PetscInt *ia[],const PetscInt *ja[],PetscBool *done)
235: {
236: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
240: *n = a->inode.node_count;
241: if (!ia) return(0);
242: if (!blockcompressed) {
243: MatGetRowIJ_SeqAIJ(A,oshift,symmetric,blockcompressed,n,ia,ja,done);;
244: } else if (symmetric) {
245: MatGetRowIJ_SeqAIJ_Inode_Symmetric(A,ia,ja,0,oshift);
246: } else {
247: MatGetRowIJ_SeqAIJ_Inode_Nonsymmetric(A,ia,ja,0,oshift);
248: }
249: return(0);
250: }
254: static PetscErrorCode MatRestoreRowIJ_SeqAIJ_Inode(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *n,const PetscInt *ia[],const PetscInt *ja[],PetscBool *done)
255: {
259: if (!ia) return(0);
261: if (!blockcompressed) {
262: MatRestoreRowIJ_SeqAIJ(A,oshift,symmetric,blockcompressed,n,ia,ja,done);;
263: } else {
264: PetscFree(*ia);
265: PetscFree(*ja);
266: }
267: return(0);
268: }
270: /* ----------------------------------------------------------- */
274: static PetscErrorCode MatGetColumnIJ_SeqAIJ_Inode_Nonsymmetric(Mat A,const PetscInt *iia[],const PetscInt *jja[],PetscInt ishift,PetscInt oshift)
275: {
276: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
278: PetscInt *work,*ia,*ja,*j,nz,nslim_row, n,row,col,*ns_col,nslim_col;
279: PetscInt *tns,*tvc,*ns_row = a->inode.size,nsz,i1,i2,*ai= a->i,*aj = a->j;
282: nslim_row = a->inode.node_count;
283: n = A->cmap->n;
285: /* Create The column_inode for this matrix */
286: Mat_CreateColInode(A,&nslim_col,&ns_col);
288: /* allocate space for reformated column_inode structure */
289: PetscMalloc1(nslim_col + 1,&tns);
290: PetscMalloc1(n + 1,&tvc);
291: for (i1=0,tns[0]=0; i1<nslim_col; ++i1) tns[i1+1] = tns[i1] + ns_col[i1];
293: for (i1=0,col=0; i1<nslim_col; ++i1) {
294: nsz = ns_col[i1];
295: for (i2=0; i2<nsz; ++i2,++col) tvc[col] = i1;
296: }
297: /* allocate space for column pointers */
298: PetscMalloc1(nslim_col+1,&ia);
299: *iia = ia;
300: PetscMemzero(ia,(nslim_col+1)*sizeof(PetscInt));
301: PetscMalloc1(nslim_col+1,&work);
303: /* determine the number of columns in each row */
304: ia[0] = oshift;
305: for (i1=0,row=0; i1<nslim_row; row+=ns_row[i1],i1++) {
306: j = aj + ai[row] + ishift;
307: col = *j++ + ishift;
308: i2 = tvc[col];
309: nz = ai[row+1] - ai[row];
310: while (nz-- > 0) { /* off-diagonal elemets */
311: /* ia[i1+1]++; */
312: ia[i2+1]++;
313: i2++;
314: while (nz > 0 && ((col = *j++ + ishift) < tns[i2])) nz--;
315: if (nz > 0) i2 = tvc[col];
316: }
317: }
319: /* shift ia[i] to point to next col */
320: for (i1=1; i1<nslim_col+1; i1++) {
321: col = ia[i1-1];
322: ia[i1] += col;
323: work[i1-1] = col - oshift;
324: }
326: /* allocate space for column pointers */
327: nz = ia[nslim_col] + (!ishift);
328: PetscMalloc1(nz,&ja);
329: *jja = ja;
331: /* loop over matrix putting into ja */
332: for (i1=0,row=0; i1<nslim_row; row+=ns_row[i1],i1++) {
333: j = aj + ai[row] + ishift;
334: col = *j++ + ishift;
335: i2 = tvc[col];
336: nz = ai[row+1] - ai[row];
337: while (nz-- > 0) {
338: /* ja[work[i1]++] = i2 + oshift; */
339: ja[work[i2]++] = i1 + oshift;
340: i2++;
341: while (nz > 0 && ((col = *j++ + ishift) < tns[i2])) nz--;
342: if (nz > 0) i2 = tvc[col];
343: }
344: }
345: PetscFree(ns_col);
346: PetscFree(work);
347: PetscFree(tns);
348: PetscFree(tvc);
349: return(0);
350: }
354: static PetscErrorCode MatGetColumnIJ_SeqAIJ_Inode(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *n,const PetscInt *ia[],const PetscInt *ja[],PetscBool *done)
355: {
359: Mat_CreateColInode(A,n,NULL);
360: if (!ia) return(0);
362: if (!blockcompressed) {
363: MatGetColumnIJ_SeqAIJ(A,oshift,symmetric,blockcompressed,n,ia,ja,done);;
364: } else if (symmetric) {
365: /* Since the indices are symmetric it does'nt matter */
366: MatGetRowIJ_SeqAIJ_Inode_Symmetric(A,ia,ja,0,oshift);
367: } else {
368: MatGetColumnIJ_SeqAIJ_Inode_Nonsymmetric(A,ia,ja,0,oshift);
369: }
370: return(0);
371: }
375: static PetscErrorCode MatRestoreColumnIJ_SeqAIJ_Inode(Mat A,PetscInt oshift,PetscBool symmetric,PetscBool blockcompressed,PetscInt *n,const PetscInt *ia[],const PetscInt *ja[],PetscBool *done)
376: {
380: if (!ia) return(0);
381: if (!blockcompressed) {
382: MatRestoreColumnIJ_SeqAIJ(A,oshift,symmetric,blockcompressed,n,ia,ja,done);;
383: } else {
384: PetscFree(*ia);
385: PetscFree(*ja);
386: }
387: return(0);
388: }
390: /* ----------------------------------------------------------- */
394: static PetscErrorCode MatMult_SeqAIJ_Inode(Mat A,Vec xx,Vec yy)
395: {
396: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
397: PetscScalar sum1,sum2,sum3,sum4,sum5,tmp0,tmp1;
398: PetscScalar *y;
399: const PetscScalar *x;
400: const MatScalar *v1,*v2,*v3,*v4,*v5;
401: PetscErrorCode ierr;
402: PetscInt i1,i2,n,i,row,node_max,nsz,sz,nonzerorow=0;
403: const PetscInt *idx,*ns,*ii;
405: #if defined(PETSC_HAVE_PRAGMA_DISJOINT)
406: #pragma disjoint(*x,*y,*v1,*v2,*v3,*v4,*v5)
407: #endif
410: if (!a->inode.size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Missing Inode Structure");
411: node_max = a->inode.node_count;
412: ns = a->inode.size; /* Node Size array */
413: VecGetArrayRead(xx,&x);
414: VecGetArray(yy,&y);
415: idx = a->j;
416: v1 = a->a;
417: ii = a->i;
419: for (i = 0,row = 0; i< node_max; ++i) {
420: nsz = ns[i];
421: n = ii[1] - ii[0];
422: nonzerorow += (n>0)*nsz;
423: ii += nsz;
424: PetscPrefetchBlock(idx+nsz*n,n,0,PETSC_PREFETCH_HINT_NTA); /* Prefetch the indices for the block row after the current one */
425: PetscPrefetchBlock(v1+nsz*n,nsz*n,0,PETSC_PREFETCH_HINT_NTA); /* Prefetch the values for the block row after the current one */
426: sz = n; /* No of non zeros in this row */
427: /* Switch on the size of Node */
428: switch (nsz) { /* Each loop in 'case' is unrolled */
429: case 1:
430: sum1 = 0.;
432: for (n = 0; n< sz-1; n+=2) {
433: i1 = idx[0]; /* The instructions are ordered to */
434: i2 = idx[1]; /* make the compiler's job easy */
435: idx += 2;
436: tmp0 = x[i1];
437: tmp1 = x[i2];
438: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
439: }
441: if (n == sz-1) { /* Take care of the last nonzero */
442: tmp0 = x[*idx++];
443: sum1 += *v1++ *tmp0;
444: }
445: y[row++]=sum1;
446: break;
447: case 2:
448: sum1 = 0.;
449: sum2 = 0.;
450: v2 = v1 + n;
452: for (n = 0; n< sz-1; n+=2) {
453: i1 = idx[0];
454: i2 = idx[1];
455: idx += 2;
456: tmp0 = x[i1];
457: tmp1 = x[i2];
458: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
459: sum2 += v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
460: }
461: if (n == sz-1) {
462: tmp0 = x[*idx++];
463: sum1 += *v1++ * tmp0;
464: sum2 += *v2++ * tmp0;
465: }
466: y[row++]=sum1;
467: y[row++]=sum2;
468: v1 =v2; /* Since the next block to be processed starts there*/
469: idx +=sz;
470: break;
471: case 3:
472: sum1 = 0.;
473: sum2 = 0.;
474: sum3 = 0.;
475: v2 = v1 + n;
476: v3 = v2 + n;
478: for (n = 0; n< sz-1; n+=2) {
479: i1 = idx[0];
480: i2 = idx[1];
481: idx += 2;
482: tmp0 = x[i1];
483: tmp1 = x[i2];
484: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
485: sum2 += v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
486: sum3 += v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
487: }
488: if (n == sz-1) {
489: tmp0 = x[*idx++];
490: sum1 += *v1++ * tmp0;
491: sum2 += *v2++ * tmp0;
492: sum3 += *v3++ * tmp0;
493: }
494: y[row++]=sum1;
495: y[row++]=sum2;
496: y[row++]=sum3;
497: v1 =v3; /* Since the next block to be processed starts there*/
498: idx +=2*sz;
499: break;
500: case 4:
501: sum1 = 0.;
502: sum2 = 0.;
503: sum3 = 0.;
504: sum4 = 0.;
505: v2 = v1 + n;
506: v3 = v2 + n;
507: v4 = v3 + n;
509: for (n = 0; n< sz-1; n+=2) {
510: i1 = idx[0];
511: i2 = idx[1];
512: idx += 2;
513: tmp0 = x[i1];
514: tmp1 = x[i2];
515: sum1 += v1[0] * tmp0 + v1[1] *tmp1; v1 += 2;
516: sum2 += v2[0] * tmp0 + v2[1] *tmp1; v2 += 2;
517: sum3 += v3[0] * tmp0 + v3[1] *tmp1; v3 += 2;
518: sum4 += v4[0] * tmp0 + v4[1] *tmp1; v4 += 2;
519: }
520: if (n == sz-1) {
521: tmp0 = x[*idx++];
522: sum1 += *v1++ * tmp0;
523: sum2 += *v2++ * tmp0;
524: sum3 += *v3++ * tmp0;
525: sum4 += *v4++ * tmp0;
526: }
527: y[row++]=sum1;
528: y[row++]=sum2;
529: y[row++]=sum3;
530: y[row++]=sum4;
531: v1 =v4; /* Since the next block to be processed starts there*/
532: idx +=3*sz;
533: break;
534: case 5:
535: sum1 = 0.;
536: sum2 = 0.;
537: sum3 = 0.;
538: sum4 = 0.;
539: sum5 = 0.;
540: v2 = v1 + n;
541: v3 = v2 + n;
542: v4 = v3 + n;
543: v5 = v4 + n;
545: for (n = 0; n<sz-1; n+=2) {
546: i1 = idx[0];
547: i2 = idx[1];
548: idx += 2;
549: tmp0 = x[i1];
550: tmp1 = x[i2];
551: sum1 += v1[0] * tmp0 + v1[1] *tmp1; v1 += 2;
552: sum2 += v2[0] * tmp0 + v2[1] *tmp1; v2 += 2;
553: sum3 += v3[0] * tmp0 + v3[1] *tmp1; v3 += 2;
554: sum4 += v4[0] * tmp0 + v4[1] *tmp1; v4 += 2;
555: sum5 += v5[0] * tmp0 + v5[1] *tmp1; v5 += 2;
556: }
557: if (n == sz-1) {
558: tmp0 = x[*idx++];
559: sum1 += *v1++ * tmp0;
560: sum2 += *v2++ * tmp0;
561: sum3 += *v3++ * tmp0;
562: sum4 += *v4++ * tmp0;
563: sum5 += *v5++ * tmp0;
564: }
565: y[row++]=sum1;
566: y[row++]=sum2;
567: y[row++]=sum3;
568: y[row++]=sum4;
569: y[row++]=sum5;
570: v1 =v5; /* Since the next block to be processed starts there */
571: idx +=4*sz;
572: break;
573: default:
574: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported");
575: }
576: }
577: VecRestoreArrayRead(xx,&x);
578: VecRestoreArray(yy,&y);
579: PetscLogFlops(2.0*a->nz - nonzerorow);
580: return(0);
581: }
582: /* ----------------------------------------------------------- */
583: /* Almost same code as the MatMult_SeqAIJ_Inode() */
586: static PetscErrorCode MatMultAdd_SeqAIJ_Inode(Mat A,Vec xx,Vec zz,Vec yy)
587: {
588: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
589: PetscScalar sum1,sum2,sum3,sum4,sum5,tmp0,tmp1;
590: const MatScalar *v1,*v2,*v3,*v4,*v5;
591: const PetscScalar *x;
592: PetscScalar *y,*z,*zt;
593: PetscErrorCode ierr;
594: PetscInt i1,i2,n,i,row,node_max,nsz,sz;
595: const PetscInt *idx,*ns,*ii;
598: if (!a->inode.size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Missing Inode Structure");
599: node_max = a->inode.node_count;
600: ns = a->inode.size; /* Node Size array */
602: VecGetArrayRead(xx,&x);
603: VecGetArrayPair(zz,yy,&z,&y);
604: zt = z;
606: idx = a->j;
607: v1 = a->a;
608: ii = a->i;
610: for (i = 0,row = 0; i< node_max; ++i) {
611: nsz = ns[i];
612: n = ii[1] - ii[0];
613: ii += nsz;
614: sz = n; /* No of non zeros in this row */
615: /* Switch on the size of Node */
616: switch (nsz) { /* Each loop in 'case' is unrolled */
617: case 1:
618: sum1 = *zt++;
620: for (n = 0; n< sz-1; n+=2) {
621: i1 = idx[0]; /* The instructions are ordered to */
622: i2 = idx[1]; /* make the compiler's job easy */
623: idx += 2;
624: tmp0 = x[i1];
625: tmp1 = x[i2];
626: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
627: }
629: if (n == sz-1) { /* Take care of the last nonzero */
630: tmp0 = x[*idx++];
631: sum1 += *v1++ * tmp0;
632: }
633: y[row++]=sum1;
634: break;
635: case 2:
636: sum1 = *zt++;
637: sum2 = *zt++;
638: v2 = v1 + n;
640: for (n = 0; n< sz-1; n+=2) {
641: i1 = idx[0];
642: i2 = idx[1];
643: idx += 2;
644: tmp0 = x[i1];
645: tmp1 = x[i2];
646: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
647: sum2 += v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
648: }
649: if (n == sz-1) {
650: tmp0 = x[*idx++];
651: sum1 += *v1++ * tmp0;
652: sum2 += *v2++ * tmp0;
653: }
654: y[row++]=sum1;
655: y[row++]=sum2;
656: v1 =v2; /* Since the next block to be processed starts there*/
657: idx +=sz;
658: break;
659: case 3:
660: sum1 = *zt++;
661: sum2 = *zt++;
662: sum3 = *zt++;
663: v2 = v1 + n;
664: v3 = v2 + n;
666: for (n = 0; n< sz-1; n+=2) {
667: i1 = idx[0];
668: i2 = idx[1];
669: idx += 2;
670: tmp0 = x[i1];
671: tmp1 = x[i2];
672: sum1 += v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
673: sum2 += v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
674: sum3 += v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
675: }
676: if (n == sz-1) {
677: tmp0 = x[*idx++];
678: sum1 += *v1++ * tmp0;
679: sum2 += *v2++ * tmp0;
680: sum3 += *v3++ * tmp0;
681: }
682: y[row++]=sum1;
683: y[row++]=sum2;
684: y[row++]=sum3;
685: v1 =v3; /* Since the next block to be processed starts there*/
686: idx +=2*sz;
687: break;
688: case 4:
689: sum1 = *zt++;
690: sum2 = *zt++;
691: sum3 = *zt++;
692: sum4 = *zt++;
693: v2 = v1 + n;
694: v3 = v2 + n;
695: v4 = v3 + n;
697: for (n = 0; n< sz-1; n+=2) {
698: i1 = idx[0];
699: i2 = idx[1];
700: idx += 2;
701: tmp0 = x[i1];
702: tmp1 = x[i2];
703: sum1 += v1[0] * tmp0 + v1[1] *tmp1; v1 += 2;
704: sum2 += v2[0] * tmp0 + v2[1] *tmp1; v2 += 2;
705: sum3 += v3[0] * tmp0 + v3[1] *tmp1; v3 += 2;
706: sum4 += v4[0] * tmp0 + v4[1] *tmp1; v4 += 2;
707: }
708: if (n == sz-1) {
709: tmp0 = x[*idx++];
710: sum1 += *v1++ * tmp0;
711: sum2 += *v2++ * tmp0;
712: sum3 += *v3++ * tmp0;
713: sum4 += *v4++ * tmp0;
714: }
715: y[row++]=sum1;
716: y[row++]=sum2;
717: y[row++]=sum3;
718: y[row++]=sum4;
719: v1 =v4; /* Since the next block to be processed starts there*/
720: idx +=3*sz;
721: break;
722: case 5:
723: sum1 = *zt++;
724: sum2 = *zt++;
725: sum3 = *zt++;
726: sum4 = *zt++;
727: sum5 = *zt++;
728: v2 = v1 + n;
729: v3 = v2 + n;
730: v4 = v3 + n;
731: v5 = v4 + n;
733: for (n = 0; n<sz-1; n+=2) {
734: i1 = idx[0];
735: i2 = idx[1];
736: idx += 2;
737: tmp0 = x[i1];
738: tmp1 = x[i2];
739: sum1 += v1[0] * tmp0 + v1[1] *tmp1; v1 += 2;
740: sum2 += v2[0] * tmp0 + v2[1] *tmp1; v2 += 2;
741: sum3 += v3[0] * tmp0 + v3[1] *tmp1; v3 += 2;
742: sum4 += v4[0] * tmp0 + v4[1] *tmp1; v4 += 2;
743: sum5 += v5[0] * tmp0 + v5[1] *tmp1; v5 += 2;
744: }
745: if (n == sz-1) {
746: tmp0 = x[*idx++];
747: sum1 += *v1++ * tmp0;
748: sum2 += *v2++ * tmp0;
749: sum3 += *v3++ * tmp0;
750: sum4 += *v4++ * tmp0;
751: sum5 += *v5++ * tmp0;
752: }
753: y[row++]=sum1;
754: y[row++]=sum2;
755: y[row++]=sum3;
756: y[row++]=sum4;
757: y[row++]=sum5;
758: v1 =v5; /* Since the next block to be processed starts there */
759: idx +=4*sz;
760: break;
761: default:
762: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported");
763: }
764: }
765: VecRestoreArrayRead(xx,&x);
766: VecRestoreArrayPair(zz,yy,&z,&y);
767: PetscLogFlops(2.0*a->nz);
768: return(0);
769: }
771: /* ----------------------------------------------------------- */
774: PetscErrorCode MatSolve_SeqAIJ_Inode_inplace(Mat A,Vec bb,Vec xx)
775: {
776: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
777: IS iscol = a->col,isrow = a->row;
778: PetscErrorCode ierr;
779: const PetscInt *r,*c,*rout,*cout;
780: PetscInt i,j,n = A->rmap->n,nz;
781: PetscInt node_max,*ns,row,nsz,aii,i0,i1;
782: const PetscInt *ai = a->i,*a_j = a->j,*vi,*ad,*aj;
783: PetscScalar *x,*tmp,*tmps,tmp0,tmp1;
784: PetscScalar sum1,sum2,sum3,sum4,sum5;
785: const MatScalar *v1,*v2,*v3,*v4,*v5,*a_a = a->a,*aa;
786: const PetscScalar *b;
789: if (!a->inode.size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Missing Inode Structure");
790: node_max = a->inode.node_count;
791: ns = a->inode.size; /* Node Size array */
793: VecGetArrayRead(bb,&b);
794: VecGetArray(xx,&x);
795: tmp = a->solve_work;
797: ISGetIndices(isrow,&rout); r = rout;
798: ISGetIndices(iscol,&cout); c = cout + (n-1);
800: /* forward solve the lower triangular */
801: tmps = tmp;
802: aa = a_a;
803: aj = a_j;
804: ad = a->diag;
806: for (i = 0,row = 0; i< node_max; ++i) {
807: nsz = ns[i];
808: aii = ai[row];
809: v1 = aa + aii;
810: vi = aj + aii;
811: nz = ad[row]- aii;
812: if (i < node_max-1) {
813: /* Prefetch the block after the current one, the prefetch itself can't cause a memory error,
814: * but our indexing to determine it's size could. */
815: PetscPrefetchBlock(aj+ai[row+nsz],ad[row+nsz]-ai[row+nsz],0,PETSC_PREFETCH_HINT_NTA); /* indices */
816: /* In my tests, it seems to be better to fetch entire rows instead of just the lower-triangular part */
817: PetscPrefetchBlock(aa+ai[row+nsz],ad[row+nsz+ns[i+1]-1]-ai[row+nsz],0,PETSC_PREFETCH_HINT_NTA);
818: /* for (j=0; j<ns[i+1]; j++) PetscPrefetchBlock(aa+ai[row+nsz+j],ad[row+nsz+j]-ai[row+nsz+j],0,0); */
819: }
821: switch (nsz) { /* Each loop in 'case' is unrolled */
822: case 1:
823: sum1 = b[*r++];
824: for (j=0; j<nz-1; j+=2) {
825: i0 = vi[0];
826: i1 = vi[1];
827: vi +=2;
828: tmp0 = tmps[i0];
829: tmp1 = tmps[i1];
830: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
831: }
832: if (j == nz-1) {
833: tmp0 = tmps[*vi++];
834: sum1 -= *v1++ *tmp0;
835: }
836: tmp[row++]=sum1;
837: break;
838: case 2:
839: sum1 = b[*r++];
840: sum2 = b[*r++];
841: v2 = aa + ai[row+1];
843: for (j=0; j<nz-1; j+=2) {
844: i0 = vi[0];
845: i1 = vi[1];
846: vi +=2;
847: tmp0 = tmps[i0];
848: tmp1 = tmps[i1];
849: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
850: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
851: }
852: if (j == nz-1) {
853: tmp0 = tmps[*vi++];
854: sum1 -= *v1++ *tmp0;
855: sum2 -= *v2++ *tmp0;
856: }
857: sum2 -= *v2++ *sum1;
858: tmp[row++]=sum1;
859: tmp[row++]=sum2;
860: break;
861: case 3:
862: sum1 = b[*r++];
863: sum2 = b[*r++];
864: sum3 = b[*r++];
865: v2 = aa + ai[row+1];
866: v3 = aa + ai[row+2];
868: for (j=0; j<nz-1; j+=2) {
869: i0 = vi[0];
870: i1 = vi[1];
871: vi +=2;
872: tmp0 = tmps[i0];
873: tmp1 = tmps[i1];
874: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
875: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
876: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
877: }
878: if (j == nz-1) {
879: tmp0 = tmps[*vi++];
880: sum1 -= *v1++ *tmp0;
881: sum2 -= *v2++ *tmp0;
882: sum3 -= *v3++ *tmp0;
883: }
884: sum2 -= *v2++ * sum1;
885: sum3 -= *v3++ * sum1;
886: sum3 -= *v3++ * sum2;
888: tmp[row++]=sum1;
889: tmp[row++]=sum2;
890: tmp[row++]=sum3;
891: break;
893: case 4:
894: sum1 = b[*r++];
895: sum2 = b[*r++];
896: sum3 = b[*r++];
897: sum4 = b[*r++];
898: v2 = aa + ai[row+1];
899: v3 = aa + ai[row+2];
900: v4 = aa + ai[row+3];
902: for (j=0; j<nz-1; j+=2) {
903: i0 = vi[0];
904: i1 = vi[1];
905: vi +=2;
906: tmp0 = tmps[i0];
907: tmp1 = tmps[i1];
908: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
909: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
910: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
911: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
912: }
913: if (j == nz-1) {
914: tmp0 = tmps[*vi++];
915: sum1 -= *v1++ *tmp0;
916: sum2 -= *v2++ *tmp0;
917: sum3 -= *v3++ *tmp0;
918: sum4 -= *v4++ *tmp0;
919: }
920: sum2 -= *v2++ * sum1;
921: sum3 -= *v3++ * sum1;
922: sum4 -= *v4++ * sum1;
923: sum3 -= *v3++ * sum2;
924: sum4 -= *v4++ * sum2;
925: sum4 -= *v4++ * sum3;
927: tmp[row++]=sum1;
928: tmp[row++]=sum2;
929: tmp[row++]=sum3;
930: tmp[row++]=sum4;
931: break;
932: case 5:
933: sum1 = b[*r++];
934: sum2 = b[*r++];
935: sum3 = b[*r++];
936: sum4 = b[*r++];
937: sum5 = b[*r++];
938: v2 = aa + ai[row+1];
939: v3 = aa + ai[row+2];
940: v4 = aa + ai[row+3];
941: v5 = aa + ai[row+4];
943: for (j=0; j<nz-1; j+=2) {
944: i0 = vi[0];
945: i1 = vi[1];
946: vi +=2;
947: tmp0 = tmps[i0];
948: tmp1 = tmps[i1];
949: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
950: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
951: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
952: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
953: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
954: }
955: if (j == nz-1) {
956: tmp0 = tmps[*vi++];
957: sum1 -= *v1++ *tmp0;
958: sum2 -= *v2++ *tmp0;
959: sum3 -= *v3++ *tmp0;
960: sum4 -= *v4++ *tmp0;
961: sum5 -= *v5++ *tmp0;
962: }
964: sum2 -= *v2++ * sum1;
965: sum3 -= *v3++ * sum1;
966: sum4 -= *v4++ * sum1;
967: sum5 -= *v5++ * sum1;
968: sum3 -= *v3++ * sum2;
969: sum4 -= *v4++ * sum2;
970: sum5 -= *v5++ * sum2;
971: sum4 -= *v4++ * sum3;
972: sum5 -= *v5++ * sum3;
973: sum5 -= *v5++ * sum4;
975: tmp[row++]=sum1;
976: tmp[row++]=sum2;
977: tmp[row++]=sum3;
978: tmp[row++]=sum4;
979: tmp[row++]=sum5;
980: break;
981: default:
982: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported \n");
983: }
984: }
985: /* backward solve the upper triangular */
986: for (i=node_max -1,row = n-1; i>=0; i--) {
987: nsz = ns[i];
988: aii = ai[row+1] -1;
989: v1 = aa + aii;
990: vi = aj + aii;
991: nz = aii- ad[row];
992: switch (nsz) { /* Each loop in 'case' is unrolled */
993: case 1:
994: sum1 = tmp[row];
996: for (j=nz; j>1; j-=2) {
997: vi -=2;
998: i0 = vi[2];
999: i1 = vi[1];
1000: tmp0 = tmps[i0];
1001: tmp1 = tmps[i1];
1002: v1 -= 2;
1003: sum1 -= v1[2] * tmp0 + v1[1] * tmp1;
1004: }
1005: if (j==1) {
1006: tmp0 = tmps[*vi--];
1007: sum1 -= *v1-- * tmp0;
1008: }
1009: x[*c--] = tmp[row] = sum1*a_a[ad[row]]; row--;
1010: break;
1011: case 2:
1012: sum1 = tmp[row];
1013: sum2 = tmp[row -1];
1014: v2 = aa + ai[row]-1;
1015: for (j=nz; j>1; j-=2) {
1016: vi -=2;
1017: i0 = vi[2];
1018: i1 = vi[1];
1019: tmp0 = tmps[i0];
1020: tmp1 = tmps[i1];
1021: v1 -= 2;
1022: v2 -= 2;
1023: sum1 -= v1[2] * tmp0 + v1[1] * tmp1;
1024: sum2 -= v2[2] * tmp0 + v2[1] * tmp1;
1025: }
1026: if (j==1) {
1027: tmp0 = tmps[*vi--];
1028: sum1 -= *v1-- * tmp0;
1029: sum2 -= *v2-- * tmp0;
1030: }
1032: tmp0 = x[*c--] = tmp[row] = sum1*a_a[ad[row]]; row--;
1033: sum2 -= *v2-- * tmp0;
1034: x[*c--] = tmp[row] = sum2*a_a[ad[row]]; row--;
1035: break;
1036: case 3:
1037: sum1 = tmp[row];
1038: sum2 = tmp[row -1];
1039: sum3 = tmp[row -2];
1040: v2 = aa + ai[row]-1;
1041: v3 = aa + ai[row -1]-1;
1042: for (j=nz; j>1; j-=2) {
1043: vi -=2;
1044: i0 = vi[2];
1045: i1 = vi[1];
1046: tmp0 = tmps[i0];
1047: tmp1 = tmps[i1];
1048: v1 -= 2;
1049: v2 -= 2;
1050: v3 -= 2;
1051: sum1 -= v1[2] * tmp0 + v1[1] * tmp1;
1052: sum2 -= v2[2] * tmp0 + v2[1] * tmp1;
1053: sum3 -= v3[2] * tmp0 + v3[1] * tmp1;
1054: }
1055: if (j==1) {
1056: tmp0 = tmps[*vi--];
1057: sum1 -= *v1-- * tmp0;
1058: sum2 -= *v2-- * tmp0;
1059: sum3 -= *v3-- * tmp0;
1060: }
1061: tmp0 = x[*c--] = tmp[row] = sum1*a_a[ad[row]]; row--;
1062: sum2 -= *v2-- * tmp0;
1063: sum3 -= *v3-- * tmp0;
1064: tmp0 = x[*c--] = tmp[row] = sum2*a_a[ad[row]]; row--;
1065: sum3 -= *v3-- * tmp0;
1066: x[*c--] = tmp[row] = sum3*a_a[ad[row]]; row--;
1068: break;
1069: case 4:
1070: sum1 = tmp[row];
1071: sum2 = tmp[row -1];
1072: sum3 = tmp[row -2];
1073: sum4 = tmp[row -3];
1074: v2 = aa + ai[row]-1;
1075: v3 = aa + ai[row -1]-1;
1076: v4 = aa + ai[row -2]-1;
1078: for (j=nz; j>1; j-=2) {
1079: vi -=2;
1080: i0 = vi[2];
1081: i1 = vi[1];
1082: tmp0 = tmps[i0];
1083: tmp1 = tmps[i1];
1084: v1 -= 2;
1085: v2 -= 2;
1086: v3 -= 2;
1087: v4 -= 2;
1088: sum1 -= v1[2] * tmp0 + v1[1] * tmp1;
1089: sum2 -= v2[2] * tmp0 + v2[1] * tmp1;
1090: sum3 -= v3[2] * tmp0 + v3[1] * tmp1;
1091: sum4 -= v4[2] * tmp0 + v4[1] * tmp1;
1092: }
1093: if (j==1) {
1094: tmp0 = tmps[*vi--];
1095: sum1 -= *v1-- * tmp0;
1096: sum2 -= *v2-- * tmp0;
1097: sum3 -= *v3-- * tmp0;
1098: sum4 -= *v4-- * tmp0;
1099: }
1101: tmp0 = x[*c--] = tmp[row] = sum1*a_a[ad[row]]; row--;
1102: sum2 -= *v2-- * tmp0;
1103: sum3 -= *v3-- * tmp0;
1104: sum4 -= *v4-- * tmp0;
1105: tmp0 = x[*c--] = tmp[row] = sum2*a_a[ad[row]]; row--;
1106: sum3 -= *v3-- * tmp0;
1107: sum4 -= *v4-- * tmp0;
1108: tmp0 = x[*c--] = tmp[row] = sum3*a_a[ad[row]]; row--;
1109: sum4 -= *v4-- * tmp0;
1110: x[*c--] = tmp[row] = sum4*a_a[ad[row]]; row--;
1111: break;
1112: case 5:
1113: sum1 = tmp[row];
1114: sum2 = tmp[row -1];
1115: sum3 = tmp[row -2];
1116: sum4 = tmp[row -3];
1117: sum5 = tmp[row -4];
1118: v2 = aa + ai[row]-1;
1119: v3 = aa + ai[row -1]-1;
1120: v4 = aa + ai[row -2]-1;
1121: v5 = aa + ai[row -3]-1;
1122: for (j=nz; j>1; j-=2) {
1123: vi -= 2;
1124: i0 = vi[2];
1125: i1 = vi[1];
1126: tmp0 = tmps[i0];
1127: tmp1 = tmps[i1];
1128: v1 -= 2;
1129: v2 -= 2;
1130: v3 -= 2;
1131: v4 -= 2;
1132: v5 -= 2;
1133: sum1 -= v1[2] * tmp0 + v1[1] * tmp1;
1134: sum2 -= v2[2] * tmp0 + v2[1] * tmp1;
1135: sum3 -= v3[2] * tmp0 + v3[1] * tmp1;
1136: sum4 -= v4[2] * tmp0 + v4[1] * tmp1;
1137: sum5 -= v5[2] * tmp0 + v5[1] * tmp1;
1138: }
1139: if (j==1) {
1140: tmp0 = tmps[*vi--];
1141: sum1 -= *v1-- * tmp0;
1142: sum2 -= *v2-- * tmp0;
1143: sum3 -= *v3-- * tmp0;
1144: sum4 -= *v4-- * tmp0;
1145: sum5 -= *v5-- * tmp0;
1146: }
1148: tmp0 = x[*c--] = tmp[row] = sum1*a_a[ad[row]]; row--;
1149: sum2 -= *v2-- * tmp0;
1150: sum3 -= *v3-- * tmp0;
1151: sum4 -= *v4-- * tmp0;
1152: sum5 -= *v5-- * tmp0;
1153: tmp0 = x[*c--] = tmp[row] = sum2*a_a[ad[row]]; row--;
1154: sum3 -= *v3-- * tmp0;
1155: sum4 -= *v4-- * tmp0;
1156: sum5 -= *v5-- * tmp0;
1157: tmp0 = x[*c--] = tmp[row] = sum3*a_a[ad[row]]; row--;
1158: sum4 -= *v4-- * tmp0;
1159: sum5 -= *v5-- * tmp0;
1160: tmp0 = x[*c--] = tmp[row] = sum4*a_a[ad[row]]; row--;
1161: sum5 -= *v5-- * tmp0;
1162: x[*c--] = tmp[row] = sum5*a_a[ad[row]]; row--;
1163: break;
1164: default:
1165: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported \n");
1166: }
1167: }
1168: ISRestoreIndices(isrow,&rout);
1169: ISRestoreIndices(iscol,&cout);
1170: VecRestoreArrayRead(bb,&b);
1171: VecRestoreArray(xx,&x);
1172: PetscLogFlops(2.0*a->nz - A->cmap->n);
1173: return(0);
1174: }
1178: PetscErrorCode MatLUFactorNumeric_SeqAIJ_Inode(Mat B,Mat A,const MatFactorInfo *info)
1179: {
1180: Mat C =B;
1181: Mat_SeqAIJ *a =(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ*)C->data;
1182: IS isrow = b->row,isicol = b->icol;
1183: PetscErrorCode ierr;
1184: const PetscInt *r,*ic,*ics;
1185: const PetscInt n=A->rmap->n,*ai=a->i,*aj=a->j,*bi=b->i,*bj=b->j,*bdiag=b->diag;
1186: PetscInt i,j,k,nz,nzL,row,*pj;
1187: const PetscInt *ajtmp,*bjtmp;
1188: MatScalar *pc,*pc1,*pc2,*pc3,*pc4,mul1,mul2,mul3,mul4,*pv,*rtmp1,*rtmp2,*rtmp3,*rtmp4;
1189: const MatScalar *aa=a->a,*v,*v1,*v2,*v3,*v4;
1190: FactorShiftCtx sctx;
1191: const PetscInt *ddiag;
1192: PetscReal rs;
1193: MatScalar d;
1194: PetscInt inod,nodesz,node_max,col;
1195: const PetscInt *ns;
1196: PetscInt *tmp_vec1,*tmp_vec2,*nsmap;
1199: /* MatPivotSetUp(): initialize shift context sctx */
1200: PetscMemzero(&sctx,sizeof(FactorShiftCtx));
1202: if (info->shifttype == (PetscReal)MAT_SHIFT_POSITIVE_DEFINITE) { /* set sctx.shift_top=max{rs} */
1203: ddiag = a->diag;
1204: sctx.shift_top = info->zeropivot;
1205: for (i=0; i<n; i++) {
1206: /* calculate sum(|aij|)-RealPart(aii), amt of shift needed for this row */
1207: d = (aa)[ddiag[i]];
1208: rs = -PetscAbsScalar(d) - PetscRealPart(d);
1209: v = aa+ai[i];
1210: nz = ai[i+1] - ai[i];
1211: for (j=0; j<nz; j++) rs += PetscAbsScalar(v[j]);
1212: if (rs>sctx.shift_top) sctx.shift_top = rs;
1213: }
1214: sctx.shift_top *= 1.1;
1215: sctx.nshift_max = 5;
1216: sctx.shift_lo = 0.;
1217: sctx.shift_hi = 1.;
1218: }
1220: ISGetIndices(isrow,&r);
1221: ISGetIndices(isicol,&ic);
1223: PetscCalloc4(n,&rtmp1,n,&rtmp2,n,&rtmp3,n,&rtmp4);
1224: ics = ic;
1226: node_max = a->inode.node_count;
1227: ns = a->inode.size;
1228: if (!ns) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Matrix without inode information");
1230: /* If max inode size > 4, split it into two inodes.*/
1231: /* also map the inode sizes according to the ordering */
1232: PetscMalloc1(n+1,&tmp_vec1);
1233: for (i=0,j=0; i<node_max; ++i,++j) {
1234: if (ns[i] > 4) {
1235: tmp_vec1[j] = 4;
1236: ++j;
1237: tmp_vec1[j] = ns[i] - tmp_vec1[j-1];
1238: } else {
1239: tmp_vec1[j] = ns[i];
1240: }
1241: }
1242: /* Use the correct node_max */
1243: node_max = j;
1245: /* Now reorder the inode info based on mat re-ordering info */
1246: /* First create a row -> inode_size_array_index map */
1247: PetscMalloc1(n+1,&nsmap);
1248: PetscMalloc1(node_max+1,&tmp_vec2);
1249: for (i=0,row=0; i<node_max; i++) {
1250: nodesz = tmp_vec1[i];
1251: for (j=0; j<nodesz; j++,row++) {
1252: nsmap[row] = i;
1253: }
1254: }
1255: /* Using nsmap, create a reordered ns structure */
1256: for (i=0,j=0; i< node_max; i++) {
1257: nodesz = tmp_vec1[nsmap[r[j]]]; /* here the reordered row_no is in r[] */
1258: tmp_vec2[i] = nodesz;
1259: j += nodesz;
1260: }
1261: PetscFree(nsmap);
1262: PetscFree(tmp_vec1);
1264: /* Now use the correct ns */
1265: ns = tmp_vec2;
1267: do {
1268: sctx.newshift = PETSC_FALSE;
1269: /* Now loop over each block-row, and do the factorization */
1270: for (inod=0,i=0; inod<node_max; inod++) { /* i: row index; inod: inode index */
1271: nodesz = ns[inod];
1273: switch (nodesz) {
1274: case 1:
1275: /*----------*/
1276: /* zero rtmp1 */
1277: /* L part */
1278: nz = bi[i+1] - bi[i];
1279: bjtmp = bj + bi[i];
1280: for (j=0; j<nz; j++) rtmp1[bjtmp[j]] = 0.0;
1282: /* U part */
1283: nz = bdiag[i]-bdiag[i+1];
1284: bjtmp = bj + bdiag[i+1]+1;
1285: for (j=0; j<nz; j++) rtmp1[bjtmp[j]] = 0.0;
1287: /* load in initial (unfactored row) */
1288: nz = ai[r[i]+1] - ai[r[i]];
1289: ajtmp = aj + ai[r[i]];
1290: v = aa + ai[r[i]];
1291: for (j=0; j<nz; j++) rtmp1[ics[ajtmp[j]]] = v[j];
1293: /* ZeropivotApply() */
1294: rtmp1[i] += sctx.shift_amount; /* shift the diagonal of the matrix */
1296: /* elimination */
1297: bjtmp = bj + bi[i];
1298: row = *bjtmp++;
1299: nzL = bi[i+1] - bi[i];
1300: for (k=0; k < nzL; k++) {
1301: pc = rtmp1 + row;
1302: if (*pc != 0.0) {
1303: pv = b->a + bdiag[row];
1304: mul1 = *pc * (*pv);
1305: *pc = mul1;
1306: pj = b->j + bdiag[row+1]+1; /* beginning of U(row,:) */
1307: pv = b->a + bdiag[row+1]+1;
1308: nz = bdiag[row]-bdiag[row+1]-1; /* num of entries in U(row,:) excluding diag */
1309: for (j=0; j<nz; j++) rtmp1[pj[j]] -= mul1 * pv[j];
1310: PetscLogFlops(1+2*nz);
1311: }
1312: row = *bjtmp++;
1313: }
1315: /* finished row so stick it into b->a */
1316: rs = 0.0;
1317: /* L part */
1318: pv = b->a + bi[i];
1319: pj = b->j + bi[i];
1320: nz = bi[i+1] - bi[i];
1321: for (j=0; j<nz; j++) {
1322: pv[j] = rtmp1[pj[j]]; rs += PetscAbsScalar(pv[j]);
1323: }
1325: /* U part */
1326: pv = b->a + bdiag[i+1]+1;
1327: pj = b->j + bdiag[i+1]+1;
1328: nz = bdiag[i] - bdiag[i+1]-1;
1329: for (j=0; j<nz; j++) {
1330: pv[j] = rtmp1[pj[j]]; rs += PetscAbsScalar(pv[j]);
1331: }
1333: /* Check zero pivot */
1334: sctx.rs = rs;
1335: sctx.pv = rtmp1[i];
1336: MatPivotCheck(B,A,info,&sctx,i);
1337: if (sctx.newshift) break;
1339: /* Mark diagonal and invert diagonal for simplier triangular solves */
1340: pv = b->a + bdiag[i];
1341: *pv = 1.0/sctx.pv; /* sctx.pv = rtmp1[i]+shiftamount if shifttype==MAT_SHIFT_INBLOCKS */
1342: break;
1344: case 2:
1345: /*----------*/
1346: /* zero rtmp1 and rtmp2 */
1347: /* L part */
1348: nz = bi[i+1] - bi[i];
1349: bjtmp = bj + bi[i];
1350: for (j=0; j<nz; j++) {
1351: col = bjtmp[j];
1352: rtmp1[col] = 0.0; rtmp2[col] = 0.0;
1353: }
1355: /* U part */
1356: nz = bdiag[i]-bdiag[i+1];
1357: bjtmp = bj + bdiag[i+1]+1;
1358: for (j=0; j<nz; j++) {
1359: col = bjtmp[j];
1360: rtmp1[col] = 0.0; rtmp2[col] = 0.0;
1361: }
1363: /* load in initial (unfactored row) */
1364: nz = ai[r[i]+1] - ai[r[i]];
1365: ajtmp = aj + ai[r[i]];
1366: v1 = aa + ai[r[i]]; v2 = aa + ai[r[i]+1];
1367: for (j=0; j<nz; j++) {
1368: col = ics[ajtmp[j]];
1369: rtmp1[col] = v1[j]; rtmp2[col] = v2[j];
1370: }
1371: /* ZeropivotApply(): shift the diagonal of the matrix */
1372: rtmp1[i] += sctx.shift_amount; rtmp2[i+1] += sctx.shift_amount;
1374: /* elimination */
1375: bjtmp = bj + bi[i];
1376: row = *bjtmp++; /* pivot row */
1377: nzL = bi[i+1] - bi[i];
1378: for (k=0; k < nzL; k++) {
1379: pc1 = rtmp1 + row;
1380: pc2 = rtmp2 + row;
1381: if (*pc1 != 0.0 || *pc2 != 0.0) {
1382: pv = b->a + bdiag[row];
1383: mul1 = *pc1*(*pv); mul2 = *pc2*(*pv);
1384: *pc1 = mul1; *pc2 = mul2;
1386: pj = b->j + bdiag[row+1]+1; /* beginning of U(row,:) */
1387: pv = b->a + bdiag[row+1]+1;
1388: nz = bdiag[row]-bdiag[row+1]-1; /* num of entries in U(row,:) excluding diag */
1389: for (j=0; j<nz; j++) {
1390: col = pj[j];
1391: rtmp1[col] -= mul1 * pv[j];
1392: rtmp2[col] -= mul2 * pv[j];
1393: }
1394: PetscLogFlops(2+4*nz);
1395: }
1396: row = *bjtmp++;
1397: }
1399: /* finished row i; check zero pivot, then stick row i into b->a */
1400: rs = 0.0;
1401: /* L part */
1402: pc1 = b->a + bi[i];
1403: pj = b->j + bi[i];
1404: nz = bi[i+1] - bi[i];
1405: for (j=0; j<nz; j++) {
1406: col = pj[j];
1407: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1408: }
1409: /* U part */
1410: pc1 = b->a + bdiag[i+1]+1;
1411: pj = b->j + bdiag[i+1]+1;
1412: nz = bdiag[i] - bdiag[i+1] - 1; /* exclude diagonal */
1413: for (j=0; j<nz; j++) {
1414: col = pj[j];
1415: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1416: }
1418: sctx.rs = rs;
1419: sctx.pv = rtmp1[i];
1420: MatPivotCheck(B,A,info,&sctx,i);
1421: if (sctx.newshift) break;
1422: pc1 = b->a + bdiag[i]; /* Mark diagonal */
1423: *pc1 = 1.0/sctx.pv;
1425: /* Now take care of diagonal 2x2 block. */
1426: pc2 = rtmp2 + i;
1427: if (*pc2 != 0.0) {
1428: mul1 = (*pc2)*(*pc1); /* *pc1=diag[i] is inverted! */
1429: *pc2 = mul1; /* insert L entry */
1430: pj = b->j + bdiag[i+1]+1; /* beginning of U(i,:) */
1431: nz = bdiag[i]-bdiag[i+1]-1; /* num of entries in U(i,:) excluding diag */
1432: for (j=0; j<nz; j++) {
1433: col = pj[j]; rtmp2[col] -= mul1 * rtmp1[col];
1434: }
1435: PetscLogFlops(1+2*nz);
1436: }
1438: /* finished row i+1; check zero pivot, then stick row i+1 into b->a */
1439: rs = 0.0;
1440: /* L part */
1441: pc2 = b->a + bi[i+1];
1442: pj = b->j + bi[i+1];
1443: nz = bi[i+2] - bi[i+1];
1444: for (j=0; j<nz; j++) {
1445: col = pj[j];
1446: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1447: }
1448: /* U part */
1449: pc2 = b->a + bdiag[i+2]+1;
1450: pj = b->j + bdiag[i+2]+1;
1451: nz = bdiag[i+1] - bdiag[i+2] - 1; /* exclude diagonal */
1452: for (j=0; j<nz; j++) {
1453: col = pj[j];
1454: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1455: }
1457: sctx.rs = rs;
1458: sctx.pv = rtmp2[i+1];
1459: MatPivotCheck(B,A,info,&sctx,i+1);
1460: if (sctx.newshift) break;
1461: pc2 = b->a + bdiag[i+1];
1462: *pc2 = 1.0/sctx.pv;
1463: break;
1465: case 3:
1466: /*----------*/
1467: /* zero rtmp */
1468: /* L part */
1469: nz = bi[i+1] - bi[i];
1470: bjtmp = bj + bi[i];
1471: for (j=0; j<nz; j++) {
1472: col = bjtmp[j];
1473: rtmp1[col] = 0.0; rtmp2[col] = 0.0; rtmp3[col] = 0.0;
1474: }
1476: /* U part */
1477: nz = bdiag[i]-bdiag[i+1];
1478: bjtmp = bj + bdiag[i+1]+1;
1479: for (j=0; j<nz; j++) {
1480: col = bjtmp[j];
1481: rtmp1[col] = 0.0; rtmp2[col] = 0.0; rtmp3[col] = 0.0;
1482: }
1484: /* load in initial (unfactored row) */
1485: nz = ai[r[i]+1] - ai[r[i]];
1486: ajtmp = aj + ai[r[i]];
1487: v1 = aa + ai[r[i]]; v2 = aa + ai[r[i]+1]; v3 = aa + ai[r[i]+2];
1488: for (j=0; j<nz; j++) {
1489: col = ics[ajtmp[j]];
1490: rtmp1[col] = v1[j]; rtmp2[col] = v2[j]; rtmp3[col] = v3[j];
1491: }
1492: /* ZeropivotApply(): shift the diagonal of the matrix */
1493: rtmp1[i] += sctx.shift_amount; rtmp2[i+1] += sctx.shift_amount; rtmp3[i+2] += sctx.shift_amount;
1495: /* elimination */
1496: bjtmp = bj + bi[i];
1497: row = *bjtmp++; /* pivot row */
1498: nzL = bi[i+1] - bi[i];
1499: for (k=0; k < nzL; k++) {
1500: pc1 = rtmp1 + row;
1501: pc2 = rtmp2 + row;
1502: pc3 = rtmp3 + row;
1503: if (*pc1 != 0.0 || *pc2 != 0.0 || *pc3 != 0.0) {
1504: pv = b->a + bdiag[row];
1505: mul1 = *pc1*(*pv); mul2 = *pc2*(*pv); mul3 = *pc3*(*pv);
1506: *pc1 = mul1; *pc2 = mul2; *pc3 = mul3;
1508: pj = b->j + bdiag[row+1]+1; /* beginning of U(row,:) */
1509: pv = b->a + bdiag[row+1]+1;
1510: nz = bdiag[row]-bdiag[row+1]-1; /* num of entries in U(row,:) excluding diag */
1511: for (j=0; j<nz; j++) {
1512: col = pj[j];
1513: rtmp1[col] -= mul1 * pv[j];
1514: rtmp2[col] -= mul2 * pv[j];
1515: rtmp3[col] -= mul3 * pv[j];
1516: }
1517: PetscLogFlops(3+6*nz);
1518: }
1519: row = *bjtmp++;
1520: }
1522: /* finished row i; check zero pivot, then stick row i into b->a */
1523: rs = 0.0;
1524: /* L part */
1525: pc1 = b->a + bi[i];
1526: pj = b->j + bi[i];
1527: nz = bi[i+1] - bi[i];
1528: for (j=0; j<nz; j++) {
1529: col = pj[j];
1530: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1531: }
1532: /* U part */
1533: pc1 = b->a + bdiag[i+1]+1;
1534: pj = b->j + bdiag[i+1]+1;
1535: nz = bdiag[i] - bdiag[i+1] - 1; /* exclude diagonal */
1536: for (j=0; j<nz; j++) {
1537: col = pj[j];
1538: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1539: }
1541: sctx.rs = rs;
1542: sctx.pv = rtmp1[i];
1543: MatPivotCheck(B,A,info,&sctx,i);
1544: if (sctx.newshift) break;
1545: pc1 = b->a + bdiag[i]; /* Mark diag[i] */
1546: *pc1 = 1.0/sctx.pv;
1548: /* Now take care of 1st column of diagonal 3x3 block. */
1549: pc2 = rtmp2 + i;
1550: pc3 = rtmp3 + i;
1551: if (*pc2 != 0.0 || *pc3 != 0.0) {
1552: mul2 = (*pc2)*(*pc1); *pc2 = mul2;
1553: mul3 = (*pc3)*(*pc1); *pc3 = mul3;
1554: pj = b->j + bdiag[i+1]+1; /* beginning of U(i,:) */
1555: nz = bdiag[i]-bdiag[i+1]-1; /* num of entries in U(i,:) excluding diag */
1556: for (j=0; j<nz; j++) {
1557: col = pj[j];
1558: rtmp2[col] -= mul2 * rtmp1[col];
1559: rtmp3[col] -= mul3 * rtmp1[col];
1560: }
1561: PetscLogFlops(2+4*nz);
1562: }
1564: /* finished row i+1; check zero pivot, then stick row i+1 into b->a */
1565: rs = 0.0;
1566: /* L part */
1567: pc2 = b->a + bi[i+1];
1568: pj = b->j + bi[i+1];
1569: nz = bi[i+2] - bi[i+1];
1570: for (j=0; j<nz; j++) {
1571: col = pj[j];
1572: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1573: }
1574: /* U part */
1575: pc2 = b->a + bdiag[i+2]+1;
1576: pj = b->j + bdiag[i+2]+1;
1577: nz = bdiag[i+1] - bdiag[i+2] - 1; /* exclude diagonal */
1578: for (j=0; j<nz; j++) {
1579: col = pj[j];
1580: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1581: }
1583: sctx.rs = rs;
1584: sctx.pv = rtmp2[i+1];
1585: MatPivotCheck(B,A,info,&sctx,i+1);
1586: if (sctx.newshift) break;
1587: pc2 = b->a + bdiag[i+1];
1588: *pc2 = 1.0/sctx.pv; /* Mark diag[i+1] */
1590: /* Now take care of 2nd column of diagonal 3x3 block. */
1591: pc3 = rtmp3 + i+1;
1592: if (*pc3 != 0.0) {
1593: mul3 = (*pc3)*(*pc2); *pc3 = mul3;
1594: pj = b->j + bdiag[i+2]+1; /* beginning of U(i+1,:) */
1595: nz = bdiag[i+1]-bdiag[i+2]-1; /* num of entries in U(i+1,:) excluding diag */
1596: for (j=0; j<nz; j++) {
1597: col = pj[j];
1598: rtmp3[col] -= mul3 * rtmp2[col];
1599: }
1600: PetscLogFlops(1+2*nz);
1601: }
1603: /* finished i+2; check zero pivot, then stick row i+2 into b->a */
1604: rs = 0.0;
1605: /* L part */
1606: pc3 = b->a + bi[i+2];
1607: pj = b->j + bi[i+2];
1608: nz = bi[i+3] - bi[i+2];
1609: for (j=0; j<nz; j++) {
1610: col = pj[j];
1611: pc3[j] = rtmp3[col]; rs += PetscAbsScalar(pc3[j]);
1612: }
1613: /* U part */
1614: pc3 = b->a + bdiag[i+3]+1;
1615: pj = b->j + bdiag[i+3]+1;
1616: nz = bdiag[i+2] - bdiag[i+3] - 1; /* exclude diagonal */
1617: for (j=0; j<nz; j++) {
1618: col = pj[j];
1619: pc3[j] = rtmp3[col]; rs += PetscAbsScalar(pc3[j]);
1620: }
1622: sctx.rs = rs;
1623: sctx.pv = rtmp3[i+2];
1624: MatPivotCheck(B,A,info,&sctx,i+2);
1625: if (sctx.newshift) break;
1626: pc3 = b->a + bdiag[i+2];
1627: *pc3 = 1.0/sctx.pv; /* Mark diag[i+2] */
1628: break;
1629: case 4:
1630: /*----------*/
1631: /* zero rtmp */
1632: /* L part */
1633: nz = bi[i+1] - bi[i];
1634: bjtmp = bj + bi[i];
1635: for (j=0; j<nz; j++) {
1636: col = bjtmp[j];
1637: rtmp1[col] = 0.0; rtmp2[col] = 0.0; rtmp3[col] = 0.0;rtmp4[col] = 0.0;
1638: }
1640: /* U part */
1641: nz = bdiag[i]-bdiag[i+1];
1642: bjtmp = bj + bdiag[i+1]+1;
1643: for (j=0; j<nz; j++) {
1644: col = bjtmp[j];
1645: rtmp1[col] = 0.0; rtmp2[col] = 0.0; rtmp3[col] = 0.0; rtmp4[col] = 0.0;
1646: }
1648: /* load in initial (unfactored row) */
1649: nz = ai[r[i]+1] - ai[r[i]];
1650: ajtmp = aj + ai[r[i]];
1651: v1 = aa + ai[r[i]]; v2 = aa + ai[r[i]+1]; v3 = aa + ai[r[i]+2]; v4 = aa + ai[r[i]+3];
1652: for (j=0; j<nz; j++) {
1653: col = ics[ajtmp[j]];
1654: rtmp1[col] = v1[j]; rtmp2[col] = v2[j]; rtmp3[col] = v3[j]; rtmp4[col] = v4[j];
1655: }
1656: /* ZeropivotApply(): shift the diagonal of the matrix */
1657: rtmp1[i] += sctx.shift_amount; rtmp2[i+1] += sctx.shift_amount; rtmp3[i+2] += sctx.shift_amount; rtmp4[i+3] += sctx.shift_amount;
1659: /* elimination */
1660: bjtmp = bj + bi[i];
1661: row = *bjtmp++; /* pivot row */
1662: nzL = bi[i+1] - bi[i];
1663: for (k=0; k < nzL; k++) {
1664: pc1 = rtmp1 + row;
1665: pc2 = rtmp2 + row;
1666: pc3 = rtmp3 + row;
1667: pc4 = rtmp4 + row;
1668: if (*pc1 != 0.0 || *pc2 != 0.0 || *pc3 != 0.0 || *pc4 != 0.0) {
1669: pv = b->a + bdiag[row];
1670: mul1 = *pc1*(*pv); mul2 = *pc2*(*pv); mul3 = *pc3*(*pv); mul4 = *pc4*(*pv);
1671: *pc1 = mul1; *pc2 = mul2; *pc3 = mul3; *pc4 = mul4;
1673: pj = b->j + bdiag[row+1]+1; /* beginning of U(row,:) */
1674: pv = b->a + bdiag[row+1]+1;
1675: nz = bdiag[row]-bdiag[row+1]-1; /* num of entries in U(row,:) excluding diag */
1676: for (j=0; j<nz; j++) {
1677: col = pj[j];
1678: rtmp1[col] -= mul1 * pv[j];
1679: rtmp2[col] -= mul2 * pv[j];
1680: rtmp3[col] -= mul3 * pv[j];
1681: rtmp4[col] -= mul4 * pv[j];
1682: }
1683: PetscLogFlops(4+8*nz);
1684: }
1685: row = *bjtmp++;
1686: }
1688: /* finished row i; check zero pivot, then stick row i into b->a */
1689: rs = 0.0;
1690: /* L part */
1691: pc1 = b->a + bi[i];
1692: pj = b->j + bi[i];
1693: nz = bi[i+1] - bi[i];
1694: for (j=0; j<nz; j++) {
1695: col = pj[j];
1696: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1697: }
1698: /* U part */
1699: pc1 = b->a + bdiag[i+1]+1;
1700: pj = b->j + bdiag[i+1]+1;
1701: nz = bdiag[i] - bdiag[i+1] - 1; /* exclude diagonal */
1702: for (j=0; j<nz; j++) {
1703: col = pj[j];
1704: pc1[j] = rtmp1[col]; rs += PetscAbsScalar(pc1[j]);
1705: }
1707: sctx.rs = rs;
1708: sctx.pv = rtmp1[i];
1709: MatPivotCheck(B,A,info,&sctx,i);
1710: if (sctx.newshift) break;
1711: pc1 = b->a + bdiag[i]; /* Mark diag[i] */
1712: *pc1 = 1.0/sctx.pv;
1714: /* Now take care of 1st column of diagonal 4x4 block. */
1715: pc2 = rtmp2 + i;
1716: pc3 = rtmp3 + i;
1717: pc4 = rtmp4 + i;
1718: if (*pc2 != 0.0 || *pc3 != 0.0 || *pc4 != 0.0) {
1719: mul2 = (*pc2)*(*pc1); *pc2 = mul2;
1720: mul3 = (*pc3)*(*pc1); *pc3 = mul3;
1721: mul4 = (*pc4)*(*pc1); *pc4 = mul4;
1722: pj = b->j + bdiag[i+1]+1; /* beginning of U(i,:) */
1723: nz = bdiag[i]-bdiag[i+1]-1; /* num of entries in U(i,:) excluding diag */
1724: for (j=0; j<nz; j++) {
1725: col = pj[j];
1726: rtmp2[col] -= mul2 * rtmp1[col];
1727: rtmp3[col] -= mul3 * rtmp1[col];
1728: rtmp4[col] -= mul4 * rtmp1[col];
1729: }
1730: PetscLogFlops(3+6*nz);
1731: }
1733: /* finished row i+1; check zero pivot, then stick row i+1 into b->a */
1734: rs = 0.0;
1735: /* L part */
1736: pc2 = b->a + bi[i+1];
1737: pj = b->j + bi[i+1];
1738: nz = bi[i+2] - bi[i+1];
1739: for (j=0; j<nz; j++) {
1740: col = pj[j];
1741: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1742: }
1743: /* U part */
1744: pc2 = b->a + bdiag[i+2]+1;
1745: pj = b->j + bdiag[i+2]+1;
1746: nz = bdiag[i+1] - bdiag[i+2] - 1; /* exclude diagonal */
1747: for (j=0; j<nz; j++) {
1748: col = pj[j];
1749: pc2[j] = rtmp2[col]; rs += PetscAbsScalar(pc2[j]);
1750: }
1752: sctx.rs = rs;
1753: sctx.pv = rtmp2[i+1];
1754: MatPivotCheck(B,A,info,&sctx,i+1);
1755: if (sctx.newshift) break;
1756: pc2 = b->a + bdiag[i+1];
1757: *pc2 = 1.0/sctx.pv; /* Mark diag[i+1] */
1759: /* Now take care of 2nd column of diagonal 4x4 block. */
1760: pc3 = rtmp3 + i+1;
1761: pc4 = rtmp4 + i+1;
1762: if (*pc3 != 0.0 || *pc4 != 0.0) {
1763: mul3 = (*pc3)*(*pc2); *pc3 = mul3;
1764: mul4 = (*pc4)*(*pc2); *pc4 = mul4;
1765: pj = b->j + bdiag[i+2]+1; /* beginning of U(i+1,:) */
1766: nz = bdiag[i+1]-bdiag[i+2]-1; /* num of entries in U(i+1,:) excluding diag */
1767: for (j=0; j<nz; j++) {
1768: col = pj[j];
1769: rtmp3[col] -= mul3 * rtmp2[col];
1770: rtmp4[col] -= mul4 * rtmp2[col];
1771: }
1772: PetscLogFlops(4*nz);
1773: }
1775: /* finished i+2; check zero pivot, then stick row i+2 into b->a */
1776: rs = 0.0;
1777: /* L part */
1778: pc3 = b->a + bi[i+2];
1779: pj = b->j + bi[i+2];
1780: nz = bi[i+3] - bi[i+2];
1781: for (j=0; j<nz; j++) {
1782: col = pj[j];
1783: pc3[j] = rtmp3[col]; rs += PetscAbsScalar(pc3[j]);
1784: }
1785: /* U part */
1786: pc3 = b->a + bdiag[i+3]+1;
1787: pj = b->j + bdiag[i+3]+1;
1788: nz = bdiag[i+2] - bdiag[i+3] - 1; /* exclude diagonal */
1789: for (j=0; j<nz; j++) {
1790: col = pj[j];
1791: pc3[j] = rtmp3[col]; rs += PetscAbsScalar(pc3[j]);
1792: }
1794: sctx.rs = rs;
1795: sctx.pv = rtmp3[i+2];
1796: MatPivotCheck(B,A,info,&sctx,i+2);
1797: if (sctx.newshift) break;
1798: pc3 = b->a + bdiag[i+2];
1799: *pc3 = 1.0/sctx.pv; /* Mark diag[i+2] */
1801: /* Now take care of 3rd column of diagonal 4x4 block. */
1802: pc4 = rtmp4 + i+2;
1803: if (*pc4 != 0.0) {
1804: mul4 = (*pc4)*(*pc3); *pc4 = mul4;
1805: pj = b->j + bdiag[i+3]+1; /* beginning of U(i+2,:) */
1806: nz = bdiag[i+2]-bdiag[i+3]-1; /* num of entries in U(i+2,:) excluding diag */
1807: for (j=0; j<nz; j++) {
1808: col = pj[j];
1809: rtmp4[col] -= mul4 * rtmp3[col];
1810: }
1811: PetscLogFlops(1+2*nz);
1812: }
1814: /* finished i+3; check zero pivot, then stick row i+3 into b->a */
1815: rs = 0.0;
1816: /* L part */
1817: pc4 = b->a + bi[i+3];
1818: pj = b->j + bi[i+3];
1819: nz = bi[i+4] - bi[i+3];
1820: for (j=0; j<nz; j++) {
1821: col = pj[j];
1822: pc4[j] = rtmp4[col]; rs += PetscAbsScalar(pc4[j]);
1823: }
1824: /* U part */
1825: pc4 = b->a + bdiag[i+4]+1;
1826: pj = b->j + bdiag[i+4]+1;
1827: nz = bdiag[i+3] - bdiag[i+4] - 1; /* exclude diagonal */
1828: for (j=0; j<nz; j++) {
1829: col = pj[j];
1830: pc4[j] = rtmp4[col]; rs += PetscAbsScalar(pc4[j]);
1831: }
1833: sctx.rs = rs;
1834: sctx.pv = rtmp4[i+3];
1835: MatPivotCheck(B,A,info,&sctx,i+3);
1836: if (sctx.newshift) break;
1837: pc4 = b->a + bdiag[i+3];
1838: *pc4 = 1.0/sctx.pv; /* Mark diag[i+3] */
1839: break;
1841: default:
1842: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Node size not yet supported \n");
1843: }
1844: if (sctx.newshift) break; /* break for (inod=0,i=0; inod<node_max; inod++) */
1845: i += nodesz; /* Update the row */
1846: }
1848: /* MatPivotRefine() */
1849: if (info->shifttype == (PetscReal) MAT_SHIFT_POSITIVE_DEFINITE && !sctx.newshift && sctx.shift_fraction>0 && sctx.nshift<sctx.nshift_max) {
1850: /*
1851: * if no shift in this attempt & shifting & started shifting & can refine,
1852: * then try lower shift
1853: */
1854: sctx.shift_hi = sctx.shift_fraction;
1855: sctx.shift_fraction = (sctx.shift_hi+sctx.shift_lo)/2.;
1856: sctx.shift_amount = sctx.shift_fraction * sctx.shift_top;
1857: sctx.newshift = PETSC_TRUE;
1858: sctx.nshift++;
1859: }
1860: } while (sctx.newshift);
1862: PetscFree4(rtmp1,rtmp2,rtmp3,rtmp4);
1863: PetscFree(tmp_vec2);
1864: ISRestoreIndices(isicol,&ic);
1865: ISRestoreIndices(isrow,&r);
1867: if (b->inode.size) {
1868: C->ops->solve = MatSolve_SeqAIJ_Inode;
1869: } else {
1870: C->ops->solve = MatSolve_SeqAIJ;
1871: }
1872: C->ops->solveadd = MatSolveAdd_SeqAIJ;
1873: C->ops->solvetranspose = MatSolveTranspose_SeqAIJ;
1874: C->ops->solvetransposeadd = MatSolveTransposeAdd_SeqAIJ;
1875: C->ops->matsolve = MatMatSolve_SeqAIJ;
1876: C->assembled = PETSC_TRUE;
1877: C->preallocated = PETSC_TRUE;
1879: PetscLogFlops(C->cmap->n);
1881: /* MatShiftView(A,info,&sctx) */
1882: if (sctx.nshift) {
1883: if (info->shifttype == (PetscReal) MAT_SHIFT_POSITIVE_DEFINITE) {
1884: PetscInfo4(A,"number of shift_pd tries %D, shift_amount %g, diagonal shifted up by %e fraction top_value %e\n",sctx.nshift,(double)sctx.shift_amount,(double)sctx.shift_fraction,(double)sctx.shift_top);
1885: } else if (info->shifttype == (PetscReal)MAT_SHIFT_NONZERO) {
1886: PetscInfo2(A,"number of shift_nz tries %D, shift_amount %g\n",sctx.nshift,(double)sctx.shift_amount);
1887: } else if (info->shifttype == (PetscReal)MAT_SHIFT_INBLOCKS) {
1888: PetscInfo2(A,"number of shift_inblocks applied %D, each shift_amount %g\n",sctx.nshift,(double)info->shiftamount);
1889: }
1890: }
1891: return(0);
1892: }
1896: PetscErrorCode MatLUFactorNumeric_SeqAIJ_Inode_inplace(Mat B,Mat A,const MatFactorInfo *info)
1897: {
1898: Mat C = B;
1899: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b = (Mat_SeqAIJ*)C->data;
1900: IS iscol = b->col,isrow = b->row,isicol = b->icol;
1901: PetscErrorCode ierr;
1902: const PetscInt *r,*ic,*c,*ics;
1903: PetscInt n = A->rmap->n,*bi = b->i;
1904: PetscInt *bj = b->j,*nbj=b->j +1,*ajtmp,*bjtmp,nz,nz_tmp,row,prow;
1905: PetscInt i,j,idx,*bd = b->diag,node_max,nodesz;
1906: PetscInt *ai = a->i,*aj = a->j;
1907: PetscInt *ns,*tmp_vec1,*tmp_vec2,*nsmap,*pj;
1908: PetscScalar mul1,mul2,mul3,tmp;
1909: MatScalar *pc1,*pc2,*pc3,*ba = b->a,*pv,*rtmp11,*rtmp22,*rtmp33;
1910: const MatScalar *v1,*v2,*v3,*aa = a->a,*rtmp1;
1911: PetscReal rs=0.0;
1912: FactorShiftCtx sctx;
1915: sctx.shift_top = 0;
1916: sctx.nshift_max = 0;
1917: sctx.shift_lo = 0;
1918: sctx.shift_hi = 0;
1919: sctx.shift_fraction = 0;
1921: /* if both shift schemes are chosen by user, only use info->shiftpd */
1922: if (info->shifttype==(PetscReal)MAT_SHIFT_POSITIVE_DEFINITE) { /* set sctx.shift_top=max{rs} */
1923: sctx.shift_top = 0;
1924: for (i=0; i<n; i++) {
1925: /* calculate rs = sum(|aij|)-RealPart(aii), amt of shift needed for this row */
1926: rs = 0.0;
1927: ajtmp = aj + ai[i];
1928: rtmp1 = aa + ai[i];
1929: nz = ai[i+1] - ai[i];
1930: for (j=0; j<nz; j++) {
1931: if (*ajtmp != i) {
1932: rs += PetscAbsScalar(*rtmp1++);
1933: } else {
1934: rs -= PetscRealPart(*rtmp1++);
1935: }
1936: ajtmp++;
1937: }
1938: if (rs>sctx.shift_top) sctx.shift_top = rs;
1939: }
1940: if (sctx.shift_top == 0.0) sctx.shift_top += 1.e-12;
1941: sctx.shift_top *= 1.1;
1942: sctx.nshift_max = 5;
1943: sctx.shift_lo = 0.;
1944: sctx.shift_hi = 1.;
1945: }
1946: sctx.shift_amount = 0;
1947: sctx.nshift = 0;
1949: ISGetIndices(isrow,&r);
1950: ISGetIndices(iscol,&c);
1951: ISGetIndices(isicol,&ic);
1952: PetscCalloc3(n,&rtmp11,n,&rtmp22,n,&rtmp33);
1953: ics = ic;
1955: node_max = a->inode.node_count;
1956: ns = a->inode.size;
1957: if (!ns) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Matrix without inode information");
1959: /* If max inode size > 3, split it into two inodes.*/
1960: /* also map the inode sizes according to the ordering */
1961: PetscMalloc1(n+1,&tmp_vec1);
1962: for (i=0,j=0; i<node_max; ++i,++j) {
1963: if (ns[i]>3) {
1964: tmp_vec1[j] = ns[i]/2; /* Assuming ns[i] < =5 */
1965: ++j;
1966: tmp_vec1[j] = ns[i] - tmp_vec1[j-1];
1967: } else {
1968: tmp_vec1[j] = ns[i];
1969: }
1970: }
1971: /* Use the correct node_max */
1972: node_max = j;
1974: /* Now reorder the inode info based on mat re-ordering info */
1975: /* First create a row -> inode_size_array_index map */
1976: PetscMalloc1(n+1,&nsmap);
1977: PetscMalloc1(node_max+1,&tmp_vec2);
1978: for (i=0,row=0; i<node_max; i++) {
1979: nodesz = tmp_vec1[i];
1980: for (j=0; j<nodesz; j++,row++) {
1981: nsmap[row] = i;
1982: }
1983: }
1984: /* Using nsmap, create a reordered ns structure */
1985: for (i=0,j=0; i< node_max; i++) {
1986: nodesz = tmp_vec1[nsmap[r[j]]]; /* here the reordered row_no is in r[] */
1987: tmp_vec2[i] = nodesz;
1988: j += nodesz;
1989: }
1990: PetscFree(nsmap);
1991: PetscFree(tmp_vec1);
1992: /* Now use the correct ns */
1993: ns = tmp_vec2;
1995: do {
1996: sctx.newshift = PETSC_FALSE;
1997: /* Now loop over each block-row, and do the factorization */
1998: for (i=0,row=0; i<node_max; i++) {
1999: nodesz = ns[i];
2000: nz = bi[row+1] - bi[row];
2001: bjtmp = bj + bi[row];
2003: switch (nodesz) {
2004: case 1:
2005: for (j=0; j<nz; j++) {
2006: idx = bjtmp[j];
2007: rtmp11[idx] = 0.0;
2008: }
2010: /* load in initial (unfactored row) */
2011: idx = r[row];
2012: nz_tmp = ai[idx+1] - ai[idx];
2013: ajtmp = aj + ai[idx];
2014: v1 = aa + ai[idx];
2016: for (j=0; j<nz_tmp; j++) {
2017: idx = ics[ajtmp[j]];
2018: rtmp11[idx] = v1[j];
2019: }
2020: rtmp11[ics[r[row]]] += sctx.shift_amount;
2022: prow = *bjtmp++;
2023: while (prow < row) {
2024: pc1 = rtmp11 + prow;
2025: if (*pc1 != 0.0) {
2026: pv = ba + bd[prow];
2027: pj = nbj + bd[prow];
2028: mul1 = *pc1 * *pv++;
2029: *pc1 = mul1;
2030: nz_tmp = bi[prow+1] - bd[prow] - 1;
2031: PetscLogFlops(1+2*nz_tmp);
2032: for (j=0; j<nz_tmp; j++) {
2033: tmp = pv[j];
2034: idx = pj[j];
2035: rtmp11[idx] -= mul1 * tmp;
2036: }
2037: }
2038: prow = *bjtmp++;
2039: }
2040: pj = bj + bi[row];
2041: pc1 = ba + bi[row];
2043: sctx.pv = rtmp11[row];
2044: rtmp11[row] = 1.0/rtmp11[row]; /* invert diag */
2045: rs = 0.0;
2046: for (j=0; j<nz; j++) {
2047: idx = pj[j];
2048: pc1[j] = rtmp11[idx]; /* rtmp11 -> ba */
2049: if (idx != row) rs += PetscAbsScalar(pc1[j]);
2050: }
2051: sctx.rs = rs;
2052: MatPivotCheck(B,A,info,&sctx,row);
2053: if (sctx.newshift) goto endofwhile;
2054: break;
2056: case 2:
2057: for (j=0; j<nz; j++) {
2058: idx = bjtmp[j];
2059: rtmp11[idx] = 0.0;
2060: rtmp22[idx] = 0.0;
2061: }
2063: /* load in initial (unfactored row) */
2064: idx = r[row];
2065: nz_tmp = ai[idx+1] - ai[idx];
2066: ajtmp = aj + ai[idx];
2067: v1 = aa + ai[idx];
2068: v2 = aa + ai[idx+1];
2069: for (j=0; j<nz_tmp; j++) {
2070: idx = ics[ajtmp[j]];
2071: rtmp11[idx] = v1[j];
2072: rtmp22[idx] = v2[j];
2073: }
2074: rtmp11[ics[r[row]]] += sctx.shift_amount;
2075: rtmp22[ics[r[row+1]]] += sctx.shift_amount;
2077: prow = *bjtmp++;
2078: while (prow < row) {
2079: pc1 = rtmp11 + prow;
2080: pc2 = rtmp22 + prow;
2081: if (*pc1 != 0.0 || *pc2 != 0.0) {
2082: pv = ba + bd[prow];
2083: pj = nbj + bd[prow];
2084: mul1 = *pc1 * *pv;
2085: mul2 = *pc2 * *pv;
2086: ++pv;
2087: *pc1 = mul1;
2088: *pc2 = mul2;
2090: nz_tmp = bi[prow+1] - bd[prow] - 1;
2091: for (j=0; j<nz_tmp; j++) {
2092: tmp = pv[j];
2093: idx = pj[j];
2094: rtmp11[idx] -= mul1 * tmp;
2095: rtmp22[idx] -= mul2 * tmp;
2096: }
2097: PetscLogFlops(2+4*nz_tmp);
2098: }
2099: prow = *bjtmp++;
2100: }
2102: /* Now take care of diagonal 2x2 block. Note: prow = row here */
2103: pc1 = rtmp11 + prow;
2104: pc2 = rtmp22 + prow;
2106: sctx.pv = *pc1;
2107: pj = bj + bi[prow];
2108: rs = 0.0;
2109: for (j=0; j<nz; j++) {
2110: idx = pj[j];
2111: if (idx != prow) rs += PetscAbsScalar(rtmp11[idx]);
2112: }
2113: sctx.rs = rs;
2114: MatPivotCheck(B,A,info,&sctx,row);
2115: if (sctx.newshift) goto endofwhile;
2117: if (*pc2 != 0.0) {
2118: pj = nbj + bd[prow];
2119: mul2 = (*pc2)/(*pc1); /* since diag is not yet inverted.*/
2120: *pc2 = mul2;
2121: nz_tmp = bi[prow+1] - bd[prow] - 1;
2122: for (j=0; j<nz_tmp; j++) {
2123: idx = pj[j];
2124: tmp = rtmp11[idx];
2125: rtmp22[idx] -= mul2 * tmp;
2126: }
2127: PetscLogFlops(1+2*nz_tmp);
2128: }
2130: pj = bj + bi[row];
2131: pc1 = ba + bi[row];
2132: pc2 = ba + bi[row+1];
2134: sctx.pv = rtmp22[row+1];
2135: rs = 0.0;
2136: rtmp11[row] = 1.0/rtmp11[row];
2137: rtmp22[row+1] = 1.0/rtmp22[row+1];
2138: /* copy row entries from dense representation to sparse */
2139: for (j=0; j<nz; j++) {
2140: idx = pj[j];
2141: pc1[j] = rtmp11[idx];
2142: pc2[j] = rtmp22[idx];
2143: if (idx != row+1) rs += PetscAbsScalar(pc2[j]);
2144: }
2145: sctx.rs = rs;
2146: MatPivotCheck(B,A,info,&sctx,row+1);
2147: if (sctx.newshift) goto endofwhile;
2148: break;
2150: case 3:
2151: for (j=0; j<nz; j++) {
2152: idx = bjtmp[j];
2153: rtmp11[idx] = 0.0;
2154: rtmp22[idx] = 0.0;
2155: rtmp33[idx] = 0.0;
2156: }
2157: /* copy the nonzeros for the 3 rows from sparse representation to dense in rtmp*[] */
2158: idx = r[row];
2159: nz_tmp = ai[idx+1] - ai[idx];
2160: ajtmp = aj + ai[idx];
2161: v1 = aa + ai[idx];
2162: v2 = aa + ai[idx+1];
2163: v3 = aa + ai[idx+2];
2164: for (j=0; j<nz_tmp; j++) {
2165: idx = ics[ajtmp[j]];
2166: rtmp11[idx] = v1[j];
2167: rtmp22[idx] = v2[j];
2168: rtmp33[idx] = v3[j];
2169: }
2170: rtmp11[ics[r[row]]] += sctx.shift_amount;
2171: rtmp22[ics[r[row+1]]] += sctx.shift_amount;
2172: rtmp33[ics[r[row+2]]] += sctx.shift_amount;
2174: /* loop over all pivot row blocks above this row block */
2175: prow = *bjtmp++;
2176: while (prow < row) {
2177: pc1 = rtmp11 + prow;
2178: pc2 = rtmp22 + prow;
2179: pc3 = rtmp33 + prow;
2180: if (*pc1 != 0.0 || *pc2 != 0.0 || *pc3 !=0.0) {
2181: pv = ba + bd[prow];
2182: pj = nbj + bd[prow];
2183: mul1 = *pc1 * *pv;
2184: mul2 = *pc2 * *pv;
2185: mul3 = *pc3 * *pv;
2186: ++pv;
2187: *pc1 = mul1;
2188: *pc2 = mul2;
2189: *pc3 = mul3;
2191: nz_tmp = bi[prow+1] - bd[prow] - 1;
2192: /* update this row based on pivot row */
2193: for (j=0; j<nz_tmp; j++) {
2194: tmp = pv[j];
2195: idx = pj[j];
2196: rtmp11[idx] -= mul1 * tmp;
2197: rtmp22[idx] -= mul2 * tmp;
2198: rtmp33[idx] -= mul3 * tmp;
2199: }
2200: PetscLogFlops(3+6*nz_tmp);
2201: }
2202: prow = *bjtmp++;
2203: }
2205: /* Now take care of diagonal 3x3 block in this set of rows */
2206: /* note: prow = row here */
2207: pc1 = rtmp11 + prow;
2208: pc2 = rtmp22 + prow;
2209: pc3 = rtmp33 + prow;
2211: sctx.pv = *pc1;
2212: pj = bj + bi[prow];
2213: rs = 0.0;
2214: for (j=0; j<nz; j++) {
2215: idx = pj[j];
2216: if (idx != row) rs += PetscAbsScalar(rtmp11[idx]);
2217: }
2218: sctx.rs = rs;
2219: MatPivotCheck(B,A,info,&sctx,row);
2220: if (sctx.newshift) goto endofwhile;
2222: if (*pc2 != 0.0 || *pc3 != 0.0) {
2223: mul2 = (*pc2)/(*pc1);
2224: mul3 = (*pc3)/(*pc1);
2225: *pc2 = mul2;
2226: *pc3 = mul3;
2227: nz_tmp = bi[prow+1] - bd[prow] - 1;
2228: pj = nbj + bd[prow];
2229: for (j=0; j<nz_tmp; j++) {
2230: idx = pj[j];
2231: tmp = rtmp11[idx];
2232: rtmp22[idx] -= mul2 * tmp;
2233: rtmp33[idx] -= mul3 * tmp;
2234: }
2235: PetscLogFlops(2+4*nz_tmp);
2236: }
2237: ++prow;
2239: pc2 = rtmp22 + prow;
2240: pc3 = rtmp33 + prow;
2241: sctx.pv = *pc2;
2242: pj = bj + bi[prow];
2243: rs = 0.0;
2244: for (j=0; j<nz; j++) {
2245: idx = pj[j];
2246: if (idx != prow) rs += PetscAbsScalar(rtmp22[idx]);
2247: }
2248: sctx.rs = rs;
2249: MatPivotCheck(B,A,info,&sctx,row+1);
2250: if (sctx.newshift) goto endofwhile;
2252: if (*pc3 != 0.0) {
2253: mul3 = (*pc3)/(*pc2);
2254: *pc3 = mul3;
2255: pj = nbj + bd[prow];
2256: nz_tmp = bi[prow+1] - bd[prow] - 1;
2257: for (j=0; j<nz_tmp; j++) {
2258: idx = pj[j];
2259: tmp = rtmp22[idx];
2260: rtmp33[idx] -= mul3 * tmp;
2261: }
2262: PetscLogFlops(1+2*nz_tmp);
2263: }
2265: pj = bj + bi[row];
2266: pc1 = ba + bi[row];
2267: pc2 = ba + bi[row+1];
2268: pc3 = ba + bi[row+2];
2270: sctx.pv = rtmp33[row+2];
2271: rs = 0.0;
2272: rtmp11[row] = 1.0/rtmp11[row];
2273: rtmp22[row+1] = 1.0/rtmp22[row+1];
2274: rtmp33[row+2] = 1.0/rtmp33[row+2];
2275: /* copy row entries from dense representation to sparse */
2276: for (j=0; j<nz; j++) {
2277: idx = pj[j];
2278: pc1[j] = rtmp11[idx];
2279: pc2[j] = rtmp22[idx];
2280: pc3[j] = rtmp33[idx];
2281: if (idx != row+2) rs += PetscAbsScalar(pc3[j]);
2282: }
2284: sctx.rs = rs;
2285: MatPivotCheck(B,A,info,&sctx,row+2);
2286: if (sctx.newshift) goto endofwhile;
2287: break;
2289: default:
2290: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Node size not yet supported \n");
2291: }
2292: row += nodesz; /* Update the row */
2293: }
2294: endofwhile:;
2295: } while (sctx.newshift);
2296: PetscFree3(rtmp11,rtmp22,rtmp33);
2297: PetscFree(tmp_vec2);
2298: ISRestoreIndices(isicol,&ic);
2299: ISRestoreIndices(isrow,&r);
2300: ISRestoreIndices(iscol,&c);
2302: (B)->ops->solve = MatSolve_SeqAIJ_inplace;
2303: /* do not set solve add, since MatSolve_Inode + Add is faster */
2304: C->ops->solvetranspose = MatSolveTranspose_SeqAIJ_inplace;
2305: C->ops->solvetransposeadd = MatSolveTransposeAdd_SeqAIJ_inplace;
2306: C->assembled = PETSC_TRUE;
2307: C->preallocated = PETSC_TRUE;
2308: if (sctx.nshift) {
2309: if (info->shifttype == (PetscReal)MAT_SHIFT_POSITIVE_DEFINITE) {
2310: PetscInfo4(A,"number of shift_pd tries %D, shift_amount %g, diagonal shifted up by %e fraction top_value %e\n",sctx.nshift,(double)sctx.shift_amount,(double)sctx.shift_fraction,(double)sctx.shift_top);
2311: } else if (info->shifttype == (PetscReal)MAT_SHIFT_NONZERO) {
2312: PetscInfo2(A,"number of shift_nz tries %D, shift_amount %g\n",sctx.nshift,(double)sctx.shift_amount);
2313: }
2314: }
2315: PetscLogFlops(C->cmap->n);
2316: MatSeqAIJCheckInode(C);
2317: return(0);
2318: }
2321: /* ----------------------------------------------------------- */
2324: PetscErrorCode MatSolve_SeqAIJ_Inode(Mat A,Vec bb,Vec xx)
2325: {
2326: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
2327: IS iscol = a->col,isrow = a->row;
2328: PetscErrorCode ierr;
2329: const PetscInt *r,*c,*rout,*cout;
2330: PetscInt i,j,n = A->rmap->n;
2331: PetscInt node_max,row,nsz,aii,i0,i1,nz;
2332: const PetscInt *ai = a->i,*a_j = a->j,*ns,*vi,*ad,*aj;
2333: PetscScalar *x,*tmp,*tmps,tmp0,tmp1;
2334: PetscScalar sum1,sum2,sum3,sum4,sum5;
2335: const MatScalar *v1,*v2,*v3,*v4,*v5,*a_a = a->a,*aa;
2336: const PetscScalar *b;
2339: if (!a->inode.size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Missing Inode Structure");
2340: node_max = a->inode.node_count;
2341: ns = a->inode.size; /* Node Size array */
2343: VecGetArrayRead(bb,&b);
2344: VecGetArray(xx,&x);
2345: tmp = a->solve_work;
2347: ISGetIndices(isrow,&rout); r = rout;
2348: ISGetIndices(iscol,&cout); c = cout;
2350: /* forward solve the lower triangular */
2351: tmps = tmp;
2352: aa = a_a;
2353: aj = a_j;
2354: ad = a->diag;
2356: for (i = 0,row = 0; i< node_max; ++i) {
2357: nsz = ns[i];
2358: aii = ai[row];
2359: v1 = aa + aii;
2360: vi = aj + aii;
2361: nz = ai[row+1]- ai[row];
2363: if (i < node_max-1) {
2364: /* Prefetch the indices for the next block */
2365: PetscPrefetchBlock(aj+ai[row+nsz],ai[row+nsz+1]-ai[row+nsz],0,PETSC_PREFETCH_HINT_NTA); /* indices */
2366: /* Prefetch the data for the next block */
2367: PetscPrefetchBlock(aa+ai[row+nsz],ai[row+nsz+ns[i+1]]-ai[row+nsz],0,PETSC_PREFETCH_HINT_NTA);
2368: }
2370: switch (nsz) { /* Each loop in 'case' is unrolled */
2371: case 1:
2372: sum1 = b[r[row]];
2373: for (j=0; j<nz-1; j+=2) {
2374: i0 = vi[j];
2375: i1 = vi[j+1];
2376: tmp0 = tmps[i0];
2377: tmp1 = tmps[i1];
2378: sum1 -= v1[j]*tmp0 + v1[j+1]*tmp1;
2379: }
2380: if (j == nz-1) {
2381: tmp0 = tmps[vi[j]];
2382: sum1 -= v1[j]*tmp0;
2383: }
2384: tmp[row++]=sum1;
2385: break;
2386: case 2:
2387: sum1 = b[r[row]];
2388: sum2 = b[r[row+1]];
2389: v2 = aa + ai[row+1];
2391: for (j=0; j<nz-1; j+=2) {
2392: i0 = vi[j];
2393: i1 = vi[j+1];
2394: tmp0 = tmps[i0];
2395: tmp1 = tmps[i1];
2396: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2397: sum2 -= v2[j] * tmp0 + v2[j+1] * tmp1;
2398: }
2399: if (j == nz-1) {
2400: tmp0 = tmps[vi[j]];
2401: sum1 -= v1[j] *tmp0;
2402: sum2 -= v2[j] *tmp0;
2403: }
2404: sum2 -= v2[nz] * sum1;
2405: tmp[row++]=sum1;
2406: tmp[row++]=sum2;
2407: break;
2408: case 3:
2409: sum1 = b[r[row]];
2410: sum2 = b[r[row+1]];
2411: sum3 = b[r[row+2]];
2412: v2 = aa + ai[row+1];
2413: v3 = aa + ai[row+2];
2415: for (j=0; j<nz-1; j+=2) {
2416: i0 = vi[j];
2417: i1 = vi[j+1];
2418: tmp0 = tmps[i0];
2419: tmp1 = tmps[i1];
2420: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2421: sum2 -= v2[j] * tmp0 + v2[j+1] * tmp1;
2422: sum3 -= v3[j] * tmp0 + v3[j+1] * tmp1;
2423: }
2424: if (j == nz-1) {
2425: tmp0 = tmps[vi[j]];
2426: sum1 -= v1[j] *tmp0;
2427: sum2 -= v2[j] *tmp0;
2428: sum3 -= v3[j] *tmp0;
2429: }
2430: sum2 -= v2[nz] * sum1;
2431: sum3 -= v3[nz] * sum1;
2432: sum3 -= v3[nz+1] * sum2;
2433: tmp[row++]=sum1;
2434: tmp[row++]=sum2;
2435: tmp[row++]=sum3;
2436: break;
2438: case 4:
2439: sum1 = b[r[row]];
2440: sum2 = b[r[row+1]];
2441: sum3 = b[r[row+2]];
2442: sum4 = b[r[row+3]];
2443: v2 = aa + ai[row+1];
2444: v3 = aa + ai[row+2];
2445: v4 = aa + ai[row+3];
2447: for (j=0; j<nz-1; j+=2) {
2448: i0 = vi[j];
2449: i1 = vi[j+1];
2450: tmp0 = tmps[i0];
2451: tmp1 = tmps[i1];
2452: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2453: sum2 -= v2[j] * tmp0 + v2[j+1] * tmp1;
2454: sum3 -= v3[j] * tmp0 + v3[j+1] * tmp1;
2455: sum4 -= v4[j] * tmp0 + v4[j+1] * tmp1;
2456: }
2457: if (j == nz-1) {
2458: tmp0 = tmps[vi[j]];
2459: sum1 -= v1[j] *tmp0;
2460: sum2 -= v2[j] *tmp0;
2461: sum3 -= v3[j] *tmp0;
2462: sum4 -= v4[j] *tmp0;
2463: }
2464: sum2 -= v2[nz] * sum1;
2465: sum3 -= v3[nz] * sum1;
2466: sum4 -= v4[nz] * sum1;
2467: sum3 -= v3[nz+1] * sum2;
2468: sum4 -= v4[nz+1] * sum2;
2469: sum4 -= v4[nz+2] * sum3;
2471: tmp[row++]=sum1;
2472: tmp[row++]=sum2;
2473: tmp[row++]=sum3;
2474: tmp[row++]=sum4;
2475: break;
2476: case 5:
2477: sum1 = b[r[row]];
2478: sum2 = b[r[row+1]];
2479: sum3 = b[r[row+2]];
2480: sum4 = b[r[row+3]];
2481: sum5 = b[r[row+4]];
2482: v2 = aa + ai[row+1];
2483: v3 = aa + ai[row+2];
2484: v4 = aa + ai[row+3];
2485: v5 = aa + ai[row+4];
2487: for (j=0; j<nz-1; j+=2) {
2488: i0 = vi[j];
2489: i1 = vi[j+1];
2490: tmp0 = tmps[i0];
2491: tmp1 = tmps[i1];
2492: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2493: sum2 -= v2[j] * tmp0 + v2[j+1] * tmp1;
2494: sum3 -= v3[j] * tmp0 + v3[j+1] * tmp1;
2495: sum4 -= v4[j] * tmp0 + v4[j+1] * tmp1;
2496: sum5 -= v5[j] * tmp0 + v5[j+1] * tmp1;
2497: }
2498: if (j == nz-1) {
2499: tmp0 = tmps[vi[j]];
2500: sum1 -= v1[j] *tmp0;
2501: sum2 -= v2[j] *tmp0;
2502: sum3 -= v3[j] *tmp0;
2503: sum4 -= v4[j] *tmp0;
2504: sum5 -= v5[j] *tmp0;
2505: }
2507: sum2 -= v2[nz] * sum1;
2508: sum3 -= v3[nz] * sum1;
2509: sum4 -= v4[nz] * sum1;
2510: sum5 -= v5[nz] * sum1;
2511: sum3 -= v3[nz+1] * sum2;
2512: sum4 -= v4[nz+1] * sum2;
2513: sum5 -= v5[nz+1] * sum2;
2514: sum4 -= v4[nz+2] * sum3;
2515: sum5 -= v5[nz+2] * sum3;
2516: sum5 -= v5[nz+3] * sum4;
2518: tmp[row++]=sum1;
2519: tmp[row++]=sum2;
2520: tmp[row++]=sum3;
2521: tmp[row++]=sum4;
2522: tmp[row++]=sum5;
2523: break;
2524: default:
2525: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported \n");
2526: }
2527: }
2528: /* backward solve the upper triangular */
2529: for (i=node_max -1,row = n-1; i>=0; i--) {
2530: nsz = ns[i];
2531: aii = ad[row+1] + 1;
2532: v1 = aa + aii;
2533: vi = aj + aii;
2534: nz = ad[row]- ad[row+1] - 1;
2536: if (i > 0) {
2537: /* Prefetch the indices for the next block */
2538: PetscPrefetchBlock(aj+ad[row-nsz+1]+1,ad[row-nsz]-ad[row-nsz+1],0,PETSC_PREFETCH_HINT_NTA);
2539: /* Prefetch the data for the next block */
2540: PetscPrefetchBlock(aa+ad[row-nsz+1]+1,ad[row-nsz-ns[i-1]+1]-ad[row-nsz+1],0,PETSC_PREFETCH_HINT_NTA);
2541: }
2543: switch (nsz) { /* Each loop in 'case' is unrolled */
2544: case 1:
2545: sum1 = tmp[row];
2547: for (j=0; j<nz-1; j+=2) {
2548: i0 = vi[j];
2549: i1 = vi[j+1];
2550: tmp0 = tmps[i0];
2551: tmp1 = tmps[i1];
2552: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2553: }
2554: if (j == nz-1) {
2555: tmp0 = tmps[vi[j]];
2556: sum1 -= v1[j]*tmp0;
2557: }
2558: x[c[row]] = tmp[row] = sum1*v1[nz]; row--;
2559: break;
2560: case 2:
2561: sum1 = tmp[row];
2562: sum2 = tmp[row-1];
2563: v2 = aa + ad[row] + 1;
2564: for (j=0; j<nz-1; j+=2) {
2565: i0 = vi[j];
2566: i1 = vi[j+1];
2567: tmp0 = tmps[i0];
2568: tmp1 = tmps[i1];
2569: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2570: sum2 -= v2[j+1] * tmp0 + v2[j+2] * tmp1;
2571: }
2572: if (j == nz-1) {
2573: tmp0 = tmps[vi[j]];
2574: sum1 -= v1[j]* tmp0;
2575: sum2 -= v2[j+1]* tmp0;
2576: }
2578: tmp0 = x[c[row]] = tmp[row] = sum1*v1[nz]; row--;
2579: sum2 -= v2[0] * tmp0;
2580: x[c[row]] = tmp[row] = sum2*v2[nz+1]; row--;
2581: break;
2582: case 3:
2583: sum1 = tmp[row];
2584: sum2 = tmp[row -1];
2585: sum3 = tmp[row -2];
2586: v2 = aa + ad[row] + 1;
2587: v3 = aa + ad[row -1] + 1;
2588: for (j=0; j<nz-1; j+=2) {
2589: i0 = vi[j];
2590: i1 = vi[j+1];
2591: tmp0 = tmps[i0];
2592: tmp1 = tmps[i1];
2593: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2594: sum2 -= v2[j+1] * tmp0 + v2[j+2] * tmp1;
2595: sum3 -= v3[j+2] * tmp0 + v3[j+3] * tmp1;
2596: }
2597: if (j== nz-1) {
2598: tmp0 = tmps[vi[j]];
2599: sum1 -= v1[j] * tmp0;
2600: sum2 -= v2[j+1] * tmp0;
2601: sum3 -= v3[j+2] * tmp0;
2602: }
2603: tmp0 = x[c[row]] = tmp[row] = sum1*v1[nz]; row--;
2604: sum2 -= v2[0]* tmp0;
2605: sum3 -= v3[1] * tmp0;
2606: tmp0 = x[c[row]] = tmp[row] = sum2*v2[nz+1]; row--;
2607: sum3 -= v3[0]* tmp0;
2608: x[c[row]] = tmp[row] = sum3*v3[nz+2]; row--;
2610: break;
2611: case 4:
2612: sum1 = tmp[row];
2613: sum2 = tmp[row -1];
2614: sum3 = tmp[row -2];
2615: sum4 = tmp[row -3];
2616: v2 = aa + ad[row]+1;
2617: v3 = aa + ad[row -1]+1;
2618: v4 = aa + ad[row -2]+1;
2620: for (j=0; j<nz-1; j+=2) {
2621: i0 = vi[j];
2622: i1 = vi[j+1];
2623: tmp0 = tmps[i0];
2624: tmp1 = tmps[i1];
2625: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2626: sum2 -= v2[j+1] * tmp0 + v2[j+2] * tmp1;
2627: sum3 -= v3[j+2] * tmp0 + v3[j+3] * tmp1;
2628: sum4 -= v4[j+3] * tmp0 + v4[j+4] * tmp1;
2629: }
2630: if (j== nz-1) {
2631: tmp0 = tmps[vi[j]];
2632: sum1 -= v1[j] * tmp0;
2633: sum2 -= v2[j+1] * tmp0;
2634: sum3 -= v3[j+2] * tmp0;
2635: sum4 -= v4[j+3] * tmp0;
2636: }
2638: tmp0 = x[c[row]] = tmp[row] = sum1*v1[nz]; row--;
2639: sum2 -= v2[0] * tmp0;
2640: sum3 -= v3[1] * tmp0;
2641: sum4 -= v4[2] * tmp0;
2642: tmp0 = x[c[row]] = tmp[row] = sum2*v2[nz+1]; row--;
2643: sum3 -= v3[0] * tmp0;
2644: sum4 -= v4[1] * tmp0;
2645: tmp0 = x[c[row]] = tmp[row] = sum3*v3[nz+2]; row--;
2646: sum4 -= v4[0] * tmp0;
2647: x[c[row]] = tmp[row] = sum4*v4[nz+3]; row--;
2648: break;
2649: case 5:
2650: sum1 = tmp[row];
2651: sum2 = tmp[row -1];
2652: sum3 = tmp[row -2];
2653: sum4 = tmp[row -3];
2654: sum5 = tmp[row -4];
2655: v2 = aa + ad[row]+1;
2656: v3 = aa + ad[row -1]+1;
2657: v4 = aa + ad[row -2]+1;
2658: v5 = aa + ad[row -3]+1;
2659: for (j=0; j<nz-1; j+=2) {
2660: i0 = vi[j];
2661: i1 = vi[j+1];
2662: tmp0 = tmps[i0];
2663: tmp1 = tmps[i1];
2664: sum1 -= v1[j] * tmp0 + v1[j+1] * tmp1;
2665: sum2 -= v2[j+1] * tmp0 + v2[j+2] * tmp1;
2666: sum3 -= v3[j+2] * tmp0 + v3[j+3] * tmp1;
2667: sum4 -= v4[j+3] * tmp0 + v4[j+4] * tmp1;
2668: sum5 -= v5[j+4] * tmp0 + v5[j+5] * tmp1;
2669: }
2670: if (j==nz-1) {
2671: tmp0 = tmps[vi[j]];
2672: sum1 -= v1[j] * tmp0;
2673: sum2 -= v2[j+1] * tmp0;
2674: sum3 -= v3[j+2] * tmp0;
2675: sum4 -= v4[j+3] * tmp0;
2676: sum5 -= v5[j+4] * tmp0;
2677: }
2679: tmp0 = x[c[row]] = tmp[row] = sum1*v1[nz]; row--;
2680: sum2 -= v2[0] * tmp0;
2681: sum3 -= v3[1] * tmp0;
2682: sum4 -= v4[2] * tmp0;
2683: sum5 -= v5[3] * tmp0;
2684: tmp0 = x[c[row]] = tmp[row] = sum2*v2[nz+1]; row--;
2685: sum3 -= v3[0] * tmp0;
2686: sum4 -= v4[1] * tmp0;
2687: sum5 -= v5[2] * tmp0;
2688: tmp0 = x[c[row]] = tmp[row] = sum3*v3[nz+2]; row--;
2689: sum4 -= v4[0] * tmp0;
2690: sum5 -= v5[1] * tmp0;
2691: tmp0 = x[c[row]] = tmp[row] = sum4*v4[nz+3]; row--;
2692: sum5 -= v5[0] * tmp0;
2693: x[c[row]] = tmp[row] = sum5*v5[nz+4]; row--;
2694: break;
2695: default:
2696: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_COR,"Node size not yet supported \n");
2697: }
2698: }
2699: ISRestoreIndices(isrow,&rout);
2700: ISRestoreIndices(iscol,&cout);
2701: VecRestoreArrayRead(bb,&b);
2702: VecRestoreArray(xx,&x);
2703: PetscLogFlops(2.0*a->nz - A->cmap->n);
2704: return(0);
2705: }
2708: /*
2709: Makes a longer coloring[] array and calls the usual code with that
2710: */
2713: PetscErrorCode MatColoringPatch_SeqAIJ_Inode(Mat mat,PetscInt ncolors,PetscInt nin,ISColoringValue coloring[],ISColoring *iscoloring)
2714: {
2715: Mat_SeqAIJ *a = (Mat_SeqAIJ*)mat->data;
2716: PetscErrorCode ierr;
2717: PetscInt n = mat->cmap->n,m = a->inode.node_count,j,*ns = a->inode.size,row;
2718: PetscInt *colorused,i;
2719: ISColoringValue *newcolor;
2722: PetscMalloc1(n+1,&newcolor);
2723: /* loop over inodes, marking a color for each column*/
2724: row = 0;
2725: for (i=0; i<m; i++) {
2726: for (j=0; j<ns[i]; j++) {
2727: newcolor[row++] = coloring[i] + j*ncolors;
2728: }
2729: }
2731: /* eliminate unneeded colors */
2732: PetscCalloc1(5*ncolors,&colorused);
2733: for (i=0; i<n; i++) {
2734: colorused[newcolor[i]] = 1;
2735: }
2737: for (i=1; i<5*ncolors; i++) {
2738: colorused[i] += colorused[i-1];
2739: }
2740: ncolors = colorused[5*ncolors-1];
2741: for (i=0; i<n; i++) {
2742: newcolor[i] = colorused[newcolor[i]]-1;
2743: }
2744: PetscFree(colorused);
2745: ISColoringCreate(PetscObjectComm((PetscObject)mat),ncolors,n,newcolor,PETSC_OWN_POINTER,iscoloring);
2746: PetscFree(coloring);
2747: return(0);
2748: }
2750: #include <petsc/private/kernels/blockinvert.h>
2754: PetscErrorCode MatSOR_SeqAIJ_Inode(Mat A,Vec bb,PetscReal omega,MatSORType flag,PetscReal fshift,PetscInt its,PetscInt lits,Vec xx)
2755: {
2756: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
2757: PetscScalar sum1 = 0.0,sum2 = 0.0,sum3 = 0.0,sum4 = 0.0,sum5 = 0.0,tmp0,tmp1,tmp2,tmp3;
2758: MatScalar *ibdiag,*bdiag,work[25],*t;
2759: PetscScalar *x,tmp4,tmp5,x1,x2,x3,x4,x5;
2760: const MatScalar *v = a->a,*v1 = NULL,*v2 = NULL,*v3 = NULL,*v4 = NULL,*v5 = NULL;
2761: const PetscScalar *xb, *b;
2762: PetscReal zeropivot = 1.0e-15, shift = 0.0;
2763: PetscErrorCode ierr;
2764: PetscInt n,m = a->inode.node_count,cnt = 0,i,j,row,i1,i2;
2765: PetscInt sz,k,ipvt[5];
2766: PetscBool allowzeropivot,zeropivotdetected=PETSC_FALSE;
2767: const PetscInt *sizes = a->inode.size,*idx,*diag = a->diag,*ii = a->i;
2770: allowzeropivot = PetscNot(A->erroriffailure);
2771: if (omega != 1.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for omega != 1.0; use -mat_no_inode");
2772: if (fshift == -1.0) fshift = 0.0; /* negative fshift indicates do not error on zero diagonal; this code never errors on zero diagonal */
2773: if (fshift != 0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for fshift != 0.0; use -mat_no_inode");
2775: if (!a->inode.ibdiagvalid) {
2776: if (!a->inode.ibdiag) {
2777: /* calculate space needed for diagonal blocks */
2778: for (i=0; i<m; i++) {
2779: cnt += sizes[i]*sizes[i];
2780: }
2781: a->inode.bdiagsize = cnt;
2783: PetscMalloc3(cnt,&a->inode.ibdiag,cnt,&a->inode.bdiag,A->rmap->n,&a->inode.ssor_work);
2784: }
2786: /* copy over the diagonal blocks and invert them */
2787: ibdiag = a->inode.ibdiag;
2788: bdiag = a->inode.bdiag;
2789: cnt = 0;
2790: for (i=0, row = 0; i<m; i++) {
2791: for (j=0; j<sizes[i]; j++) {
2792: for (k=0; k<sizes[i]; k++) {
2793: bdiag[cnt+k*sizes[i]+j] = v[diag[row+j] - j + k];
2794: }
2795: }
2796: PetscMemcpy(ibdiag+cnt,bdiag+cnt,sizes[i]*sizes[i]*sizeof(MatScalar));
2798: switch (sizes[i]) {
2799: case 1:
2800: /* Create matrix data structure */
2801: if (PetscAbsScalar(ibdiag[cnt]) < zeropivot) {
2802: if (allowzeropivot) {
2803: zeropivotdetected = PETSC_TRUE;
2804: PetscInfo1(A,"Zero pivot, row %D\n",row);
2805: } else SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MAT_LU_ZRPVT,"Zero pivot on row %D",row);
2806: }
2807: ibdiag[cnt] = 1.0/ibdiag[cnt];
2808: break;
2809: case 2:
2810: PetscKernel_A_gets_inverse_A_2(ibdiag+cnt,shift,allowzeropivot,&zeropivotdetected);
2811: break;
2812: case 3:
2813: PetscKernel_A_gets_inverse_A_3(ibdiag+cnt,shift,allowzeropivot,&zeropivotdetected);
2814: break;
2815: case 4:
2816: PetscKernel_A_gets_inverse_A_4(ibdiag+cnt,shift,allowzeropivot,&zeropivotdetected);
2817: break;
2818: case 5:
2819: PetscKernel_A_gets_inverse_A_5(ibdiag+cnt,ipvt,work,shift,allowzeropivot,&zeropivotdetected);
2820: break;
2821: default:
2822: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
2823: }
2824: if (zeropivotdetected) {
2825: A->errortype = MAT_FACTOR_NUMERIC_ZEROPIVOT;
2826: }
2828: cnt += sizes[i]*sizes[i];
2829: row += sizes[i];
2830: }
2831: a->inode.ibdiagvalid = PETSC_TRUE;
2832: }
2833: ibdiag = a->inode.ibdiag;
2834: bdiag = a->inode.bdiag;
2835: t = a->inode.ssor_work;
2837: VecGetArray(xx,&x);
2838: VecGetArrayRead(bb,&b);
2839: /* We count flops by assuming the upper triangular and lower triangular parts have the same number of nonzeros */
2840: if (flag & SOR_ZERO_INITIAL_GUESS) {
2841: if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
2843: for (i=0, row=0; i<m; i++) {
2844: sz = diag[row] - ii[row];
2845: v1 = a->a + ii[row];
2846: idx = a->j + ii[row];
2848: /* see comments for MatMult_SeqAIJ_Inode() for how this is coded */
2849: switch (sizes[i]) {
2850: case 1:
2852: sum1 = b[row];
2853: for (n = 0; n<sz-1; n+=2) {
2854: i1 = idx[0];
2855: i2 = idx[1];
2856: idx += 2;
2857: tmp0 = x[i1];
2858: tmp1 = x[i2];
2859: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
2860: }
2862: if (n == sz-1) {
2863: tmp0 = x[*idx];
2864: sum1 -= *v1 * tmp0;
2865: }
2866: t[row] = sum1;
2867: x[row++] = sum1*(*ibdiag++);
2868: break;
2869: case 2:
2870: v2 = a->a + ii[row+1];
2871: sum1 = b[row];
2872: sum2 = b[row+1];
2873: for (n = 0; n<sz-1; n+=2) {
2874: i1 = idx[0];
2875: i2 = idx[1];
2876: idx += 2;
2877: tmp0 = x[i1];
2878: tmp1 = x[i2];
2879: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
2880: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
2881: }
2883: if (n == sz-1) {
2884: tmp0 = x[*idx];
2885: sum1 -= v1[0] * tmp0;
2886: sum2 -= v2[0] * tmp0;
2887: }
2888: t[row] = sum1;
2889: t[row+1] = sum2;
2890: x[row++] = sum1*ibdiag[0] + sum2*ibdiag[2];
2891: x[row++] = sum1*ibdiag[1] + sum2*ibdiag[3];
2892: ibdiag += 4;
2893: break;
2894: case 3:
2895: v2 = a->a + ii[row+1];
2896: v3 = a->a + ii[row+2];
2897: sum1 = b[row];
2898: sum2 = b[row+1];
2899: sum3 = b[row+2];
2900: for (n = 0; n<sz-1; n+=2) {
2901: i1 = idx[0];
2902: i2 = idx[1];
2903: idx += 2;
2904: tmp0 = x[i1];
2905: tmp1 = x[i2];
2906: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
2907: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
2908: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
2909: }
2911: if (n == sz-1) {
2912: tmp0 = x[*idx];
2913: sum1 -= v1[0] * tmp0;
2914: sum2 -= v2[0] * tmp0;
2915: sum3 -= v3[0] * tmp0;
2916: }
2917: t[row] = sum1;
2918: t[row+1] = sum2;
2919: t[row+2] = sum3;
2920: x[row++] = sum1*ibdiag[0] + sum2*ibdiag[3] + sum3*ibdiag[6];
2921: x[row++] = sum1*ibdiag[1] + sum2*ibdiag[4] + sum3*ibdiag[7];
2922: x[row++] = sum1*ibdiag[2] + sum2*ibdiag[5] + sum3*ibdiag[8];
2923: ibdiag += 9;
2924: break;
2925: case 4:
2926: v2 = a->a + ii[row+1];
2927: v3 = a->a + ii[row+2];
2928: v4 = a->a + ii[row+3];
2929: sum1 = b[row];
2930: sum2 = b[row+1];
2931: sum3 = b[row+2];
2932: sum4 = b[row+3];
2933: for (n = 0; n<sz-1; n+=2) {
2934: i1 = idx[0];
2935: i2 = idx[1];
2936: idx += 2;
2937: tmp0 = x[i1];
2938: tmp1 = x[i2];
2939: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
2940: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
2941: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
2942: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
2943: }
2945: if (n == sz-1) {
2946: tmp0 = x[*idx];
2947: sum1 -= v1[0] * tmp0;
2948: sum2 -= v2[0] * tmp0;
2949: sum3 -= v3[0] * tmp0;
2950: sum4 -= v4[0] * tmp0;
2951: }
2952: t[row] = sum1;
2953: t[row+1] = sum2;
2954: t[row+2] = sum3;
2955: t[row+3] = sum4;
2956: x[row++] = sum1*ibdiag[0] + sum2*ibdiag[4] + sum3*ibdiag[8] + sum4*ibdiag[12];
2957: x[row++] = sum1*ibdiag[1] + sum2*ibdiag[5] + sum3*ibdiag[9] + sum4*ibdiag[13];
2958: x[row++] = sum1*ibdiag[2] + sum2*ibdiag[6] + sum3*ibdiag[10] + sum4*ibdiag[14];
2959: x[row++] = sum1*ibdiag[3] + sum2*ibdiag[7] + sum3*ibdiag[11] + sum4*ibdiag[15];
2960: ibdiag += 16;
2961: break;
2962: case 5:
2963: v2 = a->a + ii[row+1];
2964: v3 = a->a + ii[row+2];
2965: v4 = a->a + ii[row+3];
2966: v5 = a->a + ii[row+4];
2967: sum1 = b[row];
2968: sum2 = b[row+1];
2969: sum3 = b[row+2];
2970: sum4 = b[row+3];
2971: sum5 = b[row+4];
2972: for (n = 0; n<sz-1; n+=2) {
2973: i1 = idx[0];
2974: i2 = idx[1];
2975: idx += 2;
2976: tmp0 = x[i1];
2977: tmp1 = x[i2];
2978: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
2979: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
2980: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
2981: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
2982: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
2983: }
2985: if (n == sz-1) {
2986: tmp0 = x[*idx];
2987: sum1 -= v1[0] * tmp0;
2988: sum2 -= v2[0] * tmp0;
2989: sum3 -= v3[0] * tmp0;
2990: sum4 -= v4[0] * tmp0;
2991: sum5 -= v5[0] * tmp0;
2992: }
2993: t[row] = sum1;
2994: t[row+1] = sum2;
2995: t[row+2] = sum3;
2996: t[row+3] = sum4;
2997: t[row+4] = sum5;
2998: x[row++] = sum1*ibdiag[0] + sum2*ibdiag[5] + sum3*ibdiag[10] + sum4*ibdiag[15] + sum5*ibdiag[20];
2999: x[row++] = sum1*ibdiag[1] + sum2*ibdiag[6] + sum3*ibdiag[11] + sum4*ibdiag[16] + sum5*ibdiag[21];
3000: x[row++] = sum1*ibdiag[2] + sum2*ibdiag[7] + sum3*ibdiag[12] + sum4*ibdiag[17] + sum5*ibdiag[22];
3001: x[row++] = sum1*ibdiag[3] + sum2*ibdiag[8] + sum3*ibdiag[13] + sum4*ibdiag[18] + sum5*ibdiag[23];
3002: x[row++] = sum1*ibdiag[4] + sum2*ibdiag[9] + sum3*ibdiag[14] + sum4*ibdiag[19] + sum5*ibdiag[24];
3003: ibdiag += 25;
3004: break;
3005: default:
3006: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3007: }
3008: }
3010: xb = t;
3011: PetscLogFlops(a->nz);
3012: } else xb = b;
3013: if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
3015: ibdiag = a->inode.ibdiag+a->inode.bdiagsize;
3016: for (i=m-1, row=A->rmap->n-1; i>=0; i--) {
3017: ibdiag -= sizes[i]*sizes[i];
3018: sz = ii[row+1] - diag[row] - 1;
3019: v1 = a->a + diag[row] + 1;
3020: idx = a->j + diag[row] + 1;
3022: /* see comments for MatMult_SeqAIJ_Inode() for how this is coded */
3023: switch (sizes[i]) {
3024: case 1:
3026: sum1 = xb[row];
3027: for (n = 0; n<sz-1; n+=2) {
3028: i1 = idx[0];
3029: i2 = idx[1];
3030: idx += 2;
3031: tmp0 = x[i1];
3032: tmp1 = x[i2];
3033: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3034: }
3036: if (n == sz-1) {
3037: tmp0 = x[*idx];
3038: sum1 -= *v1*tmp0;
3039: }
3040: x[row--] = sum1*(*ibdiag);
3041: break;
3043: case 2:
3045: sum1 = xb[row];
3046: sum2 = xb[row-1];
3047: /* note that sum1 is associated with the second of the two rows */
3048: v2 = a->a + diag[row-1] + 2;
3049: for (n = 0; n<sz-1; n+=2) {
3050: i1 = idx[0];
3051: i2 = idx[1];
3052: idx += 2;
3053: tmp0 = x[i1];
3054: tmp1 = x[i2];
3055: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3056: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3057: }
3059: if (n == sz-1) {
3060: tmp0 = x[*idx];
3061: sum1 -= *v1*tmp0;
3062: sum2 -= *v2*tmp0;
3063: }
3064: x[row--] = sum2*ibdiag[1] + sum1*ibdiag[3];
3065: x[row--] = sum2*ibdiag[0] + sum1*ibdiag[2];
3066: break;
3067: case 3:
3069: sum1 = xb[row];
3070: sum2 = xb[row-1];
3071: sum3 = xb[row-2];
3072: v2 = a->a + diag[row-1] + 2;
3073: v3 = a->a + diag[row-2] + 3;
3074: for (n = 0; n<sz-1; n+=2) {
3075: i1 = idx[0];
3076: i2 = idx[1];
3077: idx += 2;
3078: tmp0 = x[i1];
3079: tmp1 = x[i2];
3080: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3081: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3082: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3083: }
3085: if (n == sz-1) {
3086: tmp0 = x[*idx];
3087: sum1 -= *v1*tmp0;
3088: sum2 -= *v2*tmp0;
3089: sum3 -= *v3*tmp0;
3090: }
3091: x[row--] = sum3*ibdiag[2] + sum2*ibdiag[5] + sum1*ibdiag[8];
3092: x[row--] = sum3*ibdiag[1] + sum2*ibdiag[4] + sum1*ibdiag[7];
3093: x[row--] = sum3*ibdiag[0] + sum2*ibdiag[3] + sum1*ibdiag[6];
3094: break;
3095: case 4:
3097: sum1 = xb[row];
3098: sum2 = xb[row-1];
3099: sum3 = xb[row-2];
3100: sum4 = xb[row-3];
3101: v2 = a->a + diag[row-1] + 2;
3102: v3 = a->a + diag[row-2] + 3;
3103: v4 = a->a + diag[row-3] + 4;
3104: for (n = 0; n<sz-1; n+=2) {
3105: i1 = idx[0];
3106: i2 = idx[1];
3107: idx += 2;
3108: tmp0 = x[i1];
3109: tmp1 = x[i2];
3110: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3111: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3112: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3113: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3114: }
3116: if (n == sz-1) {
3117: tmp0 = x[*idx];
3118: sum1 -= *v1*tmp0;
3119: sum2 -= *v2*tmp0;
3120: sum3 -= *v3*tmp0;
3121: sum4 -= *v4*tmp0;
3122: }
3123: x[row--] = sum4*ibdiag[3] + sum3*ibdiag[7] + sum2*ibdiag[11] + sum1*ibdiag[15];
3124: x[row--] = sum4*ibdiag[2] + sum3*ibdiag[6] + sum2*ibdiag[10] + sum1*ibdiag[14];
3125: x[row--] = sum4*ibdiag[1] + sum3*ibdiag[5] + sum2*ibdiag[9] + sum1*ibdiag[13];
3126: x[row--] = sum4*ibdiag[0] + sum3*ibdiag[4] + sum2*ibdiag[8] + sum1*ibdiag[12];
3127: break;
3128: case 5:
3130: sum1 = xb[row];
3131: sum2 = xb[row-1];
3132: sum3 = xb[row-2];
3133: sum4 = xb[row-3];
3134: sum5 = xb[row-4];
3135: v2 = a->a + diag[row-1] + 2;
3136: v3 = a->a + diag[row-2] + 3;
3137: v4 = a->a + diag[row-3] + 4;
3138: v5 = a->a + diag[row-4] + 5;
3139: for (n = 0; n<sz-1; n+=2) {
3140: i1 = idx[0];
3141: i2 = idx[1];
3142: idx += 2;
3143: tmp0 = x[i1];
3144: tmp1 = x[i2];
3145: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3146: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3147: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3148: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3149: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3150: }
3152: if (n == sz-1) {
3153: tmp0 = x[*idx];
3154: sum1 -= *v1*tmp0;
3155: sum2 -= *v2*tmp0;
3156: sum3 -= *v3*tmp0;
3157: sum4 -= *v4*tmp0;
3158: sum5 -= *v5*tmp0;
3159: }
3160: x[row--] = sum5*ibdiag[4] + sum4*ibdiag[9] + sum3*ibdiag[14] + sum2*ibdiag[19] + sum1*ibdiag[24];
3161: x[row--] = sum5*ibdiag[3] + sum4*ibdiag[8] + sum3*ibdiag[13] + sum2*ibdiag[18] + sum1*ibdiag[23];
3162: x[row--] = sum5*ibdiag[2] + sum4*ibdiag[7] + sum3*ibdiag[12] + sum2*ibdiag[17] + sum1*ibdiag[22];
3163: x[row--] = sum5*ibdiag[1] + sum4*ibdiag[6] + sum3*ibdiag[11] + sum2*ibdiag[16] + sum1*ibdiag[21];
3164: x[row--] = sum5*ibdiag[0] + sum4*ibdiag[5] + sum3*ibdiag[10] + sum2*ibdiag[15] + sum1*ibdiag[20];
3165: break;
3166: default:
3167: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3168: }
3169: }
3171: PetscLogFlops(a->nz);
3172: }
3173: its--;
3174: }
3175: while (its--) {
3177: if (flag & SOR_FORWARD_SWEEP || flag & SOR_LOCAL_FORWARD_SWEEP) {
3178: for (i=0, row=0, ibdiag = a->inode.ibdiag;
3179: i<m;
3180: row += sizes[i], ibdiag += sizes[i]*sizes[i], i++) {
3182: sz = diag[row] - ii[row];
3183: v1 = a->a + ii[row];
3184: idx = a->j + ii[row];
3185: /* see comments for MatMult_SeqAIJ_Inode() for how this is coded */
3186: switch (sizes[i]) {
3187: case 1:
3188: sum1 = b[row];
3189: for (n = 0; n<sz-1; n+=2) {
3190: i1 = idx[0];
3191: i2 = idx[1];
3192: idx += 2;
3193: tmp0 = x[i1];
3194: tmp1 = x[i2];
3195: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3196: }
3197: if (n == sz-1) {
3198: tmp0 = x[*idx++];
3199: sum1 -= *v1 * tmp0;
3200: v1++;
3201: }
3202: t[row] = sum1;
3203: sz = ii[row+1] - diag[row] - 1;
3204: idx = a->j + diag[row] + 1;
3205: v1 += 1;
3206: for (n = 0; n<sz-1; n+=2) {
3207: i1 = idx[0];
3208: i2 = idx[1];
3209: idx += 2;
3210: tmp0 = x[i1];
3211: tmp1 = x[i2];
3212: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3213: }
3214: if (n == sz-1) {
3215: tmp0 = x[*idx++];
3216: sum1 -= *v1 * tmp0;
3217: }
3218: /* in MatSOR_SeqAIJ this line would be
3219: *
3220: * x[row] = (1-omega)*x[row]+(sum1+(*bdiag++)*x[row])*(*ibdiag++);
3221: *
3222: * but omega == 1, so this becomes
3223: *
3224: * x[row] = sum1*(*ibdiag++);
3225: *
3226: */
3227: x[row] = sum1*(*ibdiag);
3228: break;
3229: case 2:
3230: v2 = a->a + ii[row+1];
3231: sum1 = b[row];
3232: sum2 = b[row+1];
3233: for (n = 0; n<sz-1; n+=2) {
3234: i1 = idx[0];
3235: i2 = idx[1];
3236: idx += 2;
3237: tmp0 = x[i1];
3238: tmp1 = x[i2];
3239: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3240: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3241: }
3242: if (n == sz-1) {
3243: tmp0 = x[*idx++];
3244: sum1 -= v1[0] * tmp0;
3245: sum2 -= v2[0] * tmp0;
3246: v1++; v2++;
3247: }
3248: t[row] = sum1;
3249: t[row+1] = sum2;
3250: sz = ii[row+1] - diag[row] - 2;
3251: idx = a->j + diag[row] + 2;
3252: v1 += 2;
3253: v2 += 2;
3254: for (n = 0; n<sz-1; n+=2) {
3255: i1 = idx[0];
3256: i2 = idx[1];
3257: idx += 2;
3258: tmp0 = x[i1];
3259: tmp1 = x[i2];
3260: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3261: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3262: }
3263: if (n == sz-1) {
3264: tmp0 = x[*idx];
3265: sum1 -= v1[0] * tmp0;
3266: sum2 -= v2[0] * tmp0;
3267: }
3268: x[row] = sum1*ibdiag[0] + sum2*ibdiag[2];
3269: x[row+1] = sum1*ibdiag[1] + sum2*ibdiag[3];
3270: break;
3271: case 3:
3272: v2 = a->a + ii[row+1];
3273: v3 = a->a + ii[row+2];
3274: sum1 = b[row];
3275: sum2 = b[row+1];
3276: sum3 = b[row+2];
3277: for (n = 0; n<sz-1; n+=2) {
3278: i1 = idx[0];
3279: i2 = idx[1];
3280: idx += 2;
3281: tmp0 = x[i1];
3282: tmp1 = x[i2];
3283: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3284: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3285: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3286: }
3287: if (n == sz-1) {
3288: tmp0 = x[*idx++];
3289: sum1 -= v1[0] * tmp0;
3290: sum2 -= v2[0] * tmp0;
3291: sum3 -= v3[0] * tmp0;
3292: v1++; v2++; v3++;
3293: }
3294: t[row] = sum1;
3295: t[row+1] = sum2;
3296: t[row+2] = sum3;
3297: sz = ii[row+1] - diag[row] - 3;
3298: idx = a->j + diag[row] + 3;
3299: v1 += 3;
3300: v2 += 3;
3301: v3 += 3;
3302: for (n = 0; n<sz-1; n+=2) {
3303: i1 = idx[0];
3304: i2 = idx[1];
3305: idx += 2;
3306: tmp0 = x[i1];
3307: tmp1 = x[i2];
3308: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3309: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3310: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3311: }
3312: if (n == sz-1) {
3313: tmp0 = x[*idx];
3314: sum1 -= v1[0] * tmp0;
3315: sum2 -= v2[0] * tmp0;
3316: sum3 -= v3[0] * tmp0;
3317: }
3318: x[row] = sum1*ibdiag[0] + sum2*ibdiag[3] + sum3*ibdiag[6];
3319: x[row+1] = sum1*ibdiag[1] + sum2*ibdiag[4] + sum3*ibdiag[7];
3320: x[row+2] = sum1*ibdiag[2] + sum2*ibdiag[5] + sum3*ibdiag[8];
3321: break;
3322: case 4:
3323: v2 = a->a + ii[row+1];
3324: v3 = a->a + ii[row+2];
3325: v4 = a->a + ii[row+3];
3326: sum1 = b[row];
3327: sum2 = b[row+1];
3328: sum3 = b[row+2];
3329: sum4 = b[row+3];
3330: for (n = 0; n<sz-1; n+=2) {
3331: i1 = idx[0];
3332: i2 = idx[1];
3333: idx += 2;
3334: tmp0 = x[i1];
3335: tmp1 = x[i2];
3336: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3337: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3338: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3339: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3340: }
3341: if (n == sz-1) {
3342: tmp0 = x[*idx++];
3343: sum1 -= v1[0] * tmp0;
3344: sum2 -= v2[0] * tmp0;
3345: sum3 -= v3[0] * tmp0;
3346: sum4 -= v4[0] * tmp0;
3347: v1++; v2++; v3++; v4++;
3348: }
3349: t[row] = sum1;
3350: t[row+1] = sum2;
3351: t[row+2] = sum3;
3352: t[row+3] = sum4;
3353: sz = ii[row+1] - diag[row] - 4;
3354: idx = a->j + diag[row] + 4;
3355: v1 += 4;
3356: v2 += 4;
3357: v3 += 4;
3358: v4 += 4;
3359: for (n = 0; n<sz-1; n+=2) {
3360: i1 = idx[0];
3361: i2 = idx[1];
3362: idx += 2;
3363: tmp0 = x[i1];
3364: tmp1 = x[i2];
3365: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3366: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3367: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3368: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3369: }
3370: if (n == sz-1) {
3371: tmp0 = x[*idx];
3372: sum1 -= v1[0] * tmp0;
3373: sum2 -= v2[0] * tmp0;
3374: sum3 -= v3[0] * tmp0;
3375: sum4 -= v4[0] * tmp0;
3376: }
3377: x[row] = sum1*ibdiag[0] + sum2*ibdiag[4] + sum3*ibdiag[8] + sum4*ibdiag[12];
3378: x[row+1] = sum1*ibdiag[1] + sum2*ibdiag[5] + sum3*ibdiag[9] + sum4*ibdiag[13];
3379: x[row+2] = sum1*ibdiag[2] + sum2*ibdiag[6] + sum3*ibdiag[10] + sum4*ibdiag[14];
3380: x[row+3] = sum1*ibdiag[3] + sum2*ibdiag[7] + sum3*ibdiag[11] + sum4*ibdiag[15];
3381: break;
3382: case 5:
3383: v2 = a->a + ii[row+1];
3384: v3 = a->a + ii[row+2];
3385: v4 = a->a + ii[row+3];
3386: v5 = a->a + ii[row+4];
3387: sum1 = b[row];
3388: sum2 = b[row+1];
3389: sum3 = b[row+2];
3390: sum4 = b[row+3];
3391: sum5 = b[row+4];
3392: for (n = 0; n<sz-1; n+=2) {
3393: i1 = idx[0];
3394: i2 = idx[1];
3395: idx += 2;
3396: tmp0 = x[i1];
3397: tmp1 = x[i2];
3398: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3399: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3400: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3401: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3402: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3403: }
3404: if (n == sz-1) {
3405: tmp0 = x[*idx++];
3406: sum1 -= v1[0] * tmp0;
3407: sum2 -= v2[0] * tmp0;
3408: sum3 -= v3[0] * tmp0;
3409: sum4 -= v4[0] * tmp0;
3410: sum5 -= v5[0] * tmp0;
3411: v1++; v2++; v3++; v4++; v5++;
3412: }
3413: t[row] = sum1;
3414: t[row+1] = sum2;
3415: t[row+2] = sum3;
3416: t[row+3] = sum4;
3417: t[row+4] = sum5;
3418: sz = ii[row+1] - diag[row] - 5;
3419: idx = a->j + diag[row] + 5;
3420: v1 += 5;
3421: v2 += 5;
3422: v3 += 5;
3423: v4 += 5;
3424: v5 += 5;
3425: for (n = 0; n<sz-1; n+=2) {
3426: i1 = idx[0];
3427: i2 = idx[1];
3428: idx += 2;
3429: tmp0 = x[i1];
3430: tmp1 = x[i2];
3431: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3432: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3433: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3434: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3435: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3436: }
3437: if (n == sz-1) {
3438: tmp0 = x[*idx];
3439: sum1 -= v1[0] * tmp0;
3440: sum2 -= v2[0] * tmp0;
3441: sum3 -= v3[0] * tmp0;
3442: sum4 -= v4[0] * tmp0;
3443: sum5 -= v5[0] * tmp0;
3444: }
3445: x[row] = sum1*ibdiag[0] + sum2*ibdiag[5] + sum3*ibdiag[10] + sum4*ibdiag[15] + sum5*ibdiag[20];
3446: x[row+1] = sum1*ibdiag[1] + sum2*ibdiag[6] + sum3*ibdiag[11] + sum4*ibdiag[16] + sum5*ibdiag[21];
3447: x[row+2] = sum1*ibdiag[2] + sum2*ibdiag[7] + sum3*ibdiag[12] + sum4*ibdiag[17] + sum5*ibdiag[22];
3448: x[row+3] = sum1*ibdiag[3] + sum2*ibdiag[8] + sum3*ibdiag[13] + sum4*ibdiag[18] + sum5*ibdiag[23];
3449: x[row+4] = sum1*ibdiag[4] + sum2*ibdiag[9] + sum3*ibdiag[14] + sum4*ibdiag[19] + sum5*ibdiag[24];
3450: break;
3451: default:
3452: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3453: }
3454: }
3455: xb = t;
3456: PetscLogFlops(2.0*a->nz); /* undercounts diag inverse */
3457: } else xb = b;
3459: if (flag & SOR_BACKWARD_SWEEP || flag & SOR_LOCAL_BACKWARD_SWEEP) {
3461: ibdiag = a->inode.ibdiag+a->inode.bdiagsize;
3462: for (i=m-1, row=A->rmap->n-1; i>=0; i--) {
3463: ibdiag -= sizes[i]*sizes[i];
3465: /* set RHS */
3466: if (xb == b) {
3467: /* whole (old way) */
3468: sz = ii[row+1] - ii[row];
3469: idx = a->j + ii[row];
3470: switch (sizes[i]) {
3471: case 5:
3472: v5 = a->a + ii[row-4];
3473: case 4: /* fall through */
3474: v4 = a->a + ii[row-3];
3475: case 3:
3476: v3 = a->a + ii[row-2];
3477: case 2:
3478: v2 = a->a + ii[row-1];
3479: case 1:
3480: v1 = a->a + ii[row];
3481: break;
3482: default:
3483: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3484: }
3485: } else {
3486: /* upper, no diag */
3487: sz = ii[row+1] - diag[row] - 1;
3488: idx = a->j + diag[row] + 1;
3489: switch (sizes[i]) {
3490: case 5:
3491: v5 = a->a + diag[row-4] + 5;
3492: case 4: /* fall through */
3493: v4 = a->a + diag[row-3] + 4;
3494: case 3:
3495: v3 = a->a + diag[row-2] + 3;
3496: case 2:
3497: v2 = a->a + diag[row-1] + 2;
3498: case 1:
3499: v1 = a->a + diag[row] + 1;
3500: }
3501: }
3502: /* set sum */
3503: switch (sizes[i]) {
3504: case 5:
3505: sum5 = xb[row-4];
3506: case 4: /* fall through */
3507: sum4 = xb[row-3];
3508: case 3:
3509: sum3 = xb[row-2];
3510: case 2:
3511: sum2 = xb[row-1];
3512: case 1:
3513: /* note that sum1 is associated with the last row */
3514: sum1 = xb[row];
3515: }
3516: /* do sums */
3517: for (n = 0; n<sz-1; n+=2) {
3518: i1 = idx[0];
3519: i2 = idx[1];
3520: idx += 2;
3521: tmp0 = x[i1];
3522: tmp1 = x[i2];
3523: switch (sizes[i]) {
3524: case 5:
3525: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3526: case 4: /* fall through */
3527: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3528: case 3:
3529: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3530: case 2:
3531: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3532: case 1:
3533: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3534: }
3535: }
3536: /* ragged edge */
3537: if (n == sz-1) {
3538: tmp0 = x[*idx];
3539: switch (sizes[i]) {
3540: case 5:
3541: sum5 -= *v5*tmp0;
3542: case 4: /* fall through */
3543: sum4 -= *v4*tmp0;
3544: case 3:
3545: sum3 -= *v3*tmp0;
3546: case 2:
3547: sum2 -= *v2*tmp0;
3548: case 1:
3549: sum1 -= *v1*tmp0;
3550: }
3551: }
3552: /* update */
3553: if (xb == b) {
3554: /* whole (old way) w/ diag */
3555: switch (sizes[i]) {
3556: case 5:
3557: x[row--] += sum5*ibdiag[4] + sum4*ibdiag[9] + sum3*ibdiag[14] + sum2*ibdiag[19] + sum1*ibdiag[24];
3558: x[row--] += sum5*ibdiag[3] + sum4*ibdiag[8] + sum3*ibdiag[13] + sum2*ibdiag[18] + sum1*ibdiag[23];
3559: x[row--] += sum5*ibdiag[2] + sum4*ibdiag[7] + sum3*ibdiag[12] + sum2*ibdiag[17] + sum1*ibdiag[22];
3560: x[row--] += sum5*ibdiag[1] + sum4*ibdiag[6] + sum3*ibdiag[11] + sum2*ibdiag[16] + sum1*ibdiag[21];
3561: x[row--] += sum5*ibdiag[0] + sum4*ibdiag[5] + sum3*ibdiag[10] + sum2*ibdiag[15] + sum1*ibdiag[20];
3562: break;
3563: case 4:
3564: x[row--] += sum4*ibdiag[3] + sum3*ibdiag[7] + sum2*ibdiag[11] + sum1*ibdiag[15];
3565: x[row--] += sum4*ibdiag[2] + sum3*ibdiag[6] + sum2*ibdiag[10] + sum1*ibdiag[14];
3566: x[row--] += sum4*ibdiag[1] + sum3*ibdiag[5] + sum2*ibdiag[9] + sum1*ibdiag[13];
3567: x[row--] += sum4*ibdiag[0] + sum3*ibdiag[4] + sum2*ibdiag[8] + sum1*ibdiag[12];
3568: break;
3569: case 3:
3570: x[row--] += sum3*ibdiag[2] + sum2*ibdiag[5] + sum1*ibdiag[8];
3571: x[row--] += sum3*ibdiag[1] + sum2*ibdiag[4] + sum1*ibdiag[7];
3572: x[row--] += sum3*ibdiag[0] + sum2*ibdiag[3] + sum1*ibdiag[6];
3573: break;
3574: case 2:
3575: x[row--] += sum2*ibdiag[1] + sum1*ibdiag[3];
3576: x[row--] += sum2*ibdiag[0] + sum1*ibdiag[2];
3577: break;
3578: case 1:
3579: x[row--] += sum1*(*ibdiag);
3580: break;
3581: }
3582: } else {
3583: /* no diag so set = */
3584: switch (sizes[i]) {
3585: case 5:
3586: x[row--] = sum5*ibdiag[4] + sum4*ibdiag[9] + sum3*ibdiag[14] + sum2*ibdiag[19] + sum1*ibdiag[24];
3587: x[row--] = sum5*ibdiag[3] + sum4*ibdiag[8] + sum3*ibdiag[13] + sum2*ibdiag[18] + sum1*ibdiag[23];
3588: x[row--] = sum5*ibdiag[2] + sum4*ibdiag[7] + sum3*ibdiag[12] + sum2*ibdiag[17] + sum1*ibdiag[22];
3589: x[row--] = sum5*ibdiag[1] + sum4*ibdiag[6] + sum3*ibdiag[11] + sum2*ibdiag[16] + sum1*ibdiag[21];
3590: x[row--] = sum5*ibdiag[0] + sum4*ibdiag[5] + sum3*ibdiag[10] + sum2*ibdiag[15] + sum1*ibdiag[20];
3591: break;
3592: case 4:
3593: x[row--] = sum4*ibdiag[3] + sum3*ibdiag[7] + sum2*ibdiag[11] + sum1*ibdiag[15];
3594: x[row--] = sum4*ibdiag[2] + sum3*ibdiag[6] + sum2*ibdiag[10] + sum1*ibdiag[14];
3595: x[row--] = sum4*ibdiag[1] + sum3*ibdiag[5] + sum2*ibdiag[9] + sum1*ibdiag[13];
3596: x[row--] = sum4*ibdiag[0] + sum3*ibdiag[4] + sum2*ibdiag[8] + sum1*ibdiag[12];
3597: break;
3598: case 3:
3599: x[row--] = sum3*ibdiag[2] + sum2*ibdiag[5] + sum1*ibdiag[8];
3600: x[row--] = sum3*ibdiag[1] + sum2*ibdiag[4] + sum1*ibdiag[7];
3601: x[row--] = sum3*ibdiag[0] + sum2*ibdiag[3] + sum1*ibdiag[6];
3602: break;
3603: case 2:
3604: x[row--] = sum2*ibdiag[1] + sum1*ibdiag[3];
3605: x[row--] = sum2*ibdiag[0] + sum1*ibdiag[2];
3606: break;
3607: case 1:
3608: x[row--] = sum1*(*ibdiag);
3609: break;
3610: }
3611: }
3612: }
3613: if (xb == b) {
3614: PetscLogFlops(2.0*a->nz);
3615: } else {
3616: PetscLogFlops(a->nz); /* assumes 1/2 in upper, undercounts diag inverse */
3617: }
3618: }
3619: }
3620: if (flag & SOR_EISENSTAT) {
3621: /*
3622: Apply (U + D)^-1 where D is now the block diagonal
3623: */
3624: ibdiag = a->inode.ibdiag+a->inode.bdiagsize;
3625: for (i=m-1, row=A->rmap->n-1; i>=0; i--) {
3626: ibdiag -= sizes[i]*sizes[i];
3627: sz = ii[row+1] - diag[row] - 1;
3628: v1 = a->a + diag[row] + 1;
3629: idx = a->j + diag[row] + 1;
3630: /* see comments for MatMult_SeqAIJ_Inode() for how this is coded */
3631: switch (sizes[i]) {
3632: case 1:
3634: sum1 = b[row];
3635: for (n = 0; n<sz-1; n+=2) {
3636: i1 = idx[0];
3637: i2 = idx[1];
3638: idx += 2;
3639: tmp0 = x[i1];
3640: tmp1 = x[i2];
3641: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3642: }
3644: if (n == sz-1) {
3645: tmp0 = x[*idx];
3646: sum1 -= *v1*tmp0;
3647: }
3648: x[row] = sum1*(*ibdiag);row--;
3649: break;
3651: case 2:
3653: sum1 = b[row];
3654: sum2 = b[row-1];
3655: /* note that sum1 is associated with the second of the two rows */
3656: v2 = a->a + diag[row-1] + 2;
3657: for (n = 0; n<sz-1; n+=2) {
3658: i1 = idx[0];
3659: i2 = idx[1];
3660: idx += 2;
3661: tmp0 = x[i1];
3662: tmp1 = x[i2];
3663: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3664: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3665: }
3667: if (n == sz-1) {
3668: tmp0 = x[*idx];
3669: sum1 -= *v1*tmp0;
3670: sum2 -= *v2*tmp0;
3671: }
3672: x[row] = sum2*ibdiag[1] + sum1*ibdiag[3];
3673: x[row-1] = sum2*ibdiag[0] + sum1*ibdiag[2];
3674: row -= 2;
3675: break;
3676: case 3:
3678: sum1 = b[row];
3679: sum2 = b[row-1];
3680: sum3 = b[row-2];
3681: v2 = a->a + diag[row-1] + 2;
3682: v3 = a->a + diag[row-2] + 3;
3683: for (n = 0; n<sz-1; n+=2) {
3684: i1 = idx[0];
3685: i2 = idx[1];
3686: idx += 2;
3687: tmp0 = x[i1];
3688: tmp1 = x[i2];
3689: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3690: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3691: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3692: }
3694: if (n == sz-1) {
3695: tmp0 = x[*idx];
3696: sum1 -= *v1*tmp0;
3697: sum2 -= *v2*tmp0;
3698: sum3 -= *v3*tmp0;
3699: }
3700: x[row] = sum3*ibdiag[2] + sum2*ibdiag[5] + sum1*ibdiag[8];
3701: x[row-1] = sum3*ibdiag[1] + sum2*ibdiag[4] + sum1*ibdiag[7];
3702: x[row-2] = sum3*ibdiag[0] + sum2*ibdiag[3] + sum1*ibdiag[6];
3703: row -= 3;
3704: break;
3705: case 4:
3707: sum1 = b[row];
3708: sum2 = b[row-1];
3709: sum3 = b[row-2];
3710: sum4 = b[row-3];
3711: v2 = a->a + diag[row-1] + 2;
3712: v3 = a->a + diag[row-2] + 3;
3713: v4 = a->a + diag[row-3] + 4;
3714: for (n = 0; n<sz-1; n+=2) {
3715: i1 = idx[0];
3716: i2 = idx[1];
3717: idx += 2;
3718: tmp0 = x[i1];
3719: tmp1 = x[i2];
3720: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3721: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3722: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3723: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3724: }
3726: if (n == sz-1) {
3727: tmp0 = x[*idx];
3728: sum1 -= *v1*tmp0;
3729: sum2 -= *v2*tmp0;
3730: sum3 -= *v3*tmp0;
3731: sum4 -= *v4*tmp0;
3732: }
3733: x[row] = sum4*ibdiag[3] + sum3*ibdiag[7] + sum2*ibdiag[11] + sum1*ibdiag[15];
3734: x[row-1] = sum4*ibdiag[2] + sum3*ibdiag[6] + sum2*ibdiag[10] + sum1*ibdiag[14];
3735: x[row-2] = sum4*ibdiag[1] + sum3*ibdiag[5] + sum2*ibdiag[9] + sum1*ibdiag[13];
3736: x[row-3] = sum4*ibdiag[0] + sum3*ibdiag[4] + sum2*ibdiag[8] + sum1*ibdiag[12];
3737: row -= 4;
3738: break;
3739: case 5:
3741: sum1 = b[row];
3742: sum2 = b[row-1];
3743: sum3 = b[row-2];
3744: sum4 = b[row-3];
3745: sum5 = b[row-4];
3746: v2 = a->a + diag[row-1] + 2;
3747: v3 = a->a + diag[row-2] + 3;
3748: v4 = a->a + diag[row-3] + 4;
3749: v5 = a->a + diag[row-4] + 5;
3750: for (n = 0; n<sz-1; n+=2) {
3751: i1 = idx[0];
3752: i2 = idx[1];
3753: idx += 2;
3754: tmp0 = x[i1];
3755: tmp1 = x[i2];
3756: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3757: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3758: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3759: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3760: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3761: }
3763: if (n == sz-1) {
3764: tmp0 = x[*idx];
3765: sum1 -= *v1*tmp0;
3766: sum2 -= *v2*tmp0;
3767: sum3 -= *v3*tmp0;
3768: sum4 -= *v4*tmp0;
3769: sum5 -= *v5*tmp0;
3770: }
3771: x[row] = sum5*ibdiag[4] + sum4*ibdiag[9] + sum3*ibdiag[14] + sum2*ibdiag[19] + sum1*ibdiag[24];
3772: x[row-1] = sum5*ibdiag[3] + sum4*ibdiag[8] + sum3*ibdiag[13] + sum2*ibdiag[18] + sum1*ibdiag[23];
3773: x[row-2] = sum5*ibdiag[2] + sum4*ibdiag[7] + sum3*ibdiag[12] + sum2*ibdiag[17] + sum1*ibdiag[22];
3774: x[row-3] = sum5*ibdiag[1] + sum4*ibdiag[6] + sum3*ibdiag[11] + sum2*ibdiag[16] + sum1*ibdiag[21];
3775: x[row-4] = sum5*ibdiag[0] + sum4*ibdiag[5] + sum3*ibdiag[10] + sum2*ibdiag[15] + sum1*ibdiag[20];
3776: row -= 5;
3777: break;
3778: default:
3779: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3780: }
3781: }
3782: PetscLogFlops(a->nz);
3784: /*
3785: t = b - D x where D is the block diagonal
3786: */
3787: cnt = 0;
3788: for (i=0, row=0; i<m; i++) {
3789: switch (sizes[i]) {
3790: case 1:
3791: t[row] = b[row] - bdiag[cnt++]*x[row]; row++;
3792: break;
3793: case 2:
3794: x1 = x[row]; x2 = x[row+1];
3795: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+2];
3796: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+3];
3797: t[row] = b[row] - tmp1;
3798: t[row+1] = b[row+1] - tmp2; row += 2;
3799: cnt += 4;
3800: break;
3801: case 3:
3802: x1 = x[row]; x2 = x[row+1]; x3 = x[row+2];
3803: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+3] + x3*bdiag[cnt+6];
3804: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+4] + x3*bdiag[cnt+7];
3805: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+5] + x3*bdiag[cnt+8];
3806: t[row] = b[row] - tmp1;
3807: t[row+1] = b[row+1] - tmp2;
3808: t[row+2] = b[row+2] - tmp3; row += 3;
3809: cnt += 9;
3810: break;
3811: case 4:
3812: x1 = x[row]; x2 = x[row+1]; x3 = x[row+2]; x4 = x[row+3];
3813: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+4] + x3*bdiag[cnt+8] + x4*bdiag[cnt+12];
3814: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+5] + x3*bdiag[cnt+9] + x4*bdiag[cnt+13];
3815: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+6] + x3*bdiag[cnt+10] + x4*bdiag[cnt+14];
3816: tmp4 = x1*bdiag[cnt+3] + x2*bdiag[cnt+7] + x3*bdiag[cnt+11] + x4*bdiag[cnt+15];
3817: t[row] = b[row] - tmp1;
3818: t[row+1] = b[row+1] - tmp2;
3819: t[row+2] = b[row+2] - tmp3;
3820: t[row+3] = b[row+3] - tmp4; row += 4;
3821: cnt += 16;
3822: break;
3823: case 5:
3824: x1 = x[row]; x2 = x[row+1]; x3 = x[row+2]; x4 = x[row+3]; x5 = x[row+4];
3825: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+5] + x3*bdiag[cnt+10] + x4*bdiag[cnt+15] + x5*bdiag[cnt+20];
3826: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+6] + x3*bdiag[cnt+11] + x4*bdiag[cnt+16] + x5*bdiag[cnt+21];
3827: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+7] + x3*bdiag[cnt+12] + x4*bdiag[cnt+17] + x5*bdiag[cnt+22];
3828: tmp4 = x1*bdiag[cnt+3] + x2*bdiag[cnt+8] + x3*bdiag[cnt+13] + x4*bdiag[cnt+18] + x5*bdiag[cnt+23];
3829: tmp5 = x1*bdiag[cnt+4] + x2*bdiag[cnt+9] + x3*bdiag[cnt+14] + x4*bdiag[cnt+19] + x5*bdiag[cnt+24];
3830: t[row] = b[row] - tmp1;
3831: t[row+1] = b[row+1] - tmp2;
3832: t[row+2] = b[row+2] - tmp3;
3833: t[row+3] = b[row+3] - tmp4;
3834: t[row+4] = b[row+4] - tmp5;row += 5;
3835: cnt += 25;
3836: break;
3837: default:
3838: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3839: }
3840: }
3841: PetscLogFlops(m);
3845: /*
3846: Apply (L + D)^-1 where D is the block diagonal
3847: */
3848: for (i=0, row=0; i<m; i++) {
3849: sz = diag[row] - ii[row];
3850: v1 = a->a + ii[row];
3851: idx = a->j + ii[row];
3852: /* see comments for MatMult_SeqAIJ_Inode() for how this is coded */
3853: switch (sizes[i]) {
3854: case 1:
3856: sum1 = t[row];
3857: for (n = 0; n<sz-1; n+=2) {
3858: i1 = idx[0];
3859: i2 = idx[1];
3860: idx += 2;
3861: tmp0 = t[i1];
3862: tmp1 = t[i2];
3863: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3864: }
3866: if (n == sz-1) {
3867: tmp0 = t[*idx];
3868: sum1 -= *v1 * tmp0;
3869: }
3870: x[row] += t[row] = sum1*(*ibdiag++); row++;
3871: break;
3872: case 2:
3873: v2 = a->a + ii[row+1];
3874: sum1 = t[row];
3875: sum2 = t[row+1];
3876: for (n = 0; n<sz-1; n+=2) {
3877: i1 = idx[0];
3878: i2 = idx[1];
3879: idx += 2;
3880: tmp0 = t[i1];
3881: tmp1 = t[i2];
3882: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3883: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3884: }
3886: if (n == sz-1) {
3887: tmp0 = t[*idx];
3888: sum1 -= v1[0] * tmp0;
3889: sum2 -= v2[0] * tmp0;
3890: }
3891: x[row] += t[row] = sum1*ibdiag[0] + sum2*ibdiag[2];
3892: x[row+1] += t[row+1] = sum1*ibdiag[1] + sum2*ibdiag[3];
3893: ibdiag += 4; row += 2;
3894: break;
3895: case 3:
3896: v2 = a->a + ii[row+1];
3897: v3 = a->a + ii[row+2];
3898: sum1 = t[row];
3899: sum2 = t[row+1];
3900: sum3 = t[row+2];
3901: for (n = 0; n<sz-1; n+=2) {
3902: i1 = idx[0];
3903: i2 = idx[1];
3904: idx += 2;
3905: tmp0 = t[i1];
3906: tmp1 = t[i2];
3907: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3908: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3909: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3910: }
3912: if (n == sz-1) {
3913: tmp0 = t[*idx];
3914: sum1 -= v1[0] * tmp0;
3915: sum2 -= v2[0] * tmp0;
3916: sum3 -= v3[0] * tmp0;
3917: }
3918: x[row] += t[row] = sum1*ibdiag[0] + sum2*ibdiag[3] + sum3*ibdiag[6];
3919: x[row+1] += t[row+1] = sum1*ibdiag[1] + sum2*ibdiag[4] + sum3*ibdiag[7];
3920: x[row+2] += t[row+2] = sum1*ibdiag[2] + sum2*ibdiag[5] + sum3*ibdiag[8];
3921: ibdiag += 9; row += 3;
3922: break;
3923: case 4:
3924: v2 = a->a + ii[row+1];
3925: v3 = a->a + ii[row+2];
3926: v4 = a->a + ii[row+3];
3927: sum1 = t[row];
3928: sum2 = t[row+1];
3929: sum3 = t[row+2];
3930: sum4 = t[row+3];
3931: for (n = 0; n<sz-1; n+=2) {
3932: i1 = idx[0];
3933: i2 = idx[1];
3934: idx += 2;
3935: tmp0 = t[i1];
3936: tmp1 = t[i2];
3937: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3938: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3939: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3940: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3941: }
3943: if (n == sz-1) {
3944: tmp0 = t[*idx];
3945: sum1 -= v1[0] * tmp0;
3946: sum2 -= v2[0] * tmp0;
3947: sum3 -= v3[0] * tmp0;
3948: sum4 -= v4[0] * tmp0;
3949: }
3950: x[row] += t[row] = sum1*ibdiag[0] + sum2*ibdiag[4] + sum3*ibdiag[8] + sum4*ibdiag[12];
3951: x[row+1] += t[row+1] = sum1*ibdiag[1] + sum2*ibdiag[5] + sum3*ibdiag[9] + sum4*ibdiag[13];
3952: x[row+2] += t[row+2] = sum1*ibdiag[2] + sum2*ibdiag[6] + sum3*ibdiag[10] + sum4*ibdiag[14];
3953: x[row+3] += t[row+3] = sum1*ibdiag[3] + sum2*ibdiag[7] + sum3*ibdiag[11] + sum4*ibdiag[15];
3954: ibdiag += 16; row += 4;
3955: break;
3956: case 5:
3957: v2 = a->a + ii[row+1];
3958: v3 = a->a + ii[row+2];
3959: v4 = a->a + ii[row+3];
3960: v5 = a->a + ii[row+4];
3961: sum1 = t[row];
3962: sum2 = t[row+1];
3963: sum3 = t[row+2];
3964: sum4 = t[row+3];
3965: sum5 = t[row+4];
3966: for (n = 0; n<sz-1; n+=2) {
3967: i1 = idx[0];
3968: i2 = idx[1];
3969: idx += 2;
3970: tmp0 = t[i1];
3971: tmp1 = t[i2];
3972: sum1 -= v1[0] * tmp0 + v1[1] * tmp1; v1 += 2;
3973: sum2 -= v2[0] * tmp0 + v2[1] * tmp1; v2 += 2;
3974: sum3 -= v3[0] * tmp0 + v3[1] * tmp1; v3 += 2;
3975: sum4 -= v4[0] * tmp0 + v4[1] * tmp1; v4 += 2;
3976: sum5 -= v5[0] * tmp0 + v5[1] * tmp1; v5 += 2;
3977: }
3979: if (n == sz-1) {
3980: tmp0 = t[*idx];
3981: sum1 -= v1[0] * tmp0;
3982: sum2 -= v2[0] * tmp0;
3983: sum3 -= v3[0] * tmp0;
3984: sum4 -= v4[0] * tmp0;
3985: sum5 -= v5[0] * tmp0;
3986: }
3987: x[row] += t[row] = sum1*ibdiag[0] + sum2*ibdiag[5] + sum3*ibdiag[10] + sum4*ibdiag[15] + sum5*ibdiag[20];
3988: x[row+1] += t[row+1] = sum1*ibdiag[1] + sum2*ibdiag[6] + sum3*ibdiag[11] + sum4*ibdiag[16] + sum5*ibdiag[21];
3989: x[row+2] += t[row+2] = sum1*ibdiag[2] + sum2*ibdiag[7] + sum3*ibdiag[12] + sum4*ibdiag[17] + sum5*ibdiag[22];
3990: x[row+3] += t[row+3] = sum1*ibdiag[3] + sum2*ibdiag[8] + sum3*ibdiag[13] + sum4*ibdiag[18] + sum5*ibdiag[23];
3991: x[row+4] += t[row+4] = sum1*ibdiag[4] + sum2*ibdiag[9] + sum3*ibdiag[14] + sum4*ibdiag[19] + sum5*ibdiag[24];
3992: ibdiag += 25; row += 5;
3993: break;
3994: default:
3995: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
3996: }
3997: }
3998: PetscLogFlops(a->nz);
3999: }
4000: VecRestoreArray(xx,&x);
4001: VecRestoreArrayRead(bb,&b);
4002: return(0);
4003: }
4007: PetscErrorCode MatMultDiagonalBlock_SeqAIJ_Inode(Mat A,Vec bb,Vec xx)
4008: {
4009: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
4010: PetscScalar *x,tmp1,tmp2,tmp3,tmp4,tmp5,x1,x2,x3,x4,x5;
4011: const MatScalar *bdiag = a->inode.bdiag;
4012: const PetscScalar *b;
4013: PetscErrorCode ierr;
4014: PetscInt m = a->inode.node_count,cnt = 0,i,row;
4015: const PetscInt *sizes = a->inode.size;
4018: VecGetArray(xx,&x);
4019: VecGetArrayRead(bb,&b);
4020: cnt = 0;
4021: for (i=0, row=0; i<m; i++) {
4022: switch (sizes[i]) {
4023: case 1:
4024: x[row] = b[row]*bdiag[cnt++];row++;
4025: break;
4026: case 2:
4027: x1 = b[row]; x2 = b[row+1];
4028: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+2];
4029: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+3];
4030: x[row++] = tmp1;
4031: x[row++] = tmp2;
4032: cnt += 4;
4033: break;
4034: case 3:
4035: x1 = b[row]; x2 = b[row+1]; x3 = b[row+2];
4036: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+3] + x3*bdiag[cnt+6];
4037: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+4] + x3*bdiag[cnt+7];
4038: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+5] + x3*bdiag[cnt+8];
4039: x[row++] = tmp1;
4040: x[row++] = tmp2;
4041: x[row++] = tmp3;
4042: cnt += 9;
4043: break;
4044: case 4:
4045: x1 = b[row]; x2 = b[row+1]; x3 = b[row+2]; x4 = b[row+3];
4046: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+4] + x3*bdiag[cnt+8] + x4*bdiag[cnt+12];
4047: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+5] + x3*bdiag[cnt+9] + x4*bdiag[cnt+13];
4048: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+6] + x3*bdiag[cnt+10] + x4*bdiag[cnt+14];
4049: tmp4 = x1*bdiag[cnt+3] + x2*bdiag[cnt+7] + x3*bdiag[cnt+11] + x4*bdiag[cnt+15];
4050: x[row++] = tmp1;
4051: x[row++] = tmp2;
4052: x[row++] = tmp3;
4053: x[row++] = tmp4;
4054: cnt += 16;
4055: break;
4056: case 5:
4057: x1 = b[row]; x2 = b[row+1]; x3 = b[row+2]; x4 = b[row+3]; x5 = b[row+4];
4058: tmp1 = x1*bdiag[cnt] + x2*bdiag[cnt+5] + x3*bdiag[cnt+10] + x4*bdiag[cnt+15] + x5*bdiag[cnt+20];
4059: tmp2 = x1*bdiag[cnt+1] + x2*bdiag[cnt+6] + x3*bdiag[cnt+11] + x4*bdiag[cnt+16] + x5*bdiag[cnt+21];
4060: tmp3 = x1*bdiag[cnt+2] + x2*bdiag[cnt+7] + x3*bdiag[cnt+12] + x4*bdiag[cnt+17] + x5*bdiag[cnt+22];
4061: tmp4 = x1*bdiag[cnt+3] + x2*bdiag[cnt+8] + x3*bdiag[cnt+13] + x4*bdiag[cnt+18] + x5*bdiag[cnt+23];
4062: tmp5 = x1*bdiag[cnt+4] + x2*bdiag[cnt+9] + x3*bdiag[cnt+14] + x4*bdiag[cnt+19] + x5*bdiag[cnt+24];
4063: x[row++] = tmp1;
4064: x[row++] = tmp2;
4065: x[row++] = tmp3;
4066: x[row++] = tmp4;
4067: x[row++] = tmp5;
4068: cnt += 25;
4069: break;
4070: default:
4071: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Inode size %D not supported",sizes[i]);
4072: }
4073: }
4074: PetscLogFlops(2*cnt);
4075: VecRestoreArray(xx,&x);
4076: VecRestoreArrayRead(bb,&b);
4077: return(0);
4078: }
4080: /*
4081: samestructure indicates that the matrix has not changed its nonzero structure so we
4082: do not need to recompute the inodes
4083: */
4086: PetscErrorCode MatSeqAIJCheckInode(Mat A)
4087: {
4088: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
4090: PetscInt i,j,m,nzx,nzy,*ns,node_count,blk_size;
4091: PetscBool flag;
4092: const PetscInt *idx,*idy,*ii;
4095: if (!a->inode.use) return(0);
4096: if (a->inode.checked && A->nonzerostate == a->inode.mat_nonzerostate) return(0);
4098: m = A->rmap->n;
4099: if (a->inode.size) ns = a->inode.size;
4100: else {
4101: PetscMalloc1(m+1,&ns);
4102: }
4104: i = 0;
4105: node_count = 0;
4106: idx = a->j;
4107: ii = a->i;
4108: while (i < m) { /* For each row */
4109: nzx = ii[i+1] - ii[i]; /* Number of nonzeros */
4110: /* Limits the number of elements in a node to 'a->inode.limit' */
4111: for (j=i+1,idy=idx,blk_size=1; j<m && blk_size <a->inode.limit; ++j,++blk_size) {
4112: nzy = ii[j+1] - ii[j]; /* Same number of nonzeros */
4113: if (nzy != nzx) break;
4114: idy += nzx; /* Same nonzero pattern */
4115: PetscMemcmp(idx,idy,nzx*sizeof(PetscInt),&flag);
4116: if (!flag) break;
4117: }
4118: ns[node_count++] = blk_size;
4119: idx += blk_size*nzx;
4120: i = j;
4121: }
4122: /* If not enough inodes found,, do not use inode version of the routines */
4123: if (!m || node_count > .8*m) {
4124: PetscFree(ns);
4126: a->inode.node_count = 0;
4127: a->inode.size = NULL;
4128: a->inode.use = PETSC_FALSE;
4129: A->ops->mult = MatMult_SeqAIJ;
4130: A->ops->sor = MatSOR_SeqAIJ;
4131: A->ops->multadd = MatMultAdd_SeqAIJ;
4132: A->ops->getrowij = MatGetRowIJ_SeqAIJ;
4133: A->ops->restorerowij = MatRestoreRowIJ_SeqAIJ;
4134: A->ops->getcolumnij = MatGetColumnIJ_SeqAIJ;
4135: A->ops->restorecolumnij = MatRestoreColumnIJ_SeqAIJ;
4136: A->ops->coloringpatch = 0;
4137: A->ops->multdiagonalblock = 0;
4139: PetscInfo2(A,"Found %D nodes out of %D rows. Not using Inode routines\n",node_count,m);
4140: } else {
4141: if (!A->factortype) {
4142: A->ops->mult = MatMult_SeqAIJ_Inode;
4143: A->ops->sor = MatSOR_SeqAIJ_Inode;
4144: A->ops->multadd = MatMultAdd_SeqAIJ_Inode;
4145: A->ops->multdiagonalblock = MatMultDiagonalBlock_SeqAIJ_Inode;
4146: if (A->rmap->n == A->cmap->n) {
4147: A->ops->getrowij = MatGetRowIJ_SeqAIJ_Inode;
4148: A->ops->restorerowij = MatRestoreRowIJ_SeqAIJ_Inode;
4149: A->ops->getcolumnij = MatGetColumnIJ_SeqAIJ_Inode;
4150: A->ops->restorecolumnij = MatRestoreColumnIJ_SeqAIJ_Inode;
4151: A->ops->coloringpatch = MatColoringPatch_SeqAIJ_Inode;
4152: }
4153: } else {
4154: A->ops->solve = MatSolve_SeqAIJ_Inode_inplace;
4155: }
4156: a->inode.node_count = node_count;
4157: a->inode.size = ns;
4158: PetscInfo3(A,"Found %D nodes of %D. Limit used: %D. Using Inode routines\n",node_count,m,a->inode.limit);
4159: }
4160: a->inode.checked = PETSC_TRUE;
4161: a->inode.mat_nonzerostate = A->nonzerostate;
4162: return(0);
4163: }
4167: PetscErrorCode MatDuplicate_SeqAIJ_Inode(Mat A,MatDuplicateOption cpvalues,Mat *C)
4168: {
4169: Mat B =*C;
4170: Mat_SeqAIJ *c=(Mat_SeqAIJ*)B->data,*a=(Mat_SeqAIJ*)A->data;
4172: PetscInt m=A->rmap->n;
4175: c->inode.use = a->inode.use;
4176: c->inode.limit = a->inode.limit;
4177: c->inode.max_limit = a->inode.max_limit;
4178: if (a->inode.size) {
4179: PetscMalloc1(m+1,&c->inode.size);
4180: c->inode.node_count = a->inode.node_count;
4181: PetscMemcpy(c->inode.size,a->inode.size,(m+1)*sizeof(PetscInt));
4182: /* note the table of functions below should match that in MatSeqAIJCheckInode() */
4183: if (!B->factortype) {
4184: B->ops->mult = MatMult_SeqAIJ_Inode;
4185: B->ops->sor = MatSOR_SeqAIJ_Inode;
4186: B->ops->multadd = MatMultAdd_SeqAIJ_Inode;
4187: B->ops->getrowij = MatGetRowIJ_SeqAIJ_Inode;
4188: B->ops->restorerowij = MatRestoreRowIJ_SeqAIJ_Inode;
4189: B->ops->getcolumnij = MatGetColumnIJ_SeqAIJ_Inode;
4190: B->ops->restorecolumnij = MatRestoreColumnIJ_SeqAIJ_Inode;
4191: B->ops->coloringpatch = MatColoringPatch_SeqAIJ_Inode;
4192: B->ops->multdiagonalblock = MatMultDiagonalBlock_SeqAIJ_Inode;
4193: } else {
4194: B->ops->solve = MatSolve_SeqAIJ_Inode_inplace;
4195: }
4196: } else {
4197: c->inode.size = 0;
4198: c->inode.node_count = 0;
4199: }
4200: c->inode.ibdiagvalid = PETSC_FALSE;
4201: c->inode.ibdiag = 0;
4202: c->inode.bdiag = 0;
4203: return(0);
4204: }
4208: PETSC_STATIC_INLINE PetscErrorCode MatGetRow_FactoredLU(PetscInt *cols,PetscInt nzl,PetscInt nzu,PetscInt nz,const PetscInt *ai,const PetscInt *aj,const PetscInt *adiag,PetscInt row)
4209: {
4210: PetscInt k;
4211: const PetscInt *vi;
4214: vi = aj + ai[row];
4215: for (k=0; k<nzl; k++) cols[k] = vi[k];
4216: vi = aj + adiag[row];
4217: cols[nzl] = vi[0];
4218: vi = aj + adiag[row+1]+1;
4219: for (k=0; k<nzu; k++) cols[nzl+1+k] = vi[k];
4220: return(0);
4221: }
4222: /*
4223: MatSeqAIJCheckInode_FactorLU - Check Inode for factored seqaij matrix.
4224: Modified from MatSeqAIJCheckInode().
4226: Input Parameters:
4227: . Mat A - ILU or LU matrix factor
4229: */
4232: PetscErrorCode MatSeqAIJCheckInode_FactorLU(Mat A)
4233: {
4234: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
4236: PetscInt i,j,m,nzl1,nzu1,nzl2,nzu2,nzx,nzy,node_count,blk_size;
4237: PetscInt *cols1,*cols2,*ns;
4238: const PetscInt *ai = a->i,*aj = a->j, *adiag = a->diag;
4239: PetscBool flag;
4242: if (!a->inode.use) return(0);
4243: if (a->inode.checked) return(0);
4245: m = A->rmap->n;
4246: if (a->inode.size) ns = a->inode.size;
4247: else {
4248: PetscMalloc1(m+1,&ns);
4249: }
4251: i = 0;
4252: node_count = 0;
4253: PetscMalloc2(m,&cols1,m,&cols2);
4254: while (i < m) { /* For each row */
4255: nzl1 = ai[i+1] - ai[i]; /* Number of nonzeros in L */
4256: nzu1 = adiag[i] - adiag[i+1] - 1; /* Number of nonzeros in U excluding diagonal*/
4257: nzx = nzl1 + nzu1 + 1;
4258: MatGetRow_FactoredLU(cols1,nzl1,nzu1,nzx,ai,aj,adiag,i);
4260: /* Limits the number of elements in a node to 'a->inode.limit' */
4261: for (j=i+1,blk_size=1; j<m && blk_size <a->inode.limit; ++j,++blk_size) {
4262: nzl2 = ai[j+1] - ai[j];
4263: nzu2 = adiag[j] - adiag[j+1] - 1;
4264: nzy = nzl2 + nzu2 + 1;
4265: if (nzy != nzx) break;
4266: MatGetRow_FactoredLU(cols2,nzl2,nzu2,nzy,ai,aj,adiag,j);
4267: PetscMemcmp(cols1,cols2,nzx*sizeof(PetscInt),&flag);
4268: if (!flag) break;
4269: }
4270: ns[node_count++] = blk_size;
4271: i = j;
4272: }
4273: PetscFree2(cols1,cols2);
4274: /* If not enough inodes found,, do not use inode version of the routines */
4275: if (!m || node_count > .8*m) {
4276: PetscFree(ns);
4278: a->inode.node_count = 0;
4279: a->inode.size = NULL;
4280: a->inode.use = PETSC_FALSE;
4282: PetscInfo2(A,"Found %D nodes out of %D rows. Not using Inode routines\n",node_count,m);
4283: } else {
4284: A->ops->mult = 0;
4285: A->ops->sor = 0;
4286: A->ops->multadd = 0;
4287: A->ops->getrowij = 0;
4288: A->ops->restorerowij = 0;
4289: A->ops->getcolumnij = 0;
4290: A->ops->restorecolumnij = 0;
4291: A->ops->coloringpatch = 0;
4292: A->ops->multdiagonalblock = 0;
4293: a->inode.node_count = node_count;
4294: a->inode.size = ns;
4296: PetscInfo3(A,"Found %D nodes of %D. Limit used: %D. Using Inode routines\n",node_count,m,a->inode.limit);
4297: }
4298: a->inode.checked = PETSC_TRUE;
4299: return(0);
4300: }
4304: PetscErrorCode MatSeqAIJInvalidateDiagonal_Inode(Mat A)
4305: {
4306: Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data;
4309: a->inode.ibdiagvalid = PETSC_FALSE;
4310: return(0);
4311: }
4313: /*
4314: This is really ugly. if inodes are used this replaces the
4315: permutations with ones that correspond to rows/cols of the matrix
4316: rather then inode blocks
4317: */
4320: PetscErrorCode MatInodeAdjustForInodes(Mat A,IS *rperm,IS *cperm)
4321: {
4325: PetscTryMethod(A,"MatInodeAdjustForInodes_C",(Mat,IS*,IS*),(A,rperm,cperm));
4326: return(0);
4327: }
4331: PetscErrorCode MatInodeAdjustForInodes_SeqAIJ_Inode(Mat A,IS *rperm,IS *cperm)
4332: {
4333: Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data;
4335: PetscInt m = A->rmap->n,n = A->cmap->n,i,j,nslim_row = a->inode.node_count;
4336: const PetscInt *ridx,*cidx;
4337: PetscInt row,col,*permr,*permc,*ns_row = a->inode.size,*tns,start_val,end_val,indx;
4338: PetscInt nslim_col,*ns_col;
4339: IS ris = *rperm,cis = *cperm;
4342: if (!a->inode.size) return(0); /* no inodes so return */
4343: if (a->inode.node_count == m) return(0); /* all inodes are of size 1 */
4345: Mat_CreateColInode(A,&nslim_col,&ns_col);
4346: PetscMalloc1(((nslim_row>nslim_col) ? nslim_row : nslim_col)+1,&tns);
4347: PetscMalloc2(m,&permr,n,&permc);
4349: ISGetIndices(ris,&ridx);
4350: ISGetIndices(cis,&cidx);
4352: /* Form the inode structure for the rows of permuted matric using inv perm*/
4353: for (i=0,tns[0]=0; i<nslim_row; ++i) tns[i+1] = tns[i] + ns_row[i];
4355: /* Construct the permutations for rows*/
4356: for (i=0,row = 0; i<nslim_row; ++i) {
4357: indx = ridx[i];
4358: start_val = tns[indx];
4359: end_val = tns[indx + 1];
4360: for (j=start_val; j<end_val; ++j,++row) permr[row]= j;
4361: }
4363: /* Form the inode structure for the columns of permuted matrix using inv perm*/
4364: for (i=0,tns[0]=0; i<nslim_col; ++i) tns[i+1] = tns[i] + ns_col[i];
4366: /* Construct permutations for columns */
4367: for (i=0,col=0; i<nslim_col; ++i) {
4368: indx = cidx[i];
4369: start_val = tns[indx];
4370: end_val = tns[indx + 1];
4371: for (j = start_val; j<end_val; ++j,++col) permc[col]= j;
4372: }
4374: ISCreateGeneral(PETSC_COMM_SELF,n,permr,PETSC_COPY_VALUES,rperm);
4375: ISSetPermutation(*rperm);
4376: ISCreateGeneral(PETSC_COMM_SELF,n,permc,PETSC_COPY_VALUES,cperm);
4377: ISSetPermutation(*cperm);
4379: ISRestoreIndices(ris,&ridx);
4380: ISRestoreIndices(cis,&cidx);
4382: PetscFree(ns_col);
4383: PetscFree2(permr,permc);
4384: ISDestroy(&cis);
4385: ISDestroy(&ris);
4386: PetscFree(tns);
4387: return(0);
4388: }
4392: /*@C
4393: MatInodeGetInodeSizes - Returns the inode information of the Inode matrix.
4395: Not Collective
4397: Input Parameter:
4398: . A - the Inode matrix or matrix derived from the Inode class -- e.g., SeqAIJ
4400: Output Parameter:
4401: + node_count - no of inodes present in the matrix.
4402: . sizes - an array of size node_count,with sizes of each inode.
4403: - limit - the max size used to generate the inodes.
4405: Level: advanced
4407: Notes: This routine returns some internal storage information
4408: of the matrix, it is intended to be used by advanced users.
4409: It should be called after the matrix is assembled.
4410: The contents of the sizes[] array should not be changed.
4411: NULL may be passed for information not requested.
4413: .keywords: matrix, seqaij, get, inode
4415: .seealso: MatGetInfo()
4416: @*/
4417: PetscErrorCode MatInodeGetInodeSizes(Mat A,PetscInt *node_count,PetscInt *sizes[],PetscInt *limit)
4418: {
4419: PetscErrorCode ierr,(*f)(Mat,PetscInt*,PetscInt*[],PetscInt*);
4422: if (!A->assembled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Not for unassembled matrix");
4423: PetscObjectQueryFunction((PetscObject)A,"MatInodeGetInodeSizes_C",&f);
4424: if (f) {
4425: (*f)(A,node_count,sizes,limit);
4426: }
4427: return(0);
4428: }
4432: PetscErrorCode MatInodeGetInodeSizes_SeqAIJ_Inode(Mat A,PetscInt *node_count,PetscInt *sizes[],PetscInt *limit)
4433: {
4434: Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
4437: if (node_count) *node_count = a->inode.node_count;
4438: if (sizes) *sizes = a->inode.size;
4439: if (limit) *limit = a->inode.limit;
4440: return(0);
4441: }