NQCModels.jl

To perform nonadiabatic molecular dynamics simulations, it is necessary to define the system Hamiltonian. For simple models, this often comes in the form of small matrix in the diabatic representation but equally the electronic Hamiltonian could be obtained directly from ab initio electronic structure theory.

NQCModels.jl is a package that aims to provide a common interface for defining these models that is flexible enough to allow for a wide range of specifications and requirements. NQCDynamics.jl uses this interface to obtain the potentials and couplings necessary to perform the dynamics simulations. Along with the minimal interface, NQCModels.jl also provides a small set of popular models often used in the field of nonadiabatic dynamics.

Note

Taking advantages of Julia's seamless modularity, NQCModels.jl is designed as a separate package so that it can also be used independently from the main package.

Depending on the quantities provided by the Model, we use Julia's abstract type system to group models that provide the same quantities. Currently, there are two top-level abstract types: AdiabaticModel and DiabaticModel. The AdiabaticModel is used for adiabatic dynamics, providing only the potential and force used in classical mechanics. The DiabaticModel is used for nonadiabatic dynamics, where the potential is instead a Hermitian matrix.

In the Getting started section we briefly touched on how the AdiabaticModel works and introduced one of the included models. Here let's take a look at a DiabaticModel, which is more appropriate for nonadiabatic dynamics.

The DoubleWell is a two state, 1 dimensional model where each state is harmonic with linear coupling to the single degree of freedom.

using NQCModels

model = DoubleWell()
DoubleWell{Int64, Int64, Int64, Int64}
  mass: Int64 1
  ω: Int64 1
  γ: Int64 1
  Δ: Int64 1

Our DoubleWell implements the functions potential, derivative, nstates and ndofs that return the potential, the derivative of the potential, the number of states, and the number of degrees of freedom, respectively.

julia> potential(model, 0.2)2×2 LinearAlgebra.Hermitian{Float64, StaticArraysCore.SMatrix{2, 2, Float64, 4}} with indices SOneTo(2)×SOneTo(2):
 0.302843   0.5
 0.5       -0.262843
julia> derivative(model, 0.2)2×2 LinearAlgebra.Hermitian{Float64, StaticArraysCore.SMatrix{2, 2, Float64, 4}} with indices SOneTo(2)×SOneTo(2): 1.61421 0.0 0.0 -1.21421
julia> nstates(model)2
julia> ndofs(model)1

Since this is a 1D model, the position argument that appears in the derivative and the potential is a real number. For higher dimensional models with multiple atoms, the position will need to be provided as an AbstractMatrix.

To understand how this can extend to another dimension, we can take a quick look at the GatesHollowayElbow model which is another two state diabatic model, but this one uses two dimensions to model a diatomic molecule interacting with a surface. The two coordinates are the molecular bond length and the distance from the surface. Technically, the model has been defined such that there are two atoms, each with only a single degree of freedom. This allows us to use different masses for each of the coordinates when performing dynamics.

julia> model = GatesHollowayElbow()GatesHollowayElbow
  λ₁: Float64 3.5
  λ₂: Float64 3.5
  z₀: Float64 1.4
  x₀: Float64 0.6
  α: Float64 1.028
  d: Float64 0.17161933455967182
  z12: Float64 0.5
  c: Float64 0.018374661087759297
  γ: Float64 1.0
julia> potential(model, [1.0 1.0])2×2 LinearAlgebra.Hermitian{Float64, StaticArraysCore.SMatrix{2, 2, Float64, 4}} with indices SOneTo(2)×SOneTo(2): 0.0710215 0.0111448 0.0111448 0.0744945
julia> derivative(model, [1.0 1.0])1×2 Matrix{LinearAlgebra.Hermitian{Float64, StaticArraysCore.SMatrix{2, 2, Float64, 4}}}: [0.0810696 0.0; 0.0 -0.0129425] … [-0.000787036 -0.0111448; -0.0111448 0.0810696]
julia> nstates(model)2
julia> ndofs(model)1

Here we see how the derivative now becomes a Matrix with size matching our input, but each entry is a Hermitian containing the elementwise derivative of the potential with respect to each degree of freedom. In this case, the Matrix has size = (1, 2), but it should be clear how this can extend to arbitrary numbers of atoms and degrees of freedom for complex models.

The models currently available can be seen in type tree of the Model below. The leaves of the tree are the concrete models, whereas each branch is one of the abstract types. Each of these models can be seen in the Analytic model library and many shall return later when we investigate the dynamics methods.

Model
├─ AdiabaticModel
│  ├─ AdiabaticASEModel
│  ├─ AdiabaticStateSelector
│  ├─ AveragedPotential
│  ├─ BosonBath
│  ├─ DarlingHollowayElbow
│  ├─ DiatomicHarmonic
│  ├─ Free
│  ├─ Harmonic
│  ├─ Morse
│  └─ AdiabaticFrictionModel
│     ├─ CompositeFrictionModel
│     ├─ H2AgModel
│     └─ LDFAModel
└─ DiabaticModel
   ├─ DoubleWell
   ├─ ErpenbeckThoss
   ├─ GatesHollowayElbow
   ├─ MiaoSubotnik
   ├─ AnanthModel
   │  ├─ AnanthModelOne
   │  └─ AnanthModelTwo
   ├─ LargeDiabaticModel
   │  ├─ AndersonHolstein
   │  └─ DiabaticFrictionModel
   │     ├─ OuyangModelOne
   │     ├─ Scattering1D
   │     └─ WideBandBath
   ├─ TullyModel
   │  ├─ TullyModelOne
   │  ├─ TullyModelThree
   │  └─ TullyModelTwo
   ├─ SpinBoson
   └─ ThreeStateMorse
Contributing new models

To learn more about NQCModels.jl and learn how to implement new models, visit the developer documentation.