def _compose_core(self, raw_vals): # obtain metrical matrix parameters on natural scale vals = [v * 1.e-5 for v in raw_vals] # set parameter values in the symmetrizing object and obtain new B try: newB = matrix.sqr( self._S.backward_orientation(vals).reciprocal_matrix()) except RuntimeError as e: from libtbx.utils import Sorry # write original error to debug log logger.debug('Unable to compose the crystal model') logger.debug('Original error message: {0}'.format(str(e))) logger.debug('Failing now.') raise Sorry('Unable to compose the crystal model. Please check that the ' 'experiments match the indexing of the reflections.') # returns the independent parameters given the set_orientation() B matrix # used here for side effects self._S.forward_independent_parameters() # get the derivatives of state wrt metrical matrix parameters on the # adjusted scale dB_dval = [matrix.sqr(e) * 1.e-5 \ for e in self._S.forward_gradients()] return newB, dB_dval
def __init__(self, obj): from dxtbx.model.crystal import crystal_model import cctbx.uctbx from scitbx import matrix # Get the crystal parameters unit_cell_parameters = list(obj.handle['unit_cell'][0]) unit_cell = cctbx.uctbx.unit_cell(unit_cell_parameters) U = list(obj.handle['orientation_matrix'][0].flatten()) U = matrix.sqr(U) B = matrix.sqr(unit_cell.fractionalization_matrix()).transpose() A = U * B Ai = A.inverse() real_space_a = Ai[0:3] real_space_b = Ai[3:6] real_space_c = Ai[6:9] # Get the space group symbol space_group_symbol = obj.handle['unit_cell_group'][()] # Create the model self.model = crystal_model( real_space_a, real_space_b, real_space_c, space_group_symbol)
def exercise_flood_fill(): uc = uctbx.unit_cell('10 10 10 90 90 90') for uc in (uctbx.unit_cell('10 10 10 90 90 90'), uctbx.unit_cell('9 10 11 87 91 95')): gridding = maptbx.crystal_gridding( unit_cell=uc, pre_determined_n_real=(5,5,5)) corner_cube = (0,4,20,24,100,104,120,124) # cube across all 8 corners channel = (12,37,38,39,42,43,62,63,67,68,87,112) data = flex.int(flex.grid(gridding.n_real())) for i in (corner_cube + channel): data[i] = 1 flood_fill = masks.flood_fill(data, uc) assert data.count(0) == 105 for i in corner_cube: assert data[i] == 2 for i in channel: assert data[i] == 3 assert approx_equal(flood_fill.centres_of_mass(), ((-0.5, -0.5, -0.5), (-2.5, 7/3, 2.5))) assert approx_equal(flood_fill.centres_of_mass_frac(), ((-0.1, -0.1, -0.1), (-0.5, 7/15, 0.5))) assert approx_equal(flood_fill.centres_of_mass_cart(), uc.orthogonalize(flood_fill.centres_of_mass_frac())) assert flood_fill.n_voids() == 2 assert approx_equal(flood_fill.grid_points_per_void(), (8, 12)) if 0: from crys3d import wx_map_viewer wx_map_viewer.display(raw_map=data.as_double(), unit_cell=uc, wires=False) # gridding = maptbx.crystal_gridding( unit_cell=uc, pre_determined_n_real=(10,10,10)) data = flex.int(flex.grid(gridding.n_real())) # parallelogram points = [(2,4,5),(3,4,5),(4,4,5),(5,4,5),(6,4,5), (3,5,5),(4,5,5),(5,5,5),(6,5,5),(7,5,5), (4,6,5),(5,6,5),(6,6,5),(7,6,5),(8,6,5)] points_frac = flex.vec3_double() for p in points: data[p] = 1 points_frac.append([p[i]/gridding.n_real()[i] for i in range(3)]) points_cart = uc.orthogonalize(points_frac) flood_fill = masks.flood_fill(data, uc) assert data.count(2) == 15 assert approx_equal(flood_fill.centres_of_mass_frac(), ((0.5,0.5,0.5),)) pai_cart = math.principal_axes_of_inertia( points=points_cart, weights=flex.double(points_cart.size(),1.0)) F = matrix.sqr(uc.fractionalization_matrix()) O = matrix.sqr(uc.orthogonalization_matrix()) assert approx_equal( pai_cart.center_of_mass(), flood_fill.centres_of_mass_cart()[0]) assert approx_equal( flood_fill.covariance_matrices_cart()[0], (F.transpose() * matrix.sym( sym_mat3=flood_fill.covariance_matrices_frac()[0]) * F).as_sym_mat3()) assert approx_equal( pai_cart.inertia_tensor(), flood_fill.inertia_tensors_cart()[0]) assert approx_equal(pai_cart.eigensystem().vectors(), flood_fill.eigensystems_cart()[0].vectors()) assert approx_equal(pai_cart.eigensystem().values(), flood_fill.eigensystems_cart()[0].values()) return
def v2calib2sections(filename): """The v2calib2sections() function reads calibration information stored in new style SLAC calibration file and returns a two-dimensional array of Section objects. The first index in the returned array identifies the quadrant, and the second index identifies the section within the quadrant. @param dirname Directory with calibration information @return Section objects """ from xfel.cftbx.detector.cspad_cbf_tbx import read_slac_metrology from scitbx.matrix import sqr from xfel.cxi.cspad_ana.cspad_tbx import pixel_size # metro is a dictionary where the keys are levels in the detector # hierarchy and the values are 'basis' objects metro = read_slac_metrology(filename) # 90 degree rotation to get into same frame reference_frame = sqr((0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)) d = 0 d_basis = metro[(d,)] sections = [] for q in xrange(4): sections.append([]) q_basis = metro[(d,q)] for s in xrange(8): if not (d,q,s) in metro: continue s_basis = metro[(d,q,s)] # collapse the transformations from the detector center to the quadrant center # to the sensor center transform = reference_frame * \ d_basis.as_homogenous_transformation() * \ q_basis.as_homogenous_transformation() * \ s_basis.as_homogenous_transformation() # an homologous transformation is a 4x4 matrix, with a 3x3 rotation in the # upper left corner and the translation in the right-most column. The last # row is 0,0,0,1 ori = sqr((transform[0],transform[1],transform[2], transform[4],transform[5],transform[6], transform[8],transform[9],transform[10])) angle = ori.r3_rotation_matrix_as_x_y_z_angles(deg=True)[2] # move the reference of the sensor so its relative to the upper left of the # detector instead of the center of the detector center = (1765/2)+(transform[3]/pixel_size),(1765/2)+(transform[7]/pixel_size) sections[q].append(Section(angle, center)) return sections
def compute_u(mosflm_a_matrix, unit_cell, wavelength): uc = uctbx.unit_cell(unit_cell) A = (1.0 / wavelength) * matrix.sqr(mosflm_a_matrix) B = matrix.sqr(uc.orthogonalization_matrix()).inverse() return A * B.inverse()
def __init__(self, r, d, symmetry_agreement, status): assert r.den() == 1 self.r = r order = r.order() self.r_info = sgtbx.rot_mx_info(r) type = self.r_info.type() axis = self.r_info.ev() self.symmetry_agreement = symmetry_agreement self.status = status # compute intrinsic and location part of d, using p, which is # the order times the projector onto r's invariant space p = mat.sqr(r.accumulate().as_double()) t_i_num = (p*d).as_int() t_l = d - t_i_num/order t_i = sgtbx.tr_vec(sg_t_den//order*t_i_num, tr_den=sg_t_den) # compute the origin corresponding to t_l by solving # (1 - r) o = t_l one_minus_r = -mat.sqr(self.r.minus_unit_mx().num()) one_minus_r_row_echelon = one_minus_r.as_flex_int_matrix() q = mat.identity(3).as_flex_int_matrix() rank = scitbx.math.row_echelon_form_t(one_minus_r_row_echelon, q) qd = flex.double(mat.sqr(q)*t_l)[:rank] o = flex.double((0,0,0)) scitbx.math.row_echelon_back_substitution_float( one_minus_r_row_echelon, qd, o) # construct object state self.t_i, self.raw_origin = t_i, mat.col(o) self.origin = None self.one_minus_r = one_minus_r
def dials_u_to_mosflm(dials_U, uc): """Compute the mosflm U matrix i.e. the U matrix from same UB definition as DIALS, but with Busing & Levy B matrix definition.""" from scitbx.matrix import sqr from math import sin, cos, pi parameters = uc.parameters() dials_B = sqr(uc.fractionalization_matrix()).transpose() dials_UB = dials_U * dials_B r_parameters = uc.reciprocal_parameters() a = parameters[:3] al = [pi * p / 180.0 for p in parameters[3:]] b = r_parameters[:3] be = [pi * p / 180.0 for p in r_parameters[3:]] mosflm_B = sqr( ( b[0], b[1] * cos(be[2]), b[2] * cos(be[1]), 0, b[1] * sin(be[2]), -b[2] * sin(be[1]) * cos(al[0]), 0, 0, 1.0 / a[2], ) ) mosflm_U = dials_UB * mosflm_B.inverse() return mosflm_U
def prepare(self, image_number, step = 1): """ Cache transformations that position relps at the beginning and end of the step. """ self._image_number = image_number self._step = step phi_beg = self._scan.get_angle_from_array_index(image_number, deg = False) phi_end = self._scan.get_angle_from_array_index(image_number + step, deg = False) r_beg = matrix.sqr(scitbx.math.r3_rotation_axis_and_angle_as_matrix( axis = self._axis, angle = phi_beg, deg = False)) r_end = matrix.sqr(scitbx.math.r3_rotation_axis_and_angle_as_matrix( axis = self._axis, angle = phi_end, deg = False)) self._A1 = r_beg * self._crystal.get_A_at_scan_point(image_number - \ self._first_image) self._A2 = r_end * self._crystal.get_A_at_scan_point(image_number - \ self._first_image + step) return
def step_D(self): """ Determination of vibration components (Step D). """ print_step("Step D:", self.log) es = self.eigen_system_default_handler(m=self.V_L, suffix="V_L") self.v_x, self.v_y, self.v_z = es.x, es.y, es.z self.tx, self.ty, self.tz = es.vals[0]**0.5,es.vals[1]**0.5,es.vals[2]**0.5 self.show_vector(x=self.v_x, title="v_x") self.show_vector(x=self.v_y, title="v_y") self.show_vector(x=self.v_z, title="v_z") if(min(es.vals)<0): raise RuntimeError # checked with Sorry at Step C. R = matrix.sqr( [self.v_x[0], self.v_y[0], self.v_z[0], self.v_x[1], self.v_y[1], self.v_z[1], self.v_x[2], self.v_y[2], self.v_z[2]]) self.V_V = m=R.transpose()*self.V_L*R self.show_matrix(x=self.V_V, title="V_V") self.v_x_M = self.R_ML*self.v_x self.v_y_M = self.R_ML*self.v_y self.v_z_M = self.R_ML*self.v_z self.R_MV = matrix.sqr( [self.v_x_M[0], self.v_y_M[0], self.v_z_M[0], self.v_x_M[1], self.v_y_M[1], self.v_z_M[1], self.v_x_M[2], self.v_y_M[2], self.v_z_M[2]])
def displace_panel_fast_slow(self, serial, fast, slow): """Displace all ASICS:s in the panel with serial @p serial such that their new average position becomes @p fast, @p slow. The function returns the updated transformation matrices. """ # XXX Should use per-ASIC pixel size from the phil object. dx, dy = fast * self._pixel_size[0], -slow * self._pixel_size[1] for key, (Tf, Tb) in self._matrices.iteritems(): if (len(key) == 4 and key[1] == serial): Tb_new = sqr( [Tb(0, 0), Tb(0, 1), Tb(0, 2), Tb(0, 3) + dx, Tb(1, 0), Tb(1, 1), Tb(1, 2), Tb(1, 3) + dy, Tb(2, 0), Tb(2, 1), Tb(2, 2), Tb(2, 3) + 0, Tb(3, 0), Tb(3, 1), Tb(3, 2), Tb(3, 3) + 0]) # XXX Math worked out elsewhere. Tf_new = sqr( [Tf(0, 0), Tf(0, 1), Tf(0, 2), Tf(0, 3) - Tf(0, 0) * dx - Tf(0, 1) * dy, Tf(1, 0), Tf(1, 1), Tf(1, 2), Tf(1, 3) - Tf(1, 0) * dx - Tf(1, 1) * dy, Tf(2, 0), Tf(2, 1), Tf(2, 2), Tf(2, 3) - Tf(2, 0) * dx - Tf(2, 1) * dy, Tf(3, 0), Tf(3, 1), Tf(3, 2), Tf(3, 3) - Tf(3, 0) * dx - Tf(3, 1) * dy]) self._matrices[key] = (Tf_new, Tb_new) return self._matrices
def calc_partiality_anisotropy_set(self, my_uc, rotx, roty, miller_indices, ry, rz, r0, re, nu, bragg_angle_set, alpha_angle_set, wavelength, crystal_init_orientation, spot_pred_x_mm_set, spot_pred_y_mm_set, detector_distance_mm, partiality_model, flag_beam_divergence): #use III.4 in Winkler et al 1979 (A35; P901) for set of miller indices O = sqr(my_uc.orthogonalization_matrix()).transpose() R = sqr(crystal_init_orientation.crystal_rotation_matrix()).transpose() CO = crystal_orientation(O*R, basis_type.direct) CO_rotate = CO.rotate_thru((1,0,0), rotx ).rotate_thru((0,1,0), roty) A_star = sqr(CO_rotate.reciprocal_matrix()) S0 = -1*col((0,0,1./wavelength)) #caculate rs rs_set = r0 + (re * flex.tan(bragg_angle_set)) if flag_beam_divergence: rs_set += ((ry * flex.cos(alpha_angle_set))**2 + (rz * flex.sin(alpha_angle_set))**2)**(1/2) #calculate rh x = A_star.elems * miller_indices.as_vec3_double() sd_array = x + S0.elems rh_set = sd_array.norms() - (1/wavelength) #calculate partiality if partiality_model == "Lorentzian": partiality_set = ((rs_set**2)/((2*(rh_set**2))+(rs_set**2))) elif partiality_model == "Voigt": partiality_set = self.voigt(rh_set, rs_set, nu) elif partiality_model == "Lognormal": partiality_set = self.lognpdf(rh_set, rs_set, nu) #calculate delta_xy d_ratio = -detector_distance_mm/sd_array.parts()[2] calc_xy_array = flex.vec3_double(sd_array.parts()[0]*d_ratio, \ sd_array.parts()[1]*d_ratio, flex.double([0]*len(d_ratio))) pred_xy_array = flex.vec3_double(spot_pred_x_mm_set, spot_pred_y_mm_set, flex.double([0]*len(d_ratio))) delta_xy_set = (pred_xy_array - calc_xy_array).norms() return partiality_set, delta_xy_set, rs_set, rh_set
def set_ladp(xray_structure, axes_and_atoms_i_seqs, value, depth, enable_recursion=True): sc = (math.pi/180) sites_cart = xray_structure.sites_cart() scatterers = xray_structure.scatterers() all_selections = flex.size_t() u_carts = flex.sym_mat3_double(sites_cart.size(), [0,0,0,0,0,0]) for i_seq, aaa_ in enumerate(axes_and_atoms_i_seqs): if(enable_recursion): query = i_seq >= depth else: query = i_seq == depth if(query): all_selections.extend(aaa_[0][1]) for i_seq, r in enumerate(axes_and_atoms_i_seqs): if(enable_recursion): query = i_seq >= depth else: query = i_seq == depth if(query): for aaai in r: G1 = flex.double(sites_cart[aaai[0][0]]) G2 = flex.double(sites_cart[aaai[0][1]]) g = G2-G1 dg = math.sqrt(g[0]**2+g[1]**2+g[2]**2) lx,ly,lz = g/dg l = [lx,ly,lz] L = matrix.sqr((lx**2,lx*ly,lx*lz, lx*ly,ly**2,ly*lz, lx*lz,ly*lz,lz**2)) for i_seq_moving in aaai[1]: site_cart = sites_cart[i_seq_moving] delta = flex.double(site_cart) - G1 A = matrix.sqr( (0,delta[2],-delta[1], -delta[2],0,delta[0], delta[1],-delta[0],0)) u_cart = (value * A * L * A.transpose() * sc).as_sym_mat3() check_u_cart(axis = l, u_cart = u_cart) scatterers[i_seq_moving].flags.set_use_u_aniso(True) u_carts[i_seq_moving] = list(flex.double(u_carts[i_seq_moving]) + flex.double(u_cart)) xray_structure.set_u_cart(u_cart = u_carts, selection = all_selections) return xray_structure
def compute_Q(xparm_target, xparm_move): _M = determine_rotation_to_dtrek(xparm_target) a_t, b_t, c_t = parse_xds_xparm(xparm_target) a_m, b_m, c_m = parse_xds_xparm(xparm_move) m_t = matrix.sqr(a_t + b_t + c_t) min_r = 180.0 min_ax = None for op in ['X,Y,Z', '-X,-Y,Z', '-X,Y,-Z', 'X,-Y,-Z', 'Z,X,Y', 'Z,-X,-Y', '-Z,-X,Y', '-Z,X,-Y', 'Y,Z,X', '-Y,Z,-X', 'Y,-Z,-X', '-Y,-Z,X']: op_m = op_to_mat(op) m_m = op_m * matrix.sqr(a_m + b_m + c_m) q = m_t.inverse() * m_m if math.fabs(q.determinant() - 1) > 0.1: print 'rejected %s' % op continue q_r = r3_rotation_axis_and_angle_from_matrix(q.inverse()) if math.fabs(q_r.angle(deg = True)) < min_r: if q_r.angle(deg = True) >= 0: min_ax = matrix.col(q_r.axis) min_r = q_r.angle(deg = True) else: min_ax = - matrix.col(q_r.axis) min_r = - q_r.angle(deg = True) return (_M * min_ax).elems, min_r
def get_local_d_matrix(self): ''' Get the local d matrix. ''' from scitbx import matrix if self.parent() is None: return self.get_d_matrix() tl = matrix.sqr(self.get_local_transformation_matrix()).transpose() return matrix.sqr(tl[0:3] + tl[4:7] + tl[12:15]).elems
def __init__(self, phi0, misset0, phi1, misset1): """Initialise the rotation axis and what have you from some experimental results. N.B. all input values in DEGREES.""" # canonical: X = X-ray beam # Z = rotation axis # Y = Z ^ X z = matrix.col([0, 0, 1]) # then calculate the rotation axis R = ( ( z.axis_and_angle_as_r3_rotation_matrix(phi1, deg=True) * matrix.sqr(xyz_matrix(misset1[0], misset1[1], misset1[2])) ) * ( z.axis_and_angle_as_r3_rotation_matrix(phi0, deg=True) * matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2])) ).inverse() ) self._z = z self._r = matrix.col(r3_rotation_axis_and_angle_from_matrix(R).axis) self._M0 = matrix.sqr(xyz_matrix(misset0[0], misset0[1], misset0[2])) return
def compose(self): """calculate state and derivatives""" # obtain parameters on natural scale p_vals = [p.value / 1.e5 for p in self._param] # set parameter values in the symmetrizing object and obtain new B try: newB = matrix.sqr( self._S.backward_orientation(p_vals).reciprocal_matrix()) except RuntimeError as e: from libtbx.utils import Sorry # write original error to debug log debug('Unable to compose the crystal model') debug('Original error message: {0}'.format(str(e))) debug('Failing now.') raise Sorry('Unable to compose the crystal model. Please check that the ' 'experiments match the indexing of the reflections.') # Now pass new B to the crystal model self._model.set_B(newB) # returns the independent parameters given the set_orientation() B # matrix. Used here for side effects self._S.forward_independent_parameters() # get the gradients on the adjusted scale self._dstate_dp = [matrix.sqr(e) / 1.e5 \ for e in self._S.forward_gradients()] return
def apply_reindex_operation(mosflm_a_matrix, mosflm_u_matrix, reindex): a = matrix.sqr(mosflm_a_matrix) u = matrix.sqr(mosflm_u_matrix) r = matrix.sqr(reindex).transpose() return a * r, u * r
def set_local_frame(self, fast_axis, slow_axis, origin): ''' Set the local frame. ''' from scitbx import matrix # Check if the parent is None if self.parent() is None: self.set_frame(fast_axis, slow_axis, origin) # Normalize the axes fast_axis = matrix.col(fast_axis).normalize() slow_axis = matrix.col(slow_axis).normalize() normal = fast_axis.cross(slow_axis) # Get the parent transformation matrix tp = matrix.sqr(self.parent().get_transformation_matrix()) # Get the local transformation matrix tl = matrix.sqr( fast_axis.elems + (0,) + slow_axis.elems + (0,) + normal.elems + (0,) + tuple(origin) + (1,)).transpose() # Set the current frame tgt = (tp * tl).transpose() self.set_frame(tgt[0:3], tgt[4:7], tgt[12:15])
def reeke_model_for_use_case(phi_beg, phi_end, margin): """Construct a reeke_model for the geometry of the Use Case Thaumatin dataset, taken from the XDS XPARM. The values are hard- coded here so that this module does not rely on the location of that file.""" axis = matrix.col([0.0, 1.0, 0.0]) # original (unrotated) setting ub = matrix.sqr( [ -0.0133393674072, -0.00541609051856, -0.00367748834997, 0.00989309470346, 0.000574825936669, -0.0054505379664, 0.00475395109417, -0.0163935257377, 0.00102384915696, ] ) r_beg = matrix.sqr(scitbx.math.r3_rotation_axis_and_angle_as_matrix(axis=self._axis, angle=phi_beg, deg=True)) r_osc = matrix.sqr( scitbx.math.r3_rotation_axis_and_angle_as_matrix(axis=self._axis, angle=(phi_end - phi_beg), deg=True) ) ub_beg = r_beg * ub ub_end = self._r_osc * ub_mid s0 = matrix.col([0.00237878589035, 1.55544539299e-16, -1.09015329696]) dmin = 1.20117776325 return reeke_model(ub_beg, ub_end, axis, s0, dmin, margin)
def _get_change_of_basis(self, axis_id): """ Get the 4x4 homogenous coordinate matrix for a given axis. Assumes the cbf handle has been intialized @param axis_id axis name of basis to get """ cbf = self._get_cbf_handle() axis_type = cbf.get_axis_type(axis_id) offset = col(cbf.get_axis_offset(axis_id)) vector = col(cbf.get_axis_vector(axis_id)).normalize() setting, increment = cbf.get_axis_setting(axis_id) # change of basis matrix in homologous coordinates cob = None if axis_type == "rotation": r3 = vector.axis_and_angle_as_r3_rotation_matrix(setting + increment, deg = True) cob = sqr((r3[0], r3[1], r3[2], offset[0], r3[3], r3[4], r3[5], offset[1], r3[6], r3[7], r3[8], offset[2], 0, 0, 0, 1)) elif axis_type == "translation": translation = offset + vector * (setting + increment) cob = sqr((1,0,0,translation[0], 0,1,0,translation[1], 0,0,1,translation[2], 0,0,0,1)) else: raise Sorry("Unrecognized vector type: %d"%axis_type) return cob
def test_rotaion_translation_input(self): """ Verify correct processing """ r1 = matrix.sqr([-0.955168,0.257340,-0.146391, 0.248227,0.426599,-0.869711, -0.161362,-0.867058,-0.471352]) r2 = matrix.sqr([-0.994267,-0.046533,-0.096268, -0.065414,-0.447478,0.89189, -0.084580,0.893083,0.441869]) t1 = matrix.col([167.54320,-4.09250,41.98070]) t2 = matrix.col([176.73730,27.41760,-5.85930]) trans_obj = ncs.input( hierarchy=iotbx.pdb.input(source_info=None, lines=pdb_str2).construct_hierarchy(), rotations=[r1,r2], translations=[t1,t2]) nrg = trans_obj.get_ncs_restraints_group_list()[0] self.assertEqual(list(nrg.master_iselection),[0, 1, 2, 3, 4, 5, 6, 7, 8]) c1 = nrg.copies[0] self.assertEqual(list(c1.iselection),[9,10,11,12,13,14,15,16,17]) c2 = nrg.copies[1] self.assertEqual(list(c2.iselection),[18,19,20,21,22,23,24,25,26]) # self.assertEqual(r1,c1.r) self.assertEqual(r2,c2.r) self.assertEqual(t1,c1.t) self.assertEqual(t2,c2.t)
def ersatz_misset(integrate_lp): a_s = [] b_s = [] c_s = [] for record in open(integrate_lp): if 'COORDINATES OF UNIT CELL A-AXIS' in record: a = map(float, record.split()[-3:]) a_s.append(matrix.col(a)) elif 'COORDINATES OF UNIT CELL B-AXIS' in record: b = map(float, record.split()[-3:]) b_s.append(matrix.col(b)) elif 'COORDINATES OF UNIT CELL C-AXIS' in record: c = map(float, record.split()[-3:]) c_s.append(matrix.col(c)) assert(len(a_s) == len(b_s) == len(c_s)) ub0 = matrix.sqr(a_s[0].elems + b_s[0].elems + c_s[0].elems).inverse() for j in range(len(a_s)): ub = matrix.sqr(a_s[j].elems + b_s[j].elems + c_s[j].elems).inverse() print '%7.3f %7.3f %7.3f' % tuple(xyz_angles(ub.inverse() * ub0)) return
def kabsch_rotation(reference_sites, other_sites): """ Kabsch, W. (1976). Acta Cryst. A32, 922-923. A solution for the best rotation to relate two sets of vectors Based on a prototype by Erik McKee and Reetal K. Pai. This implementation does not handle degenerate situations correctly (e.g. if all atoms are on a line or plane) and should therefore not be used in applications. It is retained here for development purposes only. """ assert reference_sites.size() == other_sites.size() sts = matrix.sqr(other_sites.transpose_multiply(reference_sites)) eigs = eigensystem.real_symmetric((sts * sts.transpose()).as_sym_mat3()) vals = list(eigs.values()) vecs = list(eigs.vectors()) a3 = list(matrix.col(vecs[:3]).cross(matrix.col(vecs[3:6]))) a = matrix.sqr(list(vecs[:6])+a3) b = list(a * sts) for i in xrange(3): d = math.sqrt(math.fabs(vals[i])) if (d > 0): for j in xrange(3): b[i*3+j] /= d b3 = list(matrix.col(b[:3]).cross(matrix.col(b[3:6]))) b = matrix.sqr(b[:6]+b3) return b.transpose() * a
def _transform(o, t): """The _transform() function returns the transformation matrices in homogeneous coordinates between the parent and child frames. The forward transform maps coordinates in the parent frame to the child frame, and the backward transform provides the inverse. The last row of the product of any two homogeneous transformation matrices is always (0, 0, 0, 1). @param o Orientation of child w.r.t. parent, as a unit quaternion @param t Translation of child w.r.t. parent @return Two-tuple of the forward and backward transformation matrices """ Rb = o.unit_quaternion_as_r3_rotation_matrix() tb = t Tb = matrix.sqr( ( Rb(0, 0), Rb(0, 1), Rb(0, 2), tb(0, 0), Rb(1, 0), Rb(1, 1), Rb(1, 2), tb(1, 0), Rb(2, 0), Rb(2, 1), Rb(2, 2), tb(2, 0), 0, 0, 0, 1, ) ) Rf = Rb.transpose() tf = -Rf * t Tf = matrix.sqr( ( Rf(0, 0), Rf(0, 1), Rf(0, 2), tf(0, 0), Rf(1, 0), Rf(1, 1), Rf(1, 2), tf(1, 0), Rf(2, 0), Rf(2, 1), Rf(2, 2), tf(2, 0), 0, 0, 0, 1, ) ) return (Tf, Tb)
def get_local_transformation_matrix(self): ''' Get the local transformation matrix. ''' from scitbx import matrix if self.parent() is None: return self.get_transformation_matrix() tp = matrix.sqr(self.parent().get_transformation_matrix()) tg = matrix.sqr(self.get_transformation_matrix()) return (tp.inverse() * tg).elems
def get_crystal_orientation(ortho_matrix, rot_matrix): #From orthogonalization matrix and rotation matrix, #generate and return crystal orientation O = sqr(ortho_matrix).transpose() R = sqr(rot_matrix).transpose() X = O*R co = crystal_orientation(X, basis_type.direct) return co
def step_a(self, T, L, S): """ Shift origin into reaction center. New S' must be symmetric as result of origin shift. """ print_step("Step a:", self.log) print >> self.log, " system of equations: m * p = b, p = m_inverse * b" L_ = L.as_sym_mat3() m = matrix.sqr(( L_[4], L_[5], -(L_[0]+L_[1]), L_[3], -(L_[0]+L_[2]), L_[5], -(L_[1]+L_[2]), L_[3], L_[4])) self.show_matrix(x=m, title="m") if(abs(m.determinant())<self.eps): print >> self.log, " det(m)<", self.eps T_p = T L_p = L S_p = S p = matrix.col((0, 0, 0)) P = matrix.sqr(( 0, p[2], -p[1], -p[2], 0, p[0], p[1], -p[0], 0)) else: b = matrix.col((S[3]-S[1], S[2]-S[6], S[7]-S[5])) self.show_vector(x=b, title="b") m_inv = m.inverse() self.show_matrix(x=m_inv, title="m_inverse") p = m_inv * b P = matrix.sqr(( 0, p[2], -p[1], -p[2], 0, p[0], p[1], -p[0], 0)) T_p = T #XXX+ (P*L*P.transpose() + P*S + S.transpose()*P.transpose()) L_p = L #XXX S_p = S #XXX- L*P #XXX assert approx_equal(S-L*P, S+L*P.transpose()) #XXX # check S_p is symmetric #XXX assert approx_equal(S_p[1], S_p[3]) #XXX assert approx_equal(S_p[2], S_p[6]) #XXX assert approx_equal(S_p[5], S_p[7]) #XXX ###### check system (3) #XXX assert approx_equal(p[1]*L_[3] + p[2]*L_[4] - p[0]*(L_[1]+L_[2]), S[7]-S[5]) #XXX assert approx_equal(p[2]*L_[5] + p[0]*L_[3] - p[1]*(L_[2]+L_[0]), S[2]-S[6]) #XXX assert approx_equal(p[0]*L_[4] + p[1]*L_[5] - p[2]*(L_[0]+L_[1]), S[3]-S[1]) self.show_vector(x=p, title="p") self.show_matrix(x=P, title="P") self.show_matrix(x=T_p, title="T_P") self.show_matrix(x=L_p, title="L_P") self.show_matrix(x=S_p, title="S_P") return group_args( T_p = T_p, L_p = L_p, S_p = S_p, p = p)
def test_uniform_rotation_matrix(N=10000,choice=2,verbose=False): """ The surface integral of a spherical harmonic function with its conjugate should be 1. (http://mathworld.wolfram.com/SphericalHarmonic.html, Eq 7) From Mathematica, l = 10; m = 10; y = SphericalHarmonicY[l, m, \[Theta], \[Phi]]; Integrate[y*Conjugate[y]*Sin[\[Theta]], {\[Theta], 0, Pi}, {\[Phi], 0, 2*Pi}] should yield 1. By picking uniformly random points on a sphere, the surface integral can be numerically approximated. The results in the comments below are for N = 1 000 000. """ if (choice == 0): # l=1, m=1 # result = (0.883199394206+0j) (0.883824001444+0j) lm = 1 c = -0.5 * math.sqrt(1.5/math.pi) elif (choice == 1): # l = 5, m = 5 # result = (0.959557841214+0j) (0.959331535539+0j) lm = 5 c = -(3/32) * math.sqrt(77/math.pi) else: # l = 10, m = 10 # result = (0.977753926603+0j) (0.97686871766+0j) lm = 10 c = (1/1024) * math.sqrt(969969/math.pi) result = [ 0.0, 0.0 ] for i in range(N): R = [ matrix.sqr(flex.random_double_r3_rotation_matrix()), matrix.sqr(flex.random_double_r3_rotation_matrix_arvo_1992()) ] for j in xrange(len(result)): result[j] += add_point(lm,c,R[j]) # multipy by area at the end, each point has an area of 4pi/N point_area = 4.0*math.pi/N # surface area of unit sphere / number of points for i in xrange(len(result)): result[i] = point_area * result[i] if (verbose): print result[i], if (verbose): print assert(result[0].real > 0.85) assert(result[0].real < 1.15) assert(result[1].real > 0.85) assert(result[1].real < 1.15)
def integrate_mtz_to_A_matrix(integrate_mtz): from iotbx import mtz from cctbx.uctbx import unit_cell from scitbx import matrix m = mtz.object(integrate_mtz) b = m.batches()[0] u = matrix.sqr(b.umat()).transpose() c = unit_cell(tuple(b.cell())) f = matrix.sqr(c.fractionalization_matrix()).transpose() return (u * f)
def generate_reindex_transformations(): '''The reindex transformations are specific for a particular presence condition, such as H + 2K + 3L = 5n. The transformation is applied in reciprocal space, and is intended to change the original incorrect basis set a*',b*',c*' into the correct basis set a*,b*,c*. The meaning of the correction matrix A is as follows: a* = A00(a*') + A01(b*') + A02(c*') b* = A10(a*') + A11(b*') + A12(c*') c* = A20(a*') + A21(b*') + A22(c*') The choice of A is not unique, we use an algorithm to select a particular solution. Briefly, for the first row of A choose the row vector HKL which satisfies the presence condition, and is shortest in length. For the second row choose the next shortest allowed row vector that is not collinear with the first. The third allowed row vector is the next shortest not coplanar with the first two. We check to see that the determinant is positive (or switch first two rows) and of magnitude equal to the mod factor; this assures that the unit cell will be reduced in volume by the appropriate factor. Our approach sometimes backfires: an already too-small unit cell can produce a positive absence test; the cell will then be reduced in volume indefinitely. Therefore the application always uses a cell volume filter after making the correction. ''' vecrep = generate_vector_representations() reindex = [] for vec in vecrep: for mod in modularities: #first point for pt in spiral_order: if (vec[0]*pt[0] + vec[1]*pt[1] + vec[2]*pt[2])%mod == 0: first = pt break #second point for pt in spiral_order: if (vec[0]*pt[0] + vec[1]*pt[1] + vec[2]*pt[2])%mod == 0 and \ not is_collinear(first,pt): second = pt break #third point for pt in spiral_order: if (vec[0]*pt[0] + vec[1]*pt[1] + vec[2]*pt[2])%mod == 0 and \ not is_coplanar(first,second,pt): third = pt break from scitbx import matrix A = matrix.sqr(first+second+third) if A.determinant()<0: A = matrix.sqr(second + first + third) assert A.determinant()==mod reindex.append({'mod':mod,'vec':vec,'trans':A,}) #print "found pts",A.elems,"for vec",vec,"mod",mod return reindex
def run_sim2smv(img_prefix=None, simparams=None, pdb_lines=None, crystal=None, spectra=None, rotation=None, rank=None, fsave=None, sfall_cluster=None, quick=False): smv_fileout = fsave direct_algo_res_limit = simparams.direct_algo_res_limit wavlen, flux, real_wavelength_A = next( spectra) # list of lambdas, list of fluxes, average wavelength real_flux = flex.sum(flux) assert real_wavelength_A > 0 # print(rank, " ## real_wavelength_A/real_flux = ", real_wavelength_A, real_flux*1.0/simparams.flux) if quick: wavlen = flex.double([real_wavelength_A]) flux = flex.double([real_flux]) # GF = gen_fmodel(resolution=simparams.direct_algo_res_limit,pdb_text=pdb_lines,algorithm=simparams.fmodel_algorithm,wavelength=real_wavelength_A) # GF.set_k_sol(simparams.k_sol) # GF.make_P1_primitive() sfall_main = sfall_cluster["main"] #GF.get_amplitudes() # use crystal structure to initialize Fhkl array # sfall_main.show_summary(prefix = "Amplitudes used ") N = crystal.number_of_cells(sfall_main.unit_cell()) #print("## number of N = ", N) SIM = nanoBragg(detpixels_slowfast=(simparams.detector_size_ny,simparams.detector_size_nx),pixel_size_mm=simparams.pixel_size_mm,\ Ncells_abc=(N,N,N),wavelength_A=real_wavelength_A,verbose=0) # workaround for problem with wavelength array, specify it separately in constructor. # SIM.adc_offset_adu = 0 # Do not offset by 40 SIM.adc_offset_adu = 10 # Do not offset by 40 SIM.seed = 0 # SIM.randomize_orientation() SIM.mosaic_spread_deg = simparams.mosaic_spread_deg # interpreted by UMAT_nm as a half-width stddev SIM.mosaic_domains = simparams.mosaic_domains # 77 seconds. SIM.distance_mm = simparams.distance_mm ## setup the mosaicity UMAT_nm = flex.mat3_double() mersenne_twister = flex.mersenne_twister(seed=0) scitbx.random.set_random_seed(1234) rand_norm = scitbx.random.normal_distribution(mean=0, sigma=SIM.mosaic_spread_deg * math.pi / 180.) g = scitbx.random.variate(rand_norm) mosaic_rotation = g(SIM.mosaic_domains) for m in mosaic_rotation: site = col(mersenne_twister.random_double_point_on_sphere()) UMAT_nm.append(site.axis_and_angle_as_r3_rotation_matrix(m, deg=False)) SIM.set_mosaic_blocks(UMAT_nm) ###################### SIM.beamcenter_convention = convention.ADXV SIM.beam_center_mm = (simparams.beam_center_x_mm, simparams.beam_center_y_mm) # 95.975 96.855 ###################### # get same noise each time this test is run SIM.seed = 0 SIM.oversample = simparams.oversample SIM.wavelength_A = real_wavelength_A SIM.polarization = simparams.polarization # this will become F000, marking the beam center SIM.default_F = simparams.default_F #SIM.missets_deg= (10,20,30) SIM.Fhkl = sfall_main Amatrix_rot = ( rotation * sqr(sfall_main.unit_cell().orthogonalization_matrix())).transpose() SIM.Amatrix_RUB = Amatrix_rot #workaround for failing init_cell, use custom written Amatrix setter # print("## inside run_sim2smv, Amat_rot = ", Amatrix_rot) Amat = sqr(SIM.Amatrix).transpose() # recovered Amatrix from SIM Ori = crystal_orientation.crystal_orientation( Amat, crystal_orientation.basis_type.reciprocal) print(fsave, "Amatrix_rot", Amatrix_rot) print(fsave, "Amat", Amat) print(fsave, "Ori", Ori) print(fsave, "rotation", rotation) print(fsave, "sqr(sfall_main.unit_cell().orthogonalization_matrix())", sqr(sfall_main.unit_cell().orthogonalization_matrix())) SIM.free_all()
p_vals[0] += 4. s0_param.set_param_vals(p_vals) # rotate crystal a bit (=3 mrad each rotation) xlo_p_vals = xlo_param.get_param_vals() p_vals = [a + b for a, b in zip(xlo_p_vals, [3., 3., 3.])] xlo_param.set_param_vals(p_vals) # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of # alpha and beta angles) xluc_p_vals = xluc_param.get_param_vals() cell_params = mycrystal.get_unit_cell().parameters() cell_params = [a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1, -0.1, 0.0])] new_uc = unit_cell(cell_params) newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose() S = symmetrize_reduce_enlarge(mycrystal.get_space_group()) S.set_orientation(orientation=newB) X = tuple([e * 1.e5 for e in S.forward_independent_parameters()]) xluc_param.set_param_vals(X) ############################# # Generate some reflections # ############################# # All indices in a 2.0 Angstrom sphere resolution = 2.0 index_generator = IndexGenerator(mycrystal.get_unit_cell(), space_group(space_group_symbols(1).hall()).type(), resolution) indices = index_generator.to_array()
def test_simplex(): from dials.array_family import flex import sys seed(0) # Ensure we have a data block experiments = ExperimentListFactory.from_json_file("experiments.json") experiments[0].scan.set_oscillation((0, 1), deg=True) # experiments[0].scan = experiments[0].scan[0:1] # experiments[0].imageset = experiments[0].imageset[0:1] # The predicted reflections reflections = flex.reflection_table.from_predictions_multi(experiments, padding=1) # Select only those within 1 deg x, y, z = reflections["xyzcal.px"].parts() selection = flex.abs(z) < 1 reflections = reflections.select(selection) selection = flex.size_t(sample(range(len(reflections)), 1000)) reflections = reflections.select(selection) parameters = (sqrt(0.0001), 0, sqrt(0.0002), 0, 0, sqrt(0.0003)) M = matrix.sqr( ( parameters[0], 0, 0, parameters[1], parameters[2], 0, parameters[3], parameters[4], parameters[5], ) ) sigma = M * M.transpose() print(sigma) # Generate observed positions s1_obs, s2_obs = generate_observations(experiments, reflections, sigma) angles = [] for s1, s2 in zip(s1_obs, s2_obs): a = matrix.col(s1).angle(matrix.col(s2), deg=True) angles.append(a) print("Mean angle between s1 and s2 %f degrees " % (sum(angles) / len(angles))) # Do the ray intersection reflections["s1_obs"] = s1_obs reflections["s1"] = s2_obs xyzobs = flex.vec3_double() xyzobspx = flex.vec3_double() for j in range(len(s1_obs)): mm = experiments[0].detector[0].get_ray_intersection(s1_obs[j]) px = experiments[0].detector[0].millimeter_to_pixel(mm) xyzobs.append((mm[0], mm[1], 0)) xyzobspx.append((px[0], px[1], 0)) reflections["xyzobs.mm.value"] = xyzobs reflections["xyzobs.px.value"] = xyzobspx # Offset the crystal orientation matrix U = matrix.sqr(experiments[0].crystal.get_U()) print( "Original orientation: ", "(%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f)" % tuple(U), ) m2 = matrix.col(experiments[0].goniometer.get_rotation_axis()) R = m2.axis_and_angle_as_r3_rotation_matrix(angle=0.5, deg=True) experiments[0].crystal.set_U(R * U) model = SimpleMosaicityModel(sigma) # Do the refinement refiner = CrystalRefiner(experiments[0], reflections, model) crystal = refiner.experiment.crystal U_old = U U = crystal.get_U() print( "Refined orientation: ", "(%.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f, %.3f)" % tuple(U), ) assert all(abs(u1 - u2) < 1e-7 for u1, u2 in zip(U_old, U)) print("OK")
def run(self, args=None): """Run the script.""" from scitbx import matrix from dials.util.options import flatten_experiments params, options = self.parser.parse_args(args) if len(params.input.experiments) == 0: self.parser.print_help() return experiments = flatten_experiments(params.input.experiments) # Determine output path self._directory = os.path.join(params.output.directory, "scan-varying_model") self._directory = os.path.abspath(self._directory) ensure_directory(self._directory) self._format = "." + params.output.format self._debug = params.output.debug # Decomposition axes self._e1 = params.orientation_decomposition.e1 self._e2 = params.orientation_decomposition.e2 self._e3 = params.orientation_decomposition.e3 # cell plot dat = [] for iexp, exp in enumerate(experiments): crystal = exp.crystal scan = exp.scan if crystal.num_scan_points == 0: print("Ignoring scan-static crystal") continue scan_pts = list(range(crystal.num_scan_points)) cells = [crystal.get_unit_cell_at_scan_point(t) for t in scan_pts] cell_params = [e.parameters() for e in cells] a, b, c, aa, bb, cc = zip(*cell_params) phi = [scan.get_angle_from_array_index(t) for t in scan_pts] vol = [e.volume() for e in cells] cell_dat = { "phi": phi, "a": a, "b": b, "c": c, "alpha": aa, "beta": bb, "gamma": cc, "volume": vol, } try: cell_esds = [ crystal.get_cell_parameter_sd_at_scan_point(t) for t in scan_pts ] sig_a, sig_b, sig_c, sig_aa, sig_bb, sig_cc = zip(*cell_esds) cell_dat["sig_a"] = sig_a cell_dat["sig_b"] = sig_b cell_dat["sig_c"] = sig_c cell_dat["sig_aa"] = sig_aa cell_dat["sig_bb"] = sig_bb cell_dat["sig_cc"] = sig_cc except RuntimeError: pass if self._debug: print("Crystal in Experiment {}".format(iexp)) print("Phi\ta\tb\tc\talpha\tbeta\tgamma\tVolume") msg = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}" line_dat = zip(phi, a, b, c, aa, bb, cc, vol) for line in line_dat: print(msg.format(*line)) dat.append(cell_dat) if dat: self.plot_cell(dat) # orientation plot dat = [] for iexp, exp in enumerate(experiments): crystal = exp.crystal scan = exp.scan if crystal.num_scan_points == 0: print("Ignoring scan-static crystal") continue scan_pts = list(range(crystal.num_scan_points)) phi = [scan.get_angle_from_array_index(t) for t in scan_pts] Umats = [ matrix.sqr(crystal.get_U_at_scan_point(t)) for t in scan_pts ] if params.orientation_decomposition.relative_to_static_orientation: # factor out static U Uinv = matrix.sqr(crystal.get_U()).inverse() Umats = [U * Uinv for U in Umats] # NB e3 and e1 definitions for the crystal are swapped compared # with those used inside the solve_r3_rotation_for_angles_given_axes # method angles = [ solve_r3_rotation_for_angles_given_axes(U, self._e3, self._e2, self._e1, deg=True) for U in Umats ] phi3, phi2, phi1 = zip(*angles) angle_dat = {"phi": phi, "phi3": phi3, "phi2": phi2, "phi1": phi1} if self._debug: print("Crystal in Experiment {}".format(iexp)) print("Image\tphi3\tphi2\tphi1") msg = "{0}\t{1}\t{2}\t{3}" line_dat = zip(phi, phi3, phi2, phi1) for line in line_dat: print(msg.format(*line)) dat.append(angle_dat) if dat: self.plot_orientation(dat) # beam centre plot dat = [] for iexp, exp in enumerate(experiments): beam = exp.beam detector = exp.detector scan = exp.scan if beam.num_scan_points == 0: print("Ignoring scan-static beam") continue scan_pts = range(beam.num_scan_points) phi = [scan.get_angle_from_array_index(t) for t in scan_pts] p = detector.get_panel_intersection(beam.get_s0()) if p < 0: print("Beam does not intersect a panel") continue panel = detector[p] s0_scan_points = [ beam.get_s0_at_scan_point(i) for i in range(beam.num_scan_points) ] bc_scan_points = [ panel.get_beam_centre_px(s0) for s0 in s0_scan_points ] bc_x, bc_y = zip(*bc_scan_points) dat.append({ "phi": phi, "beam_centre_x": bc_x, "beam_centre_y": bc_y }) if dat: self.plot_beam_centre(dat)
def get_eff_Astar(self, values): thetax = values.thetax; thetay = values.thetay; effective_orientation = self.ORI.rotate_thru((1,0,0),thetax ).rotate_thru((0,1,0),thetay ) return matrix.sqr(effective_orientation.reciprocal_matrix())
def __init__(self, experiment, vectors, frame='reciprocal', mode='main'): from libtbx.utils import Sorry self.experiment = experiment self.vectors = vectors self.frame = frame self.mode = mode gonio = experiment.goniometer scan = experiment.scan self.s0 = matrix.col(self.experiment.beam.get_s0()) self.rotation_axis = matrix.col(gonio.get_rotation_axis()) from dxtbx.model import MultiAxisGoniometer if not isinstance(gonio, MultiAxisGoniometer): raise Sorry('Only MultiAxisGoniometer models supported') axes = gonio.get_axes() if len(axes) != 3: raise Sorry('Only 3-axis goniometers supported') e1, e2, e3 = (matrix.col(e) for e in reversed(axes)) fixed_rotation = matrix.sqr(gonio.get_fixed_rotation()) setting_rotation = matrix.sqr(gonio.get_setting_rotation()) rotation_axis = matrix.col(gonio.get_rotation_axis_datum()) rotation_matrix = rotation_axis.axis_and_angle_as_r3_rotation_matrix( experiment.scan.get_oscillation()[0], deg=True) from dials.algorithms.refinement import rotation_decomposition results = OrderedDict() # from https://github.com/legrandp/xdsme/blob/master/XOalign/XOalign.py#L427 # referential_permutations sign permutations for four permutations of # parallel/antiparallel (rotation axis & beam) # y1 // e1, y2 // beamVector; y1 anti// e1, y2 // beamVector # y1 // e1, y2 anti// beamVector; y1 anti// e1, y2 anti// beamVector ex = matrix.col((1, 0, 0)) ey = matrix.col((0, 1, 0)) ez = matrix.col((0, 0, 1)) referential_permutations = ([ ex, ey, ez], [-ex, -ey, ez], [ ex, -ey, -ez], [-ex, ey, -ez]) for (v1_, v2_) in self.vectors: results[(v1_, v2_)] = OrderedDict() space_group = self.experiment.crystal.get_space_group() for smx in list(space_group.smx())[:]: results[(v1_, v2_)][smx] = [] crystal = copy.deepcopy(self.experiment.crystal) cb_op = sgtbx.change_of_basis_op(smx) crystal = crystal.change_basis(cb_op) # Goniometer datum setting [D] at which the orientation was determined D = (setting_rotation * rotation_matrix * fixed_rotation).inverse() # The setting matrix [U] will vary with the datum setting according to # [U] = [D] [U0] U = matrix.sqr(crystal.get_U()) # XXX In DIALS recorded U is equivalent to U0 - D is applied to U inside # prediction U0 = U B = matrix.sqr(crystal.get_B()) if self.frame == 'direct': B = B.inverse().transpose() v1_0 = U0 * B * v1_ v2_0 = U0 * B * v2_ #c (b) The laboratory frame vectors l1 & l2 are normally specified with the #c MODE command: MODE MAIN (the default) sets l1 (along which v1 will be #c placed) along the principle goniostat axis e1 (Omega), and l2 along #c the beam s0. This allows rotation for instance around a principle axis. #c The other mode is MODE CUSP, which puts l1 (v1) perpendicular to the #c beam (s0) and the e1 (Omega) axis, and l2 (v2) in the plane containing #c l1 & e1 (ie l1 = e1 x s0, l2 = e1). if self.mode == 'cusp': l1 = self.rotation_axis.cross(self.s0) l2 = self.rotation_axis else: l1 = self.rotation_axis.normalize() l3 = l1.cross(self.s0).normalize() l2 = l1.cross(l3) for perm in referential_permutations: S = matrix.sqr(perm[0].elems + perm[1].elems + perm[2].elems) from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame R = align_reference_frame(v1_0, S * l1, v2_0, S * l2) solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R, e1, e2, e3, return_both_solutions=True, deg=True) if solutions is None: continue results[(v1_, v2_)][smx].extend(solutions) self.all_solutions = results self.unique_solutions = OrderedDict() for (v1, v2), result in results.iteritems(): for solutions in result.itervalues(): for solution in solutions: k = tuple(round(a, 3) for a in solution[1:]) self.unique_solutions.setdefault(k, OrderedSet()) self.unique_solutions[k].add((v1, v2))
import os os.environ["DIFFBRAGG_USE_CUDA"]="1" import numpy as np import pylab as plt from scipy.stats import linregress from scipy.spatial.transform import Rotation from simtbx.nanoBragg import sim_data from scitbx.matrix import sqr, rec from cctbx import uctbx from dxtbx.model import Crystal ucell = (70, 60, 50, 90.0, 110, 90.0) symbol = "C121" a_real, b_real, c_real = sqr(uctbx.unit_cell(ucell).orthogonalization_matrix()).transpose().as_list_of_lists() C = Crystal(a_real, b_real, c_real, symbol) # random raotation rotation = Rotation.random(num=1, random_state=101)[0] Q = rec(rotation.as_quat(), n=(4, 1)) rot_ang, rot_axis = Q.unit_quaternion_as_axis_and_angle() C.rotate_around_origin(rot_axis, rot_ang) S = sim_data.SimData(use_default_crystal=True) S.crystal.dxtbx_crystal = C S.crystal.isotropic_ncells = True S.detector = sim_data.SimData.simple_detector(180, 0.1, (1024, 1024)) S.instantiate_diffBragg(verbose=0, oversample=0) assert S.D.isotropic_ncells S.D.spot_scale = 100000
def _detector(self): '''Return a model for the detector, allowing for two-theta offsets and the detector position. This will be rather more complex... and overloads the definition for the general Rigaku Saturn detector by rotating the detector by -90 degrees about the beam.''' detector_name = self._header_dictionary['DETECTOR_NAMES'].split( )[0].strip() detector_axes = map( float, self._header_dictionary['%sDETECTOR_VECTORS' % detector_name].split()) R = matrix.col( (0, 0, 1)).axis_and_angle_as_r3_rotation_matrix(-90, deg=True) detector_fast = R * matrix.col(tuple(detector_axes[:3])) detector_slow = R * matrix.col(tuple(detector_axes[3:])) beam_pixels = map( float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' % detector_name].split()[:2]) pixel_size = map( float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' % detector_name].split()[2:]) image_size = map( int, self._header_dictionary['%sDETECTOR_DIMENSIONS' % detector_name].split()) detector_origin = - (beam_pixels[0] * pixel_size[0] * detector_fast + \ beam_pixels[1] * pixel_size[1] * detector_slow) gonio_axes = map( float, self._header_dictionary['%sGONIO_VECTORS' % detector_name].split()) gonio_values = map( float, self._header_dictionary['%sGONIO_VALUES' % detector_name].split()) gonio_units = self._header_dictionary['%sGONIO_UNITS' % detector_name].split() gonio_num_axes = int(self._header_dictionary['%sGONIO_NUM_VALUES' % detector_name]) rotations = [] translations = [] for j, unit in enumerate(gonio_units): axis = matrix.col(gonio_axes[3 * j:3 * (j + 1)]) if unit == 'deg': rotations.append( axis.axis_and_angle_as_r3_rotation_matrix(gonio_values[j], deg=True)) translations.append(matrix.col((0.0, 0.0, 0.0))) elif unit == 'mm': rotations.append( matrix.sqr((1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0))) translations.append(gonio_values[j] * axis) else: raise RuntimeError, 'unknown axis unit %s' % unit rotations.reverse() translations.reverse() for j in range(gonio_num_axes): detector_fast = rotations[j] * detector_fast detector_slow = rotations[j] * detector_slow detector_origin = rotations[j] * detector_origin detector_origin = translations[j] + detector_origin overload = int(self._header_dictionary['SATURATED_VALUE']) underload = 0 return self._detector_factory.complex('CCD', detector_origin.elems, detector_fast.elems, detector_slow.elems, pixel_size, image_size, (underload, overload), gain=10)
def __init__(self, measurements_orig, params, i_model, miller_set, result, out): measurements = measurements_orig.deep_copy() # Now manipulate the data to conform to unit cell, asu, and space group # of reference. The resolution will be cut later. # Only works if there is NOT an indexing ambiguity! observations = measurements.customized_copy( anomalous_flag=not params.merge_anomalous, crystal_symmetry=miller_set.crystal_symmetry()).map_to_asu() observations_original_index = measurements.customized_copy( anomalous_flag=not params.merge_anomalous, crystal_symmetry=miller_set.crystal_symmetry()) # Ensure that match_multi_indices() will return identical results # when a frame's observations are matched against the # pre-generated Miller set, self.miller_set, and the reference # data set, self.i_model. The implication is that the same match # can be used to map Miller indices to array indices for intensity # accumulation, and for determination of the correlation # coefficient in the presence of a scaling reference. assert len(i_model.indices()) == len(miller_set.indices()) \ and (i_model.indices() == miller_set.indices()).count(False) == 0 matches = miller.match_multi_indices( miller_indices_unique=miller_set.indices(), miller_indices=observations.indices()) pair1 = flex.int([pair[1] for pair in matches.pairs()]) pair0 = flex.int([pair[0] for pair in matches.pairs()]) # narrow things down to the set that matches, only observations_pair1_selected = observations.customized_copy( indices=flex.miller_index( [observations.indices()[p] for p in pair1]), data=flex.double([observations.data()[p] for p in pair1]), sigmas=flex.double([observations.sigmas()[p] for p in pair1]), ) observations_original_index_pair1_selected = observations_original_index.customized_copy( indices=flex.miller_index( [observations_original_index.indices()[p] for p in pair1]), data=flex.double( [observations_original_index.data()[p] for p in pair1]), sigmas=flex.double( [observations_original_index.sigmas()[p] for p in pair1]), ) ################### I_observed = observations_pair1_selected.data() chosen = chosen_weights(observations_pair1_selected, params) MILLER = observations_original_index_pair1_selected.indices() ORI = result["current_orientation"][0] Astar = matrix.sqr(ORI.reciprocal_matrix()) WAVE = result["wavelength"] BEAM = matrix.col((0.0, 0.0, -1. / WAVE)) BFACTOR = 0. #calculation of correlation here I_reference = flex.double( [i_model.data()[pair[0]] for pair in matches.pairs()]) I_invalid = flex.bool( [i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) use_weights = False # New facility for getting variance-weighted correlation if use_weights: #variance weighting I_weight = flex.double([ 1. / (observations_pair1_selected.sigmas()[pair[1]])**2 for pair in matches.pairs() ]) else: I_weight = flex.double(len(observations_pair1_selected.sigmas()), 1.) I_weight.set_selected(I_invalid, 0.) chosen.set_selected(I_invalid, 0.) """Explanation of 'include_negatives' semantics as originally implemented in cxi.merge postrefinement: include_negatives = True + and - reflections both used for Rh distribution for initial estimate of RS parameter + and - reflections both used for calc/obs correlation slope for initial estimate of G parameter + and - reflections both passed to the refinery and used in the target function (makes sense if you look at it from a certain point of view) include_negatives = False + and - reflections both used for Rh distribution for initial estimate of RS parameter + reflections only used for calc/obs correlation slope for initial estimate of G parameter + and - reflections both passed to the refinery and used in the target function (makes sense if you look at it from a certain point of view) """ if params.include_negatives: SWC = simple_weighted_correlation(I_weight, I_reference, I_observed) else: non_positive = (observations_pair1_selected.data() <= 0) SWC = simple_weighted_correlation( I_weight.select(~non_positive), I_reference.select(~non_positive), I_observed.select(~non_positive)) print >> out, "Old correlation is", SWC.corr assert params.postrefinement.algorithm == "rs_hybrid" Rhall = flex.double() for mill in MILLER: H = matrix.col(mill) Xhkl = Astar * H Rh = (Xhkl + BEAM).length() - (1. / WAVE) Rhall.append(Rh) Rs = math.sqrt(flex.mean(Rhall * Rhall)) RS = 1. / 10000. # reciprocal effective domain size of 1 micron RS = Rs # try this empirically determined approximate, monochrome, a-mosaic value self.rs2_current = flex.double([SWC.slope, BFACTOR, RS, 0., 0.]) self.rs2_parameterization_class = rs_parameterization self.rs2_refinery = rs2_refinery(ORI=ORI, MILLER=MILLER, BEAM=BEAM, WAVE=WAVE, ICALCVEC=I_reference, IOBSVEC=I_observed, WEIGHTS=chosen) self.rs2_refinery.set_profile_shape(params.postrefinement.lineshape) self.nave1_refinery = nave1_refinery(ORI=ORI, MILLER=MILLER, BEAM=BEAM, WAVE=WAVE, ICALCVEC=I_reference, IOBSVEC=I_observed, WEIGHTS=chosen) self.nave1_refinery.set_profile_shape(params.postrefinement.lineshape) self.out = out self.params = params self.miller_set = miller_set self.observations_pair1_selected = observations_pair1_selected self.observations_original_index_pair1_selected = observations_original_index_pair1_selected self.i_model = i_model
def d2f_d_params(self): tphkl = 2 * math.pi * matrix.col(self.hkl) tphkl_outer = tphkl.outer_product() h,k,l = self.hkl d_exp_huh_d_u_star = matrix.col([h**2, k**2, l**2, 2*h*k, 2*h*l, 2*k*l]) d2_exp_huh_d_u_star_u_star = d_exp_huh_d_u_star.outer_product() for scatterer in self.scatterers: assert scatterer.scattering_type == "const" w = scatterer.occupancy if (not scatterer.flags.use_u_aniso()): huh = scatterer.u_iso * self.d_star_sq dw = math.exp(mtps * huh) ffp = 1 + scatterer.fp fdp = scatterer.fdp ff = (ffp + 1j * fdp) d2_site_site = flex.complex_double(flex.grid(3,3), 0j) if (not scatterer.flags.use_u_aniso()): d2_site_u_iso = flex.complex_double(flex.grid(3,1), 0j) d2_site_u_star = None else: d2_site_u_iso = None d2_site_u_star = flex.complex_double(flex.grid(3,6), 0j) d2_site_occ = flex.complex_double(flex.grid(3,1), 0j) d2_site_fp = flex.complex_double(flex.grid(3,1), 0j) d2_site_fdp = flex.complex_double(flex.grid(3,1), 0j) if (not scatterer.flags.use_u_aniso()): d2_u_iso_u_iso = 0j d2_u_iso_occ = 0j d2_u_iso_fp = 0j d2_u_iso_fdp = 0j else: d2_u_star_u_star = flex.complex_double(flex.grid(6,6), 0j) d2_u_star_occ = flex.complex_double(flex.grid(6,1), 0j) d2_u_star_fp = flex.complex_double(flex.grid(6,1), 0j) d2_u_star_fdp = flex.complex_double(flex.grid(6,1), 0j) d2_occ_fp = 0j d2_occ_fdp = 0j for s in self.space_group: r = s.r().as_rational().as_float() s_site = s * scatterer.site alpha = matrix.col(s_site).dot(tphkl) if (scatterer.flags.use_u_aniso()): s_u_star_s = r*matrix.sym(sym_mat3=scatterer.u_star)*r.transpose() huh = (matrix.row(self.hkl) * s_u_star_s).dot(matrix.col(self.hkl)) dw = math.exp(mtps * huh) e = cmath.exp(1j*alpha) site_gtmx = r.transpose() d2_site_site += flex.complex_double( site_gtmx * (w * dw * ff * e * (-1) * tphkl_outer) * site_gtmx.transpose()) if (not scatterer.flags.use_u_aniso()): d2_site_u_iso += flex.complex_double(site_gtmx * ( w * dw * ff * e * 1j * mtps * self.d_star_sq * tphkl)) else: u_star_gtmx = matrix.sqr(tensor_rank_2_gradient_transform_matrix(r)) d2_site_u_star += flex.complex_double( site_gtmx * ((w * dw * ff * e * 1j * tphkl).outer_product( mtps * d_exp_huh_d_u_star)) * u_star_gtmx.transpose()) d2_site_occ += flex.complex_double(site_gtmx * ( dw * ff * e * 1j * tphkl)) d2_site_fp += flex.complex_double(site_gtmx * ( w * dw * e * 1j * tphkl)) d2_site_fdp += flex.complex_double(site_gtmx * ( w * dw * e * (-1) * tphkl)) if (not scatterer.flags.use_u_aniso()): d2_u_iso_u_iso += w * dw * ff * e * (mtps * self.d_star_sq)**2 d2_u_iso_occ += dw * ff * e * mtps * self.d_star_sq d2_u_iso_fp += w * dw * e * mtps * self.d_star_sq d2_u_iso_fdp += 1j * w * dw * e * mtps * self.d_star_sq else: d2_u_star_u_star += flex.complex_double( u_star_gtmx * (w * dw * ff * e * mtps**2 * d2_exp_huh_d_u_star_u_star) * u_star_gtmx.transpose()) d2_u_star_occ += flex.complex_double(u_star_gtmx * ( dw * ff * e * mtps * d_exp_huh_d_u_star)) d2_u_star_fp += flex.complex_double(u_star_gtmx * ( w * dw * e * mtps * d_exp_huh_d_u_star)) d2_u_star_fdp += flex.complex_double(u_star_gtmx * ( w * dw * 1j * e * mtps * d_exp_huh_d_u_star)) d2_occ_fp += dw * e d2_occ_fdp += dw * e * 1j if (not scatterer.flags.use_u_aniso()): i_occ, i_fp, i_fdp, np = 4, 5, 6, 7 else: i_occ, i_fp, i_fdp, np = 9, 10, 11, 12 dp = flex.complex_double(flex.grid(np,np), 0j) paste = dp.matrix_paste_block_in_place paste(d2_site_site, 0,0) if (not scatterer.flags.use_u_aniso()): paste(d2_site_u_iso, 0,3) paste(d2_site_u_iso.matrix_transpose(), 3,0) else: paste(d2_site_u_star, 0,3) paste(d2_site_u_star.matrix_transpose(), 3,0) paste(d2_site_occ, 0,i_occ) paste(d2_site_occ.matrix_transpose(), i_occ,0) paste(d2_site_fp, 0,i_fp) paste(d2_site_fp.matrix_transpose(), i_fp,0) paste(d2_site_fdp, 0,i_fdp) paste(d2_site_fdp.matrix_transpose(), i_fdp,0) if (not scatterer.flags.use_u_aniso()): dp[3*7+3] = d2_u_iso_u_iso dp[3*7+4] = d2_u_iso_occ dp[4*7+3] = d2_u_iso_occ dp[3*7+5] = d2_u_iso_fp dp[5*7+3] = d2_u_iso_fp dp[3*7+6] = d2_u_iso_fdp dp[6*7+3] = d2_u_iso_fdp else: paste(d2_u_star_u_star, 3,3) paste(d2_u_star_occ, 3, 9) paste(d2_u_star_occ.matrix_transpose(), 9, 3) paste(d2_u_star_fp, 3, 10) paste(d2_u_star_fp.matrix_transpose(), 10, 3) paste(d2_u_star_fdp, 3, 11) paste(d2_u_star_fdp.matrix_transpose(), 11, 3) dp[i_occ*np+i_fp] = d2_occ_fp dp[i_fp*np+i_occ] = d2_occ_fp dp[i_occ*np+i_fdp] = d2_occ_fdp dp[i_fdp*np+i_occ] = d2_occ_fdp yield dp
fsave = save_folder + "/" + str(idx_img_pdb).zfill(6) + ".img" if os.path.isfile(fsave) or os.path.isfile(fsave + ".gz"): print("@@ file exists: ", fsave) continue spectra = transmitted_info["spectra"] iterator = None iterator = spectra.generate_recast_renormalized_image( image=idx_img_all % 100005, energy=simparams.energy_eV, total_flux=simparams.flux) random_orientation = transmitted_info["random_orientations"][ idx_img_all] rand_ori = sqr(random_orientation) # print("## rank ", rank, " ## random orientations = ", random_orientation) # print(rank, " ## random ori = ", rand_ori) print(fsave, "random_orientation", random_orientation) print(fsave, "rand_ori", rand_ori) run_sim2smv(img_prefix="PDB_"+str(idx_pdb).zfill(3),simparams=simparams,pdb_lines=pdb_lines,crystal=transmitted_info["crystal"],\ spectra=iterator,rotation=rand_ori,rank=rank,fsave=fsave,sfall_cluster=sfall_cluster,quick=simparams.quick) #run_sim2smv(prefix=simparams.prefix, crystal=transmitted_info["crystal"],spectra=iterator,rotation=rand_ori,\ # simparams=simparams,sfall_cluster=sfall_cluster,rank=rank,quick=simparams.quick) iterator = None sfall_cluster = None print("## OK exiting rank", rank, "at", datetime.datetime.now(), "elapsed", time.time() - start_elapse)
def __init__(self, dials_regression): from dials.algorithms.spot_prediction import IndexGenerator from dials.algorithms.spot_prediction import ScanStaticRayPredictor from iotbx.xds import xparm, integrate_hkl from dials.util import ioutil import dxtbx from rstbx.cftbx.coordinate_frame_converter import coordinate_frame_converter from scitbx import matrix # The XDS files to read from integrate_filename = os.path.join(dials_regression, "data", "sim_mx", "INTEGRATE.HKL") gxparm_filename = os.path.join(dials_regression, "data", "sim_mx", "GXPARM.XDS") # Read the XDS files self.integrate_handle = integrate_hkl.reader() self.integrate_handle.read_file(integrate_filename) self.gxparm_handle = xparm.reader() self.gxparm_handle.read_file(gxparm_filename) # Get the parameters we need from the GXPARM file models = dxtbx.load(gxparm_filename) self.beam = models.get_beam() self.gonio = models.get_goniometer() self.detector = models.get_detector() self.scan = models.get_scan() # Get crystal parameters self.space_group_type = ioutil.get_space_group_type_from_xparm( self.gxparm_handle) cfc = coordinate_frame_converter(gxparm_filename) a_vec = cfc.get("real_space_a") b_vec = cfc.get("real_space_b") c_vec = cfc.get("real_space_c") self.unit_cell = cfc.get_unit_cell() self.ub_matrix = matrix.sqr(a_vec + b_vec + c_vec).inverse() # Get the minimum resolution in the integrate file d = [self.unit_cell.d(h) for h in self.integrate_handle.hkl] self.d_min = min(d) # extend the resolution shell by epsilon>0 # to account for rounding artifacts on 32-bit platforms self.d_min = self.d_min - 1e-15 # Get the number of frames from the max z value xcal, ycal, zcal = zip(*self.integrate_handle.xyzcal) self.scan.set_image_range(( self.scan.get_image_range()[0], self.scan.get_image_range()[0] + int(math.ceil(max(zcal))), )) # Print stuff # print self.beam # print self.gonio # print self.detector # print self.scan # Create the index generator self.generate_indices = IndexGenerator(self.unit_cell, self.space_group_type, self.d_min) s0 = self.beam.get_s0() m2 = self.gonio.get_rotation_axis() fixed_rotation = self.gonio.get_fixed_rotation() setting_rotation = self.gonio.get_setting_rotation() UB = self.ub_matrix dphi = self.scan.get_oscillation_range(deg=False) # Create the ray predictor self.predict_rays = ScanStaticRayPredictor(s0, m2, fixed_rotation, setting_rotation, dphi) # Predict the spot locations self.reflections = self.predict_rays(self.generate_indices.to_array(), UB)
def test(): # Python and cctbx imports from math import pi from cctbx.sgtbx import space_group, space_group_symbols # Symmetry constrained parameterisation for the unit cell from cctbx.uctbx import unit_cell # We will set up a mock scan and a mock experiment list from dxtbx.model import ScanFactory from dxtbx.model.experiment_list import Experiment, ExperimentList from libtbx.phil import parse from libtbx.test_utils import approx_equal from rstbx.symmetry.constraints.parameter_reduction import symmetrize_reduce_enlarge from scitbx import matrix from scitbx.array_family import flex # Get modules to build models and minimiser using PHIL import dials.tests.algorithms.refinement.setup_geometry as setup_geometry import dials.tests.algorithms.refinement.setup_minimiser as setup_minimiser from dials.algorithms.refinement.parameterisation.beam_parameters import ( BeamParameterisation, ) from dials.algorithms.refinement.parameterisation.crystal_parameters import ( CrystalOrientationParameterisation, CrystalUnitCellParameterisation, ) # Model parameterisations from dials.algorithms.refinement.parameterisation.detector_parameters import ( DetectorParameterisationSinglePanel, ) # Parameterisation of the prediction equation from dials.algorithms.refinement.parameterisation.prediction_parameters import ( XYPhiPredictionParameterisation, ) from dials.algorithms.refinement.prediction.managed_predictors import ( ScansExperimentsPredictor, ScansRayPredictor, ) from dials.algorithms.refinement.reflection_manager import ReflectionManager # Imports for the target function from dials.algorithms.refinement.target import ( LeastSquaresPositionalResidualWithRmsdCutoff, ) # Reflection prediction from dials.algorithms.spot_prediction import IndexGenerator, ray_intersection ############################# # Setup experimental models # ############################# override = """geometry.parameters { beam.wavelength.random=False beam.wavelength.value=1.0 beam.direction.inclination.random=False crystal.a.length.random=False crystal.a.length.value=12.0 crystal.a.direction.method=exactly crystal.a.direction.exactly.direction=1.0 0.002 -0.004 crystal.b.length.random=False crystal.b.length.value=14.0 crystal.b.direction.method=exactly crystal.b.direction.exactly.direction=-0.002 1.0 0.002 crystal.c.length.random=False crystal.c.length.value=13.0 crystal.c.direction.method=exactly crystal.c.direction.exactly.direction=0.002 -0.004 1.0 detector.directions.method=exactly detector.directions.exactly.dir1=0.99 0.002 -0.004 detector.directions.exactly.norm=0.002 -0.001 0.99 detector.centre.method=exactly detector.centre.exactly.value=1.0 -0.5 199.0 }""" master_phil = parse( """ include scope dials.tests.algorithms.refinement.geometry_phil include scope dials.tests.algorithms.refinement.minimiser_phil """, process_includes=True, ) models = setup_geometry.Extract(master_phil, local_overrides=override, verbose=False) mydetector = models.detector mygonio = models.goniometer mycrystal = models.crystal mybeam = models.beam ########################### # Parameterise the models # ########################### det_param = DetectorParameterisationSinglePanel(mydetector) s0_param = BeamParameterisation(mybeam, mygonio) xlo_param = CrystalOrientationParameterisation(mycrystal) xluc_param = CrystalUnitCellParameterisation(mycrystal) # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength s0_param.set_fixed([True, False, True]) ######################################################################## # Link model parameterisations together into a parameterisation of the # # prediction equation # ######################################################################## # Build a mock scan for a 180 degree sequence sf = ScanFactory() myscan = sf.make_scan( image_range=(1, 1800), exposure_times=0.1, oscillation=(0, 0.1), epochs=list(range(1800)), deg=True, ) # Build an ExperimentList experiments = ExperimentList() experiments.append( Experiment( beam=mybeam, detector=mydetector, goniometer=mygonio, scan=myscan, crystal=mycrystal, imageset=None, )) # Create the PredictionParameterisation pred_param = XYPhiPredictionParameterisation(experiments, [det_param], [s0_param], [xlo_param], [xluc_param]) ################################ # Apply known parameter shifts # ################################ # shift detector by 1.0 mm each translation and 4 mrad each rotation det_p_vals = det_param.get_param_vals() p_vals = [ a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 4.0, 4.0, 4.0]) ] det_param.set_param_vals(p_vals) # shift beam by 4 mrad in free axis s0_p_vals = s0_param.get_param_vals() p_vals = list(s0_p_vals) p_vals[0] += 4.0 s0_param.set_param_vals(p_vals) # rotate crystal a bit (=3 mrad each rotation) xlo_p_vals = xlo_param.get_param_vals() p_vals = [a + b for a, b in zip(xlo_p_vals, [3.0, 3.0, 3.0])] xlo_param.set_param_vals(p_vals) # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of # alpha and beta angles) xluc_p_vals = xluc_param.get_param_vals() cell_params = mycrystal.get_unit_cell().parameters() cell_params = [ a + b for a, b in zip(cell_params, [0.1, -0.1, 0.1, 0.1, -0.1, 0.0]) ] new_uc = unit_cell(cell_params) newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose() S = symmetrize_reduce_enlarge(mycrystal.get_space_group()) S.set_orientation(orientation=newB) X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()]) xluc_param.set_param_vals(X) ############################# # Generate some reflections # ############################# # All indices in a 2.0 Angstrom sphere resolution = 2.0 index_generator = IndexGenerator( mycrystal.get_unit_cell(), space_group(space_group_symbols(1).hall()).type(), resolution, ) indices = index_generator.to_array() sequence_range = myscan.get_oscillation_range(deg=False) im_width = myscan.get_oscillation(deg=False)[1] assert sequence_range == (0.0, pi) assert approx_equal(im_width, 0.1 * pi / 180.0) # Predict rays within the sequence range ray_predictor = ScansRayPredictor(experiments, sequence_range) obs_refs = ray_predictor(indices) # Take only those rays that intersect the detector intersects = ray_intersection(mydetector, obs_refs) obs_refs = obs_refs.select(intersects) # Make a reflection predictor and re-predict for all these reflections. The # result is the same, but we gain also the flags and xyzcal.px columns ref_predictor = ScansExperimentsPredictor(experiments) obs_refs["id"] = flex.int(len(obs_refs), 0) obs_refs = ref_predictor(obs_refs) # Set 'observed' centroids from the predicted ones obs_refs["xyzobs.mm.value"] = obs_refs["xyzcal.mm"] # Invent some variances for the centroid positions of the simulated data im_width = 0.1 * pi / 180.0 px_size = mydetector[0].get_pixel_size() var_x = flex.double(len(obs_refs), (px_size[0] / 2.0)**2) var_y = flex.double(len(obs_refs), (px_size[1] / 2.0)**2) var_phi = flex.double(len(obs_refs), (im_width / 2.0)**2) obs_refs["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi) # The total number of observations should be 1128 assert len(obs_refs) == 1128 ############################### # Undo known parameter shifts # ############################### s0_param.set_param_vals(s0_p_vals) det_param.set_param_vals(det_p_vals) xlo_param.set_param_vals(xlo_p_vals) xluc_param.set_param_vals(xluc_p_vals) ##################################### # Select reflections for refinement # ##################################### refman = ReflectionManager(obs_refs, experiments, outlier_detector=None, close_to_spindle_cutoff=0.1) ############################## # Set up the target function # ############################## # The current 'achieved' criterion compares RMSD against 1/3 the pixel size and # 1/3 the image width in radians. For the simulated data, these are just made up mytarget = LeastSquaresPositionalResidualWithRmsdCutoff( experiments, ref_predictor, refman, pred_param, restraints_parameterisation=None) ###################################### # Set up the LSTBX refinement engine # ###################################### overrides = """minimiser.parameters.engine=GaussNewton minimiser.parameters.logfile=None""" refiner = setup_minimiser.Extract(master_phil, mytarget, pred_param, local_overrides=overrides).refiner refiner.run() assert mytarget.achieved() assert refiner.get_num_steps() == 1 assert approx_equal( mytarget.rmsds(), (0.00508252354876, 0.00420954552156, 8.97303428289e-05)) ############################### # Undo known parameter shifts # ############################### s0_param.set_param_vals(s0_p_vals) det_param.set_param_vals(det_p_vals) xlo_param.set_param_vals(xlo_p_vals) xluc_param.set_param_vals(xluc_p_vals) ###################################################### # Set up the LBFGS with curvatures refinement engine # ###################################################### overrides = """minimiser.parameters.engine=LBFGScurvs minimiser.parameters.logfile=None""" refiner = setup_minimiser.Extract(master_phil, mytarget, pred_param, local_overrides=overrides).refiner refiner.run() assert mytarget.achieved() assert refiner.get_num_steps() == 9 assert approx_equal(mytarget.rmsds(), (0.0558857700305, 0.0333446685335, 0.000347402754278))
def test_ScanVaryingCrystalOrientationParameterisation_intervals( nintervals, plots=False): """Test a ScanVaryingCrystalOrientationParameterisation with a range of different numbers of intervals""" vmp = _TestScanVaryingModelParameterisation() # Parameterise the crystal with the image range and five intervals. Init # TestOrientationModel to explore gradients at image 50, but actually # will try various time points in the test xl_op = _TestOrientationModel(50, vmp.xl, vmp.image_range, nintervals) # How many parameters? num_param = xl_op.num_free() # shift the parameters away from zero p_vals = xl_op.get_param_vals() sigmas = [1.0] * len(p_vals) new_vals = random_param_shift(p_vals, sigmas) xl_op.set_param_vals(new_vals) # recalc state and gradients at image 50 xl_op.compose() p_vals = xl_op.get_param_vals() #print "Shifted parameter vals", p_vals # compare analytical and finite difference derivatives at image 50 an_ds_dp = xl_op.get_ds_dp() fd_ds_dp = get_fd_gradients(xl_op, [1.e-6 * math.pi / 180] * num_param) param_names = xl_op.get_param_names() null_mat = matrix.sqr((0., 0., 0., 0., 0., 0., 0., 0., 0.)) for e, f in zip(an_ds_dp, fd_ds_dp): assert (approx_equal((e - f), null_mat, eps=1.e-6)) # Now test gradients at equally spaced time points across the whole # range num_points = 50 smooth_at = [] phi1_data = [] phi2_data = [] phi3_data = [] step_size = (vmp.image_range[1] - vmp.image_range[0]) / num_points for t in [vmp.image_range[0] + e * step_size \ for e in range(num_points + 1)]: # collect data for plot smooth_at.append(t) phi1_data.append(xl_op._smoother.value_weight(t, xl_op._param[0])[0]) phi2_data.append(xl_op._smoother.value_weight(t, xl_op._param[1])[0]) phi3_data.append(xl_op._smoother.value_weight(t, xl_op._param[2])[0]) xl_op.set_time_point(t) an_ds_dp = xl_op.get_ds_dp() fd_ds_dp = get_fd_gradients(xl_op, [1.e-6 * math.pi / 180] * num_param) #print t #print "Gradients:" #for s, a, f in zip(param_names, an_ds_dp, fd_ds_dp): # print s # print a # print f # print "diff:", a-f # print # for e, f in zip(an_ds_dp, fd_ds_dp): assert (approx_equal((e - f), null_mat, eps=1.e-6)) if plots: import matplotlib.pyplot as plt plt.ion() plt.clf() plt.subplot(311) plt.cla() plt.scatter(smooth_at, phi1_data) plt.title("Phi1") plt.xlabel("image number") plt.ylabel("Phi1 (mrad)") plt.subplot(312) plt.cla() plt.scatter(smooth_at, phi2_data) plt.title("Phi2") plt.xlabel("image number") plt.ylabel("Phi2 (mrad)") plt.subplot(313) plt.cla() plt.scatter(smooth_at, phi3_data) plt.title("Phi3") plt.xlabel("image number") plt.ylabel("Phi3 (mrad)") plt.suptitle("Parameter smoothing with %d intervals" % nintervals) plt.draw()
def _get_flex_image_multipanel(panels, raw_data, brightness=1.0, show_untrusted=False): # From xfel.cftbx.cspad_detector.readHeader() and # xfel.cftbx.cspad_detector.get_flex_image(). XXX Is it possible to # merge this with _get_flex_image() above? XXX Move to dxtbx Format # class (or a superclass for multipanel images)? from math import ceil from iotbx.detectors import generic_flex_image from libtbx.test_utils import approx_equal from scitbx.array_family import flex from scitbx.matrix import col, rec, sqr from xfel.cftbx.detector.metrology import get_projection_matrix assert len(panels) == len(raw_data) # Determine next multiple of eight of the largest panel size. for data in raw_data: if 'data_max_focus' not in locals(): data_max_focus = data.focus() else: data_max_focus = (max(data_max_focus[0], data.focus()[0]), max(data_max_focus[1], data.focus()[1])) data_padded = (8 * int(ceil(data_max_focus[0] / 8)), 8 * int(ceil(data_max_focus[1] / 8))) # Assert that all saturated values are equal and not None. While # dxtbx records a separated trusted_range for each panel, # generic_flex_image supports only accepts a single common value for # the saturation. for panel in panels: if 'saturation' not in locals(): saturation = panel.get_trusted_range()[1] else: assert approx_equal(saturation, panel.get_trusted_range()[1]) assert 'saturation' in locals() and saturation is not None # Create rawdata and my_flex_image before populating it. rawdata = flex.double( flex.grid(len(panels) * data_padded[0], data_padded[1])) my_flex_image = generic_flex_image(rawdata=rawdata, size1_readout=data_max_focus[0], size2_readout=data_max_focus[1], brightness=brightness, saturation=saturation, show_untrusted=show_untrusted) # XXX If a point is contained in two panels simultaneously, it will # be assigned to the panel defined first. XXX Use a Z-buffer # instead? for i in range(len(panels)): # Determine the pixel size for the panel (in meters), as pixel # sizes need not be identical. data = raw_data[i] panel = panels[i] pixel_size = (panel.get_pixel_size()[0] * 1e-3, panel.get_pixel_size()[1] * 1e-3) if len(panels) == 24 and panels[0].get_image_size() == (2463, 195): #print "DLS I23 12M" rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation( (1, 0, 0, 1), (-i * (195 + 17), 0)) continue elif len(panels) == 120 and panels[0].get_image_size() == (487, 195): i_row = i // 5 i_col = i % 5 #print i_row, i_col #print data_padded #print "DLS I23 12M" rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # XXX hardcoded panel height and row gap my_flex_image.add_transformation_and_translation( (1, 0, 0, 1), (-i_row * (195 + 17), -i_col * (487 + 7))) continue # Get unit vectors in the fast and slow directions, as well as the # the locations of the origin and the center of the panel, in # meters. fast = col(panel.get_fast_axis()) slow = col(panel.get_slow_axis()) origin = col(panel.get_origin()) * 1e-3 # Viewer will show an orthographic projection of the data onto a plane perpendicular to 0 0 1 projection_normal = col((0., 0., 1.)) beam_to_origin_proj = origin.dot(projection_normal) * projection_normal projected_origin = origin - beam_to_origin_proj center = projected_origin \ + (data.focus()[0] - 1) / 2 * pixel_size[1] * slow \ + (data.focus()[1] - 1) / 2 * pixel_size[0] * fast normal = slow.cross(fast).normalize() # Determine rotational and translational components of the # homogeneous transformation that maps the readout indices to the # three-dimensional laboratory frame. Rf = sqr((fast(0, 0), fast(1, 0), fast(2, 0), -slow(0, 0), -slow(1, 0), -slow(2, 0), normal(0, 0), normal(1, 0), normal(2, 0))) tf = -Rf * center Tf = sqr( (Rf(0, 0), Rf(0, 1), Rf(0, 2), tf(0, 0), Rf(1, 0), Rf(1, 1), Rf(1, 2), tf(1, 0), Rf(2, 0), Rf(2, 1), Rf(2, 2), tf(2, 0), 0, 0, 0, 1)) # E maps picture coordinates onto metric Cartesian coordinates, # i.e. [row, column, 1 ] -> [x, y, z, 1]. Both frames share the # same origin, but the first coordinate of the screen coordinate # system increases downwards, while the second increases towards # the right. XXX Is this orthographic projection the only one # that makes any sense? E = rec(elems=[ 0, +pixel_size[1], 0, -pixel_size[0], 0, 0, 0, 0, 0, 0, 0, 1 ], n=[4, 3]) # P: [x, y, z, 1] -> [row, column, 1]. Note that data.focus() # needs to be flipped to give (horizontal, vertical) size, # i.e. (width, height). Pf = get_projection_matrix(pixel_size, (data.focus()[1], data.focus()[0]))[0] rawdata.matrix_paste_block_in_place(block=data.as_double(), i_row=i * data_padded[0], i_column=0) # Last row of T is always [0, 0, 0, 1]. T = Pf * Tf * E R = sqr((T(0, 0), T(0, 1), T(1, 0), T(1, 1))) t = col((T(0, 2), T(1, 2))) #print i,R[0],R[1],R[2],R[3],t[0],t[1] my_flex_image.add_transformation_and_translation(R, t) my_flex_image.followup_brightness_scale() return my_flex_image
def _detector(self): '''Return a model for the detector, allowing for two-theta offsets and the detector position. This will be rather more complex...''' detector_name = self._header_dictionary['DETECTOR_NAMES'].split( )[0].strip() detector_axes = map( float, self._header_dictionary['%sDETECTOR_VECTORS' % detector_name].split()) fast = matrix.col(tuple(detector_axes[:3])) slow = matrix.col(tuple(detector_axes[3:])) distortion = map( int, self._header_dictionary['%sSPATIAL_DISTORTION_VECTORS' % detector_name].split()) # multiply through by the distortion to get the true detector fast, slow detector_fast, detector_slow = distortion[0] * fast + distortion[1] * slow, \ distortion[2] * fast + distortion[3] * slow beam_pixels = map( float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' % detector_name].split()[:2]) pixel_size = map( float, self._header_dictionary['%sSPATIAL_DISTORTION_INFO' % detector_name].split()[2:]) image_size = map( int, self._header_dictionary['%sDETECTOR_DIMENSIONS' % detector_name].split()) detector_origin = - (beam_pixels[0] * pixel_size[0] * detector_fast + \ beam_pixels[1] * pixel_size[1] * detector_slow) gonio_axes = map( float, self._header_dictionary['%sGONIO_VECTORS' % detector_name].split()) gonio_values = map( float, self._header_dictionary['%sGONIO_VALUES' % detector_name].split()) gonio_units = self._header_dictionary['%sGONIO_UNITS' % detector_name].split() gonio_num_axes = int(self._header_dictionary['%sGONIO_NUM_VALUES' % detector_name]) rotations = [] translations = [] for j, unit in enumerate(gonio_units): axis = matrix.col(gonio_axes[3 * j:3 * (j + 1)]) if unit == 'deg': rotations.append( axis.axis_and_angle_as_r3_rotation_matrix(gonio_values[j], deg=True)) translations.append(matrix.col((0.0, 0.0, 0.0))) elif unit == 'mm': rotations.append( matrix.sqr((1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0))) translations.append(gonio_values[j] * axis) else: raise RuntimeError('unknown axis unit %s' % unit) rotations.reverse() translations.reverse() for j in range(gonio_num_axes): detector_fast = rotations[j] * detector_fast detector_slow = rotations[j] * detector_slow detector_origin = rotations[j] * detector_origin detector_origin = translations[j] + detector_origin overload = int(float(self._header_dictionary['SATURATED_VALUE'])) underload = -1 # Unfortunately thickness and material are not stored in the header. Set # to sensible defaults. t0 = 0.450 material = 'Si' from cctbx.eltbx import attenuation_coefficient table = attenuation_coefficient.get_table(material) wavelength = float(self._header_dictionary['SCAN_WAVELENGTH']) mu = table.mu_at_angstrom(wavelength) / 10.0 return self._detector_factory.complex( 'PAD', detector_origin.elems, detector_fast.elems, detector_slow.elems, pixel_size, image_size, (underload, overload), px_mm=ParallaxCorrectedPxMmStrategy(mu, t0), mu=mu)
d_max=d_max) observations = observations.select(i_sel_res) alpha_angle = alpha_angle.select(i_sel_res) spot_pred_x_mm = spot_pred_x_mm.select(i_sel_res) spot_pred_y_mm = spot_pred_y_mm.select(i_sel_res) #sort by resolution perm = observations.sort_permutation(by_value="resolution", reverse=True) observations = observations.select(perm) alpha_angle = alpha_angle.select(perm) spot_pred_x_mm = spot_pred_x_mm.select(perm) spot_pred_y_mm = spot_pred_y_mm.select(perm) from prime.postrefine.mod_partiality import partiality_handler ph = partiality_handler() r0 = ph.calc_spot_radius( sqr(crystal_init_orientation.reciprocal_matrix()), observations.indices(), wavelength) two_theta = observations.two_theta(wavelength=wavelength).data() sin_theta_over_lambda_sq = observations.two_theta( wavelength=wavelength).sin_theta_over_lambda_sq().data() ry, rz, re, nu, rotx, roty = (0, 0, 0.003, 0.5, 0, 0) flag_beam_divergence = False partiality_init, delta_xy_init, rs_init, rh_init = ph.calc_partiality_anisotropy_set( crystal_init_orientation.unit_cell(), rotx, roty, observations.indices(), ry, rz, r0, re, nu, two_theta, alpha_angle, wavelength, crystal_init_orientation, spot_pred_x_mm, spot_pred_y_mm, detector_distance_mm, "Lorentzian", flag_beam_divergence) I_full = observations.data() / partiality_init sigI_full = observations.sigmas() / partiality_init observations_full = observations.customized_copy(data=I_full,
def mark_rotation(self): self.marked_rotation = matrix.sqr( gltbx.util.extract_rotation_from_gl_modelview_matrix())
params, options = parser.parse_args(show_diff_phil=False) # Ensure we have a data block experiments = flatten_experiments(params.input.experiments) experiments[0].scan.set_oscillation((0, 1), deg=True) # The predicted reflections reflections = flex.reflection_table.from_predictions_multi(experiments, padding=1) # Select only those within 1 deg x, y, z = reflections["xyzcal.px"].parts() selection = flex.abs(z) < 1 reflections = reflections.select(selection) sigma = matrix.sqr((0.000001, 0, 0, 0, 0.000002, 0, 0, 0, 0.000003)) # Generate observed positions s1_obs, s2_obs, I_obs = generate_observations2(experiments, reflections, sigma) selection = I_obs > 0 s1_obs = s1_obs.select(selection) s2_obs = s2_obs.select(selection) I_obs = I_obs.select(selection) reflections = reflections.select(selection) print(len(selection), len(reflections)) transformed_data = generate_transformed_data(experiments, reflections, sigma)
def test(args=[]): ############################# # Setup experimental models # ############################# master_phil = parse( """ include scope dials.tests.algorithms.refinement.geometry_phil include scope dials.tests.algorithms.refinement.minimiser_phil """, process_includes=True, ) models = setup_geometry.Extract( master_phil, cmdline_args=args, local_overrides="geometry.parameters.random_seed = 1", ) crystal1 = models.crystal models = setup_geometry.Extract( master_phil, cmdline_args=args, local_overrides="geometry.parameters.random_seed = 2", ) mydetector = models.detector mygonio = models.goniometer crystal2 = models.crystal mybeam = models.beam # Build a mock scan for an 18 degree sequence sf = ScanFactory() myscan = sf.make_scan( image_range=(1, 180), exposure_times=0.1, oscillation=(0, 0.1), epochs=list(range(180)), deg=True, ) sequence_range = myscan.get_oscillation_range(deg=False) im_width = myscan.get_oscillation(deg=False)[1] assert sequence_range == (0.0, pi / 10) assert approx_equal(im_width, 0.1 * pi / 180.0) # Build an experiment list experiments = ExperimentList() experiments.append( Experiment( beam=mybeam, detector=mydetector, goniometer=mygonio, scan=myscan, crystal=crystal1, imageset=None, )) experiments.append( Experiment( beam=mybeam, detector=mydetector, goniometer=mygonio, scan=myscan, crystal=crystal2, imageset=None, )) assert len(experiments.detectors()) == 1 ########################################################## # Parameterise the models (only for perturbing geometry) # ########################################################## det_param = DetectorParameterisationSinglePanel(mydetector) s0_param = BeamParameterisation(mybeam, mygonio) xl1o_param = CrystalOrientationParameterisation(crystal1) xl1uc_param = CrystalUnitCellParameterisation(crystal1) xl2o_param = CrystalOrientationParameterisation(crystal2) xl2uc_param = CrystalUnitCellParameterisation(crystal2) # Fix beam to the X-Z plane (imgCIF geometry), fix wavelength s0_param.set_fixed([True, False, True]) ################################ # Apply known parameter shifts # ################################ # shift detector by 1.0 mm each translation and 2 mrad each rotation det_p_vals = det_param.get_param_vals() p_vals = [ a + b for a, b in zip(det_p_vals, [1.0, 1.0, 1.0, 2.0, 2.0, 2.0]) ] det_param.set_param_vals(p_vals) # shift beam by 2 mrad in free axis s0_p_vals = s0_param.get_param_vals() p_vals = list(s0_p_vals) p_vals[0] += 2.0 s0_param.set_param_vals(p_vals) # rotate crystal a bit (=2 mrad each rotation) xlo_p_vals = [] for xlo in (xl1o_param, xl2o_param): p_vals = xlo.get_param_vals() xlo_p_vals.append(p_vals) new_p_vals = [a + b for a, b in zip(p_vals, [2.0, 2.0, 2.0])] xlo.set_param_vals(new_p_vals) # change unit cell a bit (=0.1 Angstrom length upsets, 0.1 degree of # gamma angle) xluc_p_vals = [] for xluc, xl in ((xl1uc_param, crystal1), ((xl2uc_param, crystal2))): p_vals = xluc.get_param_vals() xluc_p_vals.append(p_vals) cell_params = xl.get_unit_cell().parameters() cell_params = [ a + b for a, b in zip(cell_params, [0.1, 0.1, 0.1, 0.0, 0.0, 0.1]) ] new_uc = unit_cell(cell_params) newB = matrix.sqr(new_uc.fractionalization_matrix()).transpose() S = symmetrize_reduce_enlarge(xl.get_space_group()) S.set_orientation(orientation=newB) X = tuple([e * 1.0e5 for e in S.forward_independent_parameters()]) xluc.set_param_vals(X) ############################# # Generate some reflections # ############################# # All indices in a 2.5 Angstrom sphere for crystal1 resolution = 2.5 index_generator = IndexGenerator( crystal1.get_unit_cell(), space_group(space_group_symbols(1).hall()).type(), resolution, ) indices1 = index_generator.to_array() # All indices in a 2.5 Angstrom sphere for crystal2 resolution = 2.5 index_generator = IndexGenerator( crystal2.get_unit_cell(), space_group(space_group_symbols(1).hall()).type(), resolution, ) indices2 = index_generator.to_array() # Predict rays within the sequence range. Set experiment IDs ray_predictor = ScansRayPredictor(experiments, sequence_range) obs_refs1 = ray_predictor(indices1, experiment_id=0) obs_refs1["id"] = flex.int(len(obs_refs1), 0) obs_refs2 = ray_predictor(indices2, experiment_id=1) obs_refs2["id"] = flex.int(len(obs_refs2), 1) # Take only those rays that intersect the detector intersects = ray_intersection(mydetector, obs_refs1) obs_refs1 = obs_refs1.select(intersects) intersects = ray_intersection(mydetector, obs_refs2) obs_refs2 = obs_refs2.select(intersects) # Make a reflection predictor and re-predict for all these reflections. The # result is the same, but we gain also the flags and xyzcal.px columns ref_predictor = ScansExperimentsPredictor(experiments) obs_refs1 = ref_predictor(obs_refs1) obs_refs2 = ref_predictor(obs_refs2) # Set 'observed' centroids from the predicted ones obs_refs1["xyzobs.mm.value"] = obs_refs1["xyzcal.mm"] obs_refs2["xyzobs.mm.value"] = obs_refs2["xyzcal.mm"] # Invent some variances for the centroid positions of the simulated data im_width = 0.1 * pi / 18.0 px_size = mydetector[0].get_pixel_size() var_x = flex.double(len(obs_refs1), (px_size[0] / 2.0)**2) var_y = flex.double(len(obs_refs1), (px_size[1] / 2.0)**2) var_phi = flex.double(len(obs_refs1), (im_width / 2.0)**2) obs_refs1["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi) var_x = flex.double(len(obs_refs2), (px_size[0] / 2.0)**2) var_y = flex.double(len(obs_refs2), (px_size[1] / 2.0)**2) var_phi = flex.double(len(obs_refs2), (im_width / 2.0)**2) obs_refs2["xyzobs.mm.variance"] = flex.vec3_double(var_x, var_y, var_phi) # concatenate reflection lists obs_refs1.extend(obs_refs2) obs_refs = obs_refs1 ############################### # Undo known parameter shifts # ############################### s0_param.set_param_vals(s0_p_vals) det_param.set_param_vals(det_p_vals) xl1o_param.set_param_vals(xlo_p_vals[0]) xl2o_param.set_param_vals(xlo_p_vals[1]) xl1uc_param.set_param_vals(xluc_p_vals[0]) xl2uc_param.set_param_vals(xluc_p_vals[1]) # scan static first params = phil_scope.fetch(source=parse("")).extract() refiner = RefinerFactory.from_parameters_data_experiments( params, obs_refs, experiments) refiner.run() # scan varying params.refinement.parameterisation.scan_varying = True refiner = RefinerFactory.from_parameters_data_experiments( params, obs_refs, experiments) refiner.run() # Ensure all models have scan-varying state set # (https://github.com/dials/dials/issues/798) refined_experiments = refiner.get_experiments() sp = [xl.get_num_scan_points() for xl in refined_experiments.crystals()] assert sp.count(181) == 2
def run(self, experiments, reflections): self.logger.log_step_time("POSTREFINEMENT") if (not self.params.postrefinement.enable) or (self.params.scaling.algorithm != "mark0"): # mark1 implies no scaling/post-refinement self.logger.log("No post-refinement was done") if self.mpi_helper.rank == 0: self.logger.main_log("No post-refinement was done") return experiments, reflections target_symm = symmetry(unit_cell = self.params.scaling.unit_cell, space_group_info = self.params.scaling.space_group) i_model = self.params.scaling.i_model miller_set = self.params.scaling.miller_set # Ensure that match_multi_indices() will return identical results # when a frame's observations are matched against the # pre-generated Miller set, self.miller_set, and the reference # data set, self.i_model. The implication is that the same match # can be used to map Miller indices to array indices for intensity # accumulation, and for determination of the correlation # coefficient in the presence of a scaling reference. assert len(i_model.indices()) == len(miller_set.indices()) assert (i_model.indices() == miller_set.indices()).count(False) == 0 new_experiments = ExperimentList() new_reflections = flex.reflection_table() experiments_rejected_by_reason = {} # reason:how_many_rejected for experiment in experiments: exp_reflections = reflections.select(reflections['exp_id'] == experiment.identifier) # Build a miller array for the experiment reflections with original miller indexes exp_miller_indices_original = miller.set(target_symm, exp_reflections['miller_index'], not self.params.merging.merge_anomalous) observations_original_index = miller.array(exp_miller_indices_original, exp_reflections['intensity.sum.value'], flex.double(flex.sqrt(exp_reflections['intensity.sum.variance']))) assert exp_reflections.size() == exp_miller_indices_original.size() assert observations_original_index.size() == exp_miller_indices_original.size() # Build a miller array for the experiment reflections with asu miller indexes exp_miller_indices_asu = miller.set(target_symm, exp_reflections['miller_index_asymmetric'], True) observations = miller.array(exp_miller_indices_asu, exp_reflections['intensity.sum.value'], flex.double(flex.sqrt(exp_reflections['intensity.sum.variance']))) matches = miller.match_multi_indices(miller_indices_unique = miller_set.indices(), miller_indices = observations.indices()) pair1 = flex.int([pair[1] for pair in matches.pairs()]) # refers to the observations pair0 = flex.int([pair[0] for pair in matches.pairs()]) # refers to the model assert exp_reflections.size() == exp_miller_indices_original.size() assert observations_original_index.size() == exp_miller_indices_original.size() # narrow things down to the set that matches, only observations_pair1_selected = observations.customized_copy(indices = flex.miller_index([observations.indices()[p] for p in pair1]), data = flex.double([observations.data()[p] for p in pair1]), sigmas = flex.double([observations.sigmas()[p] for p in pair1])) observations_original_index_pair1_selected = observations_original_index.customized_copy(indices = flex.miller_index([observations_original_index.indices()[p] for p in pair1]), data = flex.double([observations_original_index.data()[p] for p in pair1]), sigmas = flex.double([observations_original_index.sigmas()[p] for p in pair1])) I_observed = observations_pair1_selected.data() MILLER = observations_original_index_pair1_selected.indices() ORI = crystal_orientation(experiment.crystal.get_A(), basis_type.reciprocal) Astar = matrix.sqr(ORI.reciprocal_matrix()) Astar_from_experiment = matrix.sqr(experiment.crystal.get_A()) assert Astar == Astar_from_experiment WAVE = experiment.beam.get_wavelength() BEAM = matrix.col((0.0,0.0,-1./WAVE)) BFACTOR = 0. MOSAICITY_DEG = experiment.crystal.get_half_mosaicity_deg() DOMAIN_SIZE_A = experiment.crystal.get_domain_size_ang() # calculation of correlation here I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) use_weights = False # New facility for getting variance-weighted correlation if use_weights: # variance weighting I_weight = flex.double([1./(observations_pair1_selected.sigmas()[pair[1]])**2 for pair in matches.pairs()]) else: I_weight = flex.double(len(observations_pair1_selected.sigmas()), 1.) I_weight.set_selected(I_invalid, 0.) """Explanation of 'include_negatives' semantics as originally implemented in cxi.merge postrefinement: include_negatives = True + and - reflections both used for Rh distribution for initial estimate of RS parameter + and - reflections both used for calc/obs correlation slope for initial estimate of G parameter + and - reflections both passed to the refinery and used in the target function (makes sense if you look at it from a certain point of view) include_negatives = False + and - reflections both used for Rh distribution for initial estimate of RS parameter + reflections only used for calc/obs correlation slope for initial estimate of G parameter + and - reflections both passed to the refinery and used in the target function (makes sense if you look at it from a certain point of view) """ # RB: By design, for MPI-Merge "include negatives" is implicitly True SWC = simple_weighted_correlation(I_weight, I_reference, I_observed) if self.params.output.log_level == 0: self.logger.log("Old correlation is: %f"%SWC.corr) if self.params.postrefinement.algorithm == "rs": Rhall = flex.double() for mill in MILLER: H = matrix.col(mill) Xhkl = Astar*H Rh = ( Xhkl + BEAM ).length() - (1./WAVE) Rhall.append(Rh) Rs = math.sqrt(flex.mean(Rhall*Rhall)) RS = 1./10000. # reciprocal effective domain size of 1 micron RS = Rs # try this empirically determined approximate, monochrome, a-mosaic value current = flex.double([SWC.slope, BFACTOR, RS, 0., 0.]) parameterization_class = rs_parameterization refinery = rs_refinery(ORI=ORI, MILLER=MILLER, BEAM=BEAM, WAVE=WAVE, ICALCVEC = I_reference, IOBSVEC = I_observed) elif self.params.postrefinement.algorithm == "eta_deff": eta_init = 2. * MOSAICITY_DEG * math.pi/180. D_eff_init = 2. * DOMAIN_SIZE_A current = flex.double([SWC.slope, BFACTOR, eta_init, 0., 0., D_eff_init]) parameterization_class = eta_deff_parameterization refinery = eta_deff_refinery(ORI=ORI, MILLER=MILLER, BEAM=BEAM, WAVE=WAVE, ICALCVEC = I_reference, IOBSVEC = I_observed) func = refinery.fvec_callable(parameterization_class(current)) functional = flex.sum(func * func) if self.params.output.log_level == 0: self.logger.log("functional: %f"%functional) self.current = current; self.parameterization_class = parameterization_class self.refinery = refinery; self.observations_pair1_selected = observations_pair1_selected; self.observations_original_index_pair1_selected = observations_original_index_pair1_selected error_detected = False try: self.run_plain() result_observations_original_index, result_observations, result_matches = self.result_for_cxi_merge() assert result_observations_original_index.size() == result_observations.size() assert result_matches.pairs().size() == result_observations_original_index.size() except (AssertionError, ValueError, RuntimeError) as e: error_detected = True reason = repr(e) if not reason: reason = "Unknown error" if not reason in experiments_rejected_by_reason: experiments_rejected_by_reason[reason] = 1 else: experiments_rejected_by_reason[reason] += 1 if not error_detected: new_experiments.append(experiment) new_exp_reflections = flex.reflection_table() new_exp_reflections['miller_index_asymmetric'] = flex.miller_index(result_observations.indices()) new_exp_reflections['intensity.sum.value'] = flex.double(result_observations.data()) new_exp_reflections['intensity.sum.variance'] = flex.double(flex.pow(result_observations.sigmas(),2)) new_exp_reflections['exp_id'] = flex.std_string(len(new_exp_reflections), experiment.identifier) new_reflections.extend(new_exp_reflections) ''' # debugging elif reason.startswith("ValueError"): self.logger.log("Rejected b/c of value error exp id: %s; unit cell: %s"%(exp_id, str(experiment.crystal.get_unit_cell())) ) ''' # report rejected experiments, reflections experiments_rejected_by_postrefinement = len(experiments) - len(new_experiments) reflections_rejected_by_postrefinement = reflections.size() - new_reflections.size() self.logger.log("Experiments rejected by post-refinement: %d"%experiments_rejected_by_postrefinement) self.logger.log("Reflections rejected by post-refinement: %d"%reflections_rejected_by_postrefinement) all_reasons = [] for reason, count in six.iteritems(experiments_rejected_by_reason): self.logger.log("Experiments rejected due to %s: %d"%(reason,count)) all_reasons.append(reason) comm = self.mpi_helper.comm MPI = self.mpi_helper.MPI # Collect all rejection reasons from all ranks. Use allreduce to let each rank have all reasons. all_reasons = comm.allreduce(all_reasons, MPI.SUM) all_reasons = set(all_reasons) # Now that each rank has all reasons from all ranks, we can treat the reasons in a uniform way. total_experiments_rejected_by_reason = {} for reason in all_reasons: rejected_experiment_count = 0 if reason in experiments_rejected_by_reason: rejected_experiment_count = experiments_rejected_by_reason[reason] total_experiments_rejected_by_reason[reason] = comm.reduce(rejected_experiment_count, MPI.SUM, 0) total_accepted_experiment_count = comm.reduce(len(new_experiments), MPI.SUM, 0) # how many reflections have we rejected due to post-refinement? rejected_reflections = len(reflections) - len(new_reflections); total_rejected_reflections = self.mpi_helper.sum(rejected_reflections) if self.mpi_helper.rank == 0: for reason, count in six.iteritems(total_experiments_rejected_by_reason): self.logger.main_log("Total experiments rejected due to %s: %d"%(reason,count)) self.logger.main_log("Total experiments accepted: %d"%total_accepted_experiment_count) self.logger.main_log("Total reflections rejected due to post-refinement: %d"%total_rejected_reflections) self.logger.log_step_time("POSTREFINEMENT", True) return new_experiments, new_reflections
def run(args=None): from dials.util import log from dials.util.options import OptionParser, reflections_and_experiments_from_files usage = "dials.rl_png [options] experiments.json observations.refl" parser = OptionParser( usage=usage, phil=phil_scope, read_experiments=True, read_reflections=True, check_format=False, epilog=help_message, ) params, options = parser.parse_args(args) reflections, experiments = reflections_and_experiments_from_files( params.input.reflections, params.input.experiments) if len(experiments) == 0 or len(reflections) == 0: parser.print_help() exit(0) # Configure the logging log.config(logfile="dials.rl_png.log") # Log the diff phil diff_phil = parser.diff_phil.as_str() if diff_phil != "": logger.info("The following parameters have been modified:\n") logger.info(diff_phil) reflections = reflections[0] f = ReciprocalLatticePng(settings=params) f.load_models(experiments, reflections) rotation_axis = matrix.col(experiments[0].goniometer.get_rotation_axis()) s0 = matrix.col(experiments[0].beam.get_s0()) e1 = rotation_axis.normalize() e2 = s0.normalize() e3 = e1.cross(e2).normalize() f.viewer.plot("rl_rotation_axis.png", n=e1.elems) f.viewer.plot("rl_beam_vector", n=e2.elems) f.viewer.plot("rl_e3.png", n=e3.elems) n_solutions = params.basis_vector_search.n_solutions if experiments.crystals().count(None) < len(experiments): for i, c in enumerate(experiments.crystals()): A = matrix.sqr(c.get_A()) direct_matrix = A.inverse() a = direct_matrix[:3] b = direct_matrix[3:6] c = direct_matrix[6:9] prefix = "" if len(experiments.crystals()) > 1: prefix = "%i_" % (i + 1) f.viewer.plot("rl_%sa.png" % prefix, n=a) f.viewer.plot("rl_%sb.png" % prefix, n=b) f.viewer.plot("rl_%sc.png" % prefix, n=c) elif n_solutions: if "imageset_id" not in reflections: reflections["imageset_id"] = reflections["id"] reflections.centroid_px_to_mm(experiments) reflections.map_centroids_to_reciprocal_space(experiments) if params.d_min is not None: d_spacings = 1 / reflections["rlp"].norms() sel = d_spacings > params.d_min reflections = reflections.select(sel) # derive a max_cell from mm spots max_cell = find_max_cell(reflections, max_cell_multiplier=1.3, step_size=45).max_cell result = run_dps(experiments[0], reflections, max_cell) if result: solutions = [matrix.col(v) for v in result["solutions"]] for i in range(min(n_solutions, len(solutions))): v = solutions[i] f.viewer.plot("rl_solution_%s.png" % (i + 1), n=v.elems)
def __str__(self): U = matrix.sqr(self.experiment.crystal.get_U()) B = matrix.sqr(self.experiment.crystal.get_B()) a_star_ = U * B * a_star b_star_ = U * B * b_star c_star_ = U * B * c_star Binvt = B.inverse().transpose() a_ = U * Binvt * a b_ = U * Binvt * b c_ = U * Binvt * c names = self.experiment.goniometer.get_names() axes = self.experiment.goniometer.get_axes() rows = [["Experimental axis", "a*", "b*", "c*"]] rows.append( [names[0]] + [ f"{smallest_angle(axis.angle(matrix.col(axes[0]), deg=True)):.3f}" for axis in (a_star_, b_star_, c_star_) ] ) rows.append( ["Beam"] + [ f"{smallest_angle(axis.angle(self.s0, deg=True)):.3f}" for axis in (a_star_, b_star_, c_star_) ] ) rows.append( [names[2]] + [ f"{smallest_angle(axis.angle(matrix.col(axes[2]), deg=True)):.3f}" for axis in (a_star_, b_star_, c_star_) ] ) output = [] output.append( "Angles between reciprocal cell axes and principal experimental axes:" ) output.append(tabulate(rows, headers="firstrow")) output.append("") rows = [["Experimental axis", "a", "b", "c"]] rows.append( [names[0]] + [ f"{smallest_angle(axis.angle(matrix.col(axes[0]), deg=True)):.3f}" for axis in (a_, b_, c_) ] ) rows.append( ["Beam"] + [ f"{smallest_angle(axis.angle(self.s0, deg=True)):.3f}" for axis in (a_, b_, c_) ] ) rows.append( [names[2]] + [ f"{smallest_angle(axis.angle(matrix.col(axes[2]), deg=True)):.3f}" for axis in (a_, b_, c_) ] ) output.append("Angles between unit cell axes and principal experimental axes:") output.append(tabulate(rows, headers="firstrow")) output.append("") names = self.experiment.goniometer.get_names() space_group = self.experiment.crystal.get_space_group() reciprocal = self.frame == "reciprocal" rows = [] for angles, vector_pairs in self.unique_solutions.items(): v1, v2 = list(vector_pairs)[0] rows.append( ( describe(v1, space_group, reciprocal=reciprocal), describe(v2, space_group, reciprocal=reciprocal), f"{angles[0]: 7.3f}", f"{angles[1]: 7.3f}", ) ) rows = [("Primary axis", "Secondary axis", names[1], names[0])] + sorted(rows) output.append("Independent solutions:") output.append(tabulate(rows, headers="firstrow")) return "\n".join(output)
def from_reflections(self, experiment, reflections): """ Generate the required data from the reflections """ # Get the beam vector s0 = matrix.col(experiment.beam.get_s0()) # Get the reciprocal lattice vector h_list = reflections["miller_index"] # Initialise the list of observed intensities and covariances sp_list = flex.vec3_double(len(h_list)) ctot_list = flex.double(len(h_list)) mobs_list = flex.vec2_double(len(h_list)) Sobs_list = flex.double(flex.grid(len(h_list), 4)) Bmean = matrix.sqr((0, 0, 0, 0)) # SSS = 0 logger.info("Computing observed covariance for %d reflections" % len(reflections)) s0_length = s0.length() assert len(experiment.detector) == 1 panel = experiment.detector[0] sbox = reflections["shoebox"] xyzobs = reflections["xyzobs.px.value"] for r in range(len(reflections)): # The vector to the pixel centroid sp = (matrix.col(panel.get_pixel_lab_coord( xyzobs[r][0:2])).normalize() * s0.length()) # Compute change of basis R = compute_change_of_basis_operation(s0, sp) # Get data and compute total counts data = sbox[r].data mask = sbox[r].mask bgrd = sbox[r].background # Get array of vectors i0 = sbox[r].bbox[0] j0 = sbox[r].bbox[2] assert data.all()[0] == 1 X = flex.vec2_double(flex.grid(data.all()[1], data.all()[2])) ctot = 0 C = flex.double(X.accessor()) for j in range(data.all()[1]): for i in range(data.all()[2]): c = data[0, j, i] - bgrd[0, j, i] # if mask[0,j,i] & (1 | 4 | 8) == (1 | 4 | 8) and c > 0: if mask[0, j, i] & (1 | 4) == (1 | 4) and c > 0: ctot += c ii = i + i0 jj = j + j0 s = panel.get_pixel_lab_coord((ii + 0.5, jj + 0.5)) s = matrix.col(s).normalize() * s0_length e = R * s X[j, i] = (e[0], e[1]) C[j, i] = c # Check we have a sensible number of counts assert ctot > 0, "BUG: strong spots should have more than 0 counts!" # Compute the mean vector xbar = matrix.col((0, 0)) for j in range(X.all()[0]): for i in range(X.all()[1]): x = matrix.col(X[j, i]) xbar += C[j, i] * x xbar /= ctot # Compute the covariance matrix Sobs = matrix.sqr((0, 0, 0, 0)) for j in range(X.all()[0]): for i in range(X.all()[1]): x = matrix.col(X[j, i]) Sobs += (x - xbar) * (x - xbar).transpose() * C[j, i] Sobs /= ctot assert Sobs[0] > 0, "BUG: variance must be > 0" assert Sobs[3] > 0, "BUG: variance must be > 0" # Compute the bias # zero = matrix.col((0, 0)) # Bias_sq = (xbar - zero)*(xbar - zero).transpose() # Bmean += Bias_sq # ctot += 10000 # Add to the lists sp_list[r] = sp ctot_list[r] = ctot mobs_list[r] = xbar Sobs_list[r, 0] = Sobs[0] Sobs_list[r, 1] = Sobs[1] Sobs_list[r, 2] = Sobs[2] Sobs_list[r, 3] = Sobs[3] # Print some information logger.info("") logger.info("I_min = %.2f, I_max = %.2f" % (flex.min(ctot_list), flex.max(ctot_list))) # Sometimes a single reflection might have an enormouse intensity for # whatever reason and since we weight by intensity, this can cause the # refinement to be dominated by these reflections. Therefore, if the # intensity is greater than some value, damp the weighting accordingly def damp_outlier_intensity_weights(ctot_list): sorted_ctot = sorted(ctot_list) Q1 = sorted_ctot[len(ctot_list) // 4] Q2 = sorted_ctot[len(ctot_list) // 2] Q3 = sorted_ctot[3 * len(ctot_list) // 4] IQR = Q3 - Q1 T = Q3 + 1.5 * IQR logger.info("Median I = %.2f" % Q2) logger.info("Q1/Q3 I = %.2f, %.2f" % (Q1, Q3)) logger.info("Damping effect of intensities > %f" % T) ndamped = 0 for i in range(len(ctot_list)): if ctot_list[i] > T: logger.info("Damping %.2f" % ctot_list[i]) ctot_list[i] = T ndamped += 1 logger.info("Damped %d/%d reflections" % (ndamped, len(ctot_list))) return ctot_list ctot_list = damp_outlier_intensity_weights(ctot_list) # Print the mean covariance Smean = matrix.sqr((0, 0, 0, 0)) for r in range(Sobs_list.all()[0]): Smean += matrix.sqr(tuple(Sobs_list[r:r + 1, :])) Smean /= Sobs_list.all()[0] # Bmean /= len(reflections) logger.info("") logger.info("Mean observed covariance:") print_matrix(Smean) print_eigen_values_and_vectors_of_observed_covariance(Smean, s0) # logger.info("") # logger.info("Mean observed bias^2:") # print_matrix(Bmean) # Compute the distance from the Ewald sphere epsilon = flex.double(s0.length() - matrix.col(s).length() for s in reflections["s2"]) mv = flex.mean_and_variance(epsilon) logger.info("") logger.info("Mean distance from Ewald sphere: %.3g" % mv.mean()) logger.info("Variance in distance from Ewald sphere: %.3g" % mv.unweighted_sample_variance()) # Return the profile refiner data return RefinerData(s0, sp_list, h_list, ctot_list, mobs_list, Sobs_list)
def tst_all(): F = foo() assert F == (1, 2, 3, 4) size = 1516 D = detector(slowpixels=1516, fastpixels=1516, pixel_size=0.00011) D.set_region_of_interest(0, int(0.6 * size), int(0.4 * size), int(0.6 * size)) D.set_oversampling(1) C = camera() C.distance = 0.18166 C.Ybeam = 0.08338 C.Zbeam = 0.08338 C.lambda0 = 6.2E-10 C.dispersion = 0.002 C.dispsteps = 4 C.hdivrange = 0 C.vdivrange = 0 C.hdivstep = 1 C.vdivstep = 1 C.source_distance = 10. C.fluence = 1.E24 Amat = sqr((127.6895065259495, 0.6512077339887, -0.4403031342553, -1.1449112128916, 225.3922539826207, 1.8393136632579, 1.0680694468752, -2.4923062985132, 306.0953037195841)) PSII = amplitudes_from_pdb(8., "fft", True) from cctbx import crystal_orientation X = crystal() X.orientation = crystal_orientation.crystal_orientation( Amat, crystal_orientation.basis_type.direct) X.miller = PSII.indices() X.amplitudes = PSII.data() X.Na = 6 X.Nb = 6 X.Nc = 6 SIM = fast_bragg_simulation() SIM.set_detector(D) SIM.set_camera(C) SIM.set_crystal(X) SIM.sweep_over_detector() data = D.raw scale_factor = 55000. / flex.max(data) #print "scale_factor",scale_factor fileout = "intimage_001.img" SIM.to_smv_format(fileout=fileout, intfile_scale=scale_factor, saturation=40000) import os assert os.path.isfile(fileout) os.remove(fileout) #simulation is complete, now we'll autoindex the image fragment and verify # that the indexed cell is similar to the input cell. if (not libtbx.env.has_module("annlib")): print "Skipping some tests: annlib not available." return # 1. Analysis of the image to identify the Bragg peak centers. # This step uses an inefficient algorithm and implementation and # is most time consuming; but the code is only for testing, not production from rstbx.diffraction.fastbragg.tst_utils_clustering import specific_libann_cluster M = specific_libann_cluster(scale_factor * data, intensity_cutoff=25, distance_cutoff=17) # M is a dictionary of peak intensities indexed by pixel coordinates # 2. Now autoindex the pattern from rstbx.diffraction.fastbragg.tst_utils_clustering import index_wrapper SIM.C = C SIM.D = D ai, ref_uc = index_wrapper(M.keys(), SIM, PSII) tst_uc = ai.getOrientation().unit_cell() #print ref_uc # (127.692, 225.403, 306.106, 90, 90, 90) #print tst_uc # (106.432, 223.983, 303.102, 90.3185, 91.5998, 90.5231) # 3. Final assertion. In the given orientation, # the unit cell A vector is into the beam and is not well sampled, # so tolerances have to be fairly relaxed, 5%. # Labelit does better with the target_cell restraint, but this improved # algorithm is not used here for the test assert ref_uc.is_similar_to(tst_uc, relative_length_tolerance=0.20, absolute_angle_tolerance=2.0)
def scale_frame_detail(self, result, file_name, db_mgr, out): # If the pickled integration file does not contain a wavelength, # fall back on the value given on the command line. XXX The # wavelength parameter should probably be removed from master_phil # once all pickled integration files contain it. if ("wavelength" in result): wavelength = result["wavelength"] elif (self.params.wavelength is not None): wavelength = self.params.wavelength else: # XXX Give error, or raise exception? return None assert (wavelength > 0) observations = result["observations"][0] cos_two_polar_angle = result["cos_two_polar_angle"] assert observations.size() == cos_two_polar_angle.size() tt_vec = observations.two_theta(wavelength) #print "mean tt degrees",180.*flex.mean(tt_vec.data())/math.pi cos_tt_vec = flex.cos(tt_vec.data()) sin_tt_vec = flex.sin(tt_vec.data()) cos_sq_tt_vec = cos_tt_vec * cos_tt_vec sin_sq_tt_vec = sin_tt_vec * sin_tt_vec P_nought_vec = 0.5 * (1. + cos_sq_tt_vec) F_prime = -1.0 # Hard-coded value defines the incident polarization axis P_prime = 0.5 * F_prime * cos_two_polar_angle * sin_sq_tt_vec # XXX added as a diagnostic prange = P_nought_vec - P_prime other_F_prime = 1.0 otherP_prime = 0.5 * other_F_prime * cos_two_polar_angle * sin_sq_tt_vec otherprange = P_nought_vec - otherP_prime diff2 = flex.abs(prange - otherprange) print("mean diff is", flex.mean(diff2), "range", flex.min(diff2), flex.max(diff2)) # XXX done observations = observations / (P_nought_vec - P_prime) # This corrects observations for polarization assuming 100% polarization on # one axis (thus the F_prime = -1.0 rather than the perpendicular axis, 1.0) # Polarization model as described by Kahn, Fourme, Gadet, Janin, Dumas & Andre # (1982) J. Appl. Cryst. 15, 330-337, equations 13 - 15. print("Step 3. Correct for polarization.") indexed_cell = observations.unit_cell() observations_original_index = observations.deep_copy() if result.get( "model_partialities", None ) is not None and result["model_partialities"][0] is not None: # some recordkeeping useful for simulations partialities_original_index = observations.customized_copy( crystal_symmetry=self.miller_set.crystal_symmetry(), data=result["model_partialities"][0]["data"], sigmas=flex.double(result["model_partialities"][0] ["data"].size()), #dummy value for sigmas indices=result["model_partialities"][0]["indices"], ).resolution_filter(d_min=self.params.d_min) assert len(observations_original_index.indices()) == len( observations.indices()) # Now manipulate the data to conform to unit cell, asu, and space group # of reference. The resolution will be cut later. # Only works if there is NOT an indexing ambiguity! observations = observations.customized_copy( anomalous_flag=not self.params.merge_anomalous, crystal_symmetry=self.miller_set.crystal_symmetry()).map_to_asu() observations_original_index = observations_original_index.customized_copy( anomalous_flag=not self.params.merge_anomalous, crystal_symmetry=self.miller_set.crystal_symmetry()) print("Step 4. Filter on global resolution and map to asu") print("Data in reference setting:", file=out) #observations.show_summary(f=out, prefix=" ") show_observations(observations, out=out) #if self.params.significance_filter.apply is True: # raise Exception("significance filter not implemented in samosa") if self.params.significance_filter.apply is True: #------------------------------------ # Apply an I/sigma filter ... accept resolution bins only if they # have significant signal; tends to screen out higher resolution observations # if the integration model doesn't quite fit N_obs_pre_filter = observations.size() N_bins_small_set = N_obs_pre_filter // self.params.significance_filter.min_ct N_bins_large_set = N_obs_pre_filter // self.params.significance_filter.max_ct # Ensure there is at least one bin. N_bins = max([ min([self.params.significance_filter.n_bins, N_bins_small_set]), N_bins_large_set, 1 ]) print("Total obs %d Choose n bins = %d" % (N_obs_pre_filter, N_bins)) bin_results = show_observations(observations, out=out, n_bins=N_bins) #show_observations(observations, out=sys.stdout, n_bins=N_bins) acceptable_resolution_bins = [ bin.mean_I_sigI > self.params.significance_filter.sigma for bin in bin_results ] acceptable_nested_bin_sequences = [ i for i in range(len(acceptable_resolution_bins)) if False not in acceptable_resolution_bins[:i + 1] ] if len(acceptable_nested_bin_sequences) == 0: return null_data(file_name=file_name, log_out=out.getvalue(), low_signal=True) else: N_acceptable_bins = max(acceptable_nested_bin_sequences) + 1 imposed_res_filter = float(bin_results[N_acceptable_bins - 1].d_range.split()[2]) imposed_res_sel = observations.resolution_filter_selection( d_min=imposed_res_filter) observations = observations.select(imposed_res_sel) observations_original_index = observations_original_index.select( imposed_res_sel) print("New resolution filter at %7.2f" % imposed_res_filter, file_name) print("N acceptable bins", N_acceptable_bins) print("Old n_obs: %d, new n_obs: %d" % (N_obs_pre_filter, observations.size())) print("Step 5. Frame by frame resolution filter") # Finished applying the binwise I/sigma filter--------------------------------------- if self.params.raw_data.sdfac_auto is True: raise Exception("sdfac auto not implemented in samosa.") print( "Step 6. Match to reference intensities, filter by correlation, filter out negative intensities." ) assert len(observations_original_index.indices()) \ == len(observations.indices()) data = frame_data(self.n_refl, file_name) data.set_indexed_cell(indexed_cell) data.d_min = observations.d_min() # Ensure that match_multi_indices() will return identical results # when a frame's observations are matched against the # pre-generated Miller set, self.miller_set, and the reference # data set, self.i_model. The implication is that the same match # can be used to map Miller indices to array indices for intensity # accumulation, and for determination of the correlation # coefficient in the presence of a scaling reference. if self.i_model is not None: assert len(self.i_model.indices()) == len(self.miller_set.indices()) \ and (self.i_model.indices() == self.miller_set.indices()).count(False) == 0 matches = miller.match_multi_indices( miller_indices_unique=self.miller_set.indices(), miller_indices=observations.indices()) use_weights = False # New facility for getting variance-weighted correlation if self.params.scaling.algorithm in ['mark1', 'levmar']: # Because no correlation is computed, the correlation # coefficient is fixed at zero. Setting slope = 1 means # intensities are added without applying a scale factor. sum_x = 0 sum_y = 0 for pair in matches.pairs(): data.n_obs += 1 if not self.params.include_negatives and observations.data()[ pair[1]] <= 0: data.n_rejected += 1 else: sum_y += observations.data()[pair[1]] N = data.n_obs - data.n_rejected # Early return if there are no positive reflections on the frame. if data.n_obs <= data.n_rejected: return null_data(file_name=file_name, log_out=out.getvalue(), low_signal=True) # Update the count for each matched reflection. This counts # reflections with non-positive intensities, too. data.completeness += matches.number_of_matches(0).as_int() data.wavelength = wavelength if not self.params.scaling.enable: # Do not scale anything print( "Scale factor to an isomorphous reference PDB will NOT be applied." ) slope = 1.0 offset = 0.0 observations_original_index_indices = observations_original_index.indices( ) if db_mgr is None: return unpack(MINI.x) # special exit for two-color indexing kwargs = { 'wavelength': wavelength, 'beam_x': result['xbeam'], 'beam_y': result['ybeam'], 'distance': result['distance'], 'unique_file_name': data.file_name } ORI = result["current_orientation"][0] Astar = matrix.sqr(ORI.reciprocal_matrix()) kwargs['res_ori_1'] = Astar[0] kwargs['res_ori_2'] = Astar[1] kwargs['res_ori_3'] = Astar[2] kwargs['res_ori_4'] = Astar[3] kwargs['res_ori_5'] = Astar[4] kwargs['res_ori_6'] = Astar[5] kwargs['res_ori_7'] = Astar[6] kwargs['res_ori_8'] = Astar[7] kwargs['res_ori_9'] = Astar[8] assert self.params.scaling.report_ML is True kwargs['half_mosaicity_deg'] = result["ML_half_mosaicity_deg"][0] kwargs['domain_size_ang'] = result["ML_domain_size_ang"][0] frame_id_0_base = db_mgr.insert_frame(**kwargs) xypred = result["mapped_predictions"][0] indices = flex.size_t([pair[1] for pair in matches.pairs()]) sel_observations = flex.intersection(size=observations.data().size(), iselections=[indices]) set_original_hkl = observations_original_index_indices.select( flex.intersection(size=observations_original_index_indices.size(), iselections=[indices])) set_xypred = xypred.select( flex.intersection(size=xypred.size(), iselections=[indices])) kwargs = { 'hkl_id_0_base': [pair[0] for pair in matches.pairs()], 'i': observations.data().select(sel_observations), 'sigi': observations.sigmas().select(sel_observations), 'detector_x': [xy[0] for xy in set_xypred], 'detector_y': [xy[1] for xy in set_xypred], 'frame_id_0_base': [frame_id_0_base] * len(matches.pairs()), 'overload_flag': [0] * len(matches.pairs()), 'original_h': [hkl[0] for hkl in set_original_hkl], 'original_k': [hkl[1] for hkl in set_original_hkl], 'original_l': [hkl[2] for hkl in set_original_hkl] } db_mgr.insert_observation(**kwargs) print("Lattice: %d reflections" % (data.n_obs - data.n_rejected), file=out) print("average obs", sum_y / (data.n_obs - data.n_rejected), \ "average calc", sum_x / (data.n_obs - data.n_rejected), file=out) print("Rejected %d reflections with negative intensities" % \ data.n_rejected, file=out) data.accept = True for pair in matches.pairs(): if not self.params.include_negatives and ( observations.data()[pair[1]] <= 0): continue Intensity = observations.data()[pair[1]] # Super-rare exception. If saved sigmas instead of I/sigmas in the ISIGI dict, this wouldn't be needed. if Intensity == 0: continue # Add the reflection as a two-tuple of intensity and I/sig(I) # to the dictionary of observations. index = self.miller_set.indices()[pair[0]] isigi = (Intensity, observations.data()[pair[1]] / observations.sigmas()[pair[1]], 1.0) if index in data.ISIGI: data.ISIGI[index].append(isigi) else: data.ISIGI[index] = [isigi] sigma = observations.sigmas()[pair[1]] variance = sigma * sigma data.summed_N[pair[0]] += 1 data.summed_wt_I[pair[0]] += Intensity / variance data.summed_weight[pair[0]] += 1 / variance data.set_log_out(out.getvalue()) return data
def run_sim2smv(ROI, prefix, crystal, spectra, rotation, rank, tophat_spectrum=True, quick=False): smv_fileout = prefix + ".img" direct_algo_res_limit = 1.7 wavlen, flux, wavelength_A = next( spectra) # list of lambdas, list of fluxes, average wavelength if tophat_spectrum: sum_flux = flex.sum(flux) #from IPython import embed; embed() ave_flux = sum_flux / 60. # 60 energy channels for ix in range(len(wavlen)): energy = 12398.425 / wavlen[ix] if energy >= 7090 and energy <= 7150: flux[ix] = ave_flux else: flux[ix] = 0. if quick: wavlen = flex.double([wavelength_A]) flux = flex.double([flex.sum(flux)]) print("Quick sim, lambda=%f, flux=%f" % (wavelength_A, flux[0])) #from matplotlib import pyplot as plt #plt.plot(flux,"r-") #plt.title(smv_fileout) #plt.show() GF = gen_fmodel(resolution=direct_algo_res_limit, pdb_text=pdb_lines, algorithm="fft", wavelength=wavelength_A) GF.set_k_sol(0.435) GF.make_P1_primitive() sfall_main = GF.get_amplitudes() # use crystal structure to initialize Fhkl array sfall_main.show_summary(prefix="Amplitudes used ") N = crystal.number_of_cells(sfall_main.unit_cell()) #SIM = nanoBragg(detpixels_slowfast=(2000,2000),pixel_size_mm=0.11,Ncells_abc=(5,5,5),verbose=0) SIM = nanoBragg( detpixels_slowfast=(3000, 3000), pixel_size_mm=0.11, Ncells_abc=(N, N, N), # workaround for problem with wavelength array, specify it separately in constructor. wavelength_A=wavelength_A, verbose=0) SIM.adc_offset_adu = 0 # Do not offset by 40 SIM.adc_offset_adu = 10 # Do not offset by 40 import sys if len(sys.argv) > 2: SIM.seed = -int(sys.argv[2]) print("GOTHERE seed=", SIM.seed) if len(sys.argv) > 1: if sys.argv[1] == "random": SIM.randomize_orientation() SIM.mosaic_domains = 50 # 77 seconds. With 100 energy points, 7700 seconds (2 hours) per image # 3000000 images would be 100000 hours on a 60-core machine (dials), or 11.4 years # using 2 nodes, 5.7 years. Do this at SLAC? NERSC? combination of all? # SLAC downtimes: Tues Dec 5 (24 hrs), Mon Dec 11 (72 hrs), Mon Dec 18 light use, 24 days SIM.mosaic_spread_deg = 0.05 # interpreted by UMAT_nm as a half-width stddev SIM.distance_mm = 141.7 UMAT_nm = flex.mat3_double() mersenne_twister = flex.mersenne_twister(seed=0) scitbx.random.set_random_seed(1234) rand_norm = scitbx.random.normal_distribution(mean=0, sigma=SIM.mosaic_spread_deg * math.pi / 180.) g = scitbx.random.variate(rand_norm) mosaic_rotation = g(SIM.mosaic_domains) for m in mosaic_rotation: site = col(mersenne_twister.random_double_point_on_sphere()) UMAT_nm.append(site.axis_and_angle_as_r3_rotation_matrix(m, deg=False)) SIM.set_mosaic_blocks(UMAT_nm) #SIM.detector_thick_mm = 0.5 # = 0 for Rayonix #SIM.detector_thicksteps = 1 # should default to 1 for Rayonix, but set to 5 for CSPAD #SIM.detector_attenuation_length_mm = default is silicon # get same noise each time this test is run SIM.seed = 1 SIM.oversample = 1 SIM.wavelength_A = wavelength_A SIM.polarization = 1 # this will become F000, marking the beam center SIM.default_F = 0 #SIM.missets_deg= (10,20,30) print("mosaic_seed=", SIM.mosaic_seed) print("seed=", SIM.seed) print("calib_seed=", SIM.calib_seed) print("missets_deg =", SIM.missets_deg) SIM.Fhkl = sfall_main print("Determinant", rotation.determinant()) Amatrix_rot = ( rotation * sqr(sfall_main.unit_cell().orthogonalization_matrix())).transpose() print("RAND_ORI", prefix, end=' ') for i in Amatrix_rot: print(i, end=' ') print() SIM.Amatrix_RUB = Amatrix_rot #workaround for failing init_cell, use custom written Amatrix setter print("unit_cell_Adeg=", SIM.unit_cell_Adeg) print("unit_cell_tuple=", SIM.unit_cell_tuple) Amat = sqr(SIM.Amatrix).transpose() # recovered Amatrix from SIM from cctbx import crystal_orientation Ori = crystal_orientation.crystal_orientation( Amat, crystal_orientation.basis_type.reciprocal) print("Python unit cell from SIM state", Ori.unit_cell()) # fastest option, least realistic #SIM.xtal_shape=shapetype.Tophat # RLP = hard sphere #SIM.xtal_shape=shapetype.Square # gives fringes SIM.xtal_shape = shapetype.Gauss # both crystal & RLP are Gaussian #SIM.xtal_shape=shapetype.Round # Crystal is a hard sphere # only really useful for long runs SIM.progress_meter = False # prints out value of one pixel only. will not render full image! #SIM.printout_pixel_fastslow=(500,500) #SIM.printout=True SIM.show_params() # flux is always in photons/s SIM.flux = 1e12 SIM.exposure_s = 1.0 # so total fluence is e12 # assumes round beam SIM.beamsize_mm = 0.003 #cannot make this 3 microns; spots are too intense temp = SIM.Ncells_abc print("Ncells_abc=", SIM.Ncells_abc) SIM.Ncells_abc = temp print("Ncells_abc=", SIM.Ncells_abc) print("xtal_size_mm=", SIM.xtal_size_mm) print("unit_cell_Adeg=", SIM.unit_cell_Adeg) print("unit_cell_tuple=", SIM.unit_cell_tuple) print("missets_deg=", SIM.missets_deg) print("Amatrix=", SIM.Amatrix) print("beam_center_mm=", SIM.beam_center_mm) print("XDS_ORGXY=", SIM.XDS_ORGXY) print("detector_pivot=", SIM.detector_pivot) print("xtal_shape=", SIM.xtal_shape) print("beamcenter_convention=", SIM.beamcenter_convention) print("fdet_vector=", SIM.fdet_vector) print("sdet_vector=", SIM.sdet_vector) print("odet_vector=", SIM.odet_vector) print("beam_vector=", SIM.beam_vector) print("polar_vector=", SIM.polar_vector) print("spindle_axis=", SIM.spindle_axis) print("twotheta_axis=", SIM.twotheta_axis) print("distance_meters=", SIM.distance_meters) print("distance_mm=", SIM.distance_mm) print("close_distance_mm=", SIM.close_distance_mm) print("detector_twotheta_deg=", SIM.detector_twotheta_deg) print("detsize_fastslow_mm=", SIM.detsize_fastslow_mm) print("detpixels_fastslow=", SIM.detpixels_fastslow) print("detector_rot_deg=", SIM.detector_rot_deg) print("curved_detector=", SIM.curved_detector) print("pixel_size_mm=", SIM.pixel_size_mm) print("point_pixel=", SIM.point_pixel) print("polarization=", SIM.polarization) print("nopolar=", SIM.nopolar) print("oversample=", SIM.oversample) print("region_of_interest=", SIM.region_of_interest) print("wavelength_A=", SIM.wavelength_A) print("energy_eV=", SIM.energy_eV) print("fluence=", SIM.fluence) print("flux=", SIM.flux) print("exposure_s=", SIM.exposure_s) print("beamsize_mm=", SIM.beamsize_mm) print("dispersion_pct=", SIM.dispersion_pct) print("dispsteps=", SIM.dispsteps) print("divergence_hv_mrad=", SIM.divergence_hv_mrad) print("divsteps_hv=", SIM.divsteps_hv) print("divstep_hv_mrad=", SIM.divstep_hv_mrad) print("round_div=", SIM.round_div) print("phi_deg=", SIM.phi_deg) print("osc_deg=", SIM.osc_deg) print("phisteps=", SIM.phisteps) print("phistep_deg=", SIM.phistep_deg) print("detector_thick_mm=", SIM.detector_thick_mm) print("detector_thicksteps=", SIM.detector_thicksteps) print("detector_thickstep_mm=", SIM.detector_thickstep_mm) print("***mosaic_spread_deg=", SIM.mosaic_spread_deg) print("***mosaic_domains=", SIM.mosaic_domains) print("indices=", SIM.indices) print("amplitudes=", SIM.amplitudes) print("Fhkl_tuple=", SIM.Fhkl_tuple) print("default_F=", SIM.default_F) print("interpolate=", SIM.interpolate) print("integral_form=", SIM.integral_form) from libtbx.development.timers import Profiler P = Profiler("nanoBragg") # now actually burn up some CPU #SIM.add_nanoBragg_spots() del P # simulated crystal is only 125 unit cells (25 nm wide) # amplify spot signal to simulate physical crystal of 4000x larger: 100 um (64e9 x the volume) print(crystal.domains_per_crystal) SIM.raw_pixels *= crystal.domains_per_crystal # must calculate the correct scale! output = StringIO() # open("myfile","w") make_response_plot = response_plot(False, title=prefix) for x in range(0, 100, 2): #len(flux)): if flux[x] == 0.0: continue print("+++++++++++++++++++++++++++++++++++++++ Wavelength", x) CH = channel_pixels(ROI, wavlen[x], flux[x], N, UMAT_nm, Amatrix_rot, GF, output) incremental_signal = CH.raw_pixels * crystal.domains_per_crystal if x in [26, 40, 54, 68]: # subsample 7096, 7110, 7124, 7138 eV print("----------------------> subsample", x) make_response_plot.incr_subsample(x, ROI, incremental_signal) make_response_plot.increment(x, ROI, incremental_signal) SIM.raw_pixels += incremental_signal CH.free_all() message = output.getvalue().split() miller = (int(message[4]), int(message[5]), int(message[6])) intensity = float(message[9]) #SIM.to_smv_format(fileout=prefix + "_intimage_001.img") pixels = SIM.raw_pixels roi_pixels = pixels[ROI[1][0]:ROI[1][1], ROI[0][0]:ROI[0][1]] print("Reducing full shape of", pixels.focus(), "to ROI of", roi_pixels.focus()) SIM.free_all() make_response_plot.plot(roi_pixels, miller) return dict(roi_pixels=roi_pixels, miller=miller, intensity=intensity)
def __init__(self, ub_beg, ub_end, axis, s0, dmin, margin=3): warnings.warn( "reeke_model is deprecated, use " "dials.algorithms.spot_prediction import ReekeIndexGenerator instead", DeprecationWarning, stacklevel=2, ) # the source vector and wavelength self._source = -s0 self._wavelength = 1 / math.sqrt(s0.dot(s0)) self._wavelength_sq = self._wavelength**2 # the rotation axis self._axis = axis # the resolution limit self._dstarmax = 1 / dmin self._dstarmax2 = self._dstarmax**2 # Margin by which to expand limits. Mosflm uses 3. self._margin = int(margin) # Determine the permutation order of columns of the setting matrix. Use # the setting from the beginning for this. # As a side-effect set self._permutation. col1, col2, col3 = self._permute_axes(ub_beg) # Thus set the reciprocal lattice axis vectors, in permuted order # p, q and r for both orientations rl_vec = [ ub_beg.extract_block(start=(0, 0), stop=(3, 1)), ub_beg.extract_block(start=(0, 1), stop=(3, 2)), ub_beg.extract_block(start=(0, 2), stop=(3, 3)), ] self._rlv_beg = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] rl_vec = [ ub_end.extract_block(start=(0, 0), stop=(3, 1)), ub_end.extract_block(start=(0, 1), stop=(3, 2)), ub_end.extract_block(start=(0, 2), stop=(3, 3)), ] self._rlv_end = [rl_vec[col1], rl_vec[col2], rl_vec[col3]] # Set permuted setting matrices self._p_beg = matrix.sqr(self._rlv_beg[0].elems + self._rlv_beg[1].elems + self._rlv_beg[2].elems).transpose() self._p_end = matrix.sqr(self._rlv_end[0].elems + self._rlv_end[1].elems + self._rlv_end[2].elems).transpose() ## Define a new coordinate system concentric with the Ewald sphere. ## ## X' = X - source_x ## Y' = Y - source_y ## Z' = Z - source_z ## ## X = P' h' ## - = - ## / p11 p12 p13 -source_X \ ## where h' = (p, q, r, 1)^T and P' = | p21 p22 p23 -source_y | ## - = \ p31 p32 p33 -source_z / ## # Calculate P' matrices for the beginning and end settings pp_beg = matrix.rec( self._p_beg.elems[0:3] + (-1.0 * self._source[0], ) + self._p_beg.elems[3:6] + (-1.0 * self._source[1], ) + self._p_beg.elems[6:9] + (-1.0 * self._source[2], ), n=(3, 4), ) pp_end = matrix.rec( self._p_end.elems[0:3] + (-1.0 * self._source[0], ) + self._p_end.elems[3:6] + (-1.0 * self._source[1], ) + self._p_end.elems[6:9] + (-1.0 * self._source[2], ), n=(3, 4), ) # Various quantities of interest are obtained from the reciprocal metric # tensor T of P'. These quantities are to be used (later) for solving # the intersection of a line of constant p, q index with the Ewald # sphere. It is efficient to calculate these before the outer loop. So, # calculate T for both beginning and end settings t_beg = (pp_beg.transpose() * pp_beg).as_list_of_lists() t_end = (pp_end.transpose() * pp_end).as_list_of_lists() # quantities that are constant with p, beginning orientation self._cp_beg = [ t_beg[2][2], t_beg[2][3]**2, t_beg[0][2] * t_beg[2][3] - t_beg[0][3] * t_beg[2][2], t_beg[0][2]**2 - t_beg[0][0] * t_beg[2][2], t_beg[1][2] * t_beg[2][3] - t_beg[1][3] * t_beg[2][2], t_beg[0][2] * t_beg[1][2] - t_beg[0][1] * t_beg[2][2], t_beg[1][2]**2 - t_beg[1][1] * t_beg[2][2], 2.0 * t_beg[0][2], 2.0 * t_beg[1][2], t_beg[0][0], t_beg[1][1], 2.0 * t_beg[0][1], 2.0 * t_beg[2][3], 2.0 * t_beg[1][3], 2.0 * t_beg[0][3], ] # quantities that are constant with p, end orientation self._cp_end = [ t_end[2][2], t_end[2][3]**2, t_end[0][2] * t_end[2][3] - t_end[0][3] * t_end[2][2], t_end[0][2]**2 - t_end[0][0] * t_end[2][2], t_end[1][2] * t_end[2][3] - t_end[1][3] * t_end[2][2], t_end[0][2] * t_end[1][2] - t_end[0][1] * t_end[2][2], t_end[1][2]**2 - t_end[1][1] * t_end[2][2], 2.0 * t_end[0][2], 2.0 * t_end[1][2], t_end[0][0], t_end[1][1], 2.0 * t_end[0][1], 2.0 * t_end[2][3], 2.0 * t_end[1][3], 2.0 * t_end[0][3], ] ## The following are set during the generation of indices # planes of constant p tangential to the Ewald sphere self._ewald_p_lim_beg = None self._ewald_p_lim_end = None # planes of constant p touching the circle of intersection between the # Ewald and resolution limiting spheres self._res_p_lim_beg = None self._res_p_lim_end = None # looping p limits self._p_lim = None
def test_scan_varying(raypredictor): from dials.algorithms.spot_prediction import ScanVaryingRayPredictor from dials.algorithms.spot_prediction import ReekeIndexGenerator from scitbx import matrix import scitbx.math s0 = raypredictor.beam.get_s0() m2 = raypredictor.gonio.get_rotation_axis() UB = raypredictor.ub_matrix dphi = raypredictor.scan.get_oscillation_range(deg=False) # For quick comparison look at reflections on one frame only frame = 0 angle_beg = raypredictor.scan.get_angle_from_array_index(frame, deg=False) angle_end = raypredictor.scan.get_angle_from_array_index(frame + 1, deg=False) frame0_refs = raypredictor.reflections.select( (raypredictor.reflections["phi"] >= angle_beg) & (raypredictor.reflections["phi"] <= angle_end)) # Get UB matrices at beginning and end of frame r_osc_beg = matrix.sqr( scitbx.math.r3_rotation_axis_and_angle_as_matrix(axis=m2, angle=angle_beg, deg=False)) UB_beg = r_osc_beg * raypredictor.ub_matrix r_osc_end = matrix.sqr( scitbx.math.r3_rotation_axis_and_angle_as_matrix(axis=m2, angle=angle_end, deg=False)) UB_end = r_osc_end * raypredictor.ub_matrix # Get indices r = ReekeIndexGenerator( UB_beg, UB_end, raypredictor.space_group_type, m2, s0, raypredictor.d_min, margin=1, ) h = r.to_array() # Fn to loop through hkl applying a prediction function to each and testing # the results are the same as those from the ScanStaticRayPredictor def test_each_hkl(hkl_list, predict_fn): DEG2RAD = math.pi / 180.0 count = 0 for hkl in hkl_list: ray = predict_fn(hkl) if ray is not None: count += 1 ref = frame0_refs.select(frame0_refs["miller_index"] == hkl)[0] assert ref["entering"] == ray.entering assert ref["phi"] == pytest.approx( ray.angle * DEG2RAD, abs=1e-6) # ray angle is in degrees (!) assert ref["s1"] == pytest.approx(ray.s1, abs=1e-6) # ensure all reflections were matched assert count == len(frame0_refs) # Create the ray predictor sv_predict_rays = ScanVaryingRayPredictor( s0, m2, raypredictor.scan.get_array_range()[0], raypredictor.scan.get_oscillation(), raypredictor.d_min, ) # Test with the method that allows only differing UB matrices test_each_hkl(h, lambda x: sv_predict_rays(x, UB_beg, UB_end, frame)) # Now repeat prediction using the overload that allows for different s0 # at the beginning and end of the frame. Here, pass in the same s0 each time # and the result should be the same as before test_each_hkl(h, lambda x: sv_predict_rays(x, UB_beg, UB_end, s0, s0, frame))
def _export_experiment(filename, integrated_data, experiment, params, var_model=(1, 0)): # type: (str, flex.reflection_table, dxtbx.model.Experiment, libtbx.phil.scope_extract, Tuple) """Export a single experiment to an XDS_ASCII.HKL format file. Args: filename: The file to write to integrated_data: The reflection table, pre-selected to one experiment experiment: The experiment list entry to export params: The PHIL configuration object var_model: """ # export for xds_ascii should only be for non-scaled reflections assert any(i in integrated_data for i in ["intensity.sum.value", "intensity.prf.value"]) # Handle requesting profile intensities (default via auto) but no column if "profile" in params.intensity and "intensity.prf.value" not in integrated_data: raise Sorry( "Requested profile intensity data but only summed present. Use intensity=sum." ) integrated_data = filter_reflection_table( integrated_data, intensity_choice=params.intensity, partiality_threshold=params.mtz.partiality_threshold, combine_partials=params.mtz.combine_partials, min_isigi=params.mtz.min_isigi, filter_ice_rings=params.mtz.filter_ice_rings, d_min=params.mtz.d_min, ) # calculate the scl = lp/dqe correction for outputting but don't apply it as # it has already been applied in filter_reflection_table ( integrated_data, scl, ) = FilteringReductionMethods.calculate_lp_qe_correction_and_filter( integrated_data) # sort data before output nref = len(integrated_data["miller_index"]) indices = flex.size_t_range(nref) unique = copy.deepcopy(integrated_data["miller_index"]) map_to_asu(experiment.crystal.get_space_group().type(), False, unique) perm = sorted(indices, key=lambda k: unique[k]) integrated_data = integrated_data.select(flex.size_t(perm)) if experiment.goniometer is None: print( "Warning: No goniometer. Experimentally exporting with (1 0 0) axis" ) unit_cell = experiment.crystal.get_unit_cell() if experiment.scan is None: print( "Warning: No Scan. Experimentally exporting no-oscillation values") image_range = (1, 1) phi_start, phi_range = 0.0, 0.0 else: image_range = experiment.scan.get_image_range() phi_start, phi_range = experiment.scan.get_image_oscillation( image_range[0]) # gather the required information for the reflection file nref = len(integrated_data["miller_index"]) miller_index = integrated_data["miller_index"] # profile correlation if "profile.correlation" in integrated_data: prof_corr = 100.0 * integrated_data["profile.correlation"] else: prof_corr = flex.double(nref, 100.0) # partiality if "partiality" in integrated_data: partiality = 100 * integrated_data["partiality"] else: prof_corr = flex.double(nref, 100.0) if "intensity.sum.value" in integrated_data: I = integrated_data["intensity.sum.value"] V = integrated_data["intensity.sum.variance"] assert V.all_gt(0) V = var_model[0] * (V + var_model[1] * I * I) sigI = flex.sqrt(V) else: I = integrated_data["intensity.prf.value"] V = integrated_data["intensity.prf.variance"] assert V.all_gt(0) V = var_model[0] * (V + var_model[1] * I * I) sigI = flex.sqrt(V) fout = open(filename, "w") # first write the header - in the "standard" coordinate frame... panel = experiment.detector[0] fast = panel.get_fast_axis() slow = panel.get_slow_axis() Rd = align_reference_frame(fast, (1, 0, 0), slow, (0, 1, 0)) print("Coordinate change:") print("%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n%5.2f %5.2f %5.2f\n" % Rd.elems) fast = Rd * fast slow = Rd * slow qx, qy = panel.get_pixel_size() nx, ny = panel.get_image_size() distance = matrix.col(Rd * panel.get_origin()).dot( matrix.col(Rd * panel.get_normal())) org = Rd * (matrix.col(panel.get_origin()) - distance * matrix.col(panel.get_normal())) orgx = -org.dot(fast) / qx orgy = -org.dot(slow) / qy UB = Rd * matrix.sqr(experiment.crystal.get_A()) real_space_ABC = UB.inverse().elems if experiment.goniometer is not None: axis = Rd * experiment.goniometer.get_rotation_axis() else: axis = Rd * (1, 0, 0) beam = Rd * experiment.beam.get_s0() cell_fmt = "%9.3f %9.3f %9.3f %7.3f %7.3f %7.3f" axis_fmt = "%9.3f %9.3f %9.3f" fout.write("\n".join([ "!FORMAT=XDS_ASCII MERGE=FALSE FRIEDEL'S_LAW=TRUE", "!Generated by dials.export", "!DATA_RANGE= %d %d" % image_range, "!ROTATION_AXIS= %9.6f %9.6f %9.6f" % axis.elems, "!OSCILLATION_RANGE= %f" % phi_range, "!STARTING_ANGLE= %f" % phi_start, "!STARTING_FRAME= %d" % image_range[0], "!SPACE_GROUP_NUMBER= %d" % experiment.crystal.get_space_group().type().number(), "!UNIT_CELL_CONSTANTS= %s" % (cell_fmt % unit_cell.parameters()), "!UNIT_CELL_A-AXIS= %s" % (axis_fmt % real_space_ABC[0:3]), "!UNIT_CELL_B-AXIS= %s" % (axis_fmt % real_space_ABC[3:6]), "!UNIT_CELL_C-AXIS= %s" % (axis_fmt % real_space_ABC[6:9]), "!X-RAY_WAVELENGTH= %f" % experiment.beam.get_wavelength(), "!INCIDENT_BEAM_DIRECTION= %f %f %f" % beam.elems, "!NX= %d NY= %d QX= %f QY= %f" % (nx, ny, qx, qy), "!ORGX= %9.2f ORGY= %9.2f" % (orgx, orgy), "!DETECTOR_DISTANCE= %8.3f" % distance, "!DIRECTION_OF_DETECTOR_X-AXIS= %9.5f %9.5f %9.5f" % fast.elems, "!DIRECTION_OF_DETECTOR_Y-AXIS= %9.5f %9.5f %9.5f" % slow.elems, "!VARIANCE_MODEL= %7.3e %7.3e" % var_model, "!NUMBER_OF_ITEMS_IN_EACH_DATA_RECORD=12", "!ITEM_H=1", "!ITEM_K=2", "!ITEM_L=3", "!ITEM_IOBS=4", "!ITEM_SIGMA(IOBS)=5", "!ITEM_XD=6", "!ITEM_YD=7", "!ITEM_ZD=8", "!ITEM_RLP=9", "!ITEM_PEAK=10", "!ITEM_CORR=11", "!ITEM_PSI=12", "!END_OF_HEADER", "", ])) # then write the data records s0 = Rd * matrix.col(experiment.beam.get_s0()) for j in range(nref): x, y, z = integrated_data["xyzcal.px"][j] phi = phi_start + z * phi_range h, k, l = miller_index[j] X = (UB * (h, k, l)).rotate(axis, phi, deg=True) s = s0 + X g = s.cross(s0).normalize() # find component of beam perpendicular to f, e e = -(s + s0).normalize() if h == k and k == l: u = (h, -h, 0) else: u = (k - l, l - h, h - k) q = ((matrix.col(u).transpose() * UB.inverse()).normalize().transpose().rotate(axis, phi, deg=True)) psi = q.angle(g, deg=True) if q.dot(e) < 0: psi *= -1 fout.write("%d %d %d %f %f %f %f %f %f %.1f %.1f %f\n" % ( h, k, l, I[j], sigI[j], x, y, z, scl[j], partiality[j], prof_corr[j], psi, )) fout.write("!END_OF_DATA\n") fout.close() logger.info("Output %d reflections to %s" % (nref, filename))