void hypre_F90_IFACE(hypre_parcsrpcgdestroy, HYPRE_PARCSRPCGDESTROY) ( hypre_F90_Obj *solver, hypre_F90_Int *ierr ) { *ierr = (hypre_F90_Int) ( HYPRE_ParCSRPCGDestroy( hypre_F90_PassObj (HYPRE_Solver, solver) ) ); }
HYPRE_Int hypre_AMEDestroy(void *esolver) { hypre_AMEData *ame_data = esolver; hypre_AMSData *ams_data; mv_InterfaceInterpreter* interpreter; mv_MultiVectorPtr eigenvectors; if (!ame_data) { hypre_error_in_arg(1); return hypre_error_flag; } ams_data = ame_data -> precond; interpreter = (mv_InterfaceInterpreter*) ame_data -> interpreter; eigenvectors = (mv_MultiVectorPtr) ame_data -> eigenvectors; if (!ams_data || !interpreter || !eigenvectors) { hypre_error_in_arg(1); return hypre_error_flag; } if (ame_data -> G) hypre_ParCSRMatrixDestroy(ame_data -> G); if (ame_data -> A_G) hypre_ParCSRMatrixDestroy(ame_data -> A_G); if (ame_data -> B1_G) HYPRE_BoomerAMGDestroy(ame_data -> B1_G); if (ame_data -> B2_G) HYPRE_ParCSRPCGDestroy(ame_data -> B2_G); if (ame_data -> eigenvalues) hypre_TFree(ame_data -> eigenvalues); if (eigenvectors) mv_MultiVectorDestroy(eigenvectors); if (interpreter) hypre_TFree(interpreter); if (ams_data -> beta_is_zero) { if (ame_data -> t1) hypre_ParVectorDestroy(ame_data -> t1); if (ame_data -> t2) hypre_ParVectorDestroy(ame_data -> t2); } if (ame_data) hypre_TFree(ame_data); /* Fields initialized using the Set functions are not destroyed */ return hypre_error_flag; }
~Hypre() { if(DMatrix::_communicator != MPI_COMM_NULL) { if(_strategy == 1) HYPRE_BoomerAMGDestroy(_solver); else { if(_strategy == 2) HYPRE_ParCSRPCGDestroy(_solver); else HYPRE_ParCSRFlexGMRESDestroy(_solver); HYPRE_BoomerAMGDestroy(_precond); } HYPRE_IJVectorDestroy(_x); HYPRE_IJVectorDestroy(_b); HYPRE_IJMatrixDestroy(_A); } }
int main (int argc, char *argv[]) { HYPRE_Int i; int myid, num_procs; int N, n; HYPRE_Int ilower, iupper; HYPRE_Int local_size, extra; int solver_id; int print_solution, print_system; double h, h2; HYPRE_IJMatrix A; HYPRE_ParCSRMatrix parcsr_A; HYPRE_IJVector b; HYPRE_ParVector par_b; HYPRE_IJVector x; HYPRE_ParVector par_x; HYPRE_Solver solver, precond; /* Initialize MPI */ MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); /* Default problem parameters */ n = 33; solver_id = 0; print_solution = 0; print_system = 0; /* Parse command line */ { int arg_index = 0; int print_usage = 0; while (arg_index < argc) { if ( strcmp(argv[arg_index], "-n") == 0 ) { arg_index++; n = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-solver") == 0 ) { arg_index++; solver_id = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-print_solution") == 0 ) { arg_index++; print_solution = 1; } else if ( strcmp(argv[arg_index], "-print_system") == 0 ) { arg_index++; print_system = 1; } else if ( strcmp(argv[arg_index], "-help") == 0 ) { print_usage = 1; break; } else { arg_index++; } } if ((print_usage) && (myid == 0)) { printf("\n"); printf("Usage: %s [<options>]\n", argv[0]); printf("\n"); printf(" -n <n> : problem size in each direction (default: 33)\n"); printf(" -solver <ID> : solver ID\n"); printf(" 0 - AMG (default) \n"); printf(" 1 - AMG-PCG\n"); printf(" 8 - ParaSails-PCG\n"); printf(" 50 - PCG\n"); printf(" 61 - AMG-FlexGMRES\n"); printf(" -print_solution : print the solution vector\n"); printf(" -print_system : print the matrix and rhs\n"); printf("\n"); } if (print_usage) { MPI_Finalize(); return (0); } } /* Preliminaries: want at least one processor per row */ if (n*n < num_procs) n = sqrt(num_procs) + 1; N = n*n; /* global number of rows */ h = 1.0/(n+1); /* mesh size*/ h2 = h*h; /* Each processor knows only of its own rows - the range is denoted by ilower and upper. Here we partition the rows. We account for the fact that N may not divide evenly by the number of processors. */ local_size = N/num_procs; extra = N - local_size*num_procs; ilower = local_size*myid; ilower += hypre_min(myid, extra); iupper = local_size*(myid+1); iupper += hypre_min(myid+1, extra); iupper = iupper - 1; /* How many rows do I have? */ local_size = iupper - ilower + 1; /* Create the matrix. Note that this is a square matrix, so we indicate the row partition size twice (since number of rows = number of cols) */ HYPRE_IJMatrixCreate(MPI_COMM_WORLD, ilower, iupper, ilower, iupper, &A); /* Choose a parallel csr format storage (see the User's Manual) */ HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR); /* Initialize before setting coefficients */ HYPRE_IJMatrixInitialize(A); /* Now go through my local rows and set the matrix entries. Each row has at most 5 entries. For example, if n=3: A = [M -I 0; -I M -I; 0 -I M] M = [4 -1 0; -1 4 -1; 0 -1 4] Note that here we are setting one row at a time, though one could set all the rows together (see the User's Manual). */ { HYPRE_Int nnz; double values[5]; HYPRE_Int cols[5]; for (i = ilower; i <= iupper; i++) { nnz = 0; /* The left identity block:position i-n */ if ((i-n)>=0) { cols[nnz] = i-n; values[nnz] = -1.0; nnz++; } /* The left -1: position i-1 */ if (i%n) { cols[nnz] = i-1; values[nnz] = -1.0; nnz++; } /* Set the diagonal: position i */ cols[nnz] = i; values[nnz] = 4.0; nnz++; /* The right -1: position i+1 */ if ((i+1)%n) { cols[nnz] = i+1; values[nnz] = -1.0; nnz++; } /* The right identity block:position i+n */ if ((i+n)< N) { cols[nnz] = i+n; values[nnz] = -1.0; nnz++; } /* Set the values for row i */ HYPRE_IJMatrixSetValues(A, 1, &nnz, &i, cols, values); } } /* Assemble after setting the coefficients */ HYPRE_IJMatrixAssemble(A); /* Note: for the testing of small problems, one may wish to read in a matrix in IJ format (for the format, see the output files from the -print_system option). In this case, one would use the following routine: HYPRE_IJMatrixRead( <filename>, MPI_COMM_WORLD, HYPRE_PARCSR, &A ); <filename> = IJ.A.out to read in what has been printed out by -print_system (processor numbers are omitted). A call to HYPRE_IJMatrixRead is an *alternative* to the following sequence of HYPRE_IJMatrix calls: Create, SetObjectType, Initialize, SetValues, and Assemble */ /* Get the parcsr matrix object to use */ HYPRE_IJMatrixGetObject(A, (void**) &parcsr_A); /* Create the rhs and solution */ HYPRE_IJVectorCreate(MPI_COMM_WORLD, ilower, iupper,&b); HYPRE_IJVectorSetObjectType(b, HYPRE_PARCSR); HYPRE_IJVectorInitialize(b); HYPRE_IJVectorCreate(MPI_COMM_WORLD, ilower, iupper,&x); HYPRE_IJVectorSetObjectType(x, HYPRE_PARCSR); HYPRE_IJVectorInitialize(x); /* Set the rhs values to h^2 and the solution to zero */ { double *rhs_values, *x_values; HYPRE_Int *rows; rhs_values = calloc(local_size, sizeof(double)); x_values = calloc(local_size, sizeof(double)); rows = calloc(local_size, sizeof(HYPRE_Int)); for (i=0; i<local_size; i++) { rhs_values[i] = h2; x_values[i] = 0.0; rows[i] = ilower + i; } HYPRE_IJVectorSetValues(b, local_size, rows, rhs_values); HYPRE_IJVectorSetValues(x, local_size, rows, x_values); free(x_values); free(rhs_values); free(rows); } HYPRE_IJVectorAssemble(b); /* As with the matrix, for testing purposes, one may wish to read in a rhs: HYPRE_IJVectorRead( <filename>, MPI_COMM_WORLD, HYPRE_PARCSR, &b ); as an alternative to the following sequence of HYPRE_IJVectors calls: Create, SetObjectType, Initialize, SetValues, and Assemble */ HYPRE_IJVectorGetObject(b, (void **) &par_b); HYPRE_IJVectorAssemble(x); HYPRE_IJVectorGetObject(x, (void **) &par_x); /* Print out the system - files names will be IJ.out.A.XXXXX and IJ.out.b.XXXXX, where XXXXX = processor id */ if (print_system) { HYPRE_IJMatrixPrint(A, "IJ.out.A"); HYPRE_IJVectorPrint(b, "IJ.out.b"); } /* Choose a solver and solve the system */ /* AMG */ if (solver_id == 0) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ HYPRE_BoomerAMGCreate(&solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_BoomerAMGSetPrintLevel(solver, 3); /* print solve info + parameters */ HYPRE_BoomerAMGSetCoarsenType(solver, 6); /* Falgout coarsening */ HYPRE_BoomerAMGSetRelaxType(solver, 3); /* G-S/Jacobi hybrid relaxation */ HYPRE_BoomerAMGSetNumSweeps(solver, 1); /* Sweeeps on each level */ HYPRE_BoomerAMGSetMaxLevels(solver, 20); /* maximum number of levels */ HYPRE_BoomerAMGSetTol(solver, 1e-7); /* conv. tolerance */ /* Now setup and solve! */ HYPRE_BoomerAMGSetup(solver, parcsr_A, par_b, par_x); HYPRE_BoomerAMGSolve(solver, parcsr_A, par_b, par_x); /* Run info - needed logging turned on */ HYPRE_BoomerAMGGetNumIterations(solver, &num_iterations); HYPRE_BoomerAMGGetFinalRelativeResidualNorm(solver, &final_res_norm); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", num_iterations); printf("Final Relative Residual Norm = %e\n", final_res_norm); printf("\n"); } /* Destroy solver */ HYPRE_BoomerAMGDestroy(solver); } /* PCG */ else if (solver_id == 50) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* prints out the iteration info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ /* Now setup and solve! */ HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); /* Run info - needed logging turned on */ HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", num_iterations); printf("Final Relative Residual Norm = %e\n", final_res_norm); printf("\n"); } /* Destroy solver */ HYPRE_ParCSRPCGDestroy(solver); } /* PCG with AMG preconditioner */ else if (solver_id == 1) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* print solve info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ /* Now set up the AMG preconditioner and specify any parameters */ HYPRE_BoomerAMGCreate(&precond); HYPRE_BoomerAMGSetPrintLevel(precond, 1); /* print amg solution info */ HYPRE_BoomerAMGSetCoarsenType(precond, 6); HYPRE_BoomerAMGSetRelaxType(precond, 6); /* Sym G.S./Jacobi hybrid */ HYPRE_BoomerAMGSetNumSweeps(precond, 1); HYPRE_BoomerAMGSetTol(precond, 0.0); /* conv. tolerance zero */ HYPRE_BoomerAMGSetMaxIter(precond, 1); /* do only one iteration! */ /* Set the PCG preconditioner */ HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSolve, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSetup, precond); /* Now setup and solve! */ HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); /* Run info - needed logging turned on */ HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", num_iterations); printf("Final Relative Residual Norm = %e\n", final_res_norm); printf("\n"); } /* Destroy solver and preconditioner */ HYPRE_ParCSRPCGDestroy(solver); HYPRE_BoomerAMGDestroy(precond); } /* PCG with Parasails Preconditioner */ else if (solver_id == 8) { HYPRE_Int num_iterations; double final_res_norm; int sai_max_levels = 1; double sai_threshold = 0.1; double sai_filter = 0.05; int sai_sym = 1; /* Create solver */ HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* print solve info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ /* Now set up the ParaSails preconditioner and specify any parameters */ HYPRE_ParaSailsCreate(MPI_COMM_WORLD, &precond); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_ParaSailsSetParams(precond, sai_threshold, sai_max_levels); HYPRE_ParaSailsSetFilter(precond, sai_filter); HYPRE_ParaSailsSetSym(precond, sai_sym); HYPRE_ParaSailsSetLogging(precond, 3); /* Set the PCG preconditioner */ HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_ParaSailsSolve, (HYPRE_PtrToSolverFcn) HYPRE_ParaSailsSetup, precond); /* Now setup and solve! */ HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); /* Run info - needed logging turned on */ HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", num_iterations); printf("Final Relative Residual Norm = %e\n", final_res_norm); printf("\n"); } /* Destory solver and preconditioner */ HYPRE_ParCSRPCGDestroy(solver); HYPRE_ParaSailsDestroy(precond); } /* Flexible GMRES with AMG Preconditioner */ else if (solver_id == 61) { HYPRE_Int num_iterations; double final_res_norm; int restart = 30; int modify = 1; /* Create solver */ HYPRE_ParCSRFlexGMRESCreate(MPI_COMM_WORLD, &solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_FlexGMRESSetKDim(solver, restart); HYPRE_FlexGMRESSetMaxIter(solver, 1000); /* max iterations */ HYPRE_FlexGMRESSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_FlexGMRESSetPrintLevel(solver, 2); /* print solve info */ HYPRE_FlexGMRESSetLogging(solver, 1); /* needed to get run info later */ /* Now set up the AMG preconditioner and specify any parameters */ HYPRE_BoomerAMGCreate(&precond); HYPRE_BoomerAMGSetPrintLevel(precond, 1); /* print amg solution info */ HYPRE_BoomerAMGSetCoarsenType(precond, 6); HYPRE_BoomerAMGSetRelaxType(precond, 6); /* Sym G.S./Jacobi hybrid */ HYPRE_BoomerAMGSetNumSweeps(precond, 1); HYPRE_BoomerAMGSetTol(precond, 0.0); /* conv. tolerance zero */ HYPRE_BoomerAMGSetMaxIter(precond, 1); /* do only one iteration! */ /* Set the FlexGMRES preconditioner */ HYPRE_FlexGMRESSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSolve, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSetup, precond); if (modify) /* this is an optional call - if you don't call it, hypre_FlexGMRESModifyPCDefault is used - which does nothing. Otherwise, you can define your own, similar to the one used here */ HYPRE_FlexGMRESSetModifyPC( solver, (HYPRE_PtrToModifyPCFcn) hypre_FlexGMRESModifyPCAMGExample); /* Now setup and solve! */ HYPRE_ParCSRFlexGMRESSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRFlexGMRESSolve(solver, parcsr_A, par_b, par_x); /* Run info - needed logging turned on */ HYPRE_FlexGMRESGetNumIterations(solver, &num_iterations); HYPRE_FlexGMRESGetFinalRelativeResidualNorm(solver, &final_res_norm); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", num_iterations); printf("Final Relative Residual Norm = %e\n", final_res_norm); printf("\n"); } /* Destory solver and preconditioner */ HYPRE_ParCSRFlexGMRESDestroy(solver); HYPRE_BoomerAMGDestroy(precond); } else { if (myid ==0) printf("Invalid solver id specified.\n"); } /* Print the solution */ if (print_solution) HYPRE_IJVectorPrint(x, "ij.out.x"); /* Clean up */ HYPRE_IJMatrixDestroy(A); HYPRE_IJVectorDestroy(b); HYPRE_IJVectorDestroy(x); /* Finalize MPI*/ MPI_Finalize(); return(0); }
HYPRE_Int main (HYPRE_Int argc, char *argv[]) { HYPRE_Int i; HYPRE_Int myid, num_procs; HYPRE_Int N, n; HYPRE_Int ilower, iupper; HYPRE_Int local_size, extra; HYPRE_Int solver_id; HYPRE_Int print_solution; double h, h2; #ifdef HYPRE_FORTRAN hypre_F90_Obj A; hypre_F90_Obj parcsr_A; hypre_F90_Obj b; hypre_F90_Obj par_b; hypre_F90_Obj x; hypre_F90_Obj par_x; hypre_F90_Obj solver, precond; hypre_F90_Obj long_temp_COMM; HYPRE_Int temp_COMM; HYPRE_Int precond_id; HYPRE_Int one = 1; HYPRE_Int two = 2; HYPRE_Int three = 3; HYPRE_Int six = 6; HYPRE_Int twenty = 20; HYPRE_Int thousand = 1000; HYPRE_Int hypre_type = HYPRE_PARCSR; double oo1 = 1.e-3; double tol = 1.e-7; #else HYPRE_IJMatrix A; HYPRE_ParCSRMatrix parcsr_A; HYPRE_IJVector b; HYPRE_ParVector par_b; HYPRE_IJVector x; HYPRE_ParVector par_x; HYPRE_Solver solver, precond; #endif /* Initialize MPI */ hypre_MPI_Init(&argc, &argv); hypre_MPI_Comm_rank(hypre_MPI_COMM_WORLD, &myid); hypre_MPI_Comm_size(hypre_MPI_COMM_WORLD, &num_procs); /* Default problem parameters */ n = 33; solver_id = 0; print_solution = 0; /* Parse command line */ { HYPRE_Int arg_index = 0; HYPRE_Int print_usage = 0; while (arg_index < argc) { if ( strcmp(argv[arg_index], "-n") == 0 ) { arg_index++; n = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-solver") == 0 ) { arg_index++; solver_id = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-print_solution") == 0 ) { arg_index++; print_solution = 1; } else if ( strcmp(argv[arg_index], "-help") == 0 ) { print_usage = 1; break; } else { arg_index++; } } if ((print_usage) && (myid == 0)) { hypre_printf("\n"); hypre_printf("Usage: %s [<options>]\n", argv[0]); hypre_printf("\n"); hypre_printf(" -n <n> : problem size in each direction (default: 33)\n"); hypre_printf(" -solver <ID> : solver ID\n"); hypre_printf(" 0 - AMG (default) \n"); hypre_printf(" 1 - AMG-PCG\n"); hypre_printf(" 8 - ParaSails-PCG\n"); hypre_printf(" 50 - PCG\n"); hypre_printf(" -print_solution : print the solution vector\n"); hypre_printf("\n"); } if (print_usage) { hypre_MPI_Finalize(); return (0); } } /* Preliminaries: want at least one processor per row */ if (n*n < num_procs) n = sqrt(num_procs) + 1; N = n*n; /* global number of rows */ h = 1.0/(n+1); /* mesh size*/ h2 = h*h; /* Each processor knows only of its own rows - the range is denoted by ilower and upper. Here we partition the rows. We account for the fact that N may not divide evenly by the number of processors. */ local_size = N/num_procs; extra = N - local_size*num_procs; ilower = local_size*myid; ilower += hypre_min(myid, extra); iupper = local_size*(myid+1); iupper += hypre_min(myid+1, extra); iupper = iupper - 1; /* How many rows do I have? */ local_size = iupper - ilower + 1; /* Create the matrix. Note that this is a square matrix, so we indicate the row partition size twice (since number of rows = number of cols) */ #ifdef HYPRE_FORTRAN long_temp_COMM = (hypre_F90_Obj) hypre_MPI_COMM_WORLD; temp_COMM = (HYPRE_Int) hypre_MPI_COMM_WORLD; HYPRE_IJMatrixCreate(&long_temp_COMM, &ilower, &iupper, &ilower, &iupper, &A); #else HYPRE_IJMatrixCreate(hypre_MPI_COMM_WORLD, ilower, iupper, ilower, iupper, &A); #endif /* Choose a parallel csr format storage (see the User's Manual) */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixSetObjectType(&A, &hypre_type); #else HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR); #endif /* Initialize before setting coefficients */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixInitialize(&A); #else HYPRE_IJMatrixInitialize(A); #endif /* Now go through my local rows and set the matrix entries. Each row has at most 5 entries. For example, if n=3: A = [M -I 0; -I M -I; 0 -I M] M = [4 -1 0; -1 4 -1; 0 -1 4] Note that here we are setting one row at a time, though one could set all the rows together (see the User's Manual). */ { HYPRE_Int nnz; double values[5]; HYPRE_Int cols[5]; for (i = ilower; i <= iupper; i++) { nnz = 0; /* The left identity block:position i-n */ if ((i-n)>=0) { cols[nnz] = i-n; values[nnz] = -1.0; nnz++; } /* The left -1: position i-1 */ if (i%n) { cols[nnz] = i-1; values[nnz] = -1.0; nnz++; } /* Set the diagonal: position i */ cols[nnz] = i; values[nnz] = 4.0; nnz++; /* The right -1: position i+1 */ if ((i+1)%n) { cols[nnz] = i+1; values[nnz] = -1.0; nnz++; } /* The right identity block:position i+n */ if ((i+n)< N) { cols[nnz] = i+n; values[nnz] = -1.0; nnz++; } /* Set the values for row i */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixSetValues(&A, &one, &nnz, &i, &cols[0], &values[0]); #else HYPRE_IJMatrixSetValues(A, 1, &nnz, &i, cols, values); #endif } } /* Assemble after setting the coefficients */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixAssemble(&A); #else HYPRE_IJMatrixAssemble(A); #endif /* Get the parcsr matrix object to use */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixGetObject(&A, &parcsr_A); HYPRE_IJMatrixGetObject(&A, &parcsr_A); #else HYPRE_IJMatrixGetObject(A, (void**) &parcsr_A); HYPRE_IJMatrixGetObject(A, (void**) &parcsr_A); #endif /* Create the rhs and solution */ #ifdef HYPRE_FORTRAN HYPRE_IJVectorCreate(&temp_COMM, &ilower, &iupper, &b); HYPRE_IJVectorSetObjectType(&b, &hypre_type); HYPRE_IJVectorInitialize(&b); #else HYPRE_IJVectorCreate(hypre_MPI_COMM_WORLD, ilower, iupper,&b); HYPRE_IJVectorSetObjectType(b, HYPRE_PARCSR); HYPRE_IJVectorInitialize(b); #endif #ifdef HYPRE_FORTRAN HYPRE_IJVectorCreate(&temp_COMM, &ilower, &iupper, &x); HYPRE_IJVectorSetObjectType(&x, &hypre_type); HYPRE_IJVectorInitialize(&x); #else HYPRE_IJVectorCreate(hypre_MPI_COMM_WORLD, ilower, iupper,&x); HYPRE_IJVectorSetObjectType(x, HYPRE_PARCSR); HYPRE_IJVectorInitialize(x); #endif /* Set the rhs values to h^2 and the solution to zero */ { double *rhs_values, *x_values; HYPRE_Int *rows; rhs_values = calloc(local_size, sizeof(double)); x_values = calloc(local_size, sizeof(double)); rows = calloc(local_size, sizeof(HYPRE_Int)); for (i=0; i<local_size; i++) { rhs_values[i] = h2; x_values[i] = 0.0; rows[i] = ilower + i; } #ifdef HYPRE_FORTRAN HYPRE_IJVectorSetValues(&b, &local_size, &rows[0], &rhs_values[0]); HYPRE_IJVectorSetValues(&x, &local_size, &rows[0], &x_values[0]); #else HYPRE_IJVectorSetValues(b, local_size, rows, rhs_values); HYPRE_IJVectorSetValues(x, local_size, rows, x_values); #endif free(x_values); free(rhs_values); free(rows); } #ifdef HYPRE_FORTRAN HYPRE_IJVectorAssemble(&b); HYPRE_IJVectorGetObject(&b, &par_b); #else HYPRE_IJVectorAssemble(b); HYPRE_IJVectorGetObject(b, (void **) &par_b); #endif #ifdef HYPRE_FORTRAN HYPRE_IJVectorAssemble(&x); HYPRE_IJVectorGetObject(&x, &par_x); #else HYPRE_IJVectorAssemble(x); HYPRE_IJVectorGetObject(x, (void **) &par_x); #endif /* Choose a solver and solve the system */ /* AMG */ if (solver_id == 0) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGCreate(&solver); #else HYPRE_BoomerAMGCreate(&solver); #endif /* Set some parameters (See Reference Manual for more parameters) */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGSetPrintLevel(&solver, &three); /* print solve info + parameters */ HYPRE_BoomerAMGSetCoarsenType(&solver, &six); /* Falgout coarsening */ HYPRE_BoomerAMGSetRelaxType(&solver, &three); /* G-S/Jacobi hybrid relaxation */ HYPRE_BoomerAMGSetNumSweeps(&solver, &one); /* Sweeeps on each level */ HYPRE_BoomerAMGSetMaxLevels(&solver, &twenty); /* maximum number of levels */ HYPRE_BoomerAMGSetTol(&solver, &tol); /* conv. tolerance */ #else HYPRE_BoomerAMGSetPrintLevel(solver, 3); /* print solve info + parameters */ HYPRE_BoomerAMGSetCoarsenType(solver, 6); /* Falgout coarsening */ HYPRE_BoomerAMGSetRelaxType(solver, 3); /* G-S/Jacobi hybrid relaxation */ HYPRE_BoomerAMGSetNumSweeps(solver, 1); /* Sweeeps on each level */ HYPRE_BoomerAMGSetMaxLevels(solver, 20); /* maximum number of levels */ HYPRE_BoomerAMGSetTol(solver, 1e-7); /* conv. tolerance */ #endif /* Now setup and solve! */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGSetup(&solver, &parcsr_A, &par_b, &par_x); HYPRE_BoomerAMGSolve(&solver, &parcsr_A, &par_b, &par_x); #else HYPRE_BoomerAMGSetup(solver, parcsr_A, par_b, par_x); HYPRE_BoomerAMGSolve(solver, parcsr_A, par_b, par_x); #endif /* Run info - needed logging turned on */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGGetNumIterations(&solver, &num_iterations); HYPRE_BoomerAMGGetFinalRelativeResidualNorm(&solver, &final_res_norm); #else HYPRE_BoomerAMGGetNumIterations(solver, &num_iterations); HYPRE_BoomerAMGGetFinalRelativeResidualNorm(solver, &final_res_norm); #endif if (myid == 0) { hypre_printf("\n"); hypre_printf("Iterations = %d\n", num_iterations); hypre_printf("Final Relative Residual Norm = %e\n", final_res_norm); hypre_printf("\n"); } /* Destroy solver */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGDestroy(&solver); #else HYPRE_BoomerAMGDestroy(solver); #endif } /* PCG */ else if (solver_id == 50) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGCreate(&temp_COMM, &solver); #else HYPRE_ParCSRPCGCreate(hypre_MPI_COMM_WORLD, &solver); #endif /* Set some parameters (See Reference Manual for more parameters) */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetMaxIter(&solver, &thousand); /* max iterations */ HYPRE_ParCSRPCGSetTol(&solver, &tol); /* conv. tolerance */ HYPRE_ParCSRPCGSetTwoNorm(&solver, &one); /* use the two norm as the stopping criteria */ HYPRE_ParCSRPCGSetPrintLevel(&solver, &two); /* prints out the iteration info */ #else HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* prints out the iteration info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ #endif /* Now setup and solve! */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetup(&solver, &parcsr_A, &par_b, &par_x); HYPRE_ParCSRPCGSolve(&solver, &parcsr_A, &par_b, &par_x); #else HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); #endif /* Run info - needed logging turned on */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGGetNumIterations(&solver, &num_iterations); HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(&solver, &final_res_norm); #else HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); #endif if (myid == 0) { hypre_printf("\n"); hypre_printf("Iterations = %d\n", num_iterations); hypre_printf("Final Relative Residual Norm = %e\n", final_res_norm); hypre_printf("\n"); } /* Destroy solver */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGDestroy(&solver); #else HYPRE_ParCSRPCGDestroy(solver); #endif } /* PCG with AMG preconditioner */ else if (solver_id == 1) { HYPRE_Int num_iterations; double final_res_norm; /* Create solver */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGCreate(&temp_COMM, &solver); #else HYPRE_ParCSRPCGCreate(hypre_MPI_COMM_WORLD, &solver); #endif /* Set some parameters (See Reference Manual for more parameters) */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetMaxIter(&solver, &thousand); /* max iterations */ HYPRE_ParCSRPCGSetTol(&solver, &tol); /* conv. tolerance */ HYPRE_ParCSRPCGSetTwoNorm(&solver, &one); /* use the two norm as the stopping criteria */ HYPRE_ParCSRPCGSetPrintLevel(&solver, &two); /* print solve info */ #else HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* print solve info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ #endif /* Now set up the AMG preconditioner and specify any parameters */ #ifdef HYPRE_FORTRAN HYPRE_BoomerAMGCreate(&precond); HYPRE_BoomerAMGSetPrintLevel(&precond, &one); /* print amg solution info*/ HYPRE_BoomerAMGSetCoarsenType(&precond, &six); HYPRE_BoomerAMGSetRelaxType(&precond, &three); HYPRE_BoomerAMGSetNumSweeps(&precond, &one); HYPRE_BoomerAMGSetTol(&precond, &oo1); #else HYPRE_BoomerAMGCreate(&precond); HYPRE_BoomerAMGSetPrintLevel(precond, 1); /* print amg solution info*/ HYPRE_BoomerAMGSetCoarsenType(precond, 6); HYPRE_BoomerAMGSetRelaxType(precond, 3); HYPRE_BoomerAMGSetNumSweeps(precond, 1); HYPRE_BoomerAMGSetTol(precond, 1e-3); #endif /* Set the PCG preconditioner */ #ifdef HYPRE_FORTRAN precond_id = 2; HYPRE_ParCSRPCGSetPrecond(&solver, &precond_id, &precond); #else HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSolve, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSetup, precond); #endif /* Now setup and solve! */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetup(&solver, &parcsr_A, &par_b, &par_x); HYPRE_ParCSRPCGSolve(&solver, &parcsr_A, &par_b, &par_x); #else HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); #endif /* Run info - needed logging turned on */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGGetNumIterations(&solver, &num_iterations); HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(&solver, &final_res_norm); #else HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); #endif if (myid == 0) { hypre_printf("\n"); hypre_printf("Iterations = %d\n", num_iterations); hypre_printf("Final Relative Residual Norm = %e\n", final_res_norm); hypre_printf("\n"); } /* Destroy solver and preconditioner */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGDestroy(&solver); HYPRE_BoomerAMGDestroy(&precond); #else HYPRE_ParCSRPCGDestroy(solver); HYPRE_BoomerAMGDestroy(precond); #endif } /* PCG with Parasails Preconditioner */ else if (solver_id == 8) { HYPRE_Int num_iterations; double final_res_norm; HYPRE_Int sai_max_levels = 1; double sai_threshold = 0.1; double sai_filter = 0.05; HYPRE_Int sai_sym = 1; /* Create solver */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGCreate(&temp_COMM, &solver); #else HYPRE_ParCSRPCGCreate(hypre_MPI_COMM_WORLD, &solver); #endif /* Set some parameters (See Reference Manual for more parameters) */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetMaxIter(&solver, &thousand); /* max iterations */ HYPRE_ParCSRPCGSetTol(&solver, &tol); /* conv. tolerance */ HYPRE_ParCSRPCGSetTwoNorm(&solver, &one); /* use the two norm as the stopping criteria */ HYPRE_ParCSRPCGSetPrintLevel(&solver, &two); /* print solve info */ #else HYPRE_PCGSetMaxIter(solver, 1000); /* max iterations */ HYPRE_PCGSetTol(solver, 1e-7); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 1); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* print solve info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ #endif /* Now set up the ParaSails preconditioner and specify any parameters */ #ifdef HYPRE_FORTRAN HYPRE_ParaSailsCreate(&temp_COMM, &precond); #else HYPRE_ParaSailsCreate(hypre_MPI_COMM_WORLD, &precond); #endif /* Set some parameters (See Reference Manual for more parameters) */ #ifdef HYPRE_FORTRAN HYPRE_ParaSailsSetParams(&precond, &sai_threshold, &sai_max_levels); HYPRE_ParaSailsSetFilter(&precond, &sai_filter); HYPRE_ParaSailsSetSym(&precond, &sai_sym); HYPRE_ParaSailsSetLogging(&precond, &three); #else HYPRE_ParaSailsSetParams(precond, sai_threshold, sai_max_levels); HYPRE_ParaSailsSetFilter(precond, sai_filter); HYPRE_ParaSailsSetSym(precond, sai_sym); HYPRE_ParaSailsSetLogging(precond, 3); #endif /* Set the PCG preconditioner */ #ifdef HYPRE_FORTRAN precond_id = 4; HYPRE_ParCSRPCGSetPrecond(&solver, &precond_id, &precond); #else HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_ParaSailsSolve, (HYPRE_PtrToSolverFcn) HYPRE_ParaSailsSetup, precond); #endif /* Now setup and solve! */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGSetup(&solver, &parcsr_A, &par_b, &par_x); HYPRE_ParCSRPCGSolve(&solver, &parcsr_A, &par_b, &par_x); #else HYPRE_ParCSRPCGSetup(solver, parcsr_A, par_b, par_x); HYPRE_ParCSRPCGSolve(solver, parcsr_A, par_b, par_x); #endif /* Run info - needed logging turned on */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGGetNumIterations(&solver, &num_iterations); HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(&solver, &final_res_norm); #else HYPRE_PCGGetNumIterations(solver, &num_iterations); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); #endif if (myid == 0) { hypre_printf("\n"); hypre_printf("Iterations = %d\n", num_iterations); hypre_printf("Final Relative Residual Norm = %e\n", final_res_norm); hypre_printf("\n"); } /* Destory solver and preconditioner */ #ifdef HYPRE_FORTRAN HYPRE_ParCSRPCGDestroy(&solver); HYPRE_ParaSailsDestroy(&precond); #else HYPRE_ParCSRPCGDestroy(solver); HYPRE_ParaSailsDestroy(precond); #endif } else { if (myid ==0) hypre_printf("Invalid solver id specified.\n"); } /* Print the solution */ #ifdef HYPRE_FORTRAN if (print_solution) HYPRE_IJVectorPrint(&x, "ij.out.x"); #else if (print_solution) HYPRE_IJVectorPrint(x, "ij.out.x"); #endif /* Clean up */ #ifdef HYPRE_FORTRAN HYPRE_IJMatrixDestroy(&A); HYPRE_IJVectorDestroy(&b); HYPRE_IJVectorDestroy(&x); #else HYPRE_IJMatrixDestroy(A); HYPRE_IJVectorDestroy(b); HYPRE_IJVectorDestroy(x); #endif /* Finalize MPI*/ hypre_MPI_Finalize(); return(0); }
int main (int argc, char *argv[]) { int myid, num_procs; int n, N, pi, pj, pk; double h; double tol, theta; int maxit, cycle_type; int rlx_type, rlx_sweeps, rlx_weight, rlx_omega; int amg_coarsen_type, amg_agg_levels, amg_rlx_type; int amg_interp_type, amg_Pmax; int singular_problem ; HYPRE_Int time_index; HYPRE_SStructGrid edge_grid; HYPRE_SStructGraph A_graph; HYPRE_SStructMatrix A; HYPRE_SStructVector b; HYPRE_SStructVector x; HYPRE_SStructGrid node_grid; HYPRE_SStructGraph G_graph; HYPRE_SStructStencil G_stencil[3]; HYPRE_SStructMatrix G; HYPRE_SStructVector xcoord, ycoord, zcoord; HYPRE_Solver solver, precond; /* Initialize MPI */ MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); /* Set default parameters */ n = 10; optionAlpha = 0; optionBeta = 0; maxit = 100; tol = 1e-6; cycle_type = 13; rlx_type = 2; rlx_sweeps = 1; rlx_weight = 1.0; rlx_omega = 1.0; amg_coarsen_type = 10; amg_agg_levels = 1; amg_rlx_type = 6; theta = 0.25; amg_interp_type = 6; amg_Pmax = 4; singular_problem = 0; /* Parse command line */ { int arg_index = 0; int print_usage = 0; while (arg_index < argc) { if ( strcmp(argv[arg_index], "-n") == 0 ) { arg_index++; n = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-a") == 0 ) { arg_index++; optionAlpha = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-b") == 0 ) { arg_index++; optionBeta = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-maxit") == 0 ) { arg_index++; maxit = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-tol") == 0 ) { arg_index++; tol = atof(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-type") == 0 ) { arg_index++; cycle_type = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-rlx") == 0 ) { arg_index++; rlx_type = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-rlxn") == 0 ) { arg_index++; rlx_sweeps = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-rlxw") == 0 ) { arg_index++; rlx_weight = atof(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-rlxo") == 0 ) { arg_index++; rlx_omega = atof(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-ctype") == 0 ) { arg_index++; amg_coarsen_type = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-amgrlx") == 0 ) { arg_index++; amg_rlx_type = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-agg") == 0 ) { arg_index++; amg_agg_levels = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-itype") == 0 ) { arg_index++; amg_interp_type = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-pmax") == 0 ) { arg_index++; amg_Pmax = atoi(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-sing") == 0 ) { arg_index++; singular_problem = 1; } else if ( strcmp(argv[arg_index], "-theta") == 0 ) { arg_index++; theta = atof(argv[arg_index++]); } else if ( strcmp(argv[arg_index], "-help") == 0 ) { print_usage = 1; break; } else { arg_index++; } } if ((print_usage) && (myid == 0)) { printf("\n"); printf("Usage: %s [<options>]\n", argv[0]); printf("\n"); printf(" -n <n> : problem size per processor (default: 10)\n"); printf(" -a <alpha_opt> : choice for the curl-curl coefficient (default: 1)\n"); printf(" -b <beta_opt> : choice for the mass coefficient (default: 1)\n"); printf("\n"); printf("PCG-AMS solver options: \n"); printf(" -maxit <num> : maximum number of iterations (100) \n"); printf(" -tol <num> : convergence tolerance (1e-6) \n"); printf(" -type <num> : 3-level cycle type (0-8, 11-14) \n"); printf(" -theta <num> : BoomerAMG threshold (0.25) \n"); printf(" -ctype <num> : BoomerAMG coarsening type \n"); printf(" -agg <num> : Levels of BoomerAMG agg. coarsening \n"); printf(" -amgrlx <num> : BoomerAMG relaxation type \n"); printf(" -itype <num> : BoomerAMG interpolation type \n"); printf(" -pmax <num> : BoomerAMG interpolation truncation \n"); printf(" -rlx <num> : relaxation type \n"); printf(" -rlxn <num> : number of relaxation sweeps \n"); printf(" -rlxw <num> : damping parameter (usually <=1) \n"); printf(" -rlxo <num> : SOR parameter (usually in (0,2)) \n"); printf(" -sing : curl-curl only (singular) problem \n"); printf("\n"); printf("\n"); } if (print_usage) { MPI_Finalize(); return (0); } } /* Figure out the processor grid (N x N x N). The local problem size is n^3, while pi, pj and pk indicate the position in the processor grid. */ N = pow(num_procs,1.0/3.0) + 0.5; if (num_procs != N*N*N) { if (myid == 0) printf("Can't run on %d processors, try %d.\n", num_procs, N*N*N); MPI_Finalize(); exit(1); } h = 1.0 / (N*n); pk = myid / (N*N); pj = myid/N - pk*N; pi = myid - pj*N - pk*N*N; /* Start timing */ time_index = hypre_InitializeTiming("SStruct Setup"); hypre_BeginTiming(time_index); /* 1. Set up the edge and nodal grids. Note that we do this simultaneously to make sure that they have the same extents. For simplicity we use only one part to represent the unit cube. */ { HYPRE_Int ndim = 3; HYPRE_Int nparts = 1; /* Create empty 2D grid objects */ HYPRE_SStructGridCreate(MPI_COMM_WORLD, ndim, nparts, &node_grid); HYPRE_SStructGridCreate(MPI_COMM_WORLD, ndim, nparts, &edge_grid); /* Set the extents of the grid - each processor sets its grid boxes. */ { HYPRE_Int part = 0; HYPRE_Int ilower[3] = {1 + pi*n, 1 + pj*n, 1 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructGridSetExtents(node_grid, part, ilower, iupper); HYPRE_SStructGridSetExtents(edge_grid, part, ilower, iupper); } /* Set the variable type and number of variables on each grid. */ { HYPRE_Int i; HYPRE_Int nnodevars = 1; HYPRE_Int nedgevars = 3; HYPRE_SStructVariable nodevars[1] = {HYPRE_SSTRUCT_VARIABLE_NODE}; HYPRE_SStructVariable edgevars[3] = {HYPRE_SSTRUCT_VARIABLE_XEDGE, HYPRE_SSTRUCT_VARIABLE_YEDGE, HYPRE_SSTRUCT_VARIABLE_ZEDGE}; for (i = 0; i < nparts; i++) { HYPRE_SStructGridSetVariables(node_grid, i, nnodevars, nodevars); HYPRE_SStructGridSetVariables(edge_grid, i, nedgevars, edgevars); } } /* Since there is only one part, there is no need to call the SetNeighborPart or SetSharedPart functions, which determine the spatial relation between the parts. See Examples 12, 13 and 14 for illustrations of these calls. */ /* Now the grids are ready to be used */ HYPRE_SStructGridAssemble(node_grid); HYPRE_SStructGridAssemble(edge_grid); } /* 2. Create the finite element stiffness matrix A and load vector b. */ { HYPRE_Int part = 0; /* this problem has only one part */ /* Set the ordering of the variables in the finite element problem. This is done by listing the variable offset directions relative to the element's center. See the Reference Manual for more details. */ { HYPRE_Int ordering[48] = { 0, 0, -1, -1, /* x-edge [0]-[1] */ 1, +1, 0, -1, /* y-edge [1]-[2] */ /* [7]------[6] */ 0, 0, +1, -1, /* x-edge [3]-[2] */ /* /| /| */ 1, -1, 0, -1, /* y-edge [0]-[3] */ /* / | / | */ 0, 0, -1, +1, /* x-edge [4]-[5] */ /* [4]------[5] | */ 1, +1, 0, +1, /* y-edge [5]-[6] */ /* | [3]----|-[2] */ 0, 0, +1, +1, /* x-edge [7]-[6] */ /* | / | / */ 1, -1, 0, +1, /* y-edge [4]-[7] */ /* |/ |/ */ 2, -1, -1, 0, /* z-edge [0]-[4] */ /* [0]------[1] */ 2, +1, -1, 0, /* z-edge [1]-[5] */ 2, +1, +1, 0, /* z-edge [2]-[6] */ 2, -1, +1, 0 }; /* z-edge [3]-[7] */ HYPRE_SStructGridSetFEMOrdering(edge_grid, part, ordering); } /* Set up the Graph - this determines the non-zero structure of the matrix. */ { HYPRE_Int part = 0; /* Create the graph object */ HYPRE_SStructGraphCreate(MPI_COMM_WORLD, edge_grid, &A_graph); /* See MatrixSetObjectType below */ HYPRE_SStructGraphSetObjectType(A_graph, HYPRE_PARCSR); /* Indicate that this problem uses finite element stiffness matrices and load vectors, instead of stencils. */ HYPRE_SStructGraphSetFEM(A_graph, part); /* The edge finite element matrix is full, so there is no need to call the HYPRE_SStructGraphSetFEMSparsity() function. */ /* Assemble the graph */ HYPRE_SStructGraphAssemble(A_graph); } /* Set up the SStruct Matrix and right-hand side vector */ { /* Create the matrix object */ HYPRE_SStructMatrixCreate(MPI_COMM_WORLD, A_graph, &A); /* Use a ParCSR storage */ HYPRE_SStructMatrixSetObjectType(A, HYPRE_PARCSR); /* Indicate that the matrix coefficients are ready to be set */ HYPRE_SStructMatrixInitialize(A); /* Create an empty vector object */ HYPRE_SStructVectorCreate(MPI_COMM_WORLD, edge_grid, &b); /* Use a ParCSR storage */ HYPRE_SStructVectorSetObjectType(b, HYPRE_PARCSR); /* Indicate that the vector coefficients are ready to be set */ HYPRE_SStructVectorInitialize(b); } /* Set the matrix and vector entries by finite element assembly */ { /* local stiffness matrix and load vector */ double S[12][12], F[12]; int i, j, k; HYPRE_Int index[3]; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) for (k = 1; k <= n; k++) { /* Compute the FEM matrix and r.h.s. for cell (i,j,k) with coefficients evaluated at the cell center. */ index[0] = i + pi*n; index[1] = j + pj*n; index[2] = k + pk*n; ComputeFEMND1(S,F,(pi*n+i)*h-h/2,(pj*n+j)*h-h/2,(pk*n+k)*h-h/2,h); /* Eliminate boundary conditions on x = 0 */ if (index[0] == 1) { int ii, jj, bc_edges[4] = { 3, 11, 7, 8 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Eliminate boundary conditions on y = 0 */ if (index[1] == 1) { int ii, jj, bc_edges[4] = { 0, 9, 4, 8 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Eliminate boundary conditions on z = 0 */ if (index[2] == 1) { int ii, jj, bc_edges[4] = { 0, 1, 2, 3 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Eliminate boundary conditions on x = 1 */ if (index[0] == N*n) { int ii, jj, bc_edges[4] = { 1, 10, 5, 9 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Eliminate boundary conditions on y = 1 */ if (index[1] == N*n) { int ii, jj, bc_edges[4] = { 2, 10, 6, 11 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Eliminate boundary conditions on z = 1 */ if (index[2] == N*n) { int ii, jj, bc_edges[4] = { 4, 5, 6, 7 }; for (ii = 0; ii < 4; ii++) { for (jj = 0; jj < 12; jj++) S[bc_edges[ii]][jj] = S[jj][bc_edges[ii]] = 0.0; S[bc_edges[ii]][bc_edges[ii]] = 1.0; F[bc_edges[ii]] = 0.0; } } /* Assemble the matrix */ HYPRE_SStructMatrixAddFEMValues(A, part, index, &S[0][0]); /* Assemble the vector */ HYPRE_SStructVectorAddFEMValues(b, part, index, F); } } /* Collective calls finalizing the matrix and vector assembly */ HYPRE_SStructMatrixAssemble(A); HYPRE_SStructVectorAssemble(b); } /* 3. Create the discrete gradient matrix G, which is needed in AMS. */ { HYPRE_Int part = 0; HYPRE_Int stencil_size = 2; /* Define the discretization stencil relating the edges and nodes of the grid. */ { HYPRE_Int ndim = 3; HYPRE_Int entry; HYPRE_Int var = 0; /* the node variable */ /* The discrete gradient stencils connect edge to node variables. */ HYPRE_Int Gx_offsets[2][3] = {{-1,0,0},{0,0,0}}; /* x-edge [7]-[6] */ HYPRE_Int Gy_offsets[2][3] = {{0,-1,0},{0,0,0}}; /* y-edge [5]-[6] */ HYPRE_Int Gz_offsets[2][3] = {{0,0,-1},{0,0,0}}; /* z-edge [2]-[6] */ HYPRE_SStructStencilCreate(ndim, stencil_size, &G_stencil[0]); HYPRE_SStructStencilCreate(ndim, stencil_size, &G_stencil[1]); HYPRE_SStructStencilCreate(ndim, stencil_size, &G_stencil[2]); for (entry = 0; entry < stencil_size; entry++) { HYPRE_SStructStencilSetEntry(G_stencil[0], entry, Gx_offsets[entry], var); HYPRE_SStructStencilSetEntry(G_stencil[1], entry, Gy_offsets[entry], var); HYPRE_SStructStencilSetEntry(G_stencil[2], entry, Gz_offsets[entry], var); } } /* Set up the Graph - this determines the non-zero structure of the matrix. */ { HYPRE_Int nvars = 3; HYPRE_Int var; /* the edge variables */ /* Create the discrete gradient graph object */ HYPRE_SStructGraphCreate(MPI_COMM_WORLD, edge_grid, &G_graph); /* See MatrixSetObjectType below */ HYPRE_SStructGraphSetObjectType(G_graph, HYPRE_PARCSR); /* Since the discrete gradient relates edge and nodal variables (it is a rectangular matrix), we have to specify the domain (column) grid. */ HYPRE_SStructGraphSetDomainGrid(G_graph, node_grid); /* Tell the graph which stencil to use for each edge variable on each part (we only have one part). */ for (var = 0; var < nvars; var++) HYPRE_SStructGraphSetStencil(G_graph, part, var, G_stencil[var]); /* Assemble the graph */ HYPRE_SStructGraphAssemble(G_graph); } /* Set up the SStruct Matrix */ { /* Create the matrix object */ HYPRE_SStructMatrixCreate(MPI_COMM_WORLD, G_graph, &G); /* Use a ParCSR storage */ HYPRE_SStructMatrixSetObjectType(G, HYPRE_PARCSR); /* Indicate that the matrix coefficients are ready to be set */ HYPRE_SStructMatrixInitialize(G); } /* Set the discrete gradient values, assuming a "natural" orientation of the edges (i.e. one in agreement with the coordinate directions). */ { int i; int nedges = n*(n+1)*(n+1); double *values; HYPRE_Int stencil_indices[2] = {0,1}; /* the nodes of each edge */ values = calloc(2*nedges, sizeof(double)); /* The edge orientation is fixed: from first to second node */ for (i = 0; i < nedges; i++) { values[2*i] = -1.0; values[2*i+1] = 1.0; } /* Set the values in the discrete gradient x-edges */ { HYPRE_Int var = 0; HYPRE_Int ilower[3] = {1 + pi*n, 0 + pj*n, 0 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructMatrixSetBoxValues(G, part, ilower, iupper, var, stencil_size, stencil_indices, values); } /* Set the values in the discrete gradient y-edges */ { HYPRE_Int var = 1; HYPRE_Int ilower[3] = {0 + pi*n, 1 + pj*n, 0 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructMatrixSetBoxValues(G, part, ilower, iupper, var, stencil_size, stencil_indices, values); } /* Set the values in the discrete gradient z-edges */ { HYPRE_Int var = 2; HYPRE_Int ilower[3] = {0 + pi*n, 0 + pj*n, 1 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructMatrixSetBoxValues(G, part, ilower, iupper, var, stencil_size, stencil_indices, values); } free(values); } /* Finalize the matrix assembly */ HYPRE_SStructMatrixAssemble(G); } /* 4. Create the vectors of nodal coordinates xcoord, ycoord and zcoord, which are needed in AMS. */ { int i, j, k; HYPRE_Int part = 0; HYPRE_Int var = 0; /* the node variable */ HYPRE_Int index[3]; double xval, yval, zval; /* Create empty vector objects */ HYPRE_SStructVectorCreate(MPI_COMM_WORLD, node_grid, &xcoord); HYPRE_SStructVectorCreate(MPI_COMM_WORLD, node_grid, &ycoord); HYPRE_SStructVectorCreate(MPI_COMM_WORLD, node_grid, &zcoord); /* Set the object type to ParCSR */ HYPRE_SStructVectorSetObjectType(xcoord, HYPRE_PARCSR); HYPRE_SStructVectorSetObjectType(ycoord, HYPRE_PARCSR); HYPRE_SStructVectorSetObjectType(zcoord, HYPRE_PARCSR); /* Indicate that the vector coefficients are ready to be set */ HYPRE_SStructVectorInitialize(xcoord); HYPRE_SStructVectorInitialize(ycoord); HYPRE_SStructVectorInitialize(zcoord); /* Compute and set the coordinates of the nodes */ for (i = 0; i <= n; i++) for (j = 0; j <= n; j++) for (k = 0; k <= n; k++) { index[0] = i + pi*n; index[1] = j + pj*n; index[2] = k + pk*n; xval = index[0]*h; yval = index[1]*h; zval = index[2]*h; HYPRE_SStructVectorSetValues(xcoord, part, index, var, &xval); HYPRE_SStructVectorSetValues(ycoord, part, index, var, &yval); HYPRE_SStructVectorSetValues(zcoord, part, index, var, &zval); } /* Finalize the vector assembly */ HYPRE_SStructVectorAssemble(xcoord); HYPRE_SStructVectorAssemble(ycoord); HYPRE_SStructVectorAssemble(zcoord); } /* 5. Set up a SStruct Vector for the solution vector x */ { HYPRE_Int part = 0; int nvalues = n*(n+1)*(n+1); double *values; values = calloc(nvalues, sizeof(double)); /* Create an empty vector object */ HYPRE_SStructVectorCreate(MPI_COMM_WORLD, edge_grid, &x); /* Set the object type to ParCSR */ HYPRE_SStructVectorSetObjectType(x, HYPRE_PARCSR); /* Indicate that the vector coefficients are ready to be set */ HYPRE_SStructVectorInitialize(x); /* Set the values for the initial guess x-edge */ { HYPRE_Int var = 0; HYPRE_Int ilower[3] = {1 + pi*n, 0 + pj*n, 0 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructVectorSetBoxValues(x, part, ilower, iupper, var, values); } /* Set the values for the initial guess y-edge */ { HYPRE_Int var = 1; HYPRE_Int ilower[3] = {0 + pi*n, 1 + pj*n, 0 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructVectorSetBoxValues(x, part, ilower, iupper, var, values); } /* Set the values for the initial guess z-edge */ { HYPRE_Int var = 2; HYPRE_Int ilower[3] = {0 + pi*n, 0 + pj*n, 1 + pk*n}; HYPRE_Int iupper[3] = {n + pi*n, n + pj*n, n + pk*n}; HYPRE_SStructVectorSetBoxValues(x, part, ilower, iupper, var, values); } free(values); /* Finalize the vector assembly */ HYPRE_SStructVectorAssemble(x); } /* Finalize current timing */ hypre_EndTiming(time_index); hypre_PrintTiming("SStruct phase times", MPI_COMM_WORLD); hypre_FinalizeTiming(time_index); hypre_ClearTiming(); /* 6. Set up and call the PCG-AMS solver (Solver options can be found in the Reference Manual.) */ { double final_res_norm; HYPRE_Int its; HYPRE_ParCSRMatrix par_A; HYPRE_ParVector par_b; HYPRE_ParVector par_x; HYPRE_ParCSRMatrix par_G; HYPRE_ParVector par_xcoord; HYPRE_ParVector par_ycoord; HYPRE_ParVector par_zcoord; /* Extract the ParCSR objects needed in the solver */ HYPRE_SStructMatrixGetObject(A, (void **) &par_A); HYPRE_SStructVectorGetObject(b, (void **) &par_b); HYPRE_SStructVectorGetObject(x, (void **) &par_x); HYPRE_SStructMatrixGetObject(G, (void **) &par_G); HYPRE_SStructVectorGetObject(xcoord, (void **) &par_xcoord); HYPRE_SStructVectorGetObject(ycoord, (void **) &par_ycoord); HYPRE_SStructVectorGetObject(zcoord, (void **) &par_zcoord); if (myid == 0) printf("Problem size: %lld\n\n", hypre_ParCSRMatrixGlobalNumRows((hypre_ParCSRMatrix*)par_A)); /* Start timing */ time_index = hypre_InitializeTiming("AMS Setup"); hypre_BeginTiming(time_index); /* Create solver */ HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver); /* Set some parameters (See Reference Manual for more parameters) */ HYPRE_PCGSetMaxIter(solver, maxit); /* max iterations */ HYPRE_PCGSetTol(solver, tol); /* conv. tolerance */ HYPRE_PCGSetTwoNorm(solver, 0); /* use the two norm as the stopping criteria */ HYPRE_PCGSetPrintLevel(solver, 2); /* print solve info */ HYPRE_PCGSetLogging(solver, 1); /* needed to get run info later */ /* Create AMS preconditioner */ HYPRE_AMSCreate(&precond); /* Set AMS parameters */ HYPRE_AMSSetMaxIter(precond, 1); HYPRE_AMSSetTol(precond, 0.0); HYPRE_AMSSetCycleType(precond, cycle_type); HYPRE_AMSSetPrintLevel(precond, 1); /* Set discrete gradient */ HYPRE_AMSSetDiscreteGradient(precond, par_G); /* Set vertex coordinates */ HYPRE_AMSSetCoordinateVectors(precond, par_xcoord, par_ycoord, par_zcoord); if (singular_problem) HYPRE_AMSSetBetaPoissonMatrix(precond, NULL); /* Smoothing and AMG options */ HYPRE_AMSSetSmoothingOptions(precond, rlx_type, rlx_sweeps, rlx_weight, rlx_omega); HYPRE_AMSSetAlphaAMGOptions(precond, amg_coarsen_type, amg_agg_levels, amg_rlx_type, theta, amg_interp_type, amg_Pmax); HYPRE_AMSSetBetaAMGOptions(precond, amg_coarsen_type, amg_agg_levels, amg_rlx_type, theta, amg_interp_type, amg_Pmax); /* Set the PCG preconditioner */ HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_AMSSolve, (HYPRE_PtrToSolverFcn) HYPRE_AMSSetup, precond); /* Call the setup */ HYPRE_ParCSRPCGSetup(solver, par_A, par_b, par_x); /* Finalize current timing */ hypre_EndTiming(time_index); hypre_PrintTiming("Setup phase times", MPI_COMM_WORLD); hypre_FinalizeTiming(time_index); hypre_ClearTiming(); /* Start timing again */ time_index = hypre_InitializeTiming("AMS Solve"); hypre_BeginTiming(time_index); /* Call the solve */ HYPRE_ParCSRPCGSolve(solver, par_A, par_b, par_x); /* Finalize current timing */ hypre_EndTiming(time_index); hypre_PrintTiming("Solve phase times", MPI_COMM_WORLD); hypre_FinalizeTiming(time_index); hypre_ClearTiming(); /* Get some info */ HYPRE_PCGGetNumIterations(solver, &its); HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm); /* Clean up */ HYPRE_AMSDestroy(precond); HYPRE_ParCSRPCGDestroy(solver); /* Gather the solution vector */ HYPRE_SStructVectorGather(x); if (myid == 0) { printf("\n"); printf("Iterations = %lld\n", its); printf("Final Relative Residual Norm = %g\n", final_res_norm); printf("\n"); } } /* Free memory */ HYPRE_SStructGridDestroy(edge_grid); HYPRE_SStructGraphDestroy(A_graph); HYPRE_SStructMatrixDestroy(A); HYPRE_SStructVectorDestroy(b); HYPRE_SStructVectorDestroy(x); HYPRE_SStructGridDestroy(node_grid); HYPRE_SStructGraphDestroy(G_graph); HYPRE_SStructStencilDestroy(G_stencil[0]); HYPRE_SStructStencilDestroy(G_stencil[1]); HYPRE_SStructStencilDestroy(G_stencil[2]); HYPRE_SStructMatrixDestroy(G); HYPRE_SStructVectorDestroy(xcoord); HYPRE_SStructVectorDestroy(ycoord); HYPRE_SStructVectorDestroy(zcoord); /* Finalize MPI */ MPI_Finalize(); return 0; }