예제 #1
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)
예제 #2
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)