Skip to content

Commit

Permalink
Update and test to_LaTeX_table
Browse files Browse the repository at this point in the history
  • Loading branch information
kavanase committed Jan 20, 2025
1 parent c7fa59e commit 1570ba2
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 72 deletions.
47 changes: 33 additions & 14 deletions doped/chemical_potentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from pymatgen.ext.matproj import MPRester
from pymatgen.io.vasp.inputs import Kpoints
from pymatgen.io.vasp.outputs import UnconvergedVASPWarning, Vasprun
from pymatgen.util.string import latexify
from pymatgen.util.string import latexify, latexify_spacegroup
from pymatgen.util.typing import PathLike
from scipy.interpolate import griddata, interp1d
from scipy.spatial import ConvexHull, Delaunay
Expand Down Expand Up @@ -2565,20 +2565,22 @@ def _calculate_extrinsic_chempot_lims(self, extrinsic_elements, chempots_df):
def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
"""
A very simple function to print out the competing phase formation
energies in a LaTeX table format, showing the formula, kpoints (if
present in the parsed data) and formation energy.
energies in a LaTeX table format, showing the formula, space group,
energy above hull, kpoints (if present in the parsed data) and
formation energy.
Needs the mhchem package to work and does `not` use the booktabs package
- change hline to toprule, midrule and bottomrule if you want to use
booktabs style.
Needs the ``mhchem`` package to work and does `not` use the ``booktabs``
package; change ``hline`` to ``toprule``, ``midrule`` and ``bottomrule``
if you want to use ``booktabs`` style.
Args:
splits (int):
Number of splits for the table; either 1 (default) or 2 (with
two large columns, each with the formula, kpoints (if present)
and formation energy (sub-)columns).
prune_polymorphs (bool):
Whether to only print out the lowest energy polymorphs for each composition.
Whether to only print out the lowest energy polymorphs for each
composition.
Default is True.
Returns:
Expand All @@ -2587,8 +2589,9 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
if splits not in [1, 2]:
raise ValueError("`splits` must be either 1 or 2")
# done in the pyscfermi report style
# TODO: Update (now dataframe output)
formation_energy_data = self.get_formation_energy_df(prune_polymorphs).to_dict("records")
form_e_df = self.get_formation_energy_df(prune_polymorphs)
form_e_df["Formula"] = form_e_df.index
formation_energy_data = form_e_df.to_dict(orient="records")

kpoints_col = any("k-points" in item for item in formation_energy_data)

Expand All @@ -2598,13 +2601,17 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
+ self.composition.reduced_formula
+ "} and all competing phases"
+ (", with k-meshes used in calculations." if kpoints_col else ".")
+ (" Only the lowest energy polymorphs are included}\n" if prune_polymorphs else "}\n")
+ (" Only the lowest energy polymorphs are included.}\n" if prune_polymorphs else "}\n")
)
string += "\\label{tab:competing_phase_formation_energies}\n"
column_names_string = "Formula" + (" & k-mesh" if kpoints_col else "") + " & $\\Delta E_f$ (eV/fu)"
column_names_string = (
"Formula & Space Group & E$_{\\textrm{Hull}}$ (eV/atom)"
+ (" & k-mesh" if kpoints_col else "")
+ " & $\\Delta E_f$ (eV/fu)"
)

if splits == 1:
string += "\\begin{tabular}" + ("{ccc}" if kpoints_col else "{cc}") + "\n"
string += "\\begin{tabular}" + ("{ccccc}" if kpoints_col else "{cccc}") + "\n"
string += "\\hline\n"
string += column_names_string + " \\\\ \\hline \n"
for i in formation_energy_data:
Expand All @@ -2614,13 +2621,17 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
"\\ce{"
+ i["Formula"]
+ "}"
+ " & "
+ latexify_spacegroup(i.get("Space Group", "N/A"))
+ " & "
+ f"{i['Energy above Hull (eV/atom)']:.3f}"
+ (f" & {kpoints[0]}$\\times${kpoints[1]}$\\times${kpoints[2]}" if kpoints_col else "")
+ " & "
+ f"{fe:.3f} \\\\ \n"
)

elif splits == 2:
string += "\\begin{tabular}" + ("{ccc|ccc}" if kpoints_col else "{cc|cc}") + "\n"
string += "\\begin{tabular}" + ("{ccccc|ccccc}" if kpoints_col else "{cccc|cccc}") + "\n"
string += "\\hline\n"
string += column_names_string + " & " + column_names_string + " \\\\ \\hline \n"

Expand All @@ -2637,6 +2648,10 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
"\\ce{"
+ i["Formula"]
+ "}"
+ " & "
+ latexify_spacegroup(i.get("Space Group", "N/A"))
+ " & "
+ f"{i['Energy above Hull (eV/atom)']:.3f}"
+ (
f" & {kpoints1[0]}$\\times${kpoints1[1]}$\\times${kpoints1[2]}"
if kpoints_col
Expand All @@ -2647,6 +2662,10 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
+ "\\ce{"
+ j["Formula"]
+ "}"
+ " & "
+ latexify_spacegroup(j.get("Space Group", "N/A"))
+ " & "
+ f"{j['Energy above Hull (eV/atom)']:.3f}"
+ (
f" & {kpoints2[0]}$\\times${kpoints2[1]}$\\times${kpoints2[2]}"
if kpoints_col
Expand All @@ -2660,7 +2679,7 @@ def to_LaTeX_table(self, splits=1, prune_polymorphs=True):
string += "\\end{tabular}\n"
string += "\\end{table}"

return string
print(string)

def plot_chempot_heatmap(
self,
Expand Down
37 changes: 20 additions & 17 deletions examples/chemical_potentials_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -940,8 +940,8 @@
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2025-01-20T19:25:50.784828Z",
"start_time": "2025-01-20T19:25:47.029745Z"
"end_time": "2025-01-20T20:02:54.773008Z",
"start_time": "2025-01-20T20:02:50.914559Z"
}
},
"id": "643890c87cd24d4f",
Expand All @@ -950,11 +950,11 @@
"name": "stderr",
"output_type": "stream",
"text": [
"Parsing vaspruns...: 100%|██████████| 8/8 [00:00<00:00, 91.13it/s]\n"
"Parsing vaspruns...: 100%|██████████| 8/8 [00:00<00:00, 87.36it/s]\n"
]
}
],
"execution_count": 1
"execution_count": 2
},
{
"metadata": {},
Expand Down Expand Up @@ -1708,37 +1708,40 @@
"metadata": {
"collapsed": false,
"ExecuteTime": {
"end_time": "2024-04-10T02:28:18.071044Z",
"start_time": "2024-04-10T02:28:18.057524Z"
"end_time": "2025-01-20T20:02:58.505508Z",
"start_time": "2025-01-20T20:02:58.498220Z"
}
},
"cell_type": "code",
"source": [
"cpa.to_LaTeX_table() # we can then copy and paste this into LaTeX\n",
"# this also comes with `prune_polymorphs` (True by default) and `splits` options, see docstring for info"
],
"id": "cae6d4ecc44dc46c",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\\begin{table}[h]\n",
"\\centering\n",
"\\caption{Formation energies per formula unit ($\\Delta E_f$) of \\ce{ZrO2} and all competing phases, with k-meshes used in calculations. Only the lowest energy polymorphs are included}\n",
"\\caption{Formation energies per formula unit ($\\Delta E_f$) of \\ce{ZrO2} and all competing phases, with k-meshes used in calculations. Only the lowest energy polymorphs are included.}\n",
"\\label{tab:competing_phase_formation_energies}\n",
"\\begin{tabular}{ccc}\n",
"\\begin{tabular}{ccccc}\n",
"\\hline\n",
"Formula & k-mesh & $\\Delta E_f$ (eV/fu) \\\\ \\hline \n",
"\\ce{ZrO2} & 3$\\times$3$\\times$3 & -10.975 \\\\ \n",
"\\ce{O2} & 2$\\times$2$\\times$2 & 0.000 \\\\ \n",
"\\ce{Zr} & 9$\\times$9$\\times$5 & 0.000 \\\\ \n",
"\\ce{Zr2O} & 5$\\times$5$\\times$2 & -5.729 \\\\ \n",
"\\ce{Zr3O} & 5$\\times$5$\\times$5 & -5.987 \\\\ \n",
"Formula & Space Group & E$_{\\textrm{Hull}}$ (eV/atom) & k-mesh & $\\Delta E_f$ (eV/fu) \\\\ \\hline \n",
"\\ce{ZrO2} & P2$_{1}$/c & 0.000 & 3$\\times$3$\\times$3 & -10.975 \\\\ \n",
"\\ce{Zr} & P6$_{3}$/mmc & 0.000 & 9$\\times$9$\\times$5 & 0.000 \\\\ \n",
"\\ce{O2} & P4/mmm & 0.000 & 2$\\times$2$\\times$2 & 0.000 \\\\ \n",
"\\ce{Zr3O} & R$\\overline{3}$c & 0.000 & 5$\\times$5$\\times$5 & -5.987 \\\\ \n",
"\\ce{Zr2O} & P312 & 0.019 & 5$\\times$5$\\times$2 & -5.729 \\\\ \n",
"\\hline\n",
"\\end{tabular}\n",
"\\end{table}\n"
]
}
],
"execution_count": 4,
"source": "cpa.to_LaTeX_table() # we can then copy and paste this into LaTeX",
"id": "cae6d4ecc44dc46c"
"execution_count": 3
},
{
"metadata": {},
Expand Down
67 changes: 26 additions & 41 deletions tests/test_chemical_potentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pymatgen.core.structure import Structure
from test_analysis import if_present_rm
from test_plotting import custom_mpl_image_compare
from test_thermodynamics import _run_func_and_capture_stdout_warnings

from doped import chemical_potentials
from doped.utils.symmetry import get_primitive_structure
Expand Down Expand Up @@ -519,6 +520,7 @@ def test_structure_input(self, api_key):
class ChemPotAnalyzerTestCase(unittest.TestCase):
def setUp(self):
self.EXAMPLE_DIR = os.path.join(cwd, "../examples")
self.DATA_DIR = os.path.join(cwd, "data")
self.stable_system = "ZrO2"
self.unstable_system = "Zr2O"
self.extrinsic_species = "La"
Expand Down Expand Up @@ -547,6 +549,8 @@ def tearDown(self):
for i in ["chempot_limits.csv", "CompetingPhases.csv", "input.dat"]:
if_present_rm(i)

if_present_rm(os.path.join(self.DATA_DIR, "ZrO2_LaTeX_Tables/text.tex"))

def test_cpa_csv(self):
stable_cpa = chemical_potentials.CompetingPhasesAnalyzer(self.stable_system)
stable_cpa.from_csv(self.zro2_csv_path)
Expand Down Expand Up @@ -767,53 +771,34 @@ def test_vaspruns_none_parsed(self):
assert "No vasprun files have been parsed," in str(e.value)

def test_latex_table(self):
cpa = chemical_potentials.CompetingPhasesAnalyzer(self.stable_system)
cpa.from_vaspruns(path=self.zro2_path, subfolder="relax", csv_path=self.zro2_csv_path)
cpa = chemical_potentials.CompetingPhasesAnalyzer(self.stable_system, self.zro2_path)

string = cpa.to_LaTeX_table(splits=1)
assert (
string[28:209]
== "\\caption{Formation energies per formula unit ($\\Delta E_f$) of \\ce{ZrO2} and all "
"competing phases, with k-meshes used in calculations. Only the lowest energy polymorphs "
"are included"
)
assert len(string) == 589
assert string.split("hline")[1] == "\nFormula & k-mesh & $\\Delta E_f$ (eV/fu) \\\\ \\"
assert string.split("hline")[2][2:45] == "\\ce{ZrO2} & 3$\\times$3$\\times$3 & -10.975 \\"
def _test_latex_table(cpa=cpa, ref_filename="default.tex", **kwargs):
out, text, w = _run_func_and_capture_stdout_warnings(cpa.to_LaTeX_table, **kwargs)
assert not out
assert not w

string = cpa.to_LaTeX_table(splits=2)
assert (
string[28:209]
== "\\caption{Formation energies per formula unit ($\\Delta E_f$) of \\ce{ZrO2} and all "
"competing phases, with k-meshes used in calculations. Only the lowest energy polymorphs "
"are included"
)
assert (
string.split("hline")[1]
== "\nFormula & k-mesh & $\\Delta E_f$ (eV/fu) & Formula & k-mesh & $\\Delta E_f$ ("
"eV/fu) \\\\ \\"
)
with open(f"{self.DATA_DIR}/ZrO2_LaTeX_Tables/test.tex", "w+") as f:
f.write(text)

assert string.split("hline")[2][2:45] == "\\ce{ZrO2} & 3$\\times$3$\\times$3 & -10.975 &"
assert len(string) == 586
with (
open(f"{self.DATA_DIR}/ZrO2_LaTeX_Tables/{ref_filename}") as reference_f,
open(f"{self.DATA_DIR}/ZrO2_LaTeX_Tables/test.tex") as test_f,
):
assert reference_f.read() == test_f.read()

# test without kpoints:
for entry_dict in cpa.data:
entry_dict.pop("k-points")
string = cpa.to_LaTeX_table(splits=1)
assert (
string[28:173]
== "\\caption{Formation energies per formula unit ($\\Delta E_f$) of \\ce{ZrO2} and all "
"competing phases. Only the lowest energy polymorphs are included"
)
assert len(string) == 433
assert string.split("hline")[1] == "\nFormula & $\\Delta E_f$ (eV/fu) \\\\ \\"
assert string.split("hline")[2][2:23] == "\\ce{ZrO2} & -10.975 \\"
for kwargs, ref_filename in [
({}, "default.tex"),
({"splits": 2}, "splits_2.tex"),
({"prune_polymorphs": False}, "no_prune.tex"),
]:
_test_latex_table(ref_filename=ref_filename, **kwargs)

la_cpa = chemical_potentials.CompetingPhasesAnalyzer(self.stable_system, self.la_zro2_path)
_test_latex_table(la_cpa, "la_default.tex")

cpa_csv = chemical_potentials.CompetingPhasesAnalyzer(self.stable_system)
cpa_csv.from_csv(self.zro2_csv_path)
with pytest.raises(ValueError):
cpa_csv.to_LaTeX_table(splits=3)
cpa.to_LaTeX_table(splits=3)

def test_to_csv(self):
self.tearDown() # clear out previous csvs
Expand Down

0 comments on commit 1570ba2

Please sign in to comment.