Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

User interface

In this chapter, we start the other way around, and first have a look at the proposed user interfance. The full file lib.rs is provided below. It mostly contains an enum and a helper function for solving the 2D Poisson problem.

Click here to view: lib.rs.
#![allow(unused)]
fn main() {
//! This file is part of the Poisson 2D crate.
//!! It provides functionality for solving the 2D Poisson equation using finite element methods (FEM).
//!
//! The crate includes modules for elements, mesh, quadrature rules, and solvers.

pub mod element;
pub mod mesh;
pub mod quadrature;
pub mod solver;

pub use solver::{assemble_and_solve_dense, assemble_and_solve_sparse};

pub use mesh::Mesh2d;
pub use nalgebra::DVector;

/// Enum representing the type of solver to use
// ANCHOR: solver_type
pub enum SolverType {
    Dense,
    Sparse,
}
// ANCHOR_END: solver_type

/// Helper function for solving the 2D Poisson problem
///
/// This function takes a mesh, boundary nodes, boundary function, source function, and solver type.
/// Arguments:
/// - `mesh`: The mesh representing the domain.
/// - `boundary_nodes`: Indices of the nodes on the boundary.
/// - `boundary_fn`: Function defining the boundary condition.
/// - `source_fn`: Function defining the source term.
/// - `solver_type`: Type of solver to use (Dense or Sparse).
///
/// Returns:
/// - A vector containing the solution at the mesh nodes.
// ANCHOR: solve_poisson_2d
pub fn solve_poisson_2d<F>(
    mesh: &Mesh2d,
    boundary_nodes: &[usize],
    boundary_fn: &F,
    source_fn: &F,
    solver_type: SolverType,
) -> DVector<f64>
where
    F: Fn(f64, f64) -> f64,
{
    match solver_type {
        SolverType::Dense => assemble_and_solve_dense(mesh, boundary_nodes, boundary_fn, source_fn),
        SolverType::Sparse => {
            assemble_and_solve_sparse(mesh, boundary_nodes, boundary_fn, source_fn)
        }
    }
}
// ANCHOR_END: solve_poisson_2d
}

Solver type

In this example, we consider two types of finite element solvers:

  • A dense solver which assembles dense matrices and uses a dense solver for the linear system.
  • A sparse solver which assembles sparse matrices and uses a sparse solver for the linear system.

This is encoded by defining the following enumerate:

#![allow(unused)]
fn main() {
pub enum SolverType {
    Dense,
    Sparse,
}
}

It can be used to pick the solver type by passing SolverType::Dense or SolverType::Sparse to the helper function discussed below.

Helper function

The helper function that the user should call is shown below. It takes the following input arguments:

  • A mesh, given as a Mesh2d struct implemented in the mesh.rs module.
  • The boundary nodes and the boundary function () for applying Dirichlet boundary conditions.
  • The source function .
  • And the solver type (SolverType::Dense or SolverType::Sparse).

Based on the chosen solver type, the function either calls the dense or sparse methods thanks to pattern matching.

#![allow(unused)]
fn main() {
pub fn solve_poisson_2d<F>(
    mesh: &Mesh2d,
    boundary_nodes: &[usize],
    boundary_fn: &F,
    source_fn: &F,
    solver_type: SolverType,
) -> DVector<f64>
where
    F: Fn(f64, f64) -> f64,
{
    match solver_type {
        SolverType::Dense => assemble_and_solve_dense(mesh, boundary_nodes, boundary_fn, source_fn),
        SolverType::Sparse => {
            assemble_and_solve_sparse(mesh, boundary_nodes, boundary_fn, source_fn)
        }
    }
}
}