Exemplo n.º 1
0
    def test_getq_c_and_python(self):
        """cystal_calc module: getq() in C and python."""
        #Angles for testing
        az = 1.23
        elev = 0.32
        wl = 2.32
        rot_matrix = rotation_matrix(0.31, -0.23, 0.43)
        q1 = getq_python(az, elev, wl, rot_matrix)
        q2 = getq(az, elev, wl, rot_matrix)
        assert np.allclose(q1, q2) , "Python and C getq match within float error."
        #assert np.all(q1 == q2) , "Python and C getq match exactly."

        #Now test for an array
        az = np.linspace(0, pi, 50)
        elev = az / 2
        rot_matrix = rotation_matrix(0.31, -0.23, 0.43)
        several_q = getq_python(az, elev, wl, rot_matrix)
        assert several_q.shape == (3, 50), "Correct shape"
        wl = az + 1
        several_q = getq_python(az, elev, wl, rot_matrix)
        assert several_q.shape == (3, 50), "Correct shape with wl as array"
Exemplo n.º 2
0
    def test_getq(self):
        """cystal_calc module: getq()."""
        #Zero-level test
        q1 = getq(0, 0, 1.0, rotation_matrix(0,0,0))
        assert not np.any(q1), "Non-scattered beam gives a q of 0,0,0"

        q1 = getq(-np.pi, 0.0, 1.0, rotation_matrix(0,0,0)).flatten()
        answer = np.array([0,0,-2.])*2*np.pi
        assert np.allclose(q1, answer), "Back-scattered beam gives a q of %s; result was %s" % (answer, q1)

        q1 = getq(-np.pi, 0.0, 2.0, rotation_matrix(0,0,0)).flatten()
        answer = np.array([0,0,-1.])*2*np.pi
        assert np.allclose(q1, answer), "Back-scattered beam at wl = 2 Angstrom gives a q of %s; result was %s" % (answer, q1)

        q1 = getq(-np.pi, 0, 3, rotation_matrix(0,0,0)).flatten()
        answer = np.array([0,0, -2.0/3.0])*2*np.pi
        assert np.allclose(q1, answer), "Getq handles integer inputs."

        q1 = getq(0, np.pi/2, 1.0, rotation_matrix(0,0,0)).flatten()
        answer = np.array([0,+1.,-1.])*2*np.pi
        assert np.allclose(q1, answer), "Vertically-scattered beam gives a q of %s; result was %s" % (answer, q1)
Exemplo n.º 3
0
 def test_getq_inelastic(self):
     #Angles for testing
     az = 1.23
     elev = 0.32
     wl = 2.32
     wl_input = 1.02
     rot_matrix = rotation_matrix(0.31, -0.23, 0.43)
     q1 = getq_python(az, elev, wl, rot_matrix, wl_input=wl_input)
     q2 = getq(az, elev, wl, rot_matrix, wl_input=wl_input)
     print "python:", q1
     print "c:", q2
     assert np.allclose(q1[0].flatten(), np.array(q2[0]).flatten()) , "Python and C getq (inelastic) match within float error. %s (python); %s (C)" % (q1, q2)
     assert np.allclose(q1[1].flatten(), np.array(q2[1]).flatten()) , "Python and C getq (inelastic) match within float error. %s (python); %s (C)" % (q1, q2)
Exemplo n.º 4
0
    def test_getq_with_rotation(self):
        "cystal_calc module: getq() test with sample rotation. The q-rotation matrix always uses OPPOSITE angles"

        #Rotate sample +pi/2 in phi.
        q_rot_m = rotation_matrix(-np.pi/2,0,0)
        q1 = getq(-np.pi, 0.0, 1.0, q_rot_m).flatten()
        answer = np.array([+2.,0.,0.])*2*np.pi
        assert np.allclose(q1, answer), "Back-scattered beam, with phi rotation, gives a q of %s; result was %s" % (answer, q1)

        q1 = getq(0, pi/2, 1.0, q_rot_m).flatten()
        answer = np.array([+1.,+1.,0.])*2*np.pi
        assert np.allclose(q1, answer), "Vertically-scattered beam, with phi rotation, gives a q of %s; result was %s" % (answer, q1)

        #Rotate sample +pi/2 in chi. No effect on back-scattered
        q_rot_m = rotation_matrix(0,-np.pi/2,0)
        q1 = getq(-np.pi, 0.0, 1.0, q_rot_m).flatten()
        answer = np.array([0.,0.,-2.])*2*np.pi
        assert np.allclose(q1, answer), "Back-scattered beam, with chi rotation, gives a q of %s; result was %s" % (answer, q1)
        q_rot_m = rotation_matrix(0,0.2345,0)
        q1 = getq(-np.pi, 0.0, 1.0, q_rot_m).flatten()
        answer = np.array([0.,0.,-2.])*2*np.pi
        assert np.allclose(q1, answer), "Back-scattered beam, with any chi rotation, gives a q of %s; result was %s" % (answer, q1)
Exemplo n.º 5
0
 def test_scattered_beam(self):
     """cystal_calc module: get_scattered_q_vector() tests."""
     #Easy UB matrix test
     UB = np.identity(3)
     rot_matrix = rotation_matrix(0, 0, 0)
     #Single vector
     hkl = column([1,2,3])
     scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB)
     assert scattered_q.shape==(3,1), "Returns column-wise vector."
     assert np.allclose(scattered_q, column([1.,2.,3.])), "Identity operation."
     #Several vectors
     hkl = column([1,2,3]) + np.arange(0, 10)
     scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB)
     assert scattered_q.shape==(3,10), "Returns column-wise array."
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
    def calculate_pixel_angles(self):
        """Given the center angle and other geometry of the detector, calculate the
        azimuth and elevation angle of every pixel."""

        x = np.linspace(-self.width/2, self.width/2, self.xpixels)
        y = np.linspace(-self.height/2, self.height/2, self.ypixels)
        #Starting x, y, z position
        (px, py) = np.meshgrid(x,y)

        #Start with a Z equal to the given distance
        pz = np.zeros( px.shape ) + self.distance

        #Reshape into a nx3 buncha columns, where the columns are the pixels XYZ positions
        num = self.xpixels * self.ypixels
        pixels = np.array( [ px.flatten(), py.flatten(), pz.flatten()] )

        #Ok, first rotate the detector around its center by angle.
        #Since this is rotation around z axis, it is a chi angle
        rot = rotation_matrix(0, self.rotation, 0)

        #Now do the elevation rotation, by rotating around the x axis.
        #   Elevation is positive above the horizontal plane - means the x_rotation angle has to be negative
        rot = np.dot(x_rotation_matrix(-self.elevation_center), rot)

        #Finally add an azimuthal rotation (around the y axis, or phi)
        rot = np.dot(rotation_matrix(self.azimuth_center, 0, 0), rot)

        #Save it for later
        self.pixel_rotation_matrix = rot

        #This applies to the pixels
        pixels = np.dot(rot, pixels)

        #Save em - for plotting, mostly. Indices go Z, Y, X
        self.pixels = np.reshape(pixels, (3, self.ypixels, self.xpixels) )

        #Save the corners
        self.corners = list()
        self.corners.append(self.pixels[:,  0,  0]) #One corner
        self.corners.append(self.pixels[:,  0, -1]) #The end in X
        self.corners.append(self.pixels[:, -1, -1]) #Max x and Y
        self.corners.append(self.pixels[:, -1,  0]) #The end in Y

        #This is the base point - the center of the detector
        base_pixel = column([0, 0, self.distance])
        #Do the same rotation as the rest of the pixels
        base_pixel = np.dot(rot, base_pixel)
        self.base_point = column(base_pixel)

        #Horizontal and vertical vector
        self.horizontal = column(self.corners[1] - self.corners[0])
        self.vertical = column(self.corners[3] - self.corners[0])
        #Normalize them
        self.vertical /= vector_length(self.vertical)
        self.horizontal /= vector_length(self.horizontal)

        #Normal vector: take a vector pointing in positive Z, and the do the same rotation as all the pixels.
        self.normal = column(np.cross(self.horizontal.flatten(), self.vertical.flatten() ))
        assert np.allclose(vector_length(self.normal), 1.0), "normal vector is normalized."
        #Another way to calculate the normal. Compare it
        other_normal = np.dot(rot,  column([0,0,1])).flatten()
        assert np.allclose(self.normal.flatten(), other_normal), "Match between two methods of calculating normals. %s vs %s" % (self.normal.flatten(), other_normal)

        #Now, we calculate the azimuth and elevation angle of each pixel.
        x=pixels[0,:]
        y=pixels[1,:]
        z=pixels[2,:]

        self.azimuthal_angle = np.reshape( np.arctan2(x, z), (self.ypixels, self.xpixels) )
        self.elevation_angle = np.reshape( np.arctan(y / np.sqrt(x**2 + z**2)), (self.ypixels, self.xpixels) )
Exemplo n.º 8
0
        UB = make_UB_matrix(lat, angles, np.deg2rad(90), np.deg2rad(0), np.deg2rad(0))
        M = np.array([[0,0,0.05], [0,0.1,0], [-0.2,0,0]]) * 2 * pi
        assert np.allclose(M, UB), "UB matrix for orthorombic lattice, phi=+90"
        UB = make_UB_matrix(lat, angles, np.deg2rad(0), np.deg2rad(90), np.deg2rad(0))
        M = np.array([[0,-0.1,0], [0.2,0,0], [0,0,0.05]]) * 2 * pi
        assert np.allclose(M, UB), "UB matrix for orthorombic lattice, chi=+90"

    def test_get_sample_rotation_matrix_to_get_beam(self):
        beam_wanted = column([0,1,0])
        ub_matrix = np.identity(3)
        hkl = column([0,1,1])
        (R, wl) = get_sample_rotation_matrix_to_get_beam(beam_wanted, hkl, ub_matrix)
        assert np.allclose(R, np.array([[1,0,0],[0,0,1],[0,-1,0]])), "get_sample_rotation_matrix, case 1"
#        #Lets give it a starting matrix
#        start_R = rotation_matrix(0,np.pi/4, 0)
#        (R, wl) = get_sample_rotation_matrix_to_get_beam(beam_wanted, hkl, ub_matrix, start_R)
#        assert np.allclose(R, np.array([[1,0,0],[0,0,1],[0,-1,0]])), "get_sample_rotation_matrix, with a starting matrix. We got %s" % R
        

#---------------------------------------------------------------------
if __name__ == "__main__":
    rot_matrix = numpy_utils.rotation_matrix(np.rad2deg(45), np.rad2deg(90), 0)
    print rot_matrix

    start = column([-1,0,0])
    print start
    
    rot = np.dot(rot_matrix, start)
    print rot
    #unittest.main()
Exemplo n.º 9
0
    def calculate_pixel_angles(self):
        """Given the center angle and other geometry of the detector, calculate the
        azimuth and elevation angle of every pixel."""

        x = np.linspace(-self.width / 2, self.width / 2, self.xpixels)
        y = np.linspace(-self.height / 2, self.height / 2, self.ypixels)
        #Starting x, y, z position
        (px, py) = np.meshgrid(x, y)

        #Start with a Z equal to the given distance
        pz = np.zeros(px.shape) + self.distance

        #Reshape into a nx3 buncha columns, where the columns are the pixels XYZ positions
        num = self.xpixels * self.ypixels
        pixels = np.array([px.flatten(), py.flatten(), pz.flatten()])

        #Ok, first rotate the detector around its center by angle.
        #Since this is rotation around z axis, it is a chi angle
        rot = rotation_matrix(0, self.rotation, 0)

        #Now do the elevation rotation, by rotating around the x axis.
        #   Elevation is positive above the horizontal plane - means the x_rotation angle has to be negative
        rot = np.dot(x_rotation_matrix(-self.elevation_center), rot)

        #Finally add an azimuthal rotation (around the y axis, or phi)
        rot = np.dot(rotation_matrix(self.azimuth_center, 0, 0), rot)

        #Save it for later
        self.pixel_rotation_matrix = rot

        #This applies to the pixels
        pixels = np.dot(rot, pixels)

        #Save em - for plotting, mostly. Indices go Z, Y, X
        self.pixels = np.reshape(pixels, (3, self.ypixels, self.xpixels))

        #Save the corners
        self.corners = list()
        self.corners.append(self.pixels[:, 0, 0])  #One corner
        self.corners.append(self.pixels[:, 0, -1])  #The end in X
        self.corners.append(self.pixels[:, -1, -1])  #Max x and Y
        self.corners.append(self.pixels[:, -1, 0])  #The end in Y

        #This is the base point - the center of the detector
        base_pixel = column([0, 0, self.distance])
        #Do the same rotation as the rest of the pixels
        base_pixel = np.dot(rot, base_pixel)
        self.base_point = column(base_pixel)

        #Horizontal and vertical vector
        self.horizontal = column(self.corners[1] - self.corners[0])
        self.vertical = column(self.corners[3] - self.corners[0])
        #Normalize them
        self.vertical /= vector_length(self.vertical)
        self.horizontal /= vector_length(self.horizontal)

        #Normal vector: take a vector pointing in positive Z, and the do the same rotation as all the pixels.
        self.normal = column(
            np.cross(self.horizontal.flatten(), self.vertical.flatten()))
        assert np.allclose(vector_length(self.normal),
                           1.0), "normal vector is normalized."
        #Another way to calculate the normal. Compare it
        other_normal = np.dot(rot, column([0, 0, 1])).flatten()
        assert np.allclose(
            self.normal.flatten(), other_normal
        ), "Match between two methods of calculating normals. %s vs %s" % (
            self.normal.flatten(), other_normal)

        #Now, we calculate the azimuth and elevation angle of each pixel.
        x = pixels[0, :]
        y = pixels[1, :]
        z = pixels[2, :]

        self.azimuthal_angle = np.reshape(np.arctan2(x, z),
                                          (self.ypixels, self.xpixels))
        self.elevation_angle = np.reshape(np.arctan(y / np.sqrt(x**2 + z**2)),
                                          (self.ypixels, self.xpixels))