Skip to content

Commit ad02d83

Browse files
authored
Merge pull request ACEsuit#274 from ACEsuit/tutorial_08
AtomsBase + ACEpotentials tutorial
2 parents 80e9a54 + 59915c5 commit ad02d83

File tree

5 files changed

+175
-17
lines changed

5 files changed

+175
-17
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ PrettyTables = "1.3, 2.0"
6262
Reexport = "1"
6363
StaticArrays = "1"
6464
YAML = "0.4"
65-
julia = "~1.10.0"
65+
julia = "1.10.0"
6666

6767
[extras]
6868
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,21 @@
1212
- Version 0.7.x is reserved
1313
- Version 0.8.x and onwards provides a new and much more flexible implementation, and integrates with the [AtomsBase](https://github.com/JuliaMolSim/AtomsBase.jl) ecosystem. Most but not all features from 0.6.x have been ported to this re-implementation. Usability should be the same or improved for most end-users. For developers this provides a much more flexible framework for experimentation. [[docs-v0.8]](https://acesuit.github.io/ACEpotentials.jl/dev/)
1414

15+
16+
## Quick Start
17+
18+
- Install Julia 1.10
19+
- Create new folder a.g. `acetutorial`; Open a shell
20+
- Create a new project in `acetutorial` and install `ACEpotentials.jl`
21+
```
22+
julia --project=.
23+
]
24+
registry add https://github.com/ACEsuit/ACEregistry
25+
add ACEpotentials
26+
```
27+
- Install the Julia tutorials (this installs two Jupyter notebook tutorials)
28+
```julia-repl
29+
using ACEpotentials
30+
ACEpotentials.copy_tutorial()
31+
```
32+
- Work through the tutorials.

examples/Tutorial/ACE+AtomsBase.jl

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# # ACEpotentials.jl + AtomsBase.jl Tutorial
2+
3+
# ## Introduction
4+
#
5+
# This tutorial demonstrates how the ACEpotentials.jl package
6+
# interoperates with the AtomsBase.jl ecosystem.
7+
8+
# ## Installation
9+
#
10+
# add and load general packages used in this notebook.
11+
12+
using Pkg
13+
## Uncomment the next line if installing Julia for the first time
14+
## Pkg.Registry.add("General")
15+
## Pkg.Registry.add
16+
Pkg.add(["ExtXYZ", "Unitful", "Distributed", "AtomsCalculators",
17+
"Molly", "AtomsCalculatorsUtilities", "AtomsBuilder",
18+
])
19+
20+
## ACEpotentials installation:
21+
## If ACEpotentials has not been installed yet, uncomment the following lines
22+
## Add the ACE registry, which stores the ACEpotential package information
23+
Pkg.Registry.add(RegistrySpec(url="https://github.com/ACEsuit/ACEregistry"))
24+
Pkg.add(["GeomOpt", ])
25+
## Pkg.add(["ACEpotentials",])
26+
27+
# We can check the status of the installed packages.
28+
29+
using Pkg; Pkg.activate(".")
30+
Pkg.status()
31+
32+
# Import all the packages that we will be using, create some processes
33+
# for parallel model fitting
34+
35+
using ExtXYZ, Unitful, AtomsCalculators, Distributed, ACEpotentials,
36+
AtomsCalculatorsUtilities
37+
using AtomsCalculatorsUtilities.SitePotentials: cutoff_radius
38+
addprocs(10, exeflags="--project=$(Base.active_project())")
39+
@everywhere using ACEpotentials
40+
41+
# ## Fit a potential for Cu
42+
#
43+
# The tutorial can be adapted trivially to use datasets for Ni, Cu, Li, Mo, Si, Ge.
44+
#
45+
# We generate a smallish model (about 300 basis functions) for Cu, using
46+
# correlation-order 3 (body-order 4), and default for rcut. Then we estimate
47+
# the model parameters using the standard BLR solver.
48+
49+
## generate a model for Cu
50+
sym = :Cu
51+
model = ace1_model(elements = [sym,], order = 3, totaldegree = [ 20, 16, 12 ])
52+
@show length_basis(model)
53+
@show cutoff_radius(model)
54+
## estimate parameters
55+
train, test, _ = ACEpotentials.example_dataset("Zuo20_$sym")
56+
solver = ACEfit.BLR(; factorization = :svd)
57+
acefit!(train, model; solver=solver); GC.gc()
58+
## quickly check test errors => 0.5 meV/atom and 0.014 eV/A are ok
59+
ACEpotentials.compute_errors(test, model);
60+
61+
# ## Geometry Optimization with GeomOpt
62+
#
63+
# ( Note: we should use GeometryOptimization.jl, but this is not yet updated to
64+
# AtomsBase.jl version 0.4. )
65+
#
66+
# First import some stuff + a little hack to make GeomOpt play nice with
67+
# the latest AtomsBase. This is a shortcoming of DecoratedParticles.jl
68+
# and requires some updates to fully implement the AtomsBase interface.
69+
70+
using AtomsBuilder, GeomOpt, AtomsCalculators, AtomsBase
71+
using AtomsBase: FlexibleSystem, FastSystem
72+
using AtomsCalculators: potential_energy
73+
function _flexiblesystem(sys)
74+
c3ll = cell(sys)
75+
particles = [ AtomsBase.Atom(species(sys, i), position(sys, i))
76+
for i = 1:length(sys) ]
77+
return FlexibleSystem(particles, c3ll)
78+
end;
79+
80+
# We generate a cubic Cu unit cell, but our potential might not have the same
81+
# equilibrium bond distance as the default in AtomsBuilder, so we optimize
82+
# the unit cell.
83+
84+
ucell = bulk(sym, cubic=true)
85+
ucell, _ = GeomOpt.minimise(ucell, model; variablecell=true)
86+
87+
# We keep the energy of the equilibrated unit cell to later compute the
88+
# defect formation energy.
89+
90+
Eperat = potential_energy(ucell, model) / length(ucell)
91+
@show Eperat;
92+
93+
# Now that we have an equilibrated unit cell we enlarge it, and then delete
94+
# an atom to generate a vacancy defect.
95+
96+
sys = _flexiblesystem(ucell) * (2,2,2)
97+
deleteat!(sys, 1)
98+
sys
99+
100+
# Now we do another geometry optimization to get the equilibrium geometry.
101+
102+
vacancy_equil, result = GeomOpt.minimise(sys, model; variablecell = false)
103+
@show result.g_residual;
104+
105+
# We get an estimate of the formation energy. Note this is likely a poor
106+
# estimate since we didn't train the model on vacancy configurations.
107+
108+
E_def = potential_energy(vacancy_equil, model) - length(sys) * Eperat
109+
@show E_def;
110+
111+
# ## Molecular Dynamics with Molly
112+
#
113+
# First import some stuff + a little hack to make GeomOpt play nice with
114+
# the latest AtomsBase. This is a shortcoming of DecoratedParticles.jl
115+
# and requires some updates to fully implement the AtomsBase interface.
116+
117+
import Molly
118+
sys = rattle!(bulk(sym, cubic=true) * (2,2,2), 0.03)
119+
sys_md = Molly.System(sys; force_units=u"eV/Å", energy_units=u"eV")
120+
temp = 298.0u"K"
121+
sys_md = Molly.System(
122+
sys_md;
123+
general_inters = (model,),
124+
velocities = Molly.random_velocities(sys_md, temp),
125+
loggers=(temp=Molly.TemperatureLogger(100),) )
126+
## energy = Molly.PotentialEnergyLogger(100),), )
127+
## can't add an energy logger because Molly internal energies are per mol
128+
simulator = Molly.VelocityVerlet(
129+
dt = 1.0u"fs",
130+
coupling = Molly.AndersenThermostat(temp, 1.0u"ps"), )
131+
132+
Molly.simulate!(sys_md, simulator, 1000)
133+
134+
## the temperature seems to fluctuate a bit, but at least it looks stable?
135+
@info("Temperature history:", sys_md.loggers.temp.history)
136+

examples/Tutorial/ACEpotentials-Tutorial.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,8 @@ using AtomsCalculators: potential_energy
303303

304304
function assess_model(model, train_dataset)
305305

306-
plot([-164,-158], [-164,-158]; lc=:black, label="")
307-
306+
plot([-164,-157], [-164,-157]; lc=:black, label="")
307+
308308
model_energies = []
309309
model_std = []
310310
for atoms in Si_dataset
@@ -320,8 +320,8 @@ function assess_model(model, train_dataset)
320320
@sprintf("RMSE (MAE) For Entire Dataset: %.0f (%.0f) meV/atom", 1000*rmse, 1000*mae),
321321
titlefontsize = 8,
322322
yerror = model_std,
323-
xlabel="Energy [eV/atom]", xlims=(-164,-158),
324-
ylabel="Model Energy [eV/atom]", ylims=(-164,-158),
323+
xlabel="Energy [eV/atom]", xlims=(-164,-157),
324+
ylabel="Model Energy [eV/atom]", ylims=(-164,-157),
325325
aspect_ratio = :equal, color=1)
326326

327327
model_energies = [ustrip(potential_energy(atoms, model)/length(atoms)) for atoms in train_dataset]
@@ -407,7 +407,7 @@ r_cut = 6.0
407407
rdf = ACEpotentials.get_rdf(tial_data, r_cut * u"Å")
408408
plt_TiTi = histogram(rdf[(:Ti, :Ti)], bins=100, xlabel = "", c = 1,
409409
ylabel = "RDF - TiTi", label = "", yticks = [], xlims = (0, r_cut) )
410-
plt_TiAl = histogram(rdf[(:Ti, :Ti)], bins=100, xlabel = "", c = 2,
410+
plt_TiAl = histogram(rdf[(:Ti, :Al)], bins=100, xlabel = "", c = 2,
411411
ylabel = "RDF - TiAl", label = "", yticks = [], xlims = (0, r_cut) )
412412
plt_AlAl = histogram(rdf[(:Al, :Al)], bins=100, xlabel = L"r [\AA]", c = 3,
413413
ylabel = "RDF - AlAl", label = "", yticks = [], xlims = (0, r_cut), )

src/json_interface.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,25 @@ end
182182

183183

184184
"""
185-
copy_tutorial(dest)
185+
copy_tutorial(dest = pwd())
186186
187-
Converts the `ACEpotential-Tutorial.jl` literate notebook to a jupyter notebook
188-
and copies it to the folder `dest`.
187+
Converts the `ACEpotential-Tutorial.jl` and `ACE+AtomsBase.jl` literate
188+
notebooks to jupyter notebooks and copies them to the folder `dest`.
189189
"""
190190
function copy_tutorial(dest = pwd())
191-
path = joinpath(@__DIR__(), "..", "examples", "Tutorial")
192-
orig = joinpath(path, "ACEpotentials-Tutorial.jl")
193-
dest_jl = joinpath(dest, "ACEpotentials-Tutorial.jl")
194-
cp(orig, dest_jl)
191+
# install IJulia and Literate
195192
julia_cmd = Base.julia_cmd()
196-
run(`$julia_cmd --project=. -e 'using Pkg; Pkg.add(["IJulia", "Literate"])'`)
197-
jl_script = "using Literate; Literate.notebook(\"$dest_jl\", \"$dest\"; config = Dict(\"execute\" => false))"
198-
run(`$julia_cmd --project=. -e $jl_script`)
199-
rm(dest_jl)
193+
run(`$julia_cmd --project=$dest -e 'using Pkg; Pkg.add(["IJulia", "Literate"])'`)
194+
# copy the tutorial files and convert them to jupyter notebooks
195+
path = joinpath(@__DIR__(), "..", "examples", "Tutorial")
196+
for tutfile in ["ACEpotentials-Tutorial.jl", "ACE+AtomsBase.jl" ]
197+
orig = joinpath(path, tutfile)
198+
dest_jl = joinpath(dest, tutfile)
199+
cp(orig, dest_jl)
200+
jl_script = "using Literate; Literate.notebook(\"$dest_jl\", \"$dest\"; config = Dict(\"execute\" => false))"
201+
run(`$julia_cmd --project=$dest -e $jl_script`)
202+
rm(dest_jl)
203+
end
200204
return nothing
201205
end
202206

0 commit comments

Comments
 (0)