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
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
class _BaseTest(): def setup_method(self): self.mock_ubcalc = createMockUbcalc(None) self.mock_geometry = createMockDiffractometerGeometry() names = ['delta', NUNAME, 'mu', 'eta', 'chi', 'phi'] self.mock_hardware = SimpleHardwareAdapter(names) self.constraints = YouConstraintManager(self.mock_hardware) self.calc = YouHklCalculator(self.mock_ubcalc, self.mock_geometry, self.mock_hardware, self.constraints) self.mock_hardware.set_lower_limit('delta', 0) self.mock_hardware.set_upper_limit('delta', 179.999) self.mock_hardware.set_lower_limit('mu', 0) self.mock_hardware.set_lower_limit('eta', 0) self.mock_hardware.set_lower_limit('chi', -10) self.places = 11 def _configure_ub(self): ZROT = z_rotation(self.zrot * TORAD) # -PHI YROT = y_rotation(self.yrot * TORAD) # +CHI U = ZROT * YROT UB = U * self.B self.mock_ubcalc.UB = UB def _check_hkl_to_angles(self, testname, zrot, yrot, hkl, pos_expected, wavelength, virtual_expected={}): print ('_check_hkl_to_angles(%s, %.1f, %.1f, %s, %s, %.2f, %s)' % (testname, zrot, yrot, hkl, pos_expected, wavelength, virtual_expected)) self.zrot, self.yrot = zrot, yrot self._configure_ub() pos, virtual = self.calc.hklToAngles(hkl[0], hkl[1], hkl[2], wavelength) assert_array_almost_equal(pos.totuple(), pos_expected.totuple(), self.places) assert_second_dict_almost_in_first(virtual, virtual_expected) def _check_angles_to_hkl(self, testname, zrot, yrot, hkl_expected, pos, wavelength, virtual_expected={}): print ('_check_angles_to_hkl(%s, %.1f, %.1f, %s, %s, %.2f, %s)' % (testname, zrot, yrot, hkl_expected, pos, wavelength, virtual_expected)) self.zrot, self.yrot = zrot, yrot self._configure_ub() hkl, virtual = self.calc.anglesToHkl(pos, wavelength) assert_array_almost_equal(hkl, hkl_expected, self.places, note="***Test (not diffcalc!) incorrect*** : the desired settings do not map to the target hkl") assert_second_dict_almost_in_first(virtual, virtual_expected) @raises(DiffcalcException) def _check_hkl_to_angles_fails(self, *args): self._check_hkl_to_angles(*args) def case_generator(self): for case in self.cases: yield (self._check_angles_to_hkl, case.name, self.zrot, self.yrot, case.hkl, case.position, self.wavelength, {}) test_method = (self._check_hkl_to_angles_fails if case.fails else self._check_hkl_to_angles) yield (test_method, case.name, self.zrot, self.yrot, case.hkl, case.position, self.wavelength, {})
class _BaseTest(): def setup_method(self): self.mock_ubcalc = createMockUbcalc(None) self.mock_geometry = createMockDiffractometerGeometry() names = ['delta', NUNAME, 'mu', 'eta', 'chi', 'phi'] self.mock_hardware = SimpleHardwareAdapter(names) self.constraints = YouConstraintManager(self.mock_hardware) self.calc = YouHklCalculator(self.mock_ubcalc, self.mock_geometry, self.mock_hardware, self.constraints) self.mock_hardware.set_lower_limit('delta', 0) self.mock_hardware.set_upper_limit('delta', 179.999) self.mock_hardware.set_lower_limit(NUNAME, 0) self.mock_hardware.set_upper_limit(NUNAME, 179.999) self.mock_hardware.set_lower_limit('mu', 0) self.mock_hardware.set_lower_limit('eta', 0) self.mock_hardware.set_lower_limit('chi', -10) self.places = 11 def _configure_ub(self): ZROT = z_rotation(self.zrot * TORAD) # -PHI YROT = y_rotation(self.yrot * TORAD) # +CHI U = ZROT * YROT UB = U * self.B self.mock_ubcalc.UB = UB def _check_hkl_to_angles(self, testname, zrot, yrot, hkl, pos_expected, wavelength, virtual_expected={}): print('_check_hkl_to_angles(%s, %.1f, %.1f, %s, %s, %.2f, %s)' % (testname, zrot, yrot, hkl, pos_expected, wavelength, virtual_expected)) self.zrot, self.yrot = zrot, yrot self._configure_ub() pos, virtual = self.calc.hklToAngles(hkl[0], hkl[1], hkl[2], wavelength) assert_array_almost_equal(pos.totuple(), pos_expected.totuple(), self.places) assert_second_dict_almost_in_first(virtual, virtual_expected) def _check_angles_to_hkl(self, testname, zrot, yrot, hkl_expected, pos, wavelength, virtual_expected={}): print('_check_angles_to_hkl(%s, %.1f, %.1f, %s, %s, %.2f, %s)' % (testname, zrot, yrot, hkl_expected, pos, wavelength, virtual_expected)) self.zrot, self.yrot = zrot, yrot self._configure_ub() hkl, virtual = self.calc.anglesToHkl(pos, wavelength) assert_array_almost_equal( hkl, hkl_expected, self.places, note= "***Test (not diffcalc!) incorrect*** : the desired settings do not map to the target hkl" ) assert_second_dict_almost_in_first(virtual, virtual_expected) @raises(DiffcalcException) def _check_hkl_to_angles_fails(self, *args): self._check_hkl_to_angles(*args) def case_generator(self): for case in self.cases: yield (self._check_angles_to_hkl, case.name, self.zrot, self.yrot, case.hkl, case.position, self.wavelength, {}) test_method = (self._check_hkl_to_angles_fails if case.fails else self._check_hkl_to_angles) yield (test_method, case.name, self.zrot, self.yrot, case.hkl, case.position, self.wavelength, {})