Skip to content

Commit

Permalink
Merge pull request #14 from JuliaMolSim/update_wrapper
Browse files Browse the repository at this point in the history
Improve wrapper code and update to Libxc 5
  • Loading branch information
mfherbst authored Jun 4, 2020
2 parents be2b899 + 199510d commit 6e89454
Show file tree
Hide file tree
Showing 15 changed files with 922 additions and 916 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ version = "0.2.0"
Libxc_jll = "a56a6d9d-ad03-58af-ab61-878bf78270d6"

[compat]
Libxc_jll = "4.3"
Libxc_jll = "5"
julia = "1.3"

[extras]
Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This package provides Julia bindings to the
[libxc](https://tddft.org/programs/libxc/) library
for common exchange-correlation functionals in density-functional theory.

## Usage
## Usage (High-level interface)
Install the library from Julia as usual:
```sh
] add Libxc
Expand All @@ -30,17 +30,28 @@ using Libxc

rho = [0.1, 0.2, 0.3, 0.4, 0.5]
sigma = [0.2, 0.3, 0.4, 0.5, 0.6]
result = similar(rho)

# LDA exchange
lda_x = Functional(:lda_x)
evaluate_lda!(lda_x, rho, E=result)
result = evaluate(lda_x, rho=rho)
@show result
# [-0.342809, -0.431912, -0.494416, -0.544175, -0.586194]
# result = (vrho = [-0.457078 -0.575882 -0.659220 -0.725566 -0.781592],
# zk = [-0.342808, -0.43191, -0.49441, -0.544174, -0.586194])

# GGA exchange
gga_x = Functional(:gga_x_pbe)
evaluate_gga!(gga_x, rho, sigma, E=result)
gga_x = Functional(:gga_x_pbe, n_spin=1)
result = evaluate(gga_x, rho=rho, sigma=sigma, derivative=0)
@show result
# [-0.452598, -0.478878, -0.520674, -0.561428, -0.598661]
# result = (zk = [-0.452597, -0.478877, -0.520674, -0.561427, -0.598661],)
```

### Status
Full support for evaluating LDA, GGA and meta-GGA functionals
as shown above. No support for hybrid or range-separated
functionals yet. For those you need to talk to libxc directly
using the low-level interface.

## Low-level interface
All functions from libxc are available in Julia in a C-like interface
automatically generated from the libxc source code. See the file
[src/gen/libxc.jl](src/gen/libxc.jl) for the full list.
34 changes: 34 additions & 0 deletions scripts/generate_api.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Clang

# Download libxc sources
LIBXC_VERSION = "5.0.0"
if !isfile(joinpath(@__DIR__, "libxc/src/xc.h"))
download("https://gitlab.com/libxc/libxc/-/archive/$LIBXC_VERSION/" *
"libxc-$LIBXC_VERSION.tar.gz", "libxc.tar.gz")
run(`tar xf libxc.tar.gz`)
libxc_dir = only(d for d in readdir(".") if startswith(d, "libxc-"))
run(`ln -sf $libxc_dir libxc`)
rm("libxc.tar.gz")
@assert isfile(joinpath(@__DIR__, "libxc/src/xc.h"))
end

# Generate API wrapper
LIBXC_INCLUDE = normpath(joinpath(@__DIR__, "libxc/src"))
LIBXC_HEADERS = [joinpath(LIBXC_INCLUDE, header) for header in ["xc.h"]]
OUTPUTDIR = joinpath(@__DIR__, "../src/gen")

wc = init(;headers=LIBXC_HEADERS,
output_file=joinpath(OUTPUTDIR, "libxc.jl"),
common_file=joinpath(OUTPUTDIR, "libxc_common.jl"),
header_library = x -> "libxc",
clang_includes = vcat(LIBXC_INCLUDE, CLANG_INCLUDE),
header_wrapped = (root, current) -> root == current,
clang_diagnostics = false,
)

run(wc)

# Cleanup unused files
for file in ["ctypes.jl", "LibTemplate.jl"]
rm(joinpath(OUTPUTDIR, file), force=true)
end
133 changes: 78 additions & 55 deletions src/Functional.jl
Original file line number Diff line number Diff line change
@@ -1,43 +1,22 @@
"""Return the list of available libxc functionals as strings"""
function available_functionals()
n_xc = ccall((:xc_number_of_functionals, libxc), Cint, ())
max_string_length = ccall((:xc_maximum_name_length, libxc), Cint, ())

funcnames = Vector{String}(undef, n_xc)
for i in 1:n_xc
funcnames[i] = "\0"^(max_string_length + 2)
end
ccall((:xc_available_functional_names, libxc), Cvoid, (Ptr{Ptr{UInt8}}, ), funcnames)
[string(split(funcnames[i], "\0")[1]) for i in 1:n_xc]
end

@enum FunctionalKind begin
functional_exchange = 0
functional_correlation = 1
functional_exchange_correlation = 2
functional_kinetic = 3
end

@enum FunctionalFamily begin
family_unknown = -1
family_lda = 1
family_gga = 2
family_mggai = 4
family_lca = 8
family_oep = 16
family_hyb_gga = 32
family_hyb_mgga = 64
end

"""
Struct for a Libxc functional and some basic information
"""
mutable struct Functional
number::Int
identifier::Symbol
kind::FunctionalKind
family::FunctionalFamily
n_spin::Int
name::String
kind::Symbol
family::Symbol
flags::Vector{Symbol}

# Spin dimensions libxc expects for various quantities
# Note: Only the symbols actually meaningful for this functional
# contain valid information
spin_dimensions

# Pointer holding the Libxc representation of this functional
pointer_::Ptr{xc_func_type}

# Pointer holding the LibXC representation of this functional
pointer::Ptr{XCFuncType}
end


Expand All @@ -48,17 +27,12 @@ Construct a Functional from a libxc `identifier` and the number
of spins `n_spin` to consider. `
"""
function Functional(identifier::Symbol; n_spin::Integer = 1)
if n_spin != 1 && n_spin != 2
error("n_spin needs to be 1 or 2")
end
n_spin in (1, 2) || error("n_spin needs to be 1 or 2")

number = ccall((:xc_functional_get_number, libxc), Cint, (Cstring, ),
string(identifier))
if number == -1
error("Functional $identifier is not known.")
end
number = xc_functional_get_number(string(identifier))
number == -1 && error("Functional $identifier is not known.")

function pointer_cleanup(ptr::Ptr{XCFuncType})
function pointer_cleanup(ptr::Ptr{xc_func_type})
if ptr != C_NULL
xc_func_end(ptr)
xc_func_free(ptr)
Expand All @@ -67,24 +41,73 @@ function Functional(identifier::Symbol; n_spin::Integer = 1)

pointer = xc_func_alloc()
ret = xc_func_init(pointer, number, n_spin)
if ret != 0
error("Something went wrong initialising the functional")
end
ret != 0 && error("Something went wrong initialising the functional")

try
funcinfo = xc_func_get_info(pointer)
kind = xc_func_info_get_kind(funcinfo)
family = xc_func_info_get_family(funcinfo)
flags = xc_func_info_get_flags(funcinfo)
# TODO Extract references ....
kind = KINDMAP[xc_func_info_get_kind(funcinfo)]
family = FAMILIYMAP[xc_func_info_get_family(funcinfo)]
flags = extract_flags(xc_func_info_get_flags(funcinfo))
name = unsafe_string(xc_func_info_get_name(funcinfo))
dimensions = unsafe_load(pointer).dim

# Make functional and attach finalizer for cleaning up the pointer
func = Functional(number, identifier, FunctionalKind(kind),
FunctionalFamily(family), n_spin, pointer)
finalizer(cls -> pointer_cleanup(cls.pointer), func)
func = Functional(identifier, n_spin, name, kind, family, flags,
dimensions, pointer)
finalizer(cls -> pointer_cleanup(cls.pointer_), func)
return func
catch
pointer_cleanup(pointer)
rethrow()
end
end


# Provide maps which translate between the conventions
# used in Libxc.jl and libxc

const KINDMAP = Dict(
XC_EXCHANGE => :exchange,
XC_CORRELATION => :correlation,
XC_EXCHANGE_CORRELATION => :exchange_correlation,
XC_KINETIC => :kinetic,
)

const FAMILIYMAP = Dict(
XC_FAMILY_UNKNOWN => :unknown,
XC_FAMILY_LDA => :lda,
XC_FAMILY_GGA => :gga,
XC_FAMILY_MGGA => :mgga,
XC_FAMILY_LCA => :lca,
XC_FAMILY_OEP => :oep,
XC_FAMILY_HYB_GGA => :hyb_gga,
XC_FAMILY_HYB_MGGA => :hyb_mgga,
XC_FAMILY_HYB_LDA => :hyb_lda,
)

const FLAGMAP = Dict(
XC_FLAGS_HAVE_EXC => :exc,
XC_FLAGS_HAVE_VXC => :vxc,
XC_FLAGS_HAVE_FXC => :fxc,
XC_FLAGS_HAVE_KXC => :kxc,
XC_FLAGS_HAVE_LXC => :lxc,
XC_FLAGS_1D => :dim1,
XC_FLAGS_2D => :dim2,
XC_FLAGS_3D => :dim3,
XC_FLAGS_HYB_CAM => :hyb_cam,
XC_FLAGS_HYB_CAMY => :hym_camy,
XC_FLAGS_VV10 => :vv10,
XC_FLAGS_HYB_LC => :hyb_lc,
XC_FLAGS_HYB_LCY => :hyb_lcy,
XC_FLAGS_STABLE => :stable,
XC_FLAGS_DEVELOPMENT => :development,
XC_FLAGS_NEEDS_LAPLACIAN => :needs_laplacian,
)

function extract_flags(flags)
ret = Symbol[]
for (flag, sym) in pairs(FLAGMAP)
flag & flags > 0 && push!(ret, sym)
end
ret
end
17 changes: 9 additions & 8 deletions src/Libxc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ module Libxc
using Libxc_jll
const libxc = Libxc_jll.libxc

include("version.jl")
include("xc.jl")
include("functionals_info.jl")

export Functional
include("gen/libxc_common.jl")
include("gen/libxc.jl")
include("wrapper.jl")
include("Functional.jl")

export evaluate_lda!
export evaluate_gga!
include("evaluate.jl")

const libxc_version = xc_version()
export available_functionals
export Functional
export evaluate
export evaluate!

end # module
Loading

0 comments on commit 6e89454

Please sign in to comment.