Example #1
0
    def calculate_pixel_angles_using_vectors(self, center, base, up):
        """Calculate the pixels using specified vectors:
        Parameters
            center: position of center in mm
            base: horizontal direction
            up: vertical direction
        """
        #Normalize
        base /= vector_length(base)
        up /= vector_length(up)
        #Save the vectors
        self.base_point = column(center)
        self.horizontal = column(base)
        self.vertical = column(up)
        #Calculate the normal vector
        self.normal = np.cross(self.vertical.flatten(),
                               self.horizontal.flatten())
        self.normal /= vector_length(self.normal)
        self.normal = column(self.normal)
        assert np.allclose(vector_length(self.normal),
                           1.0), "Normal vector is normalized to length 1.0"

        #Now let's make the pixels
        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)

        #XY is the horizontal, vertical position
        px = px.flatten()
        py = py.flatten()

        #Multiply by the base vectors and add the center
        pixels = px * self.horizontal + py * self.vertical + self.base_point

        #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

        #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))
Example #2
0
    def calculate_pixel_angles_using_vectors(self, center, base, up):
        """Calculate the pixels using specified vectors:
        Parameters
            center: position of center in mm
            base: horizontal direction
            up: vertical direction
        """
        #Normalize
        base /= vector_length(base)
        up /= vector_length(up)
        #Save the vectors
        self.base_point = column(center)
        self.horizontal = column(base)
        self.vertical = column(up)
        #Calculate the normal vector
        self.normal = np.cross(self.vertical.flatten(), self.horizontal.flatten())
        self.normal /= vector_length(self.normal)
        self.normal = column(self.normal)
        assert np.allclose(vector_length(self.normal), 1.0), "Normal vector is normalized to length 1.0"

        #Now let's make the pixels
        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)

        #XY is the horizontal, vertical position
        px = px.flatten()
        py = py.flatten()

        #Multiply by the base vectors and add the center
        pixels = px*self.horizontal + py*self.vertical + self.base_point

        #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

        #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) )
Example #3
0
    def get_pixel_direction(self, horizontal, vertical):
        """Return a 3x1 column vector giving the direction of a pixel
        on the face of the detector.

        Parameters:
            horizontal, vertical: position in mm on the face of the detector.
                0,0 = center of the detector

        Returns:
            3x1 column vector of the beam direction, normalized.
        """
        # Vertical position, relative to 0,0
        y = vertical + self.origin[1] + self.height/2.
        # Position in the XZ plane
        angle = horizontal / self.radius + self.angle_start + self.width/2.
        x = np.cos(angle) * self.radius
        z = np.sin(angle) * self.radius
        pixel = column([x, y, z])

        #Normalize
        pixel = pixel / vector_length(pixel)
        return pixel
Example #4
0
    def get_pixel_direction(self, horizontal, vertical):
        """Return a 3x1 column vector giving the direction of a pixel
        on the face of the detector.

        Parameters:
            horizontal, vertical: position in mm on the face of the detector.
                0,0 = center of the detector

        Returns:
            3x1 column vector of the beam direction, normalized.
        """
        # Vertical position, relative to 0,0
        y = vertical + self.origin[1] + self.height / 2.
        # Position in the XZ plane
        angle = horizontal / self.radius + self.angle_start + self.width / 2.
        x = np.cos(angle) * self.radius
        z = np.sin(angle) * self.radius
        pixel = column([x, y, z])

        #Normalize
        pixel = pixel / vector_length(pixel)
        return pixel
Example #5
0
    def get_pixel_direction(self, horizontal, vertical):
        """Return a 3x1 column vector giving the direction of a pixel
        on the face of the detector.

        Parameters:
            horizontal, vertical: position in mm on the face of the detector.
                0,0 = center of the detector.

        Returns:
            3x1 column vector of the beam direction, normalized.
        """
        #Use the vectors to build the direction
        pixel = horizontal * self.horizontal + vertical * self.vertical + self.base_point

#        #Make a column array of the pixel position, with the z given by the
#        #   detector to sample distance
#        pixel = np.array([ [horizontal], [vertical], [self.distance] ])
#        #Perform the appropriate rotation, calculated before
#        pixel = np.dot(self.pixel_rotation_matrix , pixel)

        #Normalize
        pixel = pixel / vector_length(pixel)
        return pixel
Example #6
0
    def get_pixel_direction(self, horizontal, vertical):
        """Return a 3x1 column vector giving the direction of a pixel
        on the face of the detector.

        Parameters:
            horizontal, vertical: position in mm on the face of the detector.
                0,0 = center of the detector.

        Returns:
            3x1 column vector of the beam direction, normalized.
        """
        #Use the vectors to build the direction
        pixel = horizontal * self.horizontal + vertical * self.vertical + self.base_point

        #        #Make a column array of the pixel position, with the z given by the
        #        #   detector to sample distance
        #        pixel = np.array([ [horizontal], [vertical], [self.distance] ])
        #        #Perform the appropriate rotation, calculated before
        #        pixel = np.dot(self.pixel_rotation_matrix , pixel)

        #Normalize
        pixel = pixel / vector_length(pixel)
        return pixel
Example #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) )
def get_sample_rotation_matrix_to_get_beam(beam_wanted, hkl, ub_matrix, starting_rot_matrix=None):
    """Find the sample rotation matrix that will result in a scattered beam
    going in the desired direction.

    Parameters:
        beam_wanted: vector containing a NORMALIZED vector of the DESIRED scattered beam direction.
        hkl: vector containing the h,k,l reflection of interest.
        ub_matrix: for the current sample and mounting. B converts hkl to q-vector, and U orients.
        starting_rot_matrix: optional: rotation matrix that is close to the result
            we are looking for. e.g. we want the beam to move a few degrees away from this
            starting sample orientation.

    Returns:
        rot_matrix: the 3x3 rotation matrix for the sample orientation that satisfies the
            desired beam direction; or None if it cannot be done.
        wavelength: wavelength at which it would be measured.

    Algorithm
    ---------
    - First, we find the _direction_ of q, ignoring the wavelength
        kf - ki = delta_q
        kf = two_pi_over_wl * (beam_wanted)
        ki = two_pi_over_wl (in z only)
        # so
        q/two_pi_over_wl = (kf - ki)/two_pi_over_wl = beam_x in x; beam_y in y; beam_z-1 in z
    """

    # a means two_pi_over_wl

    #First, we find the _direction_ of q, ignoring the wavelength
    q_over_a = beam_wanted.ravel()
    #Subtract 1 from Z to account for ki, incident beam
    q_over_a[2] -= 1

    #Find the q vector from HKL before sample orientation
    q0 = np.dot(ub_matrix, hkl)

    if not starting_rot_matrix is None:
        #Also rotate using the given matrix, to find a starting point
        q0 = np.dot(starting_rot_matrix, q0)

    #Flatten into vector
    q0 = q0.flatten()

    #Since the rotation does not change length, norm(q0) = norm(q_over_a),
    #   meaning that a = norm(q)/ norm(q_over_a)
    a = vector_length(q0) / vector_length(q_over_a)
    #And a's definition is such that:
    wavelength = 2*np.pi/a

    #So lets get q directly.
    q_rotated = q_over_a * a

    #Find the rotation matrix that satisfies q_over_a = R_over_a . q0
    
    #The cross product of q0 X q_over_a gives a rotation axis to use
    rotation_axis = np.cross(q0, q_over_a)
    #Normalize
    rotation_axis = rotation_axis / vector_length(rotation_axis)

    #Now we find the rotation angle about that axis that puts q0 on q_over_a
    angle = np.arccos( np.dot(q0, q_over_a) / (vector_length(q0)*vector_length(q_over_a)))

    #From http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm
    # we make a rotation matrix
    (x,y,z) = rotation_axis

    #This is a normalized rotation matrix
    R = np.array([[1 + (1-cos(angle))*(x*x-1), -z*sin(angle)+(1-cos(angle))*x*y, y*sin(angle)+(1-cos(angle))*x*z],
        [z*sin(angle)+(1-cos(angle))*x*y, 1 + (1-cos(angle))*(y*y-1), -x*sin(angle)+(1-cos(angle))*y*z],
        [-y*sin(angle)+(1-cos(angle))*x*z,  x*sin(angle)+(1-cos(angle))*y*z,  1 + (1-cos(angle))*(z*z-1)]])

    if not starting_rot_matrix is None:
        #The final rotation we want is sstarting_rot_matrix 1st; R second.
        # So this is the resulting matrix
        R = np.dot(R, starting_rot_matrix)


#    print "q0", q0.ravel()
#    print "two pi over wl (a)", a
#    print "q_over_a", q_over_a.ravel()
#    print "rotation_axis", rotation_axis
#    print "angle", angle
#    print "get_sample_rotation_matrix_to_get_beam: angle was", np.rad2deg(angle)

    return (R, wavelength)
 def check_matrix_lengths(self, M, lat):
     """Check if the lengths of the columns of M match the values in tuple lat"""
     lengths = [(vector_length(M[:,x])) for x in xrange(3)]
     #print "lengths", lengths
     return np.allclose(lengths, lat)
 def get_d_spacing(self):
     """Return the d-spacing corresponding to this hkl"""
     return 1 / (vector_length(self.q_vector) / (2*np.pi))
 def get_q_norm(self):
     """Return the norm of the q-vector corresponding to this hkl"""
     return vector_length(self.q_vector)
Example #12
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))