Getting started
The main utility of ClassicalDFT.jl is the solve function, which attempts to find the density profiles of all species that solve the set of Euler-Lagrange equations of classical DFT self-consistently.
For this, one needs to specify the geometry of the problem, the functional which describes internal interactions as well as relevant system parameters (temperature, external potential, chemical potential, etc.).
In the following example, we select PlanarGeometry, where all quantities depend only on the $z$ coordinate and are translationally invariant along the $x$ and $y$ directions, and we choose implicit hard walls at the boundaries with boundary=:walls. To describe a confined hard-sphere fluid, a RosenfeldFunctional is constructed in this geometry, the external potential Vext within the box is set to zero, and typical values for temperature T and chemical potential μ are chosen.
We can pass this setup to the solve function, which performs the self-consistent iteration. The result is a NamedTuple containing the equilibrium density profile ρ as a numerical array if the iteration has converged.
L = 10
dz = 0.01
geom = PlanarGeometry(L, dz; boundary=:walls)
functional = RosenfeldFunctional(geom)
Vext(z) = 0
T, μ = 1.0, 3.0
result = solve(functional; Vext, T, μ)
ρ = result.converged ? result.ρ : error("no equilibrium density profile found")Numerical details can be controlled with various keyword arguments of solve.
To monitor the progress, solve can be provided with callbacks which will be invoked in each iteration. For example, PrintCallback prints by default the iteration count and the value of $\Vert \Delta \rho_\mathrm{EL} \Vert_\infty$. An automatically updating plot of the density profile can be displayed with PlotCallback if the package Plots is installed and loaded.
using Plots
callbacks = [PrintCallback(), PlotCallback()]
result = solve(functional; Vext, T, μ, callbacks)