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