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