def _test_random_axes_and_angles(): # random axes e1, e2, e3 = [random_vector() for i in range(3)] # random angles phi1 = random.uniform(-math.pi, math.pi) phi2 = random.uniform(-math.pi, math.pi) phi3 = random.uniform(-math.pi, math.pi) # compose rotation matrix R1 = e1.axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = e2.axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = e3.axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1 * R2 * R3 # obtain solution sets sol1 = solve_r3_rotation_for_angles_given_axes(R, e1, e2, e3, True) sol2 = solve_r3_rotation_for_angles_given_axes(R, e1, e2, e3, False) # if either one of the solution sets is not found, indicate that this test # was skipped if sol1 is None or sol2 is None: return "skipped" # there are special solutions where rotations 1 and 3 are about the same axis. # solve_r3_rotation_for_angles_given_axes provides solutions where phi1 is # 0.0 and the rotation is fully expressed by phi3. Skip these degenerate # cases too. if sol1[0] == 0.0 and sol2[0] == 0.0: return "skipped" # one of sol1 or sol2 should match tst = (phi1, phi2, phi3) assert approx_equal(sol1, tst, out=None) or approx_equal(sol2, tst, out=None)
def _test_vs_euler_angles_xyz_angles(phi1, phi2, phi3): from scitbx.math import euler_angles_xyz_angles # compose rotation matrix R1 = matrix.col((1, 0, 0)).axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = matrix.col((0, 1, 0)).axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = matrix.col((0, 0, 1)).axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1 * R2 * R3 # get two solution sets for the principal axes sol1 = solve_r3_rotation_for_angles_given_axes(R, (1, 0, 0), (0, 1, 0), (0, 0, 1), smaller_phi2_solution=False, deg=True) sol2 = solve_r3_rotation_for_angles_given_axes(R, (1, 0, 0), (0, 1, 0), (0, 0, 1), smaller_phi2_solution=True, deg=True) # get the solution set provided by euler_angles_xyz_angles tst = euler_angles_xyz_angles(R) # one of these must match assert approx_equal(sol1, tst, out=None) or approx_equal( sol2, tst, out=None)
def test_rotation_matrices(phi1, phi2, phi3): # compose rotation matrix R1 = matrix.col((1, 0, 0)).axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = matrix.col((0, 1, 0)).axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = matrix.col((0, 0, 1)).axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1 * R2 * R3 # obtain the solutions sol1 = solve_r3_rotation_for_angles_given_axes(R, (1, 0, 0), (0, 1, 0), (0, 0, 1), smaller_phi2_solution=False) sol2 = solve_r3_rotation_for_angles_given_axes(R, (1, 0, 0), (0, 1, 0), (0, 0, 1), smaller_phi2_solution=True) # recompose these into rotation matrices tstR1 = matrix.col( (1, 0, 0)).axis_and_angle_as_r3_rotation_matrix(sol1[0], deg=False) tstR1 *= matrix.col( (0, 1, 0)).axis_and_angle_as_r3_rotation_matrix(sol1[1], deg=False) tstR1 *= matrix.col( (0, 0, 1)).axis_and_angle_as_r3_rotation_matrix(sol1[2], deg=False) tstR2 = matrix.col( (1, 0, 0)).axis_and_angle_as_r3_rotation_matrix(sol2[0], deg=False) tstR2 *= matrix.col( (0, 1, 0)).axis_and_angle_as_r3_rotation_matrix(sol2[1], deg=False) tstR2 *= matrix.col( (0, 0, 1)).axis_and_angle_as_r3_rotation_matrix(sol2[2], deg=False) # the two solution sets must reproduce the same rotation matrix assert approx_equal(tstR1, tstR2) # additionally, this matrix must be equal to the original matrix assert approx_equal(tstR1, R) # check rotated vectors #vec = R * matrix.col((0,0,1)) #tstvec1 = tstR1 * matrix.col((0,0,1)) #tstvec2 = tstR2 * matrix.col((0,0,1)) #print R #print tstR1 #print tstR2 #print vec #print tstvec1 #print tstvec2 return
def test_rotation_matrices(phi1, phi2, phi3): # compose rotation matrix R1 = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = matrix.col((0,0,1)).axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1*R2*R3 # obtain the solutions sol1 = solve_r3_rotation_for_angles_given_axes(R, (1,0,0), (0,1,0), (0,0,1), smaller_phi2_solution=False) sol2 = solve_r3_rotation_for_angles_given_axes(R, (1,0,0), (0,1,0), (0,0,1), smaller_phi2_solution=True) # recompose these into rotation matrices tstR1 = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(sol1[0], deg=False) tstR1 *= matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(sol1[1], deg=False) tstR1 *= matrix.col((0,0,1)).axis_and_angle_as_r3_rotation_matrix(sol1[2], deg=False) tstR2 = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(sol2[0], deg=False) tstR2 *= matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(sol2[1], deg=False) tstR2 *= matrix.col((0,0,1)).axis_and_angle_as_r3_rotation_matrix(sol2[2], deg=False) # the two solution sets must reproduce the same rotation matrix assert approx_equal(tstR1, tstR2) # additionally, this matrix must be equal to the original matrix assert approx_equal(tstR1, R) # check rotated vectors #vec = R * matrix.col((0,0,1)) #tstvec1 = tstR1 * matrix.col((0,0,1)) #tstvec2 = tstR2 * matrix.col((0,0,1)) #print R #print tstR1 #print tstR2 #print vec #print tstvec1 #print tstvec2 return
def test_vs_euler_angles_xyz_angles(phi1, phi2, phi3): from scitbx.math import euler_angles_xyz_angles # compose rotation matrix R1 = matrix.col((1,0,0)).axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = matrix.col((0,1,0)).axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = matrix.col((0,0,1)).axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1*R2*R3 # get two solution sets for the principal axes sol1 = solve_r3_rotation_for_angles_given_axes(R, (1,0,0), (0,1,0), (0,0,1), smaller_phi2_solution=False, deg=True) sol2 = solve_r3_rotation_for_angles_given_axes(R, (1,0,0), (0,1,0), (0,0,1), smaller_phi2_solution=True, deg=True) # get the solution set provided by euler_angles_xyz_angles tst = euler_angles_xyz_angles(R) # one of these must match assert any([approx_equal(sol1, tst, out=None), approx_equal(sol2, tst, out=None)]) return
def test_random_axes_and_angles(): # random axes e1, e2, e3 = [random_vector() for i in range(3)] # random angles phi1 = random.uniform(-math.pi, math.pi) phi2 = random.uniform(-math.pi, math.pi) phi3 = random.uniform(-math.pi, math.pi) # compose rotation matrix R1 = e1.axis_and_angle_as_r3_rotation_matrix(phi1, deg=False) R2 = e2.axis_and_angle_as_r3_rotation_matrix(phi2, deg=False) R3 = e3.axis_and_angle_as_r3_rotation_matrix(phi3, deg=False) R = R1*R2*R3 # obtain solution sets sol1 = solve_r3_rotation_for_angles_given_axes(R, e1, e2, e3, True) sol2 = solve_r3_rotation_for_angles_given_axes(R, e1, e2, e3, False) # if either one of the solution sets is not found, indicate that this test # was skipped if sol1 is None or sol2 is None: return "skipped" # there are special solutions where rotations 1 and 3 are about the same axis. # solve_r3_rotation_for_angles_given_axes provides solutions where phi1 is # 0.0 and the rotation is fully expressed by phi3. Skip these degenerate # cases too. if sol1[0] == 0.0 and sol2[0] == 0.0: return "skipped" # one of sol1 or sol2 should match tst = (phi1, phi2, phi3) assert any([approx_equal(sol1, tst, out=None), approx_equal(sol2, tst, out=None)]) return
def __init__(self, experiment, vectors, frame="reciprocal", mode="main"): from dials.util import Sorry self.experiment = experiment self.vectors = vectors self.frame = frame self.mode = mode gonio = experiment.goniometer 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 = [] # 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: result_dictionary = collections.OrderedDict() results.append((v1_, v2_, result_dictionary)) space_group = self.experiment.crystal.get_space_group() for smx in list(space_group.smx())[:]: result_dictionary[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 result_dictionary[smx].extend(solutions) self.all_solutions = results self.unique_solutions = collections.OrderedDict() for v1, v2, result in results: for solutions in result.values(): for solution in solutions: k = tuple(round(a, 3) for a in solution[1:]) self.unique_solutions.setdefault(k, []) if all(v1 != z1 or v2 != z2 for z1, z2 in self.unique_solutions[k]): self.unique_solutions[k].append((v1, v2))
def run(self, args=None): params, options = self.parser.parse_args(args, show_diff_phil=True) log.config(logfile="dials.complete_full_sphere.log") model_shadow = params.shadow experiments = flatten_experiments(params.input.experiments) if len(experiments) != 1: self.parser.print_help() return expt = experiments[0] axes = expt.goniometer.get_axes() if len(axes) != 3: sys.exit("This will only work with 3-axis goniometers") if not expt.imageset.reader().get_format(): sys.exit("This will only work with images available") if not expt.imageset.reader().get_format().get_goniometer_shadow_masker(): model_shadow = False beam = expt.beam det = expt.detector if params.resolution: resolution = params.resolution else: resolution = det.get_max_inscribed_resolution(expt.beam.get_s0()) # at this point, predict all of the reflections in the scan possible (i.e. # extend scan to 360 degrees) - this points back to expt self.make_scan_360(expt.scan) # now get a full set of all unique miller indices all_indices = miller.build_set( crystal_symmetry=crystal.symmetry( space_group=expt.crystal.get_space_group(), unit_cell=expt.crystal.get_unit_cell(), ), anomalous_flag=True, d_min=resolution, ) if model_shadow: obs, shadow = self.predict_to_miller_set_with_shadow(expt, resolution) else: obs = self.predict_to_miller_set(expt, resolution) logger.info( "Fraction of unique observations at datum: %.1f%%", 100.0 * len(obs.indices()) / len(all_indices.indices()), ) missing = all_indices.lone_set(other=obs) logger.info("%d unique reflections in blind region", len(missing.indices())) e1 = matrix.col(axes[0]) e2 = matrix.col(axes[1]) e3 = matrix.col(axes[2]) s0n = matrix.col(beam.get_s0()).normalize() # rotate blind region about beam by +/- two theta two_theta = 2.0 * math.asin(0.5 * beam.get_wavelength() / resolution) R_ptt = s0n.axis_and_angle_as_r3_rotation_matrix(two_theta) R_ntt = s0n.axis_and_angle_as_r3_rotation_matrix(-two_theta) # now decompose to e3, e2, e1 sol_plus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R_ptt, e3, e2, e1, return_both_solutions=True, deg=True ) sol_minus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R_ntt, e3, e2, e1, return_both_solutions=True, deg=True ) solutions = [] if sol_plus: solutions.extend(sol_plus) if sol_minus: solutions.extend(sol_minus) if not solutions: sys.exit(f"Impossible two theta: {two_theta * 180.0 / math.pi:.3f},") logger.info("Maximum two theta: %.3f,", two_theta * 180.0 / math.pi) logger.info("%d solutions found", len(solutions)) names = tuple( [n.replace("GON_", "").lower() for n in expt.goniometer.get_names()] ) logger.info(" %8s %8s %8s coverage expt.expt" % names) self.write_expt(experiments, "solution_0.expt") for j, s in enumerate(solutions): expt.goniometer.set_angles(s) if model_shadow: obs, shadow = self.predict_to_miller_set_with_shadow(expt, resolution) else: obs = self.predict_to_miller_set(expt, resolution) new = missing.common_set(obs) fout = "solution_%d.expt" % (j + 1) f = len(new.indices()) / len(missing.indices()) logger.info("%8.3f %8.3f %8.3f %4.2f %s", s[0], s[1], s[2], f, fout) self.write_expt(experiments, fout)
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 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 = {} for (v1_, v2_) in self.vectors: results[(v1_, v2_)] = {} crystal = copy.deepcopy(self.experiment.crystal) for smx in list(crystal.get_space_group().smx())[:]: 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 = crystal.get_U() # XXX In DIALS recorded U is equivalent to U0 - D is applied to U inside # prediction U0 = U B = 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(s0) l2 = self.rotation_axis else: l1 = self.rotation_axis.normalize() l3 = l1.cross(self.s0).normalize() l2 = l1.cross(l3) from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame R = align_reference_frame(v1_0, l1, v2_0, 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] = solutions self.all_solutions = results self.unique_solutions = {} for (v1, v2), result in results.iteritems(): for solutions in result.itervalues(): for solution in solutions: k = tuple(round(a, 2) for a in solution[1:]) self.unique_solutions.setdefault(k, set()) self.unique_solutions[k].add((v1, v2))
scan.set_exposure_times(exposure_times) write_expt(expts, sys.argv[2]) # now for amusement try decomposing rotation of 90 degrees about beam to # measure blind region - computer says no if mini kappa :( e1 = matrix.col((1, 0, 0)) e2 = matrix.col((0.914, 0.279, -0.297)) e3 = matrix.col((1, 0, 0)) R = matrix.sqr((0, 1, 0, -1, 0, 0, 0, 0, 1)) from dials.algorithms.refinement import rotation_decomposition solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R, e1, e2, e3, return_both_solutions=True, deg=True) assert solutions is None # now try getting a rotation of two-theta about the beam - this should (i) # be possible? and (ii) move the blind region into somewhere we can actually # record... R_tt = s0n.axis_and_angle_as_r3_rotation_matrix(2 * theta) s = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R_tt, e1, e2, e3, return_both_solutions=False, deg=False) # use solution print("Using angles: %.3f %.3f" % (180 * s[1] / math.pi, 180 * s[2] / math.pi))
def run(args): from dials.util.options import OptionParser from dials.util.options import flatten_experiments import libtbx.load_env usage = "%s [options] datablock.json" %( libtbx.env.dispatcher_name) parser = OptionParser( usage=usage, phil=phil_scope, read_experiments=True, check_format=False, epilog=help_message) params, options = parser.parse_args(show_diff_phil=True) experiments = flatten_experiments(params.input.experiments) if len(experiments) == 0: parser.print_help() exit(0) imagesets = experiments.imagesets() predicted_all = None dose = flex.size_t() for i_expt, expt in enumerate(experiments): if params.space_group is not None: expt.crystal.set_space_group(params.space_group.group()) strategy = Strategy(expt, d_min=params.d_min, unit_cell_scale=params.unit_cell_scale, degrees_per_bin=params.degrees_per_bin, min_frac_new=params.minimum_fraction_new) strategy.plot(prefix='strategy1_') expt2 = copy.deepcopy(expt) scan = expt2.scan gonio = expt2.goniometer angles = gonio.get_angles() theta_max = strategy.theta_max 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( scan.get_oscillation()[0], deg=True) D_p = (setting_rotation * rotation_matrix * fixed_rotation) beam = expt2.beam s0 = matrix.col(beam.get_unit_s0()) # rotate crystal by at least 2 * theta_max around axis perpendicular to # goniometer rotation axis n = rotation_axis.cross(s0) solutions = flex.vec3_double() rotation_angles = flex.double() for sign in (1, -1): i = 0 while True: rot_angle = 2 * sign * (theta_max + i) i += 1 R = n.axis_and_angle_as_r3_rotation_matrix(rot_angle, deg=True) axes = gonio.get_axes() assert len(axes) == 3 e1, e2, e3 = (matrix.col(e) for e in reversed(axes)) from dials.algorithms.refinement import rotation_decomposition solns = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R * D_p, e1, e2, e3, return_both_solutions=True, deg=True) if solns is not None: solutions.extend(flex.vec3_double(solns)) for i in range(len(solns)): rotation_angles.append(rot_angle) break for rot_angle, solution in zip(rotation_angles, solutions): angles = reversed(solution) gonio.set_angles(angles) print() print("Goniometer settings to rotate crystal by %.2f degrees:" %rot_angle) for name, angle in zip(gonio.get_names(), gonio.get_angles()): print("%s: %.2f degrees" %(name, angle)) print() strategy2 = Strategy(expt2, d_min=params.d_min, unit_cell_scale=params.unit_cell_scale, degrees_per_bin=params.degrees_per_bin, min_frac_new=params.minimum_fraction_new) strategy2.plot(prefix='strategy2_') stats = ComputeStats([strategy, strategy2]) stats.show() plot_statistics(stats, prefix='multi_strategy_') return
def run(self): """Run the script.""" from dials.util.options import flatten_experiments params, options = self.parser.parse_args() if len(params.input.experiments) == 0: self.parser.print_help() raise Sorry("No experiments found in the input") experiments = flatten_experiments(params.input.experiments) # Determine output path self._directory = os.path.join(params.output.directory, "scan-varying_crystal") 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 = 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} if self._debug: print "Crystal in Experiment {0}".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) 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 = range(crystal.num_scan_points) phi = [scan.get_angle_from_array_index(t) for t in scan_pts] Umats = [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 = 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 {0}".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) self.plot_orientation(dat)
e1 = matrix.col((1, 0, 0)) e2 = matrix.col((0.6691306063588582, 0.7431448254773942, 0)) e3 = matrix.col((1, 0, 0)) z = matrix.col((0, 0, 1)) from dials.algorithms.refinement import rotation_decomposition import math a = math.pi / 3 Rplus = z.axis_and_angle_as_r3_rotation_matrix(a) Rminus = z.axis_and_angle_as_r3_rotation_matrix(-a) Splus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( Rplus, e1, e2, e3, return_both_solutions=True, deg=True ) Sminus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( Rminus, e1, e2, e3, return_both_solutions=True, deg=True ) s = Splus[0] F = e2.axis_and_angle_as_r3_rotation_matrix( s[1] ) * e3.axis_and_angle_as_r3_rotation_matrix(s[2]) gonio.set_fixed_rotation(F.elems) gonio.set_angles(s) write_expt(expts, sys.argv[2])
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 write_dyn_cif_pets(self): self._set_virtual_frames() cif_filename = self.filename_prefix + ".cif_pets" cell_params = self.experiment.crystal.get_unit_cell().parameters() volume = self.experiment.crystal.get_unit_cell().volume() wavelength = self.experiment.beam.get_wavelength() UBmatrix = matrix.sqr(self.experiment.crystal.get_A()).as_numpy_array() # tilt semi-angle of the virtual frame precession_angle = (self.experiment.scan.get_oscillation()[1] * self.n_merged) / 2 # Some of these values are left as dummy zeroes for DIALS comment = f"""; data collection geometry: continuous rotation dstarmax: 0.000 RC width: 0.00000 mosaicity: 0.000 rotation axis position: 000.000 reflection size: 0.000 Virtual frame settings: number of merged frames: {self.n_merged} step between frames: {self.step} sum all intensities: 1 ;""" uvws = [] for frame_id, virtual_frame in enumerate(self.virtual_frames): u, v, w = virtual_frame["zone_axis"] R = virtual_frame["rotated_misset"] # Decompose U = Rω * Rα * Rβ, where: # α is around 1,0,0 # β is around 0,1,0 # ω is around 0,0,1 omega, alpha, beta = solve_r3_rotation_for_angles_given_axes( R, (0, 0, 1), (1, 0, 0), (0, 1, 0), deg=True) scale = 1 # dummy value uvws += [[ frame_id + 1, u, v, w, precession_angle, alpha, beta, omega, scale ]] ref_list = [] for frame_id, virtual_frame in enumerate(self.virtual_frames): refs = virtual_frame["reflections"] refs["intensity.sigma"] = flex.sqrt( refs[self.intensity_variance_column]) for r in refs.rows(): h, k, l = r["miller_index"] i = r[self.intensity_column] sig_i = r["intensity.sigma"] ref_list.append([h, k, l, i, sig_i, frame_id + 1]) self._write_dyn_cif_pets( cif_filename, cell_params, volume, wavelength, UBmatrix, uvws, ref_list, comment, )
def run(args): from dials.util.options import OptionParser from dials.util.options import flatten_experiments import libtbx.load_env usage = "%s [options] datablock.json" %( libtbx.env.dispatcher_name) parser = OptionParser( usage=usage, phil=phil_scope, read_experiments=True, check_format=False, epilog=help_message) params, options = parser.parse_args(show_diff_phil=True) experiments = flatten_experiments(params.input.experiments) if len(experiments) == 0: parser.print_help() exit(0) imagesets = experiments.imagesets() predicted_all = None dose = flex.size_t() for i_expt, expt in enumerate(experiments): if params.space_group is not None: expt.crystal.set_space_group(params.space_group.group()) strategy = Strategy(expt, d_min=params.d_min, unit_cell_scale=params.unit_cell_scale, degrees_per_bin=params.degrees_per_bin, min_frac_new=params.minimum_fraction_new) strategy.plot(prefix='strategy1_') expt2 = copy.deepcopy(expt) scan = expt2.scan gonio = expt2.goniometer angles = gonio.get_angles() theta_max = strategy.theta_max 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( scan.get_oscillation()[0], deg=True) D_p = (setting_rotation * rotation_matrix * fixed_rotation) beam = expt2.beam s0 = matrix.col(beam.get_unit_s0()) # rotate crystal by at least 2 * theta_max around axis perpendicular to # goniometer rotation axis n = rotation_axis.cross(s0) i = 0 while True: for sign in (1, -1): rot_angle = 2 * theta_max + i i += 1 R = n.axis_and_angle_as_r3_rotation_matrix(rot_angle, deg=True) axes = gonio.get_axes() assert len(axes) == 3 e1, e2, e3 = (matrix.col(e) for e in axes) from dials.algorithms.refinement import rotation_decomposition solutions = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R * D_p, e1, e2, e3, return_both_solutions=True, deg=True) if solutions is not None: break if solutions is not None: break angles = solutions[0] gonio.set_angles(angles) print print "Goniometer settings to rotate crystal by %.2f degrees:" %rot_angle, print "(%.2f, %.2f, %.2f)" %angles print strategy2 = Strategy(expt2, d_min=params.d_min, unit_cell_scale=params.unit_cell_scale, degrees_per_bin=params.degrees_per_bin, min_frac_new=params.minimum_fraction_new) strategy2.plot(prefix='strategy2_') stats = ComputeStats([strategy, strategy2]) stats.show() plot_statistics(stats, prefix='multi_strategy_') return
def run(self): params, options = self.parser.parse_args(show_diff_phil=True) from dials.util import log log.config(info="dials.complete_full_sphere.log", debug="dials.complete_full_sphere.debug.log") import math from scitbx import matrix from dials.algorithms.refinement import rotation_decomposition from dials.util.options import flatten_experiments from dials.array_family import flex model_shadow = params.shadow experiments = flatten_experiments(params.input.experiments) if len(experiments) != 1: self.parser.print_help() return expt = experiments[0] axes = expt.goniometer.get_axes() if len(axes) != 3: from libtbx.utils import Sorry raise Sorry("This will only work with 3-axis goniometers") if not expt.imageset.reader().get_format(): from libtbx.utils import Sorry raise Sorry("This will only work with images available") if not expt.imageset.reader().get_format( ).get_goniometer_shadow_masker(): model_shadow = False beam = expt.beam det = expt.detector if params.resolution: resolution = params.resolution else: resolution = det.get_max_inscribed_resolution(expt.beam.get_s0()) # at this point, predict all of the reflections in the scan possible (i.e. # extend scan to 360 degrees) - this points back to expt scan = self.make_scan_360(expt.scan) # now get a full set of all unique miller indices from cctbx import miller from cctbx import crystal all = miller.build_set(crystal_symmetry=crystal.symmetry( space_group=expt.crystal.get_space_group(), unit_cell=expt.crystal.get_unit_cell()), anomalous_flag=True, d_min=resolution) if model_shadow: obs, shadow = self.predict_to_miller_set_with_shadow( expt, resolution) else: obs = self.predict_to_miller_set(expt, resolution) logger.info('Fraction of unique observations at datum: %.1f%%' % (100. * len(obs.indices()) / len(all.indices()))) missing = all.lone_set(other=obs) logger.info('%d unique reflections in blind region' % len(missing.indices())) e1 = matrix.col(axes[0]) e2 = matrix.col(axes[1]) e3 = matrix.col(axes[2]) s0n = matrix.col(beam.get_s0()).normalize() # rotate blind region about beam by +/- two theta two_theta = 2.0 * math.asin(0.5 * beam.get_wavelength() / resolution) R_ptt = s0n.axis_and_angle_as_r3_rotation_matrix(two_theta) R_ntt = s0n.axis_and_angle_as_r3_rotation_matrix(-two_theta) # now decompose to e3, e2, e1 sol_plus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R_ptt, e3, e2, e1, return_both_solutions=True, deg=True) sol_minus = rotation_decomposition.solve_r3_rotation_for_angles_given_axes( R_ntt, e3, e2, e1, return_both_solutions=True, deg=True) solutions = [] if sol_plus: solutions.extend(sol_plus) if sol_minus: solutions.extend(sol_minus) if not solutions: from libtbx.utils import Sorry raise Sorry('Impossible two theta: %.3f,' % (two_theta * 180.0 / math.pi)) logger.info('Maximum two theta: %.3f,' % (two_theta * 180.0 / math.pi)) logger.info('%d solutions found' % len(solutions)) names = tuple([n.replace('GON_', '').lower() for n in \ expt.goniometer.get_names()]) logger.info(' %8s %8s %8s coverage expt.json' % names) self.write_expt(experiments, 'solution_0.json') for j, s in enumerate(solutions): expt.goniometer.set_angles(s) if model_shadow: obs, shadow = self.predict_to_miller_set_with_shadow( expt, resolution) else: obs = self.predict_to_miller_set(expt, resolution) new = missing.common_set(obs) fout = 'solution_%d.json' % (j + 1) f = len(new.indices()) / len(missing.indices()) logger.info('%8.3f %8.3f %8.3f %4.2f %s' % (s[0], s[1], s[2], f, fout)) self.write_expt(experiments, fout)