Materials phase diagrams

httk.analyse.matsci.PhaseDiagram builds a lower convex hull in composition space. It normalizes compositions and evaluates energies per atom, so entries with differently sized formula units can be compared directly. Inputs may be composition mappings or compatible StructureLike objects from httk-atomistic.

The default solver="auto" selects HiGHS when installed and the built-in solver otherwise. Installing httk-analyse[default] includes HiGHS. Both factories and PhaseDiagramBuilder also accept explicit solver="simplex" or solver="highs". HiGHS reuses models while retaining the built-in numerical checks and fallback; see Generic lower convex hulls for the solver contract. diagram.solver reports the selected route.

Build a binary diagram

Use from_compositions when the compositions are already known. The optional IDs label entries in decompositions and plots:

from httk.analyse.matsci import PhaseDiagram

diagram = PhaseDiagram.from_compositions(
    [{"A": 1}, {"B": 1}, {"A": 1, "B": 1}],
    [0.0, 0.0, -2.0],
    ids=["A", "B", "AB"],
)

assert tuple(diagram.hull_indices) == (0, 1, 2)
assert diagram.energy_above_hull[2] == 0.0

energy_above_hull is the per-atom energy above the stable lower envelope. hull_indices retains the order of the supplied entries. Phase boundaries are exposed directly as phase_lines, which delegates to the generic hull’s supported_segments.

Plotting

Binary diagrams plot as a line diagram. Higher-dimensional composition spaces plot their supported polygonal regions when possible. plot() returns a Matplotlib axes object, making it straightforward to add labels or incorporate the diagram into an existing figure:

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt

ax = diagram.plot()
plt.close(ax.figure)

Unknown-energy phases

An energy of None keeps a phase in the diagram’s separate unknown-energy channel. Its normalized composition is available through unknown_compositions and its identifier through unknown_ids; the phase is not included in compositions, energies_per_atom, or any hull calculation. This lets a diagram retain composition candidates whose energies are not known yet without changing stable phases, decompositions, or tie-lines. At least one phase must have a known energy: an input whose energies are all None is rejected by both factory methods and by PhaseDiagramBuilder.build().

Unknown phases are shown by plot() by default as open gray squares. They are visual markers and never participate as hull points or in energy references, but they do contribute their elements to the global elements union. An unknown phase introducing a new element can therefore widen the composition space and change how the diagram is drawn, such as turning a known A-B binary plot into a ternary polygon. Pass show_unknown=False to hide the markers. In a binary plot they are placed at y=0.0; in a polygon plot their positions use the normalized composition fractions as the same corner-weighted coordinates as the known phases.

Incremental building

PhaseDiagramBuilder is useful when phases arrive incrementally. add_phase and add_structure return the builder, so additions can be chained, and build() creates a PhaseDiagram snapshot:

from httk.analyse.matsci import PhaseDiagramBuilder

builder = (
    PhaseDiagramBuilder()
    .add_phase({"A": 1}, 0.0, "A")
    .add_phase({"B": 1}, 0.0, "B")
    .add_phase({"A": 1, "B": 1}, -2.0, "AB")
    .add_phase({"A": 1, "B": 2}, None, "unknown-AB2")
)
diagram = builder.build()
assert diagram.unknown_ids == ("unknown-AB2",)

Each call to build() is independent of later additions. Earlier snapshots retain the phases and element coordinates present when they were built, while the next snapshot includes all phases currently accumulated by the builder.

The plotting API is a presentation layer: use energy_above_hull and phase_lines for programmatic analysis. For hulls over non-materials coordinates, see Generic lower convex hulls.