Exemplo n.º 1
0
    def get_flux(self,
                 model_param: Dict[str, float],
                 synphot=None):
        """
        Function for calculating the average flux density for the ``filter_name``.

        Parameters
        ----------
        model_param : dict
            Model parameters and values.
        synphot : species.analysis.photometry.SyntheticPhotometry, None
            Synthetic photometry object. The object is created if set to None.

        Returns
        -------
        float
            Average flux (W m-2 um-1).
        float, None
            Uncertainty (W m-2 um-1), which is set to ``None``.
        """

        for key in self.get_parameters():
            if key not in model_param.keys():
                raise ValueError(f'The \'{key}\' parameter is required by \'{self.model}\'. '
                                 f'The mandatory parameters are {self.get_parameters()}.')

        if self.spectrum_interp is None:
            self.interpolate_model()

        spectrum = self.get_model(model_param)

        if synphot is None:
            synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_flux(spectrum.wavelength, spectrum.flux)
Exemplo n.º 2
0
    def get_magnitude(self,
                      model_param: Dict[str, Union[float, List[float]]],
                      synphot=None) -> Tuple[Tuple[float, None],
                                             Tuple[float, None]]:
        """
        Function for calculating the magnitude for the ``filter_name``.

        Parameters
        ----------
        model_param : dict
            Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc).
        synphot : species.analysis.photometry.SyntheticPhotometry, None
            Synthetic photometry object. The object is created if set to None.

        Returns
        -------
        float
            Apparent magnitude (mag).
        float
            Absolute magnitude (mag)
        """

        if 'teff' in model_param and isinstance(model_param['teff'], list):
            model_param = self.update_parameters(model_param)

        spectrum = self.get_spectrum(model_param, 100.)

        if synphot is None:
            synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_magnitude(spectrum.wavelength,
                                             spectrum.flux,
                                             distance=(model_param['distance'], None))
Exemplo n.º 3
0
    def get_flux(
            self,
            model_param: Optional[Dict[str,
                                       float]] = None) -> Tuple[float, float]:
        """
        Function for calculating the average flux for the
        ``filter_name``.

        Parameters
        ----------
        model_param : dict, None
            Model parameters. Should contain the 'scaling' value. Not
            used if set to ``None``.

        Returns
        -------
        Returns
        -------
        float
            Average flux (W m-2 um-1).
        float
            Uncertainty (W m-2 um-1).
        """

        specbox = self.get_spectrum(model_param=model_param, apply_mask=True)

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_flux(specbox.wavelength,
                                        specbox.flux,
                                        error=specbox.flux)
Exemplo n.º 4
0
    def get_magnitude(
        self,
        model_param: Optional[Dict[str, float]] = None,
        distance: Optional[Tuple[float, float]] = None
    ) -> Tuple[Tuple[float, float], Tuple[Optional[float], Optional[float]]]:
        """
        Function for calculating the apparent magnitude for the ``filter_name``.

        Parameters
        ----------
        model_param : dict, None
            Model parameters. Should contain the 'scaling' value. Not used if set to ``None``.
        distance : tuple(float, float), None
            Distance and uncertainty to the calibration object (pc). Not used if set to ``None``,
            in which case the returned absolute magnitude is ``(None, None)``.

        Returns
        -------
        tuple(float, float)
            Apparent magnitude and uncertainty.
        tuple(float, float), tuple(None, None)
            Absolute magnitude and uncertainty.
        """

        specbox = self.get_spectrum(model_param=model_param)

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_magnitude(specbox.wavelength,
                                             specbox.flux,
                                             error=specbox.error,
                                             distance=distance)
Exemplo n.º 5
0
    def get_magnitude(self, model_par):
        """
        Parameters
        ----------
        model_par : dict
            Model parameter values.

        Returns
        -------
        float
            Apparent magnitude (mag).
        float
            Absolute magnitude (mag).
        """

        if self.spectrum_interp is None:
            self.interpolate()

        spectrum = self.get_model(model_par, None)

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        if 'distance' in model_par:
            app_mag, abs_mag = synphot.spectrum_to_magnitude(
                spectrum.wavelength, spectrum.flux, model_par['distance'])

        else:
            app_mag, abs_mag = synphot.spectrum_to_magnitude(
                spectrum.wavelength, spectrum.flux, None)

        return app_mag, abs_mag
Exemplo n.º 6
0
    def get_photometry(self, model_par, synphot=None):
        """
        Parameters
        ----------
        model_par : dict
            Model parameter values.
        synphot : species.analysis.photometry.SyntheticPhotometry
            Synthetic photometry object.

        Returns
        -------
        float
            Average flux density (W m-2 micron-1).
        """

        if self.spectrum_interp is None:
            self.interpolate()

        spectrum = self.get_model(model_par, None)

        if not synphot:
            synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_photometry(spectrum.wavelength,
                                              spectrum.flux)
Exemplo n.º 7
0
    def get_flux(self,
                 model_param: Dict[str, Union[float, List[float]]],
                 synphot=None) -> Tuple[float, None]:
        """
        Function for calculating the average flux density for the ``filter_name``.

        Parameters
        ----------
        model_param : dict
            Dictionary with the 'teff' (K), 'radius' (Rjup), and 'distance' (pc).
        synphot : species.analysis.photometry.SyntheticPhotometry, None
            Synthetic photometry object. The object is created if set to None.

        Returns
        -------
        float
            Average flux density (W m-2 um-1).
        NoneType
            None
        """

        if 'teff' in model_param and isinstance(model_param['teff'], list):
            model_param = self.update_parameters(model_param)

        spectrum = self.get_spectrum(model_param, 100.)

        if synphot is None:
            synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_flux(spectrum.wavelength, spectrum.flux)
Exemplo n.º 8
0
def multi_photometry(datatype: str,
                     spectrum: str,
                     filters: List[str],
                     parameters: Dict[str, float]) -> box.SynphotBox:
    """
    Parameters
    ----------
    datatype : str
        Data type ('model' or 'calibration').
    spectrum : str
        Spectrum name (e.g., 'drift-phoenix', 'planck', 'powerlaw').
    filters : list(str, )
        List with the filter names.
    parameters : dict
        Dictionary with the model parameters.

    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)

            elif spectrum == 'powerlaw':
                synphot = photometry.SyntheticPhotometry(item)
                synphot.zero_point()  # Set the wavel_range attribute

                powerl_box = read_util.powerlaw_spectrum(synphot.wavel_range, parameters)
                flux[item] = synphot.spectrum_to_flux(powerl_box.wavelength, powerl_box.flux)[0]

            else:
                readmodel = read_model.ReadModel(spectrum, filter_name=item)

                try:
                    flux[item] = readmodel.get_flux(parameters)[0]

                except IndexError:
                    flux[item] = np.nan

                    warnings.warn(f'The wavelength range of the {item} filter does not match with '
                                  f'the wavelength range of {spectrum}. The flux is set to NaN.')

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

    print(' [DONE]')

    return box.create_box('synphot', name='synphot', flux=flux)
Exemplo n.º 9
0
    def get_magnitude(
            self, model_param: Dict[str,
                                    float]) -> Tuple[float, Optional[float]]:
        """
        Function for calculating the apparent and absolute magnitudes for the ``filter_name``.

        Parameters
        ----------
        model_param : dict
            Model parameters and values.

        Returns
        -------
        float
            Apparent magnitude.
        float, None
            Absolute magnitude. A ``None`` is returned if the ``model_param`` do not contain a
            ``radius`` and ``distance``.
        """

        for key in self.get_parameters():
            if key not in model_param.keys():
                raise ValueError(
                    f'The \'{key}\' parameter is required by \'{self.model}\'. '
                    f'The mandatory parameters are {self.get_parameters()}.')

        if self.spectrum_interp is None:
            self.interpolate_model()

        try:
            spectrum = self.get_model(model_param)

        except ValueError:
            warnings.warn(
                f'The set of model parameters {model_param} is outside the grid range '
                f'{self.get_bounds()} so returning a NaN.')

            return np.nan, np.nan

        if spectrum.wavelength.size == 0:
            app_mag = np.nan
            abs_mag = np.nan

        else:
            synphot = photometry.SyntheticPhotometry(self.filter_name)

            if 'distance' in model_param:
                app_mag, abs_mag = synphot.spectrum_to_magnitude(
                    spectrum.wavelength,
                    spectrum.flux,
                    distance=(model_param['distance'], None))

            else:
                app_mag, abs_mag = synphot.spectrum_to_magnitude(
                    spectrum.wavelength, spectrum.flux, distance=None)

        return app_mag[0], abs_mag[0]
Exemplo n.º 10
0
    def __init__(
        self,
        object_name: str,
        filters: Optional[List[str]],
        spectrum: str,
        bounds: Dict[str, Tuple[float, float]],
    ) -> None:
        """
        Parameters
        ----------
        object_name : str
            Object name in the database.
        filters : list(str)
            Filter names for which the photometry is selected. All available photometry of the
            object is selected if set to ``None``.
        spectrum : str
            Calibration spectrum as labelled in the database. The calibration spectrum can be
            stored in the database with :func:`~species.data.database.Database.add_calibration`.
        bounds : dict
            Boundaries of the scaling parameter, as ``{'scaling':(min, max)}``.

        Returns
        -------
        NoneType
            None
        """

        self.object = read_object.ReadObject(object_name)

        self.spectrum = spectrum
        self.bounds = bounds

        self.objphot = []
        self.specphot = []

        if filters is None:
            species_db = database.Database()

            objectbox = species_db.get_object(object_name,
                                              inc_phot=True,
                                              inc_spec=False)
            filters = objectbox.filters

        for item in filters:
            readcalib = read_calibration.ReadCalibration(self.spectrum, item)
            calibspec = readcalib.get_spectrum()

            synphot = photometry.SyntheticPhotometry(item)
            spec_phot = synphot.spectrum_to_flux(calibspec.wavelength,
                                                 calibspec.flux)
            self.specphot.append(spec_phot[0])

            obj_phot = self.object.get_photometry(item)
            self.objphot.append(np.array([obj_phot[2], obj_phot[3]]))

        self.modelpar = ["scaling"]
Exemplo n.º 11
0
    def get_magnitude(self, sptypes: List[str] = None) -> box.PhotometryBox:
        """
        Function for calculating the apparent magnitude for the ``filter_name``.

        Parameters
        ----------
        sptypes : list(str)
            Spectral types to select from a library. The spectral types should be indicated with
            two characters (e.g. 'M5', 'L2', 'T3'). All spectra are selected if set to ``None``.

        Returns
        -------
        species.core.box.PhotometryBox
            Box with the synthetic photometry.
        """

        specbox = self.get_spectrum(sptypes=sptypes, exclude_nan=True)

        n_spectra = len(specbox.wavelength)

        filter_profile = read_filter.ReadFilter(filter_name=self.filter_name)
        mean_wavel = filter_profile.mean_wavelength()

        wavelengths = np.full(n_spectra, mean_wavel)
        filters = np.full(n_spectra, self.filter_name)

        synphot = photometry.SyntheticPhotometry(filter_name=self.filter_name)

        app_mag = []
        abs_mag = []

        for i in range(n_spectra):

            if np.isnan(specbox.distance[i][0]):
                app_tmp = (np.nan, np.nan)
                abs_tmp = (np.nan, np.nan)

            else:
                app_tmp, abs_tmp = synphot.spectrum_to_magnitude(
                    specbox.wavelength[i],
                    specbox.flux[i],
                    error=specbox.error[i],
                    distance=(float(specbox.distance[i][0]),
                              float(specbox.distance[i][1])))

            app_mag.append(app_tmp)
            abs_mag.append(abs_tmp)

        return box.create_box(boxtype='photometry',
                              name=specbox.name,
                              sptype=specbox.sptype,
                              wavelength=wavelengths,
                              flux=None,
                              app_mag=np.asarray(app_mag),
                              abs_mag=np.asarray(abs_mag),
                              filter_name=filters)
Exemplo n.º 12
0
    def synthetic_photometry(
            self, filter_name: Union[str, List[str]]) -> PhotometryBox:
        """
        Method for calculating synthetic photometry from the model
        spectrum that is stored in the ``ModelBox``.

        Parameters
        ----------
        filter_name : str, list(str)
            Single filter name or a list of filter names for which
            synthetic photometry will be calculated.

        Returns
        -------
        species.core.box.PhotometryBox
            Box with the synthetic photometry.
        """

        if isinstance(filter_name, str):
            filter_name = [filter_name]

        list_wavel = []
        list_flux = []
        list_app_mag = []
        list_abs_mag = []

        for item in filter_name:
            syn_phot = photometry.SyntheticPhotometry(filter_name=item)

            syn_flux = syn_phot.spectrum_to_flux(wavelength=self.wavelength,
                                                 flux=self.flux)

            syn_mag = syn_phot.spectrum_to_magnitude(
                wavelength=self.wavelength, flux=self.flux)

            list_flux.append(syn_flux)
            list_app_mag.append(syn_mag[0])
            list_abs_mag.append(syn_mag[1])

            filter_profile = read_filter.ReadFilter(filter_name=item)
            list_wavel.append(filter_profile.mean_wavelength())

        phot_box = create_box(
            boxtype="photometry",
            name=None,
            sptype=None,
            wavelength=list_wavel,
            flux=list_flux,
            app_mag=list_app_mag,
            abs_mag=list_abs_mag,
            filter_name=filter_name,
        )

        return phot_box
Exemplo n.º 13
0
    def get_flux(self, sptypes: List[str] = None) -> box.PhotometryBox:
        """
        Function for calculating the average flux density for the
        ``filter_name``.

        Parameters
        ----------
        sptypes : list(str), None
            Spectral types to select from a library. The spectral types
            should be indicated with two characters (e.g. 'M5', 'L2',
            'T3'). All spectra are selected if set to ``None``.

        Returns
        -------
        species.core.box.PhotometryBox
            Box with the synthetic photometry.
        """

        specbox = self.get_spectrum(sptypes=sptypes, exclude_nan=True)

        n_spectra = len(specbox.wavelength)

        filter_profile = read_filter.ReadFilter(filter_name=self.filter_name)
        mean_wavel = filter_profile.mean_wavelength()

        wavelengths = np.full(n_spectra, mean_wavel)
        filters = np.full(n_spectra, self.filter_name)

        synphot = photometry.SyntheticPhotometry(filter_name=self.filter_name)

        phot_flux = []

        for i in range(n_spectra):
            flux = synphot.spectrum_to_flux(
                wavelength=specbox.wavelength[i],
                flux=specbox.flux[i],
                error=specbox.error[i],
            )

            phot_flux.append(flux)

        phot_flux = np.asarray(phot_flux)

        return box.create_box(
            boxtype="photometry",
            name=specbox.name,
            sptype=specbox.sptype,
            wavelength=wavelengths,
            flux=phot_flux,
            app_mag=None,
            abs_mag=None,
            filter_name=filters,
        )
Exemplo n.º 14
0
    def __init__(self, objname, filters, spectrum, bounds):
        """
        Parameters
        ----------
        objname : str
            Object name in the database.
        filters : tuple(str, )
            Filter IDs for which the photometry is selected. All available photometry of the
            object is selected if set to None.
        spectrum : str
            Calibration spectrum.
        bounds : dict
            Boundaries of the scaling parameter, as {'scaling':(min, max)}.

        Returns
        -------
        None
        """

        self.object = read_object.ReadObject(objname)

        self.spectrum = spectrum
        self.bounds = bounds

        self.objphot = []
        self.specphot = []

        if filters is None:
            species_db = database.Database()
            objectbox = species_db.get_object(objname, None)
            filters = objectbox.filter

        for item in filters:
            readcalib = read_calibration.ReadCalibration(self.spectrum, item)
            calibspec = readcalib.get_spectrum()

            synphot = photometry.SyntheticPhotometry(item)
            spec_phot = synphot.spectrum_to_photometry(calibspec.wavelength,
                                                       calibspec.flux)
            self.specphot.append(spec_phot)

            obj_phot = self.object.get_photometry(item)
            self.objphot.append((obj_phot[2], obj_phot[3]))

        self.modelpar = ['scaling']
Exemplo n.º 15
0
    def get_photometry(self, parameters=None, synphot=None):
        """
        Parameters
        ----------
        parameters : dict, None
            Model parameter values. Not used if set to None.
        synphot

        Returns
        -------
        float
            Average flux density (W m-2 micron-1).
        """

        specbox = self.get_spectrum(parameters, )

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_photometry(specbox.wavelength, specbox.flux)
Exemplo n.º 16
0
    def get_magnitude(self, parameters=None, synphot=None):
        """
        Parameters
        ----------
        parameters : dict, None
            Model parameter values. Not used if set to None.
        synphot

        Returns
        -------
        float
            Apparent magnitude (mag).
        """

        specbox = self.get_spectrum(parameters, )

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_magnitude(specbox.wavelength,
                                             specbox.flux,
                                             distance=None)
Exemplo n.º 17
0
    def get_flux(self, model_param: Dict[str, float]) -> Tuple[float, None]:
        """
        Function for calculating the average flux density for the
        ``filter_name``.

        Parameters
        ----------
        model_param : dict
            Dictionary with the model parameters and values.

        Returns
        -------
        float
            Flux (W m-2 um-1).
        NoneType
            Error (W m-2 um-1). Always set to ``None``.
        """

        spectrum = self.get_model(model_param)

        synphot = photometry.SyntheticPhotometry(self.filter_name)

        return synphot.spectrum_to_flux(spectrum.wavelength, spectrum.flux)
Exemplo n.º 18
0
def add_spex(input_path, database):
    """
    Function for adding the SpeX Prism Spectral Library to the database.

    Parameters
    ----------
    input_path : str
        Path of the data folder.
    database : h5py._hl.files.File
        The HDF5 database.

    Returns
    -------
    NoneType
        None
    """

    distance_url = 'https://people.phys.ethz.ch/~stolkert/species/distance.dat'
    distance_file = os.path.join(input_path, 'distance.dat')

    if not os.path.isfile(distance_file):
        urllib.request.urlretrieve(distance_url, distance_file)

    distance_data = pd.pandas.read_csv(
        distance_file,
        usecols=[0, 3, 4],
        names=['object', 'distance', 'distance_error'],
        delimiter=',',
        dtype={
            'object': str,
            'distance': float,
            'distance_error': float
        })

    database.create_group('spectra/spex')

    data_path = os.path.join(input_path, 'spex')

    if not os.path.exists(data_path):
        os.makedirs(data_path)

    url_all = 'http://svo2.cab.inta-csic.es/vocats/v2/spex/' \
              'cs.php?RA=180.000000&DEC=0.000000&SR=180.000000&VERB=2'

    xml_file_spex = os.path.join(data_path, 'spex.xml')

    if not os.path.isfile(xml_file_spex):
        urllib.request.urlretrieve(url_all, xml_file_spex)

    table = parse_single_table(xml_file_spex)
    # name = table.array['name']
    twomass = table.array['name2m']
    url = table.array['access_url']

    unique_id = []

    for i, item in enumerate(url):
        if twomass[i] not in unique_id:
            xml_file_1 = os.path.join(data_path,
                                      twomass[i].decode('utf-8') + '.xml')

            if not os.path.isfile(xml_file_1):
                urllib.request.urlretrieve(item.decode('utf-8'), xml_file_1)

            table = parse_single_table(xml_file_1)
            name = table.array['ID']
            name = name[0].decode('utf-8')
            url = table.array['access_url']

            print_message = f'Downloading SpeX Prism Spectral Library... {name}'
            print(f'\r{print_message:<72}', end='')

            xml_file_2 = os.path.join(data_path, f'spex_{name}.xml')

            if not os.path.isfile(xml_file_2):
                urllib.request.urlretrieve(url[0].decode('utf-8'), xml_file_2)

            unique_id.append(twomass[i])

    print_message = 'Downloading SpeX Prism Spectral Library... [DONE]'
    print(f'\r{print_message:<72}')

    h_twomass = photometry.SyntheticPhotometry('2MASS/2MASS.H')

    # 2MASS H band zero point for 0 mag (Cogen et al. 2003)
    h_zp = 1.133e-9  # (W m-2 um-1)

    for votable in os.listdir(data_path):
        if votable.startswith('spex_') and votable.endswith('.xml'):
            xml_file = os.path.join(data_path, votable)

            table = parse_single_table(xml_file)

            wavelength = table.array['wavelength']  # (Angstrom)
            flux = table.array['flux']  # Normalized units

            wavelength = np.array(wavelength * 1e-4)  # (um)
            flux = np.array(flux)  # (a.u.)
            error = np.full(flux.size, np.nan)

            # 2MASS magnitudes
            j_mag = table.get_field_by_id('jmag').value
            h_mag = table.get_field_by_id('hmag').value
            ks_mag = table.get_field_by_id('ksmag').value

            j_mag = j_mag.decode('utf-8')
            h_mag = h_mag.decode('utf-8')
            ks_mag = ks_mag.decode('utf-8')

            if j_mag == '':
                j_mag = np.nan
            else:
                j_mag = float(j_mag)

            if h_mag == '':
                h_mag = np.nan
            else:
                h_mag = float(h_mag)

            if ks_mag == '':
                ks_mag = np.nan
            else:
                ks_mag = float(ks_mag)

            name = table.get_field_by_id('name').value
            name = name.decode('utf-8')

            twomass_id = table.get_field_by_id('name2m').value
            twomass_id = twomass_id.decode('utf-8')

            try:
                sptype = table.get_field_by_id('nirspty').value
                sptype = sptype.decode('utf-8')

            except KeyError:
                try:
                    sptype = table.get_field_by_id('optspty').value
                    sptype = sptype.decode('utf-8')

                except KeyError:
                    sptype = 'None'

            sptype = data_util.update_sptype(np.array([sptype]))[0].strip()

            h_flux, _ = h_twomass.magnitude_to_flux(h_mag,
                                                    error=None,
                                                    zp_flux=h_zp)
            phot = h_twomass.spectrum_to_flux(wavelength,
                                              flux)  # Normalized units

            flux *= h_flux / phot[0]  # (W m-2 um-1)

            spdata = np.vstack([wavelength, flux, error])

            # simbad_id, distance = query_util.get_distance(f'2MASS {twomass_id}')
            simbad_id = query_util.get_simbad(f'2MASS {twomass_id}')

            if simbad_id is not None:
                simbad_id = simbad_id.decode('utf-8')

                dist_select = distance_data.loc[distance_data['object'] ==
                                                simbad_id]

                if not dist_select.empty:
                    distance = (dist_select['distance'],
                                dist_select['distance_error'])
                else:
                    distance = (np.nan, np.nan)

            else:
                distance = (np.nan, np.nan)

            if sptype[0] in ['M', 'L', 'T'] and len(sptype) == 2:
                print_message = f'Adding SpeX Prism Spectral Library... {name}'
                print(f'\r{print_message:<72}', end='')

                dset = database.create_dataset(f'spectra/spex/{name}',
                                               data=spdata)

                dset.attrs['name'] = str(name).encode()
                dset.attrs['sptype'] = str(sptype).encode()
                dset.attrs['simbad'] = str(simbad_id).encode()
                dset.attrs['2MASS/2MASS.J'] = j_mag
                dset.attrs['2MASS/2MASS.H'] = h_mag
                dset.attrs['2MASS/2MASS.Ks'] = ks_mag
                dset.attrs['distance'] = distance[0]  # (pc)
                dset.attrs['distance_error'] = distance[1]  # (pc)

    print_message = 'Adding SpeX Prism Spectral Library... [DONE]'
    print(f'\r{print_message:<72}')

    database.close()
Exemplo n.º 19
0
def add_spex(input_path: str, database: h5py._hl.files.File) -> None:
    """
    Function for adding the SpeX Prism Spectral Library to the database.

    Parameters
    ----------
    input_path : str
        Path of the data folder.
    database : h5py._hl.files.File
        The HDF5 database.

    Returns
    -------
    NoneType
        None
    """

    parallax_url = "https://home.strw.leidenuniv.nl/~stolker/species/parallax.dat"
    parallax_file = os.path.join(input_path, "parallax.dat")

    if not os.path.isfile(parallax_file):
        urllib.request.urlretrieve(parallax_url, parallax_file)

    parallax_data = pd.pandas.read_csv(
        parallax_file,
        usecols=[0, 1, 2],
        names=["object", "parallax", "parallax_error"],
        delimiter=",",
        dtype={"object": str, "parallax": float, "parallax_error": float},
    )

    database.create_group("spectra/spex")

    data_path = os.path.join(input_path, "spex")

    if not os.path.exists(data_path):
        os.makedirs(data_path)

    url_all = "http://svo2.cab.inta-csic.es/vocats/v2/spex/cs.php?" \
              "RA=180.000000&DEC=0.000000&SR=180.000000&VERB=2"

    xml_file_spex = os.path.join(data_path, "spex.xml")

    if not os.path.isfile(xml_file_spex):
        urllib.request.urlretrieve(url_all, xml_file_spex)

    table = parse_single_table(xml_file_spex)
    # name = table.array['name']
    twomass = table.array["name2m"]
    url = table.array["access_url"]

    unique_id = []

    print_message = ""

    for i, item in enumerate(url):
        if twomass[i] not in unique_id:

            if isinstance(twomass[i], str):
                xml_file_1 = os.path.join(data_path, twomass[i] + ".xml")
            else:
                # Use decode for backward compatibility
                xml_file_1 = os.path.join(
                    data_path, twomass[i].decode("utf-8") + ".xml"
                )

            if not os.path.isfile(xml_file_1):
                if isinstance(item, str):
                    urllib.request.urlretrieve(item, xml_file_1)
                else:
                    urllib.request.urlretrieve(item.decode("utf-8"), xml_file_1)

            table = parse_single_table(xml_file_1)
            name = table.array["ID"]
            url = table.array["access_url"]

            if isinstance(name[0], str):
                name = name[0]
            else:
                name = name[0].decode("utf-8")

            empty_message = len(print_message) * " "
            print(f"\r{empty_message}", end="")

            print_message = f"Downloading SpeX Prism Spectral Library... {name}"
            print(f"\r{print_message}", end="")

            xml_file_2 = os.path.join(data_path, f"spex_{name}.xml")

            if not os.path.isfile(xml_file_2):
                if isinstance(url[0], str):
                    urllib.request.urlretrieve(url[0], xml_file_2)
                else:
                    urllib.request.urlretrieve(url[0].decode("utf-8"), xml_file_2)

            unique_id.append(twomass[i])

    empty_message = len(print_message) * " "
    print(f"\r{empty_message}", end="")

    print_message = "Downloading SpeX Prism Spectral Library... [DONE]"
    print(f"\r{print_message}")

    h_twomass = photometry.SyntheticPhotometry("2MASS/2MASS.H")

    # 2MASS H band zero point for 0 mag (Cogen et al. 2003)
    h_zp = 1.133e-9  # (W m-2 um-1)

    for votable in os.listdir(data_path):
        if votable.startswith("spex_") and votable.endswith(".xml"):
            xml_file = os.path.join(data_path, votable)

            table = parse_single_table(xml_file)

            wavelength = table.array["wavelength"]  # (Angstrom)
            flux = table.array["flux"]  # Normalized units

            wavelength = np.array(wavelength * 1e-4)  # (um)
            flux = np.array(flux)  # (a.u.)
            error = np.full(flux.size, np.nan)

            # 2MASS magnitudes
            j_mag = table.get_field_by_id("jmag").value
            h_mag = table.get_field_by_id("hmag").value
            ks_mag = table.get_field_by_id("ksmag").value

            if not isinstance(j_mag, str):
                j_mag = j_mag.decode("utf-8")

            if not isinstance(h_mag, str):
                h_mag = h_mag.decode("utf-8")

            if not isinstance(ks_mag, str):
                ks_mag = ks_mag.decode("utf-8")

            if j_mag == "":
                j_mag = np.nan
            else:
                j_mag = float(j_mag)

            if h_mag == "":
                h_mag = np.nan
            else:
                h_mag = float(h_mag)

            if ks_mag == "":
                ks_mag = np.nan
            else:
                ks_mag = float(ks_mag)

            name = table.get_field_by_id("name").value

            if not isinstance(name, str):
                name = name.decode("utf-8")

            twomass_id = table.get_field_by_id("name2m").value

            if not isinstance(twomass_id, str):
                twomass_id = twomass_id.decode("utf-8")

            # Optical spectral type

            try:
                sptype_opt = table.get_field_by_id("optspty").value

                if not isinstance(sptype_opt, str):
                    sptype_opt = sptype_opt.decode("utf-8")

                sptype_opt = data_util.update_sptype(np.array([sptype_opt]))[0]

            except KeyError:
                sptype_opt = None

            # Near-infrared spectral type

            try:
                sptype_nir = table.get_field_by_id("nirspty").value

                if not isinstance(sptype_nir, str):
                    sptype_nir = sptype_nir.decode("utf-8")

                sptype_nir = data_util.update_sptype(np.array([sptype_nir]))[0]

            except KeyError:
                sptype_nir = None

            h_flux, _ = h_twomass.magnitude_to_flux(h_mag, error=None, zp_flux=h_zp)
            phot = h_twomass.spectrum_to_flux(wavelength, flux)  # Normalized units

            flux *= h_flux / phot[0]  # (W m-2 um-1)

            spdata = np.column_stack([wavelength, flux, error])

            simbad_id = query_util.get_simbad(f"2MASS {twomass_id}")

            if simbad_id is not None:
                if not isinstance(simbad_id, str):
                    simbad_id = simbad_id.decode("utf-8")

                par_select = parallax_data[parallax_data["object"] == simbad_id]

                if not par_select.empty:
                    parallax = (
                        par_select["parallax"].values[0],
                        par_select["parallax_error"].values[0],
                    )

                else:
                    parallax = (np.nan, np.nan)

            else:
                parallax = (np.nan, np.nan)

            print_message = f"Adding spectra... {name}"
            print(f"\r{print_message:<72}", end="")

            dset = database.create_dataset(f"spectra/spex/{name}", data=spdata)

            dset.attrs["name"] = str(name).encode()

            if sptype_opt is not None:
                dset.attrs["sptype"] = str(sptype_opt).encode()
            elif sptype_nir is not None:
                dset.attrs["sptype"] = str(sptype_nir).encode()
            else:
                dset.attrs["sptype"] = str("None").encode()

            dset.attrs["simbad"] = str(simbad_id).encode()
            dset.attrs["2MASS/2MASS.J"] = j_mag
            dset.attrs["2MASS/2MASS.H"] = h_mag
            dset.attrs["2MASS/2MASS.Ks"] = ks_mag
            dset.attrs["parallax"] = parallax[0]  # (mas)
            dset.attrs["parallax_error"] = parallax[1]  # (mas)

    print_message = "Adding spectra... [DONE]"
    print(f"\r{print_message:<72}")

    database.close()
Exemplo n.º 20
0
def multi_photometry(
    datatype: str,
    spectrum: str,
    filters: List[str],
    parameters: Dict[str, float],
    radtrans: Optional[read_radtrans.ReadRadtrans] = None,
) -> box.SynphotBox:
    """
    Parameters
    ----------
    datatype : str
        Data type ('model' or 'calibration').
    spectrum : str
        Spectrum name (e.g., 'drift-phoenix', 'planck', 'powerlaw',
        'petitradtrans').
    filters : list(str)
        List with the filter names.
    parameters : dict
        Dictionary with the model parameters.
    radtrans : read_radtrans.ReadRadtrans, None
        Instance of :class:`~species.read.read_radtrans.ReadRadtrans`.
        Only required with ``spectrum='petitradtrans'`. Make sure that
        the ``wavel_range`` of the ``ReadRadtrans`` instance is
        sufficiently broad to cover all the ``filters``. Not used if
        set to `None`.

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

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

    flux = {}

    if datatype == "model":
        if spectrum == "petitradtrans":
            # Calculate the petitRADTRANS spectrum only once
            radtrans_box = radtrans.get_model(parameters)

        for item in filters:

            if spectrum == "petitradtrans":
                # Use an instance of SyntheticPhotometry instead
                # of get_flux from ReadRadtrans in order to not
                # recalculate the spectrum
                syn_phot = photometry.SyntheticPhotometry(item)

                flux[item], _ = syn_phot.spectrum_to_flux(
                    radtrans_box.wavelength, radtrans_box.flux)

            elif spectrum == "powerlaw":
                synphot = photometry.SyntheticPhotometry(item)

                # Set the wavel_range attribute
                synphot.zero_point()

                powerl_box = read_util.powerlaw_spectrum(
                    synphot.wavel_range, parameters)
                flux[item] = synphot.spectrum_to_flux(powerl_box.wavelength,
                                                      powerl_box.flux)[0]

            else:
                if spectrum == "planck":
                    readmodel = read_planck.ReadPlanck(filter_name=item)

                else:
                    readmodel = read_model.ReadModel(spectrum,
                                                     filter_name=item)

                try:
                    if "teff_0" in parameters and "teff_1" in parameters:
                        # Binary system

                        param_0 = read_util.binary_to_single(parameters, 0)
                        model_flux_0 = readmodel.get_flux(param_0)[0]

                        param_1 = read_util.binary_to_single(parameters, 1)
                        model_flux_1 = readmodel.get_flux(param_1)[0]

                        flux[item] = (
                            parameters["spec_weight"] * model_flux_0 +
                            (1.0 - parameters["spec_weight"]) * model_flux_1)

                    else:
                        # Single object

                        flux[item] = readmodel.get_flux(parameters)[0]

                except IndexError:
                    flux[item] = np.nan

                    warnings.warn(
                        f"The wavelength range of the {item} filter does not "
                        f"match with the wavelength range of {spectrum}. The "
                        f"flux is set to NaN.")

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

    print(" [DONE]")

    return box.create_box("synphot", name="synphot", flux=flux)
Exemplo n.º 21
0
def add_spex(input_path, database):
    """
    Function for adding the SpeX Prism Spectral Library to the database.

    Parameters
    ----------
    input_path : str
        Path of the data folder.
    database : h5py._hl.files.File
        Database.

    Returns
    -------
    NoneType
        None
    """

    database.create_group('spectra/spex')

    data_path = os.path.join(input_path, 'spex')

    if not os.path.exists(data_path):
        os.makedirs(data_path)

    url_all = 'http://svo2.cab.inta-csic.es/vocats/v2/spex/' \
              'cs.php?RA=180.000000&DEC=0.000000&SR=180.000000&VERB=2'

    xml_file = os.path.join(data_path, 'spex.xml')

    urlretrieve(url_all, xml_file)

    table = parse_single_table(xml_file)
    name = table.array['name']
    twomass = table.array['name2m']
    url = table.array['access_url']

    os.remove(xml_file)

    for i, item in enumerate(url):
        xml_file = os.path.join(data_path, twomass[i].decode('utf-8') + '.xml')
        urlretrieve(item.decode('utf-8'), xml_file)

        table = parse_single_table(xml_file)
        name = table.array['ID']
        name = name[0].decode('utf-8')
        url = table.array['access_url']

        sys.stdout.write('\rDownloading SpeX Prism Spectral Library... ' +
                         '{:<40}'.format(name))
        sys.stdout.flush()

        os.remove(xml_file)

        xml_file = os.path.join(data_path, name + '.xml')
        urlretrieve(url[0].decode('utf-8'), xml_file)

    sys.stdout.write('\rDownloading SpeX Prism Spectral Library... ' +
                     '{:<40}'.format('[DONE]') + '\n')
    sys.stdout.flush()

    h_twomass = photometry.SyntheticPhotometry('2MASS/2MASS.H')

    transmission = read_filter.ReadFilter('2MASS/2MASS.H')
    transmission.get_filter()

    # 2MASS H band zero point for 0 mag (Cogen et al. 2003)
    h_zp = 1.133e-9  # [W m-2 micron-1]

    for votable in os.listdir(data_path):
        if votable.endswith('.xml'):
            xml_file = os.path.join(data_path, votable)

            table = parse_single_table(xml_file)

            wavelength = table.array['wavelength']  # [Angstrom]
            flux = table.array['flux']  # Normalized units

            wavelength = np.array(wavelength * 1e-4)  # [micron]
            flux = np.array(flux)

            # 2MASS magnitudes
            j_mag = table.get_field_by_id('jmag').value
            h_mag = table.get_field_by_id('hmag').value
            ks_mag = table.get_field_by_id('ksmag').value

            if j_mag == b'':
                j_mag = np.nan
            else:
                j_mag = float(j_mag)

            if h_mag == b'':
                h_mag = np.nan
            else:
                h_mag = float(h_mag)

            if ks_mag == b'':
                ks_mag = np.nan
            else:
                ks_mag = float(ks_mag)

            name = table.get_field_by_id('name').value
            name = name.decode('utf-8')
            twomass_id = table.get_field_by_id('name2m').value

            sys.stdout.write('\rAdding SpeX Prism Spectral Library... ' +
                             '{:<40}'.format(name))
            sys.stdout.flush()

            try:
                sptype = table.get_field_by_id('nirspty').value
                sptype = sptype.decode('utf-8')

            except KeyError:
                try:
                    sptype = table.get_field_by_id('optspty').value
                    sptype = sptype.decode('utf-8')

                except KeyError:
                    sptype = 'None'

            sptype = data_util.update_sptype(np.array([sptype]))[0]

            h_flux, _ = h_twomass.magnitude_to_flux(h_mag, None, h_zp)
            phot = h_twomass.spectrum_to_photometry(wavelength,
                                                    flux)  # Normalized units

            flux *= h_flux / phot  # [W m-2 micron-1]

            spdata = np.vstack((wavelength, flux))

            simbad_id, distance = queries.get_distance(
                '2MASS ' + twomass_id.decode('utf-8'))  # [pc]

            dset = database.create_dataset('spectra/spex/' + name, data=spdata)

            dset.attrs['name'] = str(name)
            dset.attrs['sptype'] = str(sptype)
            dset.attrs['simbad'] = str(simbad_id)
            dset.attrs['2MASS/2MASS.J'] = j_mag
            dset.attrs['2MASS/2MASS.H'] = h_mag
            dset.attrs['2MASS/2MASS.Ks'] = ks_mag
            dset.attrs['distance'] = distance  # [pc]

    sys.stdout.write('\rAdding SpeX Prism Spectral Library... ' +
                     '{:<40}'.format('[DONE]') + '\n')
    sys.stdout.flush()

    database.close()
Exemplo n.º 22
0
    def __init__(self,
                 object_name: str,
                 model: str,
                 bounds: Dict[str, Union[Tuple[float, float],
                                         Tuple[Optional[Tuple[float, float]],
                                               Optional[Tuple[float, float]]],
                                         List[Tuple[float, float]]]],
                 inc_phot: Union[bool, List[str]] = True,
                 inc_spec: Union[bool, List[str]] = True,
                 fit_corr: Optional[List[str]] = None) -> None:
        """
        The grid of spectra is linearly interpolated for each photometric point and spectrum while
        taking into account the filter profile, spectral resolution, and wavelength sampling.
        Therefore, when fitting spectra from a model grid, the computation time of the
        interpolation will depend on the wavelength range, spectral resolution, and parameter
        space of the spectra that are stored in the database.

        Parameters
        ----------
        object_name : str
            Object name as stored in the database with
            :func:`~species.data.database.Database.add_object` or
            :func:`~species.data.database.Database.add_companion`.
        model : str
            Atmospheric model (e.g. 'bt-settl', 'exo-rem', or 'planck').
        bounds : dict(str, tuple(float, float)), None
            The boundaries that are used for the uniform priors.

            Atmospheric model parameters (e.g. ``model='bt-settl'``):

                 - Boundaries are provided as tuple of two floats. For example,
                   ``bounds={'teff': (1000, 1500.), 'logg': (3.5, 5.), 'radius': (0.8, 1.2)}``.

                 - The grid boundaries are used if set to ``None``. For example,
                   ``bounds={'teff': None, 'logg': None}``. The radius range is set to
                   0.8-1.5 Rjup if the boundary is set to None.

            Blackbody emission parameters (``model='planck'``):

                 - Parameter boundaries have to be provided for 'teff' and 'radius'.

                 - For a single blackbody component, the values are provided as a tuple with two
                   floats. For example, ``bounds={'teff': (1000., 2000.), 'radius': (0.8, 1.2)}``.

                 - For multiple blackbody component, the values are provided as a list with tuples.
                   For example, ``bounds={'teff': [(1000., 1400.), (1200., 1600.)],
                   'radius': [(0.8, 1.5), (1.2, 2.)]}``.

                 - When fitting multiple blackbody components, a prior is used which restricts the
                   temperatures and radii to decreasing and increasing values, respectively, in the
                   order as provided in ``bounds``.

            Calibration parameters:

                 - For each spectrum/instrument, two optional parameters can be fitted to account
                   for biases in the calibration: a scaling of the flux and a constant inflation of
                   the uncertainties.

                 - For example, ``bounds={'SPHERE': ((0.8, 1.2), (-18., -14.))}`` if the scaling is
                   fitted between 0.8 and 1.2, and the error is inflated with a value between 1e-18
                   and 1e-14 W m-2 um-1.

                 - The dictionary key should be equal to the database tag of the spectrum. For
                   example, ``{'SPHERE': ((0.8, 1.2), (-18., -14.))}`` if the spectrum is stored as
                   ``'SPHERE'`` with :func:`~species.data.database.Database.add_object`.

                 - Each of the two calibration parameters can be set to ``None`` in which case the
                   parameter is not used. For example, ``bounds={'SPHERE': ((0.8, 1.2), None)}``.

                 - No calibration parameters are fitted if the spectrum name is not included in
                   ``bounds``.

            ISM extinction parameters:

                 - There are three approaches for fitting extinction. The first is with the
                   empirical relation from Cardelli et al. (1989) for ISM extinction.

                 - The extinction is parametrized by the V band extinction, A_V (``ism_ext``), and
                   the reddening, R_V (``ism_red``).

                 - The prior boundaries of ``ism_ext`` and ``ext_red`` should be provided in the
                   ``bounds`` dictionary, for example ``bounds={'ism_ext': (0., 10.),
                   'ism_red': (0., 20.)}``.

                 - Only supported by ``run_multinest``.

            Log-normal size distribution:

                 - The second approach is fitting the extinction of a log-normal size distribution
                   of grains with a crystalline MgSiO3 composition, and a homogeneous, spherical
                   structure.

                 - The size distribution is parameterized with a mean geometric radius
                   (``lognorm_radius`` in um) and a geometric standard deviation
                   (``lognorm_sigma``, dimensionless).

                 - The extinction (``lognorm_ext``) is fitted in the V band (A_V in mag) and the
                   wavelength-dependent extinction cross sections are interpolated from a
                   pre-tabulated grid.

                 - The prior boundaries of ``lognorm_radius``, ``lognorm_sigma``, and
                   ``lognorm_ext`` should be provided in the ``bounds`` dictionary, for example
                   ``bounds={'lognorm_radius': (0.01, 10.), 'lognorm_sigma': (1.2, 10.),
                   'lognorm_ext': (0., 5.)}``.

                 - A uniform prior is used for ``lognorm_sigma`` and ``lognorm_ext``, and a
                   log-uniform prior for ``lognorm_radius``.

                 - Only supported by ``run_multinest``.

            Power-law size distribution:

                 - The third approach is fitting the extinction of a power-law size distribution
                   of grains, again with a crystalline MgSiO3 composition, and a homogeneous,
                   spherical structure.

                 - The size distribution is parameterized with a maximum radius (``powerlaw_max``
                   in um) and a power-law exponent (``powerlaw_exp``, dimensionless). The
                   minimum radius is fixed to 1 nm.

                 - The extinction (``powerlaw_ext``) is fitted in the V band (A_V in mag) and the
                   wavelength-dependent extinction cross sections are interpolated from a
                   pre-tabulated grid.

                 - The prior boundaries of ``powerlaw_max``, ``powerlaw_exp``, and ``powerlaw_ext``
                   should be provided in the ``bounds`` dictionary, for example ``'powerlaw_max':
                   (0.5, 10.), 'powerlaw_exp': (-5., 5.), 'powerlaw_ext': (0., 5.)}``.

                 - A uniform prior is used for ``powerlaw_exp`` and ``powerlaw_ext``, and a
                   log-uniform prior for ``powerlaw_max``.

                 - Only supported by ``run_multinest``.

        inc_phot : bool, list(str)
            Include photometric data in the fit. If a boolean, either all (``True``) or none
            (``False``) of the data are selected. If a list, a subset of filter names (as stored in
            the database) can be provided.
        inc_spec : bool, list(str)
            Include spectroscopic data in the fit. If a boolean, either all (``True``) or none
            (``False``) of the data are selected. If a list, a subset of spectrum names (as stored
            in the database with :func:`~species.data.database.Database.add_object`) can be
            provided.
        fit_corr : list(str), None
            List with spectrum names for which the correlation length and fractional amplitude are
            fitted (see Wang et al. 2020).

        Returns
        -------
        NoneType
            None
        """

        if not inc_phot and not inc_spec:
            raise ValueError(
                'No photometric or spectroscopic data has been selected.')

        if model == 'planck' and 'teff' not in bounds or 'radius' not in bounds:
            raise ValueError(
                'The \'bounds\' dictionary should contain \'teff\' and \'radius\'.'
            )

        self.object = read_object.ReadObject(object_name)
        self.distance = self.object.get_distance()

        if fit_corr is None:
            self.fit_corr = []
        else:
            self.fit_corr = fit_corr

        self.model = model
        self.bounds = bounds

        if self.model == 'planck':
            # Fitting blackbody radiation
            if isinstance(bounds['teff'], list) and isinstance(
                    bounds['radius'], list):
                # Update temperature and radius parameters in case of multiple blackbody components
                self.n_planck = len(bounds['teff'])

                self.modelpar = []
                self.bounds = {}

                for i, item in enumerate(bounds['teff']):
                    self.modelpar.append(f'teff_{i}')
                    self.modelpar.append(f'radius_{i}')

                    self.bounds[f'teff_{i}'] = bounds['teff'][i]
                    self.bounds[f'radius_{i}'] = bounds['radius'][i]

            else:
                # Fitting a single blackbody compoentn
                self.n_planck = 1

                self.modelpar = ['teff', 'radius']
                self.bounds = bounds

        else:
            # Fitting self-consistent atmospheric models
            if self.bounds is not None:
                readmodel = read_model.ReadModel(self.model)
                bounds_grid = readmodel.get_bounds()

                for item in bounds_grid:
                    if item not in self.bounds:
                        # Set the parameter boundaries to the grid boundaries if set to None
                        self.bounds[item] = bounds_grid[item]

            else:
                # Set all parameter boundaries to the grid boundaries
                readmodel = read_model.ReadModel(self.model, None, None)
                self.bounds = readmodel.get_bounds()

            if 'radius' not in self.bounds:
                self.bounds['radius'] = (0.8, 1.5)

            self.n_planck = 0

            self.modelpar = readmodel.get_parameters()
            self.modelpar.append('radius')

        # Select filters and spectra

        if isinstance(inc_phot, bool):
            if inc_phot:
                # Select all filters if True
                species_db = database.Database()
                objectbox = species_db.get_object(object_name)
                inc_phot = objectbox.filters

            else:
                inc_phot = []

        if isinstance(inc_spec, bool):
            if inc_spec:
                # Select all filters if True
                species_db = database.Database()
                objectbox = species_db.get_object(object_name)
                inc_spec = list(objectbox.spectrum.keys())

            else:
                inc_spec = []

        # Include photometric data

        self.objphot = []
        self.modelphot = []

        for item in inc_phot:
            if self.model == 'planck':
                # Create SyntheticPhotometry objects when fitting a Planck function
                print(f'Creating synthetic photometry: {item}...',
                      end='',
                      flush=True)
                self.modelphot.append(photometry.SyntheticPhotometry(item))

            else:
                # Or interpolate the model grid for each filter
                print(f'Interpolating {item}...', end='', flush=True)
                readmodel = read_model.ReadModel(self.model, filter_name=item)
                readmodel.interpolate_grid(wavel_resample=None,
                                           smooth=False,
                                           spec_res=None)
                self.modelphot.append(readmodel)

            print(' [DONE]')

            # Store the flux and uncertainty for each filter
            obj_phot = self.object.get_photometry(item)
            self.objphot.append(np.array([obj_phot[2], obj_phot[3]]))

        # Include spectroscopic data

        if inc_spec:
            # Select all spectra
            self.spectrum = self.object.get_spectrum()

            # Select the spectrum names that are not in inc_spec
            spec_remove = []
            for item in self.spectrum:
                if item not in inc_spec:
                    spec_remove.append(item)

            # Remove the spectra that are not included in inc_spec
            for item in spec_remove:
                del self.spectrum[item]

            self.n_corr_par = 0

            for item in self.spectrum:
                if item in self.fit_corr:
                    self.modelpar.append(f'corr_len_{item}')
                    self.modelpar.append(f'corr_amp_{item}')

                    self.bounds[f'corr_len_{item}'] = (
                        -3., 0.)  # log10(corr_len) (um)
                    self.bounds[f'corr_amp_{item}'] = (0., 1.)

                    self.n_corr_par += 2

            self.modelspec = []

            if self.model != 'planck':

                for key, value in self.spectrum.items():
                    print(f'\rInterpolating {key}...', end='', flush=True)

                    wavel_range = (0.9 * value[0][0, 0], 1.1 * value[0][-1, 0])

                    readmodel = read_model.ReadModel(self.model,
                                                     wavel_range=wavel_range)

                    readmodel.interpolate_grid(
                        wavel_resample=self.spectrum[key][0][:, 0],
                        smooth=True,
                        spec_res=self.spectrum[key][3])

                    self.modelspec.append(readmodel)

                    print(' [DONE]')

        else:
            self.spectrum = {}
            self.modelspec = None
            self.n_corr_par = 0

        for item in self.spectrum:
            if item in bounds:

                if bounds[item][0] is not None:
                    # Add the flux scaling parameter
                    self.modelpar.append(f'scaling_{item}')
                    self.bounds[f'scaling_{item}'] = (bounds[item][0][0],
                                                      bounds[item][0][1])

                if bounds[item][1] is not None:
                    # Add the error offset parameters
                    self.modelpar.append(f'error_{item}')
                    self.bounds[f'error_{item}'] = (bounds[item][1][0],
                                                    bounds[item][1][1])

                if item in self.bounds:
                    del self.bounds[item]

        if 'lognorm_radius' in self.bounds and 'lognorm_sigma' in self.bounds and \
                'lognorm_ext' in self.bounds:

            self.cross_sections, _, _ = dust_util.interp_lognorm(
                inc_phot, inc_spec, self.spectrum)

            self.modelpar.append('lognorm_radius')
            self.modelpar.append('lognorm_sigma')
            self.modelpar.append('lognorm_ext')

            self.bounds['lognorm_radius'] = (
                np.log10(self.bounds['lognorm_radius'][0]),
                np.log10(self.bounds['lognorm_radius'][1]))

        elif 'powerlaw_max' in self.bounds and 'powerlaw_exp' in self.bounds and \
                'powerlaw_ext' in self.bounds:

            self.cross_sections, _, _ = dust_util.interp_powerlaw(
                inc_phot, inc_spec, self.spectrum)

            self.modelpar.append('powerlaw_max')
            self.modelpar.append('powerlaw_exp')
            self.modelpar.append('powerlaw_ext')

            self.bounds['powerlaw_max'] = (np.log10(
                self.bounds['powerlaw_max'][0]),
                                           np.log10(
                                               self.bounds['powerlaw_max'][1]))

        else:
            self.cross_sections = None

        if 'ism_ext' in self.bounds and 'ism_red' in self.bounds:
            self.modelpar.append('ism_ext')
            self.modelpar.append('ism_red')

        print(f'Fitting {len(self.modelpar)} parameters:')

        for item in self.modelpar:
            print(f'   - {item}')

        print('Prior boundaries:')

        for key, value in self.bounds.items():
            print(f'   - {key} = {value}')
Exemplo n.º 23
0
    def __init__(self,
                 objname,
                 filters,
                 model,
                 bounds,
                 inc_phot=True,
                 inc_spec=True):
        """
        Parameters
        ----------
        objname : str
            Object name in the database.
        filters : tuple(str, )
            Filter IDs for which the photometry is selected. All available photometry of the
            object is selected if set to None.
        model : str
            Atmospheric model.
        bounds : dict
            Parameter boundaries. Full parameter range is used if set to None or not specified.
            The radius parameter range is set to 0-5 Rjup if not specified.
        inc_phot : bool
            Include photometry data with the fit.
        inc_spec : bool
            Include spectral data with the fit.

        Returns
        -------
        NoneType
            None
        """

        self.object = read_object.ReadObject(objname)
        self.distance = self.object.get_distance()

        self.model = model
        self.bounds = bounds

        if not inc_phot and not inc_spec:
            raise ValueError('No photometric or spectral data has been selected.')

        if self.bounds is not None and 'teff' in self.bounds:
            teff_bound = self.bounds['teff']
        else:
            teff_bound = None

        if self.bounds is not None:
            readmodel = read_model.ReadModel(self.model, None, teff_bound)
            bounds_grid = readmodel.get_bounds()

            for item in bounds_grid:
                if item not in self.bounds:
                    self.bounds[item] = bounds_grid[item]

        else:
            readmodel = read_model.ReadModel(self.model, None, None)
            self.bounds = readmodel.get_bounds()

        if 'radius' not in self.bounds:
            self.bounds['radius'] = (0., 5.)

        if inc_phot:
            self.objphot = []
            self.modelphot = []
            self.synphot = []

            if not filters:
                species_db = database.Database()
                objectbox = species_db.get_object(objname, None)
                filters = objectbox.filter

            for item in filters:
                readmodel = read_model.ReadModel(self.model, item, teff_bound)
                readmodel.interpolate()
                self.modelphot.append(readmodel)

                sphot = photometry.SyntheticPhotometry(item)
                self.synphot.append(sphot)

                obj_phot = self.object.get_photometry(item)
                self.objphot.append((obj_phot[2], obj_phot[3]))

        else:
            self.objphot = None
            self.modelphot = None
            self.synphot = None

        if inc_spec:
            self.spectrum = self.object.get_spectrum()
            self.instrument = self.object.get_instrument()
            self.modelspec = read_model.ReadModel(self.model, (0.9, 2.5), teff_bound)

        else:
            self.spectrum = None
            self.instrument = None
            self.modelspec = None

        self.modelpar = readmodel.get_parameters()
        self.modelpar.append('radius')
Exemplo n.º 24
0
    def add_object(self,
                   object_name,
                   distance=None,
                   app_mag=None,
                   spectrum=None,
                   instrument=None):
        """
        Parameters
        ----------
        object_name: str
            Object name.
        distance : float
            Distance (pc). Not written if set to None.
        app_mag : dict
            Apparent magnitudes. Not written if set to None.
        spectrum : str
            Spectrum filename. The first three columns should contain the wavelength (micron),
            flux density (W m-2 micron-1), and the error (W m-2 micron-1). Not written if set
            to None.
        instrument : str
            Instrument that was used for the spectrum (currently only 'gpi' possible). Not
            used if set to None.

        Returns
        -------
        NoneType
            None
        """

        h5_file = h5py.File(self.database, 'a')

        if 'objects' not in h5_file:
            h5_file.create_group('objects')

        if 'objects/' + object_name not in h5_file:
            h5_file.create_group('objects/' + object_name)

        if distance:
            if 'objects/' + object_name + '/distance' in h5_file:
                del h5_file['objects/' + object_name + '/distance']

            h5_file.create_dataset('objects/' + object_name + '/distance',
                                   data=distance,
                                   dtype='f')  # [pc]

        if app_mag:
            flux = {}
            error = {}

            for item in app_mag:
                synphot = photometry.SyntheticPhotometry(item)
                flux[item], error[item] = synphot.magnitude_to_flux(
                    app_mag[item][0], app_mag[item][1])

            for item in app_mag:
                if 'objects/' + object_name + '/' + item in h5_file:
                    del h5_file['objects/' + object_name + '/' + item]

                data = np.asarray([
                    app_mag[item][0], app_mag[item][1], flux[item], error[item]
                ])

                # [mag], [mag], [W m-2 micron-1], [W m-2 micron-1]
                h5_file.create_dataset('objects/' + object_name + '/' + item,
                                       data=data,
                                       dtype='f')

        sys.stdout.write('Adding object: ' + object_name + '...')
        sys.stdout.flush()

        if spectrum:

            if 'objects/' + object_name + '/spectrum' in h5_file:
                del h5_file['objects/' + object_name + '/spectrum']

            data = np.loadtxt(spectrum)

            dset = h5_file.create_dataset('objects/' + object_name +
                                          '/spectrum',
                                          data=data[:, 0:3],
                                          dtype='f')

            dset.attrs['instrument'] = str(instrument)

        sys.stdout.write(' [DONE]\n')
        sys.stdout.flush()

        h5_file.close()