FreeBird.jl Examples

Here we provide a few examples of how to use FreeBird.jl. We focus on how to set up a sampling run with various sampling schemes. You may need to fine-tune the parameters for your specific system.

Atomistic system

Before we start, we need to load the FreeBird.jl package.

using FreeBird

Nested Sampling

First, let's generate some initial configurations

configs = generate_initial_configs(120, 562.5, 6)
120-element Vector{AtomsBase.FastSystem{3, AtomsBase.PeriodicCell{3, Quantity{Float64, 𝐋, Unitful.FreeUnits{(Å,), 𝐋, nothing}}}, Quantity{Float64, 𝐋, Unitful.FreeUnits{(Å,), 𝐋, nothing}}, Quantity{Float64, 𝐌, Unitful.FreeUnits{(u,), 𝐌, nothing}}, AtomsBase.ChemicalSpecies}}:
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 ⋮
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)
 FastSystem(H₆, periodicity = FFF)

Walkers are the objects that will be used in the simulation. They contain the information about the system's configuration. Let's warp the configurations into walkers.

walkers = AtomWalker.(generate_initial_configs(120, 562.5, 6))
120-element Vector{AtomWalker{1}}:
 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 ⋮
 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

 AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 0.0 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

Let's define the Lennard-Jones potential

lj = LJParameters(epsilon=0.1, sigma=2.5, cutoff=4.0)
LJParameters(0.1 eV, 2.5 Å, 4.0, -9.763240814208984e-5 eV)

We then create a LJAtomWalkers object that contains the walkers and the Lennard-Jones potential.

ls = LJAtomWalkers(walkers, lj)
LJAtomWalkers(AtomWalker{1}, LJParameters):
[1] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.0015339766979130627 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[2] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.0016481775042263705 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[3] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.024301827159956508 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[4] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.009938056461089194 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[5] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : 48.73075565354147 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

⋮
Omitted 110 walkers
⋮

[116] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.027598009546941183 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[117] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.07271558533627824 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[118] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.0018948696520326327 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[119] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.021190443923094944 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

[120] AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.007607628105757294 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

LJParameters(0.1 eV, 2.5 Å, 4.0, -9.763240814208984e-5 eV)

We then set up a NestedSamplingParameters object with the desired parameters. See the documentation for more information.

ns_params = NestedSamplingParameters(mc_steps=200, step_size=0.1, random_seed=1234*rand(Int))
NestedSamplingParameters(200, 0.01, 0.1, 1.0e-6, 1.0, (0.25, 0.75), 0, 100, -6421660414326538368)

We then set up how we want to perform the Monte Carlo moves. MCRandomWalkClone is a routine that clones an existing walker and performs random walks.

mc = MCRandomWalkClone()
MCRandomWalkClone([1, 2, 3])

We also set up a SaveEveryN object for saving the output.

save = SaveEveryN(n_traj=10, n_snap=20_000, df_filename="output_df_lj6.csv", n_info=10)
SaveEveryN("output_df_lj6.csv", "output.traj.extxyz", "output.ls.extxyz", 10, 20000, 10)

Finally, we run the nested sampling simulation.

energies, liveset, _ = nested_sampling(ls, ns_params, 1_000, mc, save)

Metropolis Monte Carlo

Similarly to nested sampling, we need to define some MC parameters. We will use the same Lennard-Jones potential and initial configurations.

Let's use a walker from the previous example as the initial configuration.

at = ls.walkers[1]
AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.0015339766979130627 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

Define the temperature grid, the number of equilibration steps, the number of sampling steps, and the step size.

temperatures = collect(1000.0:-50:0)
num_equilibration_steps = 100_000
num_sampling_steps = 100_000
step_size = 1.0
1.0

Pass the parameters to the MetropolisMCParameters object.

mc_params = MetropolisMCParameters(
    temperatures,
    equilibrium_steps=num_equilibration_steps,
    sampling_steps=num_sampling_steps,
    step_size=step_size,
    step_size_up=1.0,
    accept_range=(0.5,0.5)
)
MetropolisMCParameters([1000.0, 950.0, 900.0, 850.0, 800.0, 750.0, 700.0, 650.0, 600.0, 550.0  …  450.0, 400.0, 350.0, 300.0, 250.0, 200.0, 150.0, 100.0, 50.0, 0.0], 100000, 100000, 1.0, 0.001, 1.0, (0.5, 0.5), 1234)

Run the Monte Carlo simulation.

mc_energies, mc_ls, mc_cvs, acceptance_rates = monte_carlo_sampling(at, lj, mc_params)

Wang-Landau Sampling

It's also very easy to set up a Wang-Landau simulation. We will use the same Lennard-Jones potential and initial configuration.

at = ls.walkers[1]
AtomWalker{1}(
    configuration      : FastSystem(H₆, periodicity = FFF)
    energy             : -0.0015339766979130627 eV
    iter               : 0
    list_num_par       : [6]
    frozen             : Bool[0]
    energy_frozen_part : 0.0 eV)

Define the step size and the energy range.

step_size = 1.0
energy_min = -1.26
energy_max = 0.0
num_energy_bins = 1000
1000

Pass the parameters to the WangLandauParameters object.

wl_params = WangLandauParameters(num_steps=10_000,
                            energy_min=energy_min,
                            energy_max=energy_max,
                            num_energy_bins=num_energy_bins,
                            step_size=step_size,
                            max_iter=10000,
                            f_min=1.00001)
WangLandauParameters(10000, 0.8, 2.718281828459045, 1.00001, [-1.26, -1.2587387387387388, -1.2574774774774775, -1.2562162162162163, -1.254954954954955, -1.2536936936936938, -1.2524324324324325, -1.2511711711711713, -1.2499099099099098, -1.2486486486486486  …  -0.011351351351351352, -0.01009009009009009, -0.008828828828828829, -0.0075675675675675675, -0.006306306306306306, -0.005045045045045045, -0.0037837837837837837, -0.0025225225225225223, -0.0012612612612612612, 0.0], 10000, 1.0, 1234)

Viola! We can now run the Wang-Landau simulation.

energies_wl, configs, wl_params, S, H = wang_landau(at, lj, wl_params)

Lattice system

We can also perform simulations on lattice systems.

Let's set up a 2D square lattice with a supercell of dimensions 4x4x1. Make the first four sites occupied.

initial_lattice = SLattice{SquareLattice}(components=[[1,2,3,4]])
SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

Define the Hamiltonian with the adsorption energy and the nearest-neighbor and next-nearest-neighbor energies.

adsorption_energy = -0.04
nn_energy = -0.01
nnn_energy = -0.0025
h = GenericLatticeHamiltonian(adsorption_energy, [nn_energy, nnn_energy], u"eV")
GenericLatticeHamiltonian{2,Quantity{Float64, 𝐋^2 𝐌 𝐓^-2, Unitful.FreeUnits{(eV,), 𝐋^2 𝐌 𝐓^-2, nothing}}}:
    on_site_interaction:      -0.04 eV
    nth_neighbor_interactions: [-0.01, -0.0025] eV

Wang-Landau Sampling

This time, let's do a Wang-Landau simulation first, as it's the most straightforward to set up.

energy_min = 20.5 * nn_energy + nn_energy / 8
energy_max = 16 * nn_energy - nn_energy / 8
num_energy_bins = 100
100

Pass the parameters to the WangLandauParameters object.

wl_params = WangLandauParameters(
    energy_min=energy_min,
    energy_max=energy_max,
    random_seed=Int(round(time() * 1000)),)
WangLandauParameters(100, 0.8, 2.718281828459045, 1.00000001, [-0.20625000000000002, -0.20577020202020205, -0.20529040404040405, -0.20481060606060608, -0.20433080808080809, -0.20385101010101012, -0.20337121212121215, -0.20289141414141415, -0.20241161616161618, -0.20193181818181818  …  -0.16306818181818183, -0.16258838383838384, -0.16210858585858587, -0.16162878787878787, -0.1611489898989899, -0.16066919191919193, -0.16018939393939394, -0.15970959595959597, -0.15922979797979797, -0.15875], 1000, 0.01, 1743087928903)

Run the Wang-Landau simulation.

energies_wl, configs, wl_params, S, H = wang_landau(initial_lattice, h, wl_params)

Metroplis Monte Carlo

Let's make a Metropolis Monte Carlo simulation on the same lattice system.

mc_lattice = deepcopy(initial_lattice)
SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

Define the temperature grid, the number of equilibration steps, and the number of sampling steps.

temperatures = collect(200.0:-10:10)  # 200:-1:1
num_equilibration_steps = 25_000
num_sampling_steps = 25_000
25000

Pass the parameters to the MetropolisMCParameters object.

mc_params = MetropolisMCParameters(
    temperatures,
    equilibrium_steps=num_equilibration_steps,
    sampling_steps=num_sampling_steps,
    random_seed=Int(round(time()))
)
MetropolisMCParameters([200.0, 190.0, 180.0, 170.0, 160.0, 150.0, 140.0, 130.0, 120.0, 110.0, 100.0, 90.0, 80.0, 70.0, 60.0, 50.0, 40.0, 30.0, 20.0, 10.0], 25000, 25000, 0.01, 0.001, 1.0, (0.25, 0.75), 1743087929)

Run the Monte Carlo simulation.

mc_energies, mc_configs, mc_cvs, acceptance_rates = monte_carlo_sampling(mc_lattice, h, mc_params)

Nested Sampling

Finally, let's set up a nested sampling simulation. It's a bit more complicated than the previous two, and nested sampling is not the optimal method for lattice systems with many degenerate states.

Let's use the Distributions.jl package to generate the random initial configurations.

using Distributions

Make 1000 copies of the initial lattice.

walkers = [deepcopy(initial_lattice) for i in 1:1000]
1000-element Vector{SLattice{SquareLattice}}:
 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 ⋮
 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

 SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

Now using the sample function from the Distributions.jl package, we can randomly select 4 sites to be occupied.

for walker in walkers
    walker.components[1] = [false for i in 1:length(walker.components[1])]
    for i in sample(1:length(walker.components[1]), 4, replace=false)
        walker.components[1][i] = true
    end
end

Warp the walkers into LatticeWalker objects.

walkers = [LatticeWalker(walker) for walker in walkers]
1000-element Vector{LatticeWalker{1}}:
 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ● ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ● 
      ○ ● ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ○ ○ 
      ○ ○ ● ○ 
      ○ ● ○ ○ 
      ○ ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ○ ○ 
      ○ ○ ● ○ 
      ○ ○ ● ○ 
      ● ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ○ ○ 
      ● ● ○ ○ 
      ○ ● ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ○ ○ 
      ○ ○ ○ ○ 
      ○ ● ○ ○ 
      ● ○ ● ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ○ ○ 
      ● ○ ○ ○ 
      ○ ● ○ ● 
      ○ ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ○ ○ 
      ○ ○ ● ● 
      ○ ● ○ ○ 
      ● ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ● ○ 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ● ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ○ ○ 
      ○ ● ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ● ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ● 
      ○ ○ ● ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 ⋮
 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ○ ○ 
      ○ ○ ● ○ 
      ○ ○ ○ ● 
      ● ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ● ○ ○ 
      ● ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ○ ○ 
      ○ ○ ○ ○ 
      ● ○ ○ ○ 
      ○ ○ ● ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ○ ○ 
      ● ○ ○ ○ 
      ○ ○ ○ ○ 
      ○ ● ● ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ● ○ ● 
      ○ ○ ○ ○ 
      ○ ○ ○ ○ 
      ● ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ○ ○ ● 
      ● ○ ○ ○ 
      ● ○ ● ○ 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ○ ● ○ ○ 
      ○ ○ ○ ● 
      ○ ○ ● ● 
      ○ ○ ○ ○ 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ○ ○ 
      ● ○ ○ ○ 
      ○ ○ ● ○ 
      ○ ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

 LatticeWalker(
    configuration: SLattice{SquareLattice}
    lattice_vectors      : [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    positions            : 16 grid points
    supercell_dimensions : (4, 4, 1)
    basis                : [(0.0, 0.0, 0.0)]
    periodicity          : (true, true, false)
    cutoff radii         : 2 nearest neighbors cutoffs [1.1, 1.5]
    occupations          : 
      ● ○ ○ ○ 
      ● ○ ○ ○ 
      ● ○ ○ ○ 
      ○ ○ ○ ● 
    adsorptions          : full adsorption

    energy: 0.0 eV
    iter: 0)

Again, we use the same Hamiltonian as before. We then create a LatticeGasWalkers object that contains the walkers and the Hamiltonian.

ls = LatticeGasWalkers(walkers, h)
LatticeGasWalkers(LatticeWalker{1}, GenericLatticeHamiltonian{2, Quantity{Float64, 𝐋^2 𝐌 𝐓^-2, Unitful.FreeUnits{(eV,), 𝐋^2 𝐌 𝐓^-2, nothing}}}):
    lattice_vectors:      [1.0 0.0 0.0; 0.0 1.0 0.0; 0.0 0.0 1.0]
    supercell_dimensions: (4, 4, 1)
    periodicity:          (true, true, false)
    basis:                [(0.0, 0.0, 0.0)]
[1] energy = -0.165 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0]
[2] energy = -0.165 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1]
[3] energy = -0.1825 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1]
[4] energy = -0.195 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[5] energy = -0.17 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0]
⋮
Omitted 990 walkers
⋮

[996] energy = -0.195 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[997] energy = -0.17250000000000001 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0]
[998] energy = -0.1825 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0]
[999] energy = -0.175 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
[1000] energy = -0.185 eV, iter = 0
    occupations:
      components:
        component 1:
          Bool[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]

GenericLatticeHamiltonian{2,Quantity{Float64, 𝐋^2 𝐌 𝐓^-2, Unitful.FreeUnits{(eV,), 𝐋^2 𝐌 𝐓^-2, nothing}}}:
    on_site_interaction:      -0.04 eV
    nth_neighbor_interactions: [-0.01, -0.0025] eV

The rejection routine for nested sampling is the best choice for lattice systems.

mc = MCRejectionSampling()
MCRejectionSampling()

We then set up a LatticeNestedSamplingParameters object with the desired parameters. We will use the same parameters as before, but we will set the number of Monte Carlo steps to 100. We will also set the allowed fail count to 1000000, which is a bit high to make sure we explore the configuration space. We will also set the random seed to a random number.

ns_params = LatticeNestedSamplingParameters(mc_steps=100,allowed_fail_count=1_000_000,random_seed=Int(floor(1234*rand())))
LatticeNestedSamplingParameters(100, 1.0e-12, 0, 1000000, 387)

Redefine the output file name.

save = SaveEveryN(df_filename="output_ns_lattice2d.csv")
SaveEveryN("output_ns_lattice2d.csv", "output.traj.extxyz", "output.ls.extxyz", 100, 1000, 1)

And finally, we can run the nested sampling simulation

ns_energies, ls, _ = nested_sampling(ls, ns_params, 10_000, mc, save) # src

This page was generated using Literate.jl.