from math import pi
import random

from libtbx.test_utils import approx_equal
from scitbx import matrix

from dxtbx.model.experiment import beam_factory
from dials.algorithms.refinement.parameterisation.beam_parameters import \
    BeamParameterisation
from dials.algorithms.refinement.refinement_helpers \
    import get_fd_gradients, random_param_shift

if __name__ == '__main__':

  # make a random beam vector and parameterise it
  bf = beam_factory()
  s0 = bf.make_beam(matrix.col.random(3, 0.5, 1.5), wavelength=1.2)
  s0p = BeamParameterisation(s0)

  # Let's do some basic tests. First, can we change parameter values and
  # update the modelled vector s0?
  s0_old = matrix.col(s0.get_s0())
  s0p.set_param_vals([1000*0.1, 1000*0.1, 0.8])
  assert(approx_equal(matrix.col(s0.get_s0()).angle(s0_old), 0.1413033))
  assert(approx_equal(matrix.col(s0.get_s0()).length(), 0.8))

  # random initial orientations and wavelengths with a random parameter shifts
  attempts = 1000
  failures = 0
  for i in range(attempts):
  # set up a simple detector frame with directions aligned with
  # principal axes and sensor origin located on the z-axis at -110
  d1 = matrix.col((1, 0, 0))
  d2 = matrix.col((0, -1, 0))
  #lim = (0,50)
  npx_fast = 1475
  npx_slow = 1679
  pix_size_f = pix_size_s = 0.172
  detector = detector_factory.make_detector("PAD", d1, d2,
      matrix.col((0, 0, -110)), (pix_size_f, pix_size_s),
      (npx_fast, npx_slow), (0, 2e20))

  dp = DetectorParameterisationSinglePanel(detector)
  beam = beam_factory().make_beam(
          sample_to_source=-1*(matrix.col((0, 0, -110)) + 10 * d1 + 10 * d2),
          wavelength=1.0)

  # Test change of parameters
  # =========================

  # 1. shift detector plane so that the z-axis intercepts its centre
  # at a distance of 100 along the initial normal direction. As the
  # initial normal is along -z, we expect the frame to intercept the
  # z-axis at -100.

  p_vals = dp.get_param_vals()
  p_vals[0:3] = [100., 0., 0.]
  dp.set_param_vals(p_vals)
  detector = dp._model
  assert(len(detector) == 1)
Exemple #3
0
def tst_use_in_stills_parameterisation_for_beam(beam_param=0):

    # test use of analytical expression in stills prediction parameterisation

    from scitbx import matrix
    from math import pi
    import random

    print
    print "Test use of analytical expressions in stills prediction " + "parameterisation for beam parameters"

    # beam model
    from dxtbx.model.experiment import beam_factory
    from dials.algorithms.refinement.parameterisation.beam_parameters import BeamParameterisation

    beam = beam_factory().make_beam(matrix.col((0, 0, 1)), wavelength=1.1)
    s0 = matrix.col(beam.get_s0())
    s0u = matrix.col(beam.get_unit_s0())

    # beam parameterisation
    bp = BeamParameterisation(beam)

    # choose the derivative with respect to a particular parameter. 0: mu1,
    # 1: mu2, 2: nu.
    ds0_dp = bp.get_ds_dp()[beam_param]

    # pick a random point on (the positive octant of) the Ewald sphere to rotate
    s1 = matrix.col((random.random(), random.random(), random.random())).normalize() * s0.length()
    r = s1 - s0
    r0 = r.normalize()

    # calculate the axis of rotation
    e1 = r0.cross(s0u).normalize()

    # calculate c0, a vector orthogonal to s0u and e1
    c0 = s0u.cross(e1).normalize()

    # convert to derivative of the unit beam direction. This involves scaling
    # by the wavelength, then projection back onto the Ewald sphere.
    scaled = ds0_dp * beam.get_wavelength()
    ds0u_dp = scaled.dot(c0) * c0 + scaled.dot(e1) * e1

    # rotate relp off Ewald sphere a small angle (up to 1 deg)
    DeltaPsi = random.uniform(-pi / 180, pi / 180)
    q = r.rotate_around_origin(e1, -DeltaPsi)
    q0 = q.normalize()
    from libtbx.test_utils import approx_equal

    assert approx_equal(q0.cross(s0u).normalize(), e1)

    # use the fact that e1 == c0.cross(s0u) to redefine the derivative d[e1]/dp
    # from Sauter et al. (2014) (A.3)
    de1_dp = c0.cross(ds0u_dp)

    # unlike the previous definition this *is* orthogonal to e1, as expected.
    print "[e1].(d[e1]/dp) = {0} (should be 0.0)".format(e1.dot(de1_dp))

    # calculate (d[r]/d[e1])(d[e1]/dp) analytically
    from scitbx.array_family import flex
    from dials_refinement_helpers_ext import dRq_de

    dr_de1 = matrix.sqr(dRq_de(flex.double([DeltaPsi]), flex.vec3_double([e1]), flex.vec3_double([q]))[0])
    print "Analytical calculation for (d[r]/d[e1])(d[e1]/dp):"
    print dr_de1 * de1_dp

    # now calculate using finite differences.
    dp = 1.0e-8
    del_e1 = de1_dp * dp
    e1f = e1 + del_e1 * 0.5
    rfwd = q.rotate_around_origin(e1f, DeltaPsi)
    e1r = e1 - del_e1 * 0.5
    rrev = q.rotate_around_origin(e1r, DeltaPsi)

    print "Finite difference estimate for (d[r]/d[e1])(d[e1]/dp):"
    print (rfwd - rrev) * (1 / dp)

    print "These are now the same :-)"
Exemple #4
0
    # set up a simple detector frame with directions aligned with
    # principal axes and sensor origin located on the z-axis at -110
    d1 = matrix.col((1, 0, 0))
    d2 = matrix.col((0, -1, 0))
    #lim = (0,50)
    npx_fast = 1475
    npx_slow = 1679
    pix_size_f = pix_size_s = 0.172
    detector = detector_factory.make_detector("PAD", d1, d2,
                                              matrix.col((0, 0, -110)),
                                              (pix_size_f, pix_size_s),
                                              (npx_fast, npx_slow), (0, 2e20))

    dp = DetectorParameterisationSinglePanel(detector)
    beam = beam_factory().make_beam(sample_to_source=-1 * (matrix.col(
        (0, 0, -110)) + 10 * d1 + 10 * d2),
                                    wavelength=1.0)

    # Test change of parameters
    # =========================

    # 1. shift detector plane so that the z-axis intercepts its centre
    # at a distance of 100 along the initial normal direction. As the
    # initial normal is along -z, we expect the frame to intercept the
    # z-axis at -100.

    p_vals = dp.get_param_vals()
    p_vals[0:3] = [100., 0., 0.]
    dp.set_param_vals(p_vals)
    detector = dp._model
    assert (len(detector) == 1)
Exemple #5
0
def tst_use_in_stills_parameterisation_for_beam(beam_param=0):

    # test use of analytical expression in stills prediction parameterisation

    from scitbx import matrix
    from math import pi
    import random

    print()
    print("Test use of analytical expressions in stills prediction " +
          "parameterisation for beam parameters")

    # beam model
    from dxtbx.model.experiment import beam_factory
    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation, )

    beam = beam_factory().make_beam(matrix.col((0, 0, 1)), wavelength=1.1)
    s0 = matrix.col(beam.get_s0())
    s0u = matrix.col(beam.get_unit_s0())

    # beam parameterisation
    bp = BeamParameterisation(beam)

    # choose the derivative with respect to a particular parameter. 0: mu1,
    # 1: mu2, 2: nu.
    ds0_dp = bp.get_ds_dp()[beam_param]

    # pick a random point on (the positive octant of) the Ewald sphere to rotate
    s1 = (matrix.col(
        (random.random(), random.random(), random.random())).normalize() *
          s0.length())
    r = s1 - s0
    r0 = r.normalize()

    # calculate the axis of rotation
    e1 = r0.cross(s0u).normalize()

    # calculate c0, a vector orthogonal to s0u and e1
    c0 = s0u.cross(e1).normalize()

    # convert to derivative of the unit beam direction. This involves scaling
    # by the wavelength, then projection back onto the Ewald sphere.
    scaled = ds0_dp * beam.get_wavelength()
    ds0u_dp = scaled.dot(c0) * c0 + scaled.dot(e1) * e1

    # rotate relp off Ewald sphere a small angle (up to 1 deg)
    DeltaPsi = random.uniform(-pi / 180, pi / 180)
    q = r.rotate_around_origin(e1, -DeltaPsi)
    q0 = q.normalize()
    from libtbx.test_utils import approx_equal

    assert approx_equal(q0.cross(s0u).normalize(), e1)

    # use the fact that e1 == c0.cross(s0u) to redefine the derivative d[e1]/dp
    # from Sauter et al. (2014) (A.3)
    de1_dp = c0.cross(ds0u_dp)

    # unlike the previous definition this *is* orthogonal to e1, as expected.
    print("[e1].(d[e1]/dp) = {0} (should be 0.0)".format(e1.dot(de1_dp)))

    # calculate (d[r]/d[e1])(d[e1]/dp) analytically
    from scitbx.array_family import flex
    from dials_refinement_helpers_ext import dRq_de

    dr_de1 = matrix.sqr(
        dRq_de(flex.double([DeltaPsi]), flex.vec3_double([e1]),
               flex.vec3_double([q]))[0])
    print("Analytical calculation for (d[r]/d[e1])(d[e1]/dp):")
    print(dr_de1 * de1_dp)

    # now calculate using finite differences.
    dp = 1.0e-8
    del_e1 = de1_dp * dp
    e1f = e1 + del_e1 * 0.5
    rfwd = q.rotate_around_origin(e1f, DeltaPsi)
    e1r = e1 - del_e1 * 0.5
    rrev = q.rotate_around_origin(e1r, DeltaPsi)

    print("Finite difference estimate for (d[r]/d[e1])(d[e1]/dp):")
    print((rfwd - rrev) * (1 / dp))

    print("These are now the same :-)")