Commit 6d75e26f authored by Adam Fekete's avatar Adam Fekete
Browse files

cleanup + stripped pseudo_dojo

parent abcae666
......@@ -45,7 +45,6 @@ LABEL maintainer="Gian-Marco Rignanese <gian-marco.rignanese@uclouvain.be>"
# # 3. mandatory libraries: libhdf5 libnetcdf libnetcdff libpnetcdf libxc libfftw3 libxml2
USER root
WORKDIR /opt/abinit
RUN apt-get update \
&& apt install -y --no-install-recommends \
......@@ -53,48 +52,31 @@ RUN apt-get update \
liblapack3 libblas3 \
libhdf5-103 libnetcdf15 libnetcdff7 libpnetcdf0d libxc5 \
libfftw3-bin libxml2 \
# slurmd slurm-client slurmctld \
&& rm -rf /var/lib/apt/lists/*
USER $NB_UID
COPY --from=builder /opt/abinit .
RUN fix-permissions "/opt/abinit"
COPY --chown=$NB_UID:$NB_GID --from=builder /opt/abinit /opt/abinit
ENV PATH=/opt/abinit/bin:$PATH
USER $NB_UID
# Install Python 3 packages
# =========================
# fireworks's depenecies: flask-paginate gunicorn pymongo
# pseudo_dojo's depenecies:
RUN conda install --quiet --yes \
# 'ase' \
# 'pymatgen' \
# 'atomate' \
# 'matminer' \
# 'jupyterlab-git' \
'abipy' \
'jupyter-server-proxy' \
'jupyter_contrib_nbextensions' \
'jupyter_nbextensions_configurator' \
'flask-paginate' 'gunicorn' 'pymongo' \
'periodic-table-plotter' 'atomicfile' \
&& pip install --no-cache-dir jupyter-jsmol fireworks \
&& conda clean --all -f -y \
&& fix-permissions "${CONDA_DIR}" \
&& fix-permissions "/home/${NB_USER}"
# # Pseudo-dojo
# USER root
# WORKDIR /opt
# RUN git clone --depth 1 https://github.com/abinit/pseudo_dojo.git \
# && cd pseudo_dojo \
# && fix-permissions "/opt/pseudo_dojo"
# USER $NB_UID
# RUN pip install -e pseudo_dojo
ENV PATH=/opt/abinit/bin:$PATH
USER $NB_UID
WORKDIR $HOME
# Pseudo-dojo
COPY --chown=$NB_UID:$NB_GID pseudo_dojo /opt/pseudo_dojo
WORKDIR /opt/pseudo_dojo
RUN pip install -e .
WORKDIR $HOME
\ No newline at end of file
.. The source of this document is INSTALL. During the doc build process,
.. this file is copied over to doc/users/installing.rst.
.. Therefore, you must edit INSTALL, *not* doc/users/installing.rst!
**********
Installing
**********
.. _install_requirements:
Build requirements
==================
These are external packages which you will need to install before installing pseudo_dojo.
:term:`python` 2.7 (or later but not python3)
:term:`numpy` 1.1 (or later)
array support for python
(`download <http://sourceforge.net/project/showfiles.php?group_id=1369&package_id=175103>`__)
:term:`scipy`
:term:`matplotlib`
.. _install_from_source:
Installing from source
======================
Once you have satisfied the requirements detailed above, you can build pseudo_dojo::
cd pseudo_dojo
python setup.py build
python setup.py install
pseudo_dojo is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
pseudo_dojo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with pseudo_dojo.
If not, see <http://www.gnu.org/licenses/>.
PseudoDojo is an open-source Python framework for generating and validating pseudopotentials.
It uses the [AbiPy](https://github.com/abinit/abipy) package, for developing and systematically
testing pseudopotentials.
At present it contains seven different batteries of tests executed with [ABINIT](https://github.com/abinit/abinit)
([delta-gauge](https://molmod.ugent.be/deltacodesdft),
revised delta gauge by [Jollet et al](http://www.sciencedirect.com/science/article/pii/S0010465513004359),
[GBRV](https://www.physics.rutgers.edu/gbrv/) tests for fcc/bcc/compounds,
phonons at the Gamma point and tests for the presence of ghost-states below and above the Fermi level).
The tests are performed as a function of the energy cutoff (with the exception of ghosts and compounds)
and the results are then used to provide hints for the energy cutoff for actual production calculations.
We keep track of the results of the various validation tests for each pseudopotential with the `djrepo` file,
a text document in JSON format produced by the python code at the end of the test.
For further details, please consult our recent [cond-mat paper](https://arxiv.org/abs/1710.10138).
The PseudoDojo code is hosted on [github](https://github.com/abinit/pseudo_dojo)
but we also provide a user web-interface at <http://www.pseudo-dojo.org>
There you will find pseudopotential files that can be used immediately,
as well as the corresponding input files if you need to change or tune or change some parameters
(e.g. the XC functional).
The pseudopotential files are available on the web-site in the ABINIT `psp8` format,
in the `UPF2` format and in the `PSML` 1.1 XML format shared by SIESTA and ABINIT.
The input files, the results of the generation, and the test results are presented via jupyter notebooks
as static HTML pages.
One can hence easily compare pseudopotentials for a given element and then select the most appropriate
one according to a chosen criterion (e.g. efficiency vs accuracy).
How to cite the PseudoDojo project
----------------------------------
If you use the PseudoDojo pseudopotentials in your research,
please consider citing the works mentioned in [this page](http://www.pseudo-dojo.org/faq.html).
Getting PseudoDojo
------------------
Developmental version
---------------------
The developmental version is at the PseudoDojo's `Github repo <https://github.com/gmatteo/pseudo_dojo>`_.
After cloning the source, you can type::
python setup.py install
or, alternatively,
python setup.py develop
to install the package in developmental mode.
<!--
Stable version
==============
The version at the Python Package Index (PyPI) is always the latest stable
release that will be hopefully, be relatively bug-free. The easiest way to
install PseudoDojo is to use pip, as follows::
pip install pseudo_dojo
-->
Project PseudoDojo: global view
===============================
Global long-term objectives:
----------------------------
- To have, on the Web, sets of validated pseudopotentials, for the whole periodic table,
for different exchange-correlation functionals, with different possibilities of
semi-core electrons (e.g. for GW), different cut-off radii (e.g. high pressure application),
with an optimal cut-off energy.
- To have a Web portal for the generation/validation of new pseudopotentials.
- Computation of selected physical properties for selected systems, associated with one
given pseudopotential (automatic computation of the cut-off energy, computation of the
total energy, the interatomic distance, the lattice parameter of the elemental solid
and one oxide, also dimer). Results presented on the Web.
- Validation of pseudopotentials with respect to a reference.
License
=======
The pseudopotential files as well as the input files are released under the
[CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0/legalcode)
This license lets you distribute, remix, tweak, and build upon our work, even commercially,
as long as you credit the PseudoDojo project for the original creation.
The PseudoDojo code (the python code used to generate/validate the pseudos)
is released under the GPL License.
The terms of the license are as follows:
PseudoDojo is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
PseudoDojo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with PseudoDojo.
If not, see <http://www.gnu.org/licenses/>.
from __future__ import division, print_function, unicode_literals
import os
from collections import OrderedDict
from collections import abc
from monty.dev import deprecated
from monty.functools import lazy_property
from monty.design_patterns import singleton
#from pymatgen.core.periodic_table import Element
from pseudo_dojo.core.pseudos import OfficialDojoTable
from pseudo_dojo.pseudos import dojotable_absdir
@deprecated(message="Official PseudoDojo API will be released soon!")
def get_pseudos(top):
"""
Find pseudos within top, return :class:`PseudoTable` object sorted by atomic number Z.
"""
from monty.os.path import find_exts
from pymatgen.io.abinit.pseudos import PseudoTable, Pseudo
exts = ("psp8",)
pseudos = []
for p in find_exts(top, exts, exclude_dirs="_*"):
try:
pseudos.append(Pseudo.from_file(p))
except Exception as exc:
from warnings import warn
warn("Exception in pseudo %s:\n%s" % (p.filepath, exc))
return PseudoTable(pseudos).sort_by_z()
class TableMetadata(object):
"""
Metadata associated to one of the official `PseudoDojo` tables.
"""
def __init__(self, table_dir, djson_name):
"""
Args:
table_dir: basename of the directory containing the pseudos
djson_name: name of the json file in `table_dir` with the
list of pseudos and metatada.
"""
self.table_dir = table_dir
self.dojo_absdir = dojotable_absdir(table_dir)
self.djson_name = djson_name
self.djson_path = os.path.join(self.dojo_absdir, djson_name)
@singleton
class OfficialTables(abc.Mapping):
"""
Official tables provided by the PseudoDojo project.
Naming scheme:
[PP_TYPE]-[XC_NAME]-[TABLE_NAME_WITH_VERSION]-[DJSON_NAME]
where:
#. PP_TYPE in ("PAW", "NC") defines the pseudos type.
#. XC_NAME defines the exchange-correlation functional e.g. PBE
#. TABLE_NAME_WITH_VERSION is the name of the table e.g. ONCVPSP, JTH ...
#. DJSON_NAME is the name of the djson file located in the pseudodojo directory.
In the case of NC pseudos, the SOC term is treated via djson e.g. "accuracy-soc.djson".
maybe FR|SR for fully or scalar-relativistic?
"""
def __init__(self):
self._tables = tables = OrderedDict()
#tables["ONCVPSP-PBE-PDv0.2-accuracy"] = TableMetadata("ONCVPSP-PBE-PDv0.2", "test_accuracy.djson")
tables["ONCVPSP-PBE-PDv0.2-accuracy"] = TableMetadata("ONCVPSP-PBE-PDv0.3", "standard.djson")
#tables["ONCV-GYGYv0.2-PBE"] = TableMetadata("ONC-PBE-GYGYv0.2", "htc.djson")
#tables["PAW-JTHv0.2-PBE"] = TableMetadata("PAW-PBE-JTHv0.2", "standard.djson")
#tables["PAW-PBE-GBRVv0.2"] = TableMetadata("PAW-PBE-GBRVv0.2", "efficiency.djson")
# TODO: Add check on md5 of djson files.
# ABC protocol.
def __iter__(self):
return self._tables.__iter__()
def __len__(self):
return self._tables.__len__()
def __getitem__(self, key):
"""Called by self[key]"""
v = self._tables[key]
# Return v if v is table else parse the files, construct table and store it.
if not isinstance(v, TableMetadata):
return v
new_table = OfficialDojoTable.from_djson_file(v.djson_path)
new_table.dojo_name = key
self._tables[key] = new_table
return new_table
def select_tables(self, pp_type=None, xc=None):
"""
Low-level method used to select tables.
Args:
pp_type: NC for norm-conserving pseudos or PAW. If None no selection is done.
xc: If xc is not None, only the pseudos with this xc functional are selected.
else no selection is performed.
Return:
List of tables.
"""
tables = self.values()
if pp_type is not None:
tables = [t for t in tables if t.dojo_info.pp_type == pp_type]
if xc is not None:
tables = [t for t in tables if t.dojo_info.xc == xc]
return tables
@lazy_property
def available_xcs(self):
"""List with the XC functionals available."""
return sorted(set(t.xc for t in self.values()))
def all_nctables(self, xc=None):
"""
Return all norm-conserving tables available.
If xc is not None, only the pseudos with this xc functional are selected.
"""
tables = [t for t in self.values() if t.dojo_info.isnc]
if xc is not None:
tables = [t for t in tables if t.xc == xc]
return tables
def all_pawtables(self, xc=None):
"""
Return all PAW tables available.
If xc is not None, only the pseudos with this xc functional are selected.
"""
tables = [table for table in self.values() if table.dojo_info.ispaw]
if xc is not None:
tables = [t for t in tables if t.xc == xc]
return tables
def pseudo_from_symbol_md5(self, symbol, md5, pp_type, xc):
"""
Find pseudo from chemical symbol, md5 checksum, pp_type and xc.
Raises:
ValueError if pseudo is not found.
"""
# This is the __eq__ implemented for Pseudo
#return (self.md5 == other.md5 and
# self.__class__ == other.__class__ and
# self.Z == other.Z and
# self.Z_val == other.Z_val and
# self.l_max == other.l_max )
# Here it's very important the we don't have duplicated md5 in the pseudo dojo tables.
# Actually there's a check in test/test_dojotables.py
for p in self.select_pseudos(symbol, pp_type=pp_type, xc=xc):
if p.md5 == md5: return p
raise ValueError(
"Cannot find pseudo associated to the following parameters:\n"
"symbol=%s, md5=%s, pp_type=%s, xc=%s" % (symbol, md5, pp_type, xc))
def select_pseudos(self, symbol, pp_type=None, xc=None):
"""
Return the full list of Pseudo objects available in the DojoTables
with the given `pp_type` and XC functional `xc`.
"""
tables = self.select_tables(pp_type=pp_type, xc=xc)
pseudos = []
for tab in tables:
pseudos.extend(tab.pseudo_with_symbol(symbol, allow_multi=True))
return pseudos
def select_nc_pseudos(self, symbol, xc=None):
"""
Return list of NC pseudos with the given chemical `symbol`.
If xc is not None, only the pseudos with this xc functional are selected.
"""
return self.select_pseudos(symbol, pp_type="NC", xc=xc)
def select_paw_pseudos(self, symbol, xc=None):
"""
Return list of PAW pseudos with the given chemical `symbol`.
If xc is not None, only the pseudos with this xc are selected.
"""
return self.select_pseudos(symbol, pp_type="PAW", xc=xc)
#def plot_numpseudos(self, **kwargs):
# """Plot periodic table with the number of pseudos available per element."""
# import matplotlib.pyplot as plt
# from ptplotter.plotter import ElementDataPlotter
# symbols, data, max_num = [], {}, 0
# for el in Element:
# pseudos = self.select_pseudos(el.symbol, pp_type=None, xc=None)
# symbols.append(el.symbol)
# max_num = max(max_num, len(pseudos))
# data[el.symbol] = {"num_pseudos": len(pseudos)}
# def count_pseudos(elt):
# """Pseudos available"""
# return elt.get('num_pseudos', 0)
# epd = ElementDataPlotter(elements=symbols, data=data)
# #epd.ptable(functions=[count_pseudos], cmaps=["jet"], )
# #epd.cmaps[0].set_clim([0, max_num])
# #epd.redraw_ptable()
# plt.show()
def logo1():
return """\
````````````````````````````````````````````````````````````````````````````````````````````````````
```````````````-shyo.```````````````````````````````````````````````````````````````````````````````
``````````-/oo`+hhhh-:s+/.````````````-:::::::-.````````````````````````````````````````-:::::.`````
```````.+ss/-.``-//-``.:+ys/.`````````yhhooooyhy+``......```.......`..````..``......````/oooo+-`````
`````.+yo-````````````````:sy:````````yhh`````shh.+ysooss+`+ysoooo+.yy````yy.:yyoooso-`/sso+oyo-````
````.sy-````````````````````/h+```````yhh::::/yhs.oyo+///:`+hs////..hh.```hh.:hs```-hy-hh.```/hs````
````sy-```````-------.```````/h/``````yhhooooo+:.`//::/ohy.+ho::::.`yh-..-hh.:hs...:hy.yh-``.+ho````
``-shysssssss+yhhhhhhosssssssshhs`````oss`````````/soooos+`/ssoooo+`-oooooo:`:ssoooo+.`-osooos+.````
``-hhhhhhhhhhshhhhhhhshhhhhhhhhhy`````````````````````````````````````````````````````````...```````
``-hhhhhhhhhhshhhhhhhshhhhhhhhhhy`````://////:-.```.//////`````````.////+/``````````````````````````
```-yy-------.+++++++:-------:hs-`````yhh++++shy+``.+ooo+/`````--``.+ooo+/``````````````````````````
````:ho`````````````````````.yy.``````yhh`````ohh--sy+//oy+````yh.-sy+//oyo`````````````````````````
`````-ys-``````````````````/yo.```````yhh`````+hh:sh/````yh-```yh-oh/````yh:````````````````````````
``````./ys/.````````````-/ys:`````````yhh:::/+hho`+ho.``:hh-..-hh.+ho.``-hh.````````````````````````
`````````:+sso/::-::/+oys+-```````````+oooooo+/-```:+oooo/.:ooo+-``:+oooo+.`````````````````````````
````````````.-//++++/:-````````````````````````````````````````````````````.```````````````.````````
"""
def logo2():
return """\
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMd/--+NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMNdyo+No----dh+oymNMMMMMMMMMMMdhhhhhhhdNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdhhhhhNMMMMM
MMMMMMMms//ydNMMdyymMMmhs/+yNMMMMMMMMM/--++++/--sMMNNNNNNMMNNNNNNNNMNNMMMMNNMMNNNNNNMMMMyoo+oodMMMMM
MMMMMNs:omMMMMMMMMMMMMMMMNh/:hMMMMMMMM/--MMMMM/--mo:+oo+/sMs-/oooooN::NMMN:-Nh-:o++/+dMy//oo+/+mMMMM
MMMMN/:dMMMMMMMMMMMMMMMMMMMNy-sMMMMMMM/--hhhhs--/No:+osyyhMo-/yyyyNN--NMMN--Nh-/MMMd-:m--NMMMy-/MMMM
MMMN/-mNNNNNNMmmmmmmmmNNNNNNNy-yNMMMMM/--+++++ohNMyyhhyo-:No-+hhhhmN--dNNm--Nh-/NNNh-/m--dNMNs-+MMMM
MMm/--///////s-------+////////--+MMMMMo//MMMMMMMMMy++ooo/sNy/+oooooMd++oo++dMd//oo++smMdo+oo++sNMMMM
MMd----------+-------+-----------MMMMMMNMMMMMMMMMMMMNNNNMMMMNNNNNNNMMMNNNNMMMMNNNNMMMMMMMNNNNMMMMMMM
MMd----------+-------+-----------MMMMMhsssssyhdNMMMmsssssyMMMMMMMMMNsssssyMMMMMMMMMMMMMMMMMMMMMMMMMM
MMNd-:dmmmmmmmssssssshmmmmmmmh-+mMMMMM/--ssso/-:sMMmsooooyMMMMMmdMMNsooooyMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMh-oNMMMMMMMMMMMMMMMMMMMMm/:NMMMMMM/--MMMMNo--dd/:syy+:oMMMM:-md/:syy+:oNMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMd:/dMMMMMMMMMMMMMMMMMNy:+NMMMMMMM/--MMMMMs--h+-yMMMN:-dMMM--m+-yMMMM/-dMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMNy:/yNMMMMMMMMMMMMms:/hMMMMMMMMM/--hhhyo--+Ns-+mMNd--mmNd--Ns-+mMNd--mMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMNho//oyhhddhys+:/smMMMMMMMMMMMs+++++ooymMMMho+++osmhooosmMMho+++osmMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMNdyssossyhmNMMMMMMMMMMMMMMNMMMMNMMMMMMMMNMMMMMMMMMMMMMMMMMNMMMMNMMMMMMMMMMMMMMMNMMMMMMMM
"""
# flake8: noqa
from .testing import *
from .atom import *
from abipy.flowtk.tasks import TaskManager
from abipy.flowtk.pseudos import PseudoParser, PseudoTable
# coding: utf-8
"""This module provides objects and helper functions for atomic calculations."""
import collections
import numpy as np
from io import StringIO
from pseudo_dojo.refdata.nist import database as nist_database
from scipy.interpolate import UnivariateSpline
from scipy.integrate import cumtrapz
__version__ = "0.1"
__author__ = "Matteo Giantomassi"
__maintainer__ = "Matteo Giantomassi"
__all__ = [
"NlkState",
"QState",
"AtomicConfiguration",
"RadialFunction",
"RadialWaveFunction",
"plot_aepp",
"plot_logders",
]
# Helper functions
_char2l = {
"s": 0,
"p": 1,
"d": 2,
"f": 3,
"g": 4,
"h": 5,
"i": 6,
}
def _asl(obj):
try:
return _char2l[obj]
except KeyError:
return int(obj)
def states_from_string(confstr):
"""
Parse a string with an atomic configuration and build a list of `QState` instance.
"""
states = []
tokens = confstr.split()
if tokens[0].startswith("["):
noble_gas = AtomicConfiguration.neutral_from_symbol(tokens.pop(0)[1:-1])
states = noble_gas.states
states.extend(parse_orbtoken(t) for t in tokens)
return states
def parse_orbtoken(orbtoken):
import re
m = re.match(r"(\d+)([spdfghi]+)(\d+)", orbtoken.strip())
if m:
return QState(n=m.group(1), l=m.group(2), occ=m.group(3))
raise ValueError("Don't know how to interpret %s" % str(orbtoken))
class NlkState(collections.namedtuple("NlkState", "n, l, k")):
"""
Named tuple storing (n,l) or (n,l,k) for relativistic pseudos.
"""
def __str__(self):
if self.k is None:
return "n=%i, l=%i" % (self.n, self.l)
else:
return "n=%i, l=%i, k=%i" % self
@property
def to_dict(self):
return {"n": self.n, "l": self.l, "k": self.k}
class QState(collections.namedtuple("QState", "n, l, occ, eig, j, s")):
"""
This object collects the set of quantum numbers and the physical properties
associated to a single electron in a spherically symmetric atom.
.. attributes:
n: Principal quantum number.
l: Angular momentum.
occ: Occupancy of the atomic orbital.
eig: Eigenvalue of the atomic orbital.
j: J quantum number. None if spin is a good quantum number.
s: Spin polarization. None if spin is not taken into account.
"""
# TODO
# Spin +1, -1 or 1,2 or 0,1?
def __new__(cls, n, l, occ, eig=None, j=None, s=None):
"""Intercepts super.__new__ adding type conversion and default values."""
eig = float(eig) if eig is not None else eig
j = int(j) if j is not None else j
s = int(s) if s is not None else s
return super(QState, cls).__new__(cls, int(n), _asl(l), float(occ), eig=eig, j=j, s=s)
# Rich comparison support.
# Note that the ordering is based on the quantum numbers and not on energies!
#def __gt__(self, other):
# if self.has_j:
# raise NotImplementedError("")
# if self.n != other.n: return self.n > other.n
# if self.l != other.l
# if self == other:
# return False
# else:
# raise RuntimeError("Don't know how to compare %s with %s" % (self, other))
#def __lt__(self, other):
@property
def has_j(self):
return self.j is not None
@property
def has_s(self):