HYPRE_Int hypre_ParCSRMatrixMatvec( HYPRE_Complex alpha, hypre_ParCSRMatrix *A, hypre_ParVector *x, HYPRE_Complex beta, hypre_ParVector *y ) { hypre_ParCSRCommHandle **comm_handle; hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A); hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A); hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A); hypre_Vector *x_local = hypre_ParVectorLocalVector(x); hypre_Vector *y_local = hypre_ParVectorLocalVector(y); HYPRE_Int num_rows = hypre_ParCSRMatrixGlobalNumRows(A); HYPRE_Int num_cols = hypre_ParCSRMatrixGlobalNumCols(A); hypre_Vector *x_tmp; HYPRE_Int x_size = hypre_ParVectorGlobalSize(x); HYPRE_Int y_size = hypre_ParVectorGlobalSize(y); HYPRE_Int num_vectors = hypre_VectorNumVectors(x_local); HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(offd); HYPRE_Int ierr = 0; HYPRE_Int num_sends, i, j, jv, index, start; HYPRE_Int vecstride = hypre_VectorVectorStride( x_local ); HYPRE_Int idxstride = hypre_VectorIndexStride( x_local ); HYPRE_Complex *x_tmp_data, **x_buf_data; HYPRE_Complex *x_local_data = hypre_VectorData(x_local); /*--------------------------------------------------------------------- * Check for size compatibility. ParMatvec returns ierr = 11 if * length of X doesn't equal the number of columns of A, * ierr = 12 if the length of Y doesn't equal the number of rows * of A, and ierr = 13 if both are true. * * Because temporary vectors are often used in ParMatvec, none of * these conditions terminates processing, and the ierr flag * is informational only. *--------------------------------------------------------------------*/ hypre_assert( idxstride>0 ); if (num_cols != x_size) ierr = 11; if (num_rows != y_size) ierr = 12; if (num_cols != x_size && num_rows != y_size) ierr = 13; hypre_assert( hypre_VectorNumVectors(y_local)==num_vectors ); if ( num_vectors==1 ) x_tmp = hypre_SeqVectorCreate( num_cols_offd ); else { hypre_assert( num_vectors>1 ); x_tmp = hypre_SeqMultiVectorCreate( num_cols_offd, num_vectors ); } hypre_SeqVectorInitialize(x_tmp); x_tmp_data = hypre_VectorData(x_tmp); comm_handle = hypre_CTAlloc(hypre_ParCSRCommHandle*,num_vectors); /*--------------------------------------------------------------------- * If there exists no CommPkg for A, a CommPkg is generated using * equally load balanced partitionings *--------------------------------------------------------------------*/ if (!comm_pkg) { hypre_MatvecCommPkgCreate(A); comm_pkg = hypre_ParCSRMatrixCommPkg(A); } num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg); x_buf_data = hypre_CTAlloc( HYPRE_Complex*, num_vectors ); for ( jv=0; jv<num_vectors; ++jv ) x_buf_data[jv] = hypre_CTAlloc(HYPRE_Complex, hypre_ParCSRCommPkgSendMapStart (comm_pkg, num_sends)); if ( num_vectors==1 ) { index = 0; for (i = 0; i < num_sends; i++) { start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i); for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++) x_buf_data[0][index++] = x_local_data[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)]; } } else for ( jv=0; jv<num_vectors; ++jv ) { index = 0; for (i = 0; i < num_sends; i++) { start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i); for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++) x_buf_data[jv][index++] = x_local_data[ jv*vecstride + idxstride*hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j) ]; } } hypre_assert( idxstride==1 ); /* ... The assert is because the following loop only works for 'column' storage of a multivector. This needs to be fixed to work more generally, at least for 'row' storage. This in turn, means either change CommPkg so num_sends is no.zones*no.vectors (not no.zones) or, less dangerously, put a stride in the logic of CommHandleCreate (stride either from a new arg or a new variable inside CommPkg). Or put the num_vector iteration inside CommHandleCreate (perhaps a new multivector variant of it). */ for ( jv=0; jv<num_vectors; ++jv ) { comm_handle[jv] = hypre_ParCSRCommHandleCreate ( 1, comm_pkg, x_buf_data[jv], &(x_tmp_data[jv*num_cols_offd]) ); } hypre_CSRMatrixMatvec( alpha, diag, x_local, beta, y_local); for ( jv=0; jv<num_vectors; ++jv ) { hypre_ParCSRCommHandleDestroy(comm_handle[jv]); comm_handle[jv] = NULL; } hypre_TFree(comm_handle); if (num_cols_offd) hypre_CSRMatrixMatvec( alpha, offd, x_tmp, 1.0, y_local); hypre_SeqVectorDestroy(x_tmp); x_tmp = NULL; for ( jv=0; jv<num_vectors; ++jv ) hypre_TFree(x_buf_data[jv]); hypre_TFree(x_buf_data); return ierr; }
HYPRE_Int hypre_AMGSolve( void *amg_vdata, hypre_CSRMatrix *A, hypre_Vector *f, hypre_Vector *u ) { hypre_AMGData *amg_data = amg_vdata; /* Data Structure variables */ HYPRE_Int amg_ioutdat; HYPRE_Int *num_coeffs; HYPRE_Int *num_variables; /* HYPRE_Int cycle_op_count; */ HYPRE_Int num_levels; /* HYPRE_Int num_functions; */ double tol; /* char *file_name; */ hypre_CSRMatrix **A_array; hypre_Vector **F_array; hypre_Vector **U_array; /* Local variables */ HYPRE_Int j; HYPRE_Int Solve_err_flag; HYPRE_Int max_iter; HYPRE_Int cycle_count; HYPRE_Int total_coeffs; HYPRE_Int total_variables; double alpha = 1.0; double beta = -1.0; /* double cycle_cmplxty; */ double operat_cmplxty; double grid_cmplxty; double conv_factor; double resid_nrm; double resid_nrm_init; double relative_resid; double rhs_norm; double old_resid; hypre_Vector *Vtemp; amg_ioutdat = hypre_AMGDataIOutDat(amg_data); /* file_name = hypre_AMGDataLogFileName(amg_data); */ /* num_functions = hypre_AMGDataNumFunctions(amg_data); */ num_levels = hypre_AMGDataNumLevels(amg_data); A_array = hypre_AMGDataAArray(amg_data); F_array = hypre_AMGDataFArray(amg_data); U_array = hypre_AMGDataUArray(amg_data); tol = hypre_AMGDataTol(amg_data); max_iter = hypre_AMGDataMaxIter(amg_data); num_coeffs = hypre_CTAlloc(HYPRE_Int, num_levels); num_variables = hypre_CTAlloc(HYPRE_Int, num_levels); num_coeffs[0] = hypre_CSRMatrixNumNonzeros(A_array[0]); num_variables[0] = hypre_CSRMatrixNumRows(A_array[0]); A_array[0] = A; F_array[0] = f; U_array[0] = u; Vtemp = hypre_SeqVectorCreate(num_variables[0]); hypre_SeqVectorInitialize(Vtemp); hypre_AMGDataVtemp(amg_data) = Vtemp; for (j = 1; j < num_levels; j++) { num_coeffs[j] = hypre_CSRMatrixNumNonzeros(A_array[j]); num_variables[j] = hypre_CSRMatrixNumRows(A_array[j]); } /*----------------------------------------------------------------------- * Write the solver parameters *-----------------------------------------------------------------------*/ /*if (amg_ioutdat > 0) hypre_WriteSolverParams(amg_data); */ /*----------------------------------------------------------------------- * Initialize the solver error flag and assorted bookkeeping variables *-----------------------------------------------------------------------*/ Solve_err_flag = 0; total_coeffs = 0; total_variables = 0; cycle_count = 0; operat_cmplxty = 0; grid_cmplxty = 0; /*----------------------------------------------------------------------- * open the log file and write some initial info *-----------------------------------------------------------------------*/ if (amg_ioutdat > 1) { hypre_printf("\n\nAMG SOLUTION INFO:\n"); } /*----------------------------------------------------------------------- * Compute initial fine-grid residual and print to logfile *-----------------------------------------------------------------------*/ hypre_SeqVectorCopy(F_array[0],Vtemp); hypre_CSRMatrixMatvec(alpha,A_array[0],U_array[0],beta,Vtemp); resid_nrm = sqrt(hypre_SeqVectorInnerProd(Vtemp,Vtemp)); resid_nrm_init = resid_nrm; rhs_norm = sqrt(hypre_SeqVectorInnerProd(f,f)); relative_resid = 9999; if (rhs_norm) { relative_resid = resid_nrm_init / rhs_norm; } else { relative_resid = resid_nrm_init; } if (amg_ioutdat == 2 || amg_ioutdat == 3) { hypre_printf(" relative\n"); hypre_printf(" residual factor residual\n"); hypre_printf(" -------- ------ --------\n"); hypre_printf(" Initial %e %e\n",resid_nrm_init, relative_resid); } /*----------------------------------------------------------------------- * Main V-cycle loop *-----------------------------------------------------------------------*/ while (relative_resid >= tol && cycle_count < max_iter && Solve_err_flag == 0) { hypre_AMGDataCycleOpCount(amg_data) = 0; /* Op count only needed for one cycle */ Solve_err_flag = hypre_AMGCycle(amg_data, F_array, U_array); old_resid = resid_nrm; /*--------------------------------------------------------------- * Compute fine-grid residual and residual norm *----------------------------------------------------------------*/ hypre_SeqVectorCopy(F_array[0],Vtemp); hypre_CSRMatrixMatvec(alpha,A_array[0],U_array[0],beta,Vtemp); resid_nrm = sqrt(hypre_SeqVectorInnerProd(Vtemp,Vtemp)); conv_factor = resid_nrm / old_resid; relative_resid = 9999; if (rhs_norm) { relative_resid = resid_nrm / rhs_norm; } else { relative_resid = resid_nrm; } ++cycle_count; if (amg_ioutdat == 2 || amg_ioutdat == 3) { hypre_printf(" Cycle %2d %e %f %e \n",cycle_count, resid_nrm,conv_factor,relative_resid); } } if (cycle_count == max_iter) Solve_err_flag = 1; /*----------------------------------------------------------------------- * Compute closing statistics *-----------------------------------------------------------------------*/ conv_factor = pow((resid_nrm/resid_nrm_init),(1.0/((double) cycle_count))); for (j=0;j<hypre_AMGDataNumLevels(amg_data);j++) { total_coeffs += num_coeffs[j]; total_variables += num_variables[j]; } /* cycle_op_count = hypre_AMGDataCycleOpCount(amg_data); */ grid_cmplxty = ((double) total_variables) / ((double) num_variables[0]); operat_cmplxty = ((double) total_coeffs) / ((double) num_coeffs[0]); /* cycle_cmplxty = ((double) cycle_op_count) / ((double) num_coeffs[0]); */ if (amg_ioutdat > 1) { if (Solve_err_flag == 1) { hypre_printf("\n\n=============================================="); hypre_printf("\n NOTE: Convergence tolerance was not achieved\n"); hypre_printf(" within the allowed %d V-cycles\n",max_iter); hypre_printf("=============================================="); } hypre_printf("\n\n Average Convergence Factor = %f",conv_factor); hypre_printf("\n\n Complexity: grid = %f\n",grid_cmplxty); hypre_printf(" operator = %f\n",operat_cmplxty); /* hypre_printf(" cycle = %f\n\n",cycle_cmplxty); */ } /*---------------------------------------------------------- * Close the output file (if open) *----------------------------------------------------------*/ hypre_TFree(num_coeffs); hypre_TFree(num_variables); return(Solve_err_flag); }