diff --git a/docs/Manifest.toml b/docs/Manifest.toml index 410e564..59f3129 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -155,9 +155,9 @@ version = "0.1.3" [[deps.MPItrampoline_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "Pkg", "TOML"] -git-tree-sha1 = "17fd6861c826f96c5cc4bf390c046db3b3b694e0" +git-tree-sha1 = "2e56a6ec54a500679f5820fd0d9088500d2596d6" uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" -version = "5.0.0+0" +version = "5.0.1+0" [[deps.Markdown]] deps = ["Base64"] diff --git a/docs/make.jl b/docs/make.jl index c6f19b5..37c89ef 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -17,6 +17,7 @@ makedocs( pages = Any[ "Home" => "index.md", "matrix-vector.md", + "solvers-preconditioners.md", "libhypre.md", ], draft = liveserver, diff --git a/docs/src/solvers-preconditioners.md b/docs/src/solvers-preconditioners.md new file mode 100644 index 0000000..fd57608 --- /dev/null +++ b/docs/src/solvers-preconditioners.md @@ -0,0 +1,84 @@ +# Solvers and preconditioners + +HYPRE.jl wraps most of HYPREs [ParCSR solvers and +preconditioners](https://hypre.readthedocs.io/en/latest/api-sol-parcsr.html). + +The synopsis for HYPRE.jl's wrappers is the same for all solvers: + +```julia +# Setup up linear system (see previous section) +A = HYPREMatrix(...) +b = HYPREVector(...) + +# Create a solver +solver = HYPRESolver(; settings...) + +# Solve A x = b +x = HYPRE.solve(solver, A, b) +``` + +Settings are passed as keyword arguments, with the names matching directly to +`HYPRE_SolverSetXXX` calls from the HYPRE C API (see example below). Most settings are +passed directly to HYPRE, for example `Tol = 1e-9` would be passed directly to +`HYPRE_SolverSetTol` for the correponding solver. + +Setting a preconditioner can be done by passing a `HYPRESolver` directly with the `Precond` +keyword argument, without any need to also pass the corresponding `HYPRE_SolverSetup` and +`HYPRE_SolverSolve` as must be done in the C API. In addition, solvers that have required +settings when used as a preconditioner will have those applied automatically. + +HYPRE.jl adds finalizers to the solvers, which takes care of calling the their respective +`HYPRE_SolverDestroy` function when the solver is garbage collected. + +#### Example: Conjugate gradient with algebraic multigrid preconditioner + +Here is an example of creating a `PCG` (conjugate gradient) solver with `BoomerAMG` +(algebraic multigrid) as preconditioner: + +```julia +# Setup up linear system +A = HYPREMatrix(...) +b = HYPREVector(...) + +# Preconditioner +precond = HYPRE.BoomerAMG(; RelaxType = 6, CoarsenType = 6) + +# Solver +solver = HYPRE.PCG(; MaxIter = 1000, Tol = 1e-9, Precond = precond) + +# Solve +x = HYPRE.solve(solver, A, b) +``` + +Note that `Tol = 0.0` and `MaxIter = 1` are required settings when using `BoomerAMG` as a +preconditioner. These settings are added automatically since it is passed as a +preconditioner to the `PCG` solver. + +!!! not "Corresponding C code" + For comparison, here is the corresponding C code for setting up the solver above: + ```c + /* Setup linear system */ + HYPRE_IJMatrix A; + HYPRE_IJVector b, x; + + /* Preconditioner */ + HYPRE_Solver precond; + HYPRE_BoomerAMGCreate(&precond); + HYPRE_BoomerAMGSetCoarsenType(precond, 6); + HYPRE_BoomerAMGSetRelaxType(precond, 6); + HYPRE_BoomerAMGSetTol(precond, 0.0); + HYPRE_BoomerAMGSetMaxIter(precond, 1); + + /* Solver */ + HYPRE_Solver solver; + HYPRE_ParCSRPCGCreate(MPI_COMM_WORLD, &solver); + HYPRE_PCGSetMaxIter(solver, 1000); + + /* Add preconditioner */ + HYPRE_PCGSetPrecond(solver, (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSolve, + (HYPRE_PtrToSolverFcn) HYPRE_BoomerAMGSetup, precond); + + /* Solve */ + HYPRE_ParCSRPCGSetup(solver, A, b, x); + HYPRE_ParCSRPCGSolve(solver, A, b, x); + ```