int AZ_adjust_N_nz_to_fit_memory(int N,int N_int_arrays, int N_dbl_arrays) { /**************************************************************************** Find (and return) the largest value of k <= N such that we can successfully allocate N_int_arrays integer arrays of size k and N_dbl_arrays double arrays of size k. Author: Ray Tuminaro, SNL, 9222 Return code: int ============ Parameter list: =============== N: On input, the maximum number of integers and doubles that we wish to try and allocate. */ double **dptr; int **iptr; int i; iptr = (int **) AZ_allocate(N_int_arrays*sizeof(int *)); dptr = (double **) AZ_allocate(N_dbl_arrays*sizeof(double *)); if ( (dptr == 0) || (iptr == 0) ) AZ_perror("ERROR: not enough memory for preconditioner.\n"); for (i = 0 ; i < N_int_arrays ; i++ ) iptr[i] = (int *) AZ_allocate((N+20)*sizeof(int)); for (i = 0 ; i < N_dbl_arrays ; i++ ) dptr[i] = (double *) AZ_allocate((N+20)*sizeof(double)); /* add a little extra */ /* for manage memory */ /* Decrease memory until the problem fits */ while ( (dptr[N_dbl_arrays-1] == NULL) || (iptr[N_int_arrays-1] == NULL) ) { for (i = N_dbl_arrays-1 ; i >= 0; i-- ) if (dptr[i] != NULL) AZ_free(dptr[i]); for (i = N_int_arrays-1 ; i >= 0; i-- ) if (iptr[i] != NULL) AZ_free(iptr[i]); N = (int) ( ((double) N)*.91); if (N == 0) AZ_perror("ERROR: not enough memory for preconditioner.\n"); for (i = 0 ; i < N_int_arrays ; i++ ) iptr[i] = (int *) AZ_allocate((N+20)*sizeof(int)); for (i = 0 ; i < N_dbl_arrays ; i++ ) dptr[i] = (double *) AZ_allocate((N+20)*sizeof(double)); } for (i = N_dbl_arrays-1 ; i >= 0; i-- ) AZ_free(dptr[i]); for (i = N_int_arrays-1 ; i >= 0; i-- ) AZ_free(iptr[i]); AZ_free(dptr); AZ_free(iptr); return(N); }
void AZK_create_vector_c2k(int *options, double *params, int *proc_config, AZ_MATRIX *Amat_komplex, double *vc, double **vk) { AZ_KOMPLEX *linsys_pass_data; int i; int N_equations, N_external; int *data_org, *rpntr, *update_index; /* First executable statement */ linsys_pass_data = (AZ_KOMPLEX *) Amat_komplex->aux_ptr; data_org = Amat_komplex->data_org; update_index = linsys_pass_data->update_index; rpntr = Amat_komplex->rpntr; N_equations = data_org[AZ_N_internal] + data_org[AZ_N_border]; N_external = data_org[AZ_N_external]; (*vk) = (double *) AZ_allocate((N_equations+N_external)*sizeof(double)); if ((*vk) == NULL) AZ_perror("AZK_create_vector_c2k: Out of memory"); for (i=0; i <N_equations; i++) (*vk)[i] = vc[i]; /* Check if we need to reorder vector */ if (linsys_pass_data->From_Global_Indices) AZ_reorder_vec((*vk), data_org, update_index, rpntr); return; }
void AZK_create_linsys_no_copy(double *xr, double *xi, double *br, double *bi, int *options, double *params, int *proc_config, AZ_MATRIX *Amat_real, AZ_MATRIX *Amat_imag, double **x, double **b, AZ_MATRIX **Amat) { /* Transforms a complex-valued system (Ar +i*Ai) * (xr + i*xi) = (br + i*bi) where double precision arrays hold the real and imaginary parts separately. Input arguments: ================ xr,xi: On input, contains the initial guess, real part in xr and imaginary part in xi. On output contains the solution to the linear system. br,bi: Right hand side of linear system. Output arguments: ================= x: Komplex version of initial guess and solution. b: Komplex version of RHS. Amat: Komplex version of matrix stored as an AZ_MATRIX structure. */ AZ_KOMPLEX *linsys_pass_data; int N_equations, N_blk_equations, N_real, N_external; int *data_org_real, *data_org_imag; int *komplex_to_real, *komplex_to_imag; int i; if (Amat_real->has_global_indices || Amat_imag->has_global_indices) AZ_perror("AZK_create_linsys_no_copy requires local indices"); linsys_pass_data = (AZ_KOMPLEX *) AZ_allocate(sizeof(AZ_KOMPLEX)); if (linsys_pass_data == NULL) AZ_perror("AZK_create_linsys_no_copy: Out of memory."); data_org_real = Amat_real->data_org; data_org_imag = Amat_imag->data_org; N_real = data_org_real[AZ_N_internal] + data_org_real[AZ_N_border]; N_equations = 2 * N_real; N_blk_equations = N_equations; N_external = AZ_MAX(data_org_real[AZ_N_external], data_org_imag[AZ_N_external]); if (Amat_real->matrix_type == AZ_MSR_MATRIX) { Amat_real->data_org[AZ_N_int_blk] = Amat_real->data_org[AZ_N_internal]; Amat_real->data_org[AZ_N_bord_blk] = Amat_real->data_org[AZ_N_border]; N_blk_equations = N_equations; } else if (Amat_real->matrix_type == AZ_VBR_MATRIX) { N_blk_equations = data_org_real[AZ_N_int_blk] + data_org_real[AZ_N_bord_blk]; } else if (Amat_real->matrix_type == AZ_USER_MATRIX) { Amat_real->data_org[AZ_N_int_blk] = Amat_real->data_org[AZ_N_internal]; Amat_real->data_org[AZ_N_bord_blk] = Amat_real->data_org[AZ_N_border]; N_blk_equations = N_equations; } else AZ_perror("AZK_create_linsys_no_copy: Unknown matrix type."); if (Amat_imag->matrix_type == AZ_MSR_MATRIX) { Amat_imag->data_org[AZ_N_int_blk] = Amat_imag->data_org[AZ_N_internal]; Amat_imag->data_org[AZ_N_bord_blk] = Amat_imag->data_org[AZ_N_border]; } else if (Amat_imag->matrix_type == AZ_USER_MATRIX) { Amat_imag->data_org[AZ_N_int_blk] = Amat_imag->data_org[AZ_N_internal]; Amat_imag->data_org[AZ_N_bord_blk] = Amat_imag->data_org[AZ_N_border]; } (*Amat) = AZ_create_matrix(N_equations, 0, AZ_USER_MATRIX, N_blk_equations, AZ_NOT_USING_AZTEC_MATVEC); /* Merge real and imaginary parts into K matrix order */ komplex_to_real = (int *) AZ_allocate (N_real*sizeof(int)); komplex_to_imag = (int *) AZ_allocate (N_real*sizeof(int)); (*x) = (double *) AZ_allocate((N_equations+N_external)*sizeof(double)); (*b) = (double *) AZ_allocate((N_equations+N_external)*sizeof(double)); if ((*b) == NULL) AZ_perror("AZK_create_linsys_no_copy: Out of memory."); for (i=0; i <N_real; i++) { komplex_to_real[i] = 2*i; komplex_to_imag[i] = 2*i+1; (*x)[komplex_to_real[i]] = xr[i]; (*x)[komplex_to_imag[i]] = xi[i]; (*b)[komplex_to_real[i]] = br[i]; (*b)[komplex_to_imag[i]] = bi[i]; } linsys_pass_data->Amat_real = Amat_real; linsys_pass_data->Amat_imag = Amat_imag; linsys_pass_data->komplex_to_real = komplex_to_real; linsys_pass_data->komplex_to_imag = komplex_to_imag; linsys_pass_data->c11 = 1.0; linsys_pass_data->c12 = 0.0; linsys_pass_data->c21 = 0.0; linsys_pass_data->c22 = 1.0; linsys_pass_data->Form_of_Equations = AZK_Komplex_No_Copy; linsys_pass_data->From_Global_Indices = 0; (*Amat)->matvec = AZK_matvec_no_copy; (*Amat)->aux_ptr = (void *) linsys_pass_data; return; }
void AZ_space_for_padded_matrix(int overlap, int N_nonzeros, int N, int *extra_rows, int *extra_nonzeros, int N_external, int *largest) { /**************************************************************************** Estimate the number of additional rows and nonzeros due to overlapping. Currently, this estimate is based on the number of external variables and the number of nonzeros per row. Author: Ray Tuminaro, SNL, 9222 Return code: void ============ Parameter list: =============== overlap: On input, == AZ_none: nonoverlapping domain decomposition == AZ_diag: use rows corresponding to external variables but only keep the diagonal for these rows. == k : Obtain rows that are a distance k away from rows owned by this processor. N_nonzeros: On input, number of nonzeros in the unpadded matrix. N: On input, number of rows in the unpadded matrix. extra_rows: On output, estimate of the number of additional rows needed for padding the matrix corresponding to 'overlap'. extra_nonzeros: On output, estimate of the number of additional nonzeros needed for padding the matrix corresponding to 'overlap'. N_external: On input, number of external variables corresponding to the unpadded matrix. largest: On output, estimate of the maximum number of nonzeros in any row due to overlapping. ****************************************************************************/ int i; double new_exts, d_externs; int temp; if ( (overlap == 0) || (overlap == AZ_diag) ) { *extra_rows = N_external; *extra_nonzeros = N_external; *largest = 1; } else if (overlap >= 1) { /* we must estimate in this case */ *extra_rows = (int) 5.5*((double) (N_external*overlap)); d_externs = (double) N_external; new_exts = d_externs; for (i = 2; i <= overlap; i++ ) { new_exts = new_exts + 4.*(sqrt(3.14159*new_exts)+3.14159); /* This formula is based on the growth in */ /* the surface area of a sphere. */ /* S_0 = 4 pi r^2 */ /* S_1 = 4 pi (r+1)^2 */ /* = S_0 + 4 pi + 8 pi r */ /* substitute sqrt(S_0/(4 pi)) for r */ /* S_1 = S_0 + 4 ( pi + sqrt(S_0 pi)) */ d_externs += new_exts; } *extra_rows = (int) d_externs; *extra_rows = (*extra_rows)*2 + 30; if (N != 0) { temp = N_nonzeros/N; *extra_nonzeros = N + (*extra_rows)*temp; *largest = 3.5*N_nonzeros/N; *extra_rows += 25; *extra_nonzeros += 25; *largest += 25; } else { *extra_rows = 0; *extra_nonzeros = 0; *largest = 0; } } else AZ_perror("Inproper level of overlap\n"); }
void AZK_create_precon(int *options, double *params, int *proc_config,double *x, double *b, AZ_MATRIX *Amat, AZ_PRECOND **Prec) { AZ_KOMPLEX *pass_data, *Prec_pass_data; AZ_MATRIX *Pmat, *Amat_real, *Amat_imag; int N_equations, N_real; int *data_org_real, *data_org_imag; double *val; int i, is_VBR; /* Extract necessary data from pass_data */ pass_data = (AZ_KOMPLEX *) Amat->aux_ptr; if (pass_data->Form_of_Equations != AZK_Komplex_No_Copy) (*Prec) = AZ_precond_create(Amat,AZ_precondition,NULL); else { Amat_real = pass_data->Amat_real; /* Real operator in AZ_MATRIX struct */ Amat_imag = pass_data->Amat_imag; /* Imag operator in AZ_MATRIX struct */ data_org_real = Amat_real->data_org; data_org_imag = Amat_imag->data_org; N_real = data_org_real[AZ_N_internal] + data_org_real[AZ_N_border]; N_equations = 2 * N_real; if (data_org_real[AZ_matrix_type] == AZ_VBR_MATRIX && data_org_imag[AZ_matrix_type] == AZ_VBR_MATRIX ) { is_VBR = 1; } else if (data_org_real[AZ_matrix_type] == AZ_MSR_MATRIX && data_org_imag[AZ_matrix_type] == AZ_MSR_MATRIX) { is_VBR = 0; } else { printf("Unsupported Matrix types\n"); abort(); } /* set the preconditioning structure 'Prec'. */ Prec_pass_data = (AZ_KOMPLEX *) AZ_allocate(sizeof(AZ_KOMPLEX)); if (Prec_pass_data == NULL) AZ_perror("AZK_create_precon: Out of memory."); switch (options[AZ_precond]) { /* NO preconditioning. There is nothing to do */ /* We just need to give a valid matrix to the preconditioning */ case AZ_none: (*Prec) = AZ_precond_create(Amat,AZ_precondition,NULL); break; /* Polynomial preconditioning (least-squares or Neumann). */ /* Here we must give Aztec an upper bound for the norm of the */ /* matrix. In addition, we need to tell Aztec to use the */ /* USER's matrix-vector product when applying the polynomial */ /* preconditioner. */ case AZ_ls: case AZ_Neumann: Amat->matrix_norm = 8.0; (*Prec) = AZ_precond_create(Amat,AZ_precondition,NULL); break; /* Jacobi preconditioning. In this case, Aztec needs the */ /* diagonal of the matrix. This can be passed in as an MSR */ /* matrix. However, when using Jacobi, it is important to note*/ /* that the MSR 'bindx' array does not need to be specified. */ /* Only the diagonal needs to be placed in the 'val' array. */ case AZ_Jacobi: if (!is_VBR) { Pmat = AZ_create_matrix(N_equations, AZ_NO_EXTRA_SPACE, AZ_MSR_MATRIX, N_equations, AZ_NOT_USING_AZTEC_MATVEC); val = (double *) AZ_allocate(N_real * sizeof(double)); if (val == NULL) AZ_perror("AZK_create_precon: Out of memory"); for ( i = 0;i < N_real; i++) val[i] = 1.0/(Amat_real->val[i]*Amat_real->val[i] + Amat_imag->val[i]*Amat_imag->val[i]); Pmat->val = val; Pmat->bindx = NULL; Pmat->indx = NULL; Pmat->bpntr = NULL; Pmat->rpntr = NULL; Pmat->cpntr = NULL; (*Prec) = AZ_precond_create(Pmat,AZK_precon,NULL); options[AZ_precond] = AZ_user_precond; Prec_pass_data->AZK_precond = AZ_Jacobi; (*Prec)->Pmat->aux_ptr = (void *) Prec_pass_data; } else { AZ_perror("Jacobi scaling is only supported for MSR matrices"); } break; /* Domain decomposition preconditioning. In this case, Aztec */ /* needs the local matrix defined within the processor. This */ /* can be passed in as an MSR array. Note: since we do not */ /* overlap the subdomains in this specific example, only the */ /* local columns associated with local equations need to be */ /* kept. That is, we drop all references to external variables*/ case AZ_dom_decomp: AZ_perror("AZK_linsys_create_no_copy does not support dom_decomp"); break; default: AZ_perror("AZK_linsys_create_no_copy does not support this option"); } } if (Prec_pass_data) free(Prec_pass_data); Prec_pass_data = NULL; }
void AZ_calc_blk_diag_LU(double *val, int *indx, int *bindx, int *rpntr, int *cpntr, int *bpntr, double *d_inv, int *d_indx, int *d_bindx, int *d_rpntr, int *d_bpntr, int *data_org, int *ipvt) /******************************************************************************* Routine to calculate the LU factors of the block-diagonal portion of sparse matrix in 'val' and the associated integer pointer vectors. This is used for scaling. Author: Scott A. Hutchinson, SNL, 1421 ======= Return code: void ============ Parameter list: =============== val: Array containing the nonzero entries of the matrix (see Aztec User's Guide). indx, bindx, rpntr, cpntr, bpntr: Arrays used for DMSR and DVBR sparse matrix storage (see file Aztec User's Guide). d_inv: Vector containing the LU of the diagonal blocks. d_indx: The 'indx' array corresponding to the LU-block diagonals. d_bindx: The 'bindx' array corresponding to the LU-block diagonals. d_rpntr: The 'rpntr' array corresponding to the LU-block diagonals. d_bpntr: The 'bpntr' array corresponding to the LU-block diagonals. data_org: Array containing information on the distribution of the matrix to this processor as well as communication parameters (see Aztec User's Guide). *******************************************************************************/ { /* local variables */ register int i, j, iblk_row, jblk, icount = 0, iblk_count = 0, ival; int m1, n1, itemp; int m; int bpoff, idoff; int info; double *work; char *yo = "AZ_calc_blk_diag_inv: "; /**************************** execution begins ******************************/ m = data_org[AZ_N_int_blk] + data_org[AZ_N_bord_blk]; if (m == 0) return; /* allocate vectors for lapack routines */ work = (double *) AZ_allocate(rpntr[m]*sizeof(double)); if (work == NULL) AZ_perror("Not enough space for Block Jacobi\n"); /* offset of the first block */ bpoff = *bpntr; idoff = *indx; /* loop over block rows */ for (iblk_row = 0; iblk_row < m; iblk_row++) { /* number of rows in the current row block */ m1 = rpntr[iblk_row+1] - rpntr[iblk_row]; /* starting index of current row block */ ival = indx[bpntr[iblk_row] - bpoff] - idoff; /* loop over column block numbers, looking for the diagonal block */ for (j = bpntr[iblk_row] - bpoff; j < bpntr[iblk_row+1] - bpoff; j++) { jblk = bindx[j]; /* determine the number of columns in this block */ n1 = cpntr[jblk+1] - cpntr[jblk]; itemp = m1*n1; if (jblk == iblk_row) { /* diagonal block */ /* error check */ if (n1 != m1) { (void) AZ_printf_err( "%sERROR: diagonal blocks are not square\n.", yo); exit(-1); } else { /* fill the vectors */ d_indx[iblk_count] = icount; d_rpntr[iblk_count] = rpntr[iblk_row]; d_bpntr[iblk_count] = iblk_row; d_bindx[iblk_count] = iblk_row; for (i = 0; i < itemp; i++) d_inv[icount++] = val[ival + i]; /* invert the dense matrix */ DGETRF_F77(&m1, &m1, &d_inv[d_indx[iblk_count]], &m1, &(ipvt[rpntr[iblk_row]]), &info); if (info < 0) { (void) AZ_printf_err( "%sERROR: argument %d is illegal.\n", yo, -info); exit(-1); } else if (info > 0) { (void) AZ_printf_err( "%sERROR: the factorization has produced a " "singular U with U[%d][%d] being exactly zero.\n", yo, info, info); exit(-1); } iblk_count++; } break; } else ival += itemp; } } d_indx[iblk_count] = icount; d_rpntr[iblk_count] = rpntr[iblk_row]; d_bpntr[iblk_count] = iblk_row; AZ_free((void *) work); } /* AZ_calc_blk_diag_inv */
void AZ_factor_subdomain(struct context *context, int N, int N_nz, int *nz_used) { /**************************************************************************** Given an overlapped subdomain matrix, factor it according to the chosen algorithm and store the result back in subdomain. Additionally, store the number of nonzeros used in the factorization in nz_used. Notes: 1) Matrix comes in as an MSR matrix. 2) context contains several fields which need to be appropriately set. These fields are specific to the individual solvers. 3) The factorization overwrites the matrix. However, different solvers will store the factorization in different formats. Author: Ray Tuminaro, SNL, 9222 (3/98) Return code: void ============ Parameter list: =============== context On input, context contains the matrix to be factored in context.A_overlapped (MSR format), On output, context contains the factored matrix which is stored in a format specific to the solver and any additional parameters required by the backsolver. N On input, the size of the linear system to be solved. N_nz On input, the number of nonzero values in the matrix to be factored. nz_used On output, the number of nonzero values in the matrix representing the factorization. *******************************************************************************/ #ifdef HAVE_AZLU int ifail, N_nz_matrix, *rnr; double *fake_rhs, *aflag; #endif int i, j, *bindx, *bpntr, *iw; double *cr, *unorm, *a, *val; int *ind, *jnz, *ja, ifill; double dtemp = (context->aztec_choices->params)[AZ_omega]; int N_blk_rows, name = context->A_overlapped->data_org[AZ_name]; char str[80]; /* Begin Aztec 2.1 mheroux mod */ #ifdef IFPACK void *precon, *bmat; double rthresh, athresh; int N_int_blk, N_bord_blk, graph_fill; #endif /* End Aztec 2.1 mheroux mod */ bindx = context->A_overlapped->bindx; *nz_used = bindx[N]; switch(context->aztec_choices->options[AZ_subdomain_solve]) { /* Begin Aztec 2.1 mheroux mod */ case AZ_bilu_ifp: #ifdef IFPACK if (N == 0) return; bindx = context->A_overlapped->bindx; val = context->A_overlapped->val; /* for bilu(k) with k > 1 , figure out the new sparsity pattern */ AZ_sort_msr(bindx, val, N); /* Let IFPACK handle fillin */ graph_fill = (context->aztec_choices->options)[AZ_graph_fill]; (context->aztec_choices->options)[AZ_graph_fill] = 0; /* recover some space so that there will */ /* be enough room to convert back to vbr */ i = AZ_compress_msr(&(context->A_overlapped->bindx), &(context->A_overlapped->val), context->N_nz_allocated, *nz_used, name, context); context->N_nz = *nz_used; context->N_nz_allocated = *nz_used; AZ_msr2vbr_mem_efficient(N, &(context->A_overlapped->bindx), &(context->A_overlapped->val), &(context->A_overlapped->cpntr), &(context->A_overlapped->bpntr), &(context->A_overlapped->indx), &N_blk_rows, (context->A_overlapped->data_org)[AZ_name], context->tag,i); context->A_overlapped->matrix_type = AZ_VBR_MATRIX; /*ifp_initialize();*/ /* Create IFPACK encapsulation of Amat */ context->A_overlapped->rpntr = context->A_overlapped->cpntr; N_int_blk = context->A_overlapped->data_org[AZ_N_int_blk]; N_bord_blk = context->A_overlapped->data_org[AZ_N_bord_blk]; context->A_overlapped->data_org[AZ_N_int_blk] = N_blk_rows; context->A_overlapped->data_org[AZ_N_bord_blk] = 0; (context->aztec_choices->options)[AZ_graph_fill] = graph_fill; az2ifp_blockmatrix(&bmat, context->A_overlapped); context->A_overlapped->data_org[AZ_N_int_blk] = N_int_blk; context->A_overlapped->data_org[AZ_N_bord_blk] = N_bord_blk; rthresh = (context->aztec_choices->params)[AZ_rthresh]; athresh = (context->aztec_choices->params)[AZ_athresh]; ifill = (context->aztec_choices->options)[AZ_graph_fill]; ifp_preconditioner(&precon, bmat, IFP_BILUK, (double) ifill, 0.0, IFP_SVD, rthresh, athresh); if ((context->aztec_choices->options)[AZ_output]>0) { ifp_biluk_stats(precon); } context->precon = precon; break; /* End Aztec 2.1 mheroux mod */ #else AZ_perror("IFPACK not linked. Must compile with -DIFPACK"); #endif case AZ_bilu: if (N == 0) return; bindx = context->A_overlapped->bindx; val = context->A_overlapped->val; /* for bilu(k) with k > 1 , figure out the new sparsity pattern */ AZ_sort_msr(bindx, val, N); ifill = (context->aztec_choices->options)[AZ_graph_fill]; if (ifill > 0) { *nz_used = AZ_fill_sparsity_pattern(context, ifill, bindx, val, N); } /* recover some space so that there will */ /* be enough room to convert back to vbr */ i = AZ_compress_msr(&(context->A_overlapped->bindx), &(context->A_overlapped->val), context->N_nz_allocated, *nz_used, name, context); context->N_nz = *nz_used; context->N_nz_allocated = *nz_used; AZ_msr2vbr_mem_efficient(N, &(context->A_overlapped->bindx), &(context->A_overlapped->val), &(context->A_overlapped->cpntr), &(context->A_overlapped->bpntr), &(context->A_overlapped->indx), &N_blk_rows, (context->A_overlapped->data_org)[AZ_name], context->tag,i); context->A_overlapped->matrix_type = AZ_VBR_MATRIX; bindx = context->A_overlapped->bindx; bpntr = context->A_overlapped->bpntr; val = context->A_overlapped->val; sprintf(str,"ipvt %s",context->tag); context->ipvt = (int *) AZ_manage_memory((N+1)*sizeof(int), AZ_ALLOC, name, str, &i); sprintf(str,"dblock %s",context->tag); context->dblock= (int *) AZ_manage_memory((N_blk_rows+1)* sizeof(int), AZ_ALLOC, name, str, &i); context->N_blk_rows = N_blk_rows; /* set dblock to point to the diagonal block in each block row */ for (i = 0 ; i < N_blk_rows ; i++ ) { for (j = bpntr[i] ; j < bpntr[i+1] ; j++ ) { if (bindx[j] == i) context->dblock[i] = j; } } AZ_fact_bilu(N_blk_rows, context->A_overlapped, context->dblock, context->ipvt); break; case AZ_ilut: cr = (double *) AZ_allocate((2*N+3+context->max_row)*sizeof(int)+ (2*N+2+context->max_row)*sizeof(double)); if (cr == NULL) AZ_perror("Out of space in ilut.\n"); unorm = &(cr[N+2]); a = &(unorm[N]); ind = (int *) &(a[context->max_row]); jnz = &(ind[N+3]); ja = &(jnz[N]); sprintf(str,"iu %s",context->tag); context->iu = (int *) AZ_manage_memory((N+1)*sizeof(int), AZ_ALLOC, name, str, &i); AZ_fact_ilut(&N, context->A_overlapped, a, ja, (context->aztec_choices->params)[AZ_drop], context->extra_fact_nz_per_row, N_nz - bindx[N], context->iu,cr,unorm,ind, nz_used, jnz, (context->aztec_choices->params)[AZ_rthresh], (context->aztec_choices->params)[AZ_athresh]); AZ_free(cr); break; case AZ_ilu: dtemp = 0.0; case AZ_rilu: if (N == 0) return; sprintf(str,"iu %s",context->tag); bindx = context->A_overlapped->bindx; val = context->A_overlapped->val; /* for ilu(k) with k > 1 , figure out the new sparsity pattern */ AZ_sort_msr(bindx, val, N); ifill = (context->aztec_choices->options)[AZ_graph_fill]; if (ifill > 0) { *nz_used = AZ_fill_sparsity_pattern(context, ifill, bindx, val, N); } context->iu= (int *) AZ_manage_memory((N+1)*sizeof(int),AZ_ALLOC, name, str, &i); iw = (int *) AZ_allocate((N+1)*sizeof(int)); if (iw == NULL) AZ_perror("Out of space in ilu.\n"); AZ_fact_rilu(N, nz_used, context->iu, iw, context->A_overlapped, dtemp, (context->aztec_choices->params)[AZ_rthresh], (context->aztec_choices->params)[AZ_athresh]); AZ_free(iw); break; case AZ_icc: sprintf(str,"iu %s",context->tag); bindx = context->A_overlapped->bindx; val = context->A_overlapped->val; /* for ilu(k) with k > 1 , figure out the new sparsity pattern */ AZ_sort_msr(bindx, val, N); ifill = (context->aztec_choices->options)[AZ_graph_fill]; if (ifill > 0) *nz_used = AZ_fill_sparsity_pattern(context, ifill, bindx, val, N); AZ_fact_chol(context->A_overlapped->bindx, context->A_overlapped->val,N, (context->aztec_choices->params)[AZ_rthresh], (context->aztec_choices->params)[AZ_athresh]); break; case AZ_lu: #ifdef HAVE_AZLU if (N == 0) return; aflag = (double *) AZ_allocate(8*sizeof(double)); rnr = (int *) AZ_allocate(N_nz*sizeof(int)); if (rnr == NULL) AZ_perror("Out of space in lu.\n"); sprintf(str,"iflag %s",context->tag); context->iflag = (int *) AZ_manage_memory(10*sizeof(int), AZ_ALLOC, name, str ,&i); sprintf(str,"ha %s",context->tag); context->ha = (int *) AZ_manage_memory(11*(N+1)*sizeof(int), AZ_ALLOC, name, str, &i); sprintf(str,"pivot %s",context->tag); context->pivot = (double *) AZ_manage_memory((N+1)*sizeof(double), AZ_ALLOC, name, str,&i); aflag[0] = 16.0; aflag[2] = 1.0e8; aflag[3] = 1.0e-12; aflag[1] = (context->aztec_choices->params)[AZ_drop]; /* set up flags for the sparse factorization solver */ context->iflag[0] = 1; context->iflag[1] = 2; context->iflag[2] = 1; context->iflag[3] = 0; context->iflag[4] = 2; /* Note: if matrix is pos def, iflag[2] = 2 is cheaper */ N_nz_matrix = bindx[N] - 1; AZ_msr2lu(N, context->A_overlapped, rnr); /* Mark bindx so we can see what was not used later */ for (i = N_nz_matrix ; i < N_nz ; i++) bindx[i] = -7; /* factor the matrix */ if (N == 1) { context->A_overlapped->val[0]=1./context->A_overlapped->val[0]; } else { context->N_nz_factors = N_nz; fake_rhs = (double *) AZ_allocate(N*sizeof(double)); if (fake_rhs == NULL) { AZ_printf_out("Not enough memory inside subdomain_solve\n"); } for (i = 0 ; i < N ; i++ ) fake_rhs[i] = 0.0; AZ_fact_lu(fake_rhs, context->A_overlapped,aflag, context->pivot, rnr, context->ha, context->iflag, &N_nz_matrix, &ifail, &(context->N_nz_factors), &N, &N); (context->iflag)[4] = 3; AZ_free(fake_rhs); /* find out what was not used by checking what was not touched */ *nz_used = N_nz; for (i = N_nz_matrix; i < N_nz ; i++ ) { if (bindx[i] != -7) *nz_used = i; } (*nz_used)++; context->N_nz_factors = *nz_used; } AZ_free(rnr); AZ_free(aflag); #else AZ_printf_err("AZ_lu unavailable: configure with --enable-aztecoo-azlu to make available\n"); exit(1); #endif break; default: if (context->aztec_choices->options[AZ_subdomain_solve] >= AZ_SOLVER_PARAMS) { AZ_printf_err("Unknown subdomain solver(%d)\n", context->aztec_choices->options[AZ_subdomain_solve]); exit(1); } } }
void AZ_hold_space(struct context *context, int N) { /**************************************************************************** This routine is used in conjunction with AZ_free_space_holder(). Essentially, this routine allocates memory while AZ_free_space_holder() deallocates. The whole point of these two routines is to allocated all the space needed during the factorization process EXCLUDING all arrays whose size is related to the number of nonzeros. Once this is done, we can determine how much space there is left for the large arrays required for the factorization and split the remaining space amoung these large arrays. In this way LU routines where it is difficult to know the space requirements ahead of time can try to use as large an array as possible. Note: after factorization 'realloc' is used to reduce the array sizes. Author: Ray Tuminaro, SNL, 9222 (3/98) Return code: void ============ Parameter list: =============== context On input, context->aztec_choices-> options[AZ_subdomain_solve] indicates the solver being used. On output, context->space_holder points to a block of memory which can hold all the 'nonlarge' arrays required by this solver. N On input, the size of the matrix to be allocated. *******************************************************************************/ switch(context->aztec_choices->options[AZ_subdomain_solve]) { case AZ_ilut: context->space_holder = (int *) AZ_allocate((2*N+2+context->max_row)* sizeof(double) + sizeof(int)* (3*N+8+context->max_row)); if (context->space_holder == NULL) AZ_perror("No space in ilut.\n"); /* Space for cr (N+2 doubles), unorm (N doubles), a (max_row doubles),*/ /* ind (N+3 ints), jnz (N ints), iu (N+1 ints), ja(max_row ints), */ /* + 4 ints for manage memory header */ break; #ifdef HAVE_AZLU case AZ_lu: context->space_holder = (int *) AZ_allocate((2*N+9)* sizeof(double) + (11*(N+1)+22)*sizeof(int) ); /* Space for aflag (8 doubles), ifail (10 ints), ha (11*(N+1) ints), */ /* pivot (N+1 doubles), fake_rhs (N doubles)+12 ints for manage */ /* memory header */ /* Note: Arrays of size N_nz (e.g. rnr) are not allocated by this */ /* routine. Instead the subdomain field N_int_arrays is set. */ if (context->space_holder == NULL) AZ_perror("Out of space in lu.\n"); #else AZ_printf_err("AZ_lu unavailable: configure with --enable-aztecoo-azlu to make available\n"); exit(1); #endif break; case AZ_bilu: /* Begin Aztec 2.1 mheroux mod */ case AZ_bilu_ifp: /* End Aztec 2.1 mheroux mod */ context->space_holder= (int *) AZ_allocate((N+1)*sizeof(double)); if (context->space_holder == NULL) AZ_perror("No space for bilu.\n"); /* BILU is a little funny in that the maximum amount of memory */ /* required does not occur during the factorization. Instead */ /* it occurs when converting MSR to VBR. At this point, an */ /* additional array of length N is needed. */ break; case AZ_icc: context->space_holder= (int *) AZ_allocate((2*(N+1))*sizeof(int)+ (N+1)*sizeof(double)); if (context->space_holder == NULL) AZ_perror("Out of space in ilu.\n"); break; case AZ_ilu: case AZ_rilu: context->space_holder= (int *) AZ_allocate((2*(N+1)+4)*sizeof(int)); /* Space for iu (N+1 ints), iw (N+1 ints) + 4 ints for manage_memory */ if (context->space_holder == NULL) AZ_perror("Out of space in ilu.\n"); break; default: ; } }
double AZK_residual_norm_no_copy(double *xr, double *xi, double *br, double *bi, int *options, double *params, int *proc_config, AZ_MATRIX *Amat_real, AZ_MATRIX *Amat_imag) /******************************************************************************* Author: Mike Heroux, SNL, 9222 ======= Return code: double ============ Parameter list: =============== xr,xi: On input, contains the initial guess, real part in xr and imaginary part in xi. br,bi: Right hand side of linear system. options: Determines specific solution method and other parameters. params: Drop tolerance and convergence tolerance info. proc_config: Machine configuration. proc_config[AZ_node] is the node number. proc_config[AZ_N_procs] is the number of processors. Amat_real, Amat_imag: The real and imaginary parts of the complex operator, each stored separately as AZ_MATRIX structures. Overview ======== AZK_residual_norm_no_copy computes the two norm of the residual ||r|| where r = b - A*x. Specifically, writing in terms of real and imaginary parts, we have (rr + i*ri) = (br + i*bi) - (Ar + i*Ai)*(xr + i*xi). The two-norm of the complex vector r is identical to the two-norm of the twice-length real vector formed by concatenating rr = real(r) and ri = imag(r). *******************************************************************************/ { AZ_MATRIX *Amat; /* Structure representing matrix to be solved. */ double *x, *b; /* Solution and right-hand side to linear system. */ int N_equations, i; double *y_tmp, result; /* Transform complex system into komplex system */ AZK_create_linsys_no_copy (xr, xi, br, bi, options, params, proc_config, Amat_real, Amat_imag, &x, &b, &Amat); /* Allocate temp vector y */ N_equations = Amat->data_org[AZ_N_internal] + Amat->data_org[AZ_N_border]; y_tmp = (double *) AZ_allocate(N_equations*sizeof(double)); if (y_tmp == NULL) AZ_perror("AZK_residual_norm_no_copy: Out of memory."); /* Compute y = A*x. */ Amat->matvec(x, y_tmp, Amat, proc_config); /* Compute r = b - A*x (put in y_tmp) */ /*daxpy_(&N_equations, &neg_one, b, &ione, y_tmp, &ione);*/ for (i=0; i<N_equations; i++) y_tmp[i] = y_tmp[i] - b[i]; /* Use Aztec function to compute norm */ result = AZ_gvector_norm(N_equations, 2, y_tmp, proc_config); /* Free memory space */ AZK_destroy_linsys (options, params, proc_config, &x, &b, &Amat); AZ_free((void *) y_tmp); result = sqrt(result); return(result); /* AZK_residual_norm */ }
double AZK_residual_norm(double *xk, double *bk, int *options, double *params, int *proc_config, AZ_MATRIX *Amat_komplex) /******************************************************************************* Author: Mike Heroux, SNL, 9222 ======= Return code: double ============ Parameter list: =============== xk: On input, contains the initial guess. bk: Right hand side of linear system. options: Determines specific solution method and other parameters. params: Drop tolerance and convergence tolerance info. proc_config: Machine configuration. proc_config[AZ_node] is the node number. proc_config[AZ_N_procs] is the number of processors. Amat_komplex: The komplex operator, stored as an AZ_MATRIX structure. Overview ======== AZK_residual_norm computes the two norm of the residual ||r|| where r = b - A*x. Specifically, writing in terms of real and imaginary parts, we have (rr + i*ri) = (br + i*bi) - (Ar + i*Ai)*(xr + i*xi). The two-norm of the complex vector r is identical to the two-norm of the twice-length real vector formed by concatenating rr = real(r) and ri = imag(r). *******************************************************************************/ { int N_equations, i; double *y_tmp, result; /* Allocate temp vector y */ N_equations = Amat_komplex->data_org[AZ_N_internal] + Amat_komplex->data_org[AZ_N_border]; y_tmp = (double *) AZ_allocate(N_equations*sizeof(double)); if (y_tmp == NULL) AZ_perror("AZK_residual_norm: Out of memory."); /* Compute y = A*x. */ Amat_komplex->matvec(xk, y_tmp, Amat_komplex, proc_config); /* Compute r = b - A*x (put in y_tmp) */ /*daxpy_(&N_equations, &neg_one, bk, &ione, y_tmp, &ione);*/ for (i=0; i<N_equations; i++) y_tmp[i] = y_tmp[i] - bk[i]; /* Use Aztec function to compute norm */ result = AZ_gvector_norm(N_equations, 2, y_tmp, proc_config); /* Free memory space */ AZ_free((void *) y_tmp); result = sqrt(result); return(result); /* AZK_residual_norm */ }