Handling Atoms
This package makes the choice to separate the atomic parameters from their positions and velocities for ease of use with the differential equations solvers. This contrasts somewhat with most other software packages where these would be usually be joined together into a single object.
The atomic parameters here are contained within the Atoms
type introduced earlier in the Getting started section. As mentioned previously, there exist some basic constructors which use either elemental symbols or numbers to initialise the parameters:
julia> using NQCDynamics
julia> Atoms([:H, :H, :H])
Atoms{Float64}([:H, :H, :H], [1, 1, 1], [1837.4715941070515, 1837.4715941070515, 1837.4715941070515])
julia> Atoms([1, 2, 3])
Atoms{Float64}([:X, :X, :X], [0, 0, 0], [1.0, 2.0, 3.0])
If there are many atoms, you can use Julia's array manipulation utilities to create large vectors with many atoms types. For example, if adding an adsorbate to a metal surface, it could be initialised as:
julia> au = fill(:Au, 40)
40-element Vector{Symbol}: :Au :Au :Au :Au :Au :Au :Au :Au :Au :Au ⋮ :Au :Au :Au :Au :Au :Au :Au :Au :Au
julia> no = [:N, :O]
2-element Vector{Symbol}: :N :O
julia> auno = [au; no]
42-element Vector{Symbol}: :Au :Au :Au :Au :Au :Au :Au :Au :Au :Au ⋮ :Au :Au :Au :Au :Au :Au :Au :N :O
julia> Atoms(auno)
Atoms{Float64}([:Au, :Au, :Au, :Au, :Au, :Au, :Au, :Au, :Au, :Au … :Au, :Au, :Au, :Au, :Au, :Au, :Au, :Au, :N, :O], [79, 79, 79, 79, 79, 79, 79, 79, 79, 79 … 79, 79, 79, 79, 79, 79, 79, 79, 7, 8], [359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164 … 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 359048.0926227164, 25533.199026445902, 29164.39289099079])
Manipulating atomic structures with AtomsBase.jl
AtomsBase provides a convenient format for representing atomic geometries, facilitating interoperability between a collection of different packages.
When working with NQCDynamics, the most useful packages are AtomsIO for reading and writing structures and trajectories, and ASEconvert for working with ASE from within Julia.
Using Python's ase
package from Julia
Julia provides multiple options to run Python-based code from Julia scripts. The NQCD packages provide compatibility with PythonCall.jl, and some deprecated interfaces for PyCall.jl exist as well. While both of these packages function similarly, PythonCall forces you as a user to think more about when data is copied in memory between Python and Julia, enabling more efficient code.
This example shows how ase.build
can be used to build a structure from within Julia, then convert from the ASE format into the required objects for atoms, positions and unit cell for an NQCD simulation:
using PythonCall
using NQCBase
ase_build = pyimport("ase.build")
# Make a silicon supercell using ASE
atoms_ase = ase_build.bulk("Si") * pytuple((4, 1, 1))
It is currently not possible to use an AtomsBase system directly with NQCDynamics, but can be quickly converted to the correct format:
using NQCDynamics
atoms_nqcd, positions_nqcd, cell_nqcd = convert_from_ase_atoms(atoms_ase)
println(atoms_nqcd)
println(positions_nqcd)
println(cell_nqcd)
Saving and loading with AtomsIO.jl
After running a simulation it often desirable to save the trajectory in a standard format for visualization. For this, convert the NQCDynamics output into the AtomsBase format, then use AtomsIO to write the file in your chosen format.
using AtomsIO
system = System(atoms_nqcd, r, v, c)
AtomsIO.save_system("Si.xyz", system) # Save a single image
trajectory = Trajectory(atoms_nqcd, [r, r, r, r], [v, v, v, v], c)
AtomsIO.save_trajectory("Si.xyz", trajectory) # Save a trajectory
AtomsIO also provides load_system
and load_trajectory
which can be converted to the NQCDynamics format as above to initialise simulations. Refer to AtomsIO for more information.