示例#1
0
    def test_sdba_from_sdata_series(self):
        temperature, sample_form = (102., 'quasicrystal')
        angle_0_sdata = SData(data=self.list_data[0],
                              frequencies=self.frequencies,
                              temperature=temperature,
                              sample_form=sample_form)
        angle_1_sdata = SData(data=self.list_data[1],
                              frequencies=self.frequencies,
                              temperature=temperature,
                              sample_form=sample_form)

        sdba = SDataByAngle.from_sdata_series([angle_0_sdata, angle_1_sdata],
                                              angles=self.angles)

        for input_data, output_data in zip([angle_0_sdata, angle_1_sdata],
                                           sdba):
            self.assertEqual(input_data.get_sample_form(),
                             output_data.get_sample_form())
            self.assertEqual(input_data.get_temperature(),
                             output_data.get_temperature())
        self.assertTrue(
            np.allclose(input_data.get_frequencies(),
                        output_data.get_frequencies()))
        self.assertTrue(
            np.allclose(input_data.extract()['atom_0']['s']['order_1'],
                        output_data.extract()['atom_0']['s']['order_1']))
示例#2
0
    def test_s_data_add_dict(self):
        from copy import deepcopy
        s_data = SData(data=deepcopy(self.sample_data),
                       frequencies=self.frequencies)
        s_data.add_dict({'atom_1': {'s': {'order_1': np.ones(5)}}})

        assert_almost_equal(s_data[1]['order_1'],
                            self.sample_data['atom_1']['s']['order_1'] + 1)
示例#3
0
    def test_s_data(self):
        abins.parameters.sampling['min_wavenumber'] = 100
        abins.parameters.sampling['max_wavenumber'] = 150

        s_data = SData(temperature=10,
                       sample_form='Powder',
                       data=self.sample_data,
                       frequencies=self.frequencies)

        self.assertTrue(
            np.allclose(s_data.extract()['frequencies'], self.frequencies))

        self.assertTrue(
            np.allclose(s_data.extract()['atom_0']['s']['order_1'],
                        self.sample_data['atom_0']['s']['order_1']))
        self.assertTrue(
            np.allclose(s_data.extract()['atom_1']['s']['order_1'],
                        self.sample_data['atom_1']['s']['order_1']))

        with self.assertRaises(AssertionError):
            with self.assertLogs(logger=self.logger, level='WARNING'):
                s_data.check_thresholds(logger=self.logger)

        abins.parameters.sampling['s_absolute_threshold'] = 0.5
        with self.assertLogs(logger=self.logger, level='WARNING'):
            s_data.check_thresholds(logger=self.logger)
示例#4
0
    def _calculate_s_powder_one_atom(self, *, atom_index: int, k_index: int, q2: np.ndarray,
                                     sdata: SData, bins: np.ndarray,
                                     min_order: int = 1) -> None:
        """
        :param atom_index: number of atom
        :param k_index: Index of k-point in phonon data
        :param q2: Array of squared absolute q-point values in angstrom^-2. (Columns correspond to energies.)
        :sdata: Data container to which results will be summed in-place
        :bins: Frequency bins consistent with sdata
        :min_order: Lowest quantum order to evaluate. (The max is determined by self._quantum_order_num.)

        """
        kpoint_weight = self._abins_data.get_kpoints_data()[k_index].weight

        fundamentals = self._powder_data.get_frequencies()[k_index]
        fund_coeff = np.arange(fundamentals.size, dtype=INT_TYPE)

        # Initialise with fundamentals regardless of whether starting with order 1 or 2
        frequencies = np.copy(fundamentals)
        coefficients = np.copy(fund_coeff)

        a_tensor = self._powder_data.get_a_tensors()[k_index][atom_index]
        a_trace = self._powder_data.get_a_traces(k_index)[atom_index]
        b_tensor = self._powder_data.get_b_tensors()[k_index][atom_index]
        b_trace = self._powder_data.get_b_traces(k_index)[atom_index]

        calculate_order = {1: self._calculate_order_one,
                           2: self._calculate_order_two}

        # Chunking to save memory has been removed pending closer examination
        for order in range(min_order, self._quantum_order_num + 1):
            frequencies, coefficients = FrequencyPowderGenerator.construct_freq_combinations(
                previous_array=frequencies,
                previous_coefficients=coefficients,
                fundamentals_array=fundamentals,
                fundamentals_coefficients=fund_coeff,
                quantum_order=order)

            scattering_intensities = calculate_order[order](
                q2=q2, frequencies=frequencies, indices=coefficients,
                a_tensor=a_tensor, a_trace=a_trace, b_tensor=b_tensor, b_trace=b_trace)
            rebinned_spectrum, _ = np.histogram(frequencies, bins=bins,
                                                weights=(scattering_intensities * kpoint_weight),
                                                density=False)
            sdata.add_dict({f'atom_{atom_index}':
                            {'s': {f'order_{order}': rebinned_spectrum}}})

            # Prune modes with low intensity; these are assumed not to contribute to higher orders
            frequencies, coefficients = self._calculate_s_over_threshold(scattering_intensities,
                                                                         freq=frequencies,
                                                                         coeff=coefficients)
示例#5
0
    def test_s_data_autoconvolution(self):
        # Check a trivial case: starting with a single peak,
        # expect evenly-spaced sequence of same intensity
        #
        # _|____ .... -> _|_|_|_|_ ...
        #
        frequencies = np.linspace(0, 10, 50)
        data_o1 = {'atom_0': {'s': {'order_1': np.zeros(50)}}}
        data_o1['atom_0']['s']['order_1'][2] = 1.
        expected_o1 = {
            'atom_0': {
                's': {f'order_{i}': np.zeros(50)
                      for i in range(1, 11)}
            }
        }
        for i in range(1, 11):
            expected_o1['atom_0']['s'][f'order_{i}'][(2 * i)] = 1.

        s_data_o1 = SData(data=data_o1, frequencies=frequencies)
        s_data_o1.add_autoconvolution_spectra()

        expected_s_data = SData(data=expected_o1, frequencies=frequencies)

        for i in range(1, 11):
            assert_almost_equal(s_data_o1[0][f'order_{i}'],
                                expected_s_data[0][f'order_{i}'])

        # Check range restriction works, and beginning with more orders
        #
        # O1 _|____ ... + O2 __|___ ... -> O3 ___|___ ... + O4 ____|__ ...

        data_o2 = {
            'atom_0': {
                's': {
                    'order_1': np.zeros(50),
                    'order_2': np.zeros(50)
                }
            }
        }
        data_o2['atom_0']['s']['order_1'][2] = 1.
        data_o2['atom_0']['s']['order_2'][3] = 1.
        s_data_o2 = SData(data=data_o2, frequencies=frequencies)
        s_data_o2.add_autoconvolution_spectra(max_order=4)

        # Check only the approriate orders were included
        assert set(s_data_o2[0].keys()) == set(
            [f'order_{i}' for i in range(1, 5)])
        for order_key in ('order_1', 'order_2'):
            assert_almost_equal(s_data_o2[0][order_key],
                                data_o2['atom_0']['s'][order_key])
        for order in range(3, 5):
            expected = np.zeros(50)
            #         ac steps    o1  o2
            expected[(order - 2) * 2 + 3] = 1.
            assert_almost_equal(s_data_o2[0][f'order_{order}'], expected)
示例#6
0
    def test_s_data_by_angle_set_angle_data(self):
        sdba = self.get_s_data_by_angle()
        sdba.set_angle_data(
            0, SData(data=self.list_data[1], frequencies=self.frequencies))
        self.assertTrue(
            np.allclose(sdba[0].extract()['atom_1']['s']['order_1'],
                        self.list_data[1]['atom_1']['s']['order_1']))

        sdba.set_angle_data(0,
                            SData(data=self.list_data[0],
                                  frequencies=self.frequencies),
                            add_to_existing=True)
        self.assertTrue(
            np.allclose(sdba[0].extract()['atom_1']['s']['order_1'],
                        self.sum_data['atom_1']['s']['order_1']))
示例#7
0
    def test_s_data_multiply(self):
        s_data = SData(data=deepcopy(self.sample_data_two_orders),
                       frequencies=self.frequencies)

        factors = np.array([[1, 2, 3, 4, 5], [2, 3, 4, 5, 6]])

        s_data_multiplied = s_data * factors

        assert_almost_equal(s_data_multiplied[0]['order_1'],
                            np.linspace(0, 2, 5) * factors[0])
        assert_almost_equal(s_data_multiplied[0]['order_2'],
                            np.linspace(2, 4, 5) * factors[1])
        assert_almost_equal(s_data_multiplied[1]['order_1'],
                            np.linspace(3, 1, 5) * factors[0])
        assert_almost_equal(s_data_multiplied[1]['order_2'],
                            np.linspace(2, 1, 5) * factors[1])

        # Check there was no side-effect on initial sdata
        assert_almost_equal(
            s_data[0]['order_2'],
            self.sample_data_two_orders['atom_0']['s']['order_2'])

        # Now check that in-place mult gives the same results
        s_data *= factors
        for atom1, atom2 in zip(s_data, s_data_multiplied):
            assert_almost_equal(atom1['order_1'], atom2['order_1'])
            assert_almost_equal(atom1['order_2'], atom2['order_2'])
示例#8
0
    def test_s_data_apply_dw(self):
        dw = np.random.RandomState(42).rand(2, 5)

        for min_order, max_order, expected in [
            (1, 1, {
                'atom_0': {
                    'order_1': np.linspace(0, 2, 5) * dw[0, :],
                    'order_2': np.linspace(2, 4, 5)
                },
                'atom_1': {
                    'order_1': np.linspace(3, 1, 5) * dw[1, :],
                    'order_2': np.linspace(2, 1, 5)
                }
            }),
            (2, 2, {
                'atom_0': {
                    'order_1': np.linspace(0, 2, 5),
                    'order_2': np.linspace(2, 4, 5) * dw[0, :]
                },
                'atom_1': {
                    'order_1': np.linspace(3, 1, 5),
                    'order_2': np.linspace(2, 1, 5) * dw[1, :]
                }
            }),
            (1, 2, {
                'atom_0': {
                    'order_1': np.linspace(0, 2, 5) * dw[0, :],
                    'order_2': np.linspace(2, 4, 5) * dw[0, :]
                },
                'atom_1': {
                    'order_1': np.linspace(3, 1, 5) * dw[1, :],
                    'order_2': np.linspace(2, 1, 5) * dw[1, :]
                }
            })
        ]:

            sdata = SData(data=deepcopy(self.sample_data_two_orders),
                          frequencies=self.frequencies)
            sdata.apply_dw(dw, min_order=min_order, max_order=max_order)
            for atom_key, atom_data in sdata.extract().items():
                if atom_key == 'frequencies':
                    continue
                for order_key in atom_data['s']:
                    assert_almost_equal(atom_data['s'][order_key],
                                        expected[atom_key][order_key])
示例#9
0
    def _broaden_sdata(self, sdata: SData,
                       broadening_scheme: str = 'auto') -> SData:
        """
        Apply instrumental broadening to scattering data
        """
        sdata_dict = sdata.extract()
        frequencies = sdata_dict['frequencies']
        del sdata_dict['frequencies']

        for atom_key in sdata_dict:
            for order_key in sdata_dict[atom_key]['s']:
                _, sdata_dict[atom_key]['s'][order_key] = (
                    self._instrument.convolve_with_resolution_function(
                        frequencies=frequencies, bins=self._bins,
                        s_dft=sdata_dict[atom_key]['s'][order_key],
                        scheme=broadening_scheme))
        return SData(data=sdata_dict, frequencies=self._bin_centres,
                     temperature = sdata.get_temperature(),
                     sample_form = sdata.get_sample_form())
示例#10
0
    def test_sample_form(self):
        sample_form = 'Polycrystalline'

        s_data = SData(sample_form=sample_form,
                       data=self.sample_data,
                       frequencies=self.frequencies)
        self.assertEqual(sample_form, s_data.get_sample_form())

        with self.assertRaises(ValueError):
            s_data.check_known_sample_form()

        # Check should pass for 'Powder'
        powder_data = SData(sample_form='Powder',
                            data=self.sample_data,
                            frequencies=self.frequencies)
        powder_data.check_known_sample_form()
示例#11
0
    def _broaden_sdata(self,
                       sdata: SData,
                       broadening_scheme: str = 'auto') -> SData:
        """
        Apply instrumental broadening to scattering data

        If the data is 2D, process line-by-line.
        (There is room for improvement, by reworking all the broadening
        implementations to accept 2-D input.)
        """
        sdata_dict = sdata.extract()
        frequencies = sdata_dict['frequencies']
        del sdata_dict['frequencies']
        if 'q_bins' in sdata_dict:
            del sdata_dict['q_bins']

        for atom_key in sdata_dict:
            for order_key, s_dft in sdata_dict[atom_key]['s'].items():
                if len(s_dft.shape) == 1:
                    _, sdata_dict[atom_key]['s'][order_key] = (
                        self._instrument.convolve_with_resolution_function(
                            frequencies=frequencies,
                            bins=self._bins,
                            s_dft=s_dft,
                            scheme=broadening_scheme))
                else:  # 2-D data, broaden one line at a time
                    for q_i, s_dft_row in enumerate(
                            sdata_dict[atom_key]['s'][order_key]):
                        _, sdata_dict[atom_key]['s'][order_key][q_i] = (
                            self._instrument.convolve_with_resolution_function(
                                frequencies=frequencies,
                                bins=self._bins,
                                s_dft=s_dft_row,
                                scheme=broadening_scheme))

        return SData(data=sdata_dict,
                     frequencies=self._bin_centres,
                     temperature=sdata.get_temperature(),
                     sample_form=sdata.get_sample_form(),
                     q_bins=sdata.get_q_bins())
示例#12
0
    def _get_empty_sdata(self, use_fine_bins: bool = False,
                         max_order: Optional[int] = None) -> SData:
        """
        Initialise an appropriate SData object for this calculation
        """
        bin_centres = self._fine_bin_centres if use_fine_bins else self._bin_centres

        if max_order is None:
            max_order = self._quantum_order_num

        return SData.get_empty(frequencies=bin_centres,
                               atom_keys=list(self._abins_data.get_atoms_data().extract().keys()),
                               order_keys=[f'order_{n}' for n in range(1, max_order + 1)],
                               temperature=self._temperature, sample_form=self._sample_form)
示例#13
0
    def test_s_data_indexing(self):
        s_data = SData(data=self.sample_data, frequencies=self.frequencies)
        self.assertTrue(
            np.allclose(s_data[1]['order_1'],
                        self.sample_data['atom_1']['s']['order_1']))

        sliced_items = s_data[:]
        self.assertIsInstance(sliced_items, list)
        self.assertTrue(
            np.allclose(sliced_items[0]['order_1'],
                        self.sample_data['atom_0']['s']['order_1']))
        self.assertTrue(
            np.allclose(sliced_items[1]['order_1'],
                        self.sample_data['atom_1']['s']['order_1']))
示例#14
0
    def test_s_data_temperature(self):
        # Good temperature should pass without issue
        good_temperature = 10.5
        s_data_good_temperature = SData(frequencies=self.frequencies,
                                        data=self.sample_data,
                                        temperature=good_temperature)
        s_data_good_temperature.check_finite_temperature()
        self.assertAlmostEqual(good_temperature,
                               s_data_good_temperature.get_temperature())

        # Wrong type should get a TypeError at init
        with self.assertRaises(TypeError):
            SData(frequencies=self.frequencies,
                  data=self.sample_data,
                  temperature="10")

        # Non-finite values should get a ValueError when explicitly checked
        for bad_temperature in (-20., 0):
            s_data_bad_temperature = SData(frequencies=self.frequencies,
                                           data=self.sample_data,
                                           temperature=bad_temperature)
            with self.assertRaises(ValueError):
                s_data_bad_temperature.check_finite_temperature()
示例#15
0
    def test_bin_width(self):
        s_data = SData(data=self.sample_data, frequencies=self.frequencies)
        self.assertAlmostEqual(self.bin_width, s_data.get_bin_width())

        # Nonlinear frequency sampling has no bin width
        irregular_frequencies = np.exp(self.frequencies)
        s_data_irregular_freq = SData(data=self.sample_data,
                                      frequencies=irregular_frequencies)
        self.assertIsNone(s_data_irregular_freq.get_bin_width())

        # Unordered frequencies are rejected at init
        shuffled_frequencies = np.concatenate(
            [self.frequencies[4:], self.frequencies[:4]])
        with self.assertRaises(ValueError):
            SData(data=self.sample_data, frequencies=shuffled_frequencies)
示例#16
0
    def test_s_data_get_empty(self):
        from itertools import product

        sdata = SData.get_empty(frequencies=np.linspace(1., 5., 10),
                                atom_keys=['atom_2', 'atom_3'],
                                order_keys=['order_2', 'order_3'],
                                temperature=101.,
                                sample_form='etherial')
        with self.assertRaises(IndexError):
            sdata[1]
        with self.assertRaises(KeyError):
            sdata[2]['order_1']

        for atom, order in product([2, 3], ['order_2', 'order_3']):
            assert_almost_equal(sdata[atom][order], np.zeros(10))

        assert_almost_equal(sdata.get_temperature(), 101.)
        self.assertEqual(sdata.get_sample_form(), 'etherial')
示例#17
0
    def _get_empty_sdata(self,
                         use_fine_bins: bool = False,
                         max_order: Optional[int] = None,
                         shape=None) -> SData:
        """
        Initialise an appropriate SData object for this calculation

        Args:
            shape:
                '1d', '2d', or None. If '1d', spectra are 1-D (corresponding to
                energy). If '2d', spectra have rows corresponding to q bin
                centres. If None, detect dimensions based on presence of
                self._q_bin_centres.

        """
        bin_centres = self._fine_bin_centres if use_fine_bins else self._bin_centres

        if max_order is None:
            max_order = self._quantum_order_num

        if (shape and shape.lower() == '1d') or (shape is None and
                                                 self._q_bin_centres is None):
            n_rows = None
            q_bins = None
        else:
            n_rows = len(self._q_bin_centres)
            q_bins = self._q_bins

        return SData.get_empty(
            frequencies=bin_centres,
            atom_keys=list(self._abins_data.get_atoms_data().extract().keys()),
            order_keys=[f'order_{n}' for n in range(1, max_order + 1)],
            n_rows=n_rows,
            temperature=self._temperature,
            sample_form=self._sample_form,
            q_bins=q_bins)
示例#18
0
    def test_s_data_update(self):
        # Case 1: add new atom
        sdata = SData(data=self.sample_data, frequencies=self.frequencies)
        sdata_new = SData(
            data={'atom_2': {
                's': {
                    'order_1': np.linspace(0, 2, 5)
                }
            }},
            frequencies=self.frequencies)
        sdata.update(sdata_new)
        assert_almost_equal(sdata[0]['order_1'],
                            self.sample_data['atom_0']['s']['order_1'])
        assert_almost_equal(sdata[2]['order_1'], np.linspace(0, 2, 5))

        # Case 2: add new order
        sdata = SData(data=self.sample_data, frequencies=self.frequencies)
        sdata_new = SData(
            data={'atom_1': {
                's': {
                    'order_2': np.linspace(0, 2, 5)
                }
            }},
            frequencies=self.frequencies)
        sdata.update(sdata_new)
        assert_almost_equal(sdata[1]['order_1'],
                            self.sample_data['atom_1']['s']['order_1'])
        assert_almost_equal(sdata[1]['order_2'], np.linspace(0, 2, 5))

        # Case 3: update in-place
        sdata = SData(data=self.sample_data, frequencies=self.frequencies)
        sdata_new = SData(data={
            'atom_1': {
                's': {
                    'order_1': np.linspace(0, 2, 5),
                    'order_2': np.linspace(2, 4, 5)
                }
            }
        },
                          frequencies=self.frequencies)
        sdata.update(sdata_new)
        assert_almost_equal(sdata[1]['order_1'], np.linspace(0, 2, 5))
        assert_almost_equal(sdata[1]['order_2'], np.linspace(2, 4, 5))

        # Case 4: incompatible frequencies
        sdata = SData(data=self.sample_data, frequencies=self.frequencies)
        sdata_new = SData(
            data={'atom_2': {
                's': {
                    'order_1': np.linspace(0, 2, 4)
                }
            }},
            frequencies=self.frequencies[:-1])
        with self.assertRaises(ValueError):
            sdata.update(sdata_new)
示例#19
0
    def test_sdba_from_sdata_series_bad_inputs(self):
        bad_data = [  # Inconsistent frequencies
            {
                'data': [
                    SData(data=self.list_data[0],
                          frequencies=[1, 2, 3, 4, 5, 6]),
                    SData(data=self.list_data[1],
                          frequencies=[2, 4, 6, 8, 10, 12])
                ],
                'angles':
                self.angles,
                'error':
                ValueError
            },
            # Inconsistent sample_form
            {
                'data': [
                    SData(data=self.list_data[0],
                          frequencies=self.frequencies),
                    SData(data=self.list_data[1],
                          frequencies=self.frequencies,
                          sample_form='crystal')
                ],
                'angles':
                self.angles,
                'error':
                ValueError
            },
            # Inconsistent temperature
            {
                'data': [
                    SData(data=self.list_data[0],
                          frequencies=self.frequencies,
                          temperature=100.),
                    SData(data=self.list_data[1],
                          frequencies=self.frequencies,
                          temperature=200.)
                ],
                'angles':
                self.angles,
                'error':
                ValueError
            },
            # Inconsistent number of angles
            {
                'data': [
                    SData(data=self.list_data[0],
                          frequencies=self.frequencies,
                          temperature=100.)
                ],
                'angles':
                self.angles,
                'error':
                IndexError
            },
            # Bad typing
            {
                'data': [
                    SData(data=self.list_data[0],
                          frequencies=self.frequencies,
                          temperature=100.), 'SData (actually just a string)'
                ],
                'angles':
                self.angles,
                'error':
                TypeError
            },
        ]

        for dataset in bad_data:
            with self.assertRaises(dataset['error']):
                SDataByAngle.from_sdata_series(dataset['data'],
                                               angles=dataset['angles'])