Automatic differentiation and thermodynamics with `num-dual` and `feos`

92 points gernithereal

Hello /r/rust!

We are happy to announce num-dual and feos, two crates that we've been working on over the last years.

num-dual

num-dual provides an implementation of (hyper-) dual numbers. These numbers can be used for automatic differentiation. Using the DualNum<T> trait, you can write functions that are generic over any dual number type (including f64). Consider this function

fn f<D: DualNum<f64>>(x: D, y: D) -> D {
    x.powi(3) * y.powi(2)
}

fn main() {
    let (x, y) = (5.0f64, 4.0);

    // Simple function evaluation
    let fx = f(x, y);
    println!("{}", fx); // 2000

    // Simple derivative w.r.t. x
    let dfdx = f(Dual::from_re(x).derive(), Dual::from_re(y));
    println!("{}", dfdx); // 2000 + [1200]ε

    // Second order partial derivative w.r.t. x and y
    let d2fdxdy = f(
        HyperDual::from_re(x).derive1(),
        HyperDual::from_re(y).derive2(),
    );
    println!("{}", d2fdxdy); // 2000 + [1200]ε1 + [1000]ε2 + [600]ε1ε2
}

Depending on the actual data type used, any derivative (including higher order partial derivatives) can be calculated. E.g. providing f64 for x and y results in an implementation identical to using intrinsic operations for f64 while providing Dual results in a function evaluation including the first partial derivative. HyperDual would yield the first and second partial derivatives, and so on. The crate also provides a Python interface via PyO3 (pip install num-dual).

feos

feos is a thermodynamics toolkit for equations of state and classical density functional theory that heavily utilizes num-dual. With feos you can use provided models to compute properties such as pressures, densities, and entropies as well as phase equilibria, critical points or surface tensions for pure substances and mixtures. We wrote feos to be (hopefully) easy to extend with new models, since no derivatives have to be implemented (dual numbers take care of that).

feos provides a feature-complete Python interface using PyO3 (pip install feos). This allows for usage within Jupyter notebooks, which makes sharing research results super transparent and easy. You can even write your equation of state model as a Python class and plug it into feos. (We also did some small tests and ran it in the browser via wasm)


These crates emerged from codes we built (or extended) over the last years at our institute. They were originally written in fortran. We started an implementation in Rust (first as a side project) because we were intrigued by the language, but it turned out to be a lot of fun and also way more maintainable. And, of course, we can make use of awesome crates such as serde (to provide parameter input in different file formats), rayon, ndarray, rustfft and PyO3.

Although these two crates are very specific, we hope that they will be helpful for other Rustaceans! :)