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 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)
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 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.' )
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.')
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.' )
def setUp(self): param, components = self.build_atomic_input() self.atomic_db = AtomicDB(param=param, components=components)
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)
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()