Example #1
0
 def __init__(self, beamlet=None, param_path='output/beamlet/beamlet_test.xml', key=['profiles']):
     if beamlet is None:
         self.param_path = param_path
         self.param = utility.getdata.GetData(data_path_name=self.param_path).data
         self.access_path = self.param.getroot().find('body').find('beamlet_source').text
         self.key = key
         self.components = utility.getdata.GetData(data_path_name=self.access_path, data_key=self.key).data
         self.profiles = utility.getdata.GetData(data_path_name=self.access_path, data_key=self.key).data
         self.atomic_db = AtomicDB(param=self.param, components=self.components)
         self.title = None
     else:
         self.param = beamlet.param
         self.profiles = beamlet.profiles
         self.components = beamlet.components
         self.atomic_db = beamlet.atomic_db
Example #2
0
 def test_neutral_db_init(self):
     actual_param, actual_components = self.build_atomic_neutral_input()
     actual_db = AtomicDB(param=actual_param, components=actual_components)
     self.assertTrue(
         actual_db.are_neutrals,
         msg='The atomic_db is expected to have neutral cross-section data.'
     )
 def test_ceiled_electron_impact_loss(self):
     ceiled_atomic_db = AtomicDB(param=self.BEAMLET_PARAM,
                                 components=self.COMPONENTS,
                                 atomic_ceiling=2)
     ceiled_rate_coefficient = CoefficientMatrix(self.BEAMLET_PARAM,
                                                 self.PROFILES,
                                                 self.COMPONENTS,
                                                 ceiled_atomic_db)
     self.assertIsInstance(
         ceiled_rate_coefficient.electron_impact_loss_np,
         numpy.ndarray,
         msg='The electron impact '
         'ionization terms is not in the expected format.')
     self.assertTupleEqual(
         ceiled_rate_coefficient.electron_impact_loss_np.shape,
         (ceiled_atomic_db.atomic_ceiling,
          self.PROFILES['beamlet grid'].size),
         msg='The electron impact ionization term is '
         'not dimensionally accurate.')
     numpy.testing.assert_almost_equal(
         ceiled_rate_coefficient.electron_impact_loss_np,
         self.EXPECTED_ELECTRON_LOSS_TERMS[
             0:ceiled_atomic_db.atomic_ceiling, :],
         self.EXPECTED_DECIMAL_PRECISION_6,
         err_msg='Interpolation failure for electron impact loss.')
 def setUp(self):
     self.BEAMLET_PARAM, self.COMPONENTS, self.PROFILES = self._build_beamlet_input(
     )
     self.ATOMIC_DB = AtomicDB(param=self.BEAMLET_PARAM,
                               components=self.COMPONENTS)
     self.RATE_COEFFICIENT = CoefficientMatrix(self.BEAMLET_PARAM,
                                               self.PROFILES,
                                               self.COMPONENTS,
                                               self.ATOMIC_DB)
 def setup_neutral(self):
     self.neutral_param, self.neutral_components, self.neutral_profiles = self._build_beamlet_neutral_input(
     )
     self.neutral_atomic = AtomicDB(param=self.neutral_param,
                                    components=self.neutral_components,
                                    resolution='test')
     self.neutral_rate_coefficient = CoefficientMatrix(
         beamlet_param=self.neutral_param,
         beamlet_profiles=self.neutral_profiles,
         plasma_components=self.neutral_components,
         atomic_db=self.neutral_atomic)
Example #6
0
 def __init__(self,
              param=None,
              profiles=None,
              components=None,
              atomic_db=None,
              solver='numerical',
              data_path="beamlet/testimp0001.xml"):
     self.param = param
     if not isinstance(self.param, etree._ElementTree):
         self.__read_beamlet_param(data_path)
     self.profiles = profiles
     self.components = components
     self.atomic_db = atomic_db
     if not (isinstance(self.components, pandas.DataFrame)
             and isinstance(self.profiles, pandas.DataFrame)):
         self.__read_beamlet_profiles()
     if atomic_db is None:
         self.atomic_db = AtomicDB(param=self.param,
                                   components=self.components)
     self.const = Constants()
     self.coefficient_matrix = None
     self.initial_condition = None
     self.calculate_beamevolution(solver)
Example #7
0
 def test_atomic_ceiling(self):
     actual_param, actual_components = self.build_atomic_neutral_input()
     actual_db = AtomicDB(param=actual_param, components=actual_components)
     self.assertLessEqual(
         actual_db.atomic_ceiling,
         actual_db.atomic_levels,
         msg='The atomic ceiling is expected to '
         'be less or equal to the atomic levels from beam with plasma interaction.'
     )
     self.assertLessEqual(
         actual_db.atomic_ceiling,
         actual_db.neutral_db.atomic_levels,
         msg='The atomic ceiling is '
         'expected to be less or equal to the atomic levels from beam with neutral interaction.'
     )
Example #8
0
 def test_ceiled_electron_impact_loss_interpolator(self):
     ceiled_db = AtomicDB(param=self.atomic_db.param,
                          components=self.atomic_db.components,
                          atomic_ceiling=2)
     for level in range(ceiled_db.atomic_ceiling):
         rates = ceiled_db.electron_impact_loss[level](
             self.INTERPOLATION_TEST_TEMPERATURE)
         self.assertIsInstance(
             rates,
             numpy.ndarray,
             msg='Interpolator output expected to be numpy.')
         numpy.testing.assert_almost_equal(
             self.EXPECTED_ELECTRON_IMPACT_LOSS[level],
             rates,
             self.EXPECTED_DECIMAL_PRECISION_5,
             err_msg='Electron impact loss '
             'interpolator failure.')
Example #9
0
 def test_ceiled_electron_impact_loss_terms(self):
     ceiled_db = AtomicDB(param=self.atomic_db.param,
                          components=self.atomic_db.components,
                          atomic_ceiling=2)
     self.assertIsInstance(
         ceiled_db.electron_impact_loss,
         tuple,
         msg=
         'Electron impact loss functions are stored in wrong data format.')
     self.assertEqual(
         len(ceiled_db.electron_impact_loss),
         ceiled_db.atomic_ceiling,
         msg=
         'Number of expected interpolator functions is inconsistent with number of atomic levels.'
     )
     for index in range(ceiled_db.atomic_ceiling):
         self.assertIsInstance(
             ceiled_db.electron_impact_loss[index],
             scipy.interpolate.interp1d,
             msg='Provided electron impact loss functions are of wrong type.'
         )
Example #10
0
 def setUp(self):
     param, components = self.build_atomic_input()
     self.atomic_db = AtomicDB(param=param, components=components)
Example #11
0
class Beamlet:
    def __init__(self,
                 param=None,
                 profiles=None,
                 components=None,
                 atomic_db=None,
                 solver='numerical',
                 data_path="beamlet/testimp0001.xml"):
        self.param = param
        if not isinstance(self.param, etree._ElementTree):
            self.__read_beamlet_param(data_path)
        self.profiles = profiles
        self.components = components
        self.atomic_db = atomic_db
        if not (isinstance(self.components, pandas.DataFrame)
                and isinstance(self.profiles, pandas.DataFrame)):
            self.__read_beamlet_profiles()
        if atomic_db is None:
            self.atomic_db = AtomicDB(param=self.param,
                                      components=self.components)
        self.const = Constants()
        self.coefficient_matrix = None
        self.initial_condition = None
        self.calculate_beamevolution(solver)

    def __read_beamlet_param(self, data_path):
        self.param = utility.getdata.GetData(data_path_name=data_path).data
        assert isinstance(self.param, etree._ElementTree)
        print('Beamlet.param read from file: ' + data_path)

    def __read_beamlet_profiles(self):
        hdf5_path = self.param.getroot().find('body').find(
            'beamlet_source').text
        self.components = utility.getdata.GetData(data_path_name=hdf5_path,
                                                  data_key=['components']).data
        assert isinstance(self.components, pandas.DataFrame)
        print('Beamlet.imp_components read from file: ' + hdf5_path)
        self.profiles = utility.getdata.GetData(data_path_name=hdf5_path,
                                                data_key=['profiles']).data
        assert isinstance(self.profiles, pandas.DataFrame)
        print('Beamlet.imp_profiles read from file: ' + hdf5_path)

    def __initialize_ode(self):
        self.coefficient_matrix = CoefficientMatrix(self.param, self.profiles,
                                                    self.components,
                                                    self.atomic_db)
        self.initial_condition = [
            self.__get_linear_density()
        ] + [0.] * (self.atomic_db.atomic_ceiling - 1)

    def __get_linear_density(self):
        current = float(
            self.param.getroot().find('body').find('beamlet_current').text)
        return current / (self.atomic_db.velocity * self.const.charge_electron)

    def __solve_numerically(self):
        if self.coefficient_matrix is None or self.initial_condition is None:
            self.__initialize_ode()

        ode = Ode(coeff_matrix=self.coefficient_matrix.matrix,
                  init_condition=self.initial_condition)
        numerical = ode.calculate_numerical_solution(
            self.profiles['beamlet grid']['distance']['m'])

        for level in range(self.atomic_db.atomic_ceiling):
            label = 'level ' + self.atomic_db.inv_atomic_dict[level]
            self.profiles[label] = numerical[:, level]
        return

    def calculate_beamevolution(self, solver):
        assert isinstance(solver, str)
        if solver == 'numerical':
            self.__solve_numerically()
        elif solver == 'analytical':
            raise NotImplementedError('Analytical solver not yet implemented.')
        elif solver == 'disregard':
            print('Beam evolution not calculated.')
            return
        else:
            raise Exception(
                'The numerical solver: ' + solver + ' is not supported. '
                'Supported solvers are: numerical, analytical, disregard.')

    def __was_beamevolution_performed(self):
        try:
            dummy = self.profiles[
                'level ' + self.atomic_db.set_default_atomic_levels()[2]]
            return True
        except KeyError:
            return False

    def compute_linear_emission_density(self, to_level=None, from_level=None):
        if to_level is None or from_level is None:
            from_level, to_level, ground_level, transition_label = self.atomic_db.set_default_atomic_levels(
            )
        if isinstance(to_level, str) and isinstance(from_level, str):
            if self.atomic_db.atomic_dict[
                    to_level] >= self.atomic_db.atomic_dict[from_level]:
                raise Exception(
                    'Dude! Please stop screwing around. '
                    'Electrons spontaneously transit from higher to lower atomic states.'
                )
        else:
            raise Exception(
                'The expected input for atomic transitions are strings. '
                'Bundled-n for H,D,T beam species ex:[1, 2, ... 6]. '
                'l-n resolved labels for Li ex: [2s, 2p, ... 4f] and Na ex: [3s, 3p, ... 5s]'
            )
        if self.__was_beamevolution_performed():
            transition_label = from_level + '-->' + to_level
            self.profiles[transition_label] = \
                self.profiles['level '+from_level] * self.atomic_db.spontaneous_trans[self.atomic_db.atomic_dict
                                                                                      [to_level], self.atomic_db.atomic_dict[from_level]]
        else:
            print(
                'Beam evolution calculations were not performed. Execute solver first.'
            )

    def compute_linear_density_attenuation(self):
        if self.__was_beamevolution_performed():
            self.profiles['linear_density_attenuation'] = self.profiles[
                'level ' + self.atomic_db.inv_atomic_dict[0]]
            for level in range(1, self.atomic_db.atomic_ceiling):
                self.profiles['linear_density_attenuation'] += self.profiles[
                    'level ' + self.atomic_db.inv_atomic_dict[level]]
        else:
            print(
                'Beam evolution calculations were not performed. Execute solver first.'
            )

    def compute_relative_populations(self, reference_level=None):
        if self.__was_beamevolution_performed():
            if reference_level is None:
                reference_level = self.atomic_db.set_default_atomic_levels()[2]
            assert isinstance(reference_level, str)
            for level in range(self.atomic_db.atomic_ceiling):
                self.profiles['rel.pop ' + self.atomic_db.inv_atomic_dict[level]] = \
                    self.profiles['level ' + self.atomic_db.inv_atomic_dict[level]] / \
                    self.profiles['level ' + reference_level]
        else:
            print(
                'Beam evolution calculations were not performed. Execute solver first.'
            )

    def copy(self, object_copy='full'):
        if not isinstance(object_copy, str):
            raise TypeError('The expected data type for <object_copy> is str.')
        if object_copy == 'full':
            return deepcopy(self)
        elif object_copy == 'without-results':
            beamlet = deepcopy(self)
            beamlet.profiles = self._copy_profiles_input()
            return beamlet
        else:
            raise ValueError('The <object_copy> variable does not support ' +
                             object_copy)

    def _copy_profiles_input(self):
        profiles = numpy.zeros(
            (1 + len(self.components) * 2, len(self.profiles)))
        type_labels = []
        property_labels = []
        unit_labels = []

        profiles[0, :] = self.profiles['beamlet grid']['distance']['m']
        type_labels.append('beamlet grid')
        property_labels.append('distance')
        unit_labels.append('m')
        count = 1

        for component in self.components.T:
            type_labels.append(str(component))
            property_labels.append('density')
            unit_labels.append('m-3')
            profiles[count, :] = self.profiles[str(
                component)]['density']['m-3']

            type_labels.append(str(component))
            property_labels.append('temperature')
            unit_labels.append('eV')
            profiles[count +
                     1, :] = self.profiles[str(component)]['temperature']['eV']

            count += 2

        profiles = numpy.swapaxes(profiles, 0, 1)
        row_index = [i for i in range(len(self.profiles))]
        column_index = pandas.MultiIndex.from_arrays(
            [type_labels, property_labels, unit_labels],
            names=['type', 'property', 'unit'])
        return pandas.DataFrame(data=profiles,
                                columns=column_index,
                                index=row_index)
Example #12
0
class BeamletProfiles:
    def __init__(self, beamlet=None, param_path='output/beamlet/beamlet_test.xml', key=['profiles']):
        if beamlet is None:
            self.param_path = param_path
            self.param = utility.getdata.GetData(data_path_name=self.param_path).data
            self.access_path = self.param.getroot().find('body').find('beamlet_source').text
            self.key = key
            self.components = utility.getdata.GetData(data_path_name=self.access_path, data_key=self.key).data
            self.profiles = utility.getdata.GetData(data_path_name=self.access_path, data_key=self.key).data
            self.atomic_db = AtomicDB(param=self.param, components=self.components)
            self.title = None
        else:
            self.param = beamlet.param
            self.profiles = beamlet.profiles
            self.components = beamlet.components
            self.atomic_db = beamlet.atomic_db

    def set_x_range(self, x_min=None, x_max=None):
        self.x_limits = [x_min, x_max]

    def plot_RENATE_bechmark(self, plot_type='population'):
        fig1 = matplotlib.pyplot.figure()
        grid = matplotlib.pyplot.GridSpec(3, 1)
        ax1 = matplotlib.pyplot.subplot(grid[0, 0])
        ax1 = self.__setup_density_axis(ax1)
        ax2 = ax1.twinx()
        self.__setup_temperature_axis(ax2)
        self.title = 'Plasma profiles'
        ax1.set_title(self.title)
        self.__setup_RENATE_benchmark_axis(matplotlib.pyplot.subplot(grid[1:, 0]), plot_type)
        matplotlib.pyplot.show()

    def __setup_RENATE_benchmark_axis(self, axis, plot_type):
        max_val = self.profiles['level ' + self.atomic_db.inv_atomic_dict[0]][0]
        for level in self.atomic_db.atomic_dict.keys():
            if plot_type == 'population':
                axis.plot(self.profiles['beamlet grid'], self.profiles['RENATE level ' +
                          str(self.atomic_db.atomic_dict[level])], '-', label='RENATE '+level)
                axis.plot(self.profiles['beamlet grid'], self.profiles['level '+level]/max_val,
                          '--', label='ROD '+level)
                axis.set_ylabel('Relative electron population [-]')
                axis.set_yscale('log', nonposy='clip')
            elif plot_type == 'error':
                axis.set_ylabel('Relative error [-]')
                axis.plot(self.profiles['beamlet grid'], abs(self.profiles['level '+level]/max_val -
                          self.profiles['RENATE level ' + str(self.atomic_db.atomic_dict[level])]) /
                          (self.profiles['level '+level]/max_val), '--', label='Level '+level)
            else:
                raise ValueError('Grid type ' + plot_type + 'not implemented!')
        if hasattr(self, 'x_limits'):
            axis.set_xlim(self.x_limits)
        axis.legend(loc='best', ncol=1)
        self.title = 'Benchmark: RENATE - ROD'
        axis.set_title(self.title)
        axis.grid()
        return axis

    def plot_linear_emission_density(self, from_level=None, to_level=None):
        axis_dens = matplotlib.pyplot.subplot()
        self.__setup_density_axis(axis_dens)
        axis_dens.set_xlabel('Distance [m]')
        axis_em = axis_dens.twinx()
        if from_level is None or to_level is None or not isinstance(from_level, str) or not isinstance(to_level, str):
            from_level, to_level, ground_level, transition = self.atomic_db.set_default_atomic_levels()
        else:
            transition = from_level + '-' + to_level
        self.__setup_linear_emission_density_axis(axis_em, transition)
        matplotlib.pyplot.show()

    def __setup_linear_emission_density_axis(self, axis, transition):
        try:
            axis.plot(self.profiles['beamlet grid'], self.profiles[transition],
                      label='Emission for '+transition, color='r')
        except KeyError:
            raise Exception('The requested transition: <'+transition+'> is not in the stored data. '
                            'Try computing it first or please make sure it exists')
        axis.set_ylabel('Linear emission density [ph/sm]')
        axis.yaxis.label.set_color('r')
        axis.legend(loc='upper right')
        return axis

    def plot_attenuation(self):
        axis_dens = matplotlib.pyplot.subplot()
        self.__setup_density_axis(axis_dens)
        axis_dens.set_xlabel('Distance [m]')
        axis_em = axis_dens.twinx()
        self.__setup_linear_density_attenuation_axis(axis_em)
        matplotlib.pyplot.show()

    def __setup_linear_density_attenuation_axis(self, axis):
        axis.plot(self.profiles['beamlet grid'], self.profiles['linear_density_attenuation'],
                  label='Linear density attenuation', color='r')
        axis.set_ylabel('Linear density [1/m]')
        axis.yaxis.label.set_color('r')
        axis.legend(loc='upper right')
        return axis

    def plot_relative_populations(self):
        axis = matplotlib.pyplot.subplot()
        self.__setup_population_axis(axis, kind='relative')
        matplotlib.pyplot.show()

    def plot_populations(self):
        axis = matplotlib.pyplot.subplot()
        self.__setup_population_axis(axis)
        matplotlib.pyplot.show()

    def plot_all_profiles(self):
        fig1 = matplotlib.pyplot.figure()
        grid = matplotlib.pyplot.GridSpec(3, 1)
        ax1 = matplotlib.pyplot.subplot(grid[0, 0])
        ax1 = self.__setup_density_axis(ax1)
        ax2 = ax1.twinx()
        self.__setup_temperature_axis(ax2)
        self.title = 'Plasma profiles'
        ax1.set_title(self.title)
        ax3 = matplotlib.pyplot.subplot(grid[1:, 0])
        self.__setup_population_axis(ax3)
        fig1.tight_layout()
        matplotlib.pyplot.show()

    def benchmark(self, benchmark_param_path='../data/beamlet/IMAS_beamlet_test_profiles_Li.xml', key=['profiles']):
        benchmark_param = utility.getdata.GetData(data_path_name=benchmark_param_path).data
        benchmark_path = benchmark_param.getroot().find('body').find('beamlet_profiles').text
        benchmark_profiles = utility.getdata.GetData(data_path_name=benchmark_path, data_key=key).data
        fig1 = matplotlib.pyplot.figure()
        ax1 = matplotlib.pyplot.subplot()
        ax1 = self.__setup_population_axis(ax1)
        ax1 = self.setup_benchmark_axis(benchmark_profiles, axis=ax1)
        ax1.legend(loc='best', ncol=2)
        self.title = 'Beamlet profiles - benchmark'
        ax1.set_title(self.title)
        ax1.grid()
        fig1.tight_layout()
        matplotlib.pyplot.show()

    def __setup_density_axis(self, axis):
        for comp in self.components.T.keys():
            axis.plot(self.profiles['beamlet grid'], self.profiles[str(comp)]
                      ['density']['m-3'], label=str(comp))
        if hasattr(self, 'x_limits'):
            axis.set_xlim(self.x_limits)
        axis.set_ylabel('Density [1/m3]')
        axis.yaxis.label.set_color('b')
        axis.legend(loc='upper left')
        axis.grid()
        return axis

    def __setup_temperature_axis(self, axis):
        axis.plot(self.profiles['beamlet grid'], self.profiles['electron']['temperature']['eV'], '--', color='r',
                  label='Electron_temperature')
        axis.plot(self.profiles['beamlet grid'], self.profiles['ion1']['temperature']['eV'], '--',
                  label='Ion_temperature', color='m')
        axis.set_ylabel('Temperature [eV]')
        axis.yaxis.label.set_color('r')
        axis.legend(loc='lower right')
        axis.grid()
        return axis

    def __setup_population_axis(self, axis, kind='absolute'):
        pandas_key, axis_name = self.set_axis_parameters(kind)
        for level in range(self.atomic_db.atomic_ceiling):
            label = pandas_key + self.atomic_db.inv_atomic_dict[level]
            axis.plot(self.profiles['beamlet grid'], self.profiles[label], label=label)
        if hasattr(self, 'x_limits'):
            axis.set_xlim(self.x_limits)
        axis.set_yscale('log', nonposy='clip')
        axis.set_xlabel('Distance [m]')
        axis.set_ylabel(axis_name)
        axis.legend(loc='best', ncol=1)
        self.title = 'Beamlet profiles'
        axis.set_title(self.title)
        axis.grid()
        return axis

    @staticmethod
    def set_axis_parameters(kind):
        assert isinstance(kind, str)
        if kind == 'absolute':
            return 'level ', 'Linear density [1/m]'
        elif kind == 'relative':
            return 'rel.pop ', 'Relative linear density [-]'
        else:
            raise ValueError('Requested plotting format not accepted')

    def setup_benchmark_axis(self, benchmark_profiles, axis):
        benchmark_profiles = benchmark_profiles
        for level in range(self.atomic_db.atomic_ceiling):
            label = 'level ' + str(level)
            axis.plot(benchmark_profiles['beamlet grid'], benchmark_profiles[label], '--', label=label+' ref.')
        return axis

    def save_figure(self, file_path='data/output/beamlet/test_plot.pdf'):
        with PdfPages(file_path) as pdf:
            pdf.savefig()
            d = pdf.infodict()
            d['Title'] = self.title
            d['Keywords'] = 'Source hdf5 file: ' + self.access_path + ', source xml file: ' + self.param_path
            d['ModDate'] = datetime.datetime.today()