crystod.slab#
Public surface-slab API of CrystOD (the crystod-slab domain).
Cut surface slabs from a bulk crystal structure, the Python form of
crystod-slab. For each Miller index every distinct termination is built
with pymatgen’s SlabGenerator and measured: number of atoms, thickness
along the surface normal, vacuum, in-plane area, formula, whether the slab is
polar (a nonzero dipole per area from the oxidation states,
Slab.is_polar) and whether its two faces are equivalent
(Slab.is_symmetric). The slabs are written as VASP POSCAR files.
The bulk structure
load_structure()– read a POSCAR (CIF works too), optionally in the standardized conventional cell;conventional_cell()– the standardization on its own.describe_cell()– space group and the comparison with the conventional standard cell, as aCellInfo.
Miller indices
parse_miller_index()–"1 0 0","1,0,0"or a four-index(h k i l)of hexagonal axes, as(h, k, l).read_index_list()– an index list file, one index per line.distinct_miller_indices()– the indices up to a maximum that are distinct under the Laue group of the crystal (in the axes of the cell).format_miller_index()–"(1 0 -1)".
Slabs
generate_slabs()– every termination of the given surfaces (or of every distinct surface up tomax_index), as aSlabSetofSlabRecord.guess_oxidation_states(),parse_oxidation_states(),resolve_oxidation_states(),format_oxidation_states(),format_charge()– the oxidation states of the polarity test and the net charge of a (symmetrized) slab.format_table(),slab_status()– the tablecrystod-slabprints (one string;crystod.search.format_table()returns a list of lines) and the status column;table_legend(),TABLE_LEGEND,CHARGE_LEGEND– what its columns mean.
Files
write_slab_poscar(),slab_poscar_text(),slab_filename()– the POSCAR files (POSCAR_slab_SrTiO3_111_t1,..._100_s1for a symmetrized slab); likecrystod.search.write_poscar(),write_slab_poscarreturns(path, status)and keeps an identical file, replacing a different one only withoverwrite=True.
Constants
SLAB_CITATION_LINES– the papers to cite;DEFAULT_SLAB_SIZE,DEFAULT_VACUUM_SIZE,DEFAULT_TOLERANCE– the defaults of the command.
Usage:
from crystod import slab
structure = slab.load_structure("221_PPOSCAR_SrTiO3")
records = slab.generate_slabs(structure, max_index=1)
for record in records:
print(record.label, record.n_atoms, record.polar, record.symmetric)
print(slab.format_table(records))
slab.write_slab_poscar(records[0]) # ('POSCAR_slab_SrTiO3_111_t1', 'wrote')
records = slab.generate_slabs(structure, miller_index=(1, 0, 0), symmetrize=True)
Attributes resolve lazily (PEP 562): importing this module is instant and
pymatgen loads only on first use. Functions report bad input as
ValueError through this namespace (the implementation module
crystod.surface_slab raises SystemExit, as the command line wants).
- class crystod.slab.CellInfo(formula, space_group, space_group_number, n_atoms, n_conventional, is_conventional, species, lattice, point_group='1', laue_group='-1')[source]#
Bases:
objectSymmetry facts of a bulk cell, as
crystod-slabprints them.- Variables:
formula (str) – Reduced formula, elements in the order of the sites (
SrTiO3;YBa2Cu3O6, never pymatgen’sBa2Y(CuO2)3).space_group (str) – International symbol found by spglib (
Pm-3m).space_group_number (int) – Its number (221).
n_atoms (int) – Atoms in the cell.
n_conventional (int) – Atoms in the standardized conventional cell.
is_conventional (bool) – The cell has the lattice parameters and the number of atoms of the conventional standard cell, so its Miller indices are those of that cell.
species (tuple[str, ...]) – The elements in the order of their first site.
lattice (tuple[float, float, float, float, float, float]) –
(a, b, c, alpha, beta, gamma)in Angstrom and degrees.point_group (str) – The crystal point group (
m-3m).laue_group (str) – Its Laue group, under which
distinct_miller_indices()merges indices (m-3m;-3mforR-3c).
- formula: str#
- is_conventional: bool#
- lattice: tuple[float, float, float, float, float, float]#
- laue_group: str = '-1'#
- n_atoms: int#
- n_conventional: int#
- point_group: str = '1'#
- space_group: str#
- space_group_number: int#
- species: tuple[str, ...]#
- class crystod.slab.SlabRecord(miller_index, termination, shift, slab, n_atoms, thickness, vacuum, area, formula, polar, symmetric, bulk_formula, species_order, charge=None, symmetrized=False)[source]#
Bases:
objectOne slab: a termination of one Miller index, with its measurements.
- Variables:
miller_index (tuple[int, int, int]) –
(h, k, l)of the surface (pymatgen’s, divided by any common factor).termination (int) – 1, 2, … in pymatgen’s order within the index.
shift (float) – pymatgen’s termination shift, fractional
cof the oriented unit cell.slab (object) – The
pymatgen.core.surface.Slab.n_atoms (int) – Atoms in the slab cell.
thickness (float) – Extent of the atoms along the surface normal (Angstrom).
vacuum (float) – Height of the cell along the normal minus the thickness.
area (float) – In-plane area of the cell (Angstrom^2).
formula (str) – Composition of the slab cell (
Sr5Ti5O15), elements in the order ofspecies_order.polar (bool | None) –
Slab.is_polarof the slab decorated with the oxidation states;Nonewhen there are none.symmetric (bool) –
Slab.is_symmetricat the symmetry tolerance.bulk_formula (str) – Reduced formula of the bulk, elements in the order of
species_orderand never grouped (for the file names).species_order (tuple[str, ...]) – Element order of the bulk structure (for writing).
charge (float | None) – Net formal charge of the slab cell (e) from the oxidation states,
Nonewithout them; nonzero only for a non-stoichiometric (symmetrized) slab.symmetrized (bool) – The slab comes from a
symmetrize=Truerun (its label and file name uses1, s2, ...instead oft1, t2).
- area: float#
- bulk_formula: str#
- charge: float | None = None#
- formula: str#
- property label: str#
"(1 1 1) t1"("(1 0 0) s1"for a symmetrized slab).
- miller_index: tuple[int, int, int]#
- n_atoms: int#
- polar: bool | None#
- shift: float#
- slab: object#
- species_order: tuple[str, ...]#
- symmetric: bool#
- symmetrized: bool = False#
- termination: int#
- thickness: float#
- vacuum: float#
- class crystod.slab.SlabSet(records=(), *, miller_indices=(), oxidation_states=None, oxidation_source=None, notes=())[source]#
Bases:
listThe
SlabRecordlist ofgenerate_slabs(), with its context.- Variables:
miller_indices – The indices enumerated, in order.
oxidation_states – The states the polarity was computed with, or None.
oxidation_source –
"guessed","given"or None.notes – What the command prints as NOTE lines (an index without a symmetric termination, an index given twice, …).
- crystod.slab.conventional_cell(structure, tolerance=0.1, species_order=None)[source]#
The standardized conventional cell of
structure(--conventional).pymatgen’s
SpacegroupAnalyzer.get_conventional_standard_structureattolerance; the sites are sorted (stably) by element inspecies_order, by default the element order ofstructure.- Raises:
SystemExit – No conventional cell at this tolerance (
ValueErrorthroughcrystod.slab).
- crystod.slab.describe_cell(structure, tolerance=0.1)[source]#
Space group of
structureand how it compares with the conventional cell.- Return type:
- crystod.slab.distinct_miller_indices(structure, max_index, tolerance=0.1)[source]#
The Miller indices with
|h|, |k|, |l| <= max_indexthat are distinct under the Laue group of the crystal.Two indices are the same surface when a rotation of the space group of
structure(found by spglib attolerance), possibly followed by the inversion that turns a slab over, maps one onto the other. This is done in the axes of the cell as given, so it holds for every setting (a primitive rhombohedral cell, a monoclinic cell of pseudo-orthorhombic metric, …). The indices are reduced by their common factor, and the first index of each family is kept in pymatgen’s order (get_symmetrically_distinct_miller_indices: low indices first), with whose list this one agrees for a crystal that is not trigonal and whose lattice has no more symmetry than the crystal. pymatgen merges indices under the symmetry of the lattice (and, for a trigonal crystal, of its hexagonal setting), which on a primitive rhombohedral cell lists one surface twice and misses another, and on a lattice of higher symmetry than the crystal misses surfaces.Example
>>> from crystod import slab >>> from crystod.examples import example_path >>> s = slab.load_structure(example_path("221_PPOSCAR_SrTiO3")) >>> slab.distinct_miller_indices(s, 1) [(1, 1, 1), (1, 1, 0), (1, 0, 0)]
- Return type:
list[tuple[int, int, int]]
- crystod.slab.format_charge(value)[source]#
"+4","-1","0","+2.67": a charge in units of e.- Return type:
str
- crystod.slab.format_miller_index(index)[source]#
"(1 0 -1)": an index in parentheses, the components separated by spaces.- Return type:
str
- crystod.slab.format_oxidation_states(states)[source]#
"Sr+2 Ti+4 O-2"("none"for no states).- Return type:
str
- crystod.slab.format_table(records, max_atoms=None, no_polar=False, no_files=False, width=100)[source]#
The slab table
crystod-slabprints, one header line and one line per slab.The columns are
# h k l shift atoms thickness vacuum area formula [charge] polar symmetric status(seetable_legend(); the charge column only when a slab is charged); the status isslab_status(). The column widths follow the content; when the table would be wider thanwidthcolumns the units leave the header, then the columns move closer together, then the formulas leave the table for lines of their own (#1 Sr5Ti5O15) below it.- Returns:
The table as one string (lines joined by newlines, no trailing one;
crystod.search.format_table()returns a list of lines instead).- Return type:
str
- crystod.slab.generate_slabs(structure, miller_index=None, *, max_index=None, slab_size=10.0, vacuum_size=15.0, symmetrize=False, oxidation_states=None, tolerance=0.1, center=True, primitive=True, lll_reduce=False, in_unit_planes=False, max_normal_search=None, orthogonal_c=False)[source]#
Every distinct termination of the given surfaces, measured.
This is
crystod-slabwithout the files. For each index,SlabGenerator(structure, hkl, slab_size, vacuum_size, ...) .get_slabs(symmetrize=symmetrize, tol=0.1, ftol=0.1); the slabs are numberedt1, t2, ...per index in pymatgen’s order (s1, s2, ...withsymmetrize).- Parameters:
structure – The bulk
Structure(seeload_structure()); Miller indices refer to its axes.miller_index – One index (
(1, 0, 0),"1 0 0", a four-index(1, 0, -1, 0)) or a list of them. Give this ormax_index.max_index (int | None) – Every index with
|h|, |k|, |l| <= max_indexdistinct under the Laue group of the crystal (distinct_miller_indices()).slab_size (float) – Minimum slab height in Angstrom (in
d_hkllattice planes within_unit_planes): whole oriented cells are stacked until they reach it, and the atoms span that height less the gap at the cut.vacuum_size (float) – Minimum vacuum height, likewise in whole cells.
symmetrize (bool) – Symmetric slabs: atoms are removed from one face of every asymmetric slab until the faces are equivalent at
tolerance(non-stoichiometric, possibly charged:SlabRecord.charge).oxidation_states (dict[str, float] | None) –
{"Sr": 2, "Ti": 4, "O": -2}for the dipole; by default pymatgen’s guess, and no polarity (polar = None) when there is none. Given states must balance the bulk.tolerance (float) – Symmetry tolerance in Angstrom of the Laue group of
max_index, ofSlab.is_symmetricand of the symmetrization.center (bool) – Center the slab in the cell (pymatgen
center_slab).primitive (bool) – Reduce the in-plane cell to a primitive one when pymatgen can (it keeps the oriented cell’s
a,botherwise).lll_reduce (bool) – Reduce the in-plane cell to its shortest
a,band makecas perpendicular as whole in-plane vectors allow (aandbstay in the surface).in_unit_planes (bool) –
slab_sizeandvacuum_sizecountd_hkllattice planes of the cell (one can hold several atomic layers).max_normal_search (int | None) – pymatgen
max_normal_search(acvector as perpendicular to the surface as possible).orthogonal_c (bool) – Make
cperpendicular to the surface (Slab.get_orthogonal_c_slab) before the measurements.
- Returns:
The
SlabSet(a list ofSlabRecord).- Raises:
SystemExit – Both or neither of
miller_indexandmax_index, a bad index, non-positive sizes or tolerance, oxidation states that do not fit the structure, or a slab pymatgen cannot build (ValueErrorthroughcrystod.slab).- Return type:
Example
>>> from crystod import slab >>> from crystod.examples import example_path >>> s = slab.load_structure(example_path("221_PPOSCAR_SrTiO3")) >>> records = slab.generate_slabs(s, max_index=1) >>> [(r.miller_index, r.n_atoms, r.polar) for r in records] [((1, 1, 1), 25, True), ((1, 1, 0), 20, True), ((1, 0, 0), 15, False)]
- crystod.slab.guess_oxidation_states(structure)[source]#
pymatgen’s most likely oxidation states of the bulk composition.
Nonewhen pymatgen has no charge-balanced guess, or only the all-zero one of a metal: the dipole, hence the polarity, is then unknown.- Return type:
dict[str, float] | None
- crystod.slab.load_structure(path, conventional=False, tolerance=0.1)[source]#
Read the bulk structure (POSCAR; CIF and other pymatgen formats work too).
The structure is read by pymatgen in VASP’s reading of a POSCAR (
crystod.vasp_io.poscar_structure()), stripped of site properties and oxidation states, and checked to be ordered.- Parameters:
path – The structure file.
conventional (bool) – Return the standardized conventional cell (
SpacegroupAnalyzer.get_conventional_standard_structure) instead of the cell as given; Miller indices then refer to its axes. The sites keep the element order of the file.tolerance (float) – Symmetry tolerance in Angstrom of the standardization.
- Returns:
A
pymatgen.core.Structure.- Raises:
SystemExit – The file is missing or unreadable, or a site is partially occupied or shared by several species (
ValueErrorthroughcrystod.slab).
- crystod.slab.parse_miller_index(index)[source]#
A Miller index
(h, k, l)from three integers or a Miller-Bravais index.- Parameters:
index –
"1 0 0","1,0,0",["1", "0", "0"],(1, 0, 0), or four integers(h k i l)of hexagonal axes, of which the third must bei = -(h + k)and is dropped:["1", "0", "-1", "0"]->(1, 0, 0).- Returns:
(h, k, l)as given (not divided by a common factor).- Raises:
SystemExit – Not three or four integers, a four-index input with
i != -(h + k), or the zero vector (ValueErrorthroughcrystod.slab).- Return type:
tuple[int, int, int]
Example
>>> from crystod import slab >>> slab.parse_miller_index(["1", "0", "-1", "0"]) (1, 0, 0)
- crystod.slab.parse_oxidation_states(tokens)[source]#
{"Sr": 2.0, "O": -2.0}from["Sr=2", "O=-2"](or"Sr=2 O=-2").A state may be a fraction,
Fe=8/3.- Raises:
SystemExit – A token that is not
EL=Qwith a numberQ, an unknown element, or an element given twice (ValueErrorthroughcrystod.slab).- Return type:
dict[str, float]
- crystod.slab.read_index_list(path)[source]#
The Miller indices of a list file, one per line.
A line holds
1 0 0,1,0,0or a four-index1 0 -1 0;#starts a comment, blank lines are skipped.- Raises:
SystemExit – The file is missing or unreadable, a line is not a Miller index (the message names the line number), or the file holds no index (
ValueErrorthroughcrystod.slab).- Return type:
list[tuple[int, int, int]]
- crystod.slab.resolve_oxidation_states(structure, oxidation_states=None)[source]#
The states used for the dipole and where they came from.
- Returns:
the given states (checked against the structure: one per element, balancing the bulk) and
"given", pymatgen’s guess and"guessed", or(None, None)when there is no guess. Given states that are all 0 come back as(None, "given"): no ions, so the polarity is unknown.- Return type:
(states, source)- Raises:
SystemExit – Given states that miss an element, name one the structure does not have, or leave the bulk charged (
ValueErrorthroughcrystod.slab).
- crystod.slab.slab_filename(record)[source]#
POSCAR_slab_{bulk formula}_{h}{k}{l}_t{n}:POSCAR_slab_SrTiO3_111_t1.A negative index is written as
-1(POSCAR_slab_NaCl_10-1_t1); when a component is 10 or more the components are separated by_(POSCAR_slab_SrTiO3_1_1_10_t1); a symmetrized slab hass{n}instead oft{n}(POSCAR_slab_SrTiO3_100_s1). Any character other than a letter, a digit,.,_or-becomes_.- Return type:
str
- crystod.slab.slab_poscar_text(record, species_order=None)[source]#
The POSCAR of a slab: direct coordinates, one block per element.
The sites are sorted (stably) by element in
species_order, by default the element order of the bulk structure; the comment line readsSrTiO3 (1 1 1) slab, termination t1, Sr5Ti5O15, shift 0.250, crystod-slab(symmetrized s1for a symmetrized slab).- Return type:
str
- crystod.slab.slab_status(record, max_atoms=None, no_polar=False, no_files=False)[source]#
What
crystod-slabdoes with the slab, in the words of its table."skipped: 25 > 16 atoms"(more atoms thanmax_atoms), then"skipped: polar"(no_polarand a polar slab; a slab of unknown polarity is kept), otherwise"written", or"not written (--no-files)"withno_files.- Return type:
str
- crystod.slab.table_legend(records)[source]#
TABLE_LEGEND, plusCHARGE_LEGENDwhen the table ofrecordshas a charge column (a charged, symmetrized slab).- Return type:
str
- crystod.slab.write_slab_poscar(record, directory='.', species_order=None, *, overwrite=False)[source]#
Write the POSCAR of a slab (
slab_poscar_text()) intodirectory.The directory is created if needed. As
crystod.search.write_poscar()does, an identical file of the same name (slab_filename()) is kept, and one with different content is replaced only withoverwrite.- Returns:
(path, status)with status"wrote","kept"(an identical file was already there) or"replaced".- Raises:
SystemExit – A different file is in the way and
overwriteis False, the directory cannot be created or the file cannot be written (ValueErrorthroughcrystod.slab).- Return type:
tuple[str, str]
- crystod.slab.SLAB_CITATION_LINES#
The papers to cite for
crystod-slab(that of the author of the original slabkit.py) and for pymatgen’s slab construction.
- crystod.slab.TABLE_LEGEND#
What the columns of
format_table()mean (printed under the table).
- crystod.slab.CHARGE_LEGEND#
Appended to
TABLE_LEGENDwhen the table has a charge column.
- crystod.slab.DEFAULT_SLAB_SIZE = 10.0#
Minimum slab height in Angstrom (pymatgen
min_slab_size).
- crystod.slab.DEFAULT_VACUUM_SIZE = 15.0#
Minimum vacuum height in Angstrom (pymatgen
min_vacuum_size).
- crystod.slab.DEFAULT_TOLERANCE = 0.1#
Symmetry tolerance in Angstrom of the space group, the Laue group of the Miller indices and the symmetric-slab test.