xref: /petsc/src/mat/impls/aij/seq/bas/spbas_cholesky.h (revision 580bdb303e1ee3b1222b2042810b4c26340259c6)
1b2f1ab58SBarry Smith 
2b2f1ab58SBarry Smith /*
3b2f1ab58SBarry Smith    spbas_cholesky_row_alloc:
4b2f1ab58SBarry Smith       in the data arrays, find a place where another row may be stored.
5b2f1ab58SBarry Smith       Return PETSC_ERR_MEM if there is insufficient space to store the
6b2f1ab58SBarry Smith       row, so garbage collection and/or re-allocation may be done.
7b2f1ab58SBarry Smith */
8b2f1ab58SBarry Smith PetscErrorCode spbas_cholesky_row_alloc(spbas_matrix retval, PetscInt k, PetscInt r_nnz,PetscInt * n_alloc_used)
9b2f1ab58SBarry Smith {
10b2f1ab58SBarry Smith   PetscFunctionBegin;
11b2f1ab58SBarry Smith   retval.icols[k]  = &retval.alloc_icol[*n_alloc_used];
12b2f1ab58SBarry Smith   retval.values[k] = &retval.alloc_val[*n_alloc_used];
13b2f1ab58SBarry Smith   *n_alloc_used   += r_nnz;
149ccc4a9bSBarry Smith   if (*n_alloc_used > retval.n_alloc_icol) PetscFunctionReturn(PETSC_ERR_MEM);
15b2f1ab58SBarry Smith   PetscFunctionReturn(0);
16b2f1ab58SBarry Smith }
17b2f1ab58SBarry Smith 
18b2f1ab58SBarry Smith 
19b2f1ab58SBarry Smith /*
20b2f1ab58SBarry Smith   spbas_cholesky_garbage_collect:
21b2f1ab58SBarry Smith      move the rows which have been calculated so far, as well as
22b2f1ab58SBarry Smith      those currently under construction, to the front of the
23b2f1ab58SBarry Smith      array, while putting them in the proper order.
24b2f1ab58SBarry Smith      When it seems necessary, enlarge the current arrays.
25b2f1ab58SBarry Smith 
26b2f1ab58SBarry Smith      NB: re-allocation is being simulated using
27b2f1ab58SBarry Smith          PetscMalloc, memcpy, PetscFree, because
28b2f1ab58SBarry Smith          PetscRealloc does not seem to exist.
29b2f1ab58SBarry Smith 
30b2f1ab58SBarry Smith */
31be332245SKarl Rupp PetscErrorCode spbas_cholesky_garbage_collect(spbas_matrix *result,         /* I/O: the Cholesky factor matrix being constructed.
322205254eSKarl Rupp                                                                                     Only the storage, not the contents of this matrix is changed in this function */
33be332245SKarl Rupp                                               PetscInt     i_row,           /* I  : Number of rows for which the final contents are known */
34c328eeadSBarry Smith                                               PetscInt     *n_row_alloc_ok, /* I/O: Number of rows which are already in their final
35c328eeadSBarry Smith                                                                                     places in the arrays: they need not be moved any more */
36c328eeadSBarry Smith                                               PetscInt     *n_alloc_used,   /* I/O:  */
37be332245SKarl Rupp                                               PetscInt     *max_row_nnz)    /* I  : Over-estimate of the number of nonzeros needed to store each row */
38b2f1ab58SBarry Smith {
39c328eeadSBarry Smith /* PSEUDO-CODE:
40c328eeadSBarry Smith   1. Choose the appropriate size for the arrays
41c328eeadSBarry Smith   2. Rescue the arrays which would be lost during garbage collection
42c328eeadSBarry Smith   3. Reallocate and correct administration
43c328eeadSBarry Smith   4. Move all arrays so that they are in proper order */
44b2f1ab58SBarry Smith 
45b2f1ab58SBarry Smith   PetscInt        i,j;
46b2f1ab58SBarry Smith   PetscInt        nrows         = result->nrows;
47b2f1ab58SBarry Smith   PetscInt        n_alloc_ok    =0;
48b2f1ab58SBarry Smith   PetscInt        n_alloc_ok_max=0;
49b2f1ab58SBarry Smith   PetscErrorCode  ierr;
50b2f1ab58SBarry Smith   PetscInt        need_already  = 0;
51b2f1ab58SBarry Smith   PetscInt        n_rows_ahead  =0;
52b2f1ab58SBarry Smith   PetscInt        max_need_extra= 0;
53b2f1ab58SBarry Smith   PetscInt        n_alloc_max, n_alloc_est, n_alloc;
54b2f1ab58SBarry Smith   PetscInt        n_alloc_now     = result->n_alloc_icol;
55b2f1ab58SBarry Smith   PetscInt        *alloc_icol_old = result->alloc_icol;
56b2f1ab58SBarry Smith   PetscScalar     *alloc_val_old  = result->alloc_val;
57b2f1ab58SBarry Smith   PetscInt        *icol_rescue;
58b2f1ab58SBarry Smith   PetscScalar     *val_rescue;
59b2f1ab58SBarry Smith   PetscInt        n_rescue;
60b2f1ab58SBarry Smith   PetscInt        n_row_rescue;
61b2f1ab58SBarry Smith   PetscInt        i_here, i_last, n_copy;
62d36aa34eSBarry Smith   const PetscReal xtra_perc = 20;
63b2f1ab58SBarry Smith 
64b2f1ab58SBarry Smith   PetscFunctionBegin;
65c328eeadSBarry Smith   /*********************************************************
66c328eeadSBarry Smith   1. Choose appropriate array size
67c328eeadSBarry Smith   Count number of rows and memory usage which is already final */
689ccc4a9bSBarry Smith   for (i=0; i<i_row; i++)  {
69b2f1ab58SBarry Smith     n_alloc_ok     += result->row_nnz[i];
70b2f1ab58SBarry Smith     n_alloc_ok_max += max_row_nnz[i];
71b2f1ab58SBarry Smith   }
72b2f1ab58SBarry Smith 
73c328eeadSBarry Smith   /* Count currently needed memory usage and future memory requirements
74c328eeadSBarry Smith     (max, predicted)*/
759ccc4a9bSBarry Smith   for (i=i_row; i<nrows; i++) {
769ccc4a9bSBarry Smith     if (!result->row_nnz[i]) {
77b2f1ab58SBarry Smith       max_need_extra += max_row_nnz[i];
789ccc4a9bSBarry Smith     } else {
79b2f1ab58SBarry Smith       need_already += max_row_nnz[i];
80b2f1ab58SBarry Smith       n_rows_ahead++;
81b2f1ab58SBarry Smith     }
82b2f1ab58SBarry Smith   }
83b2f1ab58SBarry Smith 
84c328eeadSBarry Smith   /* Make maximal and realistic memory requirement estimates */
85b2f1ab58SBarry Smith   n_alloc_max = n_alloc_ok + need_already + max_need_extra;
869ccc4a9bSBarry Smith   n_alloc_est = n_alloc_ok + need_already + (int) (((PetscReal) max_need_extra) *  ((PetscReal) n_alloc_ok) /((PetscReal) n_alloc_ok_max));
87b2f1ab58SBarry Smith 
88c328eeadSBarry Smith   /* Choose array sizes */
892205254eSKarl Rupp   if (n_alloc_max == n_alloc_est) n_alloc = n_alloc_max;
902205254eSKarl Rupp   else if (n_alloc_now >= n_alloc_est) n_alloc = n_alloc_now;
912205254eSKarl Rupp   else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0)) n_alloc = n_alloc_max;
922205254eSKarl Rupp   else n_alloc = (int) (n_alloc_est * (1+xtra_perc/100.0));
93b2f1ab58SBarry Smith 
94c328eeadSBarry Smith   /* If new estimate is less than what we already have,
95c328eeadSBarry Smith     don't reallocate, just garbage-collect */
969ccc4a9bSBarry Smith   if (n_alloc_max != n_alloc_est && n_alloc < result->n_alloc_icol) {
97b2f1ab58SBarry Smith     n_alloc = result->n_alloc_icol;
98b2f1ab58SBarry Smith   }
99b2f1ab58SBarry Smith 
100c328eeadSBarry Smith   /* Motivate dimension choice */
1010298fd71SBarry Smith   ierr = PetscInfo1(NULL,"   Allocating %d nonzeros: ",n_alloc);CHKERRQ(ierr);
1022205254eSKarl Rupp   if (n_alloc_max == n_alloc_est) {
1030298fd71SBarry Smith     ierr = PetscInfo(NULL,"this is the correct size\n");CHKERRQ(ierr);
1042205254eSKarl Rupp   } else if (n_alloc_now >= n_alloc_est) {
1050298fd71SBarry Smith     ierr = PetscInfo(NULL,"the current size, which seems enough\n");CHKERRQ(ierr);
1062205254eSKarl Rupp   } else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0)) {
1070298fd71SBarry Smith     ierr = PetscInfo(NULL,"the maximum estimate\n");CHKERRQ(ierr);
1082205254eSKarl Rupp   } else {
1090298fd71SBarry Smith     ierr = PetscInfo1(NULL,"%6.2f %% more than the estimate\n",xtra_perc);CHKERRQ(ierr);
1102205254eSKarl Rupp   }
111b2f1ab58SBarry Smith 
112b2f1ab58SBarry Smith 
113c328eeadSBarry Smith   /**********************************************************
114c328eeadSBarry Smith   2. Rescue arrays which would be lost
115c328eeadSBarry Smith   Count how many rows and nonzeros will have to be rescued
116c328eeadSBarry Smith   when moving all arrays in place */
117b2f1ab58SBarry Smith   n_row_rescue = 0; n_rescue = 0;
1182205254eSKarl Rupp   if (*n_row_alloc_ok==0) *n_alloc_used = 0;
1199ccc4a9bSBarry Smith   else {
120b2f1ab58SBarry Smith     i = *n_row_alloc_ok - 1;
1212205254eSKarl Rupp 
1229ccc4a9bSBarry Smith     *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
123b2f1ab58SBarry Smith   }
124b2f1ab58SBarry Smith 
1259ccc4a9bSBarry Smith   for (i=*n_row_alloc_ok; i<nrows; i++) {
126b2f1ab58SBarry Smith     i_here = result->icols[i]-result->alloc_icol;
127b2f1ab58SBarry Smith     i_last = i_here + result->row_nnz[i];
1289ccc4a9bSBarry Smith     if (result->row_nnz[i]>0) {
1299ccc4a9bSBarry Smith       if (*n_alloc_used > i_here || i_last > n_alloc) {
130b2f1ab58SBarry Smith         n_rescue += result->row_nnz[i];
131b2f1ab58SBarry Smith         n_row_rescue++;
132b2f1ab58SBarry Smith       }
133b2f1ab58SBarry Smith 
1342205254eSKarl Rupp       if (i<i_row) *n_alloc_used += result->row_nnz[i];
1352205254eSKarl Rupp       else         *n_alloc_used += max_row_nnz[i];
136b2f1ab58SBarry Smith     }
137b2f1ab58SBarry Smith   }
138b2f1ab58SBarry Smith 
139c328eeadSBarry Smith   /* Allocate rescue arrays */
140785e854fSJed Brown   ierr = PetscMalloc1(n_rescue, &icol_rescue);CHKERRQ(ierr);
141785e854fSJed Brown   ierr = PetscMalloc1(n_rescue, &val_rescue);CHKERRQ(ierr);
142b2f1ab58SBarry Smith 
143c328eeadSBarry Smith   /* Rescue the arrays which need rescuing */
144b2f1ab58SBarry Smith   n_row_rescue = 0; n_rescue = 0;
1452205254eSKarl Rupp   if (*n_row_alloc_ok==0) *n_alloc_used = 0;
1469ccc4a9bSBarry Smith   else {
147b2f1ab58SBarry Smith     i             = *n_row_alloc_ok - 1;
1489ccc4a9bSBarry Smith     *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
149b2f1ab58SBarry Smith   }
150b2f1ab58SBarry Smith 
1519ccc4a9bSBarry Smith   for (i=*n_row_alloc_ok; i<nrows; i++) {
152b2f1ab58SBarry Smith     i_here = result->icols[i]-result->alloc_icol;
153b2f1ab58SBarry Smith     i_last = i_here + result->row_nnz[i];
1549ccc4a9bSBarry Smith     if (result->row_nnz[i]>0) {
1554e1ff37aSBarry Smith       if (*n_alloc_used > i_here || i_last > n_alloc) {
156*580bdb30SBarry Smith         ierr = PetscArraycpy(&icol_rescue[n_rescue], result->icols[i], result->row_nnz[i]);CHKERRQ(ierr);
157*580bdb30SBarry Smith         ierr = PetscArraycpy(&val_rescue[n_rescue], result->values[i], result->row_nnz[i]);CHKERRQ(ierr);
158b2f1ab58SBarry Smith         n_rescue += result->row_nnz[i];
159b2f1ab58SBarry Smith         n_row_rescue++;
160b2f1ab58SBarry Smith       }
161b2f1ab58SBarry Smith 
1622205254eSKarl Rupp       if (i<i_row) *n_alloc_used += result->row_nnz[i];
1632205254eSKarl Rupp       else         *n_alloc_used += max_row_nnz[i];
164b2f1ab58SBarry Smith     }
165b2f1ab58SBarry Smith   }
166b2f1ab58SBarry Smith 
167c328eeadSBarry Smith   /**********************************************************
168c328eeadSBarry Smith   3. Reallocate and correct administration */
169b2f1ab58SBarry Smith 
1709ccc4a9bSBarry Smith   if (n_alloc != result->n_alloc_icol) {
171cc6fc633SBarry Smith     n_copy = PetscMin(n_alloc,result->n_alloc_icol);
172b2f1ab58SBarry Smith 
173c328eeadSBarry Smith     /* PETSC knows no REALLOC, so we'll REALLOC ourselves.
174b2f1ab58SBarry Smith 
175c328eeadSBarry Smith         Allocate new icol-data, copy old contents */
176785e854fSJed Brown     ierr = PetscMalloc1(n_alloc, &result->alloc_icol);CHKERRQ(ierr);
177*580bdb30SBarry Smith     ierr = PetscArraycpy(result->alloc_icol, alloc_icol_old, n_copy);CHKERRQ(ierr);
178b2f1ab58SBarry Smith 
179c328eeadSBarry Smith     /* Update administration, Reset pointers to new arrays  */
180b2f1ab58SBarry Smith     result->n_alloc_icol = n_alloc;
1819ccc4a9bSBarry Smith     for (i=0; i<nrows; i++) {
1829ccc4a9bSBarry Smith       result->icols[i]  =  result->alloc_icol + (result->icols[i]  - alloc_icol_old);
1839ccc4a9bSBarry Smith       result->values[i] =  result->alloc_val  + (result->icols[i]  - result->alloc_icol);
184b2f1ab58SBarry Smith     }
185b2f1ab58SBarry Smith 
186c328eeadSBarry Smith     /* Delete old array */
187b2f1ab58SBarry Smith     ierr = PetscFree(alloc_icol_old);CHKERRQ(ierr);
188b2f1ab58SBarry Smith 
189c328eeadSBarry Smith     /* Allocate new value-data, copy old contents */
190785e854fSJed Brown     ierr = PetscMalloc1(n_alloc, &result->alloc_val);CHKERRQ(ierr);
191*580bdb30SBarry Smith     ierr = PetscArraycpy(result->alloc_val, alloc_val_old, n_copy);CHKERRQ(ierr);
192b2f1ab58SBarry Smith 
193c328eeadSBarry Smith     /* Update administration, Reset pointers to new arrays  */
194b2f1ab58SBarry Smith     result->n_alloc_val = n_alloc;
1959ccc4a9bSBarry Smith     for (i=0; i<nrows; i++) {
1969ccc4a9bSBarry Smith       result->values[i] =  result->alloc_val + (result->icols[i]  - result->alloc_icol);
197b2f1ab58SBarry Smith     }
198b2f1ab58SBarry Smith 
199c328eeadSBarry Smith     /* Delete old array */
200b2f1ab58SBarry Smith     ierr = PetscFree(alloc_val_old);CHKERRQ(ierr);
201b2f1ab58SBarry Smith   }
202b2f1ab58SBarry Smith 
203b2f1ab58SBarry Smith 
204c328eeadSBarry Smith   /*********************************************************
205c328eeadSBarry Smith   4. Copy all the arrays to their proper places */
206b2f1ab58SBarry Smith   n_row_rescue = 0; n_rescue = 0;
2072205254eSKarl Rupp   if (*n_row_alloc_ok==0) *n_alloc_used = 0;
2089ccc4a9bSBarry Smith   else {
209b2f1ab58SBarry Smith     i = *n_row_alloc_ok - 1;
2102205254eSKarl Rupp 
2119ccc4a9bSBarry Smith     *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
212b2f1ab58SBarry Smith   }
213b2f1ab58SBarry Smith 
2149ccc4a9bSBarry Smith   for (i=*n_row_alloc_ok; i<nrows; i++) {
215b2f1ab58SBarry Smith     i_here = result->icols[i]-result->alloc_icol;
216b2f1ab58SBarry Smith     i_last = i_here + result->row_nnz[i];
217b2f1ab58SBarry Smith 
218b2f1ab58SBarry Smith     result->icols[i] = result->alloc_icol + *n_alloc_used;
219b2f1ab58SBarry Smith     result->values[i]= result->alloc_val  + *n_alloc_used;
220b2f1ab58SBarry Smith 
2219ccc4a9bSBarry Smith     if (result->row_nnz[i]>0) {
2229ccc4a9bSBarry Smith       if (*n_alloc_used > i_here || i_last > n_alloc) {
223*580bdb30SBarry Smith         ierr = PetscArraycpy(result->icols[i], &icol_rescue[n_rescue], result->row_nnz[i]);CHKERRQ(ierr);
224*580bdb30SBarry Smith         ierr = PetscArraycpy(result->values[i],&val_rescue[n_rescue],result->row_nnz[i]);CHKERRQ(ierr);
2252205254eSKarl Rupp 
226b2f1ab58SBarry Smith         n_rescue += result->row_nnz[i];
227b2f1ab58SBarry Smith         n_row_rescue++;
2289ccc4a9bSBarry Smith       } else {
2299ccc4a9bSBarry Smith         for (j=0; j<result->row_nnz[i]; j++) {
230b2f1ab58SBarry Smith           result->icols[i][j]  = result->alloc_icol[i_here+j];
231b2f1ab58SBarry Smith           result->values[i][j] = result->alloc_val[i_here+j];
232b2f1ab58SBarry Smith         }
233b2f1ab58SBarry Smith       }
2342205254eSKarl Rupp       if (i<i_row) *n_alloc_used += result->row_nnz[i];
2352205254eSKarl Rupp       else         *n_alloc_used += max_row_nnz[i];
236b2f1ab58SBarry Smith     }
237b2f1ab58SBarry Smith   }
238b2f1ab58SBarry Smith 
239c328eeadSBarry Smith   /* Delete the rescue arrays */
240b2f1ab58SBarry Smith   ierr = PetscFree(icol_rescue);CHKERRQ(ierr);
241b2f1ab58SBarry Smith   ierr = PetscFree(val_rescue);CHKERRQ(ierr);
2422205254eSKarl Rupp 
243b2f1ab58SBarry Smith   *n_row_alloc_ok = i_row;
244b2f1ab58SBarry Smith   PetscFunctionReturn(0);
245b2f1ab58SBarry Smith }
246b2f1ab58SBarry Smith 
247b2f1ab58SBarry Smith /*
248b2f1ab58SBarry Smith   spbas_incomplete_cholesky:
249b2f1ab58SBarry Smith      incomplete Cholesky decomposition of a square, symmetric,
250b2f1ab58SBarry Smith      positive definite matrix.
251b2f1ab58SBarry Smith 
252b2f1ab58SBarry Smith      In case negative diagonals are encountered, function returns
253b2f1ab58SBarry Smith      NEGATIVE_DIAGONAL. When this happens, call this function again
254b2f1ab58SBarry Smith      with a larger epsdiag_in, a less sparse pattern, and/or a smaller
255b2f1ab58SBarry Smith      droptol
256b2f1ab58SBarry Smith */
2579ccc4a9bSBarry Smith PetscErrorCode spbas_incomplete_cholesky(Mat A, const PetscInt *rip, const PetscInt *riip, spbas_matrix pattern, PetscReal droptol, PetscReal epsdiag_in, spbas_matrix * matrix_L)
258b2f1ab58SBarry Smith {
259b2f1ab58SBarry Smith   PetscInt        jL;
260b2f1ab58SBarry Smith   Mat_SeqAIJ      *a =(Mat_SeqAIJ*)A->data;
261b2f1ab58SBarry Smith   PetscInt        *ai=a->i,*aj=a->j;
262b2f1ab58SBarry Smith   MatScalar       *aa=a->a;
263b2f1ab58SBarry Smith   PetscInt        nrows, ncols;
264b2f1ab58SBarry Smith   PetscInt        *max_row_nnz;
265b2f1ab58SBarry Smith   PetscErrorCode  ierr;
266b2f1ab58SBarry Smith   spbas_matrix    retval;
267b2f1ab58SBarry Smith   PetscScalar     *diag;
268b2f1ab58SBarry Smith   PetscScalar     *val;
269b2f1ab58SBarry Smith   PetscScalar     *lvec;
270b2f1ab58SBarry Smith   PetscScalar     epsdiag;
271b2f1ab58SBarry Smith   PetscInt        i,j,k;
272ace3abfcSBarry Smith   const PetscBool do_values = PETSC_TRUE;
2739ccc4a9bSBarry Smith   PetscInt        *r1_icol;
2749ccc4a9bSBarry Smith   PetscScalar     *r1_val;
2759ccc4a9bSBarry Smith   PetscInt        *r_icol;
2769ccc4a9bSBarry Smith   PetscInt        r_nnz;
2779ccc4a9bSBarry Smith   PetscScalar     *r_val;
2789ccc4a9bSBarry Smith   PetscInt        *A_icol;
2799ccc4a9bSBarry Smith   PetscInt        A_nnz;
2809ccc4a9bSBarry Smith   PetscScalar     *A_val;
2819ccc4a9bSBarry Smith   PetscInt        *p_icol;
2829ccc4a9bSBarry Smith   PetscInt        p_nnz;
2839ccc4a9bSBarry Smith   PetscInt        n_row_alloc_ok = 0;   /* number of rows which have been stored   correctly in the matrix */
2849ccc4a9bSBarry Smith   PetscInt        n_alloc_used   = 0;   /* part of result->icols and result->values   which is currently being used */
285b2f1ab58SBarry Smith 
2869ccc4a9bSBarry Smith   PetscFunctionBegin;
2874e1ff37aSBarry Smith   /* Convert the Manteuffel shift from 'fraction of average diagonal' to   dimensioned value */
288b2f1ab58SBarry Smith   ierr = MatGetSize(A, &nrows, &ncols);CHKERRQ(ierr);
289b2f1ab58SBarry Smith   ierr = MatGetTrace(A, &epsdiag);CHKERRQ(ierr);
2902205254eSKarl Rupp 
291b2f1ab58SBarry Smith   epsdiag *= epsdiag_in / nrows;
2922205254eSKarl Rupp 
29357622a8eSBarry Smith   ierr = PetscInfo2(NULL,"   Dimensioned Manteuffel shift %g Drop tolerance %g\n", (double)PetscRealPart(epsdiag),(double)droptol);CHKERRQ(ierr);
294b2f1ab58SBarry Smith 
2952205254eSKarl Rupp   if (droptol<1e-10) droptol=1e-10;
296b2f1ab58SBarry Smith 
297e32f2f54SBarry Smith   if ((nrows != pattern.nrows) || (ncols != pattern.ncols) || (ncols != nrows)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,"Dimension error in spbas_incomplete_cholesky\n");
298b2f1ab58SBarry Smith 
299b2f1ab58SBarry Smith   retval.nrows        = nrows;
300b2f1ab58SBarry Smith   retval.ncols        = nrows;
301b2f1ab58SBarry Smith   retval.nnz          = pattern.nnz/10;
302b2f1ab58SBarry Smith   retval.col_idx_type = SPBAS_COLUMN_NUMBERS;
303b2f1ab58SBarry Smith   retval.block_data   = PETSC_TRUE;
304b2f1ab58SBarry Smith 
305b2f1ab58SBarry Smith   ierr       = spbas_allocate_pattern(&retval, do_values);CHKERRQ(ierr);
306*580bdb30SBarry Smith   ierr       = PetscArrayzero(retval.row_nnz, nrows);CHKERRQ(ierr);
307b2f1ab58SBarry Smith   ierr       = spbas_allocate_data(&retval);CHKERRQ(ierr);
308b2f1ab58SBarry Smith   retval.nnz = 0;
309b2f1ab58SBarry Smith 
310785e854fSJed Brown   ierr = PetscMalloc1(nrows, &diag);CHKERRQ(ierr);
311*580bdb30SBarry Smith   ierr = PetscCalloc1(nrows, &val);CHKERRQ(ierr);
312*580bdb30SBarry Smith   ierr = PetscCalloc1(nrows, &lvec);CHKERRQ(ierr);
313*580bdb30SBarry Smith   ierr = PetscCalloc1(nrows, &max_row_nnz);CHKERRQ(ierr);
314b2f1ab58SBarry Smith 
315c328eeadSBarry Smith   /* Check correct format of sparseness pattern */
316e32f2f54SBarry Smith   if (pattern.col_idx_type != SPBAS_DIAGONAL_OFFSETS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Error in spbas_incomplete_cholesky: must have diagonal offsets in pattern\n");
317b2f1ab58SBarry Smith 
318c328eeadSBarry Smith   /* Count the nonzeros on transpose of pattern */
3194e1ff37aSBarry Smith   for (i = 0; i<nrows; i++)  {
320b2f1ab58SBarry Smith     p_nnz  = pattern.row_nnz[i];
321b2f1ab58SBarry Smith     p_icol = pattern.icols[i];
3224e1ff37aSBarry Smith     for (j=0; j<p_nnz; j++)  {
323b2f1ab58SBarry Smith       max_row_nnz[i+p_icol[j]]++;
324b2f1ab58SBarry Smith     }
325b2f1ab58SBarry Smith   }
326b2f1ab58SBarry Smith 
327c328eeadSBarry Smith   /* Calculate rows of L */
3284e1ff37aSBarry Smith   for (i = 0; i<nrows; i++)  {
329b2f1ab58SBarry Smith     p_nnz  = pattern.row_nnz[i];
330b2f1ab58SBarry Smith     p_icol = pattern.icols[i];
331b2f1ab58SBarry Smith 
332b2f1ab58SBarry Smith     r_nnz  = retval.row_nnz[i];
333b2f1ab58SBarry Smith     r_icol = retval.icols[i];
334b2f1ab58SBarry Smith     r_val  = retval.values[i];
335b2f1ab58SBarry Smith     A_nnz  = ai[rip[i]+1] - ai[rip[i]];
336b2f1ab58SBarry Smith     A_icol = &aj[ai[rip[i]]];
337b2f1ab58SBarry Smith     A_val  = &aa[ai[rip[i]]];
338b2f1ab58SBarry Smith 
339c328eeadSBarry Smith     /* Calculate  val += A(i,i:n)'; */
3404e1ff37aSBarry Smith     for (j=0; j<A_nnz; j++) {
341b2f1ab58SBarry Smith       k = riip[A_icol[j]];
3422205254eSKarl Rupp       if (k>=i) val[k] = A_val[j];
343b2f1ab58SBarry Smith     }
344b2f1ab58SBarry Smith 
345c328eeadSBarry Smith     /*  Add regularization */
346b2f1ab58SBarry Smith     val[i] += epsdiag;
347b2f1ab58SBarry Smith 
348c328eeadSBarry Smith     /* Calculate lvec   = diag(D(0:i-1)) * L(0:i-1,i);
349c328eeadSBarry Smith         val(i) = A(i,i) - L(0:i-1,i)' * lvec */
3504e1ff37aSBarry Smith     for (j=0; j<r_nnz; j++)  {
351b2f1ab58SBarry Smith       k       = r_icol[j];
352b2f1ab58SBarry Smith       lvec[k] = diag[k] * r_val[j];
353b2f1ab58SBarry Smith       val[i] -= r_val[j] * lvec[k];
354b2f1ab58SBarry Smith     }
355b2f1ab58SBarry Smith 
356c328eeadSBarry Smith     /* Calculate the new diagonal */
357b2f1ab58SBarry Smith     diag[i] = val[i];
3584e1ff37aSBarry Smith     if (PetscRealPart(diag[i])<droptol) {
359302440fdSBarry Smith       ierr = PetscInfo(NULL,"Error in spbas_incomplete_cholesky:\n");CHKERRQ(ierr);
360302440fdSBarry Smith       ierr = PetscInfo1(NULL,"Negative diagonal in row %d\n",i+1);CHKERRQ(ierr);
361b2f1ab58SBarry Smith 
362c328eeadSBarry Smith       /* Delete the whole matrix at once. */
363302440fdSBarry Smith       ierr = spbas_delete(retval);CHKERRQ(ierr);
364b2f1ab58SBarry Smith       return NEGATIVE_DIAGONAL;
365b2f1ab58SBarry Smith     }
366b2f1ab58SBarry Smith 
367c328eeadSBarry Smith     /* If necessary, allocate arrays */
3684e1ff37aSBarry Smith     if (r_nnz==0) {
369302440fdSBarry Smith       ierr = spbas_cholesky_row_alloc(retval, i, 1, &n_alloc_used);
3704e1ff37aSBarry Smith       if (ierr == PETSC_ERR_MEM) {
3719ccc4a9bSBarry Smith         ierr = spbas_cholesky_garbage_collect(&retval,  i, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
372302440fdSBarry Smith         ierr = spbas_cholesky_row_alloc(retval, i, 1, &n_alloc_used);CHKERRQ(ierr);
373302440fdSBarry Smith       } else CHKERRQ(ierr);
374b2f1ab58SBarry Smith       r_icol = retval.icols[i];
375b2f1ab58SBarry Smith       r_val  = retval.values[i];
376b2f1ab58SBarry Smith     }
377b2f1ab58SBarry Smith 
378c328eeadSBarry Smith     /* Now, fill in */
379b2f1ab58SBarry Smith     r_icol[r_nnz] = i;
380b2f1ab58SBarry Smith     r_val [r_nnz] = 1.0;
381b2f1ab58SBarry Smith     r_nnz++;
382b2f1ab58SBarry Smith     retval.row_nnz[i]++;
383b2f1ab58SBarry Smith 
384b2f1ab58SBarry Smith     retval.nnz += r_nnz;
385b2f1ab58SBarry Smith 
386c328eeadSBarry Smith     /* Calculate
387c328eeadSBarry Smith         val(i+1:n) = (A(i,i+1:n)- L(0:i-1,i+1:n)' * lvec)/diag(i) */
3884e1ff37aSBarry Smith     for (j=1; j<p_nnz; j++)  {
389b2f1ab58SBarry Smith       k       = i+p_icol[j];
390b2f1ab58SBarry Smith       r1_icol = retval.icols[k];
391b2f1ab58SBarry Smith       r1_val  = retval.values[k];
3924e1ff37aSBarry Smith       for (jL=0; jL<retval.row_nnz[k]; jL++) {
393b2f1ab58SBarry Smith         val[k] -= r1_val[jL] * lvec[r1_icol[jL]];
394b2f1ab58SBarry Smith       }
395b2f1ab58SBarry Smith       val[k] /= diag[i];
396b2f1ab58SBarry Smith 
3974e1ff37aSBarry Smith       if (PetscAbsScalar(val[k]) > droptol || PetscAbsScalar(val[k])< -droptol) {
398c328eeadSBarry Smith         /* If necessary, allocate arrays */
3994e1ff37aSBarry Smith         if (retval.row_nnz[k]==0) {
4009ccc4a9bSBarry Smith           ierr = spbas_cholesky_row_alloc(retval, k, max_row_nnz[k], &n_alloc_used);
4019ccc4a9bSBarry Smith           if (ierr == PETSC_ERR_MEM) {
4029ccc4a9bSBarry Smith             ierr   = spbas_cholesky_garbage_collect(&retval,  i, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
4039ccc4a9bSBarry Smith             ierr   = spbas_cholesky_row_alloc(retval, k, max_row_nnz[k], &n_alloc_used);CHKERRQ(ierr);
404b2f1ab58SBarry Smith             r_icol = retval.icols[i];
405302440fdSBarry Smith           } else CHKERRQ(ierr);
406b2f1ab58SBarry Smith         }
407b2f1ab58SBarry Smith 
408b2f1ab58SBarry Smith         retval.icols[k][retval.row_nnz[k]]  = i;
409b2f1ab58SBarry Smith         retval.values[k][retval.row_nnz[k]] = val[k];
410b2f1ab58SBarry Smith         retval.row_nnz[k]++;
411b2f1ab58SBarry Smith       }
412b2f1ab58SBarry Smith       val[k] = 0;
413b2f1ab58SBarry Smith     }
414b2f1ab58SBarry Smith 
41571d55d18SBarry Smith     /* Erase the values used in the work arrays */
4162205254eSKarl Rupp     for (j=0; j<r_nnz; j++) lvec[r_icol[j]] = 0;
417b2f1ab58SBarry Smith   }
418b2f1ab58SBarry Smith 
4199ccc4a9bSBarry Smith   ierr=PetscFree(lvec);CHKERRQ(ierr);
4209ccc4a9bSBarry Smith   ierr=PetscFree(val);CHKERRQ(ierr);
421b2f1ab58SBarry Smith 
4229ccc4a9bSBarry Smith   ierr = spbas_cholesky_garbage_collect(&retval, nrows, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
423b2f1ab58SBarry Smith   ierr = PetscFree(max_row_nnz);CHKERRQ(ierr);
424b2f1ab58SBarry Smith 
425c328eeadSBarry Smith   /* Place the inverse of the diagonals in the matrix */
4269ccc4a9bSBarry Smith   for (i=0; i<nrows; i++) {
427b2f1ab58SBarry Smith     r_nnz = retval.row_nnz[i];
4282205254eSKarl Rupp 
429b2f1ab58SBarry Smith     retval.values[i][r_nnz-1] = 1.0 / diag[i];
4309ccc4a9bSBarry Smith     for (j=0; j<r_nnz-1; j++) {
431b2f1ab58SBarry Smith       retval.values[i][j] *= -1;
432b2f1ab58SBarry Smith     }
433b2f1ab58SBarry Smith   }
434b2f1ab58SBarry Smith   ierr      = PetscFree(diag);CHKERRQ(ierr);
435b2f1ab58SBarry Smith   *matrix_L = retval;
436b2f1ab58SBarry Smith   PetscFunctionReturn(0);
437b2f1ab58SBarry Smith }
438b2f1ab58SBarry Smith 
439