1 2 /* 3 spbas_cholesky_row_alloc: 4 in the data arrays, find a place where another row may be stored. 5 Return PETSC_ERR_MEM if there is insufficient space to store the 6 row, so garbage collection and/or re-allocation may be done. 7 */ 8 #undef __FUNCT__ 9 #define __FUNCT__ "spbas_cholesky_row_alloc" 10 PetscErrorCode spbas_cholesky_row_alloc(spbas_matrix retval, PetscInt k, PetscInt r_nnz,PetscInt * n_alloc_used) 11 { 12 PetscFunctionBegin; 13 retval.icols[k] = &retval.alloc_icol[*n_alloc_used]; 14 retval.values[k] = &retval.alloc_val[*n_alloc_used]; 15 *n_alloc_used += r_nnz; 16 if (*n_alloc_used > retval.n_alloc_icol) 17 { 18 PetscFunctionReturn(PETSC_ERR_MEM); 19 } 20 else 21 { 22 PetscFunctionReturn(0); 23 } 24 } 25 26 27 /* 28 spbas_cholesky_garbage_collect: 29 move the rows which have been calculated so far, as well as 30 those currently under construction, to the front of the 31 array, while putting them in the proper order. 32 When it seems necessary, enlarge the current arrays. 33 34 NB: re-allocation is being simulated using 35 PetscMalloc, memcpy, PetscFree, because 36 PetscRealloc does not seem to exist. 37 38 */ 39 #undef __FUNCT__ 40 #define __FUNCT__ "spbas_cholesky_garbage_collect" 41 PetscErrorCode spbas_cholesky_garbage_collect( 42 spbas_matrix * result, // I/O: the Cholesky factor matrix being constructed. 43 // Only the storage, not the contents of this matrix 44 // is changed in this function 45 PetscInt i_row, // I : Number of rows for which the final contents are 46 // known 47 PetscInt *n_row_alloc_ok, // I/O: Number of rows which are already in their final 48 // places in the arrays: they need not be moved any more 49 PetscInt *n_alloc_used, // I/O: 50 PetscInt *max_row_nnz // I : Over-estimate of the number of nonzeros needed to 51 // store each row 52 ) 53 { 54 55 #undef garbage_debug 56 57 // PSEUDO-CODE: 58 // 1. Choose the appropriate size for the arrays 59 // 2. Rescue the arrays which would be lost during garbage collection 60 // 3. Reallocate and correct administration 61 // 4. Move all arrays so that they are in proper order 62 63 PetscInt i,j; 64 PetscInt nrows = result->nrows; 65 PetscInt n_alloc_ok=0; 66 PetscInt n_alloc_ok_max=0; 67 68 PetscErrorCode ierr; 69 PetscInt need_already= 0; 70 PetscInt n_rows_ahead=0; 71 PetscInt max_need_extra= 0; 72 PetscInt n_alloc_max, n_alloc_est, n_alloc; 73 PetscInt n_alloc_now = result->n_alloc_icol; 74 PetscInt *alloc_icol_old = result->alloc_icol; 75 PetscScalar *alloc_val_old = result->alloc_val; 76 PetscInt *icol_rescue; 77 PetscScalar *val_rescue; 78 PetscInt n_rescue; 79 PetscInt n_row_rescue; 80 PetscInt i_here, i_last, n_copy; 81 const PetscScalar xtra_perc = 20; 82 83 PetscFunctionBegin; 84 85 //********************************************************* 86 // 1. Choose appropriate array size 87 // Count number of rows and memory usage which is already final 88 for (i=0;i<i_row; i++) 89 { 90 n_alloc_ok += result->row_nnz[i]; 91 n_alloc_ok_max += max_row_nnz[i]; 92 } 93 94 // Count currently needed memory usage and future memory requirements 95 // (max, predicted) 96 for (i=i_row; i<nrows; i++) 97 { 98 if (result->row_nnz[i]==0) 99 { 100 max_need_extra += max_row_nnz[i]; 101 } 102 else 103 { 104 need_already += max_row_nnz[i]; 105 n_rows_ahead++; 106 } 107 } 108 109 // Make maximal and realistic memory requirement estimates 110 n_alloc_max = n_alloc_ok + need_already + max_need_extra; 111 n_alloc_est = n_alloc_ok + need_already + (int) 112 ((PetscScalar) max_need_extra * 113 (PetscScalar) n_alloc_ok / 114 (PetscScalar) n_alloc_ok_max); 115 116 // Choose array sizes 117 if (n_alloc_max == n_alloc_est) 118 { n_alloc = n_alloc_max; } 119 else if (n_alloc_now >= n_alloc_est) 120 { n_alloc = n_alloc_now; } 121 else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0)) 122 { n_alloc = n_alloc_max; } 123 else 124 { n_alloc = (int) (n_alloc_est * (1+xtra_perc/100.0)); } 125 126 // If new estimate is less than what we already have, 127 // don't reallocate, just garbage-collect 128 if (n_alloc_max != n_alloc_est && n_alloc < result->n_alloc_icol) 129 { 130 n_alloc = result->n_alloc_icol; 131 } 132 133 #ifdef garbage_debug 134 // Print allocation considerations 135 printf(" + Final version of rows 1..%d is available\n",i_row); 136 printf(" They have %d nonzeros: %6.2f per row\n",n_alloc_ok, 137 (PetscScalar) n_alloc_ok / (PetscScalar)i_row); 138 printf(" Without droptol, I would have had %d nonzeros\n", 139 n_alloc_ok_max); 140 printf(" So I use %6.2f%% of the allowed sparseness\n", 141 100.0 * (PetscScalar) n_alloc_ok / 142 (PetscScalar) n_alloc_ok_max); 143 printf(" + I have %d rows for which I need full sparseness pattern\n", 144 n_rows_ahead); 145 printf(" They require %d nonzeros\n", 146 need_already); 147 printf(" + After that, I shall need %d more rows\n", 148 nrows-n_rows_ahead-i_row); 149 printf(" Maximally, I will need %d nonzeros there\n", 150 max_need_extra); 151 printf(" Realistically, I expect to need %6.2f nonzeros there\n", 152 (PetscScalar) max_need_extra * 153 (PetscScalar) n_alloc_ok / 154 (PetscScalar) n_alloc_ok_max); 155 printf(" + New allocated arrays should be %d (max) or %d (realistic) long\n", 156 n_alloc_max, n_alloc_est); 157 158 #endif 159 // Motivate dimension choice 160 printf(" Allocating %d nonzeros: ",n_alloc); 161 if (n_alloc_max == n_alloc_est) 162 { printf("this is the correct size\n"); } 163 else if (n_alloc_now >= n_alloc_est) 164 { printf("the current size, which seems enough\n"); } 165 else if (n_alloc_max < n_alloc_est * (1+xtra_perc/100.0)) 166 { printf("the maximum estimate\n"); } 167 else 168 { printf("%6.2f %% more than the estimate\n",xtra_perc); } 169 170 171 //********************************************************* 172 // 2. Rescue arrays which would be lost 173 // Count how many rows and nonzeros will have to be rescued 174 // when moving all arrays in place 175 n_row_rescue = 0; n_rescue = 0; 176 if (*n_row_alloc_ok==0) { *n_alloc_used = 0; } 177 else 178 { 179 i = *n_row_alloc_ok - 1; 180 *n_alloc_used = (result->icols[i]-result->alloc_icol) + 181 result->row_nnz[i]; 182 } 183 184 #ifdef garbage_debug 185 printf("\n\n"); 186 printf("Rows 0..%d are already OK\n", *n_row_alloc_ok); 187 printf("Rows 0..%d have the right dimensions\n", i_row-1); 188 #endif 189 190 for (i=*n_row_alloc_ok; i<nrows; i++) 191 { 192 i_here = result->icols[i]-result->alloc_icol; 193 i_last = i_here + result->row_nnz[i]; 194 if (result->row_nnz[i]>0) 195 { 196 if (*n_alloc_used > i_here || i_last > n_alloc) 197 { 198 n_rescue += result->row_nnz[i]; 199 n_row_rescue++; 200 //printf(" Rescue row %d: %d nonzeros\n",i,result->row_nnz[i]); 201 //printf(" (New start at %d, old start at %d)\n", 202 // *n_alloc_used, i_here); 203 } 204 205 if (i<i_row) { *n_alloc_used += result->row_nnz[i];} 206 else { *n_alloc_used += max_row_nnz[i];} 207 } 208 } 209 210 #ifdef garbage_debug 211 printf(" + %d arrays will have to be rescued: %d nnz\n", 212 n_row_rescue, n_rescue); 213 #endif 214 215 // Allocate rescue arrays 216 ierr = PetscMalloc( n_rescue * sizeof(int), &icol_rescue); 217 CHKERRQ(ierr); 218 ierr = PetscMalloc( n_rescue * sizeof(PetscScalar), &val_rescue); 219 CHKERRQ(ierr); 220 221 // Rescue the arrays which need rescuing 222 n_row_rescue = 0; n_rescue = 0; 223 if (*n_row_alloc_ok==0) { *n_alloc_used = 0; } 224 else 225 { 226 i = *n_row_alloc_ok - 1; 227 *n_alloc_used = (result->icols[i]-result->alloc_icol) + 228 result->row_nnz[i]; 229 } 230 231 for (i=*n_row_alloc_ok; i<nrows; i++) 232 { 233 i_here = result->icols[i]-result->alloc_icol; 234 i_last = i_here + result->row_nnz[i]; 235 if (result->row_nnz[i]>0) 236 { 237 if (*n_alloc_used > i_here || i_last > n_alloc) 238 { 239 //printf(" Rescuing row %d to array[%d..]\n",i,n_rescue); 240 memcpy((void*) &icol_rescue[n_rescue], 241 (void*) result->icols[i], 242 result->row_nnz[i] * sizeof(int)); 243 memcpy((void*) &val_rescue[n_rescue], 244 (void*) result->values[i], 245 result->row_nnz[i] * sizeof(PetscScalar)); 246 n_rescue += result->row_nnz[i]; 247 n_row_rescue++; 248 } 249 250 if (i<i_row) { *n_alloc_used += result->row_nnz[i];} 251 else { *n_alloc_used += max_row_nnz[i];} 252 } 253 } 254 255 //********************************************************* 256 // 3. Reallocate and correct administration 257 258 if (n_alloc != result->n_alloc_icol) 259 { 260 n_copy = MIN(n_alloc,result->n_alloc_icol); 261 262 // PETSC knows no REALLOC, so we'll REALLOC ourselves. 263 264 // Allocate new icol-data, copy old contents 265 ierr = PetscMalloc( n_alloc * sizeof(int), 266 &result->alloc_icol); CHKERRQ(ierr); 267 memcpy(result->alloc_icol, alloc_icol_old, n_copy*sizeof(int)); 268 269 // Update administration, Reset pointers to new arrays 270 result->n_alloc_icol = n_alloc; 271 for (i=0; i<nrows; i++) 272 { 273 result->icols[i] = result->alloc_icol + 274 (result->icols[i] - alloc_icol_old); 275 result->values[i] = result->alloc_val + 276 (result->icols[i] - result->alloc_icol); 277 } 278 279 // Delete old array 280 ierr = PetscFree(alloc_icol_old); CHKERRQ(ierr); 281 282 // Allocate new value-data, copy old contents 283 ierr = PetscMalloc( n_alloc * sizeof(PetscScalar), 284 &result->alloc_val); CHKERRQ(ierr); 285 memcpy(result->alloc_val, alloc_val_old, n_copy*sizeof(PetscScalar)); 286 287 // Update administration, Reset pointers to new arrays 288 result->n_alloc_val = n_alloc; 289 for (i=0; i<nrows; i++) 290 { 291 result->values[i] = result->alloc_val + 292 (result->icols[i] - result->alloc_icol); 293 } 294 295 // Delete old array 296 ierr = PetscFree(alloc_val_old); CHKERRQ(ierr); 297 } 298 299 300 //********************************************************* 301 // 4. Copy all the arrays to their proper places 302 n_row_rescue = 0; n_rescue = 0; 303 if (*n_row_alloc_ok==0) { *n_alloc_used = 0; } 304 else 305 { 306 i = *n_row_alloc_ok - 1; 307 *n_alloc_used = (result->icols[i]-result->alloc_icol) + 308 result->row_nnz[i]; 309 } 310 311 for (i=*n_row_alloc_ok; i<nrows; i++) 312 { 313 i_here = result->icols[i]-result->alloc_icol; 314 i_last = i_here + result->row_nnz[i]; 315 316 result->icols[i] = result->alloc_icol + *n_alloc_used; 317 result->values[i]= result->alloc_val + *n_alloc_used; 318 319 if (result->row_nnz[i]>0) 320 { 321 if (*n_alloc_used > i_here || i_last > n_alloc) 322 { 323 //printf(" Copying rescued array[%d..] to row %d\n", 324 // n_rescue,i); 325 //fflush(stdout); 326 memcpy((void*) result->icols[i], 327 (void*) &icol_rescue[n_rescue], 328 result->row_nnz[i] * sizeof(int)); 329 memcpy((void*) result->values[i], 330 (void*) &val_rescue[n_rescue], 331 result->row_nnz[i] * sizeof(PetscScalar)); 332 n_rescue += result->row_nnz[i]; 333 n_row_rescue++; 334 } 335 else 336 { 337 for (j=0; j<result->row_nnz[i]; j++) 338 { 339 result->icols[i][j] = result->alloc_icol[i_here+j]; 340 result->values[i][j] = result->alloc_val[ i_here+j]; 341 } 342 } 343 if (i<i_row) { *n_alloc_used += result->row_nnz[i];} 344 else { *n_alloc_used += max_row_nnz[i];} 345 } 346 } 347 348 // Delete the rescue arrays 349 ierr = PetscFree(icol_rescue); CHKERRQ(ierr); 350 ierr = PetscFree(val_rescue); CHKERRQ(ierr); 351 *n_row_alloc_ok = i_row; 352 353 PetscFunctionReturn(0); 354 355 } 356 357 /* 358 spbas_incomplete_cholesky: 359 incomplete Cholesky decomposition of a square, symmetric, 360 positive definite matrix. 361 362 In case negative diagonals are encountered, function returns 363 NEGATIVE_DIAGONAL. When this happens, call this function again 364 with a larger epsdiag_in, a less sparse pattern, and/or a smaller 365 droptol 366 */ 367 #undef __FUNCT__ 368 #define __FUNCT__ "spbas_incomplete_cholesky" 369 PetscErrorCode spbas_incomplete_cholesky( 370 Mat A, const PetscInt *rip, const PetscInt *riip, 371 spbas_matrix pattern, 372 PetscScalar droptol, PetscScalar epsdiag_in, 373 spbas_matrix * matrix_L) 374 { 375 376 #undef cholesky_debug 377 378 #ifdef cholesky_debug 379 PetscInt idebug=0; 380 const char * fmt= " (%d,%d) -> %12.8e\n"; 381 PetscScalar tmp; 382 #endif 383 384 PetscInt jL; 385 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data; 386 PetscInt *ai=a->i,*aj=a->j; 387 MatScalar *aa=a->a; 388 PetscInt nrows, ncols; 389 PetscInt *max_row_nnz; 390 PetscErrorCode ierr; 391 spbas_matrix retval; 392 PetscScalar * diag; 393 PetscScalar * val; 394 PetscScalar * lvec; 395 PetscScalar epsdiag; 396 PetscInt i,j,k; 397 const PetscTruth do_values = PETSC_TRUE; 398 PetscInt * r1_icol; PetscScalar *r1_val; 399 PetscInt * r_icol; PetscInt r_nnz; PetscScalar *r_val; 400 PetscInt * A_icol; PetscInt A_nnz; PetscScalar *A_val; 401 PetscInt * p_icol; PetscInt p_nnz; 402 PetscInt n_row_alloc_ok = 0; // number of rows which have been stored 403 // correctly in the matrix 404 PetscInt n_alloc_used = 0; // part of result->icols and result->values 405 // which is currently being used 406 PetscFunctionBegin; 407 408 // Convert the Manteuffel shift from 'fraction of average diagonal' to 409 // dimensioned value 410 ierr = MatGetSize(A, &nrows, &ncols); CHKERRQ(ierr); 411 ierr = MatGetTrace(A, &epsdiag); CHKERRQ(ierr); 412 epsdiag *= epsdiag_in / nrows; 413 printf(" Dimensioned Manteuffel shift=%e\n", epsdiag); 414 printf(" Drop tolerance =%e\n",droptol); 415 416 if (droptol<1e-10) {droptol=1e-10;} 417 418 // Check dimensions 419 if ( (nrows != pattern.nrows) || 420 (ncols != pattern.ncols) || 421 (ncols != nrows) ) 422 { 423 SETERRQ( PETSC_ERR_ARG_INCOMP, 424 "Dimension error in spbas_incomplete_cholesky\n"); 425 } 426 427 // Set overall values 428 retval.nrows = nrows; 429 retval.ncols = nrows; 430 retval.nnz = pattern.nnz/10; 431 retval.col_idx_type = SPBAS_COLUMN_NUMBERS; 432 retval.block_data = PETSC_TRUE; 433 434 // Allocate sparseness pattern 435 ierr = spbas_allocate_pattern(&retval, do_values); CHKERRQ(ierr); 436 // Initial allocation of data 437 memset((void*) retval.row_nnz, 0, nrows*sizeof(int)); 438 ierr = spbas_allocate_data(&retval); CHKERRQ(ierr); 439 retval.nnz = 0; 440 441 // Allocate work arrays 442 ierr = PetscMalloc(nrows*sizeof(PetscScalar), &diag); CHKERRQ(ierr); 443 ierr = PetscMalloc(nrows*sizeof(PetscScalar), &val); CHKERRQ(ierr); 444 ierr = PetscMalloc(nrows*sizeof(PetscScalar), &lvec); CHKERRQ(ierr); 445 ierr = PetscMalloc(nrows*sizeof(int), &max_row_nnz); CHKERRQ(ierr); 446 if (!(diag && val && lvec && max_row_nnz)) 447 { 448 SETERRQ( PETSC_ERR_MEM, 449 "Allocation error in spbas_incomplete_cholesky\n"); 450 } 451 452 memset((void*) val, 0, nrows*sizeof(PetscScalar)); 453 memset((void*) lvec, 0, nrows*sizeof(PetscScalar)); 454 memset((void*) max_row_nnz, 0, nrows*sizeof(int)); 455 456 // Check correct format of sparseness pattern 457 if (pattern.col_idx_type != SPBAS_DIAGONAL_OFFSETS) 458 { 459 SETERRQ( PETSC_ERR_SUP_SYS, 460 "Error in spbas_incomplete_cholesky: must have diagonal offsets in pattern\n"); 461 } 462 463 // Count the nonzeros on transpose of pattern 464 for (i = 0; i<nrows; i++) 465 { 466 p_nnz = pattern.row_nnz[i]; 467 p_icol = pattern.icols[i]; 468 for (j=0; j<p_nnz; j++) 469 { 470 max_row_nnz[i+p_icol[j]]++; 471 } 472 } 473 474 // Calculate rows of L 475 for (i = 0; i<nrows; i++) 476 { 477 p_nnz = pattern.row_nnz[i]; 478 p_icol = pattern.icols[i]; 479 480 r_nnz = retval.row_nnz[i]; 481 r_icol = retval.icols[i]; 482 r_val = retval.values[i]; 483 A_nnz = ai[rip[i]+1] - ai[rip[i]]; 484 A_icol = &aj[ai[rip[i]]]; 485 A_val = &aa[ai[rip[i]]]; 486 487 // Calculate val += A(i,i:n)'; 488 for (j=0; j<A_nnz; j++) 489 { 490 k = riip[A_icol[j]]; 491 if (k>=i) { val[k] = A_val[j]; } 492 } 493 494 // Add regularization 495 val[i] += epsdiag; 496 497 // Calculate lvec = diag(D(0:i-1)) * L(0:i-1,i); 498 // val(i) = A(i,i) - L(0:i-1,i)' * lvec 499 for ( j=0; j<r_nnz; j++) 500 { 501 k = r_icol[j]; 502 lvec[k] = diag[k] * r_val[j]; 503 val[i] -= r_val[j] * lvec[k]; 504 } 505 506 // Calculate the new diagonal 507 diag[i] = val[i]; 508 if (diag[i]<droptol) 509 { 510 printf("Error in spbas_incomplete_cholesky:\n"); 511 printf("Negative diagonal in row %d\n",i+1); 512 513 // Delete the whole matrix at once. 514 ierr = spbas_delete(retval); 515 return NEGATIVE_DIAGONAL; 516 } 517 518 #ifdef cholesky_debug 519 if (idebug>=3) 520 { 521 printf("diagD * L (%d,:)=\n",i+1); 522 for (j=0; j<r_nnz; j++) 523 { 524 printf(fmt,r_icol[j]+1,i+1,lvec[r_icol[j]]); 525 } 526 printf("\n\n"); 527 } 528 529 if (idebug>=1) { printf("Diag = %12.8e\n\n\n",diag[i]);} 530 531 if (idebug>=2) 532 { 533 printf("L^T * diagD * L=\n"); 534 tmp = 0.0; 535 for ( j=0; j<r_nnz; j++) 536 { 537 k = r_icol[j]; 538 tmp += r_val[j] * lvec[k]; 539 } 540 printf(fmt, i+1,i+1,tmp); 541 } 542 #endif 543 544 // If necessary, allocate arrays 545 if (r_nnz==0) 546 { 547 ierr = spbas_cholesky_row_alloc( retval, i, 1, &n_alloc_used); 548 if (ierr == PETSC_ERR_MEM) 549 { 550 ierr = spbas_cholesky_garbage_collect( &retval, i, &n_row_alloc_ok, 551 &n_alloc_used, max_row_nnz); 552 CHKERRQ(ierr); 553 ierr = spbas_cholesky_row_alloc( retval, i, 1, &n_alloc_used); 554 } 555 CHKERRQ(ierr); 556 r_icol = retval.icols[i]; 557 r_val = retval.values[i]; 558 } 559 560 // Now, fill in 561 r_icol[r_nnz] = i; 562 r_val [r_nnz] = 1.0; 563 r_nnz++; 564 retval.row_nnz[i]++; 565 566 retval.nnz += r_nnz; 567 568 // Calculate 569 // val(i+1:n) = (A(i,i+1:n)- L(0:i-1,i+1:n)' * lvec)/diag(i) 570 for (j=1; j<p_nnz; j++) 571 { 572 k = i+p_icol[j]; 573 r1_icol = retval.icols[k]; 574 r1_val = retval.values[k]; 575 #ifdef cholesky_debug 576 tmp = 0.0; 577 #endif 578 for (jL=0; jL<retval.row_nnz[k]; jL++) 579 { 580 val[k] -= r1_val[jL] * lvec[r1_icol[jL]]; 581 #ifdef cholesky_debug 582 tmp += r1_val[jL] * lvec[r1_icol[jL]]; 583 #endif 584 } 585 #ifdef cholesky_debug 586 if (idebug>=2 && tmp!=0) {printf(fmt, k+1,i+1,tmp);} 587 #endif 588 val[k] /= diag[i]; 589 590 if (val[k] > droptol || val[k]< -droptol) 591 { 592 // If necessary, allocate arrays 593 if (retval.row_nnz[k]==0) 594 { 595 ierr = spbas_cholesky_row_alloc( retval, k, max_row_nnz[k], 596 &n_alloc_used); 597 if (ierr == PETSC_ERR_MEM) 598 { 599 ierr = spbas_cholesky_garbage_collect( 600 &retval, i, &n_row_alloc_ok, 601 &n_alloc_used, max_row_nnz); 602 CHKERRQ(ierr); 603 ierr = spbas_cholesky_row_alloc( retval, k, max_row_nnz[k], 604 &n_alloc_used); 605 r_icol = retval.icols[i]; 606 r_val = retval.values[i]; 607 } 608 CHKERRQ(ierr); 609 } 610 611 // Now, fill in 612 retval.icols[k][retval.row_nnz[k]] = i; 613 retval.values[k][retval.row_nnz[k]] = val[k]; 614 retval.row_nnz[k]++; 615 } 616 val[k] = 0; 617 } 618 #ifdef cholesky_debug 619 if (idebug>=2) {printf("\n\n");} 620 #endif 621 622 // Erase the values used in the work arrays 623 for (j=0; j<r_nnz; j++) { lvec[r_icol[j]] = 0; } 624 625 #ifdef cholesky_debug 626 if (idebug>=2) 627 { 628 printf("new L=\n"); 629 for (jL=i; jL<nrows; jL++) 630 { 631 j = retval.row_nnz[jL]-1; 632 if (j>=0) 633 { 634 k = retval.icols[jL][j]; 635 if (k==i) printf(fmt, jL+1,i+1,retval.values[jL][j]); 636 } 637 } 638 printf("\n\n"); 639 } 640 #endif 641 } 642 643 ierr=PetscFree(lvec); CHKERRQ(ierr); ierr=PetscFree(val); CHKERRQ(ierr); 644 645 ierr = spbas_cholesky_garbage_collect( &retval, nrows, &n_row_alloc_ok, 646 &n_alloc_used, max_row_nnz); 647 ierr=PetscFree(max_row_nnz); CHKERRQ(ierr); 648 649 // Place the inverse of the diagonals in the matrix 650 for (i=0; i<nrows; i++) 651 { 652 r_nnz = retval.row_nnz[i]; 653 retval.values[i][r_nnz-1] = 1.0 / diag[i]; 654 for (j=0; j<r_nnz-1; j++) 655 { 656 retval.values[i][j] *= -1; 657 } 658 } 659 ierr=PetscFree(diag); CHKERRQ(ierr); 660 661 662 // Return successfully 663 *matrix_L = retval; 664 665 #ifdef cholesky_debug 666 for (i = 0; i<nrows; i++) 667 { 668 printf("Row %d\n",i+1); 669 for (j=0; j<retval.row_nnz[i]; j++) 670 { 671 printf(fmt, i+1,retval.icols[i][j]+1,retval.values[i][j]); 672 } 673 } 674 #endif 675 PetscFunctionReturn(0); 676 } 677 678