def ion_count(self, atomic_num, shell_num): """Generates fractional abundance of ions of a specific element and shell, in a form that can be used by a table widget Parameters ---------- atomic_num : int Atomic number of element shell_num : int Shell number (note: starts from 1, not 0 which is what simulation model use) Returns ------- pandas.DataFrame Dataframe containing ion specie and fractional abundance for a specific element, against each ion number """ ion_num_density = self.ion_number_density[shell_num - 1].loc[atomic_num] element_num_density = self.number_density.loc[atomic_num, shell_num - 1] ion_count_data = ion_num_density / element_num_density # Normalization ion_count_data.index.name = "Ion" ion_count_data.fillna(0, inplace=True) return pd.DataFrame( { "Species": ion_count_data.index.map( lambda x: species_tuple_to_string((atomic_num, x)) ), "Frac. Ab. (Z={})".format(atomic_num): ion_count_data.map( "{:.6e}".format ), } )
def get_last_line_counts( self, selected_species, filter_mode=FILTER_MODES[0], group_mode=GROUP_MODES[0], ): """ Get packet counts of each last line interaction of a species. Parameters ---------- selected_species : str Valid symbol of a species (e.g Si II) selected from the species data returned by :code:`get_species_interactions` (see Notes section) filter_mode : str, optional Filter mode of the LastLineInteraction object to use for fetching the data of last lines interacted (more details in Notes section). Allowed values are given by the class variable :code:`FILTER_MODES` (default value is :code:`FILTER_MODES[0]`) group_mode : str, optional Group mode to use for grouping last line interactions by excitation lines, de-excitation lines or both. Allowed values are given by the class variable :code:`GROUP_MODES` (default value is :code:`GROUP_MODES[0]` i.e. both) Returns ------- pd.DataFrame DataFrame containing last line interactions and corresponding packet counts. Notes ----- This method depends on tardis.analysis.LastLineInteraction object for doing computations. So there is a member variable in this class - :code:`line_interaction_analysis` which is a dictionary of such objects (each of them differ in how they filter the selected wavelength range). Thus we have to specify which object to use by specifying the filter_mode parameter. This method should always be called after calling :code:`get_species_interactions` method which sets a wavelength range on LastLineInteraction object. So selected_species should be one present within that range, otherwise it will result an error. """ if selected_species: selected_species_tuple = species_string_to_tuple(selected_species) try: # Get selected species' rows from last_line_in dataframe current_last_lines_in = ( self.line_interaction_analysis[filter_mode].last_line_in. xs( key=selected_species_tuple, level=["atomic_number", "ion_number"], drop_level=False, ).reset_index()) # Get selected species' rows from last_line_out dataframe current_last_lines_out = ( self.line_interaction_analysis[filter_mode].last_line_out. xs( key=selected_species_tuple, level=["atomic_number", "ion_number"], drop_level=False, ).reset_index()) assert (current_last_lines_in.empty & current_last_lines_out.empty == False) except (KeyError, AssertionError): # selected_species is invalid allowed_species = [ species_tuple_to_string(species) for species in self.line_interaction_analysis[filter_mode]. last_line_in.groupby(["atomic_number", "ion_number" ]).groups.keys() ] raise ValueError( "Invalid value of selected_species, it must be one present " "within the currently selected wavelength range in your " f"LineInfoWidget instance, which are {allowed_species}") last_line_interaction_string = [] interacting_packets_count = [] if group_mode == "both": # Group by both exc. line ids and de-exc. line ids current_last_lines_in[ "line_id_out"] = current_last_lines_out.line_id grouped_line_interactions = current_last_lines_in.groupby( ["line_id", "line_id_out"]) # Iterate over each group's key and size and append them to list for ( line_id, count, ) in grouped_line_interactions.size().iteritems(): current_line_in = self.lines_data.loc[line_id[0]] current_line_out = self.lines_data.loc[line_id[1]] last_line_interaction_string.append( f"exc. {int(current_line_in.level_number_lower):02d}-" f"{int(current_line_in.level_number_upper):02d} " f"({current_line_in.wavelength:.2f} A) " f"de-exc. {int(current_line_out.level_number_upper):02d}-" f"{int(current_line_out.level_number_lower):02d} " f"({current_line_out.wavelength:.2f} A)") interacting_packets_count.append(count) elif group_mode == "exc": grouped_line_interactions = current_last_lines_in.groupby( "line_id") # Iterate over each group's key and size and append them to list for ( line_id, count, ) in grouped_line_interactions.size().iteritems(): current_line_in = self.lines_data.loc[line_id] last_line_interaction_string.append( f"exc. {int(current_line_in.level_number_lower):02d}-" f"{int(current_line_in.level_number_upper):02d} " f"({current_line_in.wavelength:.2f} A)") interacting_packets_count.append(count) elif group_mode == "de-exc": grouped_line_interactions = current_last_lines_out.groupby( "line_id") # Iterate over each group's key and size and append them to list for ( line_id, count, ) in grouped_line_interactions.size().iteritems(): current_line_out = self.lines_data.loc[line_id] last_line_interaction_string.append( f"de-exc. {int(current_line_out.level_number_upper):02d}-" f"{int(current_line_out.level_number_lower):02d} " f"({current_line_out.wavelength:.2f} A)") interacting_packets_count.append(count) else: raise ValueError( "Invalid value passed to group_mode argument. " f"Allowed values are {self.GROUP_MODES}") else: # species_selected is None # qgrid cannot show empty dataframe properly, # so create one row with empty strings interacting_packets_count = [""] last_line_interaction_string = [""] last_line_counts = pd.Series(interacting_packets_count) last_line_counts.name = "No. of packets" last_line_counts.index = pd.Index(last_line_interaction_string, name="Last Line Interaction") return last_line_counts.sort_values(ascending=False).to_frame()
def get_species_interactions(self, wavelength_range, filter_mode=FILTER_MODES[0]): """ Get fractional species interactions in specified wavelength range. Fractional species interactions means fraction of packets present in the specified wavelength range which experienced their last interaction with a species. The packets to consider are filtered by the specified filter mode. Parameters ---------- wavelength_range : list-like or None A list of two float values to specify the wavelength range - first for the range start and second for the range end. None specifies that no wavelength range is selected and will return empty dataframe filter_mode : str, optional Filter mode of the LastLineInteraction object to use for filtering the selected wavelength range (more details in Notes section). Allowed values are given by the class variable :code:`FILTER_MODES` (default value is :code:`FILTER_MODES[0]`) Returns ------- pandas.DataFrame Dataframe containing species symbols and corresponding fractions of packets interacting with them Notes ----- This method depends on tardis.analysis.LastLineInteraction object for doing computations. So there is a member variable in this class - :code:`line_interaction_analysis` which is a dictionary of such objects (each of them differ in how they filter the selected wavelength range). Thus we have to specify which object to use by specifying the filter_mode parameter. """ if wavelength_range: self.line_interaction_analysis[filter_mode].wavelength_start = ( wavelength_range[0] * u.AA) self.line_interaction_analysis[filter_mode].wavelength_end = ( wavelength_range[1] * u.AA) # Obtain species group from last_line_in dataframe selected_species_group = self.line_interaction_analysis[ filter_mode].last_line_in.groupby( ["atomic_number", "ion_number"]) if selected_species_group.groups: selected_species_symbols = [ species_tuple_to_string(item) for item in selected_species_group.groups.keys() ] # Normalize each group's count to find fractions of interactions fractional_species_interactions = ( selected_species_group.size() / self.line_interaction_analysis[filter_mode].last_line_in. shape[0]) else: # No species could be selected in specified wavelength_range # qgrid cannot show empty dataframe properly, # so create one row with empty strings selected_species_symbols = [""] fractional_species_interactions = pd.Series([""]) else: # wavelength_range is None selected_species_symbols = [""] fractional_species_interactions = pd.Series([""]) fractional_species_interactions.index = pd.Index( selected_species_symbols, name="Species") fractional_species_interactions.name = "Fraction of packets interacting" return fractional_species_interactions.sort_values( ascending=False).to_frame()
def test_species_tuple_to_string(species_tuple, roman_numerals, species_string): assert species_tuple_to_string( species_tuple, roman_numerals=roman_numerals) == species_string
def test_species_tuple_to_string(species_tuple, roman_numerals, species_string): assert species_tuple_to_string(species_tuple, roman_numerals=roman_numerals) == species_string