Abinit: a few modernizations for the package and its dependencies (#3699)

* libxc: added libs interface

* hdf5: added libs interface, added conflicts

* abinit: modernized package to use build interface

* netcdf-fortran: added libs interface

* abinit: added version 8.2.2
This commit is contained in:
Massimiliano Culpo 2017-04-07 11:18:34 +02:00 committed by GitHub
parent 030127a071
commit 10c395b2f5
5 changed files with 180 additions and 87 deletions

View file

@ -901,16 +901,12 @@ def __init__(self, spec, name, query_parameters):
)
is_virtual = Spec.is_virtual(name)
self._query_to_package = QueryState(
self.last_query = QueryState(
name=name,
extra_parameters=query_parameters,
isvirtual=is_virtual
)
@property
def last_query(self):
return self._query_to_package
@key_ordering
class Spec(object):

View file

@ -28,13 +28,15 @@
from spack import *
class Abinit(Package):
class Abinit(AutotoolsPackage):
"""ABINIT is a package whose main program allows one to find the total
energy, charge density and electronic structure of systems made of
electrons and nuclei (molecules and periodic solids) within
Density Functional Theory (DFT), using pseudopotentials and a planewave
or wavelet basis. ABINIT also includes options to optimize the geometry
according to the DFT forces and stresses, or to perform molecular dynamics
or wavelet basis.
ABINIT also includes options to optimize the geometry according to the
DFT forces and stresses, or to perform molecular dynamics
simulations using these forces, or to generate dynamical matrices,
Born effective charges, and dielectric tensors, based on Density-Functional
Perturbation Theory, and many more properties. Excited states can be
@ -44,11 +46,12 @@ class Abinit(Package):
programs are provided.
"""
homepage = "http://www.abinit.org"
url = "http://ftp.abinit.org/abinit-8.0.8b.tar.gz"
homepage = 'http://www.abinit.org'
url = 'http://ftp.abinit.org/abinit-8.0.8b.tar.gz'
version('8.2.2', '5f25250e06fdc0815c224ffd29858860')
# Versions before 8.0.8b are not supported.
version("8.0.8b", "abc9e303bfa7f9f43f95598f87d84d5d")
version('8.0.8b', 'abc9e303bfa7f9f43f95598f87d84d5d')
variant('mpi', default=True,
description='Builds with MPI support. Requires MPI2+')
@ -71,111 +74,108 @@ class Abinit(Package):
# Add dependencies
# currently one cannot forward options to virtual packages, see #1712.
# depends_on("blas", when="~openmp")
# depends_on("blas+openmp", when="+openmp")
# depends_on('blas', when='~openmp')
# depends_on('blas+openmp', when='+openmp')
depends_on('blas')
depends_on("lapack")
depends_on('lapack')
# Require MPI2+
depends_on("mpi@2:", when="+mpi")
depends_on('mpi@2:', when='+mpi')
depends_on("scalapack", when="+scalapack+mpi")
# depends_on("elpa", when="+elpa+mpi~openmp")
# depends_on("elpa+openmp", when="+elpa+mpi+openmp")
depends_on('scalapack', when='+scalapack+mpi')
depends_on("fftw+float", when="~openmp")
depends_on("fftw+float+openmp", when="+openmp")
# depends_on('elpa~openmp', when='+elpa+mpi~openmp')
# depends_on('elpa+openmp', when='+elpa+mpi+openmp')
depends_on("netcdf-fortran", when="+hdf5")
depends_on("hdf5+mpi", when='+mpi+hdf5') # required for NetCDF-4 support
depends_on('fftw+float', when='~openmp')
depends_on('fftw+float+openmp', when='+openmp')
depends_on('netcdf-fortran', when='+hdf5')
depends_on('hdf5+mpi', when='+mpi+hdf5') # required for NetCDF-4 support
# pin libxc version
depends_on("libxc@2.2.1")
depends_on("libxc@2.2.2")
def validate(self, spec):
"""
Checks if incompatible variants have been activated at the same time
# Cannot ask for +scalapack if it does not depend on MPI
conflicts('+scalapack', when='~mpi')
:param spec: spec of the package
:raises RuntimeError: in case of inconsistencies
"""
error = 'you cannot ask for \'+{variant}\' when \'+mpi\' is not active'
# Elpa is a substitute for scalapack and needs mpi
# conflicts('+elpa', when='~mpi')
# conflicts('+elpa', when='+scalapack')
if '+scalapack' in spec and '~mpi' in spec:
raise RuntimeError(error.format(variant='scalapack'))
def configure_args(self):
if '+elpa' in spec and ('~mpi' in spec or '~scalapack' in spec):
raise RuntimeError(error.format(variant='elpa'))
spec = self.spec
def install(self, spec, prefix):
self.validate(spec)
options = ['--prefix=%s' % prefix]
options = []
oapp = options.append
if '+mpi' in spec:
# MPI version:
# let the configure script auto-detect MPI support from mpi_prefix
oapp("--with-mpi-prefix=%s" % spec["mpi"].prefix)
oapp("--enable-mpi=yes")
oapp("--enable-mpi-io=yes")
oapp('--with-mpi-prefix={0}'.format(spec['mpi'].prefix))
oapp('--enable-mpi=yes')
oapp('--enable-mpi-io=yes')
# Activate OpenMP in Abinit Fortran code.
if '+openmp' in spec:
oapp('--enable-openmp=yes')
# BLAS/LAPACK
# BLAS/LAPACK/SCALAPACK-ELPA
linalg = spec['lapack'].libs + spec['blas'].libs
if '+scalapack' in spec:
oapp("--with-linalg-flavor=custom+scalapack")
linalg = (spec['scalapack'].libs +
spec['lapack'].libs + spec['blas'].libs)
oapp('--with-linalg-flavor=custom+scalapack')
linalg = spec['scalapack'].libs + linalg
# elif '+elpa' in spec:
else:
oapp("--with-linalg-flavor=custom")
linalg = spec['lapack'].libs + spec['blas'].libs
oapp('--with-linalg-flavor=custom')
oapp("--with-linalg-libs=%s" % linalg.ld_flags)
oapp('--with-linalg-libs={0}'.format(linalg.ld_flags))
# FFTW3: use sequential or threaded version if +openmp
fftflavor, fftlibs = "fftw3", "-lfftw3 -lfftw3f"
fftflavor, fftlibs = 'fftw3', '-lfftw3 -lfftw3f'
if '+openmp' in spec:
fftflavor = "fftw3-threads"
fftlibs = "-lfftw3_omp -lfftw3 -lfftw3f"
fftflavor = 'fftw3-threads'
fftlibs = '-lfftw3_omp -lfftw3 -lfftw3f'
options.extend([
"--with-fft-flavor=%s" % fftflavor,
"--with-fft-incs=-I%s" % spec["fftw"].prefix.include,
"--with-fft-libs=-L%s %s" % (spec["fftw"].prefix.lib, fftlibs),
'--with-fft-flavor=%s' % fftflavor,
'--with-fft-incs=-I%s' % spec['fftw'].prefix.include,
'--with-fft-libs=-L%s %s' % (spec['fftw'].prefix.lib, fftlibs),
])
oapp("--with-dft-flavor=atompaw+libxc")
oapp('--with-dft-flavor=atompaw+libxc')
# LibXC library
libxc = spec['libxc:fortran']
options.extend([
"with_libxc_incs=-I%s" % spec["libxc"].prefix.include,
"with_libxc_libs=-L%s -lxcf90 -lxc" % spec["libxc"].prefix.lib,
'with_libxc_incs={0}'.format(libxc.cppflags),
'with_libxc_libs={0}'.format(libxc.libs.ld_flags + ' -lm')
])
# Netcdf4/HDF5
if "+hdf5" in spec:
oapp("--with-trio-flavor=netcdf")
if '+hdf5' in spec:
oapp('--with-trio-flavor=netcdf')
# Since version 8, Abinit started to use netcdf4 + hdf5 and we have
# to link with -lhdf5_hl -lhdf5
hdf_libs = "-L%s -lhdf5_hl -lhdf5" % spec["hdf5"].prefix.lib
# to link with the high level HDF5 library
hdf5 = spec['hdf5:hl']
netcdff = spec['netcdf-fortran:shared']
options.extend([
"--with-netcdf-incs=-I%s" % (
spec["netcdf-fortran"].prefix.include),
"--with-netcdf-libs=-L%s -lnetcdff -lnetcdf %s" % (
spec["netcdf-fortran"].prefix.lib, hdf_libs),
'--with-netcdf-incs={0}'.format(netcdff.cppflags),
'--with-netcdf-libs={0}'.format(
netcdff.libs.ld_flags + ' ' + hdf5.libs.ld_flags
),
])
else:
# In Spack we do our best to avoid building any internally provided
# dependencies, such as netcdf3 in this case.
oapp("--with-trio-flavor=none")
oapp('--with-trio-flavor=none')
configure(*options)
make()
return options
# make("check")
# make("tests_in")
make("install")
def check(self):
"""This method is called after the build phase if tests have been
explicitly activated by user.
"""
make('check')
make('tests_in')

View file

@ -70,23 +70,82 @@ class Hdf5(AutotoolsPackage):
depends_on('szip', when='+szip')
depends_on('zlib@1.1.2:')
@run_before('configure')
def validate(self):
"""
Checks if incompatible variants have been activated at the same time
# According to ./configure --help thread-safe capabilities are:
# "Not compatible with the high-level library, Fortran, or C++ wrappers."
# (taken from hdf5@1.10.0patch1)
conflicts('+threadsafe', when='+cxx')
conflicts('+threadsafe', when='+fortran')
:param spec: spec of the package
:raises RuntimeError: in case of inconsistencies
@property
def libs(self):
"""Hdf5 can be queried for the following parameters:
- "hl": high-level interface
- "cxx": C++ APIs
- "fortran": fortran APIs
:return: list of matching libraries
"""
query_parameters = self.spec.last_query.extra_parameters
shared = '+shared' in self.spec
# This map contains a translation from query_parameters
# to the libraries needed
query2libraries = {
tuple(): ['libhdf5'],
('cxx', 'fortran', 'hl'): [
'libhdf5hl_fortran',
'libhdf5_hl_cpp',
'libhdf5_hl',
'libhdf5_fortran',
'libhdf5',
],
('cxx', 'hl'): [
'libhdf5_hl_cpp',
'libhdf5_hl',
'libhdf5',
],
('fortran', 'hl'): [
'libhdf5hl_fortran',
'libhdf5_hl',
'libhdf5_fortran',
'libhdf5',
],
('hl',): [
'libhdf5_hl',
'libhdf5',
],
('cxx', 'fortran'): [
'libhdf5_fortran',
'libhdf5_cpp',
'libhdf5',
],
('cxx',): [
'libhdf5_cpp',
'libhdf5',
],
('fortran',): [
'libhdf5_fortran',
'libhdf5',
]
}
# Turn the query into the appropriate key
key = tuple(sorted(query_parameters))
libraries = query2libraries[key]
return find_libraries(
libraries, root=self.prefix, shared=shared, recurse=True
)
@run_before('configure')
def fortran_check(self):
spec = self.spec
if '+fortran' in spec and not self.compiler.fc:
msg = 'cannot build a fortran variant without a fortran compiler'
raise RuntimeError(msg)
if '+threadsafe' in spec and ('+cxx' in spec or '+fortran' in spec):
msg = 'cannot use variant +threadsafe with either +cxx or +fortran'
raise RuntimeError(msg)
def configure_args(self):
spec = self.spec
# Handle compilation after spec validation
@ -156,11 +215,9 @@ def configure_args(self):
return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args
def configure(self, spec, prefix):
# Run the default autotools package configure
super(Hdf5, self).configure(spec, prefix)
if '@:1.8.14' in spec:
@run_after('configure')
def patch_postdeps(self):
if '@:1.8.14' in self.spec:
# On Ubuntu14, HDF5 1.8.12 (and maybe other versions)
# mysteriously end up with "-l -l" in the postdeps in the
# libtool script. Patch this by removing the spurious -l's.

View file

@ -36,6 +36,33 @@ class Libxc(Package):
version('2.2.2', 'd9f90a0d6e36df6c1312b6422280f2ec')
version('2.2.1', '38dc3a067524baf4f8521d5bb1cd0b8f')
@property
def libs(self):
"""Libxc can be queried for the following parameters:
- "static": returns the static library version of libxc
(by default the shared version is returned)
:return: list of matching libraries
"""
query_parameters = self.spec.last_query.extra_parameters
libraries = ['libxc']
# Libxc installs both shared and static libraries.
# If a client ask for static explicitly then return
# the static libraries
shared = False if 'static' in query_parameters else True
# Libxc has a fortran90 interface: give clients the
# possibility to query for it
if 'fortran' in query_parameters:
libraries = ['libxcf90'] + libraries
return find_libraries(
libraries, root=self.prefix, shared=shared, recurse=True
)
def install(self, spec, prefix):
# Optimizations for the Intel compiler, suggested by CP2K
optflags = '-O2'

View file

@ -35,3 +35,16 @@ class NetcdfFortran(AutotoolsPackage):
version('4.4.3', 'bfd4ae23a34635b273d3eb0d91cbde9e')
depends_on('netcdf')
@property
def libs(self):
libraries = ['libnetcdff']
# This package installs both shared and static libraries. Permit
# clients to query which one they want.
query_parameters = self.spec.last_query.extra_parameters
shared = 'shared' in query_parameters
return find_libraries(
libraries, root=self.prefix, shared=shared, recurse=True
)