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 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 test_get_q_from_hkl(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)
        q = get_q_from_hkl(column([1., 0, 0]), a, b, c)
        assert np.allclose(vector(q), a), "Simple get_q_from_hkl a."
        q = get_q_from_hkl(column([1., 0, 0]), a, b, c)
        assert np.allclose(vector(q), vector([2*pi/5, 0, 0])), "Simple get_q_from_hkl a, comparing to value."
        q = get_q_from_hkl(column([0, 1., 0]), a, b, c)
        assert np.allclose(vector(q), b), "Simple get_q_from_hkl b."
        q = get_q_from_hkl(column([0, 0, 1.]), a, b, c)
        assert np.allclose(vector(q), c), "Simple get_q_from_hkl c."
        q = get_q_from_hkl(column([1, 2, 3.]), a, b, c)
        assert np.allclose(vector(q), a+2*b+3*c), "get_q_from_hkl (1,2,3)."

        hkl = np.ones( (3, 12) )
        q = get_q_from_hkl(hkl, a, b, c)
        assert q.shape == (3, 12), "get_q_from_hkl correct shape."
def make_reciprocal_lattice(lattice_lengths, lattice_angles):
    """Generate a reciprocal lattice matrix.

    Parameters:
        lattice_lengths: tuple. 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

    Returns:
        (a_star, b_star, c_star): the 3 reciprocal lattice vectors.
    """
    #First, get the direct space lattice vectors
    (a,b,c, V) = make_lattice_vectors(lattice_lengths, lattice_angles)

    #With cross-products, calculate the reciprocal vectors
    a_star = 2 * np.pi * np.cross(vector(b),vector(c)) / V
    b_star = 2 * np.pi * np.cross(vector(c),vector(a)) / V
    c_star = 2 * np.pi * np.cross(vector(a),vector(b)) / V

    return (a_star, b_star, c_star)