Create fluid in a slit pore

A fluid confined to a slit pore is set up by placing fluid particles in between two planar surfaces. The latter are implemented as flat walls by an external wall potential. The fluid may consist of particles of different species, and the walls may have different interaction parameters for each species. For simplicity, only a single species is used here.

Note

The simulation box is still defined with periodic boundary conditions at all its faces. Therefore, it is crucial that the box size in the direction perpendicular to the walls is larger than the pore width to avoid spurious pair interactions across the walls.

The setup procedure has the following steps:

  • define geometry: pore width and box extents, fraction of the pore
  • place particles on an fcc lattice in the pore part of the box
  • assign random velocities according to a Maxwell–Boltzmann distribution
  • define interactions: pair potential, external wall potential
local pore_width = args.pore_width
local box_length = args.box_length
local length = {pore_width + 10, box_length, box_length}   -- add extra space "behind" the walls
local slab = {pore_width / length[1], 1, 1}
-- compute particle number from pore volume and mean density
local nparticle = math.floor(args.density * numeric.prod(slab) * numeric.prod(length))

-- create system state
local box = mdsim.box({length = length})
local particle = mdsim.particle({dimension = #length, particles = nparticle})

-- set initial particle positions
mdsim.positions.lattice({box = box, particle = particle, slab = slab}):set()

-- set initial particle velocities
mdsim.velocities.boltzmann({particle = particle, temperature = args.temperature}):set()

-- define Lennard-Jones pair potential (with parameters ε=1 and σ=1 for a single species)
-- and register computation of pair forces
definitions.lennard_jones.create_pair_force({
    box = box, particle = particle, cutoff = args.pair_cutoff, smoothing = args.smoothing
})

-- define Lennard-Jones wall potential to form a slit pore
-- and register computation of this external force
definitions.slit_pore.create_wall_force({
    box = box, particle = particle
  , pore_width = pore_width
  , epsilon = args.wall_epsilon, wetting = args.wetting
  , cutoff = args.wall_cutoff, smoothing = args.smoothing
})

We have made use of the following helper functions, which may be found in separate definitions file (see path examples/definitions):

function M.create_wall_force(args)
    local box = utility.assert_kwarg(args, "box")
    local particle = utility.assert_kwarg(args, "particle")
    local pore_width = utility.assert_kwarg(args, "pore_width")
    local sigma = args.sigma or 1
    local epsilon = args.epsilon or 1
    local wetting = args.wetting or 1
    local cutoff = args.cutoff or 2.5
    local smoothing = args.smoothing or 0.005

    local potential = mdsim.potentials.external.planar_wall({
        -- place two walls perpendicular to the x-axis
        surface_normal = {{-1, 0, 0}, {1, 0, 0}}
        -- add a space of .5σ between the nominal pore space and each of the walls
      , offset = {(pore_width + 1) / 2, (pore_width + 1) / 2}
        -- wall interaction parameters
      , sigma = sigma, epsilon = epsilon, wetting = wetting
      , cutoff = cutoff,  smoothing = smoothing
      , species = (type(sigma) == 'number') and 1 or nil
    })

    -- register computation of wall forces
    local force = mdsim.forces.external({
        box = box, particle = particle, potential = potential
    })

    return force, potential
end
function M.create_pair_force(args)
    local box = utility.assert_kwarg(args, "box")
    local particle = utility.assert_kwarg(args, "particle")
    local cutoff = args.cutoff
    local smoothing = args.smoothing or 0.005

    -- define Lennard-Jones pair potential,
    local potential = mdsim.potentials.pair.lennard_jones()
    -- optionally, apply interaction cutoff
    if cutoff then
        -- use smooth truncation
        if smoothing > 0 then
            potential = potential:truncate({"smooth_r4", cutoff = cutoff, h = smoothing})
        else
            potential = potential:truncate({cutoff = cutoff})
        end
    end

    -- register computation of pair forces
    local force = mdsim.forces.pair({
        box = box, particle = particle, potential = potential
    })

    return force, potential
end