Loading in Forcefield Files#
Lennard-Jones forcefield parameters are stored in comma-separated-value format in PorousMaterials.PATH_TO_FORCEFIELDS
.
Interaction of an adsorbate with the framework is modeled as pair-wise additive and with Lennard-Jones potentials of the form:
V(r) = 4 * epsilon * [ x ^ 12 - x ^ 6 ]
, where x = sigma / r
The Lennard Jones force field input files, e.g. UFF.csv
contain a list of pure (i.e. X-X, where X is an atom) sigmas and epsilons in units Angstrom and Kelvin, respectively. Note that, e.g., in the UFF paper, the Lennard Jones potential is written in a different form and thus parameters need to be converted to correspond to the functional form used in PorousMaterials.jl
.
using PorousMaterials
ljff = LJForceField("UFF.csv")
PorousMaterials will the output information about the forcefield file you just loaded:
Force field: UFF.csv
Number of atoms included: 106
Cut-off radius (Å) = 14.0
This also prints all of the atoms included in the loaded forcefield with their given ϵ and σ. This was excluded because it would use too much space on this page.
Building Blocks of PorousMaterials: Lennard-Jones forcefields#
# read in Lennard-Jones force field parameters from the Universal Force Field
forcefield = LJForceField("UFF.csv", cutoffradius=14.0, mixing_rules="Lorentz-Berthelot")
# access the Lennard-Jones epsilon & sigma for Xe
forcefield.pure_ϵ[:Xe] # K
forcefield.pure_σ[:Xe] # Å
# access the Lennard-Jones epsilon & sigma for Xe-C interactions
forcefield.ϵ[:Xe][:C] # K
forcefield.σ²[:Xe][:C] # Å (store σ² for faster computation)
Building Blocks of PorousMaterials: Potential energies#
First, set the fractional coordinates of the molecule in the context of some unit cell box.
# molecule in a framework
set_fractional_coords!(molecule, framework.box)
# molecule in a 10 by 10 by 10 cube
box = Box(10.0, 10.0, 10.0, π/2, π/2, π/2) # make a box
set_fractional_coords!(molecule, box)
Potential Energies: Van der Waals#
What is the van der Waals potential energy of a Xe adsorbate inside SBMOF-1 at [0.0, 1.0, 3.0]
Cartesian coordinates using the UFF as a molecular model?
using PorousMaterials
framework = Framework("SBMOF-1.cif")
forcefield = LJForceField("UFF.csv")
molecule = Molecule("Xe")
set_fractional_coords!(molecule, framework.box)
translate_to!(molecule, [0.0, 1.0, 0.0], framework.box) # need box b/c we're talking Cartesian
energy = vdw_energy(framework, molecule, forcefield) # K
Potential Energies: Electrostatics#
What is the electrostatic potential energy of a CO2 adsorbate inside CAXVII_clean at [0.0, 1.0, 0.0]
Cartesian coordinate?
using PorousMaterials
framework = Framework("CAXVII_clean.cif") # has charges
molecule = Molecule("CO2")
set_fractional_coords!(molecule, framework.box)
translate_to!(molecule, [0.0, 1.0, 0.0], framework.box) # need box b/c we're talking Cartesian
rotate!(molecule, framework.box) # let's give it a random orientation
# this is for speed. pre-compute k-vectors and allocate memory
eparams, kvectors, eikar, eikbr, eikcr = setup_Ewald_sum(12.0, framework.box)
energy = electrostatic_potential_energy(framework, molecule, eparams, kvectors, eikar, eikbr, eikcr)
Potential Energies: Equations of state#
Calculate fugacity of methane at 298 K and 65 bar using the Peng-Robinson EOS:
fluid = PengRobinsonFluid(:CH4)
props = calculate_properties(fluid, 298.0, 65.0) # dictionary of PREOS properties
props["fugacity coefficient"] # 0.8729
Calculate compressibility factor of hydrogen at 300 K and 50 bar using van der Waals EOS:
fluid = VdWFluid(:H2)
props = calculate_properties(fluid, 300.0, 50.0) # dictionary of VdW properties
props["compressibility factor"] # 1.03511
Pass eos=:PengRobinson
to gcmc_simulation
to automatically convert pressure to fugacity using the Peng-Robinson equation of state.
Forcefields#
#
PorousMaterials.LJForceField
— Type.
Data structure for a Lennard Jones forcefield.
Attributes
name::String
: name of forcefield; correponds to filenamepure_σ::Dict{Symbol, Float64}
: Dictionary that returns Lennard-Jones σ of an X-X interaction, where X is an atom. (units: Angstrom)pure_ϵ::Dict{Symbol, Float64}
: Dictionary that returns Lennard-Jones ϵ of an X-X interaction, where X is an atom. (units: K)σ²::Dict{Symbol, Dict{Symbol, Float64}}
: Lennard Jones σ² (units: Angstrom²) for cross-interactions. Example use issigmas_squared[:He][:C]
ϵ::Dict{Symbol, Dict{Symbol, Float64}}
: Lennard Jones ϵ (units: K) for cross-interactions. Example use isepsilons[:He][:C]
cutoffradius_squared::Float64
: The square of the cut-off radius beyond which we define the potential energy to be zero (units: Angstrom²). We store σ² to speed up computations, which involve σ², not σ.
#
PorousMaterials.replication_factors
— Function.
repfactors = replication_factors(unitcell, cutoffradius)
Find the replication factors needed to make a supercell big enough to fit a sphere with the specified cutoff radius. In PorousMaterials.jl, rather than replicating the atoms in the home unit cell to build the supercell that serves as a simulation box, we replicate the home unit cell to form the supercell (simulation box) in a for loop. This function ensures enough replication factors such that the nearest image convention can be applied.
A non-replicated supercell has 1 as the replication factor in each dimension (repfactors = (1, 1, 1)
).
Arguments
unitcell::Box
: The unit cell of the frameworkcutoff_radius::Float64
: Cutoff radius beyond which we define the potential energy to be zero (units: Angstrom)
Returns
repfactors::Tuple{Int, Int, Int}
: The replication factors in the a, b, c directions
#
PorousMaterials.check_forcefield_coverage
— Function.
check_forcefield_coverage(framework, ljforcefield)
check_forcefield_coverage(molecule, ljforcefield)
Check that the force field contains parameters for every atom present in a framework or molecule. Will print out which atoms are missing.
Arguments
framework::Framework
: The framework containing the crystal structure informationmolecule::Molecule
: A molecule objectljforcefield::LJForceField
: A Lennard Jones forcefield object containing information on atom interactions
Returns
all_covered::Bool
: Returns true if all atoms in theframework
are also included inljforcefield
. False otherwise
Potential Energy#
#
PorousMaterials.PotentialEnergy
— Type.
pe = PotentialEnergy()
Data structure to store potential energy, partitioned into van der Waals (energy.vdw
) and electrostatic (energy.coulomb
) interactions, both Float64
.
This returns a PotentialEnergy data type where the vdw and coulomb attributes are set to 0.0
Returns
pe::PotentialEnergy
: A structure containing van der Waals and electrostatic energies, initialized at 0.0
Attributes
vdw::Float64
: The potential energy contributions from Van der Waals interactionscoulomb::Float64
: The potential energy contributions from electrostatic interactions
#
PorousMaterials.SystemPotentialEnergy
— Type.
system_potential_energy = SystemPotentialEnergy()
Data structure to facilitate storing/partitioning potential energy of a system. It stores the potential energy from guest-host and guest-guest interactions separately.
This initializes guesthost and guestguest with PotentialEnergy(), so when it is created the total energy recorded is 0.0
Returns
system_potential_energy::SystemPotentialEnergy
: A structure containing the potential energy of the system, broken down into guest-guest and guest-host interactions
Attributes
guest_host::PotentialEnergy
: The total potential energy from all guest-host interactions in the systemguest_guest::PotentialEnergy
: The total potential energy from all guest-guest interactions in the system
Nearest Image Conventions#
#
PorousMaterials.nearest_image!
— Function.
nearest_image!(dxf)
Applies the nearest image convention on a vector dxf
between two atoms in fractional space; modifies dxf
for nearest image convention. Fractional coordinates here fall in [0, 1] so that the box is [0, 1]^3 in fractional space.
Warning: this assumes the two molecules are in the box described by fractional coords [0, 1]³.
Arguments
dxf::Array{Float64}
: A vector between two atoms in fractional space
Electrostatics Energy#
#
PorousMaterials.Eikr
— Type.
eikr = Eikr(eikar, eikbr, eikcr)
mutable struct for holding the eikr vectors
Attributes
eikar::OffsetArray{Complex{Float64}}
: array for storing e^{i * ka ⋅ r}; has indices 0:kreps[1] and corresponds to recip. vectors in a-directioneikbr::OffsetArray{Complex{Float64}}
: array for storing e^{i * kb ⋅ r}; has indices -kreps[2]:kreps[2] and corresponds to recip. vectors in b-directioneikcr::OffsetArray{Complex{Float64}}
: array for storing e^{i * kc ⋅ r}; has indices -kreps[2]:kreps[1] and corresponds to recip. vectors in c-direction
#
PorousMaterials.electrostatic_potential_energy
— Function.
ϕ = electrostatic_potential_energy(framework, molecule, eparams, eikr)
Compute the electrostatic potential energy of a molecule inside a framework.
The electrostatic potential is created by the point charges assigned to the framework atoms in framework.charges
. Periodic boundary conditions are applied through the Ewald summation. The spurious self-interaction term is neglected here because we are looking at differences in energy in a Monte Carlo simulation.
Warning: it is assumed that the framework is replicated enough such that the nearest image convention can be applied for the short-range cutoff radius supplied in eparams.sr_cutoff_r
.
Arguments
framework::Framework
: Crystal structure (seeframework.charges
for charges)molecule::Molecule
: The molecule being compared to the atoms in the framework.eparams::EwaldParams
: data structure containing Ewald summation settingseikr::Eikr
: Stores the eikar, eikbr, and eikcr OffsetArrays used in this calculation.
Returns
pot::EwaldSum
: Electrostatic potential betweenframework
andmolecule
(units: K)
ϕ = electrostatic_potential_energy(molecules, eparams, box, eikr)
Compute the electrostatic potential energy of a system comprised of an array of Molecule
s.
The EWald summation is used here in a double for loop; do not use this function for Monte Carlo simulations because it is computationally expensive.
Returns an EwaldSum
type containing short-range and long-range contributions to the Ewald sum as well as the spurious self-interaction and intramolecular interactions. Access via (ϕ.sr, ϕ.lr, ϕ.self, ϕ.intra).
Units of energy: Kelvin
Arguments
molecules::Array{Molecules, 1}
: array of molecules comprising the system.eparams::EwaldParams
: data structure containing Ewald summation settingsbox::Box
: the box the energy is being computed ineikr::Eikr
: Stores the eikar, eikbr, and eikcr OffsetArrays used in this calculation.
Returns
ϕ::GGEwaldSum
: The total electrostatic potential energy
#
PorousMaterials.precompute_kvec_wts
— Function.
kvectors = precompute_kvec_wts(kreps, box, α, max_mag_k_sqrd=Inf)
For speed, pre-compute the weights for each reciprocal lattice vector for the Ewald sum in Fourier space. This function takes advantage of the symmetry: cos(-k⋅(x-xᵢ)) + cos(k⋅(x-xᵢ)) = 2 cos(k⋅(x-xᵢ))
If max_mag_k_sqrd
is passed, k-vectors with a magnitude greater than max_mag_k_sqrd
are not included.
Arguments
kreps::Tuple{Int, Int, Int}
: number of k-vector replications required in a, b, cbox::Box
: the simulation box containing the reciprocal lattice.α::Float64
: Ewald sum convergence parameter (units: inverse Å)max_mag_k_sqrd::Float64
: cutoff for |k|² in Fourier sum; if passed, do not include
k-vectors with magnitude squared greater than this.
Returns
kvectors::Array{Kvector, 1}
: array of k-vectors to include in the Fourier sum and their
corresponding weights indicating the contribution to the Fourier sum.
#
PorousMaterials.setup_Ewald_sum
— Function.
eparams = setup_Ewald_sum(box, sr_cutoff_r; ϵ=1e-6, verbose=false)
Given the short-range cutoff radius and simulation box, automatically compute Ewald convergence parameter and number of k-vector replications in Fourier space required for a given precision. Constructs and returns Ewald parameters data type with this information.
Also, pre-compute weights on k-vector contributions to Ewald sum in Fourier space.
Also, allocate OffsetArrays for storing e^{i * k ⋅ r} where r = x - xⱼ and k is a reciprocal lattice vector.
Arguments
box::Box
: the simulation box containing the reciprocal lattice.sr_cutoff_r::Float64
: cutoff-radius (units: Å) for short-range contributions to Ewaldϵ::Float64
: desired level of precision. Typical value is 1e-6, but this does notverbose::Bool
: Iftrue
will print results
Returns
eparams::EwaldParams
: data structure containing Ewald summation settings
corresponding weights indicating the contribution to the Fourier sum.
#
PorousMaterials.total_electrostatic_potential_energy
— Function.
total_ϕ = total_electrostatic_potential_energy(molecules, eparams, box, eikr)
Calculates the total electrostatic potential energy of an array of Molecule
s using a Grand Canonical Monte Carlo (GCMC) algorithm. #TODO add to this
Arguments
molecules::Array{Molecule, 1}
: The molecules comprising the system.eparams::EwaldParams
: data structure containing Ewald summation settingsbox::Box
: The box the energy is being computed in.eikr::Eikr
: Stores the eikar, eikbr, and eikcr OffsetArrays used in this calculation.
Returns
ϕ::GGEwaldSum
: The total electrostatic potential energy
total_ϕ = total_electrostatic_potential_energy(framework, molecules, eparams, eikr)
Explanation of totalelectrostaticpotential_energy that uses framework
Arguments
framework::Framework
: Crystal structure (seeframework.charges
for charges)molecules::Array{Molecule, 1}
: The molecules comprising the system.eparams::EwaldParams
: data structure containing Ewald summation settingseikr::Eikr
: Stores the eikar, eikbr, and eikcr OffsetArrays used in this calculation.
Van der Waals Energy#
#
PorousMaterials.lennard_jones
— Function.
energy = lennard_jones(r², σ², ϵ) (units: Kelvin)
Calculate the lennard jones potential energy given the square of the radius r between two lennard-jones spheres. σ and ϵ are specific to interaction between two elements. Return the potential energy in units Kelvin (well, whatever the units of ϵ are).
Arguments
r²::Float64
: distance between two (pseudo)atoms in question squared (Angstrom²)σ²::Float64
: sigma parameter in Lennard Jones potential squared (units: Angstrom²)ϵ::Float64
: epsilon parameter in Lennard Jones potential (units: Kelvin)
Returns
energy::Float64
: Lennard Jones potential energy
#
PorousMaterials.vdw_energy
— Function.
energy = vdw_energy(framework, molecule, ljforcefield)
Calculates the van der Waals interaction energy between a molecule and a framework. Applies the nearest image convention to find the closest replicate of a specific atom.
WARNING: it is assumed that the framework is replicated sufficiently such that the nearest image convention can be applied. See replicate
.
Arguments
framework::Framework
: Crystal structuremolecule::Molecule
: adsorbate (includes position/orientation/atoms)ljforcefield::LJForceField
: Lennard Jones force field
Returns
energy::Float64
: Van der Waals interaction energy
gg_energy = vdw_energy(molecule_id, molecules, ljforcefield, simulation_box)
Calculates van der Waals interaction energy of a single adsorbate molecules[molecule_id]
with all of the other molecules in the system. Periodic boundary conditions are applied, using the nearest image convention.
Arguments
molecule_id::Int
: Molecule ID used to determine which molecule inmolecules
we wish to calculate the guest-guest interactionsmolecules::Array{Molecule, 1}
: An array of Molecule data structuresljforcefield::LJForceField
: A Lennard Jones forcefield data structure describing the interactions between different atomssimulation_box::Box
: The simulation box for the computation.
Returns
gg_energy::Float64
: The guest-guest interaction energy ofmolecules[molecule_id]
with the other molecules inmolecules
#
PorousMaterials.vdw_energy_no_PBC
— Function.
pot_energy = vdw_energy_no_PBC(atoms, molecule, ljff)
Assumes unit cell box is a unit cube and no periodic boundary conditions are applied.