def predict(self, indices, angles): # extract required information from the models sensor = self._detector.sensors()[0] # assume only one sensor for now axis = matrix.col(self._gonio.get_rotation_axis()) s0 = matrix.col(self._beam.get_s0()) UB = self._crystal.get_U() * self._crystal.get_B() # instantiate predictor rp = reflection_prediction(axis, s0, UB, sensor) # perform impact prediction # rp.predict does not like indices as miller_index. A conversion to # matrix.col fixes that temp = [] for hkl in indices: hkl = matrix.col(hkl) temp.append(hkl) Hc, Xc, Yc, Phic, Sc = rp.predict(temp, angles) # Hc is now an an array of floating point vec3. How annoying! We want # integer Miller indices. Force that to be so. # Once we have new (fast) reflection prediction code that does not # return floating point indices then this whole class can be replaced temp = flex.miller_index() for hkl in Hc: hkl = map(lambda x: int(round(x)), hkl) temp.append(tuple(hkl)) # Rescale normalised scattering vectors to the correct length wavelength = self._beam.get_wavelength() Sc = map(lambda s: matrix.col(s) / wavelength, Sc) return (temp, Xc, Yc, Phic, Sc)
def scattering_prediction(reflections, UB_mat, rotation_vector, wavelength, resolution, assert_non_integer_index=False): '''Test the reflection_prediction class.''' ra = rotation_angles(resolution, UB_mat, wavelength, rotation_vector) beam_vector = matrix.col([0, 0, 1 / wavelength]) detector_size = 100 detector_distance = 100 s = sensor( matrix.col( (-0.5 * detector_size, -0.5 * detector_size, detector_distance)), matrix.col((1, 0, 0)), matrix.col((0, 1, 0)), (0, detector_size), (0, detector_size)) rp = reflection_prediction(rotation_vector, beam_vector, UB_mat, s) for hkl in reflections: if ra(hkl): omegas = ra.get_intersection_angles() if assert_non_integer_index: assert ra.H[0] != int(ra.H[0]) or \ ra.H[1] != int(ra.H[1]) or \ ra.H[2] != int(ra.H[2]) for omegaidx in [0, 1]: rot_mat = rotation_vector.axis_and_angle_as_r3_rotation_matrix( omegas[omegaidx]) assert (math.fabs(rot_mat.determinant() - 1.0) < 0.0001) H1 = (rot_mat * UB_mat) * hkl H1 = H1 + beam_vector len_H1 = math.sqrt((H1[0] * H1[0]) + (H1[1] * H1[1]) + (H1[2] * H1[2])) if math.fabs(len_H1 - 1.0 / wavelength) > 0.0001: raise RuntimeError, 'length error for %d %d %d' % hkl if rp(hkl, omegas[omegaidx]): x, y = rp.get_prediction() assert (0 < x < detector_size) assert (0 < y < detector_size)
def scattering_prediction(reflections, UB_mat, rotation_vector, wavelength, resolution, assert_non_integer_index = False): '''Test the reflection_prediction class.''' ra = rotation_angles(resolution, UB_mat, wavelength, rotation_vector) beam_vector = matrix.col([0, 0, 1 / wavelength]) detector_size = 100 detector_distance = 100 s = sensor(matrix.col((- 0.5 * detector_size, - 0.5 * detector_size, detector_distance)), matrix.col((1, 0, 0)), matrix.col((0, 1, 0)), (0, detector_size), (0, detector_size)) rp = reflection_prediction(rotation_vector, beam_vector, UB_mat, s) for hkl in reflections: if ra(hkl): omegas = ra.get_intersection_angles() if assert_non_integer_index: assert ra.H[0] != int(ra.H[0]) or \ ra.H[1] != int(ra.H[1]) or \ ra.H[2] != int(ra.H[2]) for omegaidx in [0,1]: rot_mat = rotation_vector.axis_and_angle_as_r3_rotation_matrix( omegas[omegaidx]) assert(math.fabs(rot_mat.determinant() - 1.0) < 0.0001) H1 = (rot_mat * UB_mat)*hkl H1 = H1 + beam_vector len_H1 = math.sqrt((H1[0] * H1[0]) + (H1[1] * H1[1]) + (H1[2] * H1[2])) if math.fabs(len_H1 - 1.0 / wavelength) > 0.0001: raise RuntimeError, 'length error for %d %d %d' % hkl if rp(hkl, omegas[omegaidx]): x, y = rp.get_prediction() assert(0 < x < detector_size) assert(0 < y < detector_size)
def predict_observations(self): '''Actually perform the prediction calculations.''' d2r = math.pi / 180.0 cfc = coordinate_frame_converter(self._configuration_file) self.img_start, self.osc_start, self.osc_range = parse_xds_xparm_scan_info( self._configuration_file) if self._dmin is None: self._dmin = cfc.derive_detector_highest_resolution() phi_start = ((self._img_range[0] - self.img_start) * self.osc_range + \ self.osc_start) * d2r phi_end = ((self._img_range[1] - self.img_start + 1) * self.osc_range + \ self.osc_start) * d2r self.phi_start_rad = phi_start self.phi_end_rad = phi_end # in principle this should come from the crystal model - should that # crystal model record the cell parameters or derive them from the # axis directions? A = cfc.get_c('real_space_a') B = cfc.get_c('real_space_b') C = cfc.get_c('real_space_c') cell = (A.length(), B.length(), C.length(), B.angle(C, deg = True), C.angle(A, deg = True), A.angle(B, deg = True)) self.uc = unit_cell(cell) # generate all of the possible indices, then pull out those which should # be systematically absent sg = cfc.get('space_group_number') indices = full_sphere_indices( unit_cell = self.uc, resolution_limit = self._dmin, space_group = space_group(space_group_symbols(sg).hall())) # then get the UB matrix according to the Rossmann convention which # is used within the Labelit code. u, b = cfc.get_u_b(convention = cfc.ROSSMANN) axis = cfc.get('rotation_axis', convention = cfc.ROSSMANN) ub = u * b wavelength = cfc.get('wavelength') self.wavelength = wavelength # work out which reflections should be observed (i.e. pass through the # Ewald sphere) ra = rotation_angles(self._dmin, ub, wavelength, axis) obs_indices, obs_angles = ra.observed_indices_and_angles_from_angle_range( phi_start_rad = phi_start, phi_end_rad = phi_end, indices = indices) # convert all of these to full scattering vectors in a laboratory frame # (for which I will use the CBF coordinate frame) and calculate which # will intersect with the detector u, b = cfc.get_u_b() axis = cfc.get_c('rotation_axis') # must guarantee that sample_to_source vector is normalized so that # s0 has length of 1/wavelength. sample_to_source_vec = cfc.get_c('sample_to_source').normalize() s0 = (- 1.0 / wavelength) * sample_to_source_vec ub = u * b # need some detector properties for this as well... starting to # abstract these to a detector model. df = detector_factory_from_cfc(cfc) d = df.build() # the Use Case assumes the detector consists of a single sensor sensor = d.sensors()[0] self.pixel_size_fast, self.pixel_size_slow = d.px_size_fast(), \ d.px_size_slow() # used for polarization correction self.distance = sensor.distance rp = reflection_prediction(axis, s0, ub, sensor) if self._rocking_curve is not None: assert self._rocking_curve != "none" rp.set_rocking_curve(self._rocking_curve) rp.set_mosaicity(self._mosaicity_deg, degrees = True) return rp.predict(obs_indices, obs_angles)
my_panel = sensor(origin, fast, slow, lim, lim) # equivalent using the dials Panel dials_panel = Panel( "PAD", fast, slow, origin, (lim[1] / 200, lim[1] / 200), (200, 200), (0, 2e20) ) # get the bits needed to make a RayPredictor s0 = mybeam.get_s0() spindle = mygonio.get_rotation_axis() ray_predictor = RayPredictor(s0, spindle, UB, sweep_range) # also make a reflection_prediction object from rstbx.diffraction import reflection_prediction rp = reflection_prediction(mygonio.get_rotation_axis(), mybeam.get_s0(), UB, my_panel) # predict hkls, d1s, d2s, angles, s_dirs = rp.predict( dials_obs_indices.as_vec3_double(), dials_angles ) # dials_indices is a cctbx_array_family_flex_ext.miller_index object # dials_reflections is a dials_model_data_ext.ReflectionList object dials_reflections = ray_predictor(dials_indices) # I can use ray_predictor one reflection at a time by looping over # dials_indices. It will return a ReflectionList, which will be of length # zero if the reflection has no predicted angles, or of length two, if # the enter and exit angles are predicted.
# direct use of the sensor constructor lim = (0,50) my_panel = sensor(origin, fast, slow, lim, lim) # equivalent using the dials Panel dials_panel = Panel("PAD", fast, slow, origin, (lim[1]/200, lim[1]/200), (200, 200), (0, 2e20)) # get the bits needed to make a RayPredictor s0 = mybeam.get_s0() spindle = mygonio.get_rotation_axis() ray_predictor = RayPredictor(s0, spindle, UB, sweep_range) # also make a reflection_prediction object from rstbx.diffraction import reflection_prediction rp = reflection_prediction(mygonio.get_rotation_axis(), mybeam.get_s0(), UB, my_panel) # predict hkls, d1s, d2s, angles, s_dirs = rp.predict( dials_obs_indices.as_vec3_double(), dials_angles) # dials_indices is a cctbx_array_family_flex_ext.miller_index object # dials_reflections is a dials_model_data_ext.ReflectionList object dials_reflections = ray_predictor(dials_indices) # I can use ray_predictor one reflection at a time by looping over # dials_indices. It will return a ReflectionList, which will be of length # zero if the reflection has no predicted angles, or of length two, if # the enter and exit angles are predicted.