xref: /petsc/src/mat/impls/aij/seq/bas/spbas_cholesky.h (revision 9ccc4a9b96fc3663f3953ac586c9c547e88efdff)
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 #undef __FUNCT__
9b2f1ab58SBarry Smith #define __FUNCT__ "spbas_cholesky_row_alloc"
10b2f1ab58SBarry Smith PetscErrorCode spbas_cholesky_row_alloc(spbas_matrix retval, PetscInt k, PetscInt r_nnz,PetscInt * n_alloc_used)
11b2f1ab58SBarry Smith {
12b2f1ab58SBarry Smith    PetscFunctionBegin;
13b2f1ab58SBarry Smith    retval.icols[k]  = &retval.alloc_icol[*n_alloc_used];
14b2f1ab58SBarry Smith    retval.values[k] = &retval.alloc_val[*n_alloc_used];
15b2f1ab58SBarry Smith    *n_alloc_used   += r_nnz;
16*9ccc4a9bSBarry Smith    if (*n_alloc_used > retval.n_alloc_icol) PetscFunctionReturn(PETSC_ERR_MEM);
17b2f1ab58SBarry Smith    PetscFunctionReturn(0);
18b2f1ab58SBarry Smith }
19b2f1ab58SBarry Smith 
20b2f1ab58SBarry Smith 
21b2f1ab58SBarry Smith /*
22b2f1ab58SBarry Smith   spbas_cholesky_garbage_collect:
23b2f1ab58SBarry Smith      move the rows which have been calculated so far, as well as
24b2f1ab58SBarry Smith      those currently under construction, to the front of the
25b2f1ab58SBarry Smith      array, while putting them in the proper order.
26b2f1ab58SBarry Smith      When it seems necessary, enlarge the current arrays.
27b2f1ab58SBarry Smith 
28b2f1ab58SBarry Smith      NB: re-allocation is being simulated using
29b2f1ab58SBarry Smith          PetscMalloc, memcpy, PetscFree, because
30b2f1ab58SBarry Smith          PetscRealloc does not seem to exist.
31b2f1ab58SBarry Smith 
32b2f1ab58SBarry Smith */
33b2f1ab58SBarry Smith #undef __FUNCT__
34b2f1ab58SBarry Smith #define __FUNCT__ "spbas_cholesky_garbage_collect"
35b2f1ab58SBarry Smith PetscErrorCode spbas_cholesky_garbage_collect(
36c328eeadSBarry Smith       spbas_matrix *result, /* I/O: the Cholesky factor matrix being constructed.
37c328eeadSBarry Smith                                    Only the storage, not the contents of this matrix
38c328eeadSBarry Smith                                    is changed in this function */
39c328eeadSBarry Smith       PetscInt     i_row,             /* I  : Number of rows for which the final contents are
40c328eeadSBarry Smith 				     known */
41c328eeadSBarry Smith       PetscInt     *n_row_alloc_ok,   /* I/O: Number of rows which are already in their final
42c328eeadSBarry Smith 				     places in the arrays: they need not be moved any more */
43c328eeadSBarry Smith       PetscInt     *n_alloc_used,     /* I/O:  */
44c328eeadSBarry Smith       PetscInt     *max_row_nnz       /*I  : Over-estimate of the number of nonzeros needed to
45c328eeadSBarry Smith 				    store each row */
46b2f1ab58SBarry Smith      )
47b2f1ab58SBarry Smith {
48b2f1ab58SBarry Smith 
49b2f1ab58SBarry Smith 
50c328eeadSBarry Smith   /* PSEUDO-CODE:
51c328eeadSBarry Smith     1. Choose the appropriate size for the arrays
52c328eeadSBarry Smith     2. Rescue the arrays which would be lost during garbage collection
53c328eeadSBarry Smith     3. Reallocate and correct administration
54c328eeadSBarry Smith     4. Move all arrays so that they are in proper order */
55b2f1ab58SBarry Smith 
56b2f1ab58SBarry Smith    PetscInt        i,j;
57b2f1ab58SBarry Smith    PetscInt        nrows = result->nrows;
58b2f1ab58SBarry Smith    PetscInt        n_alloc_ok=0;
59b2f1ab58SBarry Smith    PetscInt        n_alloc_ok_max=0;
60b2f1ab58SBarry Smith    PetscErrorCode  ierr;
61b2f1ab58SBarry Smith    PetscInt        need_already= 0;
62b2f1ab58SBarry Smith    PetscInt        n_rows_ahead=0;
63b2f1ab58SBarry Smith    PetscInt        max_need_extra= 0;
64b2f1ab58SBarry Smith    PetscInt        n_alloc_max, n_alloc_est, n_alloc;
65b2f1ab58SBarry Smith    PetscInt        n_alloc_now = result->n_alloc_icol;
66b2f1ab58SBarry Smith    PetscInt        *alloc_icol_old = result->alloc_icol;
67b2f1ab58SBarry Smith    PetscScalar     *alloc_val_old  = result->alloc_val;
68b2f1ab58SBarry Smith    PetscInt        *icol_rescue;
69b2f1ab58SBarry Smith    PetscScalar     *val_rescue;
70b2f1ab58SBarry Smith    PetscInt        n_rescue;
71b2f1ab58SBarry Smith    PetscInt        n_row_rescue;
72b2f1ab58SBarry Smith    PetscInt        i_here, i_last, n_copy;
73d36aa34eSBarry Smith    const PetscReal xtra_perc = 20;
74b2f1ab58SBarry Smith 
75b2f1ab58SBarry Smith    PetscFunctionBegin;
76b2f1ab58SBarry Smith 
77c328eeadSBarry Smith    /*********************************************************
78c328eeadSBarry Smith     1. Choose appropriate array size
79c328eeadSBarry Smith     Count number of rows and memory usage which is already final */
80*9ccc4a9bSBarry Smith    for (i=0;i<i_row; i++)  {
81b2f1ab58SBarry Smith       n_alloc_ok += result->row_nnz[i];
82b2f1ab58SBarry Smith       n_alloc_ok_max += max_row_nnz[i];
83b2f1ab58SBarry Smith    }
84b2f1ab58SBarry Smith 
85c328eeadSBarry Smith    /* Count currently needed memory usage and future memory requirements
86c328eeadSBarry Smith       (max, predicted)*/
87*9ccc4a9bSBarry Smith    for (i=i_row; i<nrows; i++) {
88*9ccc4a9bSBarry Smith      if (!result->row_nnz[i]) {
89b2f1ab58SBarry Smith          max_need_extra  += max_row_nnz[i];
90*9ccc4a9bSBarry Smith       } else {
91b2f1ab58SBarry Smith          need_already    += max_row_nnz[i];
92b2f1ab58SBarry Smith          n_rows_ahead++;
93b2f1ab58SBarry Smith       }
94b2f1ab58SBarry Smith    }
95b2f1ab58SBarry Smith 
96c328eeadSBarry Smith    /* Make maximal and realistic memory requirement estimates */
97b2f1ab58SBarry Smith    n_alloc_max = n_alloc_ok + need_already + max_need_extra;
98*9ccc4a9bSBarry Smith    n_alloc_est = n_alloc_ok + need_already + (int) (((PetscReal) max_need_extra) *  ((PetscReal) n_alloc_ok) /((PetscReal) n_alloc_ok_max));
99b2f1ab58SBarry Smith 
100c328eeadSBarry Smith    /* Choose array sizes */
101*9ccc4a9bSBarry Smith    if (n_alloc_max == n_alloc_est)  { n_alloc = n_alloc_max; }
102*9ccc4a9bSBarry Smith    else if (n_alloc_now >= n_alloc_est)  { n_alloc = n_alloc_now; }
103*9ccc4a9bSBarry Smith    else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0))  { n_alloc  = n_alloc_max;  }
104*9ccc4a9bSBarry Smith    else { n_alloc = (int) (n_alloc_est * (1+xtra_perc/100.0)); }
105b2f1ab58SBarry Smith 
106c328eeadSBarry Smith    /* If new estimate is less than what we already have,
107c328eeadSBarry Smith       don't reallocate, just garbage-collect */
108*9ccc4a9bSBarry Smith    if (n_alloc_max != n_alloc_est && n_alloc < result->n_alloc_icol) {
109b2f1ab58SBarry Smith       n_alloc = result->n_alloc_icol;
110b2f1ab58SBarry Smith    }
111b2f1ab58SBarry Smith 
112c328eeadSBarry Smith    /* Motivate dimension choice */
113c328eeadSBarry Smith    ierr = PetscInfo1(PETSC_NULL,"   Allocating %d nonzeros: ",n_alloc);CHKERRQ(ierr);
114*9ccc4a9bSBarry Smith    if (n_alloc_max == n_alloc_est) { ierr = PetscInfo(PETSC_NULL,"this is the correct size\n");CHKERRQ(ierr); }
115*9ccc4a9bSBarry Smith    else if (n_alloc_now >= n_alloc_est) { ierr = PetscInfo(PETSC_NULL,"the current size, which seems enough\n");CHKERRQ(ierr); }
116*9ccc4a9bSBarry Smith    else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0)) { ierr = PetscInfo(PETSC_NULL,"the maximum estimate\n");CHKERRQ(ierr); }
117*9ccc4a9bSBarry Smith    else { ierr = PetscInfo1(PETSC_NULL,"%6.2f %% more than the estimate\n",xtra_perc);CHKERRQ(ierr); }
118b2f1ab58SBarry Smith 
119b2f1ab58SBarry Smith 
120c328eeadSBarry Smith    /**********************************************************
121c328eeadSBarry Smith     2. Rescue arrays which would be lost
122c328eeadSBarry Smith     Count how many rows and nonzeros will have to be rescued
123c328eeadSBarry Smith     when moving all arrays in place */
124b2f1ab58SBarry Smith    n_row_rescue = 0; n_rescue = 0;
125b2f1ab58SBarry Smith    if (*n_row_alloc_ok==0) { *n_alloc_used = 0; }
126*9ccc4a9bSBarry Smith    else  {
127b2f1ab58SBarry Smith       i = *n_row_alloc_ok - 1;
128*9ccc4a9bSBarry Smith       *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
129b2f1ab58SBarry Smith    }
130b2f1ab58SBarry Smith 
131*9ccc4a9bSBarry Smith    for (i=*n_row_alloc_ok; i<nrows; i++) {
132b2f1ab58SBarry Smith       i_here = result->icols[i]-result->alloc_icol;
133b2f1ab58SBarry Smith       i_last = i_here + result->row_nnz[i];
134*9ccc4a9bSBarry Smith       if (result->row_nnz[i]>0) {
135*9ccc4a9bSBarry Smith          if (*n_alloc_used > i_here || i_last > n_alloc) {
136b2f1ab58SBarry Smith             n_rescue += result->row_nnz[i];
137b2f1ab58SBarry Smith             n_row_rescue++;
138b2f1ab58SBarry Smith          }
139b2f1ab58SBarry Smith 
140b2f1ab58SBarry Smith          if (i<i_row) {  *n_alloc_used += result->row_nnz[i];}
141b2f1ab58SBarry Smith          else         {  *n_alloc_used += max_row_nnz[i];}
142b2f1ab58SBarry Smith       }
143b2f1ab58SBarry Smith    }
144b2f1ab58SBarry Smith 
145c328eeadSBarry Smith    /* Allocate rescue arrays */
146*9ccc4a9bSBarry Smith    ierr = PetscMalloc( n_rescue * sizeof(int), &icol_rescue);CHKERRQ(ierr);
147*9ccc4a9bSBarry Smith    ierr = PetscMalloc( n_rescue * sizeof(PetscScalar), &val_rescue);CHKERRQ(ierr);
148b2f1ab58SBarry Smith 
149c328eeadSBarry Smith    /* Rescue the arrays which need rescuing */
150b2f1ab58SBarry Smith    n_row_rescue = 0; n_rescue = 0;
151b2f1ab58SBarry Smith    if (*n_row_alloc_ok==0) { *n_alloc_used = 0; }
152*9ccc4a9bSBarry Smith    else {
153b2f1ab58SBarry Smith       i = *n_row_alloc_ok - 1;
154*9ccc4a9bSBarry Smith       *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
155b2f1ab58SBarry Smith    }
156b2f1ab58SBarry Smith 
157*9ccc4a9bSBarry Smith    for (i=*n_row_alloc_ok; i<nrows; i++) {
158b2f1ab58SBarry Smith       i_here = result->icols[i]-result->alloc_icol;
159b2f1ab58SBarry Smith       i_last = i_here + result->row_nnz[i];
160*9ccc4a9bSBarry Smith       if (result->row_nnz[i]>0) {
161b2f1ab58SBarry Smith          if (*n_alloc_used > i_here || i_last > n_alloc)
162b2f1ab58SBarry Smith          {
163*9ccc4a9bSBarry Smith             ierr = PetscMemcpy((void*) &icol_rescue[n_rescue], (void*) result->icols[i], result->row_nnz[i] * sizeof(int));CHKERRQ(ierr);
164*9ccc4a9bSBarry Smith             ierr = PetscMemcpy((void*) &val_rescue[n_rescue], (void*) result->values[i], result->row_nnz[i] * sizeof(PetscScalar));CHKERRQ(ierr);
165b2f1ab58SBarry Smith             n_rescue += result->row_nnz[i];
166b2f1ab58SBarry Smith             n_row_rescue++;
167b2f1ab58SBarry Smith          }
168b2f1ab58SBarry Smith 
169b2f1ab58SBarry Smith          if (i<i_row) {  *n_alloc_used += result->row_nnz[i];}
170b2f1ab58SBarry Smith          else         {  *n_alloc_used += max_row_nnz[i];}
171b2f1ab58SBarry Smith       }
172b2f1ab58SBarry Smith    }
173b2f1ab58SBarry Smith 
174c328eeadSBarry Smith    /**********************************************************
175c328eeadSBarry Smith     3. Reallocate and correct administration */
176b2f1ab58SBarry Smith 
177*9ccc4a9bSBarry Smith    if (n_alloc != result->n_alloc_icol)  {
178b2f1ab58SBarry Smith       n_copy = MIN(n_alloc,result->n_alloc_icol);
179b2f1ab58SBarry Smith 
180c328eeadSBarry Smith       /* PETSC knows no REALLOC, so we'll REALLOC ourselves.
181b2f1ab58SBarry Smith 
182c328eeadSBarry Smith 	 Allocate new icol-data, copy old contents */
183*9ccc4a9bSBarry Smith       ierr = PetscMalloc(  n_alloc * sizeof(int), &result->alloc_icol);CHKERRQ(ierr);
184*9ccc4a9bSBarry Smith       ierr = PetscMemcpy(result->alloc_icol, alloc_icol_old, n_copy*sizeof(int));CHKERRQ(ierr);
185b2f1ab58SBarry Smith 
186c328eeadSBarry Smith       /* Update administration, Reset pointers to new arrays  */
187b2f1ab58SBarry Smith       result->n_alloc_icol = n_alloc;
188*9ccc4a9bSBarry Smith       for (i=0; i<nrows; i++) {
189*9ccc4a9bSBarry Smith           result->icols[i] =  result->alloc_icol + (result->icols[i]  - alloc_icol_old);
190*9ccc4a9bSBarry Smith           result->values[i] =  result->alloc_val + (result->icols[i]  - result->alloc_icol);
191b2f1ab58SBarry Smith       }
192b2f1ab58SBarry Smith 
193c328eeadSBarry Smith       /* Delete old array */
194b2f1ab58SBarry Smith       ierr = PetscFree(alloc_icol_old);CHKERRQ(ierr);
195b2f1ab58SBarry Smith 
196c328eeadSBarry Smith       /* Allocate new value-data, copy old contents */
197*9ccc4a9bSBarry Smith       ierr = PetscMalloc(  n_alloc * sizeof(PetscScalar), &result->alloc_val);CHKERRQ(ierr);
198*9ccc4a9bSBarry Smith       ierr = PetscMemcpy(result->alloc_val, alloc_val_old, n_copy*sizeof(PetscScalar));CHKERRQ(ierr);
199b2f1ab58SBarry Smith 
200c328eeadSBarry Smith       /* Update administration, Reset pointers to new arrays  */
201b2f1ab58SBarry Smith       result->n_alloc_val  = n_alloc;
202*9ccc4a9bSBarry Smith       for (i=0; i<nrows; i++) {
203*9ccc4a9bSBarry Smith           result->values[i] =  result->alloc_val + (result->icols[i]  - result->alloc_icol);
204b2f1ab58SBarry Smith       }
205b2f1ab58SBarry Smith 
206c328eeadSBarry Smith       /* Delete old array */
207b2f1ab58SBarry Smith       ierr = PetscFree(alloc_val_old);CHKERRQ(ierr);
208b2f1ab58SBarry Smith    }
209b2f1ab58SBarry Smith 
210b2f1ab58SBarry Smith 
211c328eeadSBarry Smith    /*********************************************************
212c328eeadSBarry Smith     4. Copy all the arrays to their proper places */
213b2f1ab58SBarry Smith    n_row_rescue = 0; n_rescue = 0;
214b2f1ab58SBarry Smith    if (*n_row_alloc_ok==0) { *n_alloc_used = 0; }
215*9ccc4a9bSBarry Smith    else {
216b2f1ab58SBarry Smith       i = *n_row_alloc_ok - 1;
217*9ccc4a9bSBarry Smith       *n_alloc_used = (result->icols[i]-result->alloc_icol) +  result->row_nnz[i];
218b2f1ab58SBarry Smith    }
219b2f1ab58SBarry Smith 
220*9ccc4a9bSBarry Smith    for (i=*n_row_alloc_ok; i<nrows; i++) {
221b2f1ab58SBarry Smith       i_here = result->icols[i]-result->alloc_icol;
222b2f1ab58SBarry Smith       i_last = i_here + result->row_nnz[i];
223b2f1ab58SBarry Smith 
224b2f1ab58SBarry Smith       result->icols[i] = result->alloc_icol + *n_alloc_used;
225b2f1ab58SBarry Smith       result->values[i]= result->alloc_val  + *n_alloc_used;
226b2f1ab58SBarry Smith 
227*9ccc4a9bSBarry Smith       if (result->row_nnz[i]>0) {
228*9ccc4a9bSBarry Smith          if (*n_alloc_used > i_here || i_last > n_alloc)  {
229*9ccc4a9bSBarry Smith             ierr = PetscMemcpy((void*) result->icols[i],  (void*) &icol_rescue[n_rescue], result->row_nnz[i] * sizeof(int));CHKERRQ(ierr);
230*9ccc4a9bSBarry Smith             ierr = PetscMemcpy((void*) result->values[i], (void*) &val_rescue[n_rescue],result->row_nnz[i] * sizeof(PetscScalar));CHKERRQ(ierr);
231b2f1ab58SBarry Smith             n_rescue += result->row_nnz[i];
232b2f1ab58SBarry Smith             n_row_rescue++;
233*9ccc4a9bSBarry Smith          } else {
234*9ccc4a9bSBarry Smith             for (j=0; j<result->row_nnz[i]; j++) {
235b2f1ab58SBarry Smith                 result->icols[i][j]   = result->alloc_icol[i_here+j];
236b2f1ab58SBarry Smith                 result->values[i][j]  = result->alloc_val[ i_here+j];
237b2f1ab58SBarry Smith             }
238b2f1ab58SBarry Smith          }
239b2f1ab58SBarry Smith          if (i<i_row) {  *n_alloc_used += result->row_nnz[i];}
240b2f1ab58SBarry Smith          else         {  *n_alloc_used += max_row_nnz[i];}
241b2f1ab58SBarry Smith       }
242b2f1ab58SBarry Smith    }
243b2f1ab58SBarry Smith 
244c328eeadSBarry Smith    /* Delete the rescue arrays */
245b2f1ab58SBarry Smith    ierr = PetscFree(icol_rescue);CHKERRQ(ierr);
246b2f1ab58SBarry Smith    ierr = PetscFree(val_rescue);CHKERRQ(ierr);
247b2f1ab58SBarry Smith    *n_row_alloc_ok = i_row;
248b2f1ab58SBarry Smith    PetscFunctionReturn(0);
249b2f1ab58SBarry Smith }
250b2f1ab58SBarry Smith 
251b2f1ab58SBarry Smith /*
252b2f1ab58SBarry Smith   spbas_incomplete_cholesky:
253b2f1ab58SBarry Smith      incomplete Cholesky decomposition of a square, symmetric,
254b2f1ab58SBarry Smith      positive definite matrix.
255b2f1ab58SBarry Smith 
256b2f1ab58SBarry Smith      In case negative diagonals are encountered, function returns
257b2f1ab58SBarry Smith      NEGATIVE_DIAGONAL. When this happens, call this function again
258b2f1ab58SBarry Smith      with a larger epsdiag_in, a less sparse pattern, and/or a smaller
259b2f1ab58SBarry Smith      droptol
260b2f1ab58SBarry Smith */
261b2f1ab58SBarry Smith #undef __FUNCT__
262b2f1ab58SBarry Smith #define __FUNCT__ "spbas_incomplete_cholesky"
263*9ccc4a9bSBarry 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)
264b2f1ab58SBarry Smith {
265b2f1ab58SBarry Smith    PetscInt         jL;
266b2f1ab58SBarry Smith    Mat_SeqAIJ       *a=(Mat_SeqAIJ*)A->data;
267b2f1ab58SBarry Smith    PetscInt         *ai=a->i,*aj=a->j;
268b2f1ab58SBarry Smith    MatScalar        *aa=a->a;
269b2f1ab58SBarry Smith    PetscInt         nrows, ncols;
270b2f1ab58SBarry Smith    PetscInt         *max_row_nnz;
271b2f1ab58SBarry Smith    PetscErrorCode   ierr;
272b2f1ab58SBarry Smith    spbas_matrix     retval;
273b2f1ab58SBarry Smith    PetscScalar      * diag;
274b2f1ab58SBarry Smith    PetscScalar      * val;
275b2f1ab58SBarry Smith    PetscScalar      * lvec;
276b2f1ab58SBarry Smith    PetscScalar      epsdiag;
277b2f1ab58SBarry Smith    PetscInt         i,j,k;
278b2f1ab58SBarry Smith    const PetscTruth do_values = PETSC_TRUE;
279*9ccc4a9bSBarry Smith    PetscInt         * r1_icol;
280*9ccc4a9bSBarry Smith    PetscScalar      *r1_val;
281*9ccc4a9bSBarry Smith    PetscInt         * r_icol;
282*9ccc4a9bSBarry Smith    PetscInt         r_nnz;
283*9ccc4a9bSBarry Smith    PetscScalar      *r_val;
284*9ccc4a9bSBarry Smith    PetscInt         * A_icol;
285*9ccc4a9bSBarry Smith    PetscInt         A_nnz;
286*9ccc4a9bSBarry Smith    PetscScalar      *A_val;
287*9ccc4a9bSBarry Smith    PetscInt         * p_icol;
288*9ccc4a9bSBarry Smith    PetscInt         p_nnz;
289*9ccc4a9bSBarry Smith    PetscInt         n_row_alloc_ok = 0;  /* number of rows which have been stored   correctly in the matrix */
290*9ccc4a9bSBarry Smith    PetscInt         n_alloc_used = 0;    /* part of result->icols and result->values   which is currently being used */
291b2f1ab58SBarry Smith 
292*9ccc4a9bSBarry Smith    PetscFunctionBegin;
293c328eeadSBarry Smith    /* Convert the Manteuffel shift from 'fraction of average diagonal' to
294c328eeadSBarry Smith       dimensioned value */
295b2f1ab58SBarry Smith    ierr = MatGetSize(A, &nrows, &ncols);CHKERRQ(ierr);
296b2f1ab58SBarry Smith    ierr = MatGetTrace(A, &epsdiag);CHKERRQ(ierr);
297b2f1ab58SBarry Smith    epsdiag *= epsdiag_in / nrows;
2989767453cSBarry Smith    ierr = PetscInfo2(PETSC_NULL,"   Dimensioned Manteuffel shift %G Drop tolerance %G\n", PetscRealPart(epsdiag),droptol);CHKERRQ(ierr);
299b2f1ab58SBarry Smith 
300b2f1ab58SBarry Smith    if (droptol<1e-10) {droptol=1e-10;}
301b2f1ab58SBarry Smith 
302b2f1ab58SBarry Smith    if ( (nrows != pattern.nrows) ||
303b2f1ab58SBarry Smith         (ncols != pattern.ncols) ||
304b2f1ab58SBarry Smith         (ncols != nrows) )
305b2f1ab58SBarry Smith    {
306b2f1ab58SBarry Smith       SETERRQ( PETSC_ERR_ARG_INCOMP,
307b2f1ab58SBarry Smith                "Dimension error in spbas_incomplete_cholesky\n");
308b2f1ab58SBarry Smith    }
309b2f1ab58SBarry Smith 
310b2f1ab58SBarry Smith    retval.nrows = nrows;
311b2f1ab58SBarry Smith    retval.ncols = nrows;
312b2f1ab58SBarry Smith    retval.nnz   = pattern.nnz/10;
313b2f1ab58SBarry Smith    retval.col_idx_type = SPBAS_COLUMN_NUMBERS;
314b2f1ab58SBarry Smith    retval.block_data = PETSC_TRUE;
315b2f1ab58SBarry Smith 
316b2f1ab58SBarry Smith    ierr =  spbas_allocate_pattern(&retval, do_values);CHKERRQ(ierr);
317b2f1ab58SBarry Smith    memset((void*) retval.row_nnz, 0, nrows*sizeof(int));
318b2f1ab58SBarry Smith    ierr =  spbas_allocate_data(&retval);CHKERRQ(ierr);
319b2f1ab58SBarry Smith    retval.nnz   = 0;
320b2f1ab58SBarry Smith 
321b2f1ab58SBarry Smith    ierr = PetscMalloc(nrows*sizeof(PetscScalar), &diag);CHKERRQ(ierr);
322b2f1ab58SBarry Smith    ierr = PetscMalloc(nrows*sizeof(PetscScalar), &val);CHKERRQ(ierr);
323b2f1ab58SBarry Smith    ierr = PetscMalloc(nrows*sizeof(PetscScalar), &lvec);CHKERRQ(ierr);
324b2f1ab58SBarry Smith    ierr = PetscMalloc(nrows*sizeof(int), &max_row_nnz);CHKERRQ(ierr);
325b2f1ab58SBarry Smith    if (!(diag && val && lvec && max_row_nnz))
326b2f1ab58SBarry Smith    {
327b2f1ab58SBarry Smith       SETERRQ( PETSC_ERR_MEM,
328b2f1ab58SBarry Smith               "Allocation error in spbas_incomplete_cholesky\n");
329b2f1ab58SBarry Smith    }
330b2f1ab58SBarry Smith 
331b2f1ab58SBarry Smith    memset((void*) val, 0, nrows*sizeof(PetscScalar));
332b2f1ab58SBarry Smith    memset((void*) lvec, 0, nrows*sizeof(PetscScalar));
333b2f1ab58SBarry Smith    memset((void*) max_row_nnz, 0, nrows*sizeof(int));
334b2f1ab58SBarry Smith 
335c328eeadSBarry Smith    /* Check correct format of sparseness pattern */
336b2f1ab58SBarry Smith    if (pattern.col_idx_type != SPBAS_DIAGONAL_OFFSETS)
337b2f1ab58SBarry Smith    {
338b2f1ab58SBarry Smith       SETERRQ( PETSC_ERR_SUP_SYS,
339b2f1ab58SBarry Smith                "Error in spbas_incomplete_cholesky: must have diagonal offsets in pattern\n");
340b2f1ab58SBarry Smith    }
341b2f1ab58SBarry Smith 
342c328eeadSBarry Smith    /* Count the nonzeros on transpose of pattern */
343b2f1ab58SBarry Smith    for (i = 0; i<nrows; i++)
344b2f1ab58SBarry Smith    {
345b2f1ab58SBarry Smith       p_nnz  = pattern.row_nnz[i];
346b2f1ab58SBarry Smith       p_icol = pattern.icols[i];
347b2f1ab58SBarry Smith       for (j=0; j<p_nnz; j++)
348b2f1ab58SBarry Smith       {
349b2f1ab58SBarry Smith          max_row_nnz[i+p_icol[j]]++;
350b2f1ab58SBarry Smith       }
351b2f1ab58SBarry Smith    }
352b2f1ab58SBarry Smith 
353c328eeadSBarry Smith    /* Calculate rows of L */
354b2f1ab58SBarry Smith    for (i = 0; i<nrows; i++)
355b2f1ab58SBarry Smith    {
356b2f1ab58SBarry Smith       p_nnz  = pattern.row_nnz[i];
357b2f1ab58SBarry Smith       p_icol = pattern.icols[i];
358b2f1ab58SBarry Smith 
359b2f1ab58SBarry Smith       r_nnz  = retval.row_nnz[i];
360b2f1ab58SBarry Smith       r_icol = retval.icols[i];
361b2f1ab58SBarry Smith       r_val  = retval.values[i];
362b2f1ab58SBarry Smith       A_nnz  = ai[rip[i]+1] - ai[rip[i]];
363b2f1ab58SBarry Smith       A_icol = &aj[ai[rip[i]]];
364b2f1ab58SBarry Smith       A_val  = &aa[ai[rip[i]]];
365b2f1ab58SBarry Smith 
366c328eeadSBarry Smith       /* Calculate  val += A(i,i:n)'; */
367b2f1ab58SBarry Smith       for (j=0; j<A_nnz; j++)
368b2f1ab58SBarry Smith       {
369b2f1ab58SBarry Smith          k = riip[A_icol[j]];
370b2f1ab58SBarry Smith          if (k>=i) { val[k] = A_val[j]; }
371b2f1ab58SBarry Smith       }
372b2f1ab58SBarry Smith 
373c328eeadSBarry Smith       /*  Add regularization */
374b2f1ab58SBarry Smith       val[i] += epsdiag;
375b2f1ab58SBarry Smith 
376c328eeadSBarry Smith       /* Calculate lvec   = diag(D(0:i-1)) * L(0:i-1,i);
377c328eeadSBarry Smith 	 val(i) = A(i,i) - L(0:i-1,i)' * lvec */
378b2f1ab58SBarry Smith       for ( j=0; j<r_nnz; j++)
379b2f1ab58SBarry Smith       {
380b2f1ab58SBarry Smith          k           = r_icol[j];
381b2f1ab58SBarry Smith          lvec[k]     = diag[k] * r_val[j];
382b2f1ab58SBarry Smith          val[i]     -= r_val[j] * lvec[k];
383b2f1ab58SBarry Smith       }
384b2f1ab58SBarry Smith 
385c328eeadSBarry Smith       /* Calculate the new diagonal */
386b2f1ab58SBarry Smith       diag[i] = val[i];
3879767453cSBarry Smith       if (PetscRealPart(diag[i])<droptol)
388b2f1ab58SBarry Smith       {
389c328eeadSBarry Smith          ierr = PetscInfo(PETSC_NULL,"Error in spbas_incomplete_cholesky:\n");
390c328eeadSBarry Smith          ierr = PetscInfo1(PETSC_NULL,"Negative diagonal in row %d\n",i+1);
391b2f1ab58SBarry Smith 
392c328eeadSBarry Smith          /* Delete the whole matrix at once. */
393b2f1ab58SBarry Smith          ierr = spbas_delete(retval);
394b2f1ab58SBarry Smith          return NEGATIVE_DIAGONAL;
395b2f1ab58SBarry Smith       }
396b2f1ab58SBarry Smith 
397c328eeadSBarry Smith       /* If necessary, allocate arrays */
398b2f1ab58SBarry Smith       if (r_nnz==0)
399b2f1ab58SBarry Smith       {
400*9ccc4a9bSBarry Smith          ierr = spbas_cholesky_row_alloc( retval, i, 1, &n_alloc_used);CHKERRQ(ierr);
401b2f1ab58SBarry Smith          if (ierr == PETSC_ERR_MEM)
402b2f1ab58SBarry Smith          {
403*9ccc4a9bSBarry Smith             ierr = spbas_cholesky_garbage_collect( &retval,  i, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
404b2f1ab58SBarry Smith             ierr = spbas_cholesky_row_alloc( retval, i, 1, &n_alloc_used);
405b2f1ab58SBarry Smith          }
406b2f1ab58SBarry Smith          r_icol = retval.icols[i];
407b2f1ab58SBarry Smith          r_val  = retval.values[i];
408b2f1ab58SBarry Smith       }
409b2f1ab58SBarry Smith 
410c328eeadSBarry Smith       /* Now, fill in */
411b2f1ab58SBarry Smith       r_icol[r_nnz] = i;
412b2f1ab58SBarry Smith       r_val [r_nnz] = 1.0;
413b2f1ab58SBarry Smith       r_nnz++;
414b2f1ab58SBarry Smith       retval.row_nnz[i]++;
415b2f1ab58SBarry Smith 
416b2f1ab58SBarry Smith       retval.nnz += r_nnz;
417b2f1ab58SBarry Smith 
418c328eeadSBarry Smith       /* Calculate
419c328eeadSBarry Smith          val(i+1:n) = (A(i,i+1:n)- L(0:i-1,i+1:n)' * lvec)/diag(i) */
420b2f1ab58SBarry Smith       for (j=1; j<p_nnz; j++)
421b2f1ab58SBarry Smith       {
422b2f1ab58SBarry Smith          k = i+p_icol[j];
423b2f1ab58SBarry Smith          r1_icol = retval.icols[k];
424b2f1ab58SBarry Smith          r1_val  = retval.values[k];
425b2f1ab58SBarry Smith          for (jL=0; jL<retval.row_nnz[k]; jL++)
426b2f1ab58SBarry Smith          {
427b2f1ab58SBarry Smith             val[k] -= r1_val[jL] * lvec[r1_icol[jL]];
428b2f1ab58SBarry Smith          }
429b2f1ab58SBarry Smith          val[k] /= diag[i];
430b2f1ab58SBarry Smith 
431d36aa34eSBarry Smith          if (PetscAbsScalar(val[k]) > droptol || PetscAbsScalar(val[k])< -droptol)
432b2f1ab58SBarry Smith          {
433c328eeadSBarry Smith 	   /* If necessary, allocate arrays */
434b2f1ab58SBarry Smith             if (retval.row_nnz[k]==0)
435b2f1ab58SBarry Smith             {
436*9ccc4a9bSBarry Smith                ierr = spbas_cholesky_row_alloc( retval, k, max_row_nnz[k], &n_alloc_used);
437*9ccc4a9bSBarry Smith                if (ierr == PETSC_ERR_MEM) {
438*9ccc4a9bSBarry Smith                   ierr = spbas_cholesky_garbage_collect( &retval,  i, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
439*9ccc4a9bSBarry Smith                   ierr = spbas_cholesky_row_alloc( retval, k, max_row_nnz[k], &n_alloc_used);CHKERRQ(ierr);
440b2f1ab58SBarry Smith                   r_icol = retval.icols[i];
441b2f1ab58SBarry Smith                   r_val  = retval.values[i];
442b2f1ab58SBarry Smith                }
443b2f1ab58SBarry Smith             }
444b2f1ab58SBarry Smith 
445b2f1ab58SBarry Smith             retval.icols[k][retval.row_nnz[k]] = i;
446b2f1ab58SBarry Smith             retval.values[k][retval.row_nnz[k]] = val[k];
447b2f1ab58SBarry Smith             retval.row_nnz[k]++;
448b2f1ab58SBarry Smith          }
449b2f1ab58SBarry Smith          val[k] = 0;
450b2f1ab58SBarry Smith       }
451b2f1ab58SBarry Smith 
45271d55d18SBarry Smith       /*Erase the values used in the work arrays */
453b2f1ab58SBarry Smith       for (j=0; j<r_nnz; j++) { lvec[r_icol[j]] = 0; }
454b2f1ab58SBarry Smith    }
455b2f1ab58SBarry Smith 
456*9ccc4a9bSBarry Smith    ierr=PetscFree(lvec);CHKERRQ(ierr);
457*9ccc4a9bSBarry Smith    ierr=PetscFree(val);CHKERRQ(ierr);
458b2f1ab58SBarry Smith 
459*9ccc4a9bSBarry Smith    ierr = spbas_cholesky_garbage_collect( &retval, nrows, &n_row_alloc_ok, &n_alloc_used, max_row_nnz);CHKERRQ(ierr);
460b2f1ab58SBarry Smith    ierr=PetscFree(max_row_nnz);CHKERRQ(ierr);
461b2f1ab58SBarry Smith 
462c328eeadSBarry Smith    /* Place the inverse of the diagonals in the matrix */
463*9ccc4a9bSBarry Smith    for (i=0; i<nrows; i++) {
464b2f1ab58SBarry Smith       r_nnz = retval.row_nnz[i];
465b2f1ab58SBarry Smith       retval.values[i][r_nnz-1] = 1.0 / diag[i];
466*9ccc4a9bSBarry Smith       for (j=0; j<r_nnz-1; j++) {
467b2f1ab58SBarry Smith          retval.values[i][j] *= -1;
468b2f1ab58SBarry Smith       }
469b2f1ab58SBarry Smith    }
470b2f1ab58SBarry Smith    ierr=PetscFree(diag);CHKERRQ(ierr);
471b2f1ab58SBarry Smith    *matrix_L = retval;
472b2f1ab58SBarry Smith    PetscFunctionReturn(0);
473b2f1ab58SBarry Smith }
474b2f1ab58SBarry Smith 
475