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)
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"]
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 names. 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) 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 coverage 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)
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']
def zero_point(self) -> np.float64: """ Internal function for calculating the zero point of the provided ``filter_name``. Returns ------- float Zero-point flux (W m-2 um-1). """ if self.wavel_range is None: transmission = read_filter.ReadFilter(self.filter_name) self.wavel_range = transmission.wavelength_range() h5_file = h5py.File(self.database, "r") try: h5_file["spectra/calibration/vega"] except KeyError: h5_file.close() species_db = database.Database() species_db.add_spectra("vega") h5_file = h5py.File(self.database, "r") readcalib = read_calibration.ReadCalibration("vega", None) calibbox = readcalib.get_spectrum() wavelength = calibbox.wavelength flux = calibbox.flux wavelength_crop = wavelength[(wavelength > self.wavel_range[0]) & (wavelength < self.wavel_range[1])] flux_crop = flux[(wavelength > self.wavel_range[0]) & (wavelength < self.wavel_range[1])] h5_file.close() return self.spectrum_to_flux(wavelength_crop, flux_crop)[0]
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. """ sys.stdout.write('Calculating synthetic photometry...') sys.stdout.flush() flux = {} if datatype == 'model': for item in filters: readmodel = read_model.ReadModel(spectrum, item) flux[item] = readmodel.get_photometry(parameters) elif datatype == 'calibration': for item in filters: readcalib = read_calibration.ReadCalibration(spectrum, item) flux[item] = readcalib.get_photometry(parameters) sys.stdout.write(' [DONE]\n') sys.stdout.flush() return box.create_box('synphot', name='synphot', flux=flux)
def zero_point(self): """ Returns ------- tuple(float, float) """ if self.wl_range is None: transmission = read_filter.ReadFilter(self.filter_name) self.wl_range = transmission.wavelength_range() h5_file = h5py.File(self.database, 'r') try: h5_file['spectra/calibration/vega'] except KeyError: h5_file.close() species_db = database.Database() species_db.add_spectrum('vega') h5_file = h5py.File(self.database, 'r') readcalib = read_calibration.ReadCalibration('vega', None) calibbox = readcalib.get_spectrum() wavelength = calibbox.wavelength flux = calibbox.flux wavelength_crop = wavelength[(wavelength > self.wl_range[0]) & (wavelength < self.wl_range[1])] flux_crop = flux[(wavelength > self.wl_range[0]) & (wavelength < self.wl_range[1])] h5_file.close() return self.spectrum_to_photometry(wavelength_crop, flux_crop)
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)
def get_model(self, model_param: Dict[str, float], spec_res: Optional[float] = None, wavel_resample: Optional[np.ndarray] = None, magnitude: bool = False, smooth: bool = False) -> box.ModelBox: """ Function for extracting a model spectrum by linearly interpolating the model grid. Parameters ---------- model_param : dict Dictionary with the model parameters and values. The values should be within the boundaries of the grid. The grid boundaries of the spectra in the database can be obtained with :func:`~species.read.read_model.ReadModel.get_bounds()`. spec_res : float, None Spectral resolution that is used for smoothing the spectrum with a Gaussian kernel when ``smooth=True`` and/or resampling the spectrum when ``wavel_range`` of ``FitModel`` is not ``None``. The original wavelength points are used if both ``spec_res`` and ``wavel_resample`` are set to ``None``, or if ``smooth`` is set to ``True``. wavel_resample : np.ndarray, None Wavelength points (um) to which the spectrum is resampled. In that case, ``spec_res`` can still be used for smoothing the spectrum with a Gaussian kernel. magnitude : bool Normalize the spectrum with a flux calibrated spectrum of Vega and return the magnitude instead of flux density. smooth : bool If ``True``, the spectrum is smoothed with a Gaussian kernel to the spectral resolution of ``spec_res``. This requires either a uniform spectral resolution of the input spectra (fast) or a uniform wavelength spacing of the input spectra (slow). Returns ------- species.core.box.ModelBox Box with the model spectrum. """ if smooth and spec_res is None: warnings.warn('The \'spec_res\' argument is required for smoothing the spectrum when ' '\'smooth\' is set to True.') grid_bounds = self.get_bounds() extra_param = ['radius', 'distance', 'mass', 'luminosity', 'lognorm_radius', 'lognorm_sigma', 'lognorm_ext', 'ism_ext', 'ism_red', 'powerlaw_max', 'powerlaw_exp', 'powerlaw_ext'] 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 model_param[key] < grid_bounds[key][0]: raise ValueError(f'The input value of \'{key}\' is smaller than the lower ' f'boundary of the model grid ({model_param[key]} < ' f'{grid_bounds[key][0]}).') if model_param[key] > grid_bounds[key][1]: raise ValueError(f'The input value of \'{key}\' is larger than the upper ' f'boundary of the model grid ({model_param[key]} > ' f'{grid_bounds[key][1]}).') for key in model_param.keys(): if key not in self.get_parameters() and key not in extra_param: warnings.warn(f'The \'{key}\' parameter is not required by \'{self.model}\' so ' f'the parameter will be ignored. The mandatory parameters are ' f'{self.get_parameters()}.') if 'mass' in model_param and 'radius' not in model_param: mass = 1e3 * model_param['mass'] * constants.M_JUP # (g) radius = math.sqrt(1e3 * constants.GRAVITY * mass / (10.**model_param['logg'])) # (cm) model_param['radius'] = 1e-2 * radius / constants.R_JUP # (Rjup) if self.spectrum_interp is None: self.interpolate_model() if self.wavel_range is None: wl_points = self.get_wavelengths() self.wavel_range = (wl_points[0], wl_points[-1]) parameters = [] if 'teff' in model_param: parameters.append(model_param['teff']) if 'logg' in model_param: parameters.append(model_param['logg']) if 'feh' in model_param: parameters.append(model_param['feh']) if 'co' in model_param: parameters.append(model_param['co']) if 'fsed' in model_param: parameters.append(model_param['fsed']) flux = self.spectrum_interp(parameters)[0] if 'radius' in model_param: model_param['mass'] = read_util.get_mass(model_param['logg'], model_param['radius']) if 'distance' in model_param: scaling = (model_param['radius']*constants.R_JUP)**2 / \ (model_param['distance']*constants.PARSEC)**2 flux *= scaling if smooth: flux = read_util.smooth_spectrum(wavelength=self.wl_points, flux=flux, spec_res=spec_res) if wavel_resample is not None: flux = spectres.spectres(wavel_resample, self.wl_points, flux, spec_errs=None, fill=np.nan, verbose=True) elif spec_res is not None and not smooth: index = np.where(np.isnan(flux))[0] if index.size > 0: raise ValueError('Flux values should not contains NaNs. Please make sure that ' 'the parameter values and the wavelength range are within ' 'the grid boundaries as stored in the database.') wavel_resample = read_util.create_wavelengths( (self.wl_points[0], self.wl_points[-1]), spec_res) indices = np.where((wavel_resample > self.wl_points[0]) & (wavel_resample < self.wl_points[-2]))[0] wavel_resample = wavel_resample[indices] flux = spectres.spectres(wavel_resample, self.wl_points, flux, spec_errs=None, fill=np.nan, verbose=True) if magnitude: quantity = 'magnitude' with h5py.File(self.database, 'r') as h5_file: try: h5_file['spectra/calibration/vega'] except KeyError: h5_file.close() species_db = database.Database() species_db.add_spectrum('vega') h5_file = h5py.File(self.database, 'r') readcalib = read_calibration.ReadCalibration('vega', filter_name=None) calibbox = readcalib.get_spectrum() if wavel_resample is not None: new_spec_wavs = wavel_resample else: new_spec_wavs = self.wl_points flux_vega, _ = spectres.spectres(new_spec_wavs, calibbox.wavelength, calibbox.flux, spec_errs=calibbox.error, fill=np.nan, verbose=True) flux = -2.5*np.log10(flux/flux_vega) else: quantity = 'flux' if np.isnan(np.sum(flux)): warnings.warn(f'The resampled spectrum contains {np.sum(np.isnan(flux))} NaNs, ' f'probably because the original wavelength range does not fully ' f'encompass the new wavelength range. The happened with the ' f'following parameters: {model_param}.') if wavel_resample is None: wavelength = self.wl_points else: wavelength = wavel_resample # is_finite = np.where(np.isfinite(flux))[0] # # if wavel_resample is None: # wavelength = self.wl_points[is_finite] # else: # wavelength = wavel_resample[is_finite] # # if wavelength.shape[0] == 0: # raise ValueError(f'The model spectrum is empty. Perhaps the grid could not be ' # f'interpolated at {model_param} because zeros are stored in the ' # f'database.') model_box = box.create_box(boxtype='model', model=self.model, wavelength=wavelength, flux=flux, parameters=model_param, quantity=quantity) if 'lognorm_radius' in model_param and 'lognorm_sigma' in model_param and \ 'lognorm_ext' in model_param: model_box.flux = self.apply_lognorm_ext(model_box.wavelength, model_box.flux, model_param['lognorm_radius'], model_param['lognorm_sigma'], model_param['lognorm_ext']) if 'powerlaw_max' in model_param and 'powerlaw_exp' in model_param and \ 'powerlaw_ext' in model_param: model_box.flux = self.apply_powerlaw_ext(model_box.wavelength, model_box.flux, model_param['powerlaw_max'], model_param['powerlaw_exp'], model_param['powerlaw_ext']) if 'ism_ext' in model_param and 'ism_red' in model_param: model_box.flux = self.apply_ism_ext(model_box.wavelength, model_box.flux, model_param['ism_ext'], model_param['ism_red']) if 'radius' in model_box.parameters: model_box.parameters['luminosity'] = 4. * np.pi * ( model_box.parameters['radius'] * constants.R_JUP)**2 * constants.SIGMA_SB * \ model_box.parameters['teff']**4. / constants.L_SUN # (Lsun) return model_box
def get_mcmc_spectra(self, tag, burnin, random, wavelength, specres=None): """ Parameters ---------- tag : str Database tag with the MCMC samples. burnin : int Number of burnin steps. random : int Number of random samples. wavelength : tuple(float, float) or str Wavelength range (micron) or filter name. Full spectrum if set to None. specres : float Spectral resolution, achieved by smoothing with a Gaussian kernel. The original wavelength points are used if set to None. Returns ------- tuple(species.core.box.ModelBox, ) Boxes with the randomly sampled spectra. """ sys.stdout.write('Getting MCMC spectra...') sys.stdout.flush() h5_file = h5py.File(self.database, 'r') dset = h5_file['results/mcmc/' + tag] nparam = dset.attrs['nparam'] spectrum_type = dset.attrs['type'] spectrum_name = dset.attrs['spectrum'] if specres is not None and spectrum_type == 'calibration': warnings.warn( "Smoothing of the spectral resolution is not implemented for calibration " "spectra.") if dset.attrs.__contains__('distance'): distance = dset.attrs['distance'] else: distance = None samples = np.asarray(dset) samples = samples[:, burnin:, :] ran_walker = np.random.randint(samples.shape[0], size=random) ran_step = np.random.randint(samples.shape[1], size=random) samples = samples[ran_walker, ran_step, :] param = [] for i in range(nparam): param.append(str(dset.attrs['parameter' + str(i)])) if spectrum_type == 'model': readmodel = read_model.ReadModel(spectrum_name, wavelength) elif spectrum_type == 'calibration': readcalib = read_calibration.ReadCalibration(spectrum_name, None) boxes = [] progbar = progress.bar.Bar('\rGetting MCMC spectra...', max=samples.shape[0], suffix='%(percent)d%%') for i in range(samples.shape[0]): model_par = {} for j in range(samples.shape[1]): model_par[param[j]] = samples[i, j] if distance: model_par['distance'] = distance if spectrum_type == 'model': specbox = readmodel.get_model(model_par, specres) elif spectrum_type == 'calibration': specbox = readcalib.get_spectrum(model_par) box.type = 'mcmc' boxes.append(specbox) progbar.next() progbar.finish() h5_file.close() return tuple(boxes)