示例#1
0
    def test_a_init_unit_cube(self):
        # instantiate a cubic lattice with unit-length vectors
        # and its reciprocal lattice, still cubic with 2π-length vectors
        d, r = make_dr(1, 1, 1)
        # creating a BrillouinZone objects requires that we pass the reciprocal
        # lattice object, and passing a Direct object is a TypeError:
        with self.assertRaises(TypeError):
            s.BrillouinZone(d)
        # its first Brillouin zone is a cube in reciprocal space
        bz = s.BrillouinZone(r)
        # with six faces, defined by: (00̄1),(0̄10),(̄100),(100),(010),(001)
        p = bz.points
        self.assertEqual(p.ndim, 2)
        self.assertEqual(p.shape[0], 6) # and there is one for each of the six faces
        self.assertEqual(p.shape[1], 3) # the face vectors are 3-vectors
        n = bz.normals
        self.assertEqual(n.ndim, 2)
        self.assertEqual(n.shape[0], 6) # and there is one for each of the six faces
        self.assertEqual(n.shape[1], 3) # the face normals are 3-vectors
        n_dot_p = np.array([np.dot(x/norm(x),y/norm(y)) for x,y in zip(n,p)])
        self.assertTrue((n_dot_p == 1.0).all())

        expected = np.array([[-1,0,0],[0,-1,0],[0,0,-1],[0,0,1],[0,1,0],[1,0,0]])
        self.assertTrue(vector_lists_match(p, expected/2))
        self.assertTrue(vector_lists_match(np.array([x/norm(x) for x in n]), expected))
        #
        # the vertices of the first Brillouin zone are the 8 corners of the 1/2-unit cube:
        expected = np.array([[-1,-1,-1], [-1,-1, 1], [-1, 1,-1], [-1, 1, 1], [1,-1,-1], [1,-1, 1], [1, 1,-1], [1, 1, 1]])/2
        verts = bz.vertices
        self.assertEqual(verts.ndim, 2)
        self.assertEqual(verts.shape[0], 8)
        self.assertEqual(verts.shape[1], 3)
        self.assertTrue(vector_lists_match(verts, expected))
示例#2
0
def setup_grid(iscomplex=False, halfN=(2, 2, 2)):
    """Create a grid object for interpolating."""
    rlat = s.Reciprocal((1, 1, 1), np.array([1, 1, 1])*np.pi/2)
    bz = s.BrillouinZone(rlat)
    if iscomplex:
        bzg = s.BZGridQcomplex(bz, halfN=halfN)
    else:
        bzg = s.BZGridQ(bz, halfN=halfN)
    return bzg
示例#3
0
 def test_c_moveinto_hexagonal(self):
     d, r = make_dr(3, 3, 9, np.pi/2, np.pi/2, np.pi*2/3)
     bz = s.BrillouinZone(r)
     Q = (np.random.rand(100, 3)-0.5) * 10 # this is a uniform distribution over [-5, 5)
     if bz.isinside(Q).all(): # this is vanishingly-unlikely
         Q += 100.0
     self.assertFalse( bz.isinside(Q).all() )
     (q, tau) = bz.moveinto(Q)
     self.assertTrue( bz.isinside(q).all() )
     self.assertAlmostEqual( np.abs(Q-q-tau).sum(), 0)
示例#4
0
 def test_b_isinside_hexagonal(self):
     d, r = make_dr(3, 3, 9, np.pi/2, np.pi/2, np.pi*2/3)
     bz = s.BrillouinZone(r)
     # Q = (np.random.rand(1000, 3)-0.5) * 2 # this is a uniform distribution over [-1, 1)
     x=np.linspace(-1, 1, 100)
     X, Y, Z=np.meshgrid(x, x, 0)
     Q = np.stack( (X.flatten(), Y.flatten(), Z.flatten()), axis=-1)
     Qin = bz.isinside(Q)
     B = r.B
     X = np.stack( [ np.matmul(B, v) for v in Q[Qin,:] ] )
示例#5
0
 def test_i_iron_self_consistency(self):
     """Test with data as iron spinwaves, but test only *at* grid points."""
     d = s.Direct((2.87, 2.87, 2.87), np.pi/2*np.array((1, 1, 1)), "Im-3m")
     r = d.star
     bz = s.BrillouinZone(r)
     bzg = s.BZGridQcomplex(bz, halfN=(1, 1, 1))
     Q = bzg.rlu
     bzg.fill(fe_dispersion(Q),[1,])
     intres = bzg.interpolate_at(Q, False, False)
     antres = fe_dispersion(Q)
     self.assertTrue(np.isclose(intres, antres).all())
示例#6
0
 def test_b_isinside_unit_cube(self):
     d, r = make_dr(1, 1, 1)
     bz = s.BrillouinZone(r)
     # the first Brillouin zone of this unit-cube is bounded by
     # {(00̄1),(0̄10),(̄100),(100),(010),(001)}/2
     face_centres = np.array([ [-1, 0, 0], [0,-1, 0], [0, 0,-1], [0, 0, 1], [0, 1, 0], [1, 0, 0] ], dtype='double')/2
     self.assertTrue( (bz.isinside(face_centres)).all() )
     # including the vertices (since they are the corners of the zone)
     corners = np.array([[-1,-1,-1], [-1,-1, 1], [-1, 1,-1], [-1, 1, 1], [1,-1,-1], [1,-1, 1], [1, 1,-1], [1, 1, 1]], dtype='double')/2
     self.assertTrue( (bz.isinside(corners)).all() )
     # so all points with h, k, and l in the range [-0.5, 0.5] are in the zone
     Q = np.random.rand(100, 3) - 0.5 # this is a uniform distribution over [-0.5, 0.5) -- close enough
     self.assertTrue( bz.isinside(Q).all() )
     self.assertFalse( bz.isinside(Q+5).all() )
示例#7
0
    def test_a_init_hexagonal(self):
        # instantiate a hexagonal lattice and its reciprocal lattice, still hexagonal
        d, r = make_dr(3, 3, 9, np.pi/2, np.pi/2, np.pi*2/3)
        # creating a BrillouinZone objects requires that we pass the reciprocal
        # lattice object, and passing a Direct object is a TypeError:
        with self.assertRaises(TypeError):
            s.BrillouinZone(d)
        # its first Brillouin zone is a cube in reciprocal space
        bz = s.BrillouinZone(r)
        # with eight faces, defined by: (̄100),(̄110),(0̄10),(001),(001),(010),(1̄10),(100)
        p = bz.points
        self.assertEqual(p.ndim, 2)
        self.assertEqual(p.shape[0], 8) # and there is one for each of the eight faces
        self.assertEqual(p.shape[1], 3) # the face vectors are 3-vectors
        n = bz.normals
        self.assertEqual(n.ndim, 2)
        self.assertEqual(n.shape[0], 8) # and there is one for each of the six faces
        self.assertEqual(n.shape[1], 3) # the face normals are 3-vectors
        n_dot_p = np.array([np.dot(x/norm(x),y/norm(y)) for x,y in zip(n,p)])
        self.assertTrue(np.allclose(n_dot_p, 1.))

        expected= np.array([ [-1, 0, 0],[-1, 1, 0],[0,-1, 0],[0, 0,-1],[0, 0, 1],[0, 1, 0],[1,-1, 0],[1, 0, 0] ])
        self.assertTrue(vector_lists_match(p, expected/2))
        n_compare = np.array([x/np.max(np.abs(x)) for x in n])
        self.assertTrue(vector_lists_match(n_compare, expected))
        self.assertTrue( (bz.isinside(expected/2)).all() )
        #
        # the vertices of the first Brillouin zone are the 12 corners of the hexagonal-prism:
        expected = np.array([[-4, 2,-3],[-2,-2,-3],[-4, 2, 3],[-2,-2, 3],[-2, 4,-3],[-2, 4, 3],
                             [ 2,-4,-3],[ 2,-4, 3],[ 2, 2,-3],[ 4,-2,-3],[ 2, 2, 3],[ 4,-2, 3]])/6
        verts = bz.vertices
        self.assertEqual(verts.ndim, 2)
        self.assertEqual(verts.shape[0], 12)
        self.assertEqual(verts.shape[1], 3)
        self.assertTrue(vector_lists_match(verts, expected))
        self.assertTrue( (bz.isinside(expected)).all() )
示例#8
0
def test_aflow_crystaldatabase():
    tested = 0
    failed = 0
    errored = 0
    failed_afl = []
    failed_ratio = []
    errored_afl = []
    errored_arg = []
    hall_groups_passed = np.zeros(530, dtype='int')
    hall_groups_failed = np.zeros(530, dtype='int')
    for afl in get_aflow_lattices():
        dlat = s.Direct(afl[1], afl[2],
                        afl[0])  # use the pre-determined Hall number
        i = dlat.hall
        try:
            bz = s.BrillouinZone(dlat.star)
            vol_bz = bz.polyhedron.volume
            vol_ir = bz.ir_polyhedron.volume
            tested += 1
            if not np.isclose(vol_ir, vol_bz / s.PointSymmetry(i).size):
                failed += 1
                failed_afl.append(afl)
                failed_ratio.append(vol_ir / vol_bz * s.PointSymmetry(i).size)
                hall_groups_failed[i - 1] += 1
            else:
                hall_groups_passed[i - 1] += 1
        except Exception as err:
            errored += 1
            errored_afl.append(afl)
            errored_arg.append(err.args)
    if failed > 0:
        print("\nFailed to find correct irreducible Brillouin zone for",
              failed, "out of", tested, "lattices")
        for file, rat in zip(failed_afl, failed_ratio):
            print(file, rat)
    if errored > 0:
        print("\nException raised for", errored, "out of", tested, "lattices")
        for file, arg in zip(errored_afl, errored_arg):
            print(file, arg)
    print("\nHall groups passed (total =", hall_groups_passed.sum(), "of",
          tested, "tested)")
    encoded_hgp = [n2chr(x) for x in hall_groups_passed]
    for x in [encoded_hgp[i * 53:(i + 1) * 53] for i in range(10)]:
        print(''.join(x))
示例#9
0
def make_drbz(a, b, c, al=np.pi / 2, be=np.pi / 2, ga=np.pi / 2):
    """Make a Direct Reicprocal and BrillouinZone object."""
    d = s.Direct(a, b, c, al, be, ga)
    r = d.star
    bz = s.BrillouinZone(r)
    return (d, r, bz)
示例#10
0
 def get_conventional_BrillouinZone(self):
     return b.BrillouinZone(self.get_conventional_Direct().star)
示例#11
0
 def get_input_BrillouinZone(self):
     return b.BrillouinZone(self.get_input_Direct().star)
示例#12
0
                        Z[np.newaxis, -1] + dX[np.newaxis, -1]),
                       axis=0)
    dY = np.diff(Z, axis=1) / 2
    Z = np.concatenate(
        (Z[:, :-1] - dY, Z[:, np.newaxis, -1] - dY[:, np.newaxis, -1],
         Z[:, np.newaxis, -1] + dY[:, np.newaxis, -1]),
        axis=1)
    return Z


def pcolormesh(X, Y, Z, *args, **kwargs):
    return pp.pcolormesh(cen2corner(X), cen2corner(Y), Z, *args, **kwargs)


dlat = brille.Direct((5., 5., 5.), (90., 90., 90.), 525)
bz = brille.BrillouinZone(dlat.star)
nb = load_interpolation_data('nb')

# Next investigate now choice of maximum tetrahedra size and trellis size
# effect point-interpolation time
qx, qy = np.mgrid[1 - 0.3:1 + 0.3:0.005, 1 - 0.3:1 + 0.3:0.005]

inshape = qx.shape
px = cen2corner(qx)
py = cen2corner(qy)

qx = qx.reshape(qx.size, 1)
qy = qy.reshape(qy.size, 1)
qxyz = np.concatenate((qx, qy, 0 * qx), axis=1)
energy = 4.1 + np.zeros_like(qx)
示例#13
0
def create_bz(*args,
              is_reciprocal=False,
              use_primitive=True,
              search_length=1,
              time_reversal_symmetry=False,
              wedge_search=True,
              **kwargs):
    """
    Construct a BrillouinZone object. 

    Parameters
    ----------
    a, b, c : float
        Lattice parameters as separate floating point values
    lens : (3,) :py:class:`numpy.ndarray` or list
        Lattice parameters as a 3-element array or list
    alpha, beta, gamma : float
        Lattice angles in degrees or radians as separate floating point values
        Brille tries to determine if the input is in degrees or radians
        by looking at its magnitude. If the values are all less than PI it
        assumes the angles are in radians otherwise it assumes degrees
    angs : (3,) :py:class:`numpy.ndarray` or list
        Lattice angles in degrees or radians as a 3-element array or list
    lattice_vectors : (3, 3) :py:class:`numpy.ndarray` or list of list
        The lattice vectors as a 3x3 matrix, array or list of list
    spacegroup: str or int
        The spacegroup in either International Tables (Hermann-Mauguin)
        notation or a Hall symbol or an integer Hall number.
    is_reciprocal : bool, keyword-only optional (default: False)
        Whether the lattice parameters or lattice vectors refers to a 
        reciprocal rather than direct lattice. If True, a/b/c/lens should
        be in reciprocal Angstrom, otherwise they should be in Angstrom
    use_primitive : bool, keyword-only optional (default: True)
        Whether the primitive (or conventional) lattice should be used
    search_length : int, keyword-only optional (default: 1)
        An integer to control how-far the vertex-finding algorithm should
        search in τ-index. The default indicates that (1̄1̄1̄), (1̄1̄0), (1̄1̄1),
        (1̄0̄1), ..., (111) are included.
    time_reversal_symmetry : bool, keyword-only optional (default: False)
        Whether to include time-reversal symmetry as an operation to
        determine the irreducible Brillouin zone
    wedge_search : bool, keyword-only optional (default: True)
        If true, return an irreducible first Brillouin zone,
        otherwise just return the first Brillouin zone

    Note
    ----
    Note that the required lattice parameters must be specified as:
        - EITHER ``create_bz(a, b, c, alpha, beta, gamma, spacegroup, ...)``
        - OR     ``create_bz(lens, angs, spacegroup, ...)``
        - OR     ``create_bz(lattice_vectors, spacegroup, ...)``

    E.g. you cannot mix specifing `a`, `b`, `c`, and `angs` etc.
    """
    # Take keyword arguments in preference to positional ones
    a, b, c, alpha, beta, gamma, lens, angs = (
        kwargs.pop(pname, None)
        for pname in ['a', 'b', 'c', 'alpha', 'beta', 'gamma', 'lens', 'angs'])
    no_lat_kw_s = any([v is None for v in [a, b, c, alpha, beta, gamma]])
    no_lat_kw_v = any([v is None for v in [lens, angs]])
    if no_lat_kw_v and not no_lat_kw_s:
        lens, angs = ([a, b, c], [alpha, beta, gamma])
    lattice_vectors = kwargs.pop('lattice_vectors', None)
    spacegroup = kwargs.pop('spacegroup', None)
    # Parse positional arguments
    spg_id = 0
    if no_lat_kw_s and no_lat_kw_v and lattice_vectors is None:
        if np.shape(args[0]) == ():
            lens, angs = (args[:3], args[3:6])
            spg_id = 6
        elif np.shape(args[0]) == (3, ):
            lens, angs = tuple(args[:2])
            spg_id = 2
        elif np.shape(args[0]) == (3, 1) or np.shape(args[0]) == (1, 3):
            lens, angs = tuple(args[:2])
            lens = np.squeeze(np.array(lens))
            angs = np.squeeze(np.array(angs))
            spg_id = 2
        elif np.shape(args[0]) == (3, 3):
            lattice_vectors = args[0]
            spg_id = 1
        else:
            raise ValueError('No lattice parameters or vectors given')
    if spacegroup is None:
        if len(args) > spg_id:
            spacegroup = args[spg_id]
        else:
            raise ValueError('Spacegroup not given')
    if not isinstance(spacegroup, str):
        try:
            spacegroup = int(spacegroup)
        except TypeError as e0:
            e1 = ValueError(
                'Invalid spacegroup input. It must be a string or number')
            e1.__suppress_context__ = True
            e1.__traceback__ = e0.__traceback__
            raise e1

    if is_reciprocal:
        if lattice_vectors is not None:
            lattice = brille.Reciprocal(lattice_vectors, spacegroup)
        else:
            lattice = brille.Reciprocal(lens, angs, spacegroup)
    else:
        if lattice_vectors is not None:
            lattice = brille.Direct(lattice_vectors, spacegroup)
        else:
            lattice = brille.Direct(lens, angs, spacegroup)
        lattice = lattice.star

    try:
        return brille.BrillouinZone(
            lattice,
            use_primitive=use_primitive,
            search_length=search_length,
            time_reversal_symmetry=time_reversal_symmetry,
            wedge_search=wedge_search)
    except RuntimeError as e0:
        # We set wedge_search=True by default so add a hint here.
        if 'Failed to find an irreducible Brillouin zone' in str(e0):
            e1 = RuntimeError(str(e0) + ' You can try again with wedge_search=False ' \
                            'to calculate with just the first Brillouin zone')
            e1.__suppress_context__ = True
            e1.__traceback__ = e0.__traceback__
            raise e1
        else:
            raise e0
示例#14
0
    def test_d_all_hallgroups(self):
        tested = 0
        failed = 0
        errored = 0
        failed_spg = []
        failed_ptg = []
        failed_lat = []
        failed_ratio = []
        errored_spg = []
        errored_ptg = []
        errored_lat = []
        errored_arg = []
        print()
        for i in range(1,531):
            spacegroup = s.Spacegroup(i)
            pointgroup = s.Pointgroup(spacegroup.pointgroup_number)
            a = 5; b = 5; c = 5; al = np.pi/2; be = np.pi/2; ga = np.pi/2
            # nothing to do for cubic spacegroups
            if 'hexa' in pointgroup.holohedry:
                ga = 2*np.pi/3
            elif 'trig' in pointgroup.holohedry:
                if 'R' in spacegroup.choice:
                    al = be = ga = np.pi/3
                else: # 'H' setting or normally hexagonal
                    c = 10;
                    ga = 2*np.pi/3
            elif 'tetr' in pointgroup.holohedry:
                c = 10
            elif 'orth' in pointgroup.holohedry:
                axperm = spacegroup.choice.replace('-','')
                if 'cab' in axperm:
                    c = 5; a = 10; b = 15;
                elif 'cba' in axperm:
                    c = 5; b = 10; a = 15;
                elif 'bca' in axperm:
                    b = 5; c = 10; a = 15;
                elif 'bac' in axperm:
                    b = 5; a = 10; c = 15;
                elif 'acb' in axperm:
                    a = 5; c = 10; b = 15;
                else:
                    a = 5; b = 10; c = 15;
            elif 'mono' in pointgroup.holohedry:
                # continue # skip all monoclinic pointgroups for now
                if 'a' in spacegroup.choice:
                    a = 10; al = np.pi/180*(91+19*np.random.rand())
                elif 'b' in spacegroup.choice:
                    b = 10; be = np.pi/180*(91+19*np.random.rand())
                elif 'c' in spacegroup.choice:
                    c = 10; ga = np.pi/180*(91+19*np.random.rand())
                else:
                    print("Monoclinic without 'a', 'b', or 'c' choice?? ", spacegroup.choice)
                    continue
            elif 'tric' in pointgroup.holohedry:
                a = 5; b = 10; c = 15;
                al = np.pi/3*(1 + np.random.rand())
                be = np.pi/3*(1 + np.random.rand())
                ga = np.pi/3*(1 + np.random.rand())

            dlat, rlat = make_dr(a, b, c, al, be, ga, i)

            # print("Hall ", i, " ", dlat)
            # print(spacegroup,pointgroup)
            try:
                bz = s.BrillouinZone(rlat)
                vol_bz = bz.polyhedron.volume
                vol_ir = bz.ir_polyhedron.volume
                tested += 1
                if not np.isclose(vol_ir, vol_bz/s.PointSymmetry(i).size):
                    # print(dlat,": ",vol_ir," != ",vol_bz/s.PointSymmetry(i).size)
                    failed += 1
                    failed_spg.append(spacegroup)
                    failed_ptg.append(pointgroup)
                    failed_lat.append(dlat)
                    failed_ratio.append(vol_ir/vol_bz*s.PointSymmetry(i).size)
            except Exception as err:
                errored += 1
                errored_spg.append(spacegroup)
                errored_ptg.append(pointgroup)
                errored_lat.append(dlat)
                errored_arg.append(err.args)


        if failed > 0:
            print("\nFailed to find irreducible Brillouin zone for",failed,"out of",tested,"(max 530) Hall groups")
            # for spg, ptg, lat, rat in zip(failed_spg, failed_ptg, failed_lat, failed_ratio):
            #     print(spg,ptg,lat,rat)
        if errored > 0:
            print("\nException raised for",errored,"out of",tested,"(max 530) Hall Groups")
示例#15
0
def make_rbz(lengths, angles=np.pi / 2 * np.array((1, 1, 1))):
    """Make a reciprocal lattice and Brillouin zone."""
    r_lat = s.Reciprocal(lengths, angles)
    b_z = s.BrillouinZone(r_lat)
    return (r_lat, b_z)