def test_detector_coord(self): """CylindricalDetector.get_detector_coordinates()""" det = self.det func = det.get_detector_coordinates #Invalid parameter errors self.assertRaises(ValueError, func, np.zeros( (2,10) )) self.assertRaises(ValueError, func, np.zeros(3) ) beam = column([10.0, 0.0, 0.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(wl, 0.1), "Correct wavelength" beam = column([1.0, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0 * np.pi / 4, atol=1e-5), "H is right in the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.allclose(distance, 200.0), "Distance is equal to the detector radius." assert np.all(hits_it), "... and it hits it." beam = column([-1.0, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, +6 * 200 * np.pi / 4), "H is off to the right" assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses." beam = column([1.0, 0.0, -1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 2 * 200 * np.pi / 4), "H is off to the left" assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses."
def test_detector_coord_vertical(self): """CylindricalDetector.get_detector_coordinates()""" det = self.det beam = column([0., 1., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, 200.0), "V is 200 mm above horizontal" assert np.allclose(distance, np.sqrt(2 * 200.**2)), "Distance is correct" assert np.all(hits_it), "... and it hits it." beam = column([0., -1., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, -200.0), "V is 200 mm below horizontal" assert np.allclose(distance, np.sqrt(2 * 200.**2)), "Distance is correct" assert np.all(hits_it), "... and it hits it." beam = column([0., 2., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, 400.0), "V is 400 mm above horizontal" assert not np.all(hits_it), "... and it misses." beam = column([0., -2., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, -400.0), "V is 400 mm below horizontal" assert not np.all(hits_it), "... and it misses."
def test_detector_coord_vertical(self): """CylindricalDetector.get_detector_coordinates()""" det = self.det beam = column([0., 1., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, 200.0), "V is 200 mm above horizontal" assert np.allclose(distance, np.sqrt(2*200.**2)), "Distance is correct" assert np.all(hits_it), "... and it hits it." beam = column([0., -1., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, -200.0), "V is 200 mm below horizontal" assert np.allclose(distance, np.sqrt(2*200.**2)), "Distance is correct" assert np.all(hits_it), "... and it hits it." beam = column([0., 2., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, 400.0), "V is 400 mm above horizontal" assert not np.all(hits_it), "... and it misses." beam = column([0., -2., 1.]) (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, -200 * np.pi / 4), "H is on the edge" assert np.allclose(v, -400.0), "V is 400 mm below horizontal" assert not np.all(hits_it), "... and it misses."
def test_calculate_pixel_angles(self): """Detector.calculate_pixel_angles() tests.""" #Smaller size self.det.xpixels = 16 self.det.ypixels = 10 self.det.calculate_pixel_angles() #Check some shapes assert self.det.pixels.shape == (3, 10, 16) assert self.det.azimuthal_angle.shape == (10, 16) #What we expect az = np.fromstring("-0.12435499 -0.10791249 -0.0914112 -0.07485985 -0.0582673 -0.04164258 -0.02499479 -0.00833314 0.00833314 0.02499479 0.04164258 0.0582673 0.07485985 0.0914112 0.10791249 0.12435499", sep=" ") elev_x = np.fromstring("-0.12340447 -0.123639 -0.1238411 -0.12401028 -0.12414612 -0.12424829 -0.12431655 -0.12435072 -0.12435072 -0.12431655 -0.12424829 -0.12414612 -0.12401028 -0.1238411 -0.123639 -0.12340447", sep=" ") elev_y = np.fromstring("-0.12340447 -0.09617384 -0.06879943 -0.04132138 -0.01378076 0.01378076 0.04132138 0.06879943 0.09617384 0.12340447", sep=" ") assert np.allclose(az, self.det.azimuthal_angle[0, :]), "Azimuthal angles match." assert np.allclose(elev_x, self.det.elevation_angle[0, :]), "elevation angles match along x." assert np.allclose(elev_y, self.det.elevation_angle[:, 0]), "elevation angles match along y." #All azimuthal angle with same x index match for iy in xrange(1, self.det.ypixels): assert np.allclose(az, self.det.azimuthal_angle[iy, :]), "Azimuthal angles match in all y values." #But there is a difference in elev. angles assert np.all( abs(self.det.elevation_angle[:, 0] - self.det.elevation_angle[:, 1]) > 0), "Some small difference in elevation angles as you change x." #Corners is set assert np.allclose(self.det.corners[0], [ -50., -50., 400.]) assert np.allclose(self.det.corners[1], [ 50., -50., 400.]) assert np.allclose(self.det.corners[2], [ 50., 50., 400.]) assert np.allclose(self.det.corners[3], [ -50., 50., 400.]) assert np.allclose(self.det.base_point, column([0, 0, 400])), "Base point is in the center of the detector."; #Orientation vectors assert np.allclose( self.det.horizontal, column([1, 0, 0]) ), "Horizontal orientation vector is correct." assert np.allclose( self.det.vertical, column([0, 1, 0]) ), "Vertical orientation vector is correct."
def test_detector_coord(self): """CylindricalDetector.get_detector_coordinates()""" det = self.det func = det.get_detector_coordinates #Invalid parameter errors self.assertRaises(ValueError, func, np.zeros((2, 10))) self.assertRaises(ValueError, func, np.zeros(3)) beam = column([10.0, 0.0, 0.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(wl, 0.1), "Correct wavelength" beam = column([1.0, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose( h, 0 * np.pi / 4, atol=1e-5), "H is right in the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.allclose(distance, 200.0), "Distance is equal to the detector radius." assert np.all(hits_it), "... and it hits it." beam = column([-1.0, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, +6 * 200 * np.pi / 4), "H is off to the right" assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses." beam = column([1.0, 0.0, -1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 2 * 200 * np.pi / 4), "H is off to the left" assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses."
def test_calculate_pixel_angles_with_rotation(self): """Detector.calculate_pixel_angles() where the detector has a rotation angle.""" #Smaller size self.det.xpixels = 16 self.det.ypixels = 10 self.det.rotation = np.deg2rad(45) self.det.calculate_pixel_angles() assert np.allclose( self.det.horizontal, np.sqrt(2)/2 * column([1, 1, 0]) ), "Orientation vector is correct, rotated 45 deg." assert np.allclose( self.det.vertical, np.sqrt(2)/2 * column([-1, 1, 0]) ), "Vertical orientation vector is correct, rotated."
def test_constructor(self): """Reflection->Test the constructor""" ref = self.ref assert ref.h == 1 assert ref.k == 2 assert ref.l == 3 assert np.all(ref.hkl == column([1,2,3])) assert np.allclose(ref.q_vector, column([1.0, 0.5, 1.0/3])), "q-vector was set to %s" % ref.q_vector assert isinstance(ref.measurements, list), "Made a list." assert len(ref.measurements) == 0, "No items in list."
def test_calculate_pixel_angles(self): """Detector.calculate_pixel_angles() tests.""" #Smaller size self.det.xpixels = 16 self.det.ypixels = 10 self.det.calculate_pixel_angles() #Check some shapes assert self.det.pixels.shape == (3, 10, 16) assert self.det.azimuthal_angle.shape == (10, 16) #What we expect az = np.fromstring( "-0.12435499 -0.10791249 -0.0914112 -0.07485985 -0.0582673 -0.04164258 -0.02499479 -0.00833314 0.00833314 0.02499479 0.04164258 0.0582673 0.07485985 0.0914112 0.10791249 0.12435499", sep=" ") elev_x = np.fromstring( "-0.12340447 -0.123639 -0.1238411 -0.12401028 -0.12414612 -0.12424829 -0.12431655 -0.12435072 -0.12435072 -0.12431655 -0.12424829 -0.12414612 -0.12401028 -0.1238411 -0.123639 -0.12340447", sep=" ") elev_y = np.fromstring( "-0.12340447 -0.09617384 -0.06879943 -0.04132138 -0.01378076 0.01378076 0.04132138 0.06879943 0.09617384 0.12340447", sep=" ") assert np.allclose( az, self.det.azimuthal_angle[0, :]), "Azimuthal angles match." assert np.allclose( elev_x, self.det.elevation_angle[0, :]), "elevation angles match along x." assert np.allclose( elev_y, self.det.elevation_angle[:, 0]), "elevation angles match along y." #All azimuthal angle with same x index match for iy in xrange(1, self.det.ypixels): assert np.allclose(az, self.det.azimuthal_angle[ iy, :]), "Azimuthal angles match in all y values." #But there is a difference in elev. angles assert np.all( abs(self.det.elevation_angle[:, 0] - self.det.elevation_angle[:, 1]) > 0 ), "Some small difference in elevation angles as you change x." #Corners is set assert np.allclose(self.det.corners[0], [-50., -50., 400.]) assert np.allclose(self.det.corners[1], [50., -50., 400.]) assert np.allclose(self.det.corners[2], [50., 50., 400.]) assert np.allclose(self.det.corners[3], [-50., 50., 400.]) assert np.allclose(self.det.base_point, column( [0, 0, 400])), "Base point is in the center of the detector." #Orientation vectors assert np.allclose(self.det.horizontal, column( [1, 0, 0])), "Horizontal orientation vector is correct." assert np.allclose(self.det.vertical, column( [0, 1, 0])), "Vertical orientation vector is correct."
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))
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_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."
def test_calculate_pixel_angles_with_elevation(self): """Detector.calculate_pixel_angles() where the detector has an elevation angle.""" #Smaller size self.det.xpixels = 16 self.det.ypixels = 10 self.det.elevation_center = np.deg2rad(45) self.det.rotation = np.deg2rad(0) self.det.calculate_pixel_angles() assert np.allclose(self.det.horizontal, column( [1, 0, 0])), "Orientation vector is correct, elevation angle." assert np.allclose( self.det.vertical, np.sqrt(2) / 2 * column([0, 1, -1]) ), "Vertical orientation vector is correct, elevation angle."
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) )
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_lattice_vectors(lattice_lengths, lattice_angles): """Generate lattice vectors from lengths and angles. Parameters: lattice_lengths: tuple. the lattice lengths a,b,c in Angstroms. lattice_angles: tuple. the 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_vec, b_vec, c_vec: 3 column-wise vectors If invalid angles are given, c-vector may have a NaN. V: volume of the unit cell """ #Get the direct lattice parameters (a,b,c) = lattice_lengths (alpha, beta, gamma) = lattice_angles #Make the G metric matrix (tensor) # G =np.array( [ [a*a, a*b*cos(gamma), a*c*cos(beta)], # [a*b*cos(gamma), b*b, b*c*cos(alpha)], # [a*c*cos(beta), b*c*cos(alpha), c*c] ] ) # V = np.sqrt( np.linalg.det( G ) ) #Unit cell volume (Fundamentals of Crystallography, Giacovazzo editor, p.64) V = a*b*c * np.sqrt(1 - cos(alpha)**2 - cos(beta)**2 - cos(gamma)**2 + 2*cos(alpha)*cos(beta)*cos(gamma)) #V can be nan if bad parameters are passed in! #We take the "a" direction to be parallel with the x axis. a_vec = column( [a, 0, 0] ) #We take the b direction to be roughly towards +y, in the XY plane b_vec = column( [b*cos(gamma), b*sin(gamma), 0] ) #Finally, the c direction points towards z positive, but is not otherwise constrained # solution from Fundamentals of Crystallography, Giacovazzo editor, p.64, and 68 cos_alpha_star = (cos(beta)*cos(gamma)-cos(alpha)) / (sin(beta)*sin(gamma)) c_star = (a*b*sin(gamma)) / V c_vec = column( [c*cos(beta), -c*sin(beta)*cos_alpha_star, 1/c_star] ) return (a_vec, b_vec, c_vec, V)
def getq_python(azimuth, elevation, wl_output, rot_matrix, wl_input=None): """Find the q-vector corresponding to the azimuth, elevation and wavelength of the detector pixel. Uses only python and numpy code. Paramters: azimuth, elevation: azimuth, elevation angle of pixel(s). Can be an array, should be only 1-D though. Shapes of az and elev need to match. wl_output: output (scattered) wavelength considered; can be scalar or array matching az and elev. rot_matrix: The rotation matrix to apply to the q in the lab frame (should be the inverse of the goniometer rotation). wl_input: input (incident) wavelength; if not specified, defaults to wl_output Returns: q: q-vector, either a single column or a 3xn array depending on input size. """ #The Ewald sphere has 1/wl radius inelastic = True if wl_input is None: inelastic = False wl_input = wl_output #The scattered beam emanates from the centre of this spher. #Find the intersection of the scattered beam and the sphere, in XYZ beam = column(az_elev_direction(azimuth, elevation)) / wl_output #And here is the incident beam direction: Along the z-axis, positive incident = np.array([0, 0, 1.0]).reshape(3,1) / wl_input #The wave vector difference between the two is the q vector q = 2*pi * (beam - incident) #Now we switch to the coordinate system of the crystal. #The scattered beam direction (the detector location) is rotated relative to the crystal # because the sample is rotated. #So is the incident beam direction. #Therefore, the q-vector measured is simply rotated by the supplied rotation matrix (which has reversed angles) if inelastic: q_unrotated = q q = np.dot(rot_matrix, q_unrotated) return (q, q_unrotated) else: q = np.dot(rot_matrix, q) return q
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
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
def getq(az, elevation, wl_output, q_rot_matrix, wl_input=None): """Find the q-vector corresponding to the azimuth, elevation and wavelength of the detector pixel. Optimized for speed by using inline C code. Provides a ~45% time reduction for coverage calculation. Paramters: az, elevation: azimuth, elevation angle of pixel. Scalar only. wl_output: output (scattered) wavelength considered; can be scalar or array matching az and elev. q_rot_matrix: The q-rotation matrix; how the q-vector has to be rotated. This corresponds to the opposite angles of the sample orientation, so (-phi, -chi, -omega). wl_input: input (incident) wavelength; if not specified, defaults to wl_output Returns: q: q-vector, a single column """ support = """ #include <math.h> """ #Ensure the right data types! az = float(az) elevation = float(elevation) wl_output = float(wl_output) rot_matrix = q_rot_matrix if wl_input is None: # -- elastic --- wl_input = wl_output q = weave.inline(getq_code, ['wl_input', 'wl_output', 'elevation', 'az', 'pi', 'rot_matrix'],compiler='gcc', support_code = support,libraries = ['m']) q = column([q[0],q[1],q[2]]) return q else: #--- inelastic --- (q_both) = weave.inline(getq_inelastic_code, ['wl_input', 'wl_output', 'elevation', 'az', 'pi', 'rot_matrix'],compiler='gcc', support_code = support,libraries = ['m']) q = np.array(q_both[0:3]).reshape(3,1) q_unrot = np.array(q_both[3:]).reshape(3,1) return (q, q_unrot)
def test_detector_coord(self): """FlatDetector.detector_coord()""" det = self.det func = det.get_detector_coordinates #Invalid parameter errors self.assertRaises(ValueError, func, np.zeros( (2,10) )) self.assertRaises(ValueError, func, np.zeros(3) ) beam = column([10.0, 0.0, 0.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose( wl, 0.1), "Correct wavelength for one" beam = column([10.0, 20.0, 30.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose( wl, 1/np.sqrt(1400)), "Correct wavelength 2" beam = np.ones( (3, 15) )*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert h.shape == (15,), "Correct shape of h" # beam = column([0.0, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose( wl, 1.0), "Correct wavelength for one" beam = column([1.0, 0.0, 0.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "H and V are nan since the beam is parallel to the detector plane." assert not np.any(hits_it), "... and it doesn't hit, of course." beam = column([0.0, 1.0, 0.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "H and V are nan since the beam is parallel to the detector plane." assert not np.any(hits_it), "... and it doesn't hit, of course." beam = column([0.0, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.allclose(distance, 400.0), "Distance is equal to the detector face distance." assert np.all(hits_it), "... and it hits it." beam = column([0.0, 0.05, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v > 0.0), "V is above the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.0, -0.05, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v < 0.0), "V is below the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.0, 0.13, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v > 50.0), "V is above the detector edge." assert not np.all(hits_it), "... and it misses it." beam = column([0.05, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.all(h > 0.0), "h is to the left of the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.13, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.all(h > 50.0), "H is to the left of the detector edge." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses it." beam = column([0.0, 0.0, 0.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "Scattered beam is 0,0,0." assert not np.any(hits_it), "... and it doesn't hit, of course." #-- opposite direction --- beam = column([0.0, 0.0, -1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "H misses since the beam points the other way." assert np.isnan(v), "H misses since the beam points the other way." assert not np.all(hits_it), "Does not hit because the beam is in the opposite direction." #--- Wavelength too small ---- beam = column([0.0, 0.0, 1.0])*2*pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam, wl_min=2.0, wl_max=10.0) assert not np.all(hits_it), "Misses detector, wl is too small." (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam, wl_min=0.1, wl_max=0.5) assert not np.all(hits_it), "Misses detector, wl is too large."
def test_detector_coord(self): """FlatDetector.detector_coord()""" det = self.det func = det.get_detector_coordinates #Invalid parameter errors self.assertRaises(ValueError, func, np.zeros((2, 10))) self.assertRaises(ValueError, func, np.zeros(3)) beam = column([10.0, 0.0, 0.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(wl, 0.1), "Correct wavelength for one" beam = column([10.0, 20.0, 30.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(wl, 1 / np.sqrt(1400)), "Correct wavelength 2" beam = np.ones((3, 15)) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert h.shape == (15, ), "Correct shape of h" # beam = column([0.0, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(wl, 1.0), "Correct wavelength for one" beam = column([1.0, 0.0, 0.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan( h ), "H and V are nan since the beam is parallel to the detector plane." assert not np.any(hits_it), "... and it doesn't hit, of course." beam = column([0.0, 1.0, 0.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan( h ), "H and V are nan since the beam is parallel to the detector plane." assert not np.any(hits_it), "... and it doesn't hit, of course." beam = column([0.0, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.allclose( distance, 400.0), "Distance is equal to the detector face distance." assert np.all(hits_it), "... and it hits it." beam = column([0.0, 0.05, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v > 0.0), "V is above the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.0, -0.05, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v < 0.0), "V is below the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.0, 0.13, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.allclose(h, 0.0), "H is right in the middle of the detector." assert np.all(v > 50.0), "V is above the detector edge." assert not np.all(hits_it), "... and it misses it." beam = column([0.05, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.all( h > 0.0), "h is to the left of the middle of the detector." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert np.all(hits_it), "... and it hits it." beam = column([0.13, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.all(h > 50.0), "H is to the left of the detector edge." assert np.allclose(v, 0.0), "V is right in the middle of the detector." assert not np.all(hits_it), "... and it misses it." beam = column([0.0, 0.0, 0.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "Scattered beam is 0,0,0." assert not np.any(hits_it), "... and it doesn't hit, of course." #-- opposite direction --- beam = column([0.0, 0.0, -1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam) assert np.isnan(h), "H misses since the beam points the other way." assert np.isnan(v), "H misses since the beam points the other way." assert not np.all( hits_it ), "Does not hit because the beam is in the opposite direction." #--- Wavelength too small ---- beam = column([0.0, 0.0, 1.0]) * 2 * pi (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam, wl_min=2.0, wl_max=10.0) assert not np.all(hits_it), "Misses detector, wl is too small." (h, v, wl, distance, hits_it) = det.get_detector_coordinates(beam, wl_min=0.1, wl_max=0.5) assert not np.all(hits_it), "Misses detector, wl is too large."
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 setUp(self): hkl = column([1.0,2,3]) q_vector = 1.0/hkl self.ref = Reflection(hkl, q_vector)
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()
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 test_getq_vs_get_scattered_beam(self): "test_getq_vs_get_scattered_beam: getq and get_scattered_beam should give compatible results." #Test depends on test_make_UB_matrix() and on test_get_q_from_hkl() #Make up a simple lattice - cubic lat = ( 1.0, 1.0, 1.0) angles = tuple( np.deg2rad( [90, 90, 90])) UB = make_UB_matrix(lat, angles, 0, 0, 0) #No sample rotation rot_matrix = np.identity(3) #Let's try a non-scattered beam. q=0,0,0 hkl = column([0.,0.,0.]) scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB) assert np.allclose(scattered_q, [0,0,0]), "Non-scattered q-vector matches hkl 0,0,0" beam = get_scattered_beam(hkl, rot_matrix, UB) assert np.any(np.isnan(beam)), "Non-scattered beam direction is nan: %s" % beam.flatten() #Let's try a back-scattered beam. # So its q = 2 * (2*pi* 1/incident_wavelength) in the negative Z wl = 1.0 #1 Angstrom wl q1 = getq( -pi, 0, wl, rot_matrix) #Since the lattice is also 1 Angstrom, the reciprocal lattice is 2pi, so an l = -2 hkl = column([0.,0.,-2.]) scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB) assert np.allclose(scattered_q, q1), "Back-scattered q-vector matches hkl %s" % hkl.flatten() beam = get_scattered_beam(hkl, rot_matrix, UB) answer = column([0,0,-1.0]) * (2*pi/wl) assert np.allclose(beam, answer), "Back-scattered beam direction is correct: %s" % answer.flatten() #Let's try a back-scattered beam at twice the wavelength wl = 2.0 q1 = getq( -pi, 0, wl, rot_matrix) #Now a closer l should see it hkl = column([0.,0.,-1.]) scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB) assert np.allclose(scattered_q, q1), "Back-scattered q-vector matches hkl %s" % hkl.flatten() beam = get_scattered_beam(hkl, rot_matrix, UB) answer = column([0,0,-1.0]) * (2*pi/wl) assert np.allclose(beam, answer), "Back-scattered beam direction is correct: %s" % answer.flatten() #Opposite hkl hkl = column([0.,0.,+1.]) beam = get_scattered_beam(hkl, rot_matrix, UB) assert np.any(np.isnan(beam)), "No beam for an hkl of (0,0,1)" #Vertical q? wl = 1.0 q1 = getq( 0, np.pi/2, wl, rot_matrix) hkl = column([0.,+1.,-1.]) scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB) assert np.allclose(scattered_q, q1), "Vertically-scattered q-vector matches hkl %s" % hkl.flatten() beam = get_scattered_beam(hkl, rot_matrix, UB) answer = column([0,+1.0,0.0]) * (2*pi/wl) assert np.allclose(beam, answer), "Vertically-scattered beam direction is correct: %s" % answer.flatten() #Down q q1 = getq( 0, -np.pi/2, 1.0, rot_matrix) hkl = column([0.,-1.,-1.]) scattered_q = get_scattered_q_vector(hkl, rot_matrix, UB) assert np.allclose(scattered_q, q1), "Vertically-down-scattered q-vector matches hkl %s" % hkl.flatten() beam = get_scattered_beam(hkl, rot_matrix, UB) answer = column([0,-1.0,0.0]) * (2*pi/wl) assert np.allclose(beam, answer), "Vertically-down-scattered beam direction is correct: %s" % answer.flatten()
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"