Example #1
0
    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
Example #2
0
 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)
Example #3
0
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
Example #4
0
    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)
Example #5
0
    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)