Пример #1
0
def test_beam_parameters():
    from scitbx import matrix

    from dxtbx.model import BeamFactory
    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation,
    )
    from dials.algorithms.refinement.refinement_helpers import (
        get_fd_gradients,
        random_param_shift,
    )

    # make a random beam vector and parameterise it
    bf = BeamFactory()
    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 matrix.col(s0.get_s0()).angle(s0_old) == pytest.approx(0.1413033, abs=1e-6)
    assert matrix.col(s0.get_s0()).length() == pytest.approx(0.8, abs=1e-6)

    # random initial orientations and wavelengths with a random parameter shifts
    attempts = 1000
    failures = 0
    for i in range(attempts):

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

        # apply a random parameter shift
        p_vals = s0p.get_param_vals()
        p_vals = random_param_shift(p_vals, [1000 * pi / 9, 1000 * pi / 9, 0.01])
        s0p.set_param_vals(p_vals)

        # compare analytical and finite difference derivatives
        an_ds_dp = s0p.get_ds_dp()
        fd_ds_dp = get_fd_gradients(s0p, [1.0e-5 * pi / 180, 1.0e-5 * pi / 180, 1.0e-6])

        for j in range(3):
            try:
                assert list(fd_ds_dp[j] - an_ds_dp[j]) == pytest.approx(
                    (0, 0, 0), abs=1e-6
                )
            except Exception:
                print("for try", i)
                print("failure for parameter number", j)
                print("with fd_ds_dp = ")
                print(fd_ds_dp[j])
                print("and an_ds_dp = ")
                print(an_ds_dp[j])
                print("so that difference fd_ds_dp - an_ds_dp =")
                print(fd_ds_dp[j] - an_ds_dp[j])
                raise
Пример #2
0
  attempts = 1000
  failures = 0
  for i in range(attempts):

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

    # apply a random parameter shift
    p_vals = s0p.get_param_vals()
    p_vals = random_param_shift(p_vals, [1000*pi/9, 1000*pi/9, 0.01])
    s0p.set_param_vals(p_vals)

    # compare analytical and finite difference derivatives
    an_ds_dp = s0p.get_ds_dp()
    fd_ds_dp = get_fd_gradients(s0p, [1.e-5 * pi/180, 1.e-5 * pi/180, 1.e-6])

    for j in range(3):
      try:
        assert(approx_equal((fd_ds_dp[j] - an_ds_dp[j]),
                matrix.col((0., 0., 0.)), eps = 1.e-6))
      except Exception:
        failures += 1
        print "for try", i
        print "failure for parameter number", j
        print "with fd_ds_dp = "
        print fd_ds_dp[j]
        print "and an_ds_dp = "
        print an_ds_dp[j]
        print "so that difference fd_ds_dp - an_ds_dp ="
Пример #3
0
def test_beam_parameters():
    from dxtbx.model import BeamFactory

    from dials.algorithms.refinement.parameterisation.beam_parameters import (
        BeamParameterisation,
    )
    from dials.algorithms.refinement.refinement_helpers import (
        get_fd_gradients,
        random_param_shift,
    )

    # make a random beam vector and parameterise it
    bf = BeamFactory()
    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 matrix.col(s0.get_s0()).angle(s0_old) == pytest.approx(0.1413033, abs=1e-6)
    assert matrix.col(s0.get_s0()).length() == pytest.approx(0.8, abs=1e-6)

    # random initial orientations and wavelengths with a random parameter shifts
    attempts = 1000
    for i in range(attempts):

        # make a random beam vector and parameterise it
        sample_to_source = matrix.col.random(3, 0.5, 1.5).normalize()
        beam = bf.make_beam(sample_to_source, wavelength=random.uniform(0.8, 1.5))
        # Ensure consistent polarization (https://github.com/cctbx/dxtbx/issues/454)
        beam.set_polarization_normal(sample_to_source.ortho().normalize())

        s0p = BeamParameterisation(beam)

        # apply a random parameter shift
        p_vals = s0p.get_param_vals()
        p_vals = random_param_shift(p_vals, [1000 * pi / 9, 1000 * pi / 9, 0.01])
        s0p.set_param_vals(p_vals)

        # compare analytical and finite difference derivatives
        an_ds_dp = s0p.get_ds_dp()
        fd_ds_dp = get_fd_gradients(s0p, [1.0e-5 * pi / 180, 1.0e-5 * pi / 180, 1.0e-6])

        for j in range(3):
            try:
                assert list(fd_ds_dp[j] - an_ds_dp[j]) == pytest.approx(
                    (0, 0, 0), abs=1e-6
                )
            except Exception:
                print("for try", i)
                print("failure for parameter number", j)
                print("with fd_ds_dp = ")
                print(fd_ds_dp[j])
                print("and an_ds_dp = ")
                print(an_ds_dp[j])
                print("so that difference fd_ds_dp - an_ds_dp =")
                print(fd_ds_dp[j] - an_ds_dp[j])
                raise

        # Ensure the polarization normal vector remains orthogonal to the beam
        # (https://github.com/dials/dials/issues/1939)
        assert (
            abs(
                matrix.col(beam.get_unit_s0()).dot(
                    matrix.col(beam.get_polarization_normal())
                )
            )
            < 1e-10
        )
Пример #4
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 :-)"
Пример #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 :-)")