def test_gnomonic_projection(self): """Testing the gnomonic_projection function on a complete image.""" # incident beam ksi = 0.4 # deg Xu = np.array( [np.cos(ksi * np.pi / 180), 0., np.sin(ksi * np.pi / 180)]) # create our detector detector = RegArrayDetector2d(size=(919, 728), u_dir=[0, -1, 0], v_dir=[0, 0, -1]) detector.pixel_size = 0.254 # mm binning 2x2 detector.ucen = 445 detector.vcen = 380 detector.ref_pos = np.array([127.8, 0., 0.]) + \ (detector.size[0] / 2 - detector.ucen) * detector.u_dir * detector.pixel_size + \ (detector.size[1] / 2 - detector.vcen) * detector.v_dir * detector.pixel_size # mm OC = detector.project_along_direction( Xu) # C is the intersection of the direct beam with the detector # create test image pattern = np.zeros(detector.size, dtype=np.uint8) for i in range(self.spots.shape[0]): # light corresponding pixels pattern[self.spots[i, 0], self.spots[i, 1]] = 255 detector.data = pattern gnom = gnomonic_projection(detector, pixel_size=4, OC=OC) import os test_dir = os.path.dirname(os.path.realpath(__file__)) ref_gnom_data = np.load(os.path.join(test_dir, 'ref_gnom_data.npy')) self.assertTrue(np.array_equal(gnom.data, ref_gnom_data)) pass
def test_add_detector(self): detector = RegArrayDetector2d(size=(512, 512)) self.assertEqual(self.experiment.get_number_of_detectors(), 0) self.experiment.add_detector(detector) self.assertEqual(self.experiment.get_number_of_detectors(), 1) self.assertTrue(self.experiment.sample.microstructure.autodelete) del self.experiment
def setUp(self): """testing the detectors module:""" self.detector = RegArrayDetector2d(size=(1024, 512)) self.detector.pixel_size = 0.1 # mm self.detector.ref_pos = np.array([ 100., 0., 0. ]) # position in the laboratory frame of the middle of the detector
def test_detector_tilt(self): """Verify the tilted coordinate frame """ for tilt in [1, 5, 10, 15]: # Detector tilt alpha/X ; beta/Y ; gamma/Z alpha = np.radians(tilt) # degree to rad, rotate around X axis beta = np.radians(tilt) # degree to rad, rotate around Y axis gamma = np.radians(tilt) # degree to rad, rotate around Z axis u1 = np.sin(gamma) * np.cos(beta) u2 = -np.cos(gamma) * np.cos(alpha) + np.sin(gamma) * np.sin( beta) * np.sin(alpha) u3 = -np.cos(gamma) * np.sin(alpha) - np.sin(gamma) * np.sin( beta) * np.cos(alpha) v1 = -np.sin(beta) v2 = np.cos(beta) * np.sin(alpha) v3 = -np.cos(beta) * np.cos(alpha) det_tilt = RegArrayDetector2d(size=(487, 619), u_dir=[u1, u2, u3], v_dir=[v1, v2, v3]) # compute w using trigonometry w1 = np.cos(gamma) * np.cos(beta) w2 = np.cos(gamma) * np.sin(beta) * np.sin(alpha) + np.sin( gamma) * np.cos(alpha) w3 = np.sin(gamma) * np.sin(alpha) - np.cos(gamma) * np.sin( beta) * np.cos(alpha) self.assertAlmostEqual(w1, det_tilt.w_dir[0], 7) self.assertAlmostEqual(w2, det_tilt.w_dir[1], 7) self.assertAlmostEqual(w3, det_tilt.w_dir[2], 7)
def test_save(self): if os.path.exists('experiment.txt'): os.remove('experiment.txt') detector1 = RegArrayDetector2d(size=(512, 512)) detector1.pixel_size = 0.1 detector1.ref_pos[0] = 100. self.experiment.add_detector(detector1) # set a second detector above the sample in the horizontal plane detector2 = RegArrayDetector2d(size=(512, 512)) detector2.pixel_size = 0.1 detector2.set_v_dir([0, -90, 0]) detector2.ref_pos[2] = 100. self.experiment.add_detector(detector2) self.experiment.active_detector_id = 0 self.experiment.save() self.assertTrue(os.path.exists('experiment.txt')) exp = Experiment.load('experiment.txt') self.assertTrue(exp.get_source().max_energy == 120.)
def gnomonic_projection(detector, pixel_size=None, OC=None, verbose=False): """This function carries out the gnomonic projection of the detector image. The data must be of uint8 type (between 0 and 255) with diffraction spots equals to 255. The function create a new detector instance (think of it as a virtual detector) located at the same position as the given detector and with an inverse pixel size. The gnomonic projection is stored into this new detector data. The gnomonic projection of each white pixel (value at 255) is computed. The projection is carried out with respect to the center detector (ucen, vcen) point. :param RegArrayDetector2d detector: the detector instance with the data from which to compute the projection. :param float pixel_size: pixel size to use in the virtual detector for the gnomonic projection. :param tuple OC: coordinates of the center of the gnomonic projection in the laboratory frame. :param bool verbose: flag to activate verbose mode. :returns RegArrayDetector2d gnom: A virtual detector with the gnomonic projection as its data. """ assert detector.data.dtype == np.uint8 dif = detector.data == 255 # boolean array used to select pixels with diffracted intensity dif_indices = np.where( dif) # (ui, vi) tuple with 1D arrays of the coordinates u and v n = dif_indices[0].shape if verbose: print('%d points in the gnomonic projection' % n) print('center of the projection: %s' % OC) uv_mm = detector.pixel_to_lab(dif_indices[0], dif_indices[1]) uvg_mm = gnomonic_projection_point(uv_mm, OC) # mm print(uvg_mm.shape) # create the new virtual detector from pymicro.xray.detectors import RegArrayDetector2d gnom = RegArrayDetector2d(size=np.array(detector.size)) gnom.ref_pos = detector.ref_pos # same ref position as the actual detector if not pixel_size: gnom.pixel_size = 1. / detector.pixel_size # mm else: gnom.pixel_size = pixel_size # mm # TODO remove the next two lines gnom.ucen = detector.ucen gnom.vcen = detector.vcen # create the gnom.data array (zeros with pixels set to 1 for gnomonic projection points) gnom.data = np.zeros(gnom.size, dtype=np.uint8) # uvg_px = gnom.lab_to_pixel(uvg_mm) uvg_px = np.zeros((uvg_mm.shape[0], 2), dtype=np.int) for i in range(uvg_mm.shape[0]): uvg_px[i, :] = gnom.lab_to_pixel(uvg_mm[i, :]) # filter out point outside the virtual detector detin = (uvg_px[:, 0] >= 0) & (uvg_px[:, 0] <= gnom.size[0] - 1) & \ (uvg_px[:, 1] >= 0) & (uvg_px[:, 1] <= gnom.size[1] - 1) gnom.data[uvg_px[detin, 0], uvg_px[detin, 1]] = 1 return gnom
def test_detector_tilt(self): """Verify the tilted coordinate frame calculation. The local frame is calculated by composing 3 rotations and the definition of the detector-to-pixel conversion. We have verified that: u[0] == np.cos(delta) * np.sin(omega) u[1] == -np.cos(kappa) * np.cos(omega) + np.sin(kappa) * np.sin(delta) * np.sin(omega) u[2] == -np.sin(kappa) * np.cos(omega) - np.cos(kappa) * np.sin(delta) * np.sin(omega) v[0] == -np.sin(delta) v[1] == np.sin(kappa) * np.cos(delta) v[2] == -np.cos(kappa) * np.cos(delta) w[0] == np.cos(omega) * np.cos(delta) w[1] == np.cos(omega) * np.sin(delta) * np.sin(kappa) + np.sin(omega) * np.cos(kappa) w[2] == np.sin(omega) * np.sin(kappa) - np.cos(omega) * np.sin(delta) * np.cos(kappa) so the test chack that the matrix composition gives the final result. """ for tilt in [1, 5, 10, 15]: # degrees # Detector tilt kappa/X ; delta/Y ; omega/Z det_tilt = RegArrayDetector2d(size=(487, 619), tilts=(tilt, tilt, tilt)) kappa, delta, omega = np.radians([tilt, tilt, tilt]) # compute u, v, w using trigonometry u1 = np.cos(delta) * np.sin(omega) u2 = -np.cos(kappa) * np.cos(omega) + np.sin(kappa) * np.sin( delta) * np.sin(omega) u3 = -np.sin(kappa) * np.cos(omega) - np.cos(kappa) * np.sin( delta) * np.sin(omega) v1 = -np.sin(delta) v2 = np.sin(kappa) * np.cos(delta) v3 = -np.cos(kappa) * np.cos(delta) w1 = np.cos(omega) * np.cos(delta) w2 = np.cos(omega) * np.sin(delta) * np.sin(kappa) + np.sin( omega) * np.cos(kappa) w3 = np.sin(omega) * np.sin(kappa) - np.cos(omega) * np.sin( delta) * np.cos(kappa) self.assertAlmostEqual(u1, det_tilt.u_dir[0], 7) self.assertAlmostEqual(u2, det_tilt.u_dir[1], 7) self.assertAlmostEqual(u3, det_tilt.u_dir[2], 7) self.assertAlmostEqual(v1, det_tilt.v_dir[0], 7) self.assertAlmostEqual(v2, det_tilt.v_dir[1], 7) self.assertAlmostEqual(v3, det_tilt.v_dir[2], 7) self.assertAlmostEqual(w1, det_tilt.w_dir[0], 7) self.assertAlmostEqual(w2, det_tilt.w_dir[1], 7) self.assertAlmostEqual(w3, det_tilt.w_dir[2], 7)
def test_gnomonic_projection_point(self): """Verify that the gnomonic projection of two diffracted points on a detector give access to the angle between the lattice plane normals.""" olivine = Lattice.orthorhombic( 1.022, 0.596, 0.481) # nm Barret & Massalski convention orientation = Orientation.cube() p1 = HklPlane(2, 0, -3, olivine) p2 = HklPlane(3, -1, -3, olivine) detector = RegArrayDetector2d(size=(512, 512), u_dir=[0, -1, 0], v_dir=[0, 0, -1]) detector.pixel_size = 0.200 # mm, 0.1 mm with factor 2 binning detector.ucen = 235 detector.vcen = 297 detector.ref_pos = np.array([131., 0., 0.]) + \ (detector.size[0] / 2 - detector.ucen) * detector.u_dir * detector.pixel_size + \ (detector.size[1] / 2 - detector.vcen) * detector.v_dir * detector.pixel_size # mm angle = 180 / np.pi * np.arccos(np.dot(p1.normal(), p2.normal())) # test the gnomonic projection for normal and not normal X-ray incidence for ksi in [0.0, 1.0]: # deg Xu = np.array( [np.cos(ksi * np.pi / 180), 0., np.sin(ksi * np.pi / 180)]) OC = detector.project_along_direction( Xu ) # C is the intersection of the direct beam with the detector K1 = diffracted_vector(p1, orientation, Xu=Xu) K2 = diffracted_vector(p2, orientation, Xu=Xu) R1 = detector.project_along_direction(K1, origin=[0., 0., 0.]) R2 = detector.project_along_direction(K2, origin=[0., 0., 0.]) OP1 = gnomonic_projection_point(R1, OC=OC)[0] OP2 = gnomonic_projection_point(R2, OC=OC)[0] hkl_normal1 = OP1 / np.linalg.norm(OP1) hkl_normal2 = (OP2 / np.linalg.norm(OP2)) # the projection must give the normal to the diffracting plane for i in range(3): self.assertAlmostEqual(hkl_normal1[i], p1.normal()[i], 6) self.assertAlmostEqual(hkl_normal2[i], p2.normal()[i], 6) angle_gp = 180 / np.pi * np.arccos(np.dot(hkl_normal1, hkl_normal2)) self.assertAlmostEqual(angle, angle_gp, 6)
def load(file_path='experiment.txt'): with open(file_path, 'r') as f: dict_exp = json.load(f) sample = Sample() sample.set_name(dict_exp['Sample']['Name']) sample.set_position(dict_exp['Sample']['Position']) if 'Geometry' in dict_exp['Sample']: sample_geo = ObjectGeometry() sample_geo.set_type(dict_exp['Sample']['Geometry']['Type']) sample.set_geometry(sample_geo) if 'Material' in dict_exp['Sample']: a, b, c = dict_exp['Sample']['Material']['Lengths'] alpha, beta, gamma = dict_exp['Sample']['Material']['Angles'] centering = dict_exp['Sample']['Material']['Centering'] symmetry = Symmetry.from_string( dict_exp['Sample']['Material']['Symmetry']) material = Lattice.from_parameters(a, b, c, alpha, beta, gamma, centering=centering, symmetry=symmetry) sample.set_material(material) if 'Microstructure' in dict_exp['Sample']: micro = Microstructure( dict_exp['Sample']['Microstructure']['Name']) for i in range(len( dict_exp['Sample']['Microstructure']['Grains'])): dict_grain = dict_exp['Sample']['Microstructure']['Grains'][i] grain = Grain( dict_grain['Id'], Orientation.from_euler( dict_grain['Orientation']['Euler Angles (degrees)'])) grain.position = np.array(dict_grain['Position']) grain.volume = dict_grain['Volume'] micro.grains.append(grain) sample.set_microstructure(micro) exp = Experiment() exp.set_sample(sample) source = XraySource() source.set_position(dict_exp['Source']['Position']) if 'Min Energy (keV)' in dict_exp['Source']: source.set_min_energy(dict_exp['Source']['Min Energy (keV)']) if 'Max Energy (keV)' in dict_exp['Source']: source.set_max_energy(dict_exp['Source']['Max Energy (keV)']) exp.set_source(source) for i in range(len(dict_exp['Detectors'])): dict_det = dict_exp['Detectors'][i] if dict_det['Class'] == 'Detector2d': det = Detector2d(size=dict_det['Size (pixels)']) det.ref_pos = dict_det['Reference Position (mm)'] if dict_det['Class'] == 'RegArrayDetector2d': det = RegArrayDetector2d(size=dict_det['Size (pixels)']) det.pixel_size = dict_det['Pixel Size (mm)'] det.ref_pos = dict_det['Reference Position (mm)'] if 'Binning' in dict_det: det.set_binning(dict_det['Binning']) det.u_dir = np.array(dict_det['u_dir']) det.v_dir = np.array(dict_det['v_dir']) det.w_dir = np.array(dict_det['w_dir']) exp.add_detector(det) return exp
def test_add_detector(self): detector = RegArrayDetector2d(size=(512, 512)) self.assertEqual(self.experiment.get_number_of_detectors(), 0) self.experiment.add_detector(detector) self.assertEqual(self.experiment.get_number_of_detectors(), 1)
def load(file_path='experiment.txt'): with open(file_path, 'r') as f: dict_exp = json.load(f) name = dict_exp['Sample']['Name'] sample = Sample(name=name) sample.data_dir = dict_exp['Sample']['Data Dir'] sample.set_position(dict_exp['Sample']['Position']) if 'Geometry' in dict_exp['Sample']: sample_geo = ObjectGeometry() sample_geo.set_type(dict_exp['Sample']['Geometry']['Type']) sample.set_geometry(sample_geo) if 'Material' in dict_exp['Sample']: a, b, c = dict_exp['Sample']['Material']['Lengths'] alpha, beta, gamma = dict_exp['Sample']['Material']['Angles'] centering = dict_exp['Sample']['Material']['Centering'] symmetry = Symmetry.from_string( dict_exp['Sample']['Material']['Symmetry']) material = Lattice.from_parameters(a, b, c, alpha, beta, gamma, centering=centering, symmetry=symmetry) sample.set_material(material) if 'Microstructure' in dict_exp['Sample']: micro = Microstructure( name=dict_exp['Sample']['Microstructure']['Name'], file_path=os.path.dirname(file_path)) # crystal lattice if 'Lattice' in dict_exp['Sample']['Microstructure']: a, b, c = dict_exp['Sample']['Microstructure']['Lattice'][ 'Lengths'] alpha, beta, gamma = dict_exp['Sample']['Microstructure'][ 'Lattice']['Angles'] centering = dict_exp['Sample']['Microstructure']['Lattice'][ 'Centering'] symmetry = Symmetry.from_string( dict_exp['Sample']['Microstructure']['Lattice'] ['Symmetry']) lattice = Lattice.from_parameters(a, b, c, alpha, beta, gamma, centering=centering, symmetry=symmetry) micro.set_lattice(lattice) grain = micro.grains.row for i in range(len( dict_exp['Sample']['Microstructure']['Grains'])): dict_grain = dict_exp['Sample']['Microstructure']['Grains'][i] grain['idnumber'] = int(dict_grain['Id']) euler = dict_grain['Orientation']['Euler Angles (degrees)'] grain['orientation'] = Orientation.from_euler(euler).rod grain['center'] = np.array(dict_grain['Position']) grain['volume'] = dict_grain['Volume'] # if 'hkl_planes' in dict_grain: # grain.hkl_planes = dict_grain['hkl_planes'] grain.append() micro.grains.flush() sample.set_microstructure(micro) sample.microstructure.autodelete = True # lazy behaviour, we load only the grain_ids path, the actual array is loaded in memory if needed sample.grain_ids_path = dict_exp['Sample']['Grain Ids Path'] exp = Experiment() exp.set_sample(sample) source = XraySource() source.set_position(dict_exp['Source']['Position']) if 'Min Energy (keV)' in dict_exp['Source']: source.set_min_energy(dict_exp['Source']['Min Energy (keV)']) if 'Max Energy (keV)' in dict_exp['Source']: source.set_max_energy(dict_exp['Source']['Max Energy (keV)']) exp.set_source(source) for i in range(len(dict_exp['Detectors'])): dict_det = dict_exp['Detectors'][i] if dict_det['Class'] == 'Detector2d': det = Detector2d(size=dict_det['Size (pixels)']) det.ref_pos = dict_det['Reference Position (mm)'] if dict_det['Class'] == 'RegArrayDetector2d': det = RegArrayDetector2d(size=dict_det['Size (pixels)']) det.pixel_size = dict_det['Pixel Size (mm)'] det.ref_pos = dict_det['Reference Position (mm)'] if 'Min Energy (keV)' in dict_exp['Detectors']: det.tilt = dict_det['Tilts (deg)'] if 'Binning' in dict_det: det.set_binning(dict_det['Binning']) det.u_dir = np.array(dict_det['u_dir']) det.v_dir = np.array(dict_det['v_dir']) det.w_dir = np.array(dict_det['w_dir']) exp.add_detector(det) return exp