Source code for ase2sprkkr.potentials.definitions.sections.lattice

import numpy as np

from ase.units import Bohr
from ase.cell import Cell

from ...potential_definitions import PotSectionDefinition, PotValueDefinition
from ...potential_sections import PotentialSection

from ....ase.pbc import check_symmetry
from ....common.grammar_types import DefKeyword, Sequence, Table, Integer, Array
from ....physics.lattice_data import Pearson
from ....sprkkr.atoms_region import AtomsRegion


[docs] def _sections_lattice_left_symmetry_error(_): return "Left region of a 2D calculations have to be symmetric in all dimensions"
[docs] def _sections_lattice_right_symmetry_error(_): return "Right region of a 2D calculations have to be symmetric in all dimensions"
[docs] def _sections_lattice_central_symmetry_error(_): return "Central region of a 2D calculations have to be symmetric just in X and Y axis."
[docs] def _sections_lattice_atoms_pbc_error(_): return "For a 2D calculation, atoms have to be periodic in X and Y axes."
[docs] def _sections_lattice_value_is_not_none(value): return value is not None
[docs] def _sections_lattice_value_is_none(value): return value is None
[docs] class LatticeSection(PotentialSection): """This section retrieves the lattice geometry and it creates (during reading) the ASE Cell object"""
[docs] def _set_from_atoms(self, atoms, write_io_data): pbc = atoms.pbc.sum() if pbc == 3: self.SYSDIM = "3D" bcell = atoms.cell elif pbc == 2: if not ("left" in atoms.regions and "right" in atoms.regions and "central" in atoms.regions): raise ValueError( "To run a 2D calculation, an atoms object have to have defined " "'left', 'right' and 'central' region." ) check_symmetry(atoms.regions["left"].pbc, True, _sections_lattice_left_symmetry_error) check_symmetry(atoms.regions["right"].pbc, True, _sections_lattice_right_symmetry_error) check_symmetry(atoms.regions["central"].pbc, [True, True, False], _sections_lattice_central_symmetry_error) check_symmetry(atoms.pbc, [True, True, False], _sections_lattice_atoms_pbc_error) self.SYSDIM = "2D" bcell = atoms.regions["left"].cell else: raise ValueError(f"I don't know which calculation I should run with the periodicity of type: {atoms.pbc}.") bravais_lattice = bcell.get_bravais_lattice() alat = bravais_lattice.a pearson_symbol = bravais_lattice.pearson_symbol self["BRAVAIS"].set(Pearson.from_symbol(pearson_symbol).xband_data()) if self.SYSDIM() == "3D": self.SYSTYPE = "BULK" write_io_data["sites_order"] = slice(None) self.A_L3.clear() self.A_R3.clear() self.NQ_L.clear() self.NQ_R.clear() cell = atoms.cell elif self.SYSDIM() == "2D": for i in "left", "right", "central": if i not in atoms.regions: raise ValueError("For a 2D problem, the 'left', 'right' and 'central' regions have to be defined") self.SYSTYPE = "LIV" if atoms.regions["right"].only_vacuum_atoms() else "LIR" cell = atoms.cell if (cell[2] == [0, 0, 0]).all(): if (atoms.regions["central"] == [0, 0, 0]).all(): raise ValueError( "For a 2D problem, the third (the z-) cell vector has to be specified either for " " atoms object, or for its central region" ) cell[2] = ( atoms.regions["left"].cell[2] + atoms.regions["right"].cell[2] + atoms.regions["central"].cell[2] ) self.A_L3 = atoms.regions["left"].cell[2] / alat self.A_R3 = atoms.regions["right"].cell[2] / alat self.NQ_L = len(atoms.regions["left"]) self.NQ_R = len(atoms.regions["right"]) for i, j in [("left", "right"), ("left", "central"), ("right", "central")]: if atoms.regions[i].shared_ids_with(atoms.regions[j]): raise ValueError(f"{i.capitalize()} and {j} region can not share the same site") la = len(atoms) if self.NQ_L() + self.NQ_R() + len(atoms.regions["central"]) != la: raise ValueError("The left, central and right do not cover all the atoms in the sample") def order(region): region = atoms.regions[region] z = region.positions[:, 2] return region.ids[np.argsort(z)] write_io_data["sites_order"] = np.concatenate(list(map(order, ["left", "central", "right"]))) for i, j in zip(range(len(atoms)), write_io_data["sites_order"]): if i != j: break else: # optimalization - do not reorder write_io_data["sites_order"] = slice(None) else: raise ValueError(f"{self.SISDIM()} problem periodicity type not implemented") write_io_data["lattice.alat"] = alat self["ALAT"].set(alat / Bohr) self["SCALED_PRIMITIVE_CELL"].set(cell / alat)
[docs] def _update_atoms(self, atoms, read_io_data): alat = self["ALAT"]() * Bohr cell = Cell(self["SCALED_PRIMITIVE_CELL"]() * alat) read_io_data["lattice.alat"] = alat if self.SYSDIM() == "3D": regions = [] pbc = [True, True, True] elif self.SYSDIM() == "2D": lc = cell.copy() lc[2] = self.A_L3() * alat rc = cell.copy() rc[2] = self.A_R3() * alat cc = cell.copy() cc[2] -= lc[2] + rc[2] regions = [ AtomsRegion("left", slice(None, self.NQ_L()), lc, [True, True, True]), # NOQA E241 AtomsRegion("central", slice(self.NQ_L(), -self.NQ_R()), cc, [True, True, False]), # NOQA E241 AtomsRegion("right", slice(-self.NQ_R(), None), rc, [True, True, True]), # NOQA E241 ] pbc = [True, True, False] else: raise ValueError(f"Unknown problem periodicity type {self.SYSDIM()}") def update(atoms): atoms.cell = cell atoms.pbc = pbc atoms.set_regions(regions) read_io_data.apply_on_atoms(update, atoms)
[docs] class LatticeSectionDefinition(PotSectionDefinition):
[docs] def __init__(self, name="LATTICE", **kwargs): V = PotValueDefinition members = [ V("SYSDIM", DefKeyword("3D", "2D")), V("SYSTYPE", DefKeyword("BULK", "LIV", "LIR")), V( "BRAVAIS", Sequence(int, str, str, str, str, allowed_values=(i.xband_data() for i in Pearson.pearsons.values())), ), V("ALAT", float), # Keywords and thus the numbering has just (or at least) 10 char long V( "SCALED_PRIMITIVE_CELL", Table( [float] * 3, numbering=Integer(prefix="A(", postfix=")", after_format="<10"), length=3, format=">22.14f", ), ), V("NQ_L", int, is_optional=True), V("A_L(3)", Array(float, length=3, format="<10"), is_optional=True), V("NQ_R", int, is_optional=True), V("A_R(3)", Array(float, length=3, format="<10"), is_optional=True), ] super().__init__(name, members, has_hidden_members=True)
[docs] def validate(self, data, why: str = "set"): d3 = data["SYSDIM"] == "3D" if d3 != (data["SYSTYPE"] == "BULK"): raise ValueError("LATTICE.SYSDIM have to be 2D to create LIV or LIR structures") op = _sections_lattice_value_is_not_none if d3 else _sections_lattice_value_is_none if op(data["NQ_L"]): raise ValueError("LATTICE.NQ_L can be specified only for 2D structures") if op(data["A_L(3)"]): raise ValueError("LATTICE.A_L(3) can be specified only for 2D structures") if op(data["NQ_R"]): raise ValueError("LATTICE.NQ_R can be specified only for 2D structures") if op(data["A_R(3)"]): raise ValueError("LATTICE.A_R(3) can be specified only for 2D structures") return True
result_class = LatticeSection
section = LatticeSectionDefinition