xref: /petsc/src/mat/impls/aij/seq/aijfact.c (revision fed8bd04579a14b36e05ea2a8e40d3c1d32ad520)
1 /*$Id: aijfact.c,v 1.160 2001/04/10 19:35:19 bsmith Exp bsmith $*/
2 
3 #include "src/mat/impls/aij/seq/aij.h"
4 #include "src/vec/vecimpl.h"
5 #include "src/inline/dot.h"
6 
7 #undef __FUNCT__
8 #define __FUNCT__ "MatOrdering_Flow_SeqAIJ"
9 int MatOrdering_Flow_SeqAIJ(Mat mat,MatOrderingType type,IS *irow,IS *icol)
10 {
11   PetscFunctionBegin;
12 
13   SETERRQ(PETSC_ERR_SUP,"Code not written");
14 #if !defined(PETSC_USE_DEBUG)
15   PetscFunctionReturn(0);
16 #endif
17 }
18 
19 
20 EXTERN int MatMarkDiagonal_SeqAIJ(Mat);
21 EXTERN int Mat_AIJ_CheckInode(Mat);
22 
23 EXTERN int SPARSEKIT2dperm(int*,Scalar*,int*,int*,Scalar*,int*,int*,int*,int*,int*);
24 EXTERN int SPARSEKIT2ilutp(int*,Scalar*,int*,int*,int*,PetscReal*,PetscReal*,int*,Scalar*,int*,int*,int*,Scalar*,int*,int*,int*);
25 EXTERN int SPARSEKIT2msrcsr(int*,Scalar*,int*,Scalar*,int*,int*,Scalar*,int*);
26 
27 #undef __FUNCT__
28 #define __FUNCT__ "MatILUDTFactor_SeqAIJ"
29   /* ------------------------------------------------------------
30 
31           This interface was contribed by Tony Caola
32 
33      This routine is an interface to the pivoting drop-tolerance
34      ILU routine written by Yousef Saad (saad@cs.umn.edu) as part of
35      SPARSEKIT2.
36 
37      The SPARSEKIT2 routines used here are covered by the GNU
38      copyright; see the file gnu in this directory.
39 
40      Thanks to Prof. Saad, Dr. Hysom, and Dr. Smith for their
41      help in getting this routine ironed out.
42 
43      The major drawback to this routine is that if info->fill is
44      not large enough it fails rather than allocating more space;
45      this can be fixed by hacking/improving the f2c version of
46      Yousef Saad's code.
47 
48      ishift = 0, for indices start at 1
49      ishift = 1, for indices starting at 0
50      ------------------------------------------------------------
51   */
52 
53 int MatILUDTFactor_SeqAIJ(Mat A,MatILUInfo *info,IS isrow,IS iscol,Mat *fact)
54 {
55   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b;
56   IS         iscolf,isicol,isirow;
57   PetscTruth reorder;
58   int        *c,*r,*ic,ierr,i,n = A->m;
59   int        *old_i = a->i,*old_j = a->j,*new_i,*old_i2 = 0,*old_j2 = 0,*new_j;
60   int        *ordcol,*iwk,*iperm,*jw;
61   int        ishift = !a->indexshift;
62   int        jmax,lfill,job,*o_i,*o_j;
63   Scalar     *old_a = a->a,*w,*new_a,*old_a2 = 0,*wk,*o_a;
64   PetscReal  permtol,af;
65 
66   PetscFunctionBegin;
67 
68   if (info->dt == PETSC_DEFAULT)      info->dt      = .005;
69   if (info->dtcount == PETSC_DEFAULT) info->dtcount = (int)(1.5*a->rmax);
70   if (info->dtcol == PETSC_DEFAULT)   info->dtcol   = .01;
71   if (info->fill == PETSC_DEFAULT)    info->fill    = ((double)(n*(info->dtcount+1)))/a->nz;
72   lfill   = (int)(info->dtcount/2.0);
73   jmax    = (int)(info->fill*a->nz);
74   permtol = info->dtcol;
75 
76 
77   /* ------------------------------------------------------------
78      If reorder=.TRUE., then the original matrix has to be
79      reordered to reflect the user selected ordering scheme, and
80      then de-reordered so it is in it's original format.
81      Because Saad's dperm() is NOT in place, we have to copy
82      the original matrix and allocate more storage. . .
83      ------------------------------------------------------------
84   */
85 
86   /* set reorder to true if either isrow or iscol is not identity */
87   ierr = ISIdentity(isrow,&reorder);CHKERRQ(ierr);
88   if (reorder) {ierr = ISIdentity(iscol,&reorder);CHKERRQ(ierr);}
89   reorder = PetscNot(reorder);
90 
91 
92   /* storage for ilu factor */
93   ierr = PetscMalloc((n+1)*sizeof(int),&new_i);CHKERRQ(ierr);
94   ierr = PetscMalloc(jmax*sizeof(int),&new_j);CHKERRQ(ierr);
95   ierr = PetscMalloc(jmax*sizeof(Scalar),&new_a);CHKERRQ(ierr);
96   ierr = PetscMalloc(n*sizeof(int),&ordcol);CHKERRQ(ierr);
97 
98   /* ------------------------------------------------------------
99      Make sure that everything is Fortran formatted (1-Based)
100      ------------------------------------------------------------
101   */
102   if (ishift) {
103     for (i=old_i[0];i<old_i[n];i++) {
104       old_j[i]++;
105     }
106     for(i=0;i<n+1;i++) {
107       old_i[i]++;
108     };
109   };
110 
111   if (reorder) {
112     ierr = ISGetIndices(iscol,&c);           CHKERRQ(ierr);
113     ierr = ISGetIndices(isrow,&r);           CHKERRQ(ierr);
114     for(i=0;i<n;i++) {
115       r[i]  = r[i]+1;
116       c[i]  = c[i]+1;
117     }
118     ierr = PetscMalloc((n+1)*sizeof(int),&old_i2);CHKERRQ(ierr);
119     ierr = PetscMalloc((old_i[n]-old_i[0]+1)*sizeof(int),&old_j2);CHKERRQ(ierr);
120     ierr = PetscMalloc((old_i[n]-old_i[0]+1)*sizeof(Scalar),old_a2);CHKERRQ(ierr);
121     job  = 3; SPARSEKIT2dperm(&n,old_a,old_j,old_i,old_a2,old_j2,old_i2,r,c,&job);
122     for (i=0;i<n;i++) {
123       r[i]  = r[i]-1;
124       c[i]  = c[i]-1;
125     }
126     ierr = ISRestoreIndices(iscol,&c);CHKERRQ(ierr);
127     ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr);
128     o_a = old_a2;
129     o_j = old_j2;
130     o_i = old_i2;
131   } else {
132     o_a = old_a;
133     o_j = old_j;
134     o_i = old_i;
135   }
136 
137   /* ------------------------------------------------------------
138      Call Saad's ilutp() routine to generate the factorization
139      ------------------------------------------------------------
140   */
141 
142   ierr = PetscMalloc(2*n*sizeof(int),&iperm);CHKERRQ(ierr);
143   ierr = PetscMalloc(2*n*sizeof(int),&jw);CHKERRQ(ierr);
144   ierr = PetscMalloc(n*sizeof(Scalar),&w);CHKERRQ(ierr);
145 
146   SPARSEKIT2ilutp(&n,o_a,o_j,o_i,&lfill,&info->dt,&permtol,&n,new_a,new_j,new_i,&jmax,w,jw,iperm,&ierr);
147   if (ierr) {
148     switch (ierr) {
149       case -3: SETERRQ2(1,"ilutp(), matrix U overflows, need larger info->fill current fill %g space allocated %d",info->fill,jmax);
150       case -2: SETERRQ2(1,"ilutp(), matrix L overflows, need larger info->fill current fill %g space allocated %d",info->fill,jmax);
151       case -5: SETERRQ(1,"ilutp(), zero row encountered");
152       case -1: SETERRQ(1,"ilutp(), input matrix may be wrong");
153       case -4: SETERRQ1(1,"ilutp(), illegal info->fill value %d",jmax);
154       default: SETERRQ1(1,"ilutp(), zero pivot detected on row %d",ierr);
155     }
156   }
157 
158   ierr = PetscFree(w);CHKERRQ(ierr);
159   ierr = PetscFree(jw);CHKERRQ(ierr);
160 
161   /* ------------------------------------------------------------
162      Saad's routine gives the result in Modified Sparse Row (msr)
163      Convert to Compressed Sparse Row format (csr)
164      ------------------------------------------------------------
165   */
166 
167   ierr = PetscMalloc(n*sizeof(Scalar),&wk);CHKERRQ(ierr);
168   ierr = PetscMalloc((n+1)*sizeof(int),&iwk);CHKERRQ(ierr);
169 
170   SPARSEKIT2msrcsr(&n,new_a,new_j,new_a,new_j,new_i,wk,iwk);
171 
172   ierr = PetscFree(iwk);CHKERRQ(ierr);
173   ierr = PetscFree(wk);CHKERRQ(ierr);
174 
175   if (reorder) {
176     ierr = PetscFree(old_a2);CHKERRQ(ierr);
177     ierr = PetscFree(old_j2);CHKERRQ(ierr);
178     ierr = PetscFree(old_i2);CHKERRQ(ierr);
179   } else {
180     /* fix permutation of old_j that the factorization introduced */
181     for (i=old_i[0]; i<old_i[n]; i++) {
182       old_j[i-1] = iperm[old_j[i-1]-1];
183     }
184   }
185 
186   /* get rid of the shift to indices starting at 1 */
187   if (ishift) {
188     for (i=0; i<n+1; i++) {
189       old_i[i]--;
190     }
191     for (i=old_i[0];i<old_i[n];i++) {
192       old_j[i]--;
193     }
194   }
195 
196   /* Make the factored matrix 0-based */
197   if (ishift) {
198     for (i=0; i<n+1; i++) {
199       new_i[i]--;
200     }
201     for (i=new_i[0];i<new_i[n];i++) {
202       new_j[i]--;
203     }
204   }
205 
206   /*-- due to the pivoting, we need to reorder iscol to correctly --*/
207   /*-- permute the right-hand-side and solution vectors           --*/
208   ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr);
209   ierr = ISInvertPermutation(isrow,PETSC_DECIDE,&isirow);CHKERRQ(ierr);
210   ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr);
211   for(i=0; i<n; i++) {
212     ordcol[i] = ic[iperm[i]-1];
213   };
214   ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr);
215   ierr = ISDestroy(isicol);CHKERRQ(ierr);
216 
217   ierr = PetscFree(iperm);CHKERRQ(ierr);
218 
219   ierr = ISCreateGeneral(PETSC_COMM_SELF,n,ordcol,&iscolf);CHKERRQ(ierr);
220   ierr = PetscFree(ordcol);CHKERRQ(ierr);
221 
222   /*----- put together the new matrix -----*/
223 
224   ierr = MatCreateSeqAIJ(A->comm,n,n,0,PETSC_NULL,fact);CHKERRQ(ierr);
225   (*fact)->factor    = FACTOR_LU;
226   (*fact)->assembled = PETSC_TRUE;
227 
228   b = (Mat_SeqAIJ*)(*fact)->data;
229   ierr = PetscFree(b->imax);CHKERRQ(ierr);
230   b->sorted        = PETSC_FALSE;
231   b->singlemalloc  = PETSC_FALSE;
232   /* the next line frees the default space generated by the MatCreate() */
233   ierr             = PetscFree(b->a);CHKERRQ(ierr);
234   ierr             = PetscFree(b->ilen);CHKERRQ(ierr);
235   b->a             = new_a;
236   b->j             = new_j;
237   b->i             = new_i;
238   b->ilen          = 0;
239   b->imax          = 0;
240   /*  I am not sure why these are the inverses of the row and column permutations; but the other way is NO GOOD */
241   b->row           = isirow;
242   b->col           = iscolf;
243   ierr = PetscMalloc((n+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
244   b->maxnz = b->nz = new_i[n];
245   b->indexshift    = a->indexshift;
246   ierr = MatMarkDiagonal_SeqAIJ(*fact);CHKERRQ(ierr);
247   (*fact)->info.factor_mallocs = 0;
248 
249   ierr = MatMarkDiagonal_SeqAIJ(A);CHKERRQ(ierr);
250 
251   /* check out for identical nodes. If found, use inode functions */
252   ierr = Mat_AIJ_CheckInode(*fact);CHKERRQ(ierr);
253 
254   af = ((double)b->nz)/((double)a->nz) + .001;
255   PetscLogInfo(A,"MatILUDTFactor_SeqAIJ:Fill ratio:given %g needed %g\n",info->fill,af);
256   PetscLogInfo(A,"MatILUDTFactor_SeqAIJ:Run with -pc_ilu_fill %g or use \n",af);
257   PetscLogInfo(A,"MatILUDTFactor_SeqAIJ:PCILUSetFill(pc,%g);\n",af);
258   PetscLogInfo(A,"MatILUDTFactor_SeqAIJ:for best performance.\n");
259 
260   PetscFunctionReturn(0);
261 }
262 
263 /*
264     Factorization code for AIJ format.
265 */
266 #undef __FUNCT__
267 #define __FUNCT__ "MatLUFactorSymbolic_SeqAIJ"
268 int MatLUFactorSymbolic_SeqAIJ(Mat A,IS isrow,IS iscol,MatLUInfo *info,Mat *B)
269 {
270   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b;
271   IS         isicol;
272   int        *r,*ic,ierr,i,n = A->m,*ai = a->i,*aj = a->j;
273   int        *ainew,*ajnew,jmax,*fill,*ajtmp,nz,shift = a->indexshift;
274   int        *idnew,idx,row,m,fm,nnz,nzi,realloc = 0,nzbd,*im;
275   PetscReal  f;
276 
277   PetscFunctionBegin;
278   PetscValidHeaderSpecific(isrow,IS_COOKIE);
279   PetscValidHeaderSpecific(iscol,IS_COOKIE);
280   if (A->M != A->N) SETERRQ(PETSC_ERR_ARG_WRONG,"matrix must be square");
281 
282   if (!isrow) {
283     ierr = ISCreateStride(PETSC_COMM_SELF,A->M,0,1,&isrow);CHKERRQ(ierr);
284   }
285   if (!iscol) {
286     ierr = ISCreateStride(PETSC_COMM_SELF,A->M,0,1,&iscol);CHKERRQ(ierr);
287   }
288 
289   ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr);
290   ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr);
291   ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr);
292 
293   /* get new row pointers */
294   ierr = PetscMalloc((n+1)*sizeof(int),&ainew);CHKERRQ(ierr);
295   ainew[0] = -shift;
296   /* don't know how many column pointers are needed so estimate */
297   if (info) f = info->fill; else f = 1.0;
298   jmax  = (int)(f*ai[n]+(!shift));
299   ierr = PetscMalloc((jmax)*sizeof(int),&ajnew);CHKERRQ(ierr);
300   /* fill is a linked list of nonzeros in active row */
301   ierr = PetscMalloc((2*n+1)*sizeof(int),&fill);CHKERRQ(ierr);
302   im   = fill + n + 1;
303   /* idnew is location of diagonal in factor */
304   ierr = PetscMalloc((n+1)*sizeof(int),&idnew);CHKERRQ(ierr);
305   idnew[0] = -shift;
306 
307   for (i=0; i<n; i++) {
308     /* first copy previous fill into linked list */
309     nnz     = nz    = ai[r[i]+1] - ai[r[i]];
310     if (!nz) SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,"Empty row in matrix");
311     ajtmp   = aj + ai[r[i]] + shift;
312     fill[n] = n;
313     while (nz--) {
314       fm  = n;
315       idx = ic[*ajtmp++ + shift];
316       do {
317         m  = fm;
318         fm = fill[m];
319       } while (fm < idx);
320       fill[m]   = idx;
321       fill[idx] = fm;
322     }
323     row = fill[n];
324     while (row < i) {
325       ajtmp = ajnew + idnew[row] + (!shift);
326       nzbd  = 1 + idnew[row] - ainew[row];
327       nz    = im[row] - nzbd;
328       fm    = row;
329       while (nz-- > 0) {
330         idx = *ajtmp++ + shift;
331         nzbd++;
332         if (idx == i) im[row] = nzbd;
333         do {
334           m  = fm;
335           fm = fill[m];
336         } while (fm < idx);
337         if (fm != idx) {
338           fill[m]   = idx;
339           fill[idx] = fm;
340           fm        = idx;
341           nnz++;
342         }
343       }
344       row = fill[row];
345     }
346     /* copy new filled row into permanent storage */
347     ainew[i+1] = ainew[i] + nnz;
348     if (ainew[i+1] > jmax) {
349 
350       /* estimate how much additional space we will need */
351       /* use the strategy suggested by David Hysom <hysom@perch-t.icase.edu> */
352       /* just double the memory each time */
353       int maxadd = jmax;
354       /* maxadd = (int)((f*(ai[n]+(!shift))*(n-i+5))/n); */
355       if (maxadd < nnz) maxadd = (n-i)*(nnz+1);
356       jmax += maxadd;
357 
358       /* allocate a longer ajnew */
359       ierr = PetscMalloc(jmax*sizeof(int),&ajtmp);CHKERRQ(ierr);
360       ierr  = PetscMemcpy(ajtmp,ajnew,(ainew[i]+shift)*sizeof(int));CHKERRQ(ierr);
361       ierr  = PetscFree(ajnew);CHKERRQ(ierr);
362       ajnew = ajtmp;
363       realloc++; /* count how many times we realloc */
364     }
365     ajtmp = ajnew + ainew[i] + shift;
366     fm    = fill[n];
367     nzi   = 0;
368     im[i] = nnz;
369     while (nnz--) {
370       if (fm < i) nzi++;
371       *ajtmp++ = fm - shift;
372       fm       = fill[fm];
373     }
374     idnew[i] = ainew[i] + nzi;
375   }
376   if (ai[n] != 0) {
377     PetscReal af = ((PetscReal)ainew[n])/((PetscReal)ai[n]);
378     PetscLogInfo(A,"MatLUFactorSymbolic_SeqAIJ:Reallocs %d Fill ratio:given %g needed %g\n",realloc,f,af);
379     PetscLogInfo(A,"MatLUFactorSymbolic_SeqAIJ:Run with -pc_lu_fill %g or use \n",af);
380     PetscLogInfo(A,"MatLUFactorSymbolic_SeqAIJ:PCLUSetFill(pc,%g);\n",af);
381     PetscLogInfo(A,"MatLUFactorSymbolic_SeqAIJ:for best performance.\n");
382   } else {
383     PetscLogInfo(A,"MatLUFactorSymbolic_SeqAIJ: Empty matrix\n");
384   }
385 
386   ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr);
387   ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr);
388 
389   ierr = PetscFree(fill);CHKERRQ(ierr);
390 
391   /* put together the new matrix */
392   ierr = MatCreateSeqAIJ(A->comm,n,n,0,PETSC_NULL,B);CHKERRQ(ierr);
393   PetscLogObjectParent(*B,isicol);
394   b = (Mat_SeqAIJ*)(*B)->data;
395   ierr = PetscFree(b->imax);CHKERRQ(ierr);
396   b->singlemalloc = PETSC_FALSE;
397   /* the next line frees the default space generated by the Create() */
398   ierr = PetscFree(b->a);CHKERRQ(ierr);
399   ierr = PetscFree(b->ilen);CHKERRQ(ierr);
400   ierr          = PetscMalloc((ainew[n]+shift+1)*sizeof(Scalar),&b->a);CHKERRQ(ierr);
401   b->j          = ajnew;
402   b->i          = ainew;
403   b->diag       = idnew;
404   b->ilen       = 0;
405   b->imax       = 0;
406   b->row        = isrow;
407   b->col        = iscol;
408   if (info) {
409     b->lu_damp    = (PetscTruth) ((int)info->damp);
410     b->lu_damping = info->damping;
411   } else {
412     b->lu_damp    = PETSC_FALSE;
413     b->lu_damping = 0.0;
414   }
415   ierr          = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
416   ierr          = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
417   b->icol       = isicol;
418   ierr          = PetscMalloc((n+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
419   /* In b structure:  Free imax, ilen, old a, old j.
420      Allocate idnew, solve_work, new a, new j */
421   PetscLogObjectMemory(*B,(ainew[n]+shift-n)*(sizeof(int)+sizeof(Scalar)));
422   b->maxnz = b->nz = ainew[n] + shift;
423 
424   (*B)->factor                 =  FACTOR_LU;
425   (*B)->info.factor_mallocs    = realloc;
426   (*B)->info.fill_ratio_given  = f;
427   (*B)->ops->lufactornumeric   =  A->ops->lufactornumeric; /* Use Inode variant ONLY if A has inodes */
428 
429   if (ai[n] != 0) {
430     (*B)->info.fill_ratio_needed = ((PetscReal)ainew[n])/((PetscReal)ai[n]);
431   } else {
432     (*B)->info.fill_ratio_needed = 0.0;
433   }
434   PetscFunctionReturn(0);
435 }
436 /* ----------------------------------------------------------- */
437 EXTERN int Mat_AIJ_CheckInode(Mat);
438 
439 #undef __FUNCT__
440 #define __FUNCT__ "MatLUFactorNumeric_SeqAIJ"
441 int MatLUFactorNumeric_SeqAIJ(Mat A,Mat *B)
442 {
443   Mat        C = *B;
444   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b = (Mat_SeqAIJ *)C->data;
445   IS         isrow = b->row,isicol = b->icol;
446   int        *r,*ic,ierr,i,j,n = A->m,*ai = b->i,*aj = b->j;
447   int        *ajtmpold,*ajtmp,nz,row,*ics,shift = a->indexshift;
448   int        *diag_offset = b->diag,diag;
449   int        *pj,ndamp = 0;
450   Scalar     *rtmp,*v,*pc,multiplier,*pv,*rtmps;
451   PetscReal  damping = b->lu_damping;
452   PetscTruth damp;
453 
454   PetscFunctionBegin;
455 
456   ierr  = ISGetIndices(isrow,&r);CHKERRQ(ierr);
457   ierr  = ISGetIndices(isicol,&ic);CHKERRQ(ierr);
458   ierr = PetscMalloc((n+1)*sizeof(Scalar),&rtmp);CHKERRQ(ierr);
459   ierr  = PetscMemzero(rtmp,(n+1)*sizeof(Scalar));CHKERRQ(ierr);
460   rtmps = rtmp + shift; ics = ic + shift;
461 
462   do {
463     damp = PETSC_FALSE;
464     for (i=0; i<n; i++) {
465       nz    = ai[i+1] - ai[i];
466       ajtmp = aj + ai[i] + shift;
467       for  (j=0; j<nz; j++) rtmps[ajtmp[j]] = 0.0;
468 
469       /* load in initial (unfactored row) */
470       nz       = a->i[r[i]+1] - a->i[r[i]];
471       ajtmpold = a->j + a->i[r[i]] + shift;
472       v        = a->a + a->i[r[i]] + shift;
473       for (j=0; j<nz; j++) {
474         rtmp[ics[ajtmpold[j]]] = v[j];
475         if (ajtmpold[j] == r[i]) { /* damp the diagonal of the matrix */
476           rtmp[ics[ajtmpold[j]]] += damping;
477         }
478       }
479 
480       row = *ajtmp++ + shift;
481       while  (row < i) {
482         pc = rtmp + row;
483         if (*pc != 0.0) {
484           pv         = b->a + diag_offset[row] + shift;
485           pj         = b->j + diag_offset[row] + (!shift);
486           multiplier = *pc / *pv++;
487           *pc        = multiplier;
488           nz         = ai[row+1] - diag_offset[row] - 1;
489           for (j=0; j<nz; j++) rtmps[pj[j]] -= multiplier * pv[j];
490           PetscLogFlops(2*nz);
491         }
492         row = *ajtmp++ + shift;
493       }
494       /* finished row so stick it into b->a */
495       pv = b->a + ai[i] + shift;
496       pj = b->j + ai[i] + shift;
497       nz = ai[i+1] - ai[i];
498       for (j=0; j<nz; j++) {pv[j] = rtmps[pj[j]];}
499       diag = diag_offset[i] - ai[i];
500       if (PetscAbsScalar(pv[diag]) < 1.e-12) {
501         if (b->lu_damp) {
502           damp = PETSC_TRUE;
503           if (damping) damping *= 2.0;
504           else damping = 1.e-12;
505           ndamp++;
506           break;
507         } else {
508           SETERRQ1(PETSC_ERR_MAT_LU_ZRPVT,"Zero pivot row %d",i);
509         }
510       }
511     }
512   } while (damp);
513 
514   /* invert diagonal entries for simplier triangular solves */
515   for (i=0; i<n; i++) {
516     b->a[diag_offset[i]+shift] = 1.0/b->a[diag_offset[i]+shift];
517   }
518 
519   ierr = PetscFree(rtmp);CHKERRQ(ierr);
520   ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr);
521   ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr);
522   C->factor = FACTOR_LU;
523   ierr = Mat_AIJ_CheckInode(C);CHKERRQ(ierr);
524   (*B)->ops->lufactornumeric   =  A->ops->lufactornumeric; /* Use Inode variant ONLY if A has inodes */
525   C->assembled = PETSC_TRUE;
526   PetscLogFlops(C->n);
527   if (ndamp || b->lu_damping) {
528     PetscLogInfo(0,"MatLUFactorNumerical_SeqAIJ: number of damping tries %d damping value %g\n",ndamp,damping);
529   }
530   PetscFunctionReturn(0);
531 }
532 /* ----------------------------------------------------------- */
533 #undef __FUNCT__
534 #define __FUNCT__ "MatLUFactor_SeqAIJ"
535 int MatLUFactor_SeqAIJ(Mat A,IS row,IS col,MatLUInfo *info)
536 {
537   int ierr;
538   Mat C;
539 
540   PetscFunctionBegin;
541   ierr = MatLUFactorSymbolic(A,row,col,info,&C);CHKERRQ(ierr);
542   ierr = MatLUFactorNumeric(A,&C);CHKERRQ(ierr);
543   ierr = MatHeaderCopy(A,C);CHKERRQ(ierr);
544   PetscFunctionReturn(0);
545 }
546 /* ----------------------------------------------------------- */
547 #undef __FUNCT__
548 #define __FUNCT__ "MatSolve_SeqAIJ"
549 int MatSolve_SeqAIJ(Mat A,Vec bb,Vec xx)
550 {
551   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
552   IS         iscol = a->col,isrow = a->row;
553   int        *r,*c,ierr,i, n = A->m,*vi,*ai = a->i,*aj = a->j;
554   int        nz,shift = a->indexshift,*rout,*cout;
555   Scalar     *x,*b,*tmp,*tmps,*aa = a->a,sum,*v;
556 
557   PetscFunctionBegin;
558   if (!n) PetscFunctionReturn(0);
559 
560   ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
561   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
562   tmp  = a->solve_work;
563 
564   ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout;
565   ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout + (n-1);
566 
567   /* forward solve the lower triangular */
568   tmp[0] = b[*r++];
569   tmps   = tmp + shift;
570   for (i=1; i<n; i++) {
571     v   = aa + ai[i] + shift;
572     vi  = aj + ai[i] + shift;
573     nz  = a->diag[i] - ai[i];
574     sum = b[*r++];
575     while (nz--) sum -= *v++ * tmps[*vi++];
576     tmp[i] = sum;
577   }
578 
579   /* backward solve the upper triangular */
580   for (i=n-1; i>=0; i--){
581     v   = aa + a->diag[i] + (!shift);
582     vi  = aj + a->diag[i] + (!shift);
583     nz  = ai[i+1] - a->diag[i] - 1;
584     sum = tmp[i];
585     while (nz--) sum -= *v++ * tmps[*vi++];
586     x[*c--] = tmp[i] = sum*aa[a->diag[i]+shift];
587   }
588 
589   ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr);
590   ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr);
591   ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);
592   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
593   PetscLogFlops(2*a->nz - A->n);
594   PetscFunctionReturn(0);
595 }
596 
597 /* ----------------------------------------------------------- */
598 #undef __FUNCT__
599 #define __FUNCT__ "MatSolve_SeqAIJ_NaturalOrdering"
600 int MatSolve_SeqAIJ_NaturalOrdering(Mat A,Vec bb,Vec xx)
601 {
602   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
603   int        n = A->m,*ai = a->i,*aj = a->j,*adiag = a->diag,ierr;
604   Scalar     *x,*b,*aa = a->a,sum;
605 #if !defined(PETSC_USE_FORTRAN_KERNEL_SOLVEAIJ)
606   int        adiag_i,i,*vi,nz,ai_i;
607   Scalar     *v;
608 #endif
609 
610   PetscFunctionBegin;
611   if (!n) PetscFunctionReturn(0);
612   if (a->indexshift) {
613      ierr = MatSolve_SeqAIJ(A,bb,xx);CHKERRQ(ierr);
614      PetscFunctionReturn(0);
615   }
616 
617   ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
618   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
619 
620 #if defined(PETSC_USE_FORTRAN_KERNEL_SOLVEAIJ)
621   fortransolveaij_(&n,x,ai,aj,adiag,aa,b);
622 #else
623   /* forward solve the lower triangular */
624   x[0] = b[0];
625   for (i=1; i<n; i++) {
626     ai_i = ai[i];
627     v    = aa + ai_i;
628     vi   = aj + ai_i;
629     nz   = adiag[i] - ai_i;
630     sum  = b[i];
631     while (nz--) sum -= *v++ * x[*vi++];
632     x[i] = sum;
633   }
634 
635   /* backward solve the upper triangular */
636   for (i=n-1; i>=0; i--){
637     adiag_i = adiag[i];
638     v       = aa + adiag_i + 1;
639     vi      = aj + adiag_i + 1;
640     nz      = ai[i+1] - adiag_i - 1;
641     sum     = x[i];
642     while (nz--) sum -= *v++ * x[*vi++];
643     x[i]    = sum*aa[adiag_i];
644   }
645 #endif
646   PetscLogFlops(2*a->nz - A->n);
647   ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);
648   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
649   PetscFunctionReturn(0);
650 }
651 
652 #undef __FUNCT__
653 #define __FUNCT__ "MatSolveAdd_SeqAIJ"
654 int MatSolveAdd_SeqAIJ(Mat A,Vec bb,Vec yy,Vec xx)
655 {
656   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
657   IS         iscol = a->col,isrow = a->row;
658   int        *r,*c,ierr,i, n = A->m,*vi,*ai = a->i,*aj = a->j;
659   int        nz,shift = a->indexshift,*rout,*cout;
660   Scalar     *x,*b,*tmp,*aa = a->a,sum,*v;
661 
662   PetscFunctionBegin;
663   if (yy != xx) {ierr = VecCopy(yy,xx);CHKERRQ(ierr);}
664 
665   ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
666   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
667   tmp  = a->solve_work;
668 
669   ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout;
670   ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout + (n-1);
671 
672   /* forward solve the lower triangular */
673   tmp[0] = b[*r++];
674   for (i=1; i<n; i++) {
675     v   = aa + ai[i] + shift;
676     vi  = aj + ai[i] + shift;
677     nz  = a->diag[i] - ai[i];
678     sum = b[*r++];
679     while (nz--) sum -= *v++ * tmp[*vi++ + shift];
680     tmp[i] = sum;
681   }
682 
683   /* backward solve the upper triangular */
684   for (i=n-1; i>=0; i--){
685     v   = aa + a->diag[i] + (!shift);
686     vi  = aj + a->diag[i] + (!shift);
687     nz  = ai[i+1] - a->diag[i] - 1;
688     sum = tmp[i];
689     while (nz--) sum -= *v++ * tmp[*vi++ + shift];
690     tmp[i] = sum*aa[a->diag[i]+shift];
691     x[*c--] += tmp[i];
692   }
693 
694   ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr);
695   ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr);
696   ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);
697   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
698   PetscLogFlops(2*a->nz);
699 
700   PetscFunctionReturn(0);
701 }
702 /* -------------------------------------------------------------------*/
703 #undef __FUNCT__
704 #define __FUNCT__ "MatSolveTranspose_SeqAIJ"
705 int MatSolveTranspose_SeqAIJ(Mat A,Vec bb,Vec xx)
706 {
707   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
708   IS         iscol = a->col,isrow = a->row;
709   int        *r,*c,ierr,i,n = A->m,*vi,*ai = a->i,*aj = a->j;
710   int        nz,shift = a->indexshift,*rout,*cout,*diag = a->diag;
711   Scalar     *x,*b,*tmp,*aa = a->a,*v,s1;
712 
713   PetscFunctionBegin;
714   ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
715   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
716   tmp  = a->solve_work;
717 
718   ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout;
719   ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout;
720 
721   /* copy the b into temp work space according to permutation */
722   for (i=0; i<n; i++) tmp[i] = b[c[i]];
723 
724   /* forward solve the U^T */
725   for (i=0; i<n; i++) {
726     v   = aa + diag[i] + shift;
727     vi  = aj + diag[i] + (!shift);
728     nz  = ai[i+1] - diag[i] - 1;
729     s1  = tmp[i];
730     s1 *= *(v++);  /* multiply by inverse of diagonal entry */
731     while (nz--) {
732       tmp[*vi++ + shift] -= (*v++)*s1;
733     }
734     tmp[i] = s1;
735   }
736 
737   /* backward solve the L^T */
738   for (i=n-1; i>=0; i--){
739     v   = aa + diag[i] - 1 + shift;
740     vi  = aj + diag[i] - 1 + shift;
741     nz  = diag[i] - ai[i];
742     s1  = tmp[i];
743     while (nz--) {
744       tmp[*vi-- + shift] -= (*v--)*s1;
745     }
746   }
747 
748   /* copy tmp into x according to permutation */
749   for (i=0; i<n; i++) x[r[i]] = tmp[i];
750 
751   ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr);
752   ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr);
753   ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);
754   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
755 
756   PetscLogFlops(2*a->nz-A->n);
757   PetscFunctionReturn(0);
758 }
759 
760 #undef __FUNCT__
761 #define __FUNCT__ "MatSolveTransposeAdd_SeqAIJ"
762 int MatSolveTransposeAdd_SeqAIJ(Mat A,Vec bb,Vec zz,Vec xx)
763 {
764   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data;
765   IS         iscol = a->col,isrow = a->row;
766   int        *r,*c,ierr,i,n = A->m,*vi,*ai = a->i,*aj = a->j;
767   int        nz,shift = a->indexshift,*rout,*cout,*diag = a->diag;
768   Scalar     *x,*b,*tmp,*aa = a->a,*v;
769 
770   PetscFunctionBegin;
771   if (zz != xx) VecCopy(zz,xx);
772 
773   ierr = VecGetArray(bb,&b);CHKERRQ(ierr);
774   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
775   tmp = a->solve_work;
776 
777   ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout;
778   ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout;
779 
780   /* copy the b into temp work space according to permutation */
781   for (i=0; i<n; i++) tmp[i] = b[c[i]];
782 
783   /* forward solve the U^T */
784   for (i=0; i<n; i++) {
785     v   = aa + diag[i] + shift;
786     vi  = aj + diag[i] + (!shift);
787     nz  = ai[i+1] - diag[i] - 1;
788     tmp[i] *= *v++;
789     while (nz--) {
790       tmp[*vi++ + shift] -= (*v++)*tmp[i];
791     }
792   }
793 
794   /* backward solve the L^T */
795   for (i=n-1; i>=0; i--){
796     v   = aa + diag[i] - 1 + shift;
797     vi  = aj + diag[i] - 1 + shift;
798     nz  = diag[i] - ai[i];
799     while (nz--) {
800       tmp[*vi-- + shift] -= (*v--)*tmp[i];
801     }
802   }
803 
804   /* copy tmp into x according to permutation */
805   for (i=0; i<n; i++) x[r[i]] += tmp[i];
806 
807   ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr);
808   ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr);
809   ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr);
810   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
811 
812   PetscLogFlops(2*a->nz);
813   PetscFunctionReturn(0);
814 }
815 /* ----------------------------------------------------------------*/
816 EXTERN int MatMissingDiagonal_SeqAIJ(Mat);
817 
818 #undef __FUNCT__
819 #define __FUNCT__ "MatILUFactorSymbolic_SeqAIJ"
820 int MatILUFactorSymbolic_SeqAIJ(Mat A,IS isrow,IS iscol,MatILUInfo *info,Mat *fact)
821 {
822   Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b;
823   IS         isicol;
824   int        *r,*ic,ierr,prow,n = A->m,*ai = a->i,*aj = a->j;
825   int        *ainew,*ajnew,jmax,*fill,*xi,nz,*im,*ajfill,*flev;
826   int        *dloc,idx,row,m,fm,nzf,nzi,len, realloc = 0,dcount = 0;
827   int        incrlev,nnz,i,shift = a->indexshift,levels,diagonal_fill;
828   PetscTruth col_identity,row_identity;
829   PetscReal  f;
830 
831   PetscFunctionBegin;
832   if (info) {
833     f             = info->fill;
834     levels        = (int)info->levels;
835     diagonal_fill = (int)info->diagonal_fill;
836   } else {
837     f             = 1.0;
838     levels        = 0;
839     diagonal_fill = 0;
840   }
841   ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr);
842 
843   /* special case that simply copies fill pattern */
844   ierr = ISIdentity(isrow,&row_identity);CHKERRQ(ierr);
845   ierr = ISIdentity(iscol,&col_identity);CHKERRQ(ierr);
846   if (!levels && row_identity && col_identity) {
847     ierr = MatDuplicate_SeqAIJ(A,MAT_DO_NOT_COPY_VALUES,fact);CHKERRQ(ierr);
848     (*fact)->factor = FACTOR_LU;
849     b               = (Mat_SeqAIJ*)(*fact)->data;
850     if (!b->diag) {
851       ierr = MatMarkDiagonal_SeqAIJ(*fact);CHKERRQ(ierr);
852     }
853     ierr = MatMissingDiagonal_SeqAIJ(*fact);CHKERRQ(ierr);
854     b->row              = isrow;
855     b->col              = iscol;
856     b->icol             = isicol;
857     if (info) {
858       b->lu_damp    = (PetscTruth)((int)info->damp);
859       b->lu_damping = info->damping;
860     } else {
861       b->lu_damp    = PETSC_FALSE;
862       b->lu_damping = 0.0;
863     }
864     ierr                = PetscMalloc(((*fact)->m+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
865     (*fact)->ops->solve = MatSolve_SeqAIJ_NaturalOrdering;
866     ierr                = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
867     ierr                = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
868     PetscFunctionReturn(0);
869   }
870 
871   ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr);
872   ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr);
873 
874   /* get new row pointers */
875   ierr = PetscMalloc((n+1)*sizeof(int),&ainew);CHKERRQ(ierr);
876   ainew[0] = -shift;
877   /* don't know how many column pointers are needed so estimate */
878   jmax = (int)(f*(ai[n]+!shift));
879   ierr = PetscMalloc((jmax)*sizeof(int),&ajnew);CHKERRQ(ierr);
880   /* ajfill is level of fill for each fill entry */
881   ierr = PetscMalloc((jmax)*sizeof(int),&ajfill);CHKERRQ(ierr);
882   /* fill is a linked list of nonzeros in active row */
883   ierr = PetscMalloc((n+1)*sizeof(int),&fill);CHKERRQ(ierr);
884   /* im is level for each filled value */
885   ierr = PetscMalloc((n+1)*sizeof(int),&im);CHKERRQ(ierr);
886   /* dloc is location of diagonal in factor */
887   ierr = PetscMalloc((n+1)*sizeof(int),&dloc);CHKERRQ(ierr);
888   dloc[0]  = 0;
889   for (prow=0; prow<n; prow++) {
890 
891     /* copy current row into linked list */
892     nzf     = nz  = ai[r[prow]+1] - ai[r[prow]];
893     if (!nz) SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,"Empty row in matrix");
894     xi      = aj + ai[r[prow]] + shift;
895     fill[n]    = n;
896     fill[prow] = -1; /* marker to indicate if diagonal exists */
897     while (nz--) {
898       fm  = n;
899       idx = ic[*xi++ + shift];
900       do {
901         m  = fm;
902         fm = fill[m];
903       } while (fm < idx);
904       fill[m]   = idx;
905       fill[idx] = fm;
906       im[idx]   = 0;
907     }
908 
909     /* make sure diagonal entry is included */
910     if (diagonal_fill && fill[prow] == -1) {
911       fm = n;
912       while (fill[fm] < prow) fm = fill[fm];
913       fill[prow] = fill[fm]; /* insert diagonal into linked list */
914       fill[fm]   = prow;
915       im[prow]   = 0;
916       nzf++;
917       dcount++;
918     }
919 
920     nzi = 0;
921     row = fill[n];
922     while (row < prow) {
923       incrlev = im[row] + 1;
924       nz      = dloc[row];
925       xi      = ajnew  + ainew[row] + shift + nz + 1;
926       flev    = ajfill + ainew[row] + shift + nz + 1;
927       nnz     = ainew[row+1] - ainew[row] - nz - 1;
928       fm      = row;
929       while (nnz-- > 0) {
930         idx = *xi++ + shift;
931         if (*flev + incrlev > levels) {
932           flev++;
933           continue;
934         }
935         do {
936           m  = fm;
937           fm = fill[m];
938         } while (fm < idx);
939         if (fm != idx) {
940           im[idx]   = *flev + incrlev;
941           fill[m]   = idx;
942           fill[idx] = fm;
943           fm        = idx;
944           nzf++;
945         } else {
946           if (im[idx] > *flev + incrlev) im[idx] = *flev+incrlev;
947         }
948         flev++;
949       }
950       row = fill[row];
951       nzi++;
952     }
953     /* copy new filled row into permanent storage */
954     ainew[prow+1] = ainew[prow] + nzf;
955     if (ainew[prow+1] > jmax-shift) {
956 
957       /* estimate how much additional space we will need */
958       /* use the strategy suggested by David Hysom <hysom@perch-t.icase.edu> */
959       /* just double the memory each time */
960       /*  maxadd = (int)((f*(ai[n]+!shift)*(n-prow+5))/n); */
961       int maxadd = jmax;
962       if (maxadd < nzf) maxadd = (n-prow)*(nzf+1);
963       jmax += maxadd;
964 
965       /* allocate a longer ajnew and ajfill */
966       ierr   = PetscMalloc(jmax*sizeof(int),&xi);CHKERRQ(ierr);
967       ierr   = PetscMemcpy(xi,ajnew,(ainew[prow]+shift)*sizeof(int));CHKERRQ(ierr);
968       ierr   = PetscFree(ajnew);CHKERRQ(ierr);
969       ajnew  = xi;
970       ierr   = PetscMalloc(jmax*sizeof(int),&xi);CHKERRQ(ierr);
971       ierr   = PetscMemcpy(xi,ajfill,(ainew[prow]+shift)*sizeof(int));CHKERRQ(ierr);
972       ierr   = PetscFree(ajfill);CHKERRQ(ierr);
973       ajfill = xi;
974       realloc++; /* count how many times we realloc */
975     }
976     xi          = ajnew + ainew[prow] + shift;
977     flev        = ajfill + ainew[prow] + shift;
978     dloc[prow]  = nzi;
979     fm          = fill[n];
980     while (nzf--) {
981       *xi++   = fm - shift;
982       *flev++ = im[fm];
983       fm      = fill[fm];
984     }
985     /* make sure row has diagonal entry */
986     if (ajnew[ainew[prow]+shift+dloc[prow]]+shift != prow) {
987       SETERRQ1(PETSC_ERR_MAT_LU_ZRPVT,"Row %d has missing diagonal in factored matrix\n\
988     try running with -pc_ilu_nonzeros_along_diagonal or -pc_ilu_diagonal_fill",prow);
989     }
990   }
991   ierr = PetscFree(ajfill);CHKERRQ(ierr);
992   ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr);
993   ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr);
994   ierr = PetscFree(fill);CHKERRQ(ierr);
995   ierr = PetscFree(im);CHKERRQ(ierr);
996 
997   {
998     PetscReal af = ((PetscReal)ainew[n])/((PetscReal)ai[n]);
999     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Reallocs %d Fill ratio:given %g needed %g\n",realloc,f,af);
1000     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Run with -pc_ilu_fill %g or use \n",af);
1001     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:PCILUSetFill(pc,%g);\n",af);
1002     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:for best performance.\n");
1003     if (diagonal_fill) {
1004       PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Detected and replace %d missing diagonals",dcount);
1005     }
1006   }
1007 
1008   /* put together the new matrix */
1009   ierr = MatCreateSeqAIJ(A->comm,n,n,0,PETSC_NULL,fact);CHKERRQ(ierr);
1010   PetscLogObjectParent(*fact,isicol);
1011   b = (Mat_SeqAIJ*)(*fact)->data;
1012   ierr = PetscFree(b->imax);CHKERRQ(ierr);
1013   b->singlemalloc = PETSC_FALSE;
1014   len = (ainew[n] + shift)*sizeof(Scalar);
1015   /* the next line frees the default space generated by the Create() */
1016   ierr = PetscFree(b->a);CHKERRQ(ierr);
1017   ierr = PetscFree(b->ilen);CHKERRQ(ierr);
1018   ierr = PetscMalloc(len+1,&b->a);CHKERRQ(ierr);
1019   b->j          = ajnew;
1020   b->i          = ainew;
1021   for (i=0; i<n; i++) dloc[i] += ainew[i];
1022   b->diag       = dloc;
1023   b->ilen       = 0;
1024   b->imax       = 0;
1025   b->row        = isrow;
1026   b->col        = iscol;
1027   ierr          = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
1028   ierr          = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
1029   b->icol       = isicol;
1030   ierr = PetscMalloc((n+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
1031   /* In b structure:  Free imax, ilen, old a, old j.
1032      Allocate dloc, solve_work, new a, new j */
1033   PetscLogObjectMemory(*fact,(ainew[n]+shift-n) * (sizeof(int)+sizeof(Scalar)));
1034   b->maxnz          = b->nz = ainew[n] + shift;
1035   if (info) {
1036     b->lu_damp    = (PetscTruth)((int)info->damp);
1037     b->lu_damping = info->damping;
1038   } else {
1039     b->lu_damp    = PETSC_FALSE;
1040     b->lu_damping = 0.0;
1041   }
1042   (*fact)->factor   = FACTOR_LU;
1043 
1044   (*fact)->info.factor_mallocs    = realloc;
1045   (*fact)->info.fill_ratio_given  = f;
1046   (*fact)->info.fill_ratio_needed = ((PetscReal)ainew[n])/((PetscReal)ai[prow]);
1047   (*fact)->factor                 =  FACTOR_LU;
1048 
1049   PetscFunctionReturn(0);
1050 }
1051 
1052 
1053 
1054 
1055