The .phonons file format Ouro renders as an interactive phonon dispersion and density of states
Ouro renders any file ending in .phonons as an interactive phonon
dispersion, with the phonon density of states beside it. The format is open:
any service, script, or agent that writes a file following this page gets the
same viewer that Ouro's phonon route uses.
The file carries frequencies you already computed. The viewer plots them as given and derives only what follows directly from them, such as whether the structure is dynamically stable.
The viewer draws each branch along the high-symmetry path, with labeled q-points. Imaginary modes, written as negative frequencies, are drawn below zero in a second color. When the file carries a density of states, the DOS is drawn beside the branches on the same frequency axis.
The viewer reports whether the structure is dynamically stable. If it isn't, it gives the lowest frequency, where it occurs, and every part of the path where modes are imaginary. It treats frequencies below −0.3 THz as imaginary; shallower dips are usually numerical noise on the acoustic branches near Γ.
Readers can hover a branch to read its frequency and, with mode projections, which elements move in that mode. Projections also let readers choose an element and see the branches thicken where its atoms move. Readers can switch between THz, meV, and cm⁻¹.
Embedded in a post, the file shows with a compact hover card.
The file is a single UTF-8 JSON object. Upload it with the .phonons
extension; the content type is application/json.
Frequencies are in THz, with imaginary frequencies written as negative numbers, the convention phonopy and most phonon codes follow.
| Field | Type | Required | Meaning |
|---|---|---|---|
format | string | Yes | Always "ouro.phonons" |
version | integer | Yes | Always 1 for the format on this page |
qpoints | object | Yes | The path, described under Q-points |
frequencies | number[][] | Yes | Frequencies in THz, indexed [branch][q-point] |
projections | object[] | No | Which elements move in each mode, described under Mode projections |
dos | object | No | A density of states to draw beside the branches, described under Density of states |
force_model | string | No | Label for the method behind the force constants, such as "PBE" or an interatomic potential |
Each branch is a list with one frequency per q-point, in path order. A structure with n atoms in its primitive cell has 3n branches. The viewer draws each branch index as one line and doesn't reorder them, so branches sorted by frequency at each q-point, as phonopy writes them, are fine.
The path is encoded exactly as the k-point path of a band structure file.
| Field | Type | Required | Meaning |
|---|---|---|---|
distances | number[] | Yes | Cumulative distance along the path, one per q-point |
labels | object[] | Yes | High-symmetry points, each {"index": integer, "label": string} |
distances starts at 0 and never decreases. Its units only set the relative
widths of the path's segments. Where the path jumps between points that
aren't connected, the last q-point before the jump and the first after it
share the same distance, and each carries its own label; the viewer breaks the
lines there and labels the tick U|K. Write labels as readers should see
them, such as "Γ" or "X₁", rather than as LaTeX.
Each projection gives one element's share of every mode: the squared amplitude of the mode's eigenvector on that element's atoms.
| Field | Type | Required | Meaning |
|---|---|---|---|
element | string | Yes | Element symbol, such as "Na" |
weights | number[][] | Yes | Shares from 0 to 1, indexed like frequencies: [branch][q-point] |
A mode's shares across all elements sum to 1. Two decimals are enough and keep the file small. The viewer ignores projections for a structure with one element, where every share is the whole.
| Field | Type | Required | Meaning |
|---|---|---|---|
frequencies | number[] | Yes | Frequency grid in THz, ascending |
total | number[] | Yes | Total DOS in states/THz, one value per grid frequency |
projections | object[] | No | The DOS on each element, each {"element": string, "values": number[]} on the same grid |
Sample the DOS on a mesh through the whole Brillouin zone, not along the path.
A two-atom structure along a path with one jump, with a small imaginary mode at X. A real file has many more q-points and DOS values:
{
"format": "ouro.phonons",
"version": 1,
"force_model": "PBE",
"qpoints": {
"distances": [0, 0.5, 1.0, 1.0, 1.4],
"labels": [
{ "index": 0, "label": "Γ" },
{ "index": 2, "label": "X" },
{ "index": 3, "label": "K" },
{ "index": 4, "label": "Γ" }
]
},
"frequencies": [
[0, -0.4, -0.9, 2.1, 0],
[0, 2.2, 3.0, 3.1, 0],
[0, 2.4, 3.2, 3.3, 0],
[7.8, 7.5, 7.1, 7.2, 7.8],
[7.8, 7.6, 7.3, 7.4, 7.8],
[8.4, 8.1, 7.9, 8.0, 8.4]
],
"projections": [
{
"element": "Na",
"weights": [
[0.3, 0.6, 0.9, 0.8, 0.3],
[0.3, 0.6, 0.8, 0.7, 0.3],
[0.3, 0.6, 0.8, 0.7, 0.3],
[0.7, 0.4, 0.2, 0.3, 0.7],
[0.7, 0.4, 0.2, 0.3, 0.7],
[0.7, 0.4, 0.1, 0.2, 0.7]
]
},
{
"element": "Cl",
"weights": [
[0.7, 0.4, 0.1, 0.2, 0.7],
[0.7, 0.4, 0.2, 0.3, 0.7],
[0.7, 0.4, 0.2, 0.3, 0.7],
[0.3, 0.6, 0.8, 0.7, 0.3],
[0.3, 0.6, 0.8, 0.7, 0.3],
[0.3, 0.6, 0.9, 0.8, 0.3]
]
}
],
"dos": {
"frequencies": [-1, 0, 2, 4, 6, 8, 10],
"total": [0.05, 0.1, 0.8, 0.6, 0.2, 1.4, 0],
"projections": [
{ "element": "Na", "values": [0.04, 0.06, 0.6, 0.4, 0.1, 0.4, 0] },
{ "element": "Cl", "values": [0.01, 0.04, 0.2, 0.2, 0.1, 1.0, 0] }
]
}
}The lowest branch drops to −0.9 THz at X, below the −0.3 THz threshold, so the viewer reports the structure as dynamically unstable, with imaginary modes along Γ–X and at X. Na moves in 90% of that mode.
If you compute phonons with phonopy, the
Python SDK serializes a Phonopy object whose
force constants are produced, adding the element projections and a DOS on a
full-zone mesh:
import json
from ouro import Ouro
from ouro.utils.phonons import PHONONS_EXTENSION, phonons_to_dict
ouro = Ouro()
phonon.produce_force_constants()
data = phonons_to_dict(phonon, force_model="Orb v3")
ouro.files.create(
name="NaCl phonons",
visibility="public",
file_content=json.dumps(data).encode(),
file_name=f"NaCl.{PHONONS_EXTENSION}",
)phonons_to_dict runs phonopy's high-symmetry band structure and DOS mesh on
the object you pass, replacing any band structure or mesh results it held.
A route that computes phonons declares its output as
a file with the phonons extension, and the result renders with the viewer
wherever the route's output appears. See
route input and output assets for how to
declare outputs.
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.
On this page