From a81ca465315eb811ae8ec3c0513b733b36980e9a Mon Sep 17 00:00:00 2001 From: gmatteo Date: Tue, 24 May 2016 16:38:49 +0200 Subject: [PATCH] More tests, fix treatment of in deltafactor API --- docs/index.rst | 1 - pseudo_dojo/core/dojoreport.py | 41 ++++- pseudo_dojo/data/__init__.py | 4 + pseudo_dojo/ppcodes/oncvpsp.py | 3 +- pseudo_dojo/ppcodes/tests/test_oncvpsp.py | 1 + pseudo_dojo/pseudos/__init__.py | 169 +---------------- pseudo_dojo/refdata/deltafactor/database.py | 24 ++- .../deltafactor/tests/test_deltafactor.py | 31 +++- pseudo_dojo/scripts/dojodata.py | 2 +- pseudo_dojo/util/notebook.py | 170 ++++++++++++++++++ pseudo_dojo/util/tests/__init__.py | 0 pseudo_dojo/util/tests/test_notebook.py | 19 ++ 12 files changed, 280 insertions(+), 185 deletions(-) create mode 100644 pseudo_dojo/util/notebook.py create mode 100644 pseudo_dojo/util/tests/__init__.py create mode 100644 pseudo_dojo/util/tests/test_notebook.py diff --git a/docs/index.rst b/docs/index.rst index 30bbd669..16e5cb2f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,6 @@ Contents: :maxdepth: 2 - Indices and tables ================== diff --git a/pseudo_dojo/core/dojoreport.py b/pseudo_dojo/core/dojoreport.py index ebcbd93a..d1c8bde3 100644 --- a/pseudo_dojo/core/dojoreport.py +++ b/pseudo_dojo/core/dojoreport.py @@ -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__) @@ -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 diff --git a/pseudo_dojo/data/__init__.py b/pseudo_dojo/data/__init__.py index 88086837..f7f20e4f 100644 --- a/pseudo_dojo/data/__init__.py +++ b/pseudo_dojo/data/__init__.py @@ -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.""" diff --git a/pseudo_dojo/ppcodes/oncvpsp.py b/pseudo_dojo/ppcodes/oncvpsp.py index 851f8b73..608a63d0 100644 --- a/pseudo_dojo/ppcodes/oncvpsp.py +++ b/pseudo_dojo/ppcodes/oncvpsp.py @@ -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 diff --git a/pseudo_dojo/ppcodes/tests/test_oncvpsp.py b/pseudo_dojo/ppcodes/tests/test_oncvpsp.py index f009886b..80e0b47d 100644 --- a/pseudo_dojo/ppcodes/tests/test_oncvpsp.py +++ b/pseudo_dojo/ppcodes/tests/test_oncvpsp.py @@ -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) diff --git a/pseudo_dojo/pseudos/__init__.py b/pseudo_dojo/pseudos/__init__.py index 193ecbcf..6c9dc76c 100644 --- a/pseudo_dojo/pseudos/__init__.py +++ b/pseudo_dojo/pseudos/__init__.py @@ -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 @@ -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`") - diff --git a/pseudo_dojo/refdata/deltafactor/database.py b/pseudo_dojo/refdata/deltafactor/database.py index 37df254c..9b4fba40 100644 --- a/pseudo_dojo/refdata/deltafactor/database.py +++ b/pseudo_dojo/refdata/deltafactor/database.py @@ -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 @@ -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"], } @@ -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 = {} @@ -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. @@ -190,9 +201,11 @@ 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: @@ -200,11 +213,10 @@ def get_entry(self, symbol, code=None): @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 diff --git a/pseudo_dojo/refdata/deltafactor/tests/test_deltafactor.py b/pseudo_dojo/refdata/deltafactor/tests/test_deltafactor.py index 83f21cf8..b0df9c77 100644 --- a/pseudo_dojo/refdata/deltafactor/tests/test_deltafactor.py +++ b/pseudo_dojo/refdata/deltafactor/tests/test_deltafactor.py @@ -1,8 +1,14 @@ from __future__ import print_function, division +import unittest2 as unittest + from pseudo_dojo.core import PseudoDojoTest -from pseudo_dojo.refdata.deltafactor import df_database, df_compute +from pseudo_dojo.refdata.deltafactor.database import df_database, df_compute, read_tables_from_file +try: + import matplotlib +except ImportError: + matplotlib = None class DeltaFactorDatabaseTest(PseudoDojoTest): @@ -11,18 +17,20 @@ def setUp(self): self.pbe_db.xc == "PBE" # Cached? self.assertTrue(df_database() is self.pbe_db) + assert "WIEN2k" in self.pbe_db.codes + assert "VASP" in self.pbe_db.codes self.pw_db = df_database("PW") assert self.pw_db.xc == "PW" assert self.pw_db is not self.pbe_db + assert "WIEN2k" in self.pw_db.codes def test_get_entry(self): """Get deltafactor entry.""" # PBE assert "Si" in self.pbe_db.symbols - # FIXME - #assert self.pbe_db.has_symbol("Si") - #assert not self.pbe_db.has_symbol("Foo") + assert self.pbe_db.has_symbol("Si") + assert not self.pbe_db.has_symbol("Foo") e = self.pbe_db.get_entry("Si") assert e.xc == self.pbe_db.xc == "PBE" @@ -30,6 +38,9 @@ def test_get_entry(self): e = self.pbe_db.get_entry("Si", code="VASP") self.assert_almost_equal([e.v0, e.b0_GPa, e.b1], [20.446, 88.790, 4.296]) + with self.assertRaises(self.pbe_db.Error): + self.pbe_db.get_entry("Dy") + # LDA-PW e = self.pw_db.get_entry("Si") assert e.xc == self.pw_db.xc == "PW" @@ -55,6 +66,12 @@ def test_compute_deltaf(self): same_df = df_compute(wien2k.v0, wien2k.b0, wien2k.b1, vasp.v0, vasp.b0, vasp.b1, b0_GPa=False) self.assert_almost_equal(df, same_df, decimal=2) - #def test_plot(self): - # """Test plot_error_of_code.""" - # self.pbe_db.plot_error_of_code("VASP", show=False) + @unittest.skipIf(matplotlib is None, "Requires matplotlib") + def test_plot(self): + """Test plot_error_of_code.""" + self.pbe_db.plot_error_of_code("VASP", show=False) + + #def test_read_tables_from_file(filepath): + # for xc, files in DeltaFactorDatabase._FILES4XC.items(): + # for f in files: + # frame = read_tables_from_ diff --git a/pseudo_dojo/scripts/dojodata.py b/pseudo_dojo/scripts/dojodata.py index 0f4868ee..dc411b70 100755 --- a/pseudo_dojo/scripts/dojodata.py +++ b/pseudo_dojo/scripts/dojodata.py @@ -343,7 +343,7 @@ def dojo_notebook(options): """ Generate an ipython notebook for each pseudopotential and open it in the browser. """ - from pseudo_dojo.pseudos import make_open_notebook + from pseudo_dojo.util.notebook import make_open_notebook retcode = 0 for p in options.pseudos: retcode += make_open_notebook(p.filepath) diff --git a/pseudo_dojo/util/notebook.py b/pseudo_dojo/util/notebook.py new file mode 100644 index 00000000..65b3fc9e --- /dev/null +++ b/pseudo_dojo/util/notebook.py @@ -0,0 +1,170 @@ +"""Tools to produce jupyter notebooks """ +from __future__ import print_function, division, unicode_literals + +import os + +from monty.os.path import which + +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 + """ + + 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`") diff --git a/pseudo_dojo/util/tests/__init__.py b/pseudo_dojo/util/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pseudo_dojo/util/tests/test_notebook.py b/pseudo_dojo/util/tests/test_notebook.py new file mode 100644 index 00000000..9f79b35e --- /dev/null +++ b/pseudo_dojo/util/tests/test_notebook.py @@ -0,0 +1,19 @@ +"""Unit tests for jupyter tools.""" +from __future__ import unicode_literals, division, print_function + +import os +import pseudo_dojo.data as pdj_data + +from pseudo_dojo.core.testing import PseudoDojoTest +from pseudo_dojo.util.notebook import write_notebook + + +class DojoNotebookTestCase(PseudoDojoTest): + + def test_write_notebook(self): + """Testing write_notebook function.""" + nbpath = write_notebook(pdj_data.pseudopath("Si.GGA_PBE-JTH-paw.xml"), with_eos=True, tmpfile=True) + assert os.path.exists(nbpath) + + nbpath = write_notebook(pdj_data.pseudopath("Si.psp8"), with_eos=False, tmpfile=True) + assert os.path.exists(nbpath)