HYPRE Quick Start
This quick start walks through a complete beginner workflow:
- Pull the E4S base container
- Start an interactive container session
- Install and load HYPRE with Spack
- Build and run a simple HYPRE program
Step 1: Pull Container
Download the E4S base image from Docker Hub.
Flip for details
Use ecpe4s/e4s-spack-cpu as a portable environment with Spack and MPI.
Step 2: Enter Container
Run the container in interactive mode.
Flip for details
Mount a local working directory and get a shell prompt in the container.
Step 3: Install HYPRE
Install and load HYPRE with Spack.
Flip for details
Build HYPRE once, then load it into your environment for compile and run.
Step 4: Run Example
Compile and run a minimal HYPRE program.
Flip for details
Use mpicc with the HYPRE include and library paths from Spack.
1. Pull the E4S Base Container
docker pull ecpe4s/e4s-spack-cpu:latest
Optional sanity check:
docker images ecpe4s/e4s-spack-cpu
2. Start an Interactive Container Session
Create a local work directory:
mkdir -p ~/hypre-quickstart
cd ~/hypre-quickstart
Start the container and mount your current directory at /work:
docker run -it --rm \
--entrypoint bash \
-v "$PWD:/work" \
-w /work \
ecpe4s/e4s-spack-cpu:latest
You are now inside the container.
3. Install and Load HYPRE with Spack
Inside the container, first load MPI:
spack load mpich
Install HYPRE (this can take several minutes):
spack install hypre +mpi ^mpich
Load HYPRE:
spack load hypre +mpi ^mpich
Confirm HYPRE is loaded:
spack find --loaded
Record the install location for compile flags:
HYPRE_DIR=$(spack location -i hypre)
echo "$HYPRE_DIR"
4. Build and Run a Tridiagonal HYPRE Solve
Create a file named hypre_hello.c.
You can do this with an editor, or directly in the terminal using:
cat > hypre_hello.c
Then paste the following code and press Ctrl-D to save:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include "HYPRE.h"
#include "HYPRE_IJ_mv.h"
#include "HYPRE_parcsr_ls.h"
int main(int argc, char *argv[])
{
int n = 5;
if (argc > 1) {
n = atoi(argv[1]);
}
if (n < 2) {
n = 2;
}
MPI_Init(&argc, &argv);
int rank, nprocs;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
HYPRE_Init();
/* Partition rows across ranks. */
int rows_per_rank = n / nprocs;
int remainder = n % nprocs;
int local_n = rows_per_rank + (rank < remainder ? 1 : 0);
int ilower = rank * rows_per_rank + (rank < remainder ? rank : remainder);
int iupper = ilower + local_n - 1;
HYPRE_IJMatrix A;
HYPRE_IJMatrixCreate(MPI_COMM_WORLD, ilower, iupper, ilower, iupper, &A);
HYPRE_IJMatrixSetObjectType(A, HYPRE_PARCSR);
HYPRE_IJMatrixInitialize(A);
for (int i = ilower; i <= iupper; i++) {
int cols[3];
double vals[3];
int ncols = 0;
if (i - 1 >= 0) {
cols[ncols] = i - 1;
vals[ncols] = -1.0;
ncols++;
}
cols[ncols] = i;
vals[ncols] = 2.0;
ncols++;
if (i + 1 < n) {
cols[ncols] = i + 1;
vals[ncols] = -1.0;
ncols++;
}
int row = i;
HYPRE_IJMatrixSetValues(A, 1, &ncols, &row, cols, vals);
}
HYPRE_IJMatrixAssemble(A);
HYPRE_ParCSRMatrix par_A;
HYPRE_IJMatrixGetObject(A, (void **) &par_A);
HYPRE_IJVector b;
HYPRE_IJVectorCreate(MPI_COMM_WORLD, ilower, iupper, &b);
HYPRE_IJVectorSetObjectType(b, HYPRE_PARCSR);
HYPRE_IJVectorInitialize(b);
HYPRE_IJVector x;
HYPRE_IJVectorCreate(MPI_COMM_WORLD, ilower, iupper, &x);
HYPRE_IJVectorSetObjectType(x, HYPRE_PARCSR);
HYPRE_IJVectorInitialize(x);
for (int i = ilower; i <= iupper; i++) {
int idx = i;
double bval = 1.0;
double xval = 0.0;
HYPRE_IJVectorSetValues(b, 1, &idx, &bval);
HYPRE_IJVectorSetValues(x, 1, &idx, &xval);
}
HYPRE_IJVectorAssemble(b);
HYPRE_IJVectorAssemble(x);
HYPRE_ParVector par_b;
HYPRE_ParVector par_x;
HYPRE_IJVectorGetObject(b, (void **) &par_b);
HYPRE_IJVectorGetObject(x, (void **) &par_x);
HYPRE_Solver solver;
HYPRE_Solver precond;
HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver);
HYPRE_PCGSetMaxIter(solver, 100);
HYPRE_PCGSetTol(solver, 1.0e-10);
HYPRE_PCGSetPrintLevel(solver, 2);
HYPRE_BoomerAMGCreate(&precond);
HYPRE_BoomerAMGSetPrintLevel(precond, 0);
HYPRE_BoomerAMGSetCoarsenType(precond, 6);
HYPRE_BoomerAMGSetRelaxType(precond, 6);
HYPRE_BoomerAMGSetNumSweeps(precond, 1);
HYPRE_ParCSRPCGSetPrecond(
solver,
(HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSolve,
(HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSetup,
precond);
HYPRE_ParCSRPCGSetup(solver, par_A, par_b, par_x);
HYPRE_ParCSRPCGSolve(solver, par_A, par_b, par_x);
int num_iterations = 0;
double final_res_norm = 0.0;
HYPRE_PCGGetNumIterations(solver, &num_iterations);
HYPRE_PCGGetFinalRelativeResidualNorm(solver, &final_res_norm);
if (rank == 0) {
printf("Solved 1D tridiagonal system with n = %d\n", n);
printf("Iterations: %d\n", num_iterations);
printf("Final relative residual norm: %.6e\n", final_res_norm);
}
for (int i = ilower; i <= iupper; i++) {
int idx = i;
double xval = 0.0;
HYPRE_IJVectorGetValues(x, 1, &idx, &xval);
if (rank == 0) {
printf("x[%d] = %.12f\n", i, xval);
}
}
HYPRE_ParCSRPCGDestroy(solver);
HYPRE_BoomerAMGDestroy(precond);
HYPRE_IJVectorDestroy(x);
HYPRE_IJVectorDestroy(b);
HYPRE_IJMatrixDestroy(A);
HYPRE_Finalize();
MPI_Finalize();
return 0;
}
Select the HYPRE library directory (lib or lib64):
if [ -d "$HYPRE_DIR/lib64" ]; then
HYPRE_LIBDIR="$HYPRE_DIR/lib64"
else
HYPRE_LIBDIR="$HYPRE_DIR/lib"
fi
echo "$HYPRE_LIBDIR"
Compile the program with an embedded runtime library path (rpath):
mpicc -O2 hypre_hello.c -o hypre_hello \
-I"$HYPRE_DIR/include" \
-L"$HYPRE_LIBDIR" -Wl,-rpath,"$HYPRE_LIBDIR" -lHYPRE -lm
If you already compiled without rpath and see a libHYPRE runtime error, set:
export LD_LIBRARY_PATH="$HYPRE_LIBDIR:$LD_LIBRARY_PATH"
Run with one MPI rank and the example size n = 5:
mpirun -n 1 ./hypre_hello 5
To change problem size, pass a different n value (for example, 20):
mpirun -n 1 ./hypre_hello 20
Expected output includes lines like:
Solved 1D tridiagonal system with n = 5
Iterations: ...
Final relative residual norm: ...
x[0] = ...
What You Learned
- How to use an E4S base container for a reproducible environment
- How to install and load HYPRE with Spack
- How to compile and run a HYPRE linear solver example
Next, you can extend this by changing the right-hand side, trying larger n, or running with multiple MPI ranks.