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)