species.util.phot_util — species 0.1.2 documentation

# Source code for species.util.phot_util

    """
    Utility functions for photometry.
    """

    import spectres
    import numpy as np

    from species.core import box
    from species.read import read_model, read_calibration, read_filter, read_planck

    def multi_photometry(datatype,
                         spectrum,
                         filters,
                         parameters):
        """
        Parameters
        ----------
        datatype : str
            Data type ('model' or 'calibration').
        spectrum : str
            Spectrum name (e.g., 'drift-phoenix').
        filters : tuple(str, )
            Filter IDs.
        parameters : dict
            Parameters and values for the spectrum

        Returns
        -------
        species.core.box.SynphotBox
            Box with synthetic photometry.
        """

        print('Calculating synthetic photometry...', end='', flush=True)

        flux = {}

        if datatype == 'model':
            for item in filters:
                if spectrum == 'planck':
                    readmodel = read_planck.ReadPlanck(filter_name=item)
                else:
                    readmodel = read_model.ReadModel(spectrum, filter_name=item)

                flux[item] = readmodel.get_flux(parameters)

        elif datatype == 'calibration':
            for item in filters:
                readcalib = read_calibration.ReadCalibration(spectrum, filter_name=item)
                flux[item] = readcalib.get_flux(parameters)

        print(' [DONE]')

        return box.create_box('synphot', name='synphot', flux=flux)

    def apparent_to_absolute(app_mag,
                             distance):
        """
        Parameters
        ----------
        app_mag : float or numpy.ndarray
            Apparent magnitude (mag).
        distance : float or numpy.ndarray
            Distance (pc).

        Returns
        -------
        float or numpy.ndarray
            Absolute magnitude (mag).
        """

        return app_mag - 5.*np.log10(distance) + 5.

    def get_residuals(datatype,
                      spectrum,
                      parameters,
                      filters,
                      objectbox,
                      inc_phot=True,
                      inc_spec=False):
        """
        Parameters
        ----------
        datatype : str
            Data type ('model' or 'calibration').
        spectrum : str
            Name of the atmospheric model or calibration spectrum.
        parameters : dict
            Parameters and values for the spectrum
        filters : tuple(str, )
            Filter IDs. All available photometry of the object is used if set to None.
        objectbox : species.core.box.ObjectBox
            Box with the photometry and/or spectrum of an object.
        inc_phot : bool
            Include photometry.
        inc_spec : bool
            Include spectrum.

        Returns
        -------
        species.core.box.ResidualsBox
            Box with the photometry and/or spectrum residuals.
        """

        if filters is None:
            filters = objectbox.filters

        if inc_phot:
            model_phot = multi_photometry(datatype=datatype,
                                          spectrum=spectrum,
                                          filters=filters,
                                          parameters=parameters)

            res_phot = np.zeros((2, len(objectbox.flux)))

            for i, item in enumerate(filters):
                transmission = read_filter.ReadFilter(item)

                res_phot[0, i] = transmission.mean_wavelength()
                res_phot[1, i] = (objectbox.flux[item][0]-model_phot.flux[item])/objectbox.flux[item][1]

        else:
            res_phot = None

        print('Calculating residuals...', end='', flush=True)

        if inc_spec:
            wavel_range = (0.9*objectbox.spectrum[0, 0], 1.1*objectbox.spectrum[-1, 0])

            if spectrum == 'planck':
                readmodel = read_planck.ReadPlanck(wavel_range=wavel_range)
                model = readmodel.get_spectrum(model_param=parameters, spec_res=1000.)

            else:
                readmodel = read_model.ReadModel(spectrum, wavel_range=wavel_range)
                model = readmodel.get_model(model_param=parameters, spec_res=1000.)

            wl_new = objectbox.spectrum[:, 0]

            flux_new = spectres.spectres(new_spec_wavs=wl_new,
                                         old_spec_wavs=model.wavelength,
                                         spec_fluxes=model.flux,
                                         spec_errs=None)

            res_spec = np.zeros((2, objectbox.spectrum.shape[0]))

            res_spec[0, :] = wl_new
            res_spec[1, :] = (objectbox.spectrum[:, 1]-flux_new)/objectbox.spectrum[:, 2]

        else:
            res_spec = None

        print(' [DONE]')

        return box.create_box(boxtype='residuals',
                              name=objectbox.name,
                              photometry=res_phot,
                              spectrum=res_spec)