Source code for httk.atomistic.unitcellstructure

#
#    The high-throughput toolkit (httk)
#    Copyright (C) 2012-2015 Rickard Armiento
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
from httk.core.httkobject import HttkObject, httk_typed_property, httk_typed_property_resolve, httk_typed_property_delayed, httk_typed_init
from httk.core.reference import Reference
from httk.atomistic.cell import Cell
from httk.atomistic.assignments import Assignments
from httk.atomistic.unitcellsites import UnitcellSites
from httk.atomistic.data import spacegroups
from httk.atomistic.structureutils import *
from httk.atomistic.spacegroup import Spacegroup


[docs]class UnitcellStructure(HttkObject): """ A UnitcellStructure represents N sites of, e.g., atoms or ions, in any periodic or non-periodic arrangement. It keeps track of all the copies of the atoms within a unitcell. The structure object is meant to be immutable and assumes that no internal variables are changed after its creation. All methods that 'changes' the object creates and returns a new, updated, structure object. Naming conventions in httk.atomistic: For cells: cell = an abstract name for any reasonable representation of a 'cell' that defines the basis vectors used for representing the structure. When a 'cell' is returned, it is an object of type Cell basis = a 3x3 sequence-type with (in rows) the three basis vectors (for a periodic system, defining the unit cell, and defines the unit of repetition for the periodic dimensions) lengths_and_angles = (a,b,c,alpha,beta,gamma): the basis vector lengths and angles niggli_matrix = ((v1*v1, v2*v2, v3*v3),(2*v2*v3, 2*v1*v3, 2*v2*v3)) where v1, v2, v3 are the vectors forming the basis metric = ((v1*v1,v1*v2,v1*v3),(v2*v1,v2*v2,v2*v3),(v3*v1,v3*v2,v3*v3)) For sites: These following prefixes are used to describe types of site specifications: representative cell/rc = only representative atoms are given, which are then to be repeated by structure symmetry group to give all sites unit cell/uc = all atoms in unitcell reduced = coordinates given in cell vectors cartesian = coordinates given as direct cartesian coordinates sites = used as an abstract name for any sensible representation of a list of coordinates and a cell, when a 'sites' is returned, it is an object of type Sites counts = number of atoms of each type (one per entry in assignments) coordgroups = coordinates represented as a 3-level-list of coordinates, e.g. [[[0,0,0],[0.5,0.5,0.5]],[[0.25,0.25,0.25]]] where level-1 list = groups: one group for each equivalent atom counts and coords = one list with the number of atoms of each type (one per entry in assignments) and a 2-level list of coordinates. For assignments of atoms, etc. to sites: assignments = abstract name for any representation of assignment of atoms. When returned, will be object of type Assignment. atomic_numbers = a sequence of integers for the atomic number of each species occupations = a sequence where the assignments are *repeated* for each coordinate as needed (prefixed with uc or rc depending on which coordinates) For cell scaling: scaling = abstract name for any representation of cell scaling scale = multiply all basis vectors with this number volume = rescaling the cell such that it takes this volume For periodicity: periodicity = abstract name of a representation of periodicity pbc = 'periodic boundary conditions' = sequence of True and False for which basis vectors are periodic / non-periodic nonperiodic_vecs = integer, number of basis vectors, counted from the first, which are non-periodic For spacegroup: spacegroup = abstract name for any spacegroup representation. When returned, is of type Spacegroup. hall_symbol = specifically the hall_symbol string representation of the spacegroup """ @httk_typed_init({'assignments': Assignments, 'uc_sites': UnitcellSites, 'uc_cell': Cell}, index=['assignments', 'uc_sites', 'uc_cell']) def __init__(self, assignments=None, uc_sites=None, uc_cell=None): """ Private constructor, as per httk coding guidelines. Use Structure.create instead. """ self.assignments = assignments self.uc_cell = uc_cell self.uc_sites = uc_sites
[docs] @classmethod def create(cls, structure=None, uc_cell=None, uc_basis=None, uc_lengths=None, uc_angles=None, uc_niggli_matrix=None, uc_metric=None, uc_a=None, uc_b=None, uc_c=None, uc_alpha=None, uc_beta=None, uc_gamma=None, uc_sites=None, uc_reduced_coordgroups=None, uc_cartesian_coordgroups=None, uc_reduced_coords=None, uc_cartesian_coords=None, uc_reduced_occupationscoords=None, uc_cartesian_occupationscoords=None, uc_occupancies=None, uc_counts=None, uc_scale=None, uc_scaling=None, uc_volume=None, volume_per_atom=None, assignments=None, periodicity=None, nonperiodic_vecs=None, other_reps=None, refs=None, tags=None): """ A FullStructure represents N sites of, e.g., atoms or ions, in any periodic or non-periodic arrangement, where the positions of all cites are given (as opposed to a set of unique sites + symmetry operations). This is a swiss-army-type constructor that allows several different ways to create a FullStructure object. To create a new structure, three primary components are: - cell: defines the basis vectors in which reduced coordinates are expressed, and the unit of repetition (*if* the structure has any periodicity - see the 'periodicity' parameter) - assignments: a list of 'things' (atoms, ions, etc.) that goes on the sites in the structure - sites: a sensible representation of location / coordinates of the sites. Note: `uc_`-prefixes are consistently enforced for any quantity that would be different in a UniqueSitesStructure. This is to allow for painless change between the various structure-type objects without worrying about accidently using the wrong type of sites object. Note: see help(Structure) for parameter naming conventions, i.e., what type of object is expected given a parameter name. Input parameters: - ONE OF: 'uc_cell'; 'uc_basis', 'uc_length_and_angles'; 'uc_niggli_matrix'; 'uc_metric'; all of: uc_a,uc_b,uc_c, uc_alpha, uc_beta, uc_gamma. (cell requires a Cell object or a very specific format, so unless you know what you are doing, use one of the others.) - ONE OF: 'uc_assignments', 'uc_atomic_numbers', 'uc_occupations' (uc_assignments requires an Assignments object or a sequence.), uc_occupations repeats similar site assignments as needed - ONE OF: 'uc_sites', 'uc_coords' (IF uc_occupations OR uc_counts are also given), or 'uc_B_C', where B=reduced or cartesian, C=coordgroups, coords, or occupationscoords Notes: - occupationscoords may differ from coords by *order*, since giving occupations as, e.g., ['H','O','H'] does not necessarily have the same order of the coordinates as the format of counts+coords as (2,1), ['H','O']. - uc_sites requires a Sites object or a python list on a very specific format, (so unless you know what you are doing, use one of the others.) - ONE OF: uc_scale, uc_volume, or volume_per_atom: scale = multiply the basis vectors with this scaling factor, volume = the unit cell volume (overrides 'scale' if both are given) volume_per_atom = cell volume / number of atoms - ONE OF periodicity or nonperiodic_vecs """ if structure is not None: UnitcellStructure.use(structure) #TODO: Handle that vollume_per_atom is given instead, move this block below sorting out sites and if uc_volume is not set, #calculate a new volume if uc_cell is not None: Cell.use(uc_cell) else: uc_cell = Cell.create(cell=uc_cell, basis=uc_basis, metric=uc_metric, niggli_matrix=uc_niggli_matrix, a=uc_a, b=uc_b, c=uc_c, alpha=uc_alpha, beta=uc_beta, gamma=uc_gamma, lengths=uc_lengths, angles=uc_angles, scale=uc_scale, scaling=uc_scaling, volume=uc_volume) if uc_sites is not None: uc_sites = UnitcellSites.use(uc_sites) else: if uc_reduced_coordgroups is None and \ uc_reduced_coords is None and \ uc_occupancies is not None: # Structure created by occupationscoords and occupations, this is a slightly tricky representation if uc_reduced_occupationscoords is not None: assignments, uc_reduced_coordgroups = occupations_and_coords_to_assignments_and_coordgroups(uc_reduced_occupationscoords, uc_occupancies) if uc_reduced_coordgroups is not None or \ uc_reduced_coords is not None: try: uc_sites = UnitcellSites.create(reduced_coordgroups=uc_reduced_coordgroups, reduced_coords=uc_reduced_coords, counts=uc_counts, periodicity=periodicity, occupancies=uc_occupancies) except Exception: uc_sites = None else: uc_sites = None if uc_sites is None and uc_reduced_coordgroups is None and \ uc_reduced_coords is None and uc_reduced_occupationscoords is None: # Cartesian coordinate input must be handled here in structure since scalelessstructure knows nothing about cartesian coordinates... if uc_cartesian_coordgroups is None and uc_cartesian_coords is None and \ uc_occupancies is not None and uc_cartesian_occupationscoords is not None: assignments, uc_cartesian_coordgroups = occupations_and_coords_to_assignments_and_coordgroups(uc_cartesian_occupationscoords, uc_occupancies) if uc_cartesian_coords is not None and uc_cartesian_coordgroups is None: uc_cartesian_coordgroups = coords_and_counts_to_coordgroups(uc_cartesian_coords, uc_counts) if uc_cell is not None: uc_reduced_coordgroups = coordgroups_cartesian_to_reduced(uc_cartesian_coordgroups, uc_cell) if assignments is not None: assignments = Assignments.use(assignments) if uc_sites is None: raise Exception("Structure.create: not enough information for information about sites.") new = cls(assignments=assignments, uc_sites=uc_sites, uc_cell=uc_cell) return new
[docs] @classmethod def use(cls, other): from httk.atomistic.structure import Structure from httk.atomistic.representativestructure import RepresentativeStructure if isinstance(other, UnitcellStructure): return other elif isinstance(other, Structure): return UnitcellStructure(other.assignments, other.uc_sites, other.uc_cell) elif isinstance(other, RepresentativeStructure): return cls.use(Structure.use(other)) raise Exception("RepresentativeStructure.use: do not know how to use object of class:"+str(other.__class__))
@property def uc_cartesian_occupationscoords(self): raise Exception("UnitcellStructure.uc_cartesian_occupationscoords: not implemented") return @property def uc_cartesian_coordgroups(self): return self.uc_sites.get_cartesian_coordgroups(self.uc_cell) @property def uc_cartesian_coords(self): return self.uc_sites.get_cartesian_coords(self.uc_cell) @property def uc_reduced_coords(self): return self.uc_sites.reduced_coords @property def uc_lengths_and_angles(self): return [self.uc_a, self.uc_b, self.uc_c, self.uc_alpha, self.uc_beta, self.uc_gamma] @httk_typed_property(float) def uc_a(self): return self.uc_cell.a @httk_typed_property(float) def uc_b(self): return self.uc_cell.b @httk_typed_property(float) def uc_c(self): return self.uc_cell.c @httk_typed_property(float) def uc_alpha(self): return self.uc_cell.alpha @httk_typed_property(float) def uc_beta(self): return self.uc_cell.beta @httk_typed_property(float) def uc_gamma(self): return self.uc_cell.gamma @property def uc_basis(self): return self.uc_cell.basis @httk_typed_property(float) def uc_volume(self): return self.uc_cell.volume @httk_typed_property(float) def uc_volume_per_atom(self): return self.uc_cell.volume/self.uc_sites.total_number_of_atoms @httk_typed_property(int) def uc_cell_orientation(self): return self.uc_cell.orientation @httk_typed_property((bool, 1, 3)) def pbc(self): return self.uc_sites.pbc @property def uc_reduced_coordgroups(self): return self.uc_sites.reduced_coordgroups @httk_typed_property([int]) def uc_counts(self): return self.uc_sites.counts
[docs] def transform(self, matrix, max_search_cells=20, max_atoms=1000): return transform(self, matrix, max_search_cells=max_search_cells, max_atoms=max_atoms)
def __str__(self): return "<httk UnitcellStructure object:\n "+str(self.uc_cell)+"\n "+str(self.assignments)+"\n "+str(self.uc_sites)+"\n>"