def make_emission_from_emissivity(temp, emiss_src_spec): """ Create an emission SourceSpectrum using a blackbody and an emissivity curve Parameters ---------- temp : float, Quantity [Kelvin] If float, then must be in Kelvin emiss_src_spec : synphot.SpectralElement An emissivity response curve in the range [0..1] Returns ------- flux : synphot.SourceSpectrum """ if isinstance(temp, u.Quantity): temp = temp.to(u.Kelvin, equivalencies=u.temperature()).value if emiss_src_spec is None: logging.warning("Either emission or emissivity must be set") flux = None else: flux = SourceSpectrum(BlackBody1D, temperature=temp) flux.meta["solid_angle"] = u.sr**-1 flux = flux * emiss_src_spec flux.meta["history"] = [ "Created from Blackbody curve. Units are to be" " understood as per steradian" ] return flux
def convert_to_list_of_spectra(spectra, lam): spectra_list = [] if isinstance(spectra, SourceSpectrum): spectra_list += [spectra] elif lam is None and\ isinstance(spectra, (tuple, list)) and \ isinstance(spectra[0], SourceSpectrum): spectra_list += spectra elif lam is not None and len(spectra.shape) == 1 and \ isinstance(spectra, np.ndarray) and \ isinstance(lam, np.ndarray): spec = SourceSpectrum(Empirical1D, points=lam, lookup_table=spectra) spectra_list += [spec] elif ((isinstance(spectra, np.ndarray) and len(spectra.shape) == 2) or (isinstance(spectra, (list, tuple)) and isinstance(spectra[0], np.ndarray))) and \ isinstance(lam, np.ndarray): for sp in spectra: spec = SourceSpectrum(Empirical1D, points=lam, lookup_table=sp) spectra_list += [spec] return spectra_list
def add_abs_lines(self, center, ew, fwhm): """ TODO: accept different profiles (Lorentz1D, Voigt1D, etc) Add a absorption line of to a spectrum with center, fwhm and equivalent width specified by the user It also supports emission lines if ew is negative Parameters ---------- center: float, list, np.ndarray, u.Quantity The center of the line fwhm: float, list, np.ndarray, u.Quantity The FWHM of the line ew: float, list, np.ndarray, u.Quantity The Equivalent Width of the line Returns ------- Spextrum """ if isinstance(center, u.Quantity) is True: center = center.to(u.AA).value if isinstance(ew, u.Quantity) is True: ew = ew.to(u.AA).value if isinstance(fwhm, u.Quantity) is True: fwhm = fwhm.to(u.AA).value centers = np.array([center]).flatten() ews = np.array([ew]).flatten() fwhms = np.array([fwhm]).flatten() sp = self # .__class__(modelclass=self.model) sp.meta.update({"em_lines": {"center": list(centers), "ew": list(ews), "fwhm": list(fwhms)}}) for c, e, f in zip(centers, ews, fwhms): sign = -1 * np.sign(e) # to keep the convention that EL are negative and ABS are positive left, right = c - np.abs(e / 2), c + np.abs(e / 2) wavelengths = self.waveset[(self.waveset.value >= left) & (self.waveset.value <= right)] fluxes = units.convert_flux(wavelengths=wavelengths, fluxes=self(wavelengths), out_flux_unit=units.FLAM) flux = np.trapz(fluxes.value, wavelengths.value) line = GaussianFlux1D(mean=c, total_flux=sign * flux, fwhm=f) lam = line.sampleset(factor_step=0.35) # bit better than Nyquist g_abs = SourceSpectrum(Empirical1D, points=lam, lookup_table=line(lam)) sp = sp + g_abs if (sp(wavelengths).value < 0).any(): warnings.warn("Warning: Flux<0 for specified EW and FHWM, setting it to Zero") waves = sp.waveset[sp(sp.waveset) < 0] zero_sp = SourceSpectrum(Empirical1D, points=waves, lookup_table=-1 * sp(waves).value) sp = sp + zero_sp # Spextrum(modelclass=sp.model + zero_sp.model) sp = self._restore_attr(Spextrum(modelclass=sp)) return sp
def get_normalized_star_spectrum(spectral_type, magnitude, filter_name): """ spec_data = get_normalized_star_spectrum(spectral_type, magnitude, filter_name) Returns a structure containing the synthetic spectrum of the star having the spectral type and magnitude in the specified input filter. Magnitude is in VEGAMAG-F(lambda) system. Spectra are from PICKLES, PASP, 110, 863 (1998) Absolute flux spectra, no effect of atmospheric and instrument transmission Parameters ---------- r0AtZenith: float overall r0 at zenith [m] spectral_type: string. spectral type and luminosity class (e.g. G2V or M4III) or 'vega' magnitude: float. magnitude in the filter_name filter filter_name: string. Name of the filter. See Filters.get() for the list of available filters Returns ------- spectrum: synphot.SourceSpectrum object defining the spectrum Examples -------- Plot the spectrum of a vega, A0V, G2V stars of mag=8 defined on JohnsonR filter >>> sp= get_normalized_star_spectrum('vega', 8, Filters.JOHNSON_R) >>> spA0V= get_normalized_star_spectrum('A0V', 8, Filters.JOHNSON_R) >>> spG2V= get_normalized_star_spectrum('G2V', 8, Filters.JOHNSON_R) >>> plt.plot(sp.waveset, sp(sp.waveset), label='Vega') >>> plt.plot(spA0V.waveset, spA0V(spA0V.waveset), label='A0V') >>> plt.plot(spG2V.waveset, spG2V(spG2V.waveset), label='G2V') >>> plt.grid(True) >>> plt.xlabel('nm') >>> plt.ylabel('FLAM') >>> plt.xlim(0, 10000) >>> plt.legend() """ # read the sourcespectrum if spectral_type == 'vega': spectrum = SourceSpectrum.from_vega() else: spectrum = SourceSpectrum.from_file( PickelsLibrary.filename(spectral_type)) bandpass = Filters.get(filter_name) spectrum_norm = spectrum.normalize( magnitude * synphot.units.VEGAMAG, bandpass, vegaspec=SourceSpectrum.from_vega()) return spectrum_norm
def test_round_trip_snr_limmag(snr, exptime, ra, dec, time, night): """Test round trip: get_snr(get_limmag(...))""" kwargs = dict( exptime=exptime * u.s, coord=SkyCoord(ra * u.deg, dec * u.deg), time=time, night=night) limmag = get_limmag( SourceSpectrum(ConstFlux1D, amplitude=0*u.ABmag), snr=snr, **kwargs) snr_2 = get_snr(SourceSpectrum(ConstFlux1D, amplitude=limmag), **kwargs) assert snr_2 == approx(snr)
def misc(): # get_vega() downloads this one synphot.specio.read_remote_spec( 'http://ssb.stsci.edu/cdbs/calspec/alpha_lyr_stis_008.fits') # G5V of UVKLIB subset of Pickles library # see http://www.stsci.edu/hst/instrumentation/reference-data-for-calibration-and-tools/astronomical-catalogs/pickles-atlas.html synphot.specio.read_remote_spec( 'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_27.fits') # read the sourcespectrum spG5V = SourceSpectrum.from_file( 'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_27.fits') spG2V = SourceSpectrum.from_file( 'http://ssb.stsci.edu/cdbs/grid/pickles/dat_uvk/pickles_uk_26.fits') filtR = SpectralElement.from_filter('johnson_r') spG2V_19r = spG2V.normalize(19 * synphot.units.VEGAMAG, filtR, vegaspec=SourceSpectrum.from_vega()) bp = SpectralElement(Box1D, x_0=700 * u.nm, width=600 * u.nm) obs = Observation(spG2V_19r, bp) obs.countrate(area=50 * u.m**2) bp220 = SpectralElement(Box1D, x_0=800 * u.nm, width=400 * u.nm) bpCRed = SpectralElement(Box1D, x_0=1650 * u.nm, width=300 * u.nm) * 0.8 Observation(spG2V_19r, bp220).countrate(area=50 * u.m**2) Observation(spG2V_19r, bpCRed).countrate(area=50 * u.m**2) spM0V_8R = get_normalized_star_spectrum('M0V', 8.0, 'johnson_r') uPhotonSecM2Micron = u.photon / (u.s * u.m**2 * u.micron) spG2V_8R = get_normalized_star_spectrum("G2V", 8.0, 'johnson_r') plt.plot(spG2V_8R.waveset, spG2V_8R(spG2V_8R.waveset).to(uPhotonSecM2Micron)) # compare with Armando's spG2V_19R = get_normalized_star_spectrum("G2V", 19, 'johnson_r') bp = SpectralElement(Box1D, x_0=700 * u.nm, width=600 * u.nm) obs = Observation(spG2V_19R, bp) obs.countrate(area=50 * u.m**2) # zeropoint in filtro r in erg/s/cm2/A Observation(get_normalized_star_spectrum('A0V', 0, 'johnson_r'), SpectralElement.from_filter('johnson_r')).effstim('flam') # zeropoint in ph/s/m2 Observation(get_normalized_star_spectrum('A0V', 0, 'johnson_r'), SpectralElement.from_filter('johnson_r')).countrate(area=1 * u.m**2)
def make_emission_from_array(flux, wave, meta): """ Create an emission SourceSpectrum using array. Takes care of bins and solid angles. The solid_angle is kept in the returned SourceSpectrum meta dictionary under self.meta["solid_angle"] Parameters ---------- flux : array-like, Quantity if flux is not an array, the ``emission_unit`` must be in meta dict wave : array-like, Quantity if flux is not an array, the ``wavelength_unit`` must be in meta dict meta : dict Returns ------- flux : synphot.SourceSpectrum """ if not isinstance(flux, u.Quantity): if "emission_unit" in meta: flux = quantify(flux, meta["emission_unit"]) else: logging.warning("emission_unit must be set in self.meta, " "or emission must be an astropy.Quantity") flux = None if isinstance(wave, u.Quantity) and isinstance(flux, u.Quantity): flux_unit, angle = extract_type_from_unit(flux.unit, "solid angle") flux = flux / angle if is_flux_binned(flux.unit): flux = normalise_binned_flux(flux, wave) orig_unit = flux.unit flux = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) flux.meta["solid_angle"] = angle flux.meta["history"] = [ "Created from emission array with units {}" "".format(orig_unit) ] else: logging.warning("wavelength and emission must be " "astropy.Quantity py_objects") flux = None return flux
def from_arrays(cls, waves, flux, meta=None, wave_unit=u.AA, flux_unit=units.FLAM): """ Create a ``Passband`` directly from from arrays (lists, numpy.arrays, etc) Parameters ---------- waves: list-like flux: list-like meta: dictionary containing the metadata wave_unit: u.Quantity, defaulted to angstroms flux_unit: u.Quantiy, defaulted to FLAM Returns ------- Passband """ if isinstance(waves, u.Quantity) is False: waves = waves * wave_unit if isinstance(flux, (u.Quantity, u.core.Unit)) is False: flux = flux * flux_unit modelclass = SourceSpectrum(Empirical1D, points=waves, lookup_table=flux, meta=meta) sp = cls(modelclass=modelclass) sp.repr = repr(sp.model) return sp
def image_source(): n = 50 unit = u.Unit("ph s-1 m-2 um-1") wave = np.linspace(0.5, 2.5, n) * u.um specs = [ SourceSpectrum(Empirical1D, points=wave, lookup_table=np.linspace(0, 4, n) * unit) ] n = 50 im_wcs = wcs.WCS(naxis=2) im_wcs.wcs.cunit = [u.arcsec, u.arcsec] im_wcs.wcs.cdelt = [0.2, 0.2] im_wcs.wcs.crval = [0, 0] im_wcs.wcs.crpix = [n // 2, n // 2] im_wcs.wcs.ctype = ["RA---TAN", "DEC--TAN"] im = np.ones((n + 1, n + 1)) * 1E-11 im[0, n] += 5 im[n, 0] += 5 im[n // 2, n // 2] += 10 im_hdu = fits.ImageHDU(data=im, header=im_wcs.to_header()) im_hdu.header["SPEC_REF"] = 0 im_source = Source(image_hdu=im_hdu, spectra=specs) return im_source
def calcMagFromSpec(bp, specPath, redden=None): sp = SourceSpectrum.from_file(specPath) if redden: sp = sp * redden obs = Observation(sp, bp) counts = obs.countrate(1.0) return -2.5 * np.log10(counts.value)
def read_eso_spectra(filepath): try: hdul = fits.open(filepath) except FileNotFoundError: print("Cannot find file {}".format(filepath)) return None data = hdul[0].data hdr = hdul[0].header yyy = data if hdr.get('NAXIS3') == 4: # FLOYDS merged data, slice/bandid 1 has the extracted spectrum yyy = data[0][0] warnings.simplefilter('ignore', category=FITSFixedWarning) w = WCS(hdr, naxis=1, relax=False, fix=False) lam = w.wcs_pix2world(np.arange(len(yyy)), 0)[0] wavelength = get_x_units(lam) flux = get_y_units(yyy, filepath, hdr) source_spec = SourceSpectrum(Empirical1D, points=wavelength, lookup_table=flux, keep_neg=True, meta={'header': hdr}) return source_spec
def filter_vega_zp(filterfile, filterzero): ''' ###################################################### # Input # # -------------------------------------------------- # # filterfile: file containing filter function # # filterzero: flux corresponding to mag=0 # # -------------------------------------------------- # # Output # # -------------------------------------------------- # # mag_0: magnitude of Vega in filter system. # ###################################################### ''' from synphot import SourceSpectrum, SpectralElement, Observation #load Vega spectrum spec = SourceSpectrum.from_vega() #Load ascii filter function if filterfile.split('/')[-1][:6] == 'Bessel': filt = SpectralElement.from_file(filterfile, wave_unit='nm') else: filt = SpectralElement.from_file(filterfile, wave_unit='AA') wave = filt.waveset #Synthetic observation obs = Observation(spec, filt) flux = obs.effstim(flux_unit='jy', waverange=(wave[0],wave[-1])) #Calibrate to zero point (zp) mag_0 = -2.512*np.log10(flux/filterzero) return mag_0
def from_specutils(cls, spectrum_object): """ This function _tries_ to create a Spectrum from a ``specutils.Spectrum1D`` instance. ``specutils.Spectrum1D`` can read multiple file formats with the ``.read`` method. please read ``specutils`` documentation. Parameters ---------- spectrum_object: specutils.Spectrum1D object Returns ------- a Spextrum instance """ meta = spectrum_object.meta lam = spectrum_object.spectral_axis flux = spectrum_object.flux modelclass = SourceSpectrum(Empirical1D, points=lam, lookup_table=flux, meta=meta) sp = cls(modelclass=modelclass) sp.repr = "Spextrum.from_specutils(%s)" % repr(spectrum_object) return sp
def collapse(self, waveset): throughput = self.radiometry_table.throughput(waveset) self._throughput = SpectralElement(Empirical1D, points=waveset, lookup_table=throughput) emission = self.radiometry_table.emission(waveset) self._emission = SourceSpectrum(Empirical1D, points=waveset, lookup_table=emission)
def extract_range_from_spectrum(spectrum, waverange): if not isinstance(spectrum, SourceSpectrum): raise ValueError(f"spectrum must be of type synphot.SourceSpectrum: " f"{type(spectrum)}") wave_min, wave_max = utils.quantify(waverange, u.um).to(u.AA).value spec_waveset = spectrum.waveset.to(u.AA).value mask = (spec_waveset > wave_min) * (spec_waveset < wave_max) if sum(mask) == 0: logging.warning(f"Waverange does not overlap with Spectrum waveset: " f"{[wave_min, wave_max]} <> {spec_waveset} " f"for spectrum {spectrum}") if wave_min < min(spec_waveset) or wave_max > max(spec_waveset): logging.warning(f"Waverange only partially overlaps with Spectrum waveset: " f"{[wave_min, wave_max]} <> {spec_waveset} " f"for spectrum {spectrum}") wave = np.r_[wave_min, spec_waveset[mask], wave_max] flux = spectrum(wave) new_spectrum = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) new_spectrum.meta.update(spectrum.meta) return new_spectrum
def sso_to_source_spec(self, tax_type): """Returns a SourceSpectrum from the passed <tax_type> if it is found in the Bus-DeMeo taxonomy, otherwise None is returned. The spectrum is produced by multiplying the reflectance spectra by a Kurucz model for the Sun so will need to be normalized""" source_spec = None if tax_type.lower().startswith('sso::') is False: tax_type = 'sso::' + tax_type.strip() config_item = conf.source_mapping.get(tax_type, None) if config_item is not None: filename = config_item() file_path = os.path.expandvars(filename) if not os.path.exists(file_path): file_path = str( pkg_resources.files('etc.data').joinpath(filename)) # Flux unit for LSST throughputs (*almost* FLAM but nm not Angstroms) lsst_funit = u.erg / u.cm**2 / u.s / u.nm source_spec = SourceSpectrum.from_file(file_path, wave_unit=u.nm, flux_unit=lsst_funit, header_start=1) source_spec.meta['header']['source'] = config_item.description source_spec.meta['header']['filename'] = filename return source_spec
def calculate_values(detector, filt, mjd, aper): # parameters can be removed from obsmode as needed obsmode = 'wfc3,{},{},mjd#{},aper#{}'.format(detector, filt, mjd, aper) bp = stsyn.band(obsmode) # STMag photflam = bp.unit_response(stsyn.conf.area) # inverse sensitivity in flam stmag = -21.1 - 2.5 * log10(photflam.value) # Pivot Wavelength and bandwidth photplam = bp.pivot() # pivot wavelength in angstroms bandwidth = bp.photbw() # bandwidth in angstroms # ABMag abmag = stmag - 5 * log10(photplam.value) + 18.6921 # Vegamag #for some reason stsyn.Vega doesn't load so we redefine it stsyn.Vega = SourceSpectrum.from_vega() obs = Observation( stsyn.Vega, bp, binset=bp.binset ) # synthetic observation of vega in bandpass using vega spectrum vegamag = -obs.effstim(flux_unit='obmag', area=stsyn.conf.area) return obsmode, photplam.value, bandwidth.value, photflam.value, stmag, abmag, vegamag.value
def get_phot(waves, exts, bands): """ Compute the extinction in the requested bands Parameters ---------- waves : numpy.ndarray The wavelengths exts : numpy.ndarray The extinction values at wavelengths "waves" bands: list of strings Bands requested Outputs ------- band extinctions : numpy array Calculated band extinctions """ # create a SourceSpectrum object from the extinction curve spectrum = SourceSpectrum( Empirical1D, points=waves * 1e4, lookup_table=exts, ) # path for band response curves band_path = ( "/Users/mdecleir/measure_extinction/measure_extinction/data/Band_RespCurves/" ) # dictionary linking the bands to their response curves bandnames = { "J": "2MASSJ", "H": "2MASSH", "K": "2MASSKs", "IRAC1": "IRAC1", "IRAC2": "IRAC2", "WISE1": "WISE1", "WISE2": "WISE2", "L": "AAOL", "M": "AAOM", } # compute the extinction value in each band band_ext = np.zeros(len(bands)) for k, band in enumerate(bands): # create the bandpass (as a SpectralElement object) bp = SpectralElement.from_file( "%s%s.dat" % (band_path, bandnames[band])) # assumes wavelengths are in Angstrom!! # integrate the extinction curve over the bandpass, only if the bandpass fully overlaps with the extinction curve (this actually excludes WISE2) if bp.check_overlap(spectrum) == "full": obs = Observation(spectrum, bp) band_ext[k] = obs.effstim().value else: band_ext[k] = np.nan return band_ext
def _unity_source(dx=0, dy=0, angle=0, weight=1, n=100): unit = u.Unit("ph s-1 m-2 um-1") wave = np.linspace(0.5, 2.5, n) * u.um specs = [ SourceSpectrum(Empirical1D, points=wave, lookup_table=np.ones(n) * unit) ] im_wcs = wcs.WCS(naxis=2) im_wcs.wcs.cunit = [u.arcsec, u.arcsec] im_wcs.wcs.cdelt = [1, 1] im_wcs.wcs.crval = [0, 0] im_wcs.wcs.crpix = [n / 2, n / 2] im_wcs.wcs.ctype = ["RA---TAN", "DEC--TAN"] im = np.ones((n, n)) im_hdu = fits.ImageHDU(data=im, header=im_wcs.to_header()) im_hdu.header["SPEC_REF"] = 0 im_source = Source(image_hdu=im_hdu, spectra=specs) angle = angle * np.pi / 180 im_source.fields[0].header["CRVAL1"] += dx * u.arcsec.to(u.deg) im_source.fields[0].header["CRVAL2"] += dy * u.arcsec.to(u.deg) im_source.fields[0].header["PC1_1"] = np.cos(angle) im_source.fields[0].header["PC1_2"] = np.sin(angle) im_source.fields[0].header["PC2_1"] = -np.sin(angle) im_source.fields[0].header["PC2_2"] = np.cos(angle) im_source.fields[0].data *= weight return im_source
def ab_spectrum(mag=0): # ..todo: the waves vector is a bit random, in particular its length, but sets the resolution of # the final spectrum in scopesim. Can this be make more general? waves = np.geomspace(100, 300000, 50000) sp = ConstFlux1D(amplitude=mag * u.ABmag) return SourceSpectrum(Empirical1D, points=waves, lookup_table=sp(waves))
def get_phot(spec, bands): """ Compute the fluxes in the requested bands. Parameters ---------- spec : SpecData object the spectrum bands: list of strings bands requested Outputs ------- band fluxes : numpy array calculated band fluxes """ # create a SourceSpectrum object from the spectrum, excluding the bad regions spectrum = SourceSpectrum( Empirical1D, points=spec.waves.to(u.Angstrom)[spec.npts != 0], lookup_table=spec.fluxes[spec.npts != 0], ) # path for band response curves band_path = pkg_resources.resource_filename("measure_extinction", "data/Band_RespCurves/") # dictionary linking the bands to their response curves bandnames = { "J": "2MASSJ", "H": "2MASSH", "K": "2MASSKs", "IRAC1": "IRAC1", "IRAC2": "IRAC2", "WISE1": "WISE1", "WISE2": "WISE2", "L": "AAOL", "M": "AAOM", } # define the units of the output fluxes funit = u.erg / (u.s * u.cm * u.cm * u.Angstrom) # compute the flux in each band fluxes = np.zeros(len(bands)) for k, band in enumerate(bands): # create the bandpass (as a SpectralElement object) bp = SpectralElement.from_file( "%s%s.dat" % (band_path, bandnames[band])) # assumes wavelengths are in Angstrom!! # integrate the spectrum over the bandpass, only if the bandpass fully overlaps with the spectrum (this actually excludes WISE2) if bp.check_overlap(spectrum) == "full": obs = Observation(spectrum, bp) fluxes[k] = obs.effstim(funit).value else: fluxes[k] = np.nan return fluxes
def apply_to(self, obj): """ obj == SourceBase - applies throughput obj == ImagePlaneBase - applies emission if Imager obj == FieldOfViewBase - applies emission if Spectrograph """ if isinstance(obj, SourceBase) and not self.is_empty: self.meta = utils.from_currsys(self.meta) for ii in range(len(obj.spectra)): spec = obj.spectra[ii] wave_val = spec.waveset.value wave_unit = spec.waveset.unit # angstrom wave_min = quantify(self.meta["wave_min"], u.um).to(u.AA) wave_max = quantify(self.meta["wave_max"], u.um).to(u.AA) mask = (wave_val > wave_min.value) * (wave_val < wave_max.value) wave = ([wave_min.value] + list(wave_val[mask]) + [wave_max.value]) * wave_unit thru = self.throughput(wave) flux = spec(wave) flux *= thru new_source = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) obj.spectra[ii] = new_source elif isinstance(obj, ImagePlaneBase) and not self.is_empty: # by calling use_area, the surface area is taken into account, but # the units are stuck in PHOTLAM for synphot emission = self.get_emission(use_area=True) # --> PHOTLAM * area if emission is not None: wave = emission.waveset # angstrom flux = emission(wave) # PHOTLAM --> ph s-1 cm-2 AA-1 * cm2 phs = (np.trapz(flux, wave) * u.cm**2).to(u.Unit("ph s-1")) else: phs = 0 * (u.ph / u.s) obj.hdu.data += phs.value elif isinstance(obj, FieldOfViewBase) and not self.is_empty: # ..todo:: Super hacky, FIX THIS!! emission = self.get_emission(use_area=True) # --> PHOTLAM * area if emission is not None: wave_val = emission.waveset.value wave_unit = emission.waveset.unit # angstrom wave_min = quantify(obj.meta["wave_min"], u.um).to(wave_unit) wave_max = quantify(obj.meta["wave_max"], u.um).to(wave_unit) mask = (wave_val > wave_min.value) * (wave_val < wave_max.value) wave = ([wave_min.value] + list(wave_val[mask]) + [wave_max.value]) * wave_unit flux = emission(wave) # PHOTLAM --> ph s-1 cm-2 AA-1 * cm2 phs = (np.trapz(flux, wave) * u.cm**2).to(u.Unit("ph s-1")) else: phs = 0 * (u.ph / u.s) obj.hdu.data += phs.value return obj
def __init__(self, template_name=None, modelclass=None, **kwargs): if template_name is not None: if template_name in DEFAULT_SPECTRA: template_name = DEFAULT_SPECTRA[template_name] SpectrumContainer.__init__(self, template_name) meta, lam, flux = self._loader() SourceSpectrum.__init__(self, Empirical1D, points=lam, lookup_table=flux, meta=meta, **kwargs) self.repr = "Spextrum(%s)" % self.template elif modelclass is not None: SourceSpectrum.__init__(self, modelclass=modelclass, **kwargs) else: raise ValueError("please define a spectra")
def test_throws_error_if_only_partial_overlap_exists(self): wave = np.arange(0.7, 2.05, 0.1) * u.um flux = np.arange(len(wave)) * PHOTLAM spec = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) with pytest.raises(ValueError): waverange = [1.98, 2.12] * u.um new_spec = fov_utils.extract_range_from_spectrum(spec, waverange)
def sky_spectrum_from_filter(self, filtername='V'): waveset = np.arange(3000, 12001, 1) * u.AA sky_flux = np.empty(len(waveset)) sky_flux.fill(self._photon_rate(filtername)) sky_flux = u.Quantity(sky_flux, unit=units.PHOTLAM) sky = SourceSpectrum(Empirical1D, points=waveset, lookup_table=sky_flux) return sky
def _planck(Tscale, T, eph): """Planck function and temperature for dust thermal emission.""" if not synphot: raise AstropyWarning( 'synphot is required for blackbody calculations') if T is None: T = Tscale * 278 / np.sqrt(eph['rh'] / u.au) * u.K # Does not include the factor of pi: return SourceSpectrum(BlackBody1D, temperature=T)
def test_returns_correct_units_with_without_area_argument( self, area, expected_units): flux = np.ones(11) * u.Unit("ph s-1 m-2 um-1") wave = np.linspace(1, 2, 11) * u.um spec = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) counts = source_utils.photons_in_range([spec], 1 * u.um, 2 * u.um, area=area) assert counts.unit == expected_units
def test_round_trip_snr_exptime(snr, mag, ra, dec, time, night): """Test round trip: get_snr(get_limmag(...))""" source = SourceSpectrum(ConstFlux1D, amplitude=mag * u.ABmag) kwargs = dict( coord=SkyCoord(ra * u.deg, dec * u.deg), night=night, time=time) exptime = get_exptime(source, snr=snr, **kwargs) snr_2 = get_snr(source, exptime=exptime, **kwargs) assert snr_2 == approx(snr)
def Scorr_vega(filt1,filt2, zerof1,zerof2): from synphot import SourceSpectrum #load Vega spectrum spec = SourceSpectrum.from_vega() #Scorr = -2.5log(flux2/flux1) such that mag2 = mag1 + Scorr mag1 = filter_mag(filt1, zerof1, spec) mag2 = filter_mag(filt2, zerof2, spec) scorr = mag2 - mag1 return scorr
def test_extracts_the_wave_range_needed(self): wave = np.arange(0.7, 2.5, 0.1) * u.um flux = np.arange(len(wave)) * PHOTLAM spec = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) waverange = [1.98, 2.12] * u.um new_spec = fov_utils.extract_range_from_spectrum(spec, waverange) assert len(new_spec.waverange) == 2 assert new_spec.waverange[0] == 1.98 * u.um assert new_spec(1.98 * u.um).value == approx(12.8)