---
title: "Phase diagram format"
description: "The .phasediagram file format Ouro renders as an interactive phase diagram"
date: "2026-09-24"
last_updated: "2026-09-24"
---

Ouro renders any file ending in `.phasediagram` as an interactive
thermodynamic phase diagram. The format is open: any service, script, or
agent that writes a file following this page gets the same viewer that Ouro's
own materials routes use.

A `.phasediagram` file carries the thermodynamics you already computed:
formation energies, hull distances, and the facets of the convex hull. The
viewer draws that hull as given instead of recomputing one, so what readers
see is exactly the hull your numbers were measured against.

## What the viewer shows

| Elements | Drawn as                                                         |
| -------- | ---------------------------------------------------------------- |
| 2        | Formation energy against composition                             |
| 3        | Composition triangle, or a 3D energy surface                     |
| 4        | Rotatable composition tetrahedron                                |
| 5+       | Straight-line cuts only (on the file page)                       |

On the file page, readers can also take a straight-line cut between any two
stable phases, hover anywhere in composition space to see which phases form
there, and read each phase's balanced decomposition reaction. Embedded in a
post, the diagram shows with a compact hover card.

Everything beyond the file's contents is derived from `facets`, described
below, so a file needs nothing more than this page lists.

## Encoding

A `.phasediagram` file is a single UTF-8 JSON object. Upload it with the
`.phasediagram` extension; the content type is `application/json`. Energies
are in eV/atom throughout.

## Top-level fields

| Field          | Type         | Required | Meaning                                                                  |
| -------------- | ------------ | -------- | ------------------------------------------------------------------------ |
| `format`       | string       | Yes      | Always `"ouro.phase-diagram"`                                            |
| `version`      | integer      | Yes      | Always `1` for the format on this page                                   |
| `elements`     | string[]     | Yes      | Element symbols, in the order every `composition` uses                   |
| `entries`      | object[]     | Yes      | The phases, described under [Entries](#entries)                          |
| `facets`       | integer[][]  | Yes      | Hull facets as indices into `entries`, described under [Facets](#facets) |
| `highlight`    | integer      | No       | Index of an entry to feature, usually the structure being assessed      |
| `energy_model` | string       | No       | Label for the method behind the energies, such as `"Orb v3"` or `"PBE"`  |

## Entries

Each entry is one phase: one structure at one composition. Polymorphs are
separate entries with the same composition.

| Field                       | Type           | Required | Meaning                                                                 |
| --------------------------- | -------------- | -------- | ----------------------------------------------------------------------- |
| `id`                        | string or null | Yes      | Your identifier for the phase. IDs starting with `mp-` link to the Materials Project |
| `formula`                   | string         | Yes      | Reduced formula, such as `"Fe3Bi2"`                                     |
| `composition`               | number[]       | Yes      | Atomic fractions, ordered like `elements`, summing to 1                 |
| `energy_per_atom`           | number         | Yes      | Total energy per atom                                                   |
| `formation_energy_per_atom` | number         | Yes      | Energy per atom relative to the pure elements                           |
| `e_above_hull`              | number         | Yes      | Distance above the hull, 0 for stable phases                            |
| `stable`                    | boolean        | Yes      | Whether the phase is a vertex of the hull                               |
| `space_group`               | string         | No       | Hermann–Mauguin symbol in pymatgen's notation, such as `"P6_3/mmc"`     |
| `asset_id`                  | string         | No       | UUID of an Ouro file holding this phase's structure                     |

`formula` is shown to readers and used to balance decomposition reactions, so
write it as element symbols followed by integer counts, without parentheses,
and keep it consistent with `composition`.

When `asset_id` is set, the viewer links the entry to that file and marks it
as an Ouro structure.

`space_group` is how readers tell polymorphs apart: the viewer shows it with
each phase and lists every polymorph of a formula by energy. Write `_` before
a screw-axis subscript and `-` before a rotoinversion, as in `"P6_3/mmc"` and
`"Fm-3m"`.

## Facets

`facets` lists the simplices of the lower convex hull in composition and
formation-energy space. Each facet is an array of entry indices, one per
element: pairs for a binary, triangles for a ternary, tetrahedra for a
quaternary. Every index in a facet must point to a stable entry.

Projected onto composition, the facets tile the whole composition simplex
without gaps or overlaps. That lets the viewer find the facet containing any
composition, and from it:

- which stable phases a composition decomposes into, with the facet's
  barycentric weights as the share of atoms in each phase
- the hull energy at that composition, which is the weighted sum of those
  phases' formation energies
- the hull along any straight line, which bends only where the line crosses
  from one facet into the next

## Consistency rules

The viewer trusts the file rather than checking it, so a valid file keeps these
true:

- Each element has a stable entry with pure composition and a formation energy
  of 0.
- Stable entries have `e_above_hull` of 0. Only stable entries appear in
  `facets`.
- Every other entry's `e_above_hull` equals its formation energy minus the
  hull energy at its composition, as computed from `facets`.
- You may leave out unstable entries, for example everything more than
  0.2 eV/atom above the hull. Keep every stable entry and the `highlight`
  entry, since facets and the featured phase refer to them.

## Example

A complete Fe–Bi binary with one compound on the hull and one phase above it:

```json
{
  "format": "ouro.phase-diagram",
  "version": 1,
  "elements": ["Fe", "Bi"],
  "energy_model": "Orb v3",
  "entries": [
    {
      "id": "mp-13",
      "formula": "Fe",
      "composition": [1, 0],
      "energy_per_atom": -8.31,
      "formation_energy_per_atom": 0,
      "e_above_hull": 0,
      "stable": true
    },
    {
      "id": "mp-23152",
      "formula": "Bi",
      "composition": [0, 1],
      "energy_per_atom": -3.87,
      "formation_energy_per_atom": 0,
      "e_above_hull": 0,
      "stable": true
    },
    {
      "id": null,
      "formula": "FeBi2",
      "composition": [0.333333, 0.666667],
      "energy_per_atom": -5.43,
      "formation_energy_per_atom": -0.08,
      "e_above_hull": 0,
      "stable": true
    },
    {
      "id": null,
      "formula": "Fe3Bi2",
      "composition": [0.6, 0.4],
      "energy_per_atom": -6.542,
      "formation_energy_per_atom": -0.008,
      "e_above_hull": 0.04,
      "stable": false
    }
  ],
  "facets": [
    [0, 2],
    [2, 1]
  ],
  "highlight": 3
}
```

Fe₃Bi₂ lies on the Fe–FeBi₂ facet, where the hull energy is −0.048 eV/atom.
Its formation energy of −0.008 eV/atom puts it 0.04 eV/atom above the hull,
and the viewer shows it decomposing as Fe₃Bi₂ → 2 Fe + FeBi₂.

## Writing files from pymatgen

If you build phase diagrams with
[pymatgen](https://pymatgen.org/pymatgen.analysis.html#module-pymatgen.analysis.phase_diagram),
the [Python SDK](/docs/developers/libraries) serializes a `PhaseDiagram`
directly:

```python showLineNumbers
import json

from ouro import Ouro
from ouro.utils.phase_diagram import PHASE_DIAGRAM_EXTENSION, phase_diagram_to_dict

ouro = Ouro()

data = phase_diagram_to_dict(
    phase_diagram,               # a pymatgen PhaseDiagram
    max_e_above_hull=0.2,        # drop unstable phases further above the hull
    highlight=my_entry,          # optional entry to feature
    energy_model="Orb v3",       # optional label
)
ouro.files.create(
    name="Fe-Bi phase diagram",
    visibility="public",
    file_content=json.dumps(data).encode(),
    file_name=f"Fe-Bi.{PHASE_DIAGRAM_EXTENSION}",
)
```

`phase_diagram_to_dict` also takes `asset_ids`, a mapping from entry IDs to
Ouro file UUIDs, to link phases to their structure files. It writes
`space_group` from each entry's structure when the entries are
`ComputedStructureEntry` objects, or from `entry.data["space_group"]`
otherwise.

Without pymatgen, compute the lower convex hull of your phases with any hull
code, write its facets as entry indices, and derive `e_above_hull` from them so
the file follows the consistency rules above.

## Returning files from a route

A [route](/docs/concepts/routes) that produces phase diagrams declares its
output as a file with the `phasediagram` extension, and the result renders
with the viewer wherever the route's output appears. See
[route input and output assets](/guides/route-input-output-assets) for how to
declare outputs.

## Versioning

The `version` field changes only for changes that would break existing readers.
Readers should reject versions they don't know, as Ouro's viewer does, and
ignore fields they don't recognize, so optional fields can be added within a
version.
