Current version: v1.0 - initial working version
Implements a python module pyHNC for solving the Ornstein-Zernike
(OZ) equation using the hypernetted-chain (HNC) closure, for
single-component systems, with soft potentials (no hard cores) such as
dissipative particle dynamics (DPD). It uses the
FFTW library to do the Fourier transforms,
accessed via the pyFFTW
wrapper, together with basic NumPy function
calls.
The code is intended for rapid prototyping, but is also partly pedagogical with the intent of attempting to capture some of the tacit knowledge involved in undertaking this kind of calculation.
Basic codes in the repository include:
pyHNC.py: python module implementing the functionality;fftw_demo.py: test FFTW for Fourier-Bessel transforms;dpd_demo.py: demonstrate the capabilities for standard DPD;dpd_eos.py: calculate data for standard DPD equation of state (EoS);dpd_gw_compare.py: compare to Groot and Warren, J. Chem. Phys. 107, 4423 (1997).
For more details see extensive comments in the codes, and also the documentation for the parallel SunlightHNC project. The book "Theory of Simple Liquids" by Jean-Pierre Hansen and Ian R. McDonald is foundational -- either the 3rd edition (2006) or the 4th edition (2013).
Simplifications compared to the (faster) SunlightHNC include the fact that hard cores are not implemented, only a single component is assumed, and simple Picard iteration is used rather than the Ng accelerator. The present code is also implemented entirely in python, rather than SunlightHNC which is mostly implemented in FORTRAN 90.
The --sunlight option for dpd_demo.py compares the present
implementation to results from
SunlightHNC. For
this to work, the compiled python interface (*.pyf) and shared
object (*.so) dynamically-linked library from
SunlightHNC should be
made acessible to dpd_demo.py. This can be done for example by
copying oz.pyf and oz.*.so from
SunlightHNC
(available after running make) to the directory containing
dpd_demo.py.
Codes related to the nDPD model in Sokhan et al., Soft Matter 19, 5824 (2023);
ndpd_demo.py: vanilla nDPD, as in the above paper;ndpd_rpa.py: implement the RPA and EXP approximations for the EoS;ndpd_wca.py: implement Weeks-Chandler-Andersen (WCA) high-temperature approx for EoS;ndpd_liquidus.py: estimate the liquidus as the point where p = 0; condor-enabled;
Other codes related to many-body DPD (MBDPD).
mdpd_hnc.py: various HNC variants for MBDPD; condor-enabled;mdpd_dft.py: 'vanilla' DFT for MBDPD;mdpd_percus.py: Percus-like DFT for MBDPD;
Other files herein:
timing.py: for measuring performance of condor DAGMan jobs.solute_demo.ipynb: jupyter notebook illustrating solute calculations;mu_dpd_hendrikse2025.csv: solute excess chemical potential data digitised from Fig. 1 of Hendrikse et al., Phys. Chem. Chem. Phys. 27, 1554-66 (2025).
What's being solved here is the Ornstein-Zernike (OZ) equation in reciprocal space in the form
in combination with the hypernetted-chain (HNC) closure in real space as
using Picard iteration.
Here
Given an initial guess
- Fourier-Bessel forward transform
$c(r) \to c(q)$ ; - solve the OZ equation for
$e(q) = c(q) / [1-\rho\, c(q)]-c(q)$ ; - Fourier-Bessel back transform
$e(q) \to e(r)$ ; - implement the HNC closure as
$c\prime(r)=\exp[-v(r)+e(r)]-e(r)-1$ ; - replace
$c(r)$ by$\alpha\,c\prime(r)+(1-\alpha)\,c(r)$ (Picard mixing step); - check for convergence by comparing
$c(r)$ and$c\prime(r)$ ; - if not converged, repeat.
Typically this works for a Picard mixing fraction
A suitable initial guess for soft potentials is
Once converged, the pair correlation function and static structure factor can be found from:
Thermodynamic quantities can also now be computed, for example the excess energy density and virial pressure follow from Eqs. (2.5.20) and (2.5.22) in Hansen and McDonald, "Theory of Simple Liquids" (3rd edition) as:
where
In practice these should usually be calculated with
Eq. (2.6.12) in Hansen and McDonald shows that in units of
where
Employing this at
Given
A result peculiar to the HNC is the closed-form expression for the chemical potential given in Eq. (4.3.21) in Hansen and McDonald (I thank Andrew Masters for drawing my attention to this),
Here the reference standard state corresponds to
It follows from the basic definition of the free energy
Since the free energy can be differentiated to find the pressure, this
is the basis for the so-called energy route to the EoS. For example,
if the free energy density is available as a function of density,
The mean-field contribution to the free energy can be calculated
immediately since the contribution to the energy density
For the non-mean-field correlation contribution we sketch the algorithm:
- solve the HNC closure of OZ equation for the scaled pair potential
$\lambda\,v(r)$ to get$h(r;\lambda)$ ; - calculate th excess energy
$\Delta e(\lambda)=2\pi\rho^2\int_0^\infty\text{d}r\, r^2\,v(r)\,h(r;\lambda)$ with the unscaled pair potential; - the excess correlation free energy is then the integral
$\Delta f=\int_0^1\text{d}\lambda\,\Delta e(\lambda)$ - the excess correlation pressure then follows from
$\Delta p = \rho^2\,\text{d}(\Delta f/\rho)/\text{d}\rho$ . This should be added to the mean-field contribution to obtain the excess pressure, and the whole added to the ideal contribution to find the total pressure.
In practice a basic trapezium rule can often suffice for the integration step in the above. The derivative with respect to density would usually be computed numerically too.
The above methodology can be repurposed to solve also the case of an infinitely dilute solute inside a solvent. To do this we start from the OZ equations for a two-component mixture and specialise to the case where the density of the second component vanishes. In this limit the OZ equations partially decouple in the sense that the solvent case reduces to the above one-component problem, which can be solved as already indicated. The off-diagonal OZ relations become
The equivalence between the two can be proven from the OZ relation for the solvent. These should be supplemented by the HNC closure for the off-diagonal case
The second off-diagonal OZ relation can be written as
where
Applications of this infinitely-dilute solute limit are in the process of being investigated.
The code illustrates how to implement three-dimensional Fourier transforms using FFTW. The starting point is the Fourier transform pair
If the functions have radial symmetry, these reduce to the forward and backward Fourier-Bessel transforms
From the FFTW
documentation,
RODFT00 implements
where
To cast this into the right form, set
For the desired Fourier-Bessel forward transform we can then write
with the factor after the multiplication sign being calculated by
RODFT00.
The Fourier-Bessel back transform is handled similarly.
Timing tests (below) indicate that FFTW is very fast when the array
length
Hence, the grid size
$ time ./fftw_demo.py --ng=2^22 --deltar=1e-3
ng, Δr, Δq, iters = 4194304 0.001 0.0007490140565847857 10
FFTW array sizes = 4194303
real 0m4.087s
user 0m3.928s
sys 0m0.822s
$ time ./fftw_demo.py --ng=2^22+1 --deltar=1e-3
ng, Δr, Δq, iters = 4194305 0.001 0.0007490138780059611 10
FFTW array sizes = 4194304
real 0m10.682s
user 0m9.840s
sys 0m1.505s
$ time ./fftw_demo.py --ng=2^22-1 --deltar=1e-3
ng, Δr, Δq, iters = 4194303 0.001 0.0007490142351636954 10
FFTW array sizes = 4194302
real 0m14.539s
user 0m14.079s
sys 0m1.121s
In the code, FFTW is set up with the most basic FFTW_ESTIMATE
planner flag.
This may make a difference in the end, but timing tests indicate that
with a power of two as used here, it takes much longer for FFTW to
find an optimized plan, than it does if it just uses the simple
heuristic implied by FFTW_ESTIMATE. Obviously some further
investigations could be undertaken into this aspect.
The TL ; DR take-home message here is set
From above
--deltar=0.05 --ng=2^11 (ng=2048 ⇒ Δq ≈ 0.031 )
--deltar=0.02 --ng=2^13 (ng=8192 ⇒ Δq ≈ 0.019 )
--deltar=0.01 --ng=2^15 (ng=32768 ⇒ Δq ≈ 0.0096 )
--deltar=5e-3 --ng=2^17 (ng=131072 ⇒ Δq ≈ 4.79e-3)
--deltar=2e-3 --ng=2^20 (ng=1048576 ⇒ Δq ≈ 1.50e-3)
--deltar=1e-3 --ng=2^22 (ng=4194304 ⇒ Δq ≈ 0.749e-3)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
This program is copyright © 2023-2026 Patrick B Warren (STFC).
Additional modifications copyright © 2025 Joshua F Robinson (STFC).
Send email to patrick.warren{at}stfc.ac.uk.