示例#1
0
    def __init__(self,
                 element,
                 ion_state,
                 wavelength,
                 gamma,
                 f_value,
                 field=None,
                 identifier=None):
        self.element = element
        self.ion_state = ion_state
        self.wavelength = float(wavelength)
        self.gamma = float(gamma)
        self.f_value = float(f_value)
        self.name = '%s %s %d' % (element, ion_state,
                                  round(float(wavelength), 0))
        if identifier is None:
            identifier = self.name
        self.identifier = identifier

        # Automatically populate the field if not defined
        if field is None:
            ion_number = from_roman(ion_state)
            keyword = "%s_p%d" % (element, (ion_number - 1))
            field = "%s_number_density" % keyword
        self.field = field
示例#2
0
def _determine_ions_from_lines(line_database, lines):
    """
    Figure out what ions are necessary to produce the desired lines
    """
    if line_database is not None:
        line_database = LineDatabase(line_database)
        ion_list = line_database.parse_subset_to_ions(lines)
    else:
        ion_list = []
        if lines == 'all' or lines == ['all']:
            for k,v in six.iteritems(atomic_number):
                for j in range(v+1):
                    ion_list.append((k, j+1))
        else:
            for line in lines:
                linen = line.split()
                if len(linen) >= 2:
                    ion_list.append((linen[0], from_roman(linen[1])))
                elif len(linen) == 1:
                    num_states = atomic_number[linen[0]]
                    for j in range(num_states+1):
                        ion_list.append((linen[0], j+1))
                else:
                    raise RuntimeError("Cannot add a blank ion.")

    return uniquify(ion_list)
示例#3
0
    def parse_subset_to_ions(self, subsets=None):
        """
        Select ions based on those needed to create specific lines.
        Once you've created a LineDatabase, you can subselect
        certain ions from it based on the line characteristics of atom,
        ion state, identifier, and/or wavelength.  Similar to
        :class:`~trident.LineDatabase.parse_subset` but outputs a list of
        ion tuples (e.g. ('H', 1), ('Fe', 2)), instead of a list of
        :class:`~trident.Line` objects.

        Will return the unique union of all ions matching the specified
        subsets from the :class:`~trident.LineDatabase`.

        **Parameters**

        :subsets: list of strings, optional

            List strings matching possible lines.  Strings can be of the
            form:
            * Atom - Examples: "H", "C", "Mg"
            * Ion - Examples: "H I", "H II", "C IV", "Mg II"
            * Line - Examples: "H I 1216", "C II 1336", "Mg II 1240"
            * Identifier - Examples: "Ly a", "Ly b"

            If set to None, selects ions necessary to produce **all** lines
            in :class:`~trident.LineDatabase`.
            Default: None

        **Returns**

        :ion subset: list of ion tuples

            A list of the ions necessary to produce the desired lines
            Each ion tuple is of the form ('H', 1) = neutral hydrogen

        **Example**

        Get a list of all ions necessary to generate lines for Carbon,
        Mg II and Lyman alpha

        >>> ldb = LineDatabase('lines.txt')
        >>> ions = ldb.parse_subset_to_ions(['C', 'Mg II', 'H I 1216'])
        >>> print(ions)
        """
        self.parse_subset(subsets)
        ions = []
        for line in self.lines_subset:
            ions.append((line.element, from_roman(line.ion_state)))
        ions = uniquify(ions)
        return ions
示例#4
0
def add_ion_fields(ds,
                   ions,
                   ftype='gas',
                   ionization_table=None,
                   field_suffix=False,
                   line_database=None,
                   sampling_type='local',
                   particle_type=None):
    """
    Preferred method for adding ion fields to a yt dataset.

    Select ions based on the selection indexing set up in
    :class:`~trident.LineDatabase.parse_subset_to_ions` function, that is,
    by specifying a list of strings where each string represents an ion or
    line.  Strings are of one of three forms:

        * <element>
        * <element> <ion state>
        * <element> <ion state> <line_wavelength>

    If a line_database is selected, then the ions chosen will be a subset
    of the ions present in the equivalent :class:`~trident.LineDatabase`,
    nominally located in ``trident.__path__/data/line_lists``.

    For each ion species selected, four fields will be added (example for
    Mg II):

        * Ion fraction field. e.g. ("gas", 'Mg_p1_ion_fraction')
        * Number density field. e.g. ("gas", 'Mg_p1_number_density')
        * Density field. e.g. ("gas", 'Mg_p1_density')
        * Mass field. e.g. ("gas", 'Mg_p1_mass')

    This function is the preferred method for adding ion fields to one's
    dataset, but for more fine-grained control, one can also employ the
    :class:`~trident.add_ion_fraction_field`,
    :class:`~trident.add_ion_number_density_field`,
    :class:`~trident.add_ion_density_field`,
    :class:`~trident.add_ion_mass_field` functions individually.

    Fields are added assuming collisional ionization equilibrium and
    photoionization in the optically thin limit from a redshift-dependent
    metagalactic ionizing background using the ionization_table specified.

    **Parameters**

    :ds: yt dataset object

        This is the dataset to which the ion fraction field will be added.

    :ions: list of strings

            List of strings matching possible lines.  Strings can be of the
            form:
            * Atom - Examples: "H", "C", "Mg"
            * Ion - Examples: "H I", "H II", "C IV", "Mg II"
            * Line - Examples: "H I 1216", "C II 1336", "Mg II 1240"

            If set to 'all', creates **all** ions for the first 30 elements:
            (ie hydrogen to zinc).  If set to 'all' with ``line_database``
            keyword set, then creates **all** ions associated with the lines
            specified in the equivalent :class:`~trident.LineDatabase`.

    :ionization_table: string, optional

        Path to an appropriately formatted HDF5 table that can be used to
        compute the ion fraction as a function of density, temperature,
        metallicity, and redshift.  When set to None, it uses the table
        specified in ~/.trident/config
        Default: None

    :field_suffix: boolean, optional

        Determines whether or not to append a suffix to the field name that
        indicates what ionization table was used.  Useful when using generating
        ion_fields that already exist in a dataset.

    :line_database: string, optional

        Ions are selected out of the set of ions present in the line_database
        constructed from the line list filename specified here.  See
        :class:`~trident.LineDatabase` for more information.

    :ftype: string, optional

        This is deprecated and no longer necessary since all relevant
        fields are aliased to the 'gas' ftype.
        Default: 'gas'

    :sampling_type: string, optional

        This is deprecated and no longer necessary.
        Default: 'local'

    :particle_type: boolean, optional

        This is deprecated and no longer necessary.
        Default: 'auto'

    **Example**

    To add ionized hydrogen, doubly-ionized Carbon, and all of the Magnesium
    species fields to a dataset, you would run:

    >>> import yt
    >>> import trident
    >>> ds = yt.load('path/to/file')
    >>> trident.add_ion_fields(ds, ions=['H II', 'C III', 'Mg'])
    """
    ion_list = []

    if ionization_table is None:
        ionization_table = ion_table_filepath

    # Parse the ions given following the LineDatabase syntax

    # If line_database is set, then use the underlying file as the line list
    # to select ions from.
    if line_database is not None:
        line_database = LineDatabase(line_database)
        ion_list = line_database.parse_subset_to_ions(ions)

    # Otherwise, any ion can be selected (not just ones in the line list).
    else:
        if ions == 'all' or ions == ['all']:
            for k, v in atomic_number.items():
                for j in range(v + 1):
                    ion_list.append((k, j + 1))
        else:
            for ion in ions:
                ionn = ion.split()
                if len(ionn) >= 2:
                    ion_list.append((ionn[0], from_roman(ionn[1])))
                elif len(ionn) == 1:
                    num_states = atomic_number[ionn[0]]
                    for j in range(num_states + 1):
                        ion_list.append((ionn[0], j + 1))
                else:
                    raise RuntimeError("Cannot add a blank ion.")

    # make sure ion list is unique
    ion_list = uniquify(ion_list)

    # adding X_p#_ion_mass field triggers the addition of:
    # - X_P#_ion_fraction
    # - X_P#_number_density
    # - X_P#_density
    for (atom, ion) in ion_list:
        add_ion_mass_field(atom,
                           ion,
                           ds,
                           ftype,
                           ionization_table,
                           field_suffix=field_suffix,
                           sampling_type=sampling_type)