Example #1
0
  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
Example #2
0
  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)
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #7
0
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
Example #9
0
 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]])
Example #10
0
  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
Example #12
0
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
Example #13
0
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
Example #14
0
 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
Example #15
0
    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
Example #16
0
  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
Example #17
0
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
Example #18
0
  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])
Example #19
0
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)
Example #22
0
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
Example #23
0
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
Example #24
0
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)
Example #25
0
 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
Example #26
0
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)
Example #29
0
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)
Example #30
0
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")
Example #34
0
    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)
Example #35
0
 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())
Example #36
0
  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
Example #38
0
    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)
Example #42
0
    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()
Example #45
0
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
Example #46
0
    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)
Example #47
0
                                                      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,
Example #48
0
 def mark_rotation(self):
     self.marked_rotation = matrix.sqr(
         gltbx.util.extract_rotation_from_gl_modelview_matrix())
Example #49
0
    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)
Example #50
0
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
Example #51
0
  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
Example #52
0
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)
Example #53
0
    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)
Example #54
0
    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)
Example #56
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
Example #57
0
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)
Example #58
0
    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
Example #59
0
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))
Example #60
0
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))