def test_make_reciprocal_lattice(self): "cystal_calc module: make_reciprocal_lattice()" #Make up a lattice - orthorombic lat = ( 5.0, 10.0, 20.0) lat_inverse = 2 * pi * np.array((0.2, 0.1, 0.05)) angles = tuple( np.deg2rad( [90, 90, 90])) (a,b,c) = make_reciprocal_lattice(lat, angles) res = (vectors_to_matrix(a,b,c)) M = np.array([ [0.2, 0, 0], [0, 0.1, 0], [0, 0, 0.05] ]) * 2 * pi assert np.allclose(M, res), "orthorombic reciprocal lattice" assert self.check_matrix_lengths(res, lat_inverse), "orthorombic: reciprocal lattice matrix is correct." #Triclinic example angles = tuple( np.deg2rad( [30, 45, 60])) V = 335.219981051 #From calculation of the program lat_inverse = 2*pi*np.array( (200*sin( angles[0] )/V, 100*sin( angles[1] )/V, 50*sin( angles[2] )/V)) #From formulae (a,b,c) = make_reciprocal_lattice(lat, angles) res = (vectors_to_matrix(a,b,c)) assert self.check_matrix_lengths(res, lat_inverse), "Triclinic: reciprocal vectors are correct length."
def test_make_lattice_vectors(self): "cystal_calc module: make_lattice_vectors()" #Make up a lattice - orthorombic lat = ( 5.0, 10.0, 20.0) angles = tuple( np.deg2rad( [90, 90, 90])) #Make the expected matrix M = np.identity(3) for x in xrange(3): M[x,x] = lat[x] (a,b,c,V) = make_lattice_vectors(lat, angles) res = (vectors_to_matrix(a,b,c)) assert np.allclose(M, res), "Simple orthorombic lattice" assert self.check_matrix_lengths(res, lat), "orthorombic: vectors are correct length." #Monoclinic example angles = tuple( np.deg2rad( [45, 90, 90])) M[:,2] = np.sqrt(2)/2 * vector( 0, 20, 20 ) #Value by inspection (a,b,c,V) = make_lattice_vectors(lat, angles) res = (vectors_to_matrix(a,b,c)) assert np.allclose(M, res), "Monoclinic lattice" assert self.check_matrix_lengths(res, lat), "Monoclinic: vectors are correct length." #Rhombohedral example angles = tuple( np.deg2rad( [45, 45, 45])) M = np.identity(3) for x in xrange(3): M[x,x] = lat[x] M[:,1] = np.sqrt(2)/2 * vector( 10, 10, 0 ) #Value by inspection M[:,2] = vector( 14.14213562, 5.85786438, 12.87188506 ) #Value came from program (a,b,c,V) = make_lattice_vectors(lat, angles) res = (vectors_to_matrix(a,b,c)) assert np.allclose(M, res), "Rhombohedral lattice" assert self.check_matrix_lengths(res, lat), "Rhombohedral: vectors are correct length." #Triclinic example angles = tuple( np.deg2rad( [30, 45, 60])) M = np.identity(3) for x in xrange(3): M[x,x] = lat[x] M[:,1] = vector( 5, 8.66025404, 0 ) #Value came from program M[:,2] = vector( 14.14213562, 11.83503419, 7.74157385 ) #Value came from program (a,b,c,V) = make_lattice_vectors(lat, angles) res = (vectors_to_matrix(a,b,c)) assert np.allclose(M, res), "Triclinic lattice" assert self.check_matrix_lengths(res, lat), "Triclinic: vectors are correct length."
def get_q_from_hkl(hkl, a_star, b_star, c_star): """Calculate a set of q-vector from a set of hkl indices. Parameters: hkl: a 3xN array of the hkl indices of the reflection. (a_star, b_star, c_star): The 3 reciprocal lattice vectors (3 element array each) Returns: q: a 3xN array of Q vectors, column-wise """ #Make the B matrix B = numpy_utils.vectors_to_matrix(a_star, b_star, c_star) #Matrix multiply B.hkl to get all the Qs return np.dot(B, hkl)
def test_get_hkl_from_q(self): lat = ( 5.0, 10.0, 20.0) lat_inverse = (0.2, 0.1, 0.05) angles = tuple( np.deg2rad( [90, 90, 90])) (a,b,c) = make_reciprocal_lattice(lat, angles) rec = vectors_to_matrix(a,b,c) hkl = get_hkl_from_q(column([0.2, 0, 0])*2*pi, rec) assert np.allclose(vector(hkl), vector([1,0,0])), "get_hkl_from_q (1,0,0)." #Sanity check for i in xrange(10): val = column(np.random.rand(3)) q = get_q_from_hkl(val, a, b, c) hkl = get_hkl_from_q(q, rec) assert np.allclose(vector(hkl), vector(val)), "get_hkl_from_q vs get_q_from_hkl for random values."
def make_UB_matrix(lattice_lengths, lattice_angles, sample_phi, sample_chi, sample_omega, U_matrix=None): """Make a UB matrix from the given parameters. Parameters: lattice_lengths: the DIRECT lattice lengths a,b,c in Angstroms. lattice_angles: tuple. the DIRECT lattice lengths alpha, beta, gamma, in radians. alpha = angle between b and c; beta = angle between a and c; gamma = angle between b and c sample_phi, sample_chi, sample_omega: These three angles (in radians) determine how the crystal is mounted. Here's how it works: 0 - Instrument coordinates: +Y is vertical, +Z is the beam direction. 1 - Start with the crystal mounted so that 'a' (real lattice vector) is exactly aligned towards +X, and 'b' is pointing towards +Y in the XY plane, and 'c' is pointing towards +Z 2 - Do the phi rotation = around the Y axis (vertical). 3 - Do the chi rotation = around the Z axis. 4 - Do the omega rotation = around the Y axis again. For example, if 'a' is pointing up, use 0, +90, 0. if 'a' is pointing down along the beam direction, use -90, 0, 0 (I think) U_matrix : specify to use this U matrix instead of the angles """ #Get the reciprocal vectors (a_star, b_star, c_star) = make_reciprocal_lattice(lattice_lengths, lattice_angles) #The B matrix is such that B.hkl = the q-vector (minus some rotations) # so, B is a matrix with each column = to a_star, b_star, c_star # B.hkl = a_star*h + b_star*k + c_star*l B = numpy_utils.vectors_to_matrix(a_star, b_star, c_star) #Now lets make a rotation matrix U to account for sample mounting. # We used the same set of phi,chi,omega rotations as for sample orientations. U = numpy_utils.rotation_matrix(sample_phi, sample_chi, sample_omega) if not U_matrix is None: U = U_matrix #Return the UB matrix product. U*Bget_q_from_hkl return np.dot(U, B)