A look under the hood of the NQCD packages
13.06.2024
Classical system Hamiltonian \[ \mathrm{H=\frac{\mathbf{P}^2}{2M}+V(\mathbf{R})} \]
Starting conditions \[ \vec{v}=\begin{bmatrix}0\\\vdots\\0\end{bmatrix}, \vec{r}=\begin{bmatrix}\vdots\end{bmatrix} \]
Integration scheme
Velocity Verlet integration
Consistent structure for creating problems and solving them.
Identical I/O for different propagation methods.
Flexible, extendable.
ODEProblem
Equation of motion (1D Harmonic oscillator)
function hamiltonian_1d(u; omega=omega_1, m=m1)
return (0.5*omega^2*m*u.x[2]^2) + (1/2 * u.x[1]^2 * m)
end
Starting parameters
Resulting ODE problem:
ODEProblem
DifferentialEquations.jl
pipelineMD workflows may require:
NQCBase.jl
Atoms
PeriodicCell
convert_from_ase_atoms
convert_to_ase_atoms
NQCModels.jl
Model
potential(model, R), derivative(model, R)
(and in-place versions)DynamicalDistribution
VelocityBoltzmann
)[:X]
atoms)Simulation
Simulation
s11sim = Simulation{Method}(
2 atoms::Atoms{T},
3 model::Model;
4 temperature=0u"K",
5 cell::AbstractCell=InfiniteCell()
)
Simulation
s contain a Calculator
to cache energies, forces,…simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
run_dynamics
creates the O/SDE problem for DifferentialEquations.jl to solve1simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
DynamicalDistribution
to sample from.simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
DynamicsOutputs
simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
saveat=
is specified
simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
selection=nothing
for random sampling, otherwise indices of distribution to sample from.Reduction
s applied to outputs
MeanReduction
for ensemble MeanFileReduction
simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
Parallelisation strategy
EnsembleSerial
: One trajectory at a time.
EnsembleDistributed
: One trajectory per process. No shared memory.
EnsembleThreads
: One trajectory per thread. Shared memory.
EnsembleSplitThreads
: One trajectory per thread per process.
simulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
Callbacks1:
EnsembleAlgorithm
ssimulation_output = run_dynamics(
sim,
(0,1000),
initial_conditions;
output = (OutputPosition, OutputVelocity),
dt = 0.1,
trajectories = 100,
selection = 1:100,
reduction = MeanReduction(),
ensemble_algorithm = SciMLBase.EnsembleDistributed(),
callback = CellBoundaryCallback(),
)
EnsembleSerial
: One trajectory at a time.
EnsembleDistributed
: One trajectory per process. No shared memory.
EnsembleThreads
: One trajectory per thread. Shared memory.
EnsembleSplitThreads
: One trajectory per thread per process.
ClusterScripts.jl
1fixed_parameters=Dict(
"task" => "mdef+2tm",
"trajectories" => 10000,
"runtime" => 4.7u"ps",
"timestep" => 0.1u"fs",
"ensemble_algorithm" => EnsembleSerial(),
"outputs" => (OutputInitial, OutputFinal),
"friction_atoms" => friction_atoms,
)
variables=Dict(
"starting_temperature" => [100, 150, 200, 250, 300],
"fluence" => [10,20,40,60,80,100,120],
)
job_queue=build_job_queue(fixed_parameters, variables, postprocess_queue)
serialise_queue!(job_queue; filename="simulation_parameters.jld2")
DynamicsOutputs
src/DynamicsOutputs.jl
OutputKineticEnergy(sol, i) = DynamicsUtils.classical_kinetic_energy.(sol.prob.p, sol.u)
export OutputKineticEnergy
struct OutputQuantisedDiatomic{S,H,V}
sim::S
height::H
normal_vector::V
end
export OutputQuantisedDiatomic
function (output::OutputQuantisedDiatomic)(sol, i)
final = last(sol.u)
ν, J = QuantisedDiatomic.quantise_diatomic(output.sim,
DynamicsUtils.get_velocities(final), DynamicsUtils.get_positions(final);
height=output.height, normal_vector=output.normal_vector)
return (ν, J)
end
src/structure.jl
src/Analysis/Analysis.jl
diatomic.jl
.A model in NQCModels.jl needs to implement:
ndofs(m::Model)
potential(m::Model, R::AbstractArray)
derivative(m::Model, R::AbstractArray)
Adiabatic models: - Single electronic state
Diabatic models: \[ \mathbf{V(R)}=\begin{bmatrix}V_1 & \Lambda_{12}\\\Lambda_{21} & V_2\end{bmatrix} \]
Link to this presentation
Running nonadiabatic MD in Julia