class TestSolutionGenerator():
    def setup(self):

        names = ['delta', NUNAME, 'mu', 'eta', 'chi', 'phi']
        self.hardware = SimpleHardwareAdapter(names)
        self.calc = YouHklCalculator(createMockUbcalc(None),
                                     createMockDiffractometerGeometry(),
                                     self.hardware,
                                     Mock())

    # constraint could have been 'delta', NUNAME, 'qaz' or 'naz'.

    def test_generate_possible_det_soln_no_limits_constrained_qaz_or_naz(self):
        # we will enfoce the order too, incase this later effects heuristically
        # made choices
        expected = (
                    (.1, .2),
                    (.1, -.2),
                    (.1, .2 - pi),
                    (.1, pi - .2),
                    (-.1, .2),
                    (-.1, -.2),
                    (-.1, .2 - pi),
                    (-.1, pi - .2),
                    (.1 - pi, .2),  # pi + x cuts to x-pi
                    (.1 - pi, -.2),
                    (.1 - pi, .2 - pi),
                    (.1 - pi, pi - .2),
                    (pi - .1, .2),
                    (pi - .1, -.2),
                    (pi - .1, .2 - pi),
                    (pi - .1, pi - .2),
                   )

        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (.1, .2), ('delta', NUNAME), ('naz',)))
        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (.1, .2), ('delta', NUNAME), ('qaz',)))

    def test_generate_poss_det_soln_no_lim_cons_qaz_or_naz_delta_and_nu_at_zro(self):  # @IgnorePep8
        # we will enfoce the order too, incase this later effects hearistically
        # made choices
        expected = (
                    (0., 0,),
                    (0., pi),
                    (pi, 0.),
                    (pi, pi)
                    )

        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (-2e-9, 2e-9), ('delta', NUNAME), ('naz',)))
        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (-2e-9, 2e-9), ('delta', NUNAME), ('qaz',)))

    def test_generate_possible_det_solutions_no_limits_constrained_delta(self):
        expected = (
                    (.1, .2),
                    (.1, -.2),
                    (.1, .2 - pi),
                    (.1, pi - .2),
                   )

        assert_2darray_almost_equal(expected,
                self.calc._generate_possible_solutions(
                    (.1, .2), ('delta', NUNAME), ('delta',)))

    def test_generate_possible_det_solutions_no_limits_constrained_nu(self):
        expected = (
                    (.1, .2),
                    (-.1, .2),
                    (.1 - pi, .2),
                    (pi - .1, .2),
                   )

        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (.1, .2), ('delta', NUNAME), (NUNAME,)))

    def test_generate_possible_det_soln_with_limits_constrained_delta(self):
        self.hardware.set_lower_limit(NUNAME, 0)
        expected = (
                    (.1, .2),
                    (.1, pi - .2),
                   )

        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (.1, .2), ('delta', NUNAME), ('delta',)))

    def test_generate_possible_det_solutions_with_limits_constrained_nu(self):
        self.hardware.set_upper_limit('delta', 0)
        expected = (
                    (-.1, .2),
                    (.1 - pi, .2),  # cuts to .1-pi
                   )

        assert_2darray_almost_equal(expected,
            self.calc._generate_possible_solutions(
                (.1, .2), ('delta', NUNAME), (NUNAME,)))

    def test_generate_poss_det_soln_with_limits_overly_constrained_nu(self):
        self.hardware.set_lower_limit('delta', .3)
        self.hardware.set_upper_limit('delta', .31)
        eq_(len(self.calc._generate_possible_solutions(
            (.1, .2), ('delta', NUNAME), (NUNAME,))), 0)

    def test_generate_possible_sample_solutions(self):
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('naz',))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'naz')
        assert_2darray_almost_equal(generated, result)
        eq_(4 ** 4, len(result))

    def test_generate_possible_sample_solutions_fixed_chi(self):
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('chi',))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'chi')
        assert_2darray_almost_equal(generated, result)
        eq_(4 ** 3, len(result))

    def test_generate_possible_sample_solutions_fixed_chi_positive_mu(self):
        self.hardware.set_lower_limit('mu', 0)
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('chi',))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'chi')
        assert_2darray_almost_equal(generated, result)
        eq_(2 * (4 ** 2), len(result))

    def _hardcoded_generate_possible_sample_solutions(self, mu, eta, chi, phi,
                                                      sample_constraint_name):
        possible_solutions = []
        _identity = lambda x: x
        _transforms = (_identity,
                      lambda x: -x,
                      lambda x: pi + x,
                      lambda x: pi - x)
        _transforms_for_zero = (lambda x: 0.,
                               lambda x: pi,)
        SMALL = 1e-8

        def cut_at_minus_pi(value):
            if value < (-pi - SMALL):
                return value + 2 * pi
            if value >= pi + SMALL:
                return value - 2 * pi
            return value

        def is_small(x):
            return abs(x) < SMALL

        name = sample_constraint_name

        for transform in ((_identity,) if name == 'mu' else
                           _transforms if not is_small(mu) else
                           _transforms_for_zero):
            transformed_mu = (transform(mu))
            if not self.hardware.is_axis_value_within_limits('mu',
                    self.hardware.cut_angle('mu', transformed_mu * TODEG)):
                continue
            for transform in ((_identity,) if name == 'eta' else
                               _transforms if not is_small(eta) else
                               _transforms_for_zero):
                transformed_eta = transform(eta)
                if not self.hardware.is_axis_value_within_limits('eta',
                    self.hardware.cut_angle('eta', transformed_eta * TODEG)):
                    continue
                for transform in ((_identity,) if name == 'chi' else
                                   _transforms if not is_small(chi) else
                                   _transforms_for_zero):
                    transformed_chi = transform(chi)
                    if not self.hardware.is_axis_value_within_limits('chi',
                        self.hardware.cut_angle('chi',
                                               transformed_chi * TODEG)):
                        continue
                    for transform in ((_identity,) if name == 'phi' else
                                       _transforms if not is_small(phi) else
                                       _transforms_for_zero):
                        transformed_phi = transform(phi)
                        if not self.hardware.is_axis_value_within_limits('phi',
                            self.hardware.cut_angle('phi',
                                                   transformed_phi * TODEG)):
                            continue
                        possible_solutions.append((
                            cut_at_minus_pi(transformed_mu),
                            cut_at_minus_pi(transformed_eta),
                            cut_at_minus_pi(transformed_chi),
                            cut_at_minus_pi(transformed_phi)))
        return possible_solutions
Exemplo n.º 2
0
class TestSolutionGenerator():
    def setup_method(self):

        names = ['delta', NUNAME, 'mu', 'eta', 'chi', 'phi']
        self.hardware = SimpleHardwareAdapter(names)
        self.calc = YouHklCalculator(createMockUbcalc(None),
                                     createMockDiffractometerGeometry(),
                                     self.hardware, Mock())

    # constraint could have been 'delta', NUNAME, 'qaz' or 'naz'.

    def test_generate_possible_det_soln_no_limits_constrained_qaz_or_naz(self):
        # we will enfoce the order too, incase this later effects heuristically
        # made choices
        expected = (
            (.1, .2),
            (.1, -.2),
            (.1, .2 - pi),
            (.1, pi - .2),
            (-.1, .2),
            (-.1, -.2),
            (-.1, .2 - pi),
            (-.1, pi - .2),
            (.1 - pi, .2),  # pi + x cuts to x-pi
            (.1 - pi, -.2),
            (.1 - pi, .2 - pi),
            (.1 - pi, pi - .2),
            (pi - .1, .2),
            (pi - .1, -.2),
            (pi - .1, .2 - pi),
            (pi - .1, pi - .2),
        )

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   ('naz', )))
        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   ('qaz', )))

    def test_generate_poss_det_soln_no_lim_cons_qaz_or_naz_delta_and_nu_at_zro(
            self):  # @IgnorePep8
        # we will enfoce the order too, incase this later effects hearistically
        # made choices
        expected = ((
            0.,
            0,
        ), (0., pi), (pi, 0.), (pi, pi))

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions(
                (-2e-9, 2e-9), ('delta', NUNAME), ('naz', )))
        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions(
                (-2e-9, 2e-9), ('delta', NUNAME), ('qaz', )))

    def test_generate_possible_det_solutions_no_limits_constrained_delta(self):
        expected = (
            (.1, .2),
            (.1, -.2),
            (.1, .2 - pi),
            (.1, pi - .2),
        )

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   ('delta', )))

    def test_generate_possible_det_solutions_no_limits_constrained_nu(self):
        expected = (
            (.1, .2),
            (-.1, .2),
            (.1 - pi, .2),
            (pi - .1, .2),
        )

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   (NUNAME, )))

    def test_generate_possible_det_soln_with_limits_constrained_delta(self):
        self.hardware.set_lower_limit(NUNAME, 0)
        expected = (
            (.1, .2),
            (.1, pi - .2),
        )

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   ('delta', )))

    def test_generate_possible_det_solutions_with_limits_constrained_nu(self):
        self.hardware.set_upper_limit('delta', 0)
        expected = (
            (-.1, .2),
            (.1 - pi, .2),  # cuts to .1-pi
        )

        assert_2darray_almost_equal(
            expected,
            self.calc._generate_possible_solutions((.1, .2), ('delta', NUNAME),
                                                   (NUNAME, )))

    def test_generate_poss_det_soln_with_limits_overly_constrained_nu(self):
        self.hardware.set_lower_limit('delta', .3)
        self.hardware.set_upper_limit('delta', .31)
        eq_(
            len(
                self.calc._generate_possible_solutions(
                    (.1, .2), ('delta', NUNAME), (NUNAME, ))), 0)

    def test_generate_possible_sample_solutions(self):
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('naz', ))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'naz')
        assert_2darray_almost_equal(generated, result)
        eq_(4**4, len(result))

    def test_generate_possible_sample_solutions_fixed_chi(self):
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('chi', ))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'chi')
        assert_2darray_almost_equal(generated, result)
        eq_(4**3, len(result))

    def test_generate_possible_sample_solutions_fixed_chi_positive_mu(self):
        self.hardware.set_lower_limit('mu', 0)
        result = self.calc._generate_possible_solutions(
            (.1, .2, .3, .4), ('mu', 'eta', 'chi', 'phi'), ('chi', ))
        generated = self._hardcoded_generate_possible_sample_solutions(
            .1, .2, .3, .4, 'chi')
        assert_2darray_almost_equal(generated, result)
        eq_(2 * (4**2), len(result))

    def _hardcoded_generate_possible_sample_solutions(self, mu, eta, chi, phi,
                                                      sample_constraint_name):
        possible_solutions = []
        _identity = lambda x: x
        _transforms = (_identity, lambda x: -x, lambda x: pi + x,
                       lambda x: pi - x)
        _transforms_for_zero = (
            lambda x: 0.,
            lambda x: pi,
        )
        SMALL = 1e-8

        def cut_at_minus_pi(value):
            if value < (-pi - SMALL):
                return value + 2 * pi
            if value >= pi + SMALL:
                return value - 2 * pi
            return value

        def is_small(x):
            return abs(x) < SMALL

        name = sample_constraint_name

        for transform in ((_identity, ) if name == 'mu' else _transforms
                          if not is_small(mu) else _transforms_for_zero):
            transformed_mu = (transform(mu))
            if not self.hardware.is_axis_value_within_limits(
                    'mu', self.hardware.cut_angle('mu',
                                                  transformed_mu * TODEG)):
                continue
            for transform in ((_identity, ) if name == 'eta' else _transforms
                              if not is_small(eta) else _transforms_for_zero):
                transformed_eta = transform(eta)
                if not self.hardware.is_axis_value_within_limits(
                        'eta',
                        self.hardware.cut_angle('eta',
                                                transformed_eta * TODEG)):
                    continue
                for transform in ((_identity, )
                                  if name == 'chi' else _transforms if
                                  not is_small(chi) else _transforms_for_zero):
                    transformed_chi = transform(chi)
                    if not self.hardware.is_axis_value_within_limits(
                            'chi',
                            self.hardware.cut_angle('chi',
                                                    transformed_chi * TODEG)):
                        continue
                    for transform in ((_identity, ) if name == 'phi' else
                                      _transforms if not is_small(phi) else
                                      _transforms_for_zero):
                        transformed_phi = transform(phi)
                        if not self.hardware.is_axis_value_within_limits(
                                'phi',
                                self.hardware.cut_angle(
                                    'phi', transformed_phi * TODEG)):
                            continue
                        possible_solutions.append(
                            (cut_at_minus_pi(transformed_mu),
                             cut_at_minus_pi(transformed_eta),
                             cut_at_minus_pi(transformed_chi),
                             cut_at_minus_pi(transformed_phi)))
        return possible_solutions