示例#1
0
    def test_absorption_spectrum_non_cosmo(self):
        """
        This test generates an absorption spectrum from a simple light ray on a
        grid dataset
        """

        lr = LightRay(COSMO_PLUS_SINGLE)

        ray_start = [0,0,0]
        ray_end = [1,1,1]
        lr.make_light_ray(start_position=ray_start, end_position=ray_end,
                          fields=[('gas', 'temperature'),
                                  ('gas', 'density'),
                                  ('gas', 'H_p0_number_density')],
                          data_filename='lightray.h5')

        sp = AbsorptionSpectrum(1200.0, 1300.0, 10001)

        my_label = 'HI Lya'
        field = ('gas', 'H_p0_number_density')
        wavelength = 1215.6700  # Angstromss
        f_value = 4.164E-01
        gamma = 6.265e+08
        mass = 1.00794

        sp.add_line(my_label, field, wavelength, f_value,
                    gamma, mass, label_threshold=1.e10)

        filename = "spectrum.h5"
        wavelength, flux = sp.make_spectrum('lightray.h5',
                                            output_file=filename,
                                            output_absorbers_file='lines.txt',
                                            use_peculiar_velocity=True)
        return filename
示例#2
0
    def __init__(self,
                 instrument=None,
                 lambda_min=None,
                 lambda_max=None,
                 n_lambda=None,
                 dlambda=None,
                 lsf_kernel=None,
                 line_database='lines.txt',
                 ionization_table=None,
                 bin_space='wavelength'):
        if instrument is None and \
          ((lambda_min is None or lambda_max is None) or \
           (dlambda is None and n_lambda is None)):
            instrument = 'COS'
            mylog.info(
                "No parameters specified, defaulting to COS instrument.")
        elif instrument is None:
            instrument = Instrument(lambda_min=lambda_min,
                                    lambda_max=lambda_max,
                                    n_lambda=n_lambda,
                                    dlambda=dlambda,
                                    lsf_kernel=lsf_kernel,
                                    name="Custom",
                                    bin_space=bin_space)
        self.observing_redshift = 0.
        self._set_instrument(instrument)
        mylog.info("Setting instrument to %s" % self.instrument.name)
        self.dlambda = self.instrument.dlambda

        AbsorptionSpectrum.__init__(self,
                                    self.instrument.lambda_min,
                                    self.instrument.lambda_max,
                                    n_lambda=self.instrument.n_lambda,
                                    dlambda=self.instrument.dlambda,
                                    bin_space=bin_space)

        if isinstance(line_database, LineDatabase):
            self.line_database = line_database
        else:
            # instantiate the LineDatabase
            self.line_database = LineDatabase(line_database)

        # Instantiate the spectrum to be zeros and ones for tau_field and
        # flux_field respectively.
        self.clear_spectrum()

        if ionization_table is not None:
            # figure out where the user-specified files lives
            if os.path.isfile(ion_table_file):
                self.ionization_table = ion_table_file
            elif os.path.isfile(ion_table_filepath):
                self.ionization_table = ion_table_filepath
            else:
                raise RuntimeError(
                    "ionization_table %s is not found in local "
                    "directory or in %s" %
                    (ion_table_file.split(os.sep)[-1], ion_table_dir))
        else:
            self.ionization_table = None
示例#3
0
    def test_equivalent_width_conserved(self):
        """
        This tests that the equivalent width of the optical depth is conserved 
        regardless of the bin width employed in wavelength space.
        Unresolved lines should still deposit optical depth into the spectrum.
        """

        lr = LightRay(COSMO_PLUS_SINGLE)

        ray_start = [0, 0, 0]
        ray_end = [1, 1, 1]
        lr.make_light_ray(
            start_position=ray_start,
            end_position=ray_end,
            fields=['temperature', 'density', 'H_number_density'],
            data_filename='lightray.h5')

        my_label = 'HI Lya'
        field = 'H_number_density'
        wave = 1215.6700  # Angstromss
        f_value = 4.164E-01
        gamma = 6.265e+08
        mass = 1.00794

        lambda_min = 1200
        lambda_max = 1300
        lambda_bin_widths = [1e-3, 1e-2, 1e-1, 1e0, 1e1]
        total_tau = []

        for lambda_bin_width in lambda_bin_widths:
            n_lambda = ((lambda_max - lambda_min) / lambda_bin_width) + 1
            sp = AbsorptionSpectrum(lambda_min=lambda_min,
                                    lambda_max=lambda_max,
                                    n_lambda=n_lambda)
            sp.add_line(my_label, field, wave, f_value, gamma, mass)
            wavelength, flux = sp.make_spectrum('lightray.h5')
            total_tau.append((lambda_bin_width * sp.tau_field).sum())

        # assure that the total tau values are all within 1e-3 of each other
        for tau in total_tau:
            assert_almost_equal(tau, total_tau[0], 3)
示例#4
0
    def test_absorption_spectrum_with_continuum(self):
        """
        This test generates an absorption spectrum from a simple light ray on a
        grid dataset and adds Lyman alpha and Lyman continuum to it
        """

        ds = load(ISO_GALAXY)
        lr = LightRay(ds)

        ray_start = ds.domain_left_edge
        ray_end = ds.domain_right_edge
        lr.make_light_ray(
            start_position=ray_start,
            end_position=ray_end,
            fields=['temperature', 'density', 'H_number_density'],
            data_filename='lightray.h5')

        sp = AbsorptionSpectrum(800.0, 1300.0, 5001)

        my_label = 'HI Lya'
        field = 'H_number_density'
        wavelength = 1215.6700  # Angstromss
        f_value = 4.164E-01
        gamma = 6.265e+08
        mass = 1.00794

        sp.add_line(my_label,
                    field,
                    wavelength,
                    f_value,
                    gamma,
                    mass,
                    label_threshold=1.e10)

        my_label = 'Ly C'
        field = 'H_number_density'
        wavelength = 912.323660  # Angstroms
        normalization = 1.6e17
        index = 3.0

        sp.add_continuum(my_label, field, wavelength, normalization, index)

        filename = "spectrum.h5"
        wavelength, flux = sp.make_spectrum('lightray.h5',
                                            output_file=filename,
                                            line_list_file='lines.txt',
                                            use_peculiar_velocity=True)
        return filename
示例#5
0
    def test_absorption_spectrum_cosmo(self):
        """
        This test generates an absorption spectrum from a compound light ray on a
        grid dataset
        """

        lr = LightRay(COSMO_PLUS, 'Enzo', 0.0, 0.03)

        lr.make_light_ray(
            seed=1234567,
            fields=['temperature', 'density', 'H_number_density'],
            data_filename='lightray.h5')

        sp = AbsorptionSpectrum(900.0, 1800.0, 10000)

        my_label = 'HI Lya'
        field = 'H_number_density'
        wavelength = 1215.6700  # Angstromss
        f_value = 4.164E-01
        gamma = 6.265e+08
        mass = 1.00794

        sp.add_line(my_label,
                    field,
                    wavelength,
                    f_value,
                    gamma,
                    mass,
                    label_threshold=1.e10)

        my_label = 'HI Lya'
        field = 'H_number_density'
        wavelength = 912.323660  # Angstroms
        normalization = 1.6e17
        index = 3.0

        sp.add_continuum(my_label, field, wavelength, normalization, index)

        filename = "spectrum.h5"
        wavelength, flux = sp.make_spectrum('lightray.h5',
                                            output_file=filename,
                                            line_list_file='lines.txt',
                                            use_peculiar_velocity=True)
        return filename
示例#6
0
    def test_absorption_spectrum_fits(self):
        """
        This test generates an absorption spectrum and saves it as a fits file.
        """

        lr = LightRay(COSMO_PLUS_SINGLE)

        ray_start = [0, 0, 0]
        ray_end = [1, 1, 1]
        lr.make_light_ray(
            start_position=ray_start,
            end_position=ray_end,
            fields=['temperature', 'density', 'H_number_density'],
            data_filename='lightray.h5')

        sp = AbsorptionSpectrum(900.0, 1800.0, 10000)

        my_label = 'HI Lya'
        field = 'H_number_density'
        wavelength = 1215.6700  # Angstromss
        f_value = 4.164E-01
        gamma = 6.265e+08
        mass = 1.00794

        sp.add_line(my_label,
                    field,
                    wavelength,
                    f_value,
                    gamma,
                    mass,
                    label_threshold=1.e10)

        my_label = 'HI Lya'
        field = 'H_number_density'
        wavelength = 912.323660  # Angstroms
        normalization = 1.6e17
        index = 3.0

        sp.add_continuum(my_label, field, wavelength, normalization, index)

        wavelength, flux = sp.make_spectrum('lightray.h5',
                                            output_file='spectrum.fits',
                                            line_list_file='lines.txt',
                                            use_peculiar_velocity=True)
示例#7
0
    def test_absorption_spectrum_with_zero_field(self):
        """
        This test generates an absorption spectrum with some 
        particle dataset
        """

        ds = load(FIRE)
        lr = LightRay(ds)

        # Define species and associated parameters to add to continuum
        # Parameters used for both adding the transition to the spectrum
        # and for fitting
        # Note that for single species that produce multiple lines
        # (as in the OVI doublet), 'numLines' will be equal to the number
        # of lines, and f,gamma, and wavelength will have multiple values.

        HI_parameters = {
            'name': 'HI',
            'field': 'H_number_density',
            'f': [.4164],
            'Gamma': [6.265E8],
            'wavelength': [1215.67],
            'mass': 1.00794,
            'numLines': 1,
            'maxN': 1E22,
            'minN': 1E11,
            'maxb': 300,
            'minb': 1,
            'maxz': 6,
            'minz': 0,
            'init_b': 30,
            'init_N': 1E14
        }

        species_dicts = {'HI': HI_parameters}

        # Get all fields that need to be added to the light ray
        fields = [('gas', 'temperature')]
        for s, params in species_dicts.items():
            fields.append(params['field'])

        # With a single dataset, a start_position and
        # end_position or trajectory must be given.
        # Trajectory should be given as (r, theta, phi)
        lr.make_light_ray(start_position=ds.arr([0., 0., 0.], 'unitary'),
                          end_position=ds.arr([1., 1., 1.], 'unitary'),
                          solution_filename='test_lightraysolution.txt',
                          data_filename='test_lightray.h5',
                          fields=fields)

        # Create an AbsorptionSpectrum object extending from
        # lambda = 900 to lambda = 1800, with 10000 pixels
        sp = AbsorptionSpectrum(900.0, 1400.0, 50000)

        # Iterate over species
        for s, params in species_dicts.items():
            # Iterate over transitions for a single species
            for i in range(params['numLines']):
                # Add the lines to the spectrum
                sp.add_line(s,
                            params['field'],
                            params['wavelength'][i],
                            params['f'][i],
                            params['Gamma'][i],
                            params['mass'],
                            label_threshold=1.e10)

        # Make and save spectrum
        wavelength, flux = sp.make_spectrum('test_lightray.h5',
                                            output_file='test_spectrum.h5',
                                            line_list_file='test_lines.txt',
                                            use_peculiar_velocity=True)
示例#8
0
    def make_spectrum(self,
                      ray,
                      lines='all',
                      output_file=None,
                      use_peculiar_velocity=True,
                      observing_redshift=0.0,
                      ly_continuum=True,
                      store_observables=False,
                      min_tau=1e-3,
                      njobs="auto"):
        """
        Make a spectrum from ray data depositing the desired lines.  Make sure
        to pass this function a LightRay object and potentially also a list of
        strings representing what lines you'd like to actually have be
        deposited in your final spectrum.

        **Parameters**

        :ray: string or dataset

            Ray dataset filename or a loaded ray dataset

        :lines: list of strings

            List of strings that determine which lines will be added
            to the spectrum.  List can include things like "C", "O VI",
            or "Mg II ####", where #### would be the integer wavelength
            value of the desired line.  If set to 'all', includes all lines
            in LineDatabase set in SpectrumGenerator.
            Default: 'all'

        :output_file: optional, string

            Filename of output if you wish to save the spectrum immediately
            without any further processing. File formats are chosen based on the
            filename extension.  ".h5" for HDF5, ".fits" for FITS,
            and everything else is ASCII.  Equivalent of calling
            :class:`~trident.SpectrumGenerator.save_spectrum`.
            Default: None

        :use_peculiar_velocity: optional, bool

            If True, include the effects of doppler redshift of the gas
            in shifting lines in the final spectrum.
            Default: True

        :observing_redshift: optional, float

            This is the value of the redshift at which the observer of this
            spectrum exists.  In most cases, this will be a redshift of 0.
            Default: 0.

        :ly_continuum: optional, boolean

            If any H I lines are used in the line list, this assures a
            Lyman continuum will be included in the spectral generation.
            Lyman continuum begins at final Lyman line deposited (Ly 39 =
            912.32 A) not at formal Lyman Limit (911.76 A) so as to not have
            a gap between final Lyman lines and continuum.  Uses power law
            of index 3 and normalization to match opacity of final Lyman lines.
            Default: True

        :store_observables: optional, boolean

            If set to true, observable properties for each cell in the light
            ray will be saved for each line in the line list. Properties
            include the column density, tau, thermal b, and the wavelength
            where tau was deposited. Best applied for a reasonable number
            of lines.
            Default: False

        :min_tau: optional, float
           This value determines size of the wavelength window used to
           deposit lines or continua.  The wavelength window is expanded
           until the optical depth at the edge is below this value.  If too
           high, this will result in features appearing cut off at the edges.
           Decreasing this will make features smoother but will also increase
           run time.  An increase by a factor of ten will result in roughly a
           2x slow down.
           Default: 1e-3.

        :njobs: optional, int or "auto"

            The number of process groups into which the loop over
            absorption lines will be divided.  If set to -1, each
            absorption line will be deposited by exactly one processor.
            If njobs is set to a value less than the total number of
            available processors (N), then the deposition of an
            individual line will be parallelized over (N / njobs)
            processors.  If set to "auto", it will first try to
            parallelize over the list of lines and only parallelize
            the line deposition if there are more processors than
            lines.  This is the optimal strategy for parallelizing
            spectrum generation.
            Default: "auto"

        **Example**

        Make a one zone ray and generate a COS spectrum for it including
        only Oxygen VI, Mg II, and all Carbon lines, and plot to disk.

        >>> import trident
        >>> ray = trident.make_onezone_ray()
        >>> sg = trident.SpectrumGenerator('COS')
        >>> sg.make_spectrum(ray, lines=['O VI', 'Mg II', 'C'])
        >>> sg.plot_spectrum('spec_raw.png')
        """
        self.observing_redshift = observing_redshift

        if isinstance(ray, str):
            ray = load(ray)
        ad = ray.all_data()

        # Clear out any previous spectrum that existed first
        self.clear_spectrum()

        active_lines = self.line_database.parse_subset(lines)

        # Make sure we've produced all the necessary
        # derived fields if they aren't native to the data
        for line in active_lines:
            # if successful, means line.field is in ds.derived_field_list
            try:
                disk_field = ad._determine_fields(line.field)[0]
            # otherwise we probably need to add the field to the dataset
            except:
                my_ion = \
                  line.field[:line.field.find("number_density")]
                on_ion = my_ion.split("_")
                # Add the field if greater than level 1 ionization
                # because there is only one naming convention for these fields:
                # X_pY_number_density
                if on_ion[1]:
                    my_lev = int(on_ion[1][1:]) + 1
                    mylog.info("Creating %s from ray's density, "
                               "temperature, metallicity." % (line.field))
                    add_ion_number_density_field(
                        on_ion[0],
                        my_lev,
                        ray,
                        ionization_table=self.ionization_table)
                # If level 1 ionization, check to see if other name for
                # field is present in dataset
                else:
                    my_lev = 1
                    alias_field = ('gas',
                                   "".join([my_ion, 'p0_number_density']))
                    # Don't add the X_number_density if X_p0_number_density is
                    # in dataset already
                    if alias_field in ray.derived_field_list:
                        line.field = alias_field
                    # But add the field if neither X_number_density nor
                    # X_p0_number_density is in the dataset
                    else:
                        mylog.info("Creating %s from ray's density, "
                                   "temperature, metallicity." % (line.field))
                        add_ion_number_density_field(
                            on_ion[0],
                            my_lev,
                            ray,
                            ionization_table=self.ionization_table)

            self.add_line(line.identifier,
                          line.field,
                          float(line.wavelength),
                          float(line.f_value),
                          float(line.gamma),
                          atomic_mass[line.element],
                          label_threshold=1e3)

        # If there are H I lines present, add a Lyman continuum source
        # Lyman continuum source starts at wavelength where last Lyman line
        # is deposited (Ly 40), as opposed to true Lyman Limit at 911.763 A
        # so there won't be a gap between lines and continuum.  Using
        # power law of index 3.0 and normalization to match the opacity of
        # the final Lyman line into the FUV.
        H_lines = self.line_database.select_lines(source_list=active_lines,
                                                  element='H',
                                                  ion_state='I')
        if (len(H_lines) > 0) and (ly_continuum == True):
            self.add_continuum('Ly C', H_lines[0].field, 912.32336, 1.6e17,
                               3.0)

        AbsorptionSpectrum.make_spectrum(
            self,
            ray,
            output_file=None,
            line_list_file=None,
            use_peculiar_velocity=use_peculiar_velocity,
            observing_redshift=observing_redshift,
            store_observables=store_observables,
            min_tau=min_tau,
            njobs=njobs)
def test_min_greater_than_max():
    with assert_raises(RuntimeError):
        AbsorptionSpectrum(lambda_min=1200, lambda_max=1100, n_lambda=1000)
示例#10
0
def test_n_lambda_with_auto():
    with assert_raises(RuntimeError):
        AbsorptionSpectrum(lambda_min='auto', lambda_max='auto', n_lambda=1000)
示例#11
0
def test_no_n_lambda_or_dlambda():
    with assert_raises(RuntimeError):
        AbsorptionSpectrum(lambda_min=1100, lambda_max=1200)