Electrostatics

UAMMD implements fast spectral solvers for the Poisson equation with Gaussian sources of charge with arbitrary widths centered at the particles’ locations. Two solvers are available with triply or doubly periodic boundary conditions.

In general, we want to solve the Poisson equation in a periodic domain in the presence of a charge density f(\vec{\fpos}=(x,y,z)),

\varepsilon\Delta\phi=-f.

Here \varepsilon represents the permittivity of the medium and f accounts for N Gaussian charges of strength Q_i located at \vec{\ppos}_i,

f(\vec{\fpos})= \oper{S}(\vec{\fpos})\vec{Q} = \sum_iQ_i\delta_a(||\vec{\fpos}-\vec{\ppos}_i||).

Let us denote with the vector containing all charges as \vec{Q} = \{Q_1,\dots,Q_N\}. We will use the spreading operator, \oper{S}, (see Immersed Boundary Method) to transform the particles charges to a smooth charge density field. We use the Gaussian kernel,

\delta_a(\vec{r})=\frac{1}{\left(2\pi a^2\right)^{3/2}}\exp{\left(\frac{-r^2}{2a^2}\right)},

Identifying a as the width the charges (notice that the case a\rightarrow 0 corresponds to point charges). Once the Poisson equation is solved we have the value of the potential in every point in space and can be evaluated at the charges locations via the interpolation operator (see Immersed Boundary Method).

\phi_{\vec{\ppos}_i} = \oper{J}_{\vec{\ppos}_i}\phi = \int Q_i\delta_a(\vec{\ppos}_i - \vec{\fpos})\phi(\vec{\fpos})d\vec{\fpos}.

Here \oper{J} represents the interpolation operator, that averages a quantity defined in space to a charge’s location. The electrostatic energy can be computed as

U =  \frac{1}{2}\sum_i{\phi_{\vec{\ppos}_i}}.

In a similar way we compute the electrostatic force, \vec{F}_i = -Q_i\nabla_i{\phi}, acting on each charge from the electric field

\vec{E} = -\nabla{\phi}.

Interpolating again we get

\vec{E}_i = \oper{J}_{\vec{\ppos}_i}\vec{E}(\vec{\fpos}).

Thus, the electrostatic force acting on particle i is

\vec{F}_i = Q_i\oper{J}_{\vec{\ppos}_i}\vec{E}.

Given that the Gaussian kernel has, in principle, an infinite support evaluating the charge density at every point in space, as well as computing the averages of the electric potential and field at the particles’ locations can be highly inefficient. In practice we overcome this limitation by truncating the Gaussian kernel at a certain distance according to a desired tolerance.

Triply periodic boundary conditions

In this instance we solve the Poisson equation with in a periodic boundary (in the three dimensions). Our approach is similar to the one presented at [1]. However, the authors of [1] make use of the so-called Fast Gaussian Gridding (FGG) to accelerate spreading/interpolation while UAMMD’s its Immersed Boundary framework. The electrostatic modules in UAMMD make use of Ewald splitting framework following closely from the mathematical machinery laid out in [2]. One notable thing about the following algorithm is that it can be seen as merely a reinterpretation of terms in the non-fluctuating version of the Force Coupling Method for hydrodynamics.

We solve the Poisson equation in Fourier space by convolution with the Poisson’s Greens function,

\hat\phi(\vec{k}) = \frac{\hat f(\vec{k})}{\varepsilon k^2}.

We can reuse the methodological machinery devised for the Force Coupling Method.

The electric field can be derived from the potential in fourier space via ik differentiation,

\hat{\vec{E}} = i\vec{k}\hat{\phi}.

This equation can be discretized using a 3D FFT in a grid with spacing fine enough to resolve the Gaussian charges.

The whole algorithm, going from particle charges to forces, can be summarized as follows
  • Spread charges to the grid, f=\oper{S}\vec{Q}.

  • Fourier transform \hat{f} = \mathfrak{F}f.

  • Multiply by the Poisson’s Greens function to obtain the potential, \fou{\phi} = \frac{\hat{f}}{\varepsilon k^2}.

  • Compute field via ik differentiation, \fou{\vec{E}} = i\vec{k}\fou\phi.

  • Transform potential and field back to real space \phi = \mathfrak{F}^{-1}\fou\phi; \vec{E} = \mathfrak{F}^{-1}\fou{\vec{E}}.

  • Interpolate energy and/or force to charge locations, \phi_i = \oper{J}\phi; \vec{E}_i = \oper{J}_{\vec{\ppos}_i}\vec{E}.

The grid size is coupled to the Gaussian charge width, hindering the simulation of systems with narrow charges or large domains. UAMMD’s implementation has an Ewald splitting mode to overcome this limitation.

Without getting into too much detail (see [2]), we can write the potential as

\phi=(\phi - \gamma^{1/2}\star\psi) + \gamma^{1/2}\star\psi = \phi^{\near} + \phi^{\far},

where \star represents convolution and the intermediate solution \psi satisfies

\varepsilon\Delta\psi=-f\star\gamma^{1/2}.

The splitting function \gamma is defined as

\gamma^{1/2} = \frac{8\xi^3}{(2\pi)^{3/2}}\exp\left(-2r^2\xi^2\right).

Here the splitting parameter, \xi, is an arbitrary factor that is chosen to optimize performance. Given that the Laplacian commutes with the convolution we can divide the problem in two separate parts, denoted as near and far field

&\varepsilon\Delta\phi^{\far}=-f\star\gamma,\\
&\varepsilon\Delta\phi^{\near}=-f\star(1-\gamma).

The convolution of two Gaussians is also a Gaussian, so in the case of the far field the RHS results in wider Gaussian sources that can be interpreted as smeared versions of the original ones. The far field RHS thus decays exponentially in Fourier space and is solved as in the non Ewald split case. On the other hand the near field resulting charges are sharply peaked and more compactly supported than the originals, furthermore integrating to zero in 3D. The near field Green’s function is computed analytically in real space and evaluated for each pair of particles inside a given radius (that is controlled by the desired tolerance). The electric field is computed by analytically differentiating and evaluating this Green’s function. For a given tolerance, the splitting parameters controls the load that each part of the algorithm takes. In each case there will be an optimal split that gives the best performance.

Usage

The triply periodic Poisson solver is available as an Interactor called Poisson.

The following parameters are available:
  • Box box Simulation domain (must be triply periodic).

  • real epsilon Permittivity.

  • real gw Gaussian width of the charges (all charges have the same width).

  • real tolerance Overall tolerance of the algorithm.

  • real split = 0 The splitting parameter, \xi, for the Ewald mode. If it is equal to 0 the non-Ewald split mode is used.

#include<uammd.cuh>
#include<Interactor/SpectralEwaldPoisson.cuh>
using namespace uammd;
//Creates and returns a triply periodic Poisson solver Interactor
auto createTPPoissonInteractor(std::shared_ptr<ParticleData> pd){
  Poisson::Parameters par;
  par.box = Box({128, 128, 128});
  //Permittivity
  par.epsilon = 1.0;
  //Gaussian width of the sources
  par.gw = 1.0;
  //Overall tolerance of the algorithm
  par.tolerance = 1e-4;
  //If a splitting parameter is passed
  // the code will run in Ewald split mode
  //Otherwise, the non Ewald version will be used
  //par.split = 1.0;
  return std::make_shared<Poisson>(pd, par);
}

Here, pd is a ParticleData instance.

Hint

A ParticleGroup can be provided instead of a ParticleData for the module to act only on a subset of particles.

Note

As usual, this Interactor can be added to an Integrator.

Note

The tolerance is the maximum relative error allowed in the potential for two charges. The potential for L->inf is extrapolated and compared with the analytical solution. Also in Ewald split mode the relative error between two different splits is less than the tolerance. See test/Potential/Poisson

Doubly periodic boundary conditions

We want to solve the Poisson equation with the following set of boundary conditions for the potential

&\phi(x,y,z\rightarrow 0^+)=\phi(x,y,z\rightarrow 0^-)\\
&\phi(x,y,z\rightarrow H^-)=\phi(x,y,z\rightarrow H^+).

And for the electric field

&\varepsilon_0 \frac{\partial \phi}{\partial z}(x,y,z\rightarrow 0^+)-\varepsilon_b \frac{\partial \phi}{\partial z}(x,y,z\rightarrow 0^-)=-\sigma_b(x,y)\label{eq:dppoissonbcs3}\\
&\varepsilon_0 \frac{\partial \phi}{\partial z}(x,y,z\rightarrow H^-)-\varepsilon_t \frac{\partial \phi}{\partial z}(x,y,z\rightarrow H^+)=\sigma_t(x,y)

We introduce, via these BCs, the possibility of having arbitrary surface charges at the walls, \sigma_b and \sigma_t for the bottom and top respectively. Additionally, we can set different permittivities inside the slab (\varepsilon_0) above (\varepsilon_t) and below (\varepsilon_b) it.

Finally, we assume that the domain is overall electroneutral,

\sum_{k=1}^N{Q_k} + \int_0^{L_{xy}}{\int_0^{L_{xy}}{(\sigma_b(x,y) + \sigma_t(x,y))dx dy}} = 0.

We impose that the sources do not overlap the boundaries in the z direction, f(z>H \text{ or } z<0) = 0, so that the charge density integrates to one inside the slab. Given that the Gaussian is not compactly supported we truncate it at n_\sigma a \ge 4 a to overcome this, ensuring that the integral is at least 99.9\% of the charge Q.

The approach to solve the set of equations above is wildly different from the triply periodic case, a complete description of the algorithm can be found in [3]. In short, we use a grid-based solver as in the triply periodic case and make use of Ewald splitting, the main difference now is that we work in a Fourier-Chebyshev space instead of just Fourier.

Usage

The creation of the Doubly Periodic Poisson Interactor is similar to that of the triply periodic case. With the exception that now the box size is communicated separately in the parallel and perpendicular directions and the permittivity can be different inside and outside the domain. Besides the parameters in the source code example below, additional ones are available to fine-tune several internal precision parameters (such as support, upsampling or overall tolerance). By default, the module will provide an overall tolerance of around 4 digits, which is the study case in the original work describing the doubly periodic algorithm [3]. Additionally, a special functor can be provided specifying the surface charges. In all instances, the surface charge will enforce overall electroneutrality inside the domain. For instance, if a single positive charge of strength Q is located inside the domain, each wall will be assigned a constant charge of -Q/2.

The following parameters are available:
  • real Lxy Simulation domain size in the plane.

  • real H Domain height (z\in [-H/2, H/2]).

  • DPPoissonSlab::Permitivity perm Permittivity in the three domains, contains a top, bottom and inside members.

  • real gw Gaussian width of the charges (all charges have the same width).

  • real split = 0 The splitting parameter, \xi, for the Ewald mode. If it is equal to 0 the non-Ewald split mode is used.

  • std::shared_ptr<SurfaceChargeDispatch> surfaceCharge An object providing the surface charge, see below.

Additionally, some optional/advanced parameters are available:
  • int Nxy Instead of the splitting parameter the number of cells for the far field can be specified.

  • int support Number of support cells for the Gaussian kernel.

  • real numberStandardDeviations n_\sigma above, number of standard deviations to truncate the Gaussian kernel at.

  • real tolerance Controls the cut off distance of the near field Green’s function.

#include<Interactor/DoublyPeriodic/DPPoissonSlab.cuh>
using namespace uammd;

auto createDPPoissonInteractor(std::shared_ptr<ParticleData> pd){
  DPPoissonSlab::Parameters par;
  par.Lxy = 128;
  par.H = 10; //Domain height
  DPPoissonSlab::Permitivity perm;
  perm.inside = 1.0;
  perm.top = 1.0;
  perm.bottom = 1.0;
  par.permitivity = perm;
  par.gw = 1.0; //Width of the Gaussian sources
  par.split = gw*0.1; //Splitting parameter
  auto poisson = make_shared<DPPoissonSlab>(pd, par);
  return poisson;
}

Hint

The doubly periodic electrostatic Interactor does not accept an overall tolerance parameter. The accuracy is defaulted to provide a relative error around 1e-3. Advanced users can refer to [3] to tune the advanced parameters to achieve more accuracy.

Here, pd is a ParticleData instance.

Hint

A ParticleGroup can be provided instead of a ParticleData for the module to act only on a subset of particles.

Note

As usual, this Interactor can be added to an Integrator.

Note

A set of examples showcasing this implementation can be found at https://github.com/stochasticHydroTools/DPPoissonTests , which can be used to reproduce the results in [3].

Providing the surface charges

The surface charge parameter in the DPPoisson module must inherit from the type DPPoissonSlab_ns::SurfaceChargeDispatch.

class DPPoissonSlab_ns::SurfaceChargeDispatch
virtual real top(real x, real y);

Must return the surface charge at position x,y on the top wall, \sigma_t.

virtual real bottom(real x, real y);

Must return the surface charge at position x,y on the bottom wall, \sigma_b.

Example

A constant surface charge dispatcher.

#include<Interactor/DoublyPeriodic/DPPoissonSlab.cuh>
using namespace uammd;

struct ConstantSurfaceCharge: public DPPoissonSlab_ns::SurfaceChargeDispatch{
  real top(real x, real y) override{ return 1.0;}
  real bottom(real x, real y) override{ return -1.0;}
};

References: