Skip to content

Commit

Permalink
More tests, fix treatment of in deltafactor API
Browse files Browse the repository at this point in the history
  • Loading branch information
gmatteo committed May 24, 2016
1 parent 30f32c2 commit a81ca46
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 185 deletions.
1 change: 0 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Contents:
:maxdepth: 2



Indices and tables
==================

Expand Down
41 changes: 40 additions & 1 deletion pseudo_dojo/core/dojoreport.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from monty.string import list_strings, is_string
from pymatgen.analysis.eos import EOS
from pymatgen.core.periodic_table import Element
#from pymatgen.core.xcfunc import XcFunc
from pymatgen.util.plotting_utils import add_fig_kwargs, get_ax_fig_plt

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -783,3 +782,43 @@ def plot_trials(self, trials="all", accuracies="all", **kwargs):
plt.setp(ax.xaxis.get_majorticklabels(), rotation=25)

return fig


class DojoReportContext(object):
"""
Context manager to update the values in the DojoReport
Example::
with DojoReportContext(pseudo) as report:
dojo_ecut = '%.1f' % ecut
report[dojo_trial][dojo_ecut] = new_entry
In pseudo code, this is equivalent to
read_dojo_report_from_pseudo
update_report
write__new_report_with_file_locking
update_report_inpseudo
"""
def __init__(self, pseudo):
self.pseudo = pseudo

def __enter__(self):
self.report = self.pseudo.read_dojo_report()
return self.report

def __exit__(self, exc_type, exc_value, traceback):
# Return immediately if exception was raised inside the with block.
if any(a is None for a in (exc_type, exc_value, traceback)):
return False

try:
# Write new dojo_report
self.pseudo.write_dojo_report(report=self.report)
# Update the report in the pseudo.
self.pseudo.report = self.report
return True
except Exception as exc:
logger.critical(exc)
return False
4 changes: 4 additions & 0 deletions pseudo_dojo/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

dirpath = os.path.dirname(__file__)

def pseudopath(filename):
"""Returns the absolute pathname of a pseudo."""
return os.path.join(dirpath, filename)


def pseudo(filename):
"""Returns a `Pseudo` object."""
Expand Down
3 changes: 2 additions & 1 deletion pseudo_dojo/ppcodes/oncvpsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ def plot_der_potentials(self, ax=None, order=1, **kwargs):
else:
legends.append("$s-order derivative PS l=%s" % str(l))

decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \phi(r)$" % order, title="Derivative of the ion Pseudopotentials",
decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \phi(r)$" % order,
title="Derivative of the ion Pseudopotentials",
lines=lines, legends=legends)
return fig

Expand Down
1 change: 1 addition & 0 deletions pseudo_dojo/ppcodes/tests/test_oncvpsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pseudo_dojo.core import PseudoDojoTest
from pseudo_dojo.ppcodes.oncvpsp import OncvOutputParser


def filepath(basename):
return os.path.join(os.path.dirname(__file__), basename)

Expand Down
169 changes: 1 addition & 168 deletions pseudo_dojo/pseudos/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""
Functions providing access to file data.
Mainly used to build the public APIs and write unit tests.
Functions providing access to file data. Mainly used to build the public APIs and write unit tests.
"""
from __future__ import print_function, division, unicode_literals

Expand All @@ -26,169 +25,3 @@ def dojotable_absdir(basedir):
"Change pseudo_dojo/pseudos/__init__.py" % basedir)

return os.path.join(here, basedir)


def write_notebook(pseudopath, with_eos=False, tmpfile=None):
"""
Read a pseudopotential file and write an ipython notebook.
By default, the notebook is created in the same directory
as pseudopath but with the extension `ipynb` unless `tmpfile` is set to True.
In the later case, a temporay file is created.
Args:
pseudopath: Path to the pseudopotential file.
with_eos: True if EOS plots are wanted.
Returns:
The path to the ipython notebook.
See http://nbviewer.ipython.org/gist/fperez/9716279
"""
try:
# Here we have a deprecation warning but the API of v4 is different!
from nbformat import current as nbf
#import nbformat.v3 as nbf
except ImportError:
from IPython.nbformat import current as nbf

nb = nbf.new_notebook()

cells = [
nbf.new_heading_cell("This is an auto-generated notebook for %s" % os.path.basename(pseudopath)),
nbf.new_code_cell("""\
from __future__ import print_function, division, unicode_literals
%matplotlib inline
import mpld3
from mpld3 import plugins as plugs
plugs.DEFAULT_PLUGINS = [plugs.Reset(), plugs.Zoom(), plugs.BoxZoom(), plugs.MousePosition()]
mpld3.enable_notebook()
import seaborn as sns
#sns.set(style="dark", palette="Set2")
sns.set(style='ticks', palette='Set2')"""),

nbf.new_code_cell("""\
# Construct the pseudo object and get the DojoReport
from pseudo_dojo.core.pseudos import dojopseudo_from_file
pseudo = dojopseudo_from_file('%s')
report = pseudo.dojo_report""" % os.path.abspath(pseudopath)),

nbf.new_heading_cell("ONCVPSP Input File:"),
nbf.new_code_cell("""\
input_file = pseudo.filepath.replace(".psp8", ".in")
%cat $input_file"""),

nbf.new_code_cell("""\
# Get data from the output file
from pseudo_dojo.ppcodes.oncvpsp import OncvOutputParser, PseudoGenDataPlotter
onc_parser = OncvOutputParser(pseudo.filepath.replace(".psp8", ".out"))
# Parse the file and build the plotter
onc_parser.scan()
plotter = onc_parser.make_plotter()"""),

nbf.new_heading_cell("AE and PS radial wavefunctions $\phi(r)$:"),
nbf.new_code_cell("fig = plotter.plot_radial_wfs(show=False)"),

nbf.new_heading_cell("Arctan of the logarithmic derivatives:"),
nbf.new_code_cell("fig = plotter.plot_atan_logders(show=False)"),

nbf.new_heading_cell("Convergence in $G$-space estimated by ONCVPSP:"),
nbf.new_code_cell("fig = plotter.plot_ene_vs_ecut(show=False)"),

nbf.new_heading_cell("Projectors:"),
nbf.new_code_cell("fig = plotter.plot_projectors(show=False)"),

nbf.new_heading_cell("Core-Valence-Model charge densities:"),
nbf.new_code_cell("fig = plotter.plot_densities(show=False)"),

nbf.new_heading_cell("Local potential and $l$-dependent potentials:"),
nbf.new_code_cell("fig = plotter.plot_potentials(show=False)"),

#nbf.new_heading_cell("1-st order derivative of $v_l$ and $v_{loc}$ computed via finite differences:"),
#nbf.new_code_cell("""fig = plotter.plot_der_potentials(order=1, show=False)"""),
#nbf.new_heading_cell("2-nd order derivative of $v_l$ and $v_{loc}$ computed via finite differences:"),
#nbf.new_code_cell("""fig = plotter.plot_der_potentials(order=2, show=False)"""),

nbf.new_heading_cell("Model core charge and form factors computed by ABINIT"),
nbf.new_code_cell("""\
with pseudo.open_pspsfile() as psps:
psps.plot()"""),

nbf.new_heading_cell("Convergence of the total energy:"),
nbf.new_code_cell("""\
# Convergence of the total energy (computed from the deltafactor runs with Wien2K equilibrium volume)
fig = report.plot_etotal_vs_ecut(show=False)"""),

nbf.new_heading_cell("Convergence of the deltafactor results:"),
nbf.new_code_cell("""fig = report.plot_deltafactor_convergence(xc=pseudo.xc, what=("dfact_meV", "dfactprime_meV"), show=False)"""),

nbf.new_heading_cell("Convergence of $\Delta v_0$, $\Delta b_0$, and $\Delta b_1$ (deltafactor tests)"),
nbf.new_code_cell("""\
# Here we plot the difference wrt Wien2k results.
fig = report.plot_deltafactor_convergence(xc=pseudo.xc, what=("-dfact_meV", "-dfactprime_meV"), show=False)"""),

nbf.new_heading_cell("deltafactor EOS for the different cutoff energies:"),
nbf.new_code_cell("fig = report.plot_deltafactor_eos(show=False)"),

nbf.new_heading_cell("Convergence of the GBRV lattice parameters:"),
nbf.new_code_cell("fig = report.plot_gbrv_convergence(show=False)"),

nbf.new_heading_cell("Convergence of phonon frequencies at $\Gamma$:"),
nbf.new_code_cell("fig = report.plot_phonon_convergence(show=False)"),

#nbf.new_heading_cell("Comparison with the other pseudos in this table"),
#nbf.new_code_cell("""\
#from pseudo_dojo import get_pseudos
#pseudos = get_pseudos(".")
#if len(pseudos) > 1:
# pseudos.dojo_compare()"""),
]

if with_eos:
# Add EOS plots
cells.extend([
nbf.new_heading_cell("GBRV EOS for the FCC structure:"),
nbf.new_code_cell("""fig = report.plot_gbrv_eos(struct_type="fcc", show=False)"""),

nbf.new_heading_cell("GBRV EOS for the BCC structure:"),
nbf.new_code_cell("""fig = report.plot_gbrv_eos(struct_type="bcc", show=False)"""),
])

# Now that we have the cells, we can make a worksheet with them and add it to the notebook:
nb['worksheets'].append(nbf.new_worksheet(cells=cells))

# Next, we write it to a file on disk that we can then open as a new notebook.
# Note: This should be as easy as: nbf.write(nb, fname), but the current api is
# a little more verbose and needs a real file-like object.
if tmpfile is None:
root, ext = os.path.splitext(pseudopath)
nbpath = root + '.ipynb'
else:
import tempfile
_, nbpath = tempfile.mkstemp(suffix='.ipynb', text=True)

with open(nbpath, 'wt') as f:
nbf.write(nb, f, 'ipynb')

return nbpath


def make_open_notebook(pseudopath, with_eos=True):
"""
Generate an ipython notebook from the pseudopotential path and
open it in the browser. Return system exit code.
Raise:
RuntimeError if jupyther or ipython are not in $PATH
"""
from monty.os.path import which
path = write_notebook(pseudopath, with_eos=with_eos, tmpfile=True)

if which("jupyter") is not None:
return os.system("jupyter notebook %s" % path)

if which("ipython") is not None:
return os.system("ipython notebook %s" % path)

raise RuntimeError("Cannot find neither jupyther nor ipython. Install them with `pip install`")

24 changes: 18 additions & 6 deletions pseudo_dojo/refdata/deltafactor/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def read_data_from_filepath(filepath, xc):


def read_tables_from_file(filepath):
"""Read deltafactor data from filepath. Returns pandas dataframe."""
import pandas as pd
columns = ["v0", "b0_GPa", "b1", "deltaf"]
title = None
Expand Down Expand Up @@ -133,15 +134,19 @@ class DeltaFactorDatabaseError(Exception):

class DeltaFactorDatabase(object):
"""
This object stores the deltafactor results and
provides methods to access the data.
This object stores the deltafactor results for a given code and XC.
It provides methods to access the data and plot the results.
This object is not meant to instantiated explicitly.
Client code should get the database via the public API:
wien2k_db = df_database(xc="PBE")
"""
# Reference code.
_REF_CODE = "WIEN2k"

# mapping xc_name --> file_list
_FILES4XC = {
"PBE": ["WIEN2k-PBE.txt", "VASP-PBE.txt", "VASP-relaxed-PBE.txt"],
"PBE": ["WIEN2k-PBE.txt", "VASP-PBE.txt"],
"PW": ["WIEN2k-PW.txt"],
}

Expand All @@ -158,6 +163,7 @@ def __init__(self, xc="PBE"):
file_path = os.path.join(self.dirpath, bname)
if os.path.isfile(file_path) and file_path.endswith(".txt"):
code, ext = os.path.splitext(bname)
code = code.split("-")[0]
self._data[code] = read_data_from_filepath(file_path, self.xc)

self._cif_paths = {}
Expand All @@ -182,6 +188,11 @@ def symbols(self):
"""Chemical symbols available in the database."""
return self._cif_paths.keys()

@lazy_property
def codes(self):
"""List of code names e.g. WIEN2k, VASP"""
return list(sorted(self._data.keys()))

def get_entry(self, symbol, code=None):
"""
Return a :class:`DeltaFactorEntry` for the given chemical symbol.
Expand All @@ -190,21 +201,22 @@ def get_entry(self, symbol, code=None):
symbol: Chemical symbol
code: String identifying the code used to compute the entry.
Default is self._REF_CODE (Wien2K)
raise:
self.Error if symbol is not in the database.
"""
if code is None: code = self._REF_CODE
code = code + "-" + str(self.xc)
try:
return self._data[code][symbol]
except KeyError:
raise self.Error("No entry found for code %s, symbol %s" % (code, symbol))

@add_fig_kwargs
def plot_error_of_code(self, codename_or_data, values=("v0", "b0", "b1"), ref_code=None, **kwargs):
"""Plot the error of one code vs ref_code."""
import matplotlib.pyplot as plt

if ref_code is None: ref_code = self._REF_CODE
ref_code = ref_code + "-" + str(self.xc)

ref_data = self._data[ref_code]

data = codename_or_data
Expand Down
Loading

0 comments on commit a81ca46

Please sign in to comment.