Ejemplo n.º 1
0
class TestGetterSetter(unittest.TestCase):
    database = '_data_for_unittest'

    def setUp(self):
        _stack = {
            'CoAg': {
                'elements': ['Co', 'Ag'],
                'stoichiometric_ratio': [1, 2],
                'thickness': {
                    'value': 0.025,
                    'units': 'mm'
                },
                'density': {
                    'value': np.NaN,
                    'units': 'g/cm3'
                },
            },
            'U': {
                'elements': ['U'],
                'stoichiometric_ratio': [1],
                'thickness': {
                    'value': 0.03,
                    'units': 'mm'
                },
                'density': {
                    'value': np.NaN,
                    'units': 'g/cm3'
                },
            },
        }
        self.o_reso = Resonance(stack=_stack, database=self.database)

        # stoichiometric ratio

    def test_retrieve_stoichiometric_of_uo3_sample(self):
        """assert retrieve stoichiometric work for complex sample such as UO3"""
        o_reso = self.o_reso
        o_reso.add_layer(formula='UO3', thickness=0.25, density=0.5)
        o_reso.add_layer(formula='AgCo', thickness=0.5, density=0.8)
        _stoichiometric_ratio = o_reso.get_isotopic_ratio(compound='UO3',
                                                          element='U')
        self.assertEqual(_stoichiometric_ratio['238-U'], 0.992745)

    def test_retrieve_stoichiometric_ratio_raises_error_if_unknown_compound(
            self):
        """assert ValueError raised if wrong compound when getting stoichiometric ratio"""
        self.assertRaises(ValueError,
                          self.o_reso.get_isotopic_ratio,
                          compound='unknown')

    def test_if_element_misssing_use_compound_and_raises_error_if_wrong(self):
        """assert ValueError raised if element does not exist"""
        self.assertRaises(ValueError,
                          self.o_reso.get_isotopic_ratio,
                          compound='CoAg')

    def test_stoichiometric_ratio_returned(self):
        """assert the stoichiometric ratio are correctly returned"""
        _stoichiometric_ratio = self.o_reso.get_isotopic_ratio(compound='U')
        _expected_dict = {
            '233-U': 0.0,
            '234-U': 5.5e-5,
            '235-U': 0.0072,
            '238-U': 0.992745
        }
        self.assertEqual(_expected_dict['233-U'],
                         _stoichiometric_ratio['233-U'])
        self.assertEqual(_expected_dict['235-U'],
                         _stoichiometric_ratio['235-U'])
        self.assertEqual(_expected_dict['238-U'],
                         _stoichiometric_ratio['238-U'])

    def test_list_all_stoichiometric_ratio(self):
        """assert the entire stoichiometric list is returned"""
        _stoichiometric_ratio = self.o_reso.get_isotopic_ratio()
        _expected_dict = {
            'U': {
                'U': {
                    '233-U': 0.0,
                    '234-U': 5.5e-5,
                    '235-U': 0.0072,
                    '238-U': 0.992745
                },
            },
            'CoAg': {
                'Ag': {
                    '107-Ag': 0.51839,
                    '109-Ag': 0.4816
                },
                'Co': {
                    '58-Co': 0.0,
                    '59-Co': 1.0
                },
            },
        }
        self.assertEqual(_expected_dict['U']['U']['233-U'],
                         _stoichiometric_ratio['U']['U']['233-U'])
        self.assertEqual(_expected_dict['U']['U']['238-U'],
                         _stoichiometric_ratio['U']['U']['238-U'])
        self.assertEqual(_expected_dict['CoAg']['Ag']['107-Ag'],
                         _stoichiometric_ratio['CoAg']['Ag']['107-Ag'])

    def test_set_stoichiometric_ratio_raises_value_error_if_wrong_compound(
            self):
        """assert ValueError raised if wrong compound in stoichiometric ratio setter"""
        self.assertRaises(ValueError, self.o_reso.set_isotopic_ratio)
        self.assertRaises(ValueError,
                          self.o_reso.set_isotopic_ratio,
                          compound='unknown')

    def test_set_stoichiometric_ratio_raises_value_error_if_wrong_element(
            self):
        """assert ValueError raised if wrong element in stoichiometric ratio setter"""
        self.assertRaises(ValueError,
                          self.o_reso.set_isotopic_ratio,
                          compound='CoAg')
        self.assertRaises(ValueError,
                          self.o_reso.set_isotopic_ratio,
                          compound='CoAg',
                          element='unknown')

    def test_set_stoichiometric_ratio_has_correct_new_list_size(self):
        """assert ValueRror raised if new list of ratio does not match old list size"""
        self.assertRaises(ValueError,
                          self.o_reso.set_isotopic_ratio,
                          compound='U',
                          element='U',
                          list_ratio=[0, 1, 2])

    def test_set_stoichiometric_ratio_correctly_calculates_new_molar_mass(
            self):
        """assert molar mass is correctly calculated for new set of stoichiometric coefficient"""
        self.o_reso.set_isotopic_ratio(compound='CoAg',
                                       element='Co',
                                       list_ratio=[0.5, 0.5])
        new_molar_mass = self.o_reso.stack['CoAg']['Co']['molar_mass']['value']
        list_isotopes_mass = self.o_reso.stack['CoAg']['Co']['isotopes'][
            'mass']['value']
        list_isotopes_ratio = self.o_reso.stack['CoAg']['Co']['isotopes'][
            'isotopic_ratio']
        mass_ratio = zip(list_isotopes_mass, list_isotopes_ratio)
        expected_molar_mass = np.array([_m * _r
                                        for _m, _r in mass_ratio]).sum()
        self.assertAlmostEqual(new_molar_mass,
                               expected_molar_mass,
                               delta=0.0001)

    def test_set_stoichiometric_ratio_correctly_calculates_new_density(self):
        """assert density is correctly calculated for new set of stoichiometric coefficient"""
        self.o_reso.set_isotopic_ratio(compound='CoAg',
                                       element='Co',
                                       list_ratio=[0.5, 0.5])
        new_density = self.o_reso.stack['CoAg']['Co']['density']['value']
        list_density = self.o_reso.stack['CoAg']['Co']['isotopes']['density'][
            'value']
        list_isotopes_ratio = self.o_reso.stack['CoAg']['Co']['isotopes'][
            'isotopic_ratio']
        density_ratio = zip(list_density, list_isotopes_ratio)
        expected_density = np.array([_d * _r
                                     for _d, _r in density_ratio]).sum()
        self.assertAlmostEqual(new_density, expected_density, delta=0.0001)

        # density

    def test_retrieve_density_raises_error_if_unknown_compound(self):
        """assert ValueError raised if wrong compound when getting density"""
        self.assertRaises(ValueError,
                          self.o_reso.get_density,
                          compound='unknown')

    def test_if_element_misssing_use_compound_and_raises_error_if_wrong_when_getting_density(
            self):
        """assert ValueError raised if element does not exist when getting density"""
        self.assertRaises(ValueError, self.o_reso.get_density, compound='CoAg')

    def test_density_returned(self):
        """assert the density are correctly returned"""
        _density = self.o_reso.get_density(compound='U')
        _expected_density = 18.95
        self.assertEqual(_density, _expected_density)

    def test_density_returned_all(self):
        """assert the density of all element works"""
        _density_list = self.o_reso.get_density()
        _expected_density = {
            'CoAg': {
                'Co': 8.9,
                'Ag': 10.5,
            },
            'U': {
                'U': 18.95,
            },
        }
        self.assertEqual(_expected_density, _density_list)
Ejemplo n.º 2
0
class Simulation(object):
    # Input sample name or names as str, case sensitive

    def __init__(self, energy_min=1e-5, energy_max=1000, energy_step=0.01, database='ENDF_VIII'):
        """
        initialize the a Simulation() using the Resonance() in ImagingReso

        :param energy_min:
        :type energy_min:
        :param energy_max:
        :type energy_max:
        :param energy_step:
        :type energy_step:
        :param database:
        :type database:
        """
        self.energy_min = energy_min
        self.energy_max = energy_max
        self.energy_step = energy_step
        self.database = database

        self.o_reso = Resonance(energy_min=energy_min,
                                energy_max=energy_max,
                                energy_step=energy_step,
                                database=database)
        self.neutron_pulse = None

        self.layer_list = []
        self.layer = fit_util.Layer()

        self.x_tof_us = None
        self.y_att = None

    def add_layer(self, layer: str, thickness_mm: float, density_gcm3=np.NaN):
        """

        :param layer:
        :type layer:
        :param thickness_mm:
        :type thickness_mm:
        :param density_gcm3:
        :type density_gcm3:
        :return:
        :rtype:
        """
        self.o_reso.add_layer(formula=layer,
                              thickness=thickness_mm,
                              density=density_gcm3)
        self.layer_list.append(layer)
        self.layer.add_layer(layer=layer, thickness_mm=thickness_mm, density_gcm3=density_gcm3)

    def add_Layer(self, layer: Layer):
        """
        Add layer using Layer class

        :param layer:
        """
        for _each_layer in list(layer.info.keys()):
            self.add_layer(layer=_each_layer,
                           thickness_mm=layer.info[_each_layer]['thickness']['value'],
                           density_gcm3=layer.info[_each_layer]['density']['value'])

    def set_isotopic_ratio(self, layer, element, new_isotopic_ratio_list):
        """
        Set isotopic ratios for picked element and update x y values to pass

        :param layer:
        :param element:
        :param new_isotopic_ratio_list:
        :return: x in eV
                 y in attenuation
        """
        if type(new_isotopic_ratio_list) is not list:
            raise ValueError("{} is not a list".format(new_isotopic_ratio_list))
        # Check if layer exist
        if layer not in self.layer_list:
            raise ValueError('Layer {} does not exist.'.format(layer))
        # Check if element exist
        _formula = re.findall(r'([A-Z][a-z]*)(\d*)', layer)
        _elements = []
        for _element in _formula:
            _single_element = list(_element)[0]
            _elements.append(_single_element)
        if element not in _elements:
            raise ValueError('Element {} specified does not exist in {} layer.'.format(element, layer))
        self.o_reso.set_isotopic_ratio(compound=layer, element=element, list_ratio=new_isotopic_ratio_list)
        # self.x_simu = np.array(self.o_reso.total_signal['energy_eV']).round(5)
        # self.y_simu = np.array(self.o_reso.total_signal['attenuation'])

    def get_x(self, x_type, offset_us=None, source_to_detector_m=None, t_unit='us',
              t_start_us=None, time_resolution_us=None, num_offset=0):
        """
        Get x by specified type

        :param x_type:
        :type x_type:
        :param offset_us:
        :type offset_us:
        :param source_to_detector_m:
        :type source_to_detector_m:
        :return: x in specified type
        :rtype: np.array
        """
        fit_util.check_if_in_list(x_type, fit_util.x_type_list)
        _x = np.array(self.o_reso.total_signal['energy_eV']).round(5)
        x = fit_util.convert_energy_to(x=_x,
                                       x_type=x_type,
                                       offset_us=offset_us,
                                       source_to_detector_m=source_to_detector_m,
                                       t_unit=t_unit,
                                       t_start_us=t_start_us,
                                       time_resolution_us=time_resolution_us,
                                       num_offset=num_offset)
        return x

    def get_y(self, y_type):
        """
        Get x by specified type

        :param y_type:
        :type y_type:
        :return: y in specified type
        :rtype: np.array
        """
        fit_util.check_if_in_list(y_type, fit_util.y_type_list)
        y = self.o_reso.total_signal[y_type]
        return y

    def _convolve_beam_shapes(self, source_to_detector_m, conv_proton, proton_params={}, model_index=1):
        _file_path = os.path.abspath(os.path.dirname(__file__))
        _rel_path_to_neutron1 = 'data/_data_for_tutorial/neutron_pulse/source_section_1.dat'
        _rel_path_to_neutron2 = 'data/_data_for_tutorial/neutron_pulse/source_section_2.dat'
        path1 = os.path.join(_file_path, _rel_path_to_neutron1)
        path2 = os.path.join(_file_path, _rel_path_to_neutron2)

        self.neutron_pulse = NeutronPulse(path1, model_index=model_index)
        self.neutron_pulse.load_shape_each(path2)
        self.neutron_pulse.fit_shape(e_min=1, e_max=500,
                                     drop=False, norm=True,
                                     check_each=False,
                                     save_fig=False,
                                     overwrite_csv=False)
        self.neutron_pulse.fit_params(check_each=False, loglog_fit=True, overwrite_csv=False)

        self.neutron_pulse.make_shape(e_ev=self.get_x(x_type='energy'), t_interp=None, for_sum=True, norm=False,
                                      source_to_detector_m=source_to_detector_m,
                                      conv_proton=conv_proton, proton_params=proton_params,
                                      overwrite_csv=False)

        tof_beam_shape_df = self.neutron_pulse.shape_tof_df_interp.set_index('tof_us')
        tof_trans_df = tof_beam_shape_df * self.o_reso.total_signal['transmission']

        tof_beam_shape_df['sum'] = tof_beam_shape_df.sum(axis=1)
        tof_trans_df['sum'] = tof_trans_df.sum(axis=1)
        # print(tof_beam_shape_df)
        # print(tof_trans_df)

        self.x_tof_us = np.array(tof_beam_shape_df.index)
        self.y_att = 1 - np.array(tof_trans_df['sum'] / tof_beam_shape_df['sum'])

    def peak_map(self, x_type, y_type, thres=0.15, min_dist=20, impr_reso=True,
                 offset_us=None, source_to_detector_m=None, t_unit='us',
                 t_start_us=None, time_resolution_us=None, num_offset=0,
                 ):
        """
        Get peak map for each element and/or isotope

        :param thres:
        :type thres:
        :param min_dist:
        :type min_dist:
        :param impr_reso:
        :type impr_reso:
        :return:
        :rtype:
        """
        if len(self.layer_list) == 0:
            raise ValueError("No layer has been added.")

        _stack_signal = self.o_reso.stack_signal
        _layer_list = self.layer_list
        # _x_energy = _stack_signal[_layer_list[0]][_layer_list[0]]['energy_eV']
        _x = self.get_x(x_type=x_type,
                        offset_us=offset_us,
                        source_to_detector_m=source_to_detector_m,
                        t_unit=t_unit,
                        t_start_us=t_start_us,
                        time_resolution_us=time_resolution_us,
                        num_offset=num_offset
                        )
        # _x = sorted(_x)
        peak_map = {}
        for _ele in _layer_list:
            # Isotope
            for _iso in self.o_reso.stack[_ele][_ele]['isotopes']['list']:
                peak_map[_iso] = {}
                _iso_y = _stack_signal[_ele][_ele][_iso]['attenuation']
                _peak_df = fit_util.find_peak(x=_x, y=_iso_y, x_name='x',
                                              thres=thres, min_dist=min_dist,
                                              imprv_reso=impr_reso)
                if y_type == 'transmission':
                    _peak_df['y'] = 1 - _peak_df['y']
                peak_map[_iso]['ideal'] = _peak_df
            # Element
            peak_map[_ele] = {}
            _ele_y = _stack_signal[_ele][_ele]['attenuation']
            _peak_df = fit_util.find_peak(x=_x, y=_ele_y, x_name='x',
                                          thres=thres, min_dist=min_dist,
                                          imprv_reso=impr_reso)
            if y_type == 'transmission':
                _peak_df['y'] = 1 - _peak_df['y']
            peak_map[_ele]['ideal'] = _peak_df
        peak_map_dict = {'peak_map': peak_map,
                         'x_type': x_type,
                         'y_type': y_type}
        return peak_map_dict

    def plot(self, y_type='attenuation', x_type='energy',
             logx=False, logy=False,
             mixed=True, all_layers=False, all_elements=False,
             all_isotopes=False, items_to_plot=None, time_unit='us', offset_us=0.,
             source_to_detector_m=16.,
             t_start_us=1,
             time_resolution_us=0.16,
             ax_mpl=None,
             fmt='-', ms=2, lw=1.5, alpha=1):
        if len(self.layer_list) == 0:
            raise ValueError("No layer has been added.")
        if items_to_plot is not None:
            # shape format of items
            items = fit_util.Items(o_reso=self.o_reso, database=self.database)
            items_to_plot = items.shaped(items_list=items_to_plot)

        ax = self.o_reso.plot(y_axis=y_type, x_axis=x_type, mixed=mixed,
                              all_layers=all_layers, all_elements=all_elements,
                              all_isotopes=all_isotopes, items_to_plot=items_to_plot,
                              source_to_detector_m=source_to_detector_m,
                              offset_us=offset_us,
                              time_resolution_us=time_resolution_us,
                              time_unit=time_unit,
                              t_start_us=t_start_us,
                              ax_mpl=ax_mpl,
                              logx=logx,
                              logy=logy,
                              # plotly=plotly
                              fmt=fmt,
                              ms=ms,
                              lw=lw,
                              alpha=alpha)
        return ax

    def export(self, output_type='clip', filename=None, x_type='energy', y_type='attenuation',
               all_layers=False, all_elements=False, all_isotopes=False, items_to_export=None,
               offset_us=0., source_to_detector_m=16.,
               t_start_us=1, time_resolution_us=0.16, time_unit='us'):
        if items_to_export is not None:
            # Shape items
            items = fit_util.Items(o_reso=self.o_reso, database=self.database)
            items_to_export = items.shaped(items_list=items_to_export)

        _df = self.o_reso.export(output_type=output_type,
                                 filename=filename,
                                 x_axis=x_type,
                                 y_axis=y_type,
                                 all_layers=all_layers,
                                 all_elements=all_elements,
                                 all_isotopes=all_isotopes,
                                 items_to_export=items_to_export,
                                 offset_us=offset_us,
                                 source_to_detector_m=source_to_detector_m,
                                 t_start_us=t_start_us,
                                 time_resolution_us=time_resolution_us,
                                 time_unit=time_unit)
        return _df