def test_e_subclass_star(self): d = s.Direct((1, 1, 1), np.array([1, 1, 1]) * np.pi / 2) r = s.Reciprocal( np.array([1, 1, 1]) * np.pi * 2, np.array([1, 1, 1]) * np.pi / 2) self.assertTrue(d.isstar(r)) self.assertTrue(r.isstar(d)) self.assertEqual(d, r.star) self.assertEqual(r, d.star)
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())
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))
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)
def isapprox(self, other): return b.Direct(self.lat).isapprox(b.Direct(other.lat))
def get_conventional_Direct(self): return b.Direct(self.get_conventional_basis(), self.get_conventional_atom_positions(), self.get_conventional_atom_index(), self.hall)
def get_input_Direct(self): return b.Direct(self.get_input_basis(), self.get_input_atom_positions(), self.get_input_atom_index(), self.hall)
Z = np.concatenate((Z[:-1] - dX, Z[np.newaxis, -1] - dX[np.newaxis, -1], 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)
Z = np.concatenate((Z[:-1] - dX, Z[np.newaxis, -1] - dX[np.newaxis, -1], 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((10, 10, 10.), (90., 90., 90.), 525) bz = brille.BrillouinZone(dlat.star) # max_sizes = 1/np.arange(100,5000,500) max_sizes = 1 / (10**np.linspace(6, 12, 5))**(1 / 3) num_levels = np.arange(1, 5).reshape(4, 1) print('pybind object creation times:') it = np.nditer([max_sizes, num_levels, None, None, None]) for s, l, c, e, n in it: tictoc.tic() while not (tictoc.elapsed() > 30 or tictoc.relative_uncertainty() < 0.2): mesh = brille.BZNestQ(bz, max_volume=s, max_branchings=l) tictoc.toc() c[...] = tictoc.average() e[...] = tictoc.uncertainty()
if hall_sym != explicit_sym: print('Something has gone horribly wrong') else: print('The generated space groups are equivalent! (All is well.)') if np.all(hall_sym.W == explicit_sym.W): print( "\tWe're extra lucky that the groups have the same-ordered motions" ) else: print( "\tSymmetry group equivalency does not imply same-ordered motions") # Now construct a real space Direct lattice a few ways: # -F 4 3 2 is a cubic system, so all lattice basis vector lengths are the same lat_parameters_hall_symbol = brille.Direct((1, 1, 1), (90, 90, 90), '-F 4 3 2') # we can also provide explicit basis vectors as a matrix # a possible pitfall: brille does not store the orientation of the basis vectors bv = lambda t: np.array([[np.cos(t), 0, np.sin(t)], [0, 1, 0], [-np.sin(t), 0, np.cos(t)]]) lat_basis_hall_symbol = brille.Direct(bv(np.random.rand() * np.pi), '-F 4 3 2') if lat_basis_hall_symbol != lat_parameters_hall_symbol: print('Something has gone wrong creating the Direct lattices') p1_cube = brille.Direct((1, 1, 1), (90, 90, 90)) # another potential pitfall, lattice equivalency does not consider spacegroups if lat_basis_hall_symbol == p1_cube: print('brille Lattice equivalency ignores the Spacegroup information') if lat_basis_hall_symbol.spacegroup != p1_cube.spacegroup: print('\tSo explicit checks of the spacegroup may be necessary')
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
def make_dr(a, b, c, al=np.pi/2, be=np.pi/2, ga=np.pi/2, hall=1): """Make a Direct and Reciprocal lattice from Direct lattice parameters.""" d = s.Direct(a, b, c, al, be, ga, hall) r = d.star return (d, r)