Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly integrate XSF #23

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/file_formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The following list all currently available parsers, in the order they are tried

```@docs
AtomsIO.ExtxyzParser
AtomsIO.XcrysdenstructureformatParser
AtomsIO.ChemfilesParser
AtomsIOPython.AseParser
```
2 changes: 2 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ AtomsIO currently integrates with

- [Chemfiles](https://github.com/chemfiles/Chemfiles.jl)
- [ExtXYZ](https://github.com/libAtoms/ExtXYZ.jl)
- [XCrySDenStructureFormat](https://github.com/azadoks/XCrySDenStructureFormat.jl)
- [ASEconvert](https://github.com/mfherbst/ASEconvert.jl)
(respectively [ASE](https://wiki.fysik.dtu.dk/ase/))

Expand All @@ -16,6 +17,7 @@ and supports all file formats any of these packages support
- [Quantum Espresso](https://www.quantum-espresso.org/Doc/INPUT_PW.html) / [ABINIT](https://docs.abinit.org/variables/) / [VASP](https://www.vasp.at/wiki/) input files
- ASE / [Gromacs](http://manual.gromacs.org/archive/5.0.7/online/trj.html) / [LAMMPS](https://lammps.sandia.gov/doc/dump.html) / [Amber](http://ambermd.org/netcdf/nctraj.xhtml) trajectory files
- [XYZ](https://openbabel.org/wiki/XYZ) and [extxyz](https://github.com/libAtoms/extxyz#extended-xyz-specification-and-parsing-tools) files
- [XSF](http://www.xcrysden.org/doc/XSF.html) (XCrySDen) atomic structure files.

For more details see [Saving and loading files](@ref) and [File Formats](@ref).

Expand Down
4 changes: 3 additions & 1 deletion src/AtomsIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import PeriodicTable
include("parser.jl")
include("chemfiles.jl")
include("extxyz.jl")
include("xsf.jl")
include("saveload.jl")

export load_system, save_system, load_trajectory, save_trajectory
export AbstractParser, ChemfilesParser, ExtxyzParser
export AbstractParser
export ChemfilesParser, ExtxyzParser, XcrysdenstructureformatParser
end
4 changes: 3 additions & 1 deletion src/saveload.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
# *breaking change* (as it alters the behaviour of AtomsIO.load_system).
# Moreover since not all users will want to rely on Python dependencies, it is
# crucial that the python packages are only *appended* to this list.
const DEFAULT_PARSER_ORDER = AbstractParser[ExtxyzParser(), ChemfilesParser()]
const DEFAULT_PARSER_ORDER = AbstractParser[
ExtxyzParser(), XcrysdenstructureformatParser(), ChemfilesParser(),
]

function determine_parser(file; save=false, trajectory=false)
idx_parser = findfirst(DEFAULT_PARSER_ORDER) do parser
Expand Down
46 changes: 29 additions & 17 deletions src/xsf.jl
Original file line number Diff line number Diff line change
@@ -1,43 +1,55 @@
import XCrySDenStructureFormat as XSF

"""
Parse or write file using [XSF](https://github.com/azadoks/XCrySDenStructureFormat.jl)
Parse or write file using [XCrySDenStructureFormat](https://github.com/azadoks/XCrySDenStructureFormat.jl).

Supported formats:
- [XSF](http://www.xcrysden.org/doc/XSF.html)
- [XSF](http://www.xcrysden.org/doc/XSF.html) and [AXSF](XCrySDenStructureFormat)
atomic structure files. These are the files typically used by the
[XCrySDen](http://www.xcrysden.org/) visualisation program.
"""
struct XsfParser <: AbstractParser end
struct XcrysdenstructureformatParser <: AbstractParser end

function supports_parsing(::XsfParser, file; save, trajectory)
function supports_parsing(::XcrysdenstructureformatParser, file; save, trajectory)
_, ext = splitext(file)
ext in (".xsf", ".axsf")
end

function load_system(::XsfParser, file::AbstractString, index=nothing)
if isnothing(index)
frames = XSF.load_xsf(file)
function load_system(::XcrysdenstructureformatParser, file::AbstractString, index=nothing)
if !isnothing(index)
return XSF.load_xsf(file)[index]
end


frames = XSF.load_xsf(file)
if !(frames isa AbstractVector)
# load_xsf Returns plain structure in case only a single structure in the file
return frames
else
isempty(frames) && error(
"XSF returned no frames. Check the passed file is a valid (a)xsf file."
)
return last(frames)
else
return XSF.load_xsf(file)[index]
end
end

function save_system(::XsfParser, file::AbstractString, system::AbstractSystem)
function save_system(::XcrysdenstructureformatParser,
file::AbstractString, system::AbstractSystem)
XSF.save_xsf(file, system)
end

function load_trajectory(::XsfParser, file::AbstractString)
XSF.load_xsf(file)
end

function save_system(::XsfParser, file::AbstractString, system::AbstractSystem)
XSF.save_xsf(file, system)
function load_trajectory(::XcrysdenstructureformatParser, file::AbstractString)
# load_xsf Returns plain structure in case only a single structure in the file,
# so we need to re-wrap to keep a consistent interface.
ret = XSF.load_xsf(file)
if !(ret isa AbstractVector)
return [ret]
else
return ret
end
end

function save_trajectory(::XsfParser, file::AbstractString,
function save_trajectory(::XcrysdenstructureformatParser, file::AbstractString,
systems::AbstractVector{<:AbstractSystem})
XSF.save_xsf(file, systems)
end
10 changes: 8 additions & 2 deletions test/failed_files.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ using LinearAlgebra

# Tests parsing files, where previously users reported problems
@testset "Failed files" begin
@testset "Empty XYZ" begin
@test_throws "ExtXYZ returned no frames." load_system("files/empty.xyz")
end

@testset "XYZ from Lammps" begin
@test_throws "ExtXYZ returned no frames." load_system("files/lammps.xyz")
end

@testset "CIF Graphene P6/mmm" begin
parsed = load_system("files/graphene.cif")
reduced = reduce(hcat, bounding_box(parsed))
Expand All @@ -15,7 +23,5 @@ using LinearAlgebra
@test atomic_symbol(parsed) == [:C1, :C2, :C3, :C4]
@test atomic_number(parsed) == [6, 6, 6, 6]
@test parsed[:name] == "Graphene"


end
end
4 changes: 4 additions & 0 deletions test/files/empty.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@




3 changes: 3 additions & 0 deletions test/files/lammps.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1
Atoms. Timestep: 1000000
Ar 1.4102613692638457 0.9647607662828660 1.3209769521273491
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if GROUP == "Core"
@testset "AtomsIO.jl" begin
include("chemfiles.jl")
include("extxyz.jl")
include("xsf.jl")
include("failed_files.jl")
# For the comparison tests (also between Chemfiles and ExtXYZ and other
# non-python libraries) see the AtomsIOPython subproject
Expand Down
6 changes: 6 additions & 0 deletions test/xsf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ using Test
using AtomsBaseTesting

@testset "XSF system write / read" begin
XsfParser = AtomsIO.XcrysdenstructureformatParser

system = make_test_system().system
mktempdir() do d
outfile = joinpath(d, "output.xsf")
Expand All @@ -13,6 +15,8 @@ using AtomsBaseTesting
end

@testset "XSF trajectory write/read" begin
XsfParser = AtomsIO.XcrysdenstructureformatParser

systems = [make_test_system().system for _ in 1:3]
mktempdir() do d
outfile = joinpath(d, "output.axsf")
Expand All @@ -28,6 +32,8 @@ end

@testset "ExtXYZ supports_parsing" begin
import AtomsIO: supports_parsing
XsfParser = AtomsIO.XcrysdenstructureformatParser

prefix = "test"
save = trajectory = true
@test supports_parsing(XsfParser(), prefix * ".xsf"; save, trajectory)
Expand Down
Loading