Utilities#
Pure computation with no dependencies on the rest of the package.
Seed-id generation: the element set -> deterministic combination ids (3.0).
Pure stdlib – no science imports, no store, no I/O. This is the n-ary knob’s
engine: the user configures run.elements plus run.combination_sizes
([1] for single elements, [2] for binary, [2, 3] to add ternary,
…; omitted = all sizes 1..N, expanded by the config schema), and every run
enumerates the same combinations in the same order, so seed ids are stable
across runs and machines (enqueue idempotency then makes re-seeding a
no-op).
A seed id is the sorted element symbols joined with - ("Cl-Na",
"Cl-Na-O"): filesystem-safe, human-readable, and unambiguous, since
element symbols never contain -.
- matmelt.core.seeds.element_combinations(elements, sizes)[source]#
Enumerate the seed ids for
elementsat each combination size.- Parameters:
elements (
Sequence[str]) – Element symbols fromrun.elements. Deduplicated and sorted before anything is enumerated, so the result does not depend on config order.sizes (
Sequence[int]) – Combination sizes to enumerate, deduplicated and sorted. Size 1 yields the bare element symbols (elemental seeds). A size larger than the element set yields nothing for that size – enumeration stays silent and total, and the preflight is what reports such no-ops.
- Returns:
Seed ids, grouped by ascending size and lexicographic within each size.
- Return type:
- Raises:
ValueError – If any size is below 1. The config schema enforces the same floor; this guard is for direct callers.
Examples
>>> element_combinations(["Na", "Cl"], [2]) ['Cl-Na'] >>> element_combinations(["O", "Na", "Cl"], [1, 3]) ['Cl', 'Na', 'O', 'Cl-Na-O'] >>> element_combinations(["Na", "Cl"], [3]) # more elements than we have []
DFTB+ .gen geometry -> CIF text: the export writer (M10).
Pure stdlib and pure computation – no science imports, no AiiDA, no I/O, no
Rich. The cif command feeds this the geom.out.gen text that DFTB+
relaxed to (fetched from the user’s AiiDA repository, or cached in
calc_result.json) and writes the returned document to disk; keeping the
conversion here means every cell/coordinate rule is unit-testable in the
science-free dev venv, and no CIF is ever produced by a dependency we do not
own.
The written document is deliberately plain: space group P 1 (a relaxed
DFTB+ cell carries no symmetry claim – the atoms have moved), one
_atom_site_* loop in fractional coordinates, and whatever provenance the
caller passes as _mcli_* items (material id, WorkChain/CalcJob pk,
energy, …). It round-trips through the extract runner’s own CIF reader,
and VESTA/ASE read it directly.
Two deliberate non-transformations, so an exported CIF is exactly what the calculation produced:
coordinates are not wrapped into
[0, 1)– an atom that relaxed to0.999998stays there rather than jumping across the cell;the
.genorigin row is ignored (as ASE does) – lattice vectors alone define the cell.
extract_runner.py holds the inverse helpers (CIF -> cell vectors); it
is a self-contained runner staged to compute backends and may never import
this module, so the two directions live apart by design.
- matmelt.core.cif.Vector#
A cartesian or fractional triple.
- matmelt.core.cif.Lattice#
Three lattice vectors (rows), in angstrom.
- class matmelt.core.cif.Geometry(species, fractional, lattice)[source]#
Bases:
objectOne periodic structure, ready to serialize.
- species#
One element symbol per site, already expanded from the
.genspecies table.
- matmelt.core.cif.parse_gen(text)[source]#
Parse DFTB+
.gentext into aGeometry.- Parameters:
text (
str) – The file’s contents. Blank lines and#comments are ignored.- Returns:
The structure, always in fractional coordinates.
- Return type:
- Raises:
ValueError – For a cluster geometry (
C), which has no cell to write; for an unknown geometry type; and for any malformed header, species row, atom row, or lattice block. Every rejection names the offending row – a geometry that cannot be read must never be guessed at.
Notes
Both periodic forms are supported:
F(fractional – what our HSD template and DFTB+’sgeom.out.genproduce) andS(cartesian, converted here against the lattice).
- matmelt.core.cif.cell_volume(lattice)[source]#
Compute the cell volume.
- Parameters:
lattice (
tuple[tuple[float,float,float],tuple[float,float,float],tuple[float,float,float]]) – The three cell vectors, in angstrom.- Returns:
Volume in cubic angstrom – the absolute determinant, so a left-handed cell reports a positive volume.
- Return type:
Examples
>>> cell_volume(((4.0, 0.0, 0.0), (0.0, 4.0, 0.0), (0.0, 0.0, 4.0))) 64.0
- matmelt.core.cif.cell_parameters(lattice)[source]#
Convert lattice vectors to the six CIF cell parameters.
- Parameters:
lattice (
tuple[tuple[float,float,float],tuple[float,float,float],tuple[float,float,float]]) – The three cell vectors, in angstrom.- Returns:
(a, b, c, alpha, beta, gamma)with lengths in angstrom and angles in degrees. Following the crystallographic convention the CIF tags name,alphais the angle betweenbandc,betabetweenaandc, andgammabetweenaandb.- Return type:
- Raises:
ValueError – If any vector has zero length – it has no direction, so the honest answer is a refusal rather than a NaN angle.
Examples
>>> cell_parameters(((3.0, 0.0, 0.0), (0.0, 3.0, 0.0), (0.0, 0.0, 5.0))) (3.0, 3.0, 5.0, 90.0, 90.0, 90.0)
- matmelt.core.cif.cart_to_frac(position, lattice)[source]#
Convert cartesian coordinates to fractional ones.
The inverse of
extract_runner.frac_to_cart.- Parameters:
- Returns:
The fractional triple. Not wrapped into
[0, 1)– see the module docstring.- Return type:
- Raises:
ValueError – If the lattice vectors are linearly dependent, so the cell has no volume and cannot be inverted.
- matmelt.core.cif.formula_sum(species)[source]#
Build the
_chemical_formula_sumtext for a set of sites.- Parameters:
species (
Sequence[str]) – One element symbol per site; order is irrelevant.- Returns:
Alphabetical symbols with their counts, the count omitted when it is 1.
- Return type:
Examples
>>> formula_sum(["Na", "Cl", "Na", "Cl", "O"]) 'Cl2 Na2 O'
- matmelt.core.cif.geometry_to_cif(geometry, *, data_name, extra=None)[source]#
Serialize a
Geometryas a P1 CIF document.- Parameters:
geometry (
Geometry) – The structure to write.data_name (
str) – Names the data block – a material id. CIF forbids whitespace here, and an empty name too.extra (
Mapping[str,Any] |None, default:None) – Provenance items written as_mcli_<key>tags in the given order. Keys must match[A-Za-z0-9_]+; values may be strings, numbers, bools, orNone.
- Returns:
The complete CIF document, newline-terminated.
- Return type:
- Raises:
ValueError – For an empty or whitespace-bearing
data_name; a geometry whose species and coordinate counts disagree or that holds no sites; a degenerate cell; or a provenance key with illegal characters.
- matmelt.core.cif.gen_to_cif(gen_text, *, data_name, extra=None)[source]#
Parse DFTB+
.gentext and serialize it as a P1 CIF document.The one call the
cifcommand makes per material.- Parameters:
- Returns:
The complete CIF document.
- Return type:
- Raises:
ValueError – From
parse_genfor unreadable geometry, or fromgeometry_to_ciffor an unwritable one.