def pop_planes(geometry, kwargs): # Convert miller index specifications to normal vectors miller_defs = kwargs.pop("planes_miller", None) if miller_defs is not None: if np.any(np.all(abs(miller_defs[:,0:3]) < EPSILON, axis=1)): error("Emtpy miller index tuple") miller_defs[:,0:3] = miller_to_normal( np.dot(geometry.latvecs, geometry.bravais_cell), miller_defs[:,0:3]) else: miller_defs = np.zeros((0, 4), dtype=float) # Convert plane normal vector specifications into cartesian coords. normal_defs = kwargs.pop("planes_normal", None) if normal_defs is not None: normal_defs[:,0:3] = geometry.coord_transform( normal_defs[:,0:3], kwargs.pop("planes_normal_coordsys", "lattice")) if np.any(np.all(abs(normal_defs[:,0:3]) < EPSILON, axis=1)): error("Emtpy normal vector definition") else: normal_defs = np.zeros((0, 4), dtype=float) # Append two defintions planes_normal = np.vstack(( miller_defs, normal_defs )) return planes_normal
def __init__(self, geometry, period, **kwargs): """Construct Periodic1DPrism instance. Keyword args: shift_vector: Origin of the body. planes_normal: Plane definitions with normal vectors and distances. planes_miller: Plane definitions with miller indices and distances. """ # Check for plane normals not orthogonal to axis (plane cuts axis) self.periodicity = period axis = self.periodicity.get_axis("cartesian") planes_normal = self.pop_planes(geometry, kwargs) projections = abs(np.dot(planes_normal[:,:3], axis.transpose())) if np.any(projections > EPSILON): error("Some plane(s) are not parallel to axis") # Determine basal planes. Shift them with a small amount to make sure # atoms do not stay outside due to arithmetic errors. axisnorm = np.linalg.norm(axis[0]) axis0 = axis[0] / axisnorm basal_planes = np.array( [[ axis0[0], axis0[1], axis0[2], -PERIODIC_TOLERANCE ], [ axis0[0], axis0[1], axis0[2], axisnorm + PERIODIC_TOLERANCE ]]) # Extend planes by basal planes and call base class planes_normal = np.vstack(( basal_planes, planes_normal )) kwargs["planes_normal"] = planes_normal kwargs["planes_normal_coordsys"] = "cartesian" Polyhedron.__init__(self, geometry, period, **kwargs)
def __init__(self, geometry, period, **kwargs): """Construct Periodic1DPrism instance. Keyword args: shift_vector: Origin of the body. planes_normal: Plane definitions with normal vectors and distances. planes_miller: Plane definitions with miller indices and distances. """ # Check for plane normals not orthogonal to axis (plane cuts axis) self.periodicity = period axis = self.periodicity.get_axis("cartesian") planes_normal = self.pop_planes(geometry, kwargs) projections = abs(np.dot(planes_normal[:, :3], axis.transpose())) if np.any(projections > EPSILON): error("Some plane(s) are not parallel to axis") # Determine basal planes. Shift them with a small amount to make sure # atoms do not stay outside due to arithmetic errors. axisnorm = np.linalg.norm(axis[0]) axis0 = axis[0] / axisnorm basal_planes = np.array( [[axis0[0], axis0[1], axis0[2], -PERIODIC_TOLERANCE], [axis0[0], axis0[1], axis0[2], axisnorm + PERIODIC_TOLERANCE]]) # Extend planes by basal planes and call base class planes_normal = np.vstack((basal_planes, planes_normal)) kwargs["planes_normal"] = planes_normal kwargs["planes_normal_coordsys"] = "cartesian" Polyhedron.__init__(self, geometry, period, **kwargs)
def pop_planes(geometry, kwargs): # Convert miller index specifications to normal vectors miller_defs = kwargs.pop("planes_miller", None) if miller_defs is not None: if np.any(np.all(abs(miller_defs[:, 0:3]) < EPSILON, axis=1)): error("Emtpy miller index tuple") miller_defs[:, 0:3] = miller_to_normal( np.dot(geometry.latvecs, geometry.bravais_cell), miller_defs[:, 0:3]) else: miller_defs = np.zeros((0, 4), dtype=float) # Convert plane normal vector specifications into cartesian coords. normal_defs = kwargs.pop("planes_normal", None) if normal_defs is not None: normal_defs[:, 0:3] = geometry.coord_transform( normal_defs[:, 0:3], kwargs.pop("planes_normal_coordsys", "lattice")) if np.any(np.all(abs(normal_defs[:, 0:3]) < EPSILON, axis=1)): error("Emtpy normal vector definition") else: normal_defs = np.zeros((0, 4), dtype=float) # Append two defintions planes_normal = np.vstack((miller_defs, normal_defs)) return planes_normal
def cell_axis_from_superlattice(superlattice, latvecs): """Returns three vectors spawning a supercell similar to a given one. Args: superlattice: Lattice vectors of the supercell. latvecs: Original lattice vectors. Returns: Three vectors in relative coordinates (respective the original lattice vectors) which spawn a superlattice similar to the specified one. """ # Transformation to build superlattice from current lattice vectors. trans = np.dot(superlattice, np.linalg.inv(latvecs)) # Rescale transformation matrix to contain only elements >= 1.0. nonzero = np.nonzero(np.greater(np.abs(trans), nc.EPSILON)) trans_nonzero = trans[nonzero] minelemind = np.argmin(np.abs(trans_nonzero)) trans_nonzero /= abs(trans_nonzero[minelemind]) # If biggest element greater tolerance: we would leave 64 bit integer range. if np.any(np.greater(np.abs(trans_nonzero), 11.0)): error("Target lattice coefficients too big") # Scale up transformation to ensure that all components are very close to # integers, if superlattice and lattice are commensurable factor = np.prod(np.arange(2, 11 + 1, dtype=int)) trans_nonzero *= factor trans_nonzero_int = np.around(trans_nonzero).astype(int) # Check, whether all coefficients are close to integers. if np.any( np.abs(trans_nonzero_int - trans_nonzero) > nc.RELATIVE_PERIODIC_TOLERANCE): error("Target lattice and source lattices probably incompatible") # Simplify transformation matrix with greatest common divisor. factor = gcd(abs(trans_nonzero_int.flatten())) trans_nonzero_int /= factor # Fill nonzero components into axis. axis = np.zeros((3, 3), dtype=int) axis[nonzero] = trans_nonzero_int return axis
def cell_axis_from_superlattice(superlattice, latvecs): """Returns three vectors spawning a supercell similar to a given one. Args: superlattice: Lattice vectors of the supercell. latvecs: Original lattice vectors. Returns: Three vectors in relative coordinates (respective the original lattice vectors) which spawn a superlattice similar to the specified one. """ # Transformation to build superlattice from current lattice vectors. trans = np.dot(superlattice, np.linalg.inv(latvecs)) # Rescale transformation matrix to contain only elements >= 1.0. nonzero = np.nonzero(np.greater(np.abs(trans), nc.EPSILON)) trans_nonzero = trans[nonzero] minelemind = np.argmin(np.abs(trans_nonzero)) trans_nonzero /= abs(trans_nonzero[minelemind]) # If biggest element greater tolerance: we would leave 64 bit integer range. if np.any(np.greater(np.abs(trans_nonzero), 11.0)): error("Target lattice coefficients too big") # Scale up transformation to ensure that all components are very close to # integers, if superlattice and lattice are commensurable factor = np.prod(np.arange(2, 11 + 1, dtype=int)) trans_nonzero *= factor trans_nonzero_int = np.around(trans_nonzero).astype(int) # Check, whether all coefficients are close to integers. if np.any(np.abs(trans_nonzero_int - trans_nonzero) > nc.RELATIVE_PERIODIC_TOLERANCE): error("Target lattice and source lattices probably incompatible") # Simplify transformation matrix with greatest common divisor. factor = gcd(abs(trans_nonzero_int.flatten())) trans_nonzero_int /= factor # Fill nonzero components into axis. axis = np.zeros((3, 3), dtype=int) axis[nonzero] = trans_nonzero_int return axis
def fromdict(cls, inidict): """Initliazes geometry from dict with type checking. Args: cls: Class type. inidict: Dictionary with settings """ if "lattice_vectors" not in inidict: error("latvecs not defined.") if "basis" not in inidict: error("Basis not defined.") try: latvecs = np.array( [float(s) for s in inidict["lattice_vectors"].split()]) latvecs.shape = (3, 3) except ValueError: error("Invalid lattice vector specification.") if abs(np.linalg.det(latvecs)) < EPSILON: error("Linearly dependent lattice vectors.") basis = inidict["basis"].split() basis_names = [ basis.pop(idx) for idx in range(0, len(basis) * 3 // 4, 3) ] try: basis = np.array([float(s) for s in basis]) basis.shape = (-1, 3) except ValueError: error("Invalid basis specification.") basis_names_idx = range(len(basis)) basis_coordsys = inidict.get("basis_coordsys", "lattice") if basis_coordsys not in ["lattice", "cartesian"]: error("Invalid coordinate system specification.") shiftstr = inidict.get("shift_vector", "0.0 0.0 0.0") try: shift = np.array([float(ss) for ss in shiftstr.split()]) shift.shape = (3, ) except ValueError: error("Invalid shift vector for basis") shift_coordsys = inidict.get("shift_vector_coordsys", "lattice") bravais_cell = inidict.get("bravais_cell", "1 0 0 0 1 0 0 0 1") try: bravais_cell = np.array([float(ss) for ss in bravais_cell.split()]) bravais_cell.shape = (3, 3) except ValueError: error("Invalid Bravais cell definition") return cls(latvecs, basis, basis_names_idx, basis_names, basis_coordsys, shift, shift_coordsys, bravais_cell)
def fromdict(cls, inidict): """Initliazes geometry from dict with type checking. Args: cls: Class type. inidict: Dictionary with settings """ if "lattice_vectors" not in inidict: error("latvecs not defined.") if "basis" not in inidict: error("Basis not defined.") try: latvecs = np.array( [ float(s) for s in inidict["lattice_vectors"].split() ]) latvecs.shape = (3, 3) except ValueError: error("Invalid lattice vector specification.") if abs(np.linalg.det(latvecs)) < EPSILON: error("Linearly dependent lattice vectors.") basis = inidict["basis"].split() basis_names=[ basis.pop(idx) for idx in range(0, len(basis) * 3 // 4, 3) ] try: basis = np.array([ float(s) for s in basis ]) basis.shape= (-1, 3) except ValueError: error("Invalid basis specification.") basis_names_idx = range(len(basis)) basis_coordsys = inidict.get("basis_coordsys", "lattice") if basis_coordsys not in ["lattice", "cartesian"]: error("Invalid coordinate system specification.") shiftstr = inidict.get("shift_vector", "0.0 0.0 0.0") try: shift = np.array([ float(ss) for ss in shiftstr.split() ]) shift.shape = (3, ) except ValueError: error("Invalid shift vector for basis") shift_coordsys = inidict.get("shift_vector_coordsys", "lattice") bravais_cell = inidict.get("bravais_cell", "1 0 0 0 1 0 0 0 1") try: bravais_cell = np.array( [ float(ss) for ss in bravais_cell.split() ]) bravais_cell.shape = (3, 3) except ValueError: error("Invalid Bravais cell definition") return cls(latvecs, basis, basis_names_idx, basis_names, basis_coordsys, shift, shift_coordsys, bravais_cell)
def fromdict(cls, geometry, inidict): """Builds instance from dictionary.""" period_type = inidict.get("period_type", "0D") if period_type not in ["0D", "1D", "2D", "3D"]: error("Invalid periodicty type '" + period_type + "'") # 0D periodicity if period_type == "0D": return cls(geometry, "0D") # 1D periodicity if period_type == "1D": axis = inidict.get("axis", None) if axis is None: error("Missing axis specification for 1D periodicity.") try: axis = np.array([int(s) for s in axis.split()]) axis.shape = (1, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") # 2D periodicity elif period_type == "2D": axis = inidict.get("axis", None) miller = inidict.get("miller_indices", None) if axis is None and miller is None: error("Either 'axis' or 'miller_indices' needed for " "periodicity specification.") elif axis is not None and miller is not None: error( "Only one of the keywords 'axis' or 'miller_indices' can " "be used for periodicity specification.") if miller: try: miller = np.array([int(s) for s in miller.split()]) miller.shape = (3, ) except ValueError: error("Invalid miller index for 2D periodicity") if np.all(miller == 0): error("Invalid miller index for 2D periodicity") axis = plane_axis_from_miller(miller) else: try: axis = np.array([int(s) for s in axis.split()]) axis.shape = (2, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") if np.all(np.cross(axis[0], axis[1]) == 0): error("Axis are parallel.") # 3D periodicity else: axis = inidict.get("axis", None) superlattice = inidict.get("superlattice", None) if axis is None and superlattice is None: error("Either 'axis' or 'superlattice' needed for " "periodicity specification.") elif axis is not None and superlattice is not None: error("Only one of the keywords 'axis' or 'superlattice'" "can be used for periodicity specification.") if superlattice: try: superlattice = np.array( [float(s) for s in superlattice.split()]) superlattice.shape = (3, 3) except ValueError: error("Invalid superlattice specification") if np.abs(np.linalg.det(superlattice)) < nc.EPSILON: error("Linearly dependent superlattice vectors") axis = cell_axis_from_superlattice( superlattice, np.dot(geometry.bravais_cell, geometry.latvecs)) else: try: axis = np.array([int(s) for s in axis.split()]) axis.shape = (3, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") if np.abs(np.linalg.det(axis)) < nc.EPSILON: error("Linearly dependent axis") # Switch back to primitive lattice, if necessary if np.any(geometry.bravais_cell != np.eye(3, dtype=int)): printstatus("Axis with respect to Bravais lattice:") for vec in axis: printstatus( "{:3d} {:3d} {:3d}".format(*[int(ss) for ss in vec]), indentlevel=1) axis = np.dot(axis, geometry.bravais_cell) # Get smallest possible unit cell for ii in range(len(axis)): divisor = gcd(abs(axis[ii])) axis[ii] = axis[ii] // divisor printstatus("Axis with respect to primitive lattice:") for vec in axis: printstatus("{:3d} {:3d} {:3d}".format(*[int(ss) for ss in vec]), indentlevel=1) # Repeat unit cell cellrep = inidict.get("axis_repetition", None) if cellrep: try: cellrep = np.array([float(s) for s in cellrep.split()]) cellrep.shape = (int(period_type[0]), ) except ValueError: error("Invalid axis repetition specification.") axis = np.array(axis * cellrep[:, np.newaxis], int) printstatus("Axis repetition:" + " ".join(["{:3d}".format(int(s)) for s in cellrep])) return cls(geometry, period_type, axis)
def fromdict(cls, geometry, inidict): """Builds instance from dictionary.""" period_type = inidict.get("period_type", "0D") if period_type not in [ "0D", "1D", "2D", "3D"]: error("Invalid periodicty type '" + period_type + "'") # 0D periodicity if period_type == "0D": return cls(geometry, "0D") # 1D periodicity if period_type == "1D": axis = inidict.get("axis", None) if axis is None: error("Missing axis specification for 1D periodicity.") try: axis = np.array([ int(s) for s in axis.split() ]) axis.shape = (1, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") # 2D periodicity elif period_type == "2D": axis = inidict.get("axis", None) miller = inidict.get("miller_indices", None) if axis is None and miller is None: error("Either 'axis' or 'miller_indices' needed for " "periodicity specification.") elif axis is not None and miller is not None: error("Only one of the keywords 'axis' or 'miller_indices' can " "be used for periodicity specification.") if miller: try: miller = np.array([ int(s) for s in miller.split() ]) miller.shape = (3, ) except ValueError: error("Invalid miller index for 2D periodicity") if np.all(miller == 0): error("Invalid miller index for 2D periodicity") axis = plane_axis_from_miller(miller) else: try: axis = np.array([ int(s) for s in axis.split() ]) axis.shape = (2, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") if np.all(np.cross(axis[0], axis[1]) == 0): error("Axis are parallel.") # 3D periodicity else: axis = inidict.get("axis", None) superlattice = inidict.get("superlattice", None) if axis is None and superlattice is None: error("Either 'axis' or 'superlattice' needed for " "periodicity specification.") elif axis is not None and superlattice is not None: error("Only one of the keywords 'axis' or 'superlattice'" "can be used for periodicity specification.") if superlattice: try: superlattice = np.array([ float(s) for s in superlattice.split() ]) superlattice.shape = (3, 3) except ValueError: error("Invalid superlattice specification") if np.abs(np.linalg.det(superlattice)) < nc.EPSILON: error("Linearly dependent superlattice vectors") axis = cell_axis_from_superlattice(superlattice, np.dot(geometry.bravais_cell, geometry.latvecs)) else: try: axis = np.array([ int(s) for s in axis.split() ]) axis.shape = (3, 3) except ValueError: error("Invalid axis specification.") if np.all(axis == 0): error("Invalid axis direction.") if np.abs(np.linalg.det(axis)) < nc.EPSILON: error("Linearly dependent axis") # Switch back to primitive lattice, if necessary if np.any(geometry.bravais_cell != np.eye(3, dtype=int)): printstatus("Axis with respect to Bravais lattice:") for vec in axis: printstatus("{:3d} {:3d} {:3d}".format( *[ int(ss) for ss in vec ]), indentlevel=1) axis = np.dot(axis, geometry.bravais_cell) # Get smallest possible unit cell for ii in range(len(axis)): divisor = gcd(abs(axis[ii])) axis[ii] /= divisor printstatus("Axis with respect to primitive lattice:") for vec in axis: printstatus("{:3d} {:3d} {:3d}".format( *[ int(ss) for ss in vec ]), indentlevel=1) # Repeat unit cell cellrep = inidict.get("axis_repetition", None) if cellrep: try: cellrep = np.array([ float(s) for s in cellrep.split() ]) cellrep.shape = (int(period_type[0]), ) except ValueError: error("Invalid axis repetition specification.") axis *= cellrep[:,np.newaxis] printstatus("Axis repetition:" + " ".join([ "{:3d}".format(int(s)) for s in cellrep ])) return cls(geometry, period_type, axis)