12. Draw the Ca–Ti–O phase diagram¶
The collected store contains the relaxed structure entries, total-energy
records, and product links from page 11. The Run.outputs edges provide the
same honest loose-reference join without assuming a SQL table layout; fetch the
two entry types and pass the resulting structures and energies to the
materials-science constructor:
from math import gcd
from httk.analyse.matsci import PhaseDiagram
from httk.atomistic import StructureEntry, UnitcellStructureView
from httk.core import DataRecord, Run
from httk.store import Backend, SqlStore
store = SqlStore(Backend.sqlite("presentation.sqlite"))
structures, energies, ids = [], [], []
search = store.searcher()
run = search.variable(Run)
for item in search.results(run=run).scalars():
structure_edge = next(edge for edge in item.outputs if edge.entry_type == "structures")
energy_edge = next(edge for edge in item.outputs if edge.entry_type == "_httk_records")
structure = store.fetch_entry(StructureEntry, structure_edge.entry_id)
energy = store.fetch_by_content_id(DataRecord, energy_edge.entry_id)
assert structure is not None and energy is not None
structures.append(structure)
energies.append(energy.value)
ids.append(structure_edge.entry_id)
pd = PhaseDiagram.from_structures(structures, energies, ids=ids)
views = [UnitcellStructureView(structure) for structure in structures]
def label(structure):
amounts = structure.composition.amount_mapping
divisor = 0
for amount in amounts.values():
divisor = gcd(divisor, int(amount))
order = sorted(amounts, key=lambda element: (element == "O", element))
return "".join(
element + (str(int(amounts[element]) // divisor) if int(amounts[element]) // divisor != 1 else "")
for element in order
)
labels = [label(structure) for structure in views]
stable = {labels[index] for index in pd.hull_indices}
print("stable", sorted(stable))
print("energy above hull", dict(zip(
labels,
pd.energy_above_hull,
)))
print("TiO stable", "TiO" in stable)
assert len(structures) == 6
assert stable == {"Ca", "Ti", "O", "CaO", "CaTiO3"}
assert "TiO" not in stable
The identifiers are content IDs, so the code does not assume filenames or hard-code compositions or energies. To make the result readable, map the stable IDs back to the six page-09 tags in the surrounding application; the expected stable set is Ca, Ti, O, CaO, and CaTiO3, with TiO above the hull.
Plotting is an explicit presentation step:
ax = pd.plot()
ax.figure.savefig("catio3-phase-diagram.png", dpi=160, bbox_inches="tight")
print("saved catio3-phase-diagram.png")
The mock values are demonstration numbers, not physics. The solver uses
numpy.float64 linear programming for the hull; from_structures derives the
compositions from the collected structures and normalizes the total energies
per atom before solving.
See the materials phase-diagram API in the versioned httk-analyse documentation for more analysis options.