Skip to content

Commit d6fde5f

Browse files
authored
Extend AtomsBaseTesting and AtomsBase test routines (#121)
1 parent ec347fa commit d6fde5f

19 files changed

+268
-238
lines changed

lib/AtomsBaseTesting/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "AtomsBaseTesting"
22
uuid = "ed7c10db-df7e-4efa-a7be-4f4190f7f227"
33
authors = ["JuliaMolSim community"]
4-
version = "0.2.0"
4+
version = "0.3.0"
55

66
[deps]
77
AtomsBase = "a963bdd2-2df7-4f54-a1ee-49d51e6be12a"

lib/AtomsBaseTesting/src/AtomsBaseTesting.jl

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using LinearAlgebra
66
using Unitful
77
using UnitfulAtomic
88

9-
using AtomsBase: AbstractSystem
9+
using AtomsBase: AbstractSystem
1010

1111
export test_approx_eq
1212
export make_test_system
@@ -17,12 +17,10 @@ properties can be ignored during the comparison using the respective kwargs.
1717
"""
1818
function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
1919
rtol=1e-14, ignore_atprop=Symbol[], ignore_sysprop=Symbol[],
20-
common_only=false)
20+
common_only=false, quiet=false)
2121
rnorm(a, b) = (ustrip(norm(a)) < rtol ? norm(a - b) / 1unit(norm(a))
2222
: norm(a - b) / norm(a))
2323

24-
_isinfinite(s) = any(isinf, reduce(vcat, bounding_box(s)))
25-
2624
for method in (length, size, periodicity, )
2725
@test method(s) == method(t)
2826
end
@@ -32,7 +30,7 @@ function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
3230
@test rnorm(method(s, 1), method(t, 1)) < rtol
3331
end
3432

35-
# TODO: add element_symbol back in
33+
# TODO: add element_symbol back in
3634
for method in (species, atomic_symbol, atomic_number, )
3735
@test method(s, :) == method(t, :)
3836
@test method(s, 1) == method(t, 1)
@@ -46,6 +44,7 @@ function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
4644
end
4745
end
4846

47+
# test properties of atoms
4948
if common_only
5049
test_atprop = [k for k in atomkeys(s) if hasatomkey(t, k)]
5150
else
@@ -56,7 +55,7 @@ function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
5655
prop in ignore_atprop && continue
5756
prop in (:velocity, :position) && continue
5857
if hasatomkey(s, prop) != hasatomkey(t, prop)
59-
println("hashatomkey mismatch for $prop")
58+
quiet || println("hashatomkey mismatch for $prop")
6059
@test hasatomkey(s, prop) == hasatomkey(t, prop)
6160
continue
6261
end
@@ -72,6 +71,12 @@ function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
7271
end
7372
end
7473

74+
# Test some things on cell objects
75+
@test typeof(cell(s)) == typeof(cell(t))
76+
@test periodicity(cell(s)) == periodicity(cell(t))
77+
@test n_dimensions(cell(s)) == n_dimensions(cell(t))
78+
79+
# test properties of systems
7580
if common_only
7681
test_sysprop = [k for k in keys(s) if haskey(t, k)]
7782
else
@@ -81,15 +86,15 @@ function test_approx_eq(s::AbstractSystem, t::AbstractSystem;
8186
for prop in test_sysprop
8287
prop in ignore_sysprop && continue
8388
if haskey(s, prop) != haskey(t, prop)
84-
println("haskey mismatch for $prop")
89+
quiet || println("haskey mismatch for $prop")
8590
@test haskey(s, prop) == haskey(t, prop)
8691
continue
8792
end
8893
(haskey(s, prop) && haskey(t, prop)) || continue
8994

9095
if s[prop] isa Quantity
9196
@test rnorm(s[prop], t[prop]) < rtol
92-
elseif prop in (:bounding_box, ) && !(_isinfinite(s))
97+
elseif prop in (:bounding_box, ) && (cell(s) isa PeriodicCell)
9398
@test maximum(map(rnorm, s[prop], t[prop])) < rtol
9499
else
95100
@test s[prop] == t[prop]
@@ -104,23 +109,44 @@ Extra atomic or system properties can be specified using `extra_atprop` and `ext
104109
and specific standard keys can be ignored using `drop_atprop` and `drop_sysprop`.
105110
"""
106111
function make_test_system(D=3; drop_atprop=Symbol[], drop_sysprop=Symbol[],
107-
extra_atprop=(; ), extra_sysprop=(; ), cellmatrix=:full,
112+
extra_atprop=(; ), extra_sysprop=(; ), cellmatrix=:full,
108113
n_atoms = 5, )
109114
@assert D == 3
110115

111-
# Generate some random data to store in Atoms
116+
if cellmatrix == :lower_triangular
117+
box = ([1.54732, -0.807289, -0.500870]u"Å",
118+
[ 0.0, 0.4654985, 0.5615117]u"Å",
119+
[ 0.0, 0.0, 0.7928950]u"Å")
120+
elseif cellmatrix == :upper_triangular
121+
box = ([1.54732, 0.0, 0.0]u"Å",
122+
[-0.807289, 0.4654985, 0.0]u"Å",
123+
[-0.500870, 0.5615117, 0.7928950]u"Å")
124+
elseif cellmatrix == :diagonal
125+
box = ([1.54732, 0.0, 0.0]u"Å",
126+
[0.0, 0.4654985, 0.0]u"Å",
127+
[0.0, 0.0, 0.7928950]u"Å")
128+
else
129+
box = ([1.50304, 0.850344, 0.717239]u"Å",
130+
[ 0.36113, 1.008144, 0.814712]u"Å",
131+
[ 0.06828, 0.381122, 2.129081]u"Å")
132+
end
133+
134+
# Generate some random data to store in atoms and system
112135
atprop = Dict{Symbol,Any}(
113136
:position => [randn(3) for _ = 1:n_atoms]u"Å",
114137
:velocity => [randn(3) for _ = 1:n_atoms] * 10^6*u"m/s",
115-
# Note: reasonable velocity range in au
116-
:atomic_symbol => [:H, :H, :C, :N, :He],
138+
# Note to above: Reasonable velocity range in au
139+
:species => ChemicalSpecies.([:H, :H, :C, :N, :He]),
117140
:charge => [2, 1, 3.0, -1.0, 0.0]u"e_au",
118-
:atomic_mass => 10rand(n_atoms)u"u",
141+
:mass => 10rand(n_atoms)u"u",
119142
:vdw_radius => randn(n_atoms)u"Å",
120143
:covalent_radius => randn(n_atoms)u"Å",
121144
:magnetic_moment => [0.0, 0.0, 1.0, -1.0, 0.0],
122145
)
123146
sysprop = Dict{Symbol,Any}(
147+
:bounding_box => box,
148+
:periodicity => (true, true, false),
149+
#
124150
:extra_data => 42,
125151
:charge => -1u"e_au",
126152
:multiplicity => 2,
@@ -136,36 +162,23 @@ function make_test_system(D=3; drop_atprop=Symbol[], drop_sysprop=Symbol[],
136162
atprop = merge(atprop, pairs(extra_atprop))
137163

138164
atoms = map(1:n_atoms) do i
139-
atargs = Dict(k => v[i] for (k, v) in pairs(atprop)
140-
if !(k in (:position, :velocity)))
165+
atargs = Dict(k => v[i] for (k, v) in pairs(atprop) if !(k in (:position, :velocity)))
141166
if haskey(atprop, :velocity)
142-
Atom(atprop[:atomic_symbol][i], atprop[:position][i], atprop[:velocity][i];
143-
atargs...)
167+
Atom(atprop[:species][i], atprop[:position][i], atprop[:velocity][i]; atargs...)
144168
else
145-
Atom(atprop[:atomic_symbol][i], atprop[:position][i]; atargs...)
169+
Atom(atprop[:species][i], atprop[:position][i]; atargs...)
146170
end
147171
end
148-
if cellmatrix == :lower_triangular
149-
box = ([1.54732, -0.807289, -0.500870]u"Å",
150-
[ 0.0, 0.4654985, 0.5615117]u"Å",
151-
[ 0.0, 0.0, 0.7928950]u"Å")
152-
elseif cellmatrix == :upper_triangular
153-
box = ([1.54732, 0.0, 0.0]u"Å",
154-
[-0.807289, 0.4654985, 0.0]u"Å",
155-
[-0.500870, 0.5615117, 0.7928950]u"Å")
156-
elseif cellmatrix == :diagonal
157-
box = ([1.54732, 0.0, 0.0]u"Å",
158-
[0.0, 0.4654985, 0.0]u"Å",
159-
[0.0, 0.0, 0.7928950]u"Å")
160-
else
161-
box = ([1.50304, 0.850344, 0.717239]u"Å",
162-
[ 0.36113, 1.008144, 0.814712]u"Å",
163-
[ 0.06828, 0.381122, 2.129081]u"Å")
164-
end
165-
pbcs = (true, true, false)
166-
system = atomic_system(atoms, box, pbcs; sysprop...)
172+
cell = PeriodicCell(; cell_vectors=sysprop[:bounding_box],
173+
periodicity=sysprop[:periodicity])
174+
175+
sysargs = Dict(k => v for (k, v) in pairs(sysprop)
176+
if !(k in (:bounding_box, :periodicity)))
177+
system = FlexibleSystem(atoms, cell; sysargs...)
167178

168-
(; system, atoms, atprop=NamedTuple(atprop), sysprop=NamedTuple(sysprop), box, pbcs)
179+
(; system, atoms, cell,
180+
bounding_box=sysprop[:bounding_box], periodicity=sysprop[:periodicity],
181+
atprop=NamedTuple(atprop), sysprop=NamedTuple(sysprop))
169182
end
170183

171184
end

lib/AtomsBaseTesting/test/runtests.jl

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ include("testmacros.jl")
99

1010
@testset "AtomsBaseTesting.jl" begin
1111
@testset "make_test_system" begin
12+
let case = make_test_system()
13+
# Data that is delivered agrees with the constructed system
14+
# TODO Could test more here
15+
@test sort(collect(keys(case.atprop))) == sort(collect(atomkeys(case.system)))
16+
@test sort(collect(keys(case.atprop))) == sort(collect(keys(case.atoms[1])))
17+
@test sort(collect(keys(case.sysprop))) == sort(collect(keys(case.system)))
18+
@test case.bounding_box == bounding_box(case.system)
19+
@test case.periodicity == periodicity(case.system)
20+
end
21+
1222
let case = make_test_system(; cellmatrix=:full)
1323
box = reduce(hcat, bounding_box(case.system))
1424
@test UpperTriangular(box) != box
@@ -33,7 +43,7 @@ include("testmacros.jl")
3343
@test UpperTriangular(box) == box
3444
@test LowerTriangular(box) == box
3545
end
36-
46+
3747
@test hasatomkey(make_test_system().system, :vdw_radius)
3848
@test !hasatomkey(make_test_system(; drop_atprop=[:vdw_radius]).system, :vdw_radius)
3949

@@ -52,9 +62,9 @@ include("testmacros.jl")
5262
# once we require Julia 1.7
5363
case = make_test_system()
5464
system = case.system
55-
atoms = case.atoms
56-
box = case.box
57-
bcs = case.pbcs
65+
atoms = case.atoms
66+
box = case.bounding_box
67+
bcs = case.periodicity
5868
sysprop = case.sysprop
5969
# end simplify
6070

@@ -71,17 +81,17 @@ include("testmacros.jl")
7181
# once we require Julia 1.7
7282
case = make_test_system()
7383
system = case.system
74-
atoms = case.atoms
75-
box = case.box
76-
bcs = case.pbcs
84+
atoms = case.atoms
85+
box = case.bounding_box
86+
bcs = case.periodicity
7787
sysprop = case.sysprop
7888
# end simplify
7989

8090
sysprop_dict = Dict(pairs(sysprop))
8191
pop!(sysprop_dict, :multiplicity)
8292
system_edit = atomic_system(atoms, box, bcs; sysprop_dict...)
8393

84-
@testfail test_approx_eq(system, system_edit)
94+
@testfail test_approx_eq(system, system_edit, quiet=true)
8595
@testpass test_approx_eq(system, system_edit; ignore_sysprop=[:multiplicity])
8696
@testpass test_approx_eq(system, system_edit; common_only=true)
8797
end

src/AtomsBase.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ using UnitfulAtomic
55
using StaticArrays
66
using Requires
77

8-
export Atom, FlexibleSystem, FastSystem, AbstractSystem
8+
export Atom, FlexibleSystem, FastSystem, AbstractSystem
99

10-
# Main Interface specification and inline docs
10+
# Main Interface specification and inline docs
1111
include("interface.jl")
1212

13-
# utilities useful to share across implementations
13+
# utilities useful to share across implementations
1414
include("utils/cells.jl")
1515
include("utils/chemspecies.jl")
1616
include("utils/properties.jl")
@@ -19,15 +19,15 @@ include("utils/show.jl")
1919
include("utils/atomview.jl")
2020

2121

22-
# prototype implementations
22+
# prototype implementations
2323
include("implementation/atom.jl")
2424
include("implementation/flexible_system.jl")
2525
include("implementation/fast_system.jl")
2626
include("implementation/utils.jl")
2727

2828

29-
# TODO:
30-
# - this should be converted to an extension
29+
# TODO:
30+
# - this should be converted to an extension
3131
# - should work for AbstractSystem
3232
function __init__()
3333
@require AtomsView="ee286e10-dd2d-4ff2-afcb-0a3cd50c8041" begin

src/implementation/atom.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ struct Atom{D, L<:Unitful.Length, V<:Unitful.Velocity, M<:Unitful.Mass}
1616
data::Dict{Symbol, Any} # Store arbitrary data about the atom.
1717
end
1818

19-
velocity(atom::Atom) = atom.velocity
20-
position(atom::Atom) = atom.position
21-
mass(atom::Atom) = atom.mass
22-
species(atom::Atom) = atom.species
19+
velocity(atom::Atom) = atom.velocity
20+
position(atom::Atom) = atom.position
21+
mass(atom::Atom) = atom.mass
22+
species(atom::Atom) = atom.species
2323

2424
n_dimensions(::Atom{D}) where {D} = D
2525

@@ -68,7 +68,7 @@ function _default_velocity(position::AbstractVector{L}) where {L <: Unitful.Leng
6868
elseif uL == u"bohr"
6969
return zeros(TFL, length(position))u"nm/s"
7070
elseif uL == u"m"
71-
return zeros(TFL, length(position))u"m/s"
71+
return zeros(TFL, length(position))u"m/s"
7272
end
7373
@warn("Cannot infer default velocity for position with unit $(unit(position[1]))")
7474
return zeros(TFL, length(position)) * (uL / u"s")

src/implementation/fast_system.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function FastSystem(cϵll::TCELL, positions::AbstractVector{<: SVector{D, L}},
2727
species::AbstractVector{S}, masses) where {TCELL, D, L, S}
2828
if D != n_dimensions(cϵll)
2929
throw(ArgumentError("Cell dimension D=$(n_dimensions(cϵll)) does not match particle dimension D=$D."))
30-
end
30+
end
3131
FastSystem{D, TCELL, L, typeof(masses), S}(
3232
cϵll, positions, species, masses)
3333
end
@@ -91,8 +91,6 @@ Base.getindex(system::FastSystem, ::Colon, x::Symbol) = getfield(system, x)
9191
position(s::FastSystem, ::Colon) = s.position
9292
position(sys::FastSystem, i::Union{Integer, AbstractVector}) = sys.position[i]
9393

94-
velocity(::FastSystem, args...) = missing
95-
9694
mass(s::FastSystem, ::Colon) = s.mass
9795
mass(sys::FastSystem, i::Union{Integer, AbstractVector}) = sys.mass[i]
9896

src/implementation/flexible_system.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ velocity(sys::FlexibleSystem, i::Integer) =
116116
velocity(sys.particles[i])
117117

118118
velocity(sys::FlexibleSystem, i::Union{AbstractVector, Colon}) =
119-
[ velocity(x) for x in sys.particles[i] ]
119+
[ velocity(x) for x in sys.particles[i] ]
120120

121121
mass(sys::FlexibleSystem, i::Integer) =
122122
mass(sys.particles[i])
@@ -128,4 +128,4 @@ species(sys::FlexibleSystem, i::Integer) =
128128
species(sys.particles[i])
129129

130130
species(sys::FlexibleSystem, i::Union{AbstractVector, Colon}) =
131-
[ species(x) for x in sys.particles[i] ]
131+
[ species(x) for x in sys.particles[i] ]

src/implementation/utils.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ julia> hydrogen = atomic_system([:H => [0, 0, 1.]u"bohr",
2222
bounding_box, pbcs)
2323
```
2424
"""
25-
atomic_system(atoms::AbstractVector{<:Atom}, box, bcs; kwargs...) =
26-
FlexibleSystem(atoms, box, bcs; kwargs...)
25+
atomic_system(atoms::AbstractVector{<:Atom}, box, pbcs; kwargs...) =
26+
FlexibleSystem(atoms, box, pbcs; kwargs...)
2727

28-
atomic_system(atoms::AbstractVector, box, bcs; kwargs...) =
29-
FlexibleSystem(convert.(Atom, atoms), box, bcs; kwargs...)
28+
atomic_system(atoms::AbstractVector, box, pbcs; kwargs...) =
29+
FlexibleSystem(convert.(Atom, atoms), box, pbcs; kwargs...)
3030

3131

3232
"""

0 commit comments

Comments
 (0)