xref: /petsc/src/mat/impls/aij/seq/aijfact.c (revision b0a32e0c6855ee6a6cd3495fa7da12ea9885bc5d)
1 /*$Id: aijfact.c,v 1.157 2000/10/24 20:25:32 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 __FUNC__
8 #define __FUNC__ "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 __FUNC__
28 #define __FUNC__ "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 __FUNC__
267 #define __FUNC__ /*<a name="MatLUFactorSymbolic_SeqAIJ""></a>*/"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 __FUNC__
440 #define __FUNC__ "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 __FUNC__
534 #define __FUNC__ "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 __FUNC__
548 #define __FUNC__ "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 __FUNC__
599 #define __FUNC__ "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 __FUNC__
653 #define __FUNC__ "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 __FUNC__
704 #define __FUNC__ "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 __FUNC__
761 #define __FUNC__ "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 __FUNC__
819 #define __FUNC__ "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   if (!isrow) {
842     ierr = ISCreateStride(PETSC_COMM_SELF,A->M,0,1,&isrow);CHKERRQ(ierr);
843   }
844   if (!iscol) {
845     ierr = ISCreateStride(PETSC_COMM_SELF,A->M,0,1,&iscol);CHKERRQ(ierr);
846   }
847 
848   ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr);
849 
850   /* special case that simply copies fill pattern */
851   ierr = ISIdentity(isrow,&row_identity);CHKERRQ(ierr);
852   ierr = ISIdentity(iscol,&col_identity);CHKERRQ(ierr);
853   if (!levels && row_identity && col_identity) {
854     ierr = MatDuplicate_SeqAIJ(A,MAT_DO_NOT_COPY_VALUES,fact);CHKERRQ(ierr);
855     (*fact)->factor = FACTOR_LU;
856     b               = (Mat_SeqAIJ*)(*fact)->data;
857     if (!b->diag) {
858       ierr = MatMarkDiagonal_SeqAIJ(*fact);CHKERRQ(ierr);
859     }
860     ierr = MatMissingDiagonal_SeqAIJ(*fact);CHKERRQ(ierr);
861     b->row              = isrow;
862     b->col              = iscol;
863     b->icol             = isicol;
864     if (info) {
865       b->lu_damp    = (PetscTruth)((int)info->damp);
866       b->lu_damping = info->damping;
867     } else {
868       b->lu_damp    = PETSC_FALSE;
869       b->lu_damping = 0.0;
870     }
871     ierr                = PetscMalloc(((*fact)->m+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
872     (*fact)->ops->solve = MatSolve_SeqAIJ_NaturalOrdering;
873     ierr                = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
874     ierr                = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
875     PetscFunctionReturn(0);
876   }
877 
878   ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr);
879   ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr);
880 
881   /* get new row pointers */
882   ierr = PetscMalloc((n+1)*sizeof(int),&ainew);CHKERRQ(ierr);
883   ainew[0] = -shift;
884   /* don't know how many column pointers are needed so estimate */
885   jmax = (int)(f*(ai[n]+!shift));
886   ierr = PetscMalloc((jmax)*sizeof(int),&ajnew);CHKERRQ(ierr);
887   /* ajfill is level of fill for each fill entry */
888   ierr = PetscMalloc((jmax)*sizeof(int),&ajfill);CHKERRQ(ierr);
889   /* fill is a linked list of nonzeros in active row */
890   ierr = PetscMalloc((n+1)*sizeof(int),&fill);CHKERRQ(ierr);
891   /* im is level for each filled value */
892   ierr = PetscMalloc((n+1)*sizeof(int),&im);CHKERRQ(ierr);
893   /* dloc is location of diagonal in factor */
894   ierr = PetscMalloc((n+1)*sizeof(int),&dloc);CHKERRQ(ierr);
895   dloc[0]  = 0;
896   for (prow=0; prow<n; prow++) {
897 
898     /* copy current row into linked list */
899     nzf     = nz  = ai[r[prow]+1] - ai[r[prow]];
900     if (!nz) SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,"Empty row in matrix");
901     xi      = aj + ai[r[prow]] + shift;
902     fill[n]    = n;
903     fill[prow] = -1; /* marker to indicate if diagonal exists */
904     while (nz--) {
905       fm  = n;
906       idx = ic[*xi++ + shift];
907       do {
908         m  = fm;
909         fm = fill[m];
910       } while (fm < idx);
911       fill[m]   = idx;
912       fill[idx] = fm;
913       im[idx]   = 0;
914     }
915 
916     /* make sure diagonal entry is included */
917     if (diagonal_fill && fill[prow] == -1) {
918       fm = n;
919       while (fill[fm] < prow) fm = fill[fm];
920       fill[prow] = fill[fm]; /* insert diagonal into linked list */
921       fill[fm]   = prow;
922       im[prow]   = 0;
923       nzf++;
924       dcount++;
925     }
926 
927     nzi = 0;
928     row = fill[n];
929     while (row < prow) {
930       incrlev = im[row] + 1;
931       nz      = dloc[row];
932       xi      = ajnew  + ainew[row] + shift + nz + 1;
933       flev    = ajfill + ainew[row] + shift + nz + 1;
934       nnz     = ainew[row+1] - ainew[row] - nz - 1;
935       fm      = row;
936       while (nnz-- > 0) {
937         idx = *xi++ + shift;
938         if (*flev + incrlev > levels) {
939           flev++;
940           continue;
941         }
942         do {
943           m  = fm;
944           fm = fill[m];
945         } while (fm < idx);
946         if (fm != idx) {
947           im[idx]   = *flev + incrlev;
948           fill[m]   = idx;
949           fill[idx] = fm;
950           fm        = idx;
951           nzf++;
952         } else {
953           if (im[idx] > *flev + incrlev) im[idx] = *flev+incrlev;
954         }
955         flev++;
956       }
957       row = fill[row];
958       nzi++;
959     }
960     /* copy new filled row into permanent storage */
961     ainew[prow+1] = ainew[prow] + nzf;
962     if (ainew[prow+1] > jmax-shift) {
963 
964       /* estimate how much additional space we will need */
965       /* use the strategy suggested by David Hysom <hysom@perch-t.icase.edu> */
966       /* just double the memory each time */
967       /*  maxadd = (int)((f*(ai[n]+!shift)*(n-prow+5))/n); */
968       int maxadd = jmax;
969       if (maxadd < nzf) maxadd = (n-prow)*(nzf+1);
970       jmax += maxadd;
971 
972       /* allocate a longer ajnew and ajfill */
973       ierr   = PetscMalloc(jmax*sizeof(int),&xi);CHKERRQ(ierr);
974       ierr   = PetscMemcpy(xi,ajnew,(ainew[prow]+shift)*sizeof(int));CHKERRQ(ierr);
975       ierr   = PetscFree(ajnew);CHKERRQ(ierr);
976       ajnew  = xi;
977       ierr   = PetscMalloc(jmax*sizeof(int),&xi);CHKERRQ(ierr);
978       ierr   = PetscMemcpy(xi,ajfill,(ainew[prow]+shift)*sizeof(int));CHKERRQ(ierr);
979       ierr   = PetscFree(ajfill);CHKERRQ(ierr);
980       ajfill = xi;
981       realloc++; /* count how many times we realloc */
982     }
983     xi          = ajnew + ainew[prow] + shift;
984     flev        = ajfill + ainew[prow] + shift;
985     dloc[prow]  = nzi;
986     fm          = fill[n];
987     while (nzf--) {
988       *xi++   = fm - shift;
989       *flev++ = im[fm];
990       fm      = fill[fm];
991     }
992     /* make sure row has diagonal entry */
993     if (ajnew[ainew[prow]+shift+dloc[prow]]+shift != prow) {
994       SETERRQ1(PETSC_ERR_MAT_LU_ZRPVT,"Row %d has missing diagonal in factored matrix\n\
995     try running with -pc_ilu_nonzeros_along_diagonal or -pc_ilu_diagonal_fill",prow);
996     }
997   }
998   ierr = PetscFree(ajfill);CHKERRQ(ierr);
999   ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr);
1000   ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr);
1001   ierr = PetscFree(fill);CHKERRQ(ierr);
1002   ierr = PetscFree(im);CHKERRQ(ierr);
1003 
1004   {
1005     PetscReal af = ((PetscReal)ainew[n])/((PetscReal)ai[n]);
1006     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Reallocs %d Fill ratio:given %g needed %g\n",realloc,f,af);
1007     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Run with -pc_ilu_fill %g or use \n",af);
1008     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:PCILUSetFill(pc,%g);\n",af);
1009     PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:for best performance.\n");
1010     if (diagonal_fill) {
1011       PetscLogInfo(A,"MatILUFactorSymbolic_SeqAIJ:Detected and replace %d missing diagonals",dcount);
1012     }
1013   }
1014 
1015   /* put together the new matrix */
1016   ierr = MatCreateSeqAIJ(A->comm,n,n,0,PETSC_NULL,fact);CHKERRQ(ierr);
1017   PetscLogObjectParent(*fact,isicol);
1018   b = (Mat_SeqAIJ*)(*fact)->data;
1019   ierr = PetscFree(b->imax);CHKERRQ(ierr);
1020   b->singlemalloc = PETSC_FALSE;
1021   len = (ainew[n] + shift)*sizeof(Scalar);
1022   /* the next line frees the default space generated by the Create() */
1023   ierr = PetscFree(b->a);CHKERRQ(ierr);
1024   ierr = PetscFree(b->ilen);CHKERRQ(ierr);
1025   ierr = PetscMalloc(len+1,&b->a);CHKERRQ(ierr);
1026   b->j          = ajnew;
1027   b->i          = ainew;
1028   for (i=0; i<n; i++) dloc[i] += ainew[i];
1029   b->diag       = dloc;
1030   b->ilen       = 0;
1031   b->imax       = 0;
1032   b->row        = isrow;
1033   b->col        = iscol;
1034   ierr          = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr);
1035   ierr          = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr);
1036   b->icol       = isicol;
1037   ierr = PetscMalloc((n+1)*sizeof(Scalar),&b->solve_work);CHKERRQ(ierr);
1038   /* In b structure:  Free imax, ilen, old a, old j.
1039      Allocate dloc, solve_work, new a, new j */
1040   PetscLogObjectMemory(*fact,(ainew[n]+shift-n) * (sizeof(int)+sizeof(Scalar)));
1041   b->maxnz          = b->nz = ainew[n] + shift;
1042   if (info) {
1043     b->lu_damp    = (PetscTruth)((int)info->damp);
1044     b->lu_damping = info->damping;
1045   } else {
1046     b->lu_damp    = PETSC_FALSE;
1047     b->lu_damping = 0.0;
1048   }
1049   (*fact)->factor   = FACTOR_LU;
1050 
1051   (*fact)->info.factor_mallocs    = realloc;
1052   (*fact)->info.fill_ratio_given  = f;
1053   (*fact)->info.fill_ratio_needed = ((PetscReal)ainew[n])/((PetscReal)ai[prow]);
1054   (*fact)->factor                 =  FACTOR_LU;
1055 
1056   PetscFunctionReturn(0);
1057 }
1058 
1059 
1060 
1061 
1062