def _calc_planck_mean_opacity(self): """Calculate the Planck-mean total opacity for each grid cell. See, e.g. Mihalas and Mihalas 1984, for details on the averaging process. Returns ------- kappa_planck_mean : astropy.units.Quantity ndarray Planck-mean opacity (shape Nshells) """ kappa_planck_mean = np.zeros(self.nshells) / units.cm for i in range(self.nshells): delta_nu = self.nu_bins[1:] - self.nu_bins[:-1] T = self.mdl.plasma.t_rad[i] tmp = ( blackbody_nu(self.nu_bins[:-1], T) * delta_nu * self.kappa_tot[:, 0] ).sum() tmp /= (blackbody_nu(self.nu_bins[:-1], T) * delta_nu).sum() kappa_planck_mean[i] = tmp return kappa_planck_mean.to("1/cm")
def SED_model(nu, Tdust, Mdust, phi, D): """ Perez-Beaupuits 2018 phi = beam area filling factor Bnu = planck function angular_size = source solid angle T = dust temperature Mdust = dust mass D = distance to the source phi_cold = filling factor of the coldest component kd = absorption coefficient nu = freq in GHz beta = 2 """ D = D * u.Mpc nu = u.Quantity(nu, u.GHz) Tdust = Tdust * u.K Mdust = Mdust * u.Msun angular_size_arcsec = 17.3 * 9.2 * (u.arcsec**2) #arcsec**2 angular_size = angular_size_arcsec.to(u.sr) d_m = D.to(u.m) Mdust_kg = Mdust.to(u.kg) Tcmb = 2.73 # K phi_cold = 5.0e-1 beta = 2 kd = (u.m**2 / u.kg) * 0.04 * (nu / (250. * u.GHz))**beta # m^2 / kg tau = kd * Mdust_kg / (angular_size.value * phi_cold * d_m**2) Bnu_T = blackbody_nu(nu, Tdust) Bnu_Tcmb = blackbody_nu(nu, Tcmb) Snu = (1. - np.exp(-tau)) * (Bnu_T - Bnu_Tcmb) * angular_size * phi Snu_jy = Snu.to(u.Jy) return Snu_jy
def I_external(nu, Tbkg, Tff, tau_ff, Tr, nu0=100e6 * u.MHz, alpha=-2.6): """ This method is equivalent to the IDL routine :param nu: Frequency. (Hz) or astropy.units.Quantity_ .. _astropy.units.Quantity: http://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity """ if Tbkg.value != 0: bnu_bkg = blackbody_nu(nu, Tbkg) else: bnu_bkg = 0 if Tff.value != 0: bnu_ff = blackbody_nu(nu, Tff) exp_ff = (1. - np.exp(-tau_ff)) else: bnu_ff = 0 exp_ff = 0 if Tr.value != 0: Tpl = plaw(nu, nu0, Tr, alpha) #Tr*np.power(nu/nu0, alpha) bnu_pl = blackbody_nu(nu, Tpl) else: bnu_pl = 0 return bnu_bkg + bnu_ff * exp_ff + bnu_pl
def __call__( self, T1c=200., F1c=0.5, T2c=800., F2c=0.5, T1f=200., F1f=0.5, T2f=800., F2f=0.5, *args, **kwargs ): #default values for temperatures and fractions will most likely never be used. *args will be a list of (8) absolute abundances of the dust species. #relativeAbundances = np.append(10**np.array(args),1.-np.sum(10**np.array(args))) # The 8th abundance is 1 minus the sum of the other 7. We are doing the parameter space exploration in the log space to ensure proper sampling of small fractions. dustAbundances = 10**np.array( args ) #We are doing the parameter space exploration in the log space to ensure proper sampling of small fractions. freq = const.c.value / (self.wavelength * 1e-6) fModel = (np.matmul(self.opacity_array, dustAbundances)) fModel = fModel * ( F1f * blackbody.blackbody_nu(freq, T1f).to(u.Jy / u.sr).value + F2f * blackbody.blackbody_nu(freq, T2f).to(u.Jy / u.sr).value) + ( F1c * blackbody.blackbody_nu(freq, T1c).to(u.Jy / u.sr).value + F2c * blackbody.blackbody_nu(freq, T2c).to(u.Jy / u.sr).value) self.modelFlux = fModel
def test_blackbody_array_temperature(): """Regression test to make sure that the temperature can be an array.""" flux = blackbody_nu(1.2 * u.mm, [100, 200, 300] * u.K) np.testing.assert_allclose( flux.value, [1.804908e-12, 3.721328e-12, 5.638513e-12], rtol=1e-5) flux = blackbody_nu([2, 4, 6] * u.mm, [100, 200, 300] * u.K) np.testing.assert_allclose( flux.value, [6.657915e-13, 3.420677e-13, 2.291897e-13], rtol=1e-5) flux = blackbody_nu(np.ones((3, 4)) * u.mm, np.ones(4) * u.K) assert flux.shape == (3, 4)
def I_cont(nu, Te, tau, I0, unitless=False): """ Computes the specific intensity due to a blackbody at temperature :math:`T_{e}` and optical depth :math:`\\tau`. It considers that there is background radiation with :math:`I_{0}`. :param nu: Frequency. :type nu: (Hz) or astropy.units.Quantity_ :param Te: Temperature of the source function. (K) or astropy.units.Quantity_ :param tau: Optical depth of the medium. :param I0: Specific intensity of the background radiation. Must have units of erg / (cm2 Hz s sr) or see `unitless`. :param unitless: If True the return :returns: The specific intensity of a ray of light after traveling in an LTE \ medium with source function :math:`B_{\\nu}(T_{e})` after crossing an optical \ depth :math:`\\tau_{\\nu}`. The units are erg / (cm2 Hz s sr). See `astropy.analytic_functions.blackbody.blackbody_nu`__ __ blackbody_ .. _blackbody: http://docs.astropy.org/en/stable/api/astropy.analytic_functions.blackbody.blackbody_nu.html#astropy.analytic_functions.blackbody.blackbody_nu """ bnu = blackbody_nu(nu, Te) if unitless: bnu = bnu.cgs.value return bnu * (1. - np.exp(-tau)) + I0 * np.exp(-tau)
def mass(integrated_flux, wave, t, kappa, distance): """ Accepts integrated flux in Jy, wavelength in m, temperature in K, dust opacity per unit mass in cm^2/g, and the distance to the object in pc, and computes the mass Parameters ---------- integrated_Flux : float integrated flux in Jy. wave : float wavelength (m) t: float (optional) temperature (K) kappa: float dust opacity per unit mass (cm^2g^-1) distance: float distance to the object (pc) """ integrated_flux = integrated_flux * (ap.Jy) wave = wave * u.m t = t * u.K kappa = kappa * (u.cm**2 / u.g) distance = distance * (u.pc) B = blackbody_nu(wave.to(u.Hz, equivalencies=u.spectral()), t) B = B * u.sr m = (distance**2. * integrated_flux) / (kappa * B) m = m.to(ap.solMass) return m
def column_density(flux, beam, wave, t, kappa, mu=2.8): """ Computes column density from continuum data Parameters ---------- flux : float flux in Jy/beam beam : array like beam size in arcseconds wave : float wavelength (m) t: float (optional) temperature (K) kappa: float dust opacity per unit mass (cm^2g^-1) mu : float (optional) molecular weight (default = 2.8; i.e. assumes density is given as density of hydrogen molecules) """ beam = beam * u.arcsec omega_beam = beam_solid_angle(beam) flux = (flux * u.Jy / u.beam).to( u.Jy / u.sr, equivalencies=u.beam_angular_area(omega_beam)) wave = wave * u.m t = t * u.K kappa = kappa * (u.cm**2 / u.g) B = blackbody_nu(wave.to(u.Hz, equivalencies=u.spectral()), t) N = flux / (mu * ap.M_p * kappa * B) N = N.to(1. / u.cm**2) return N
def __call__(self, t=1., scale=1., index=1., dist=1., *args, **kwargs): print(args) relativeAbundances = np.append( np.array(args), 1. - np.sum(np.array(args)) ) #np.append(10**np.array(args),1.-np.sum(10**np.array(args))) #print(relativeAbundances) if self.redshift: z = dist dist = cosmo.luminosity_distance(z).to(u.m) freq = const.c.value / ((self.wavelength / (1. + z)) * 1e-6) else: dist = dist * u.pc.to(u.m) freq = const.c.value / (self.wavelength * 1e-6) #Simple bug catches for inputs to opacity spectrum if len(relativeAbundances) != self.nSpecies: print('Number of weights must be same as number of species') #if scale <= 0.0: # print('Scale factor must be positive and non-zero.') #not relevant - scale is a log if t <= 0.0: print('Temperature must be positive and in Kelvin.') bb = blackbody.blackbody_nu(freq, t).to(u.Jy / u.sr).value bb = bb / dist**2 bb = bb * 10**(scale) * self.sigmaNormWave * ( (self.wavelength / self.normWave)**index) #Subtract the sum of opacities from the blackbody continuum to calculate model spectrum fModel = bb * (1.0 - (np.matmul(self.opacity_array, relativeAbundances))) self.modelFlux = fModel
def I_broken_plaw(nu, Tr, nu0, alpha1, alpha2): """ Returns the blackbody function evaluated at nu. As temperature a broken power law is used. The power law shape has parameters: Tr, nu0, alpha1 and alpha2. :param nu: Frequency. (Hz) or astropy.units.Quantity_ :type nu: (Hz) or astropy.units.Quantity_ :param Tr: Temperature at nu0. (K) or astropy.units.Quantity_ :param nu0: Frequency at which the spectral index changes. (Hz) or astropy.units.Quantity_ :param alpha1: spectral index for :math:`\\nu<\\nu_0` :param alpha2: spectral index for :math:`\\nu\\geq\\nu_0` :returns: Specific intensity in :math:`\\rm{erg}\\,\\rm{cm}^{-2}\\,\\rm{Hz}^{-1}\\,\\rm{s}^{-1}\\,\\rm{sr}^{-1}`. See `astropy.analytic_functions.blackbody.blackbody_nu`__ :rtype: astropy.units.Quantity_ .. _astropy.units.Quantity: http://docs.astropy.org/en/stable/api/astropy.units.Quantity.html#astropy.units.Quantity __ blackbody_ .. _blackbody: http://docs.astropy.org/en/stable/api/astropy.analytic_functions.blackbody.blackbody_nu.html#astropy.analytic_functions.blackbody.blackbody_nu """ Tbpl = broken_plaw(nu, nu0, Tr, alpha1, alpha2) bnu_bpl = blackbody_nu(nu, Tbpl) return bnu_bpl
def planck(data,temp,sr_o,key = 'wave'): sr = sr_o*u.sr ### Setting Steradian temperature = temp * u.K if key == 'wave': wave = [x*10 for x in data] # change the wavelength nm to Angstrom dw = 1 d_w = dw*u.AA wavelengths = np.arange(wave[0], wave[1],dw) * u.AA flux_lam = blackbody_lambda(wavelengths, temperature) flux_lam_f = flux_lam*sr flux_wat = flux_lam_f.to(u.W/u.cm**2/u.AA) # Change the blackbody intensity to "Wats/cm^2/A" flux_lam_p = flux_lam_f*wavelengths/(h*c) # The number of photons flux_lam_p = flux_lam_p.to(u.m**-2/u.AA/u.s) total_flux_photon = sum(flux_lam_p)*d_w elif key == 'hertz': dnu = 1e12 d_nu = dnu*u.Hz nu = np.arange(data[0],data[1],dnu)*u.Hz flux_nu = blackbody_nu(nu, temperature) flux_nu_f = flux_nu*sr flux_wat = flux_nu_f.to(u.W/u.cm**2/u.Hz) # Change the blackbody intensity to "Wats/cm^2/A" flux_nu_p = flux_nu_f/(h*nu) # The number of photons flux_nu_p = flux_nu_p.to(u.cm**-2/u.Hz/u.s) total_flux_photon = sum(flux_nu_p)*d_nu else: print "Please re-input the right key" return total_flux_photon,flux_wat
def coreprop(freq, tdust, flux, dist, kappa, sigmav, tgas, smaj, smin, wmol): """ Input sigmav is 1-D velocity dispersion, deconvolved with instrument channel width. smaj & smin are deconvolved size in arcsec (from casaviewer 2-D fitter) """ BT = blackbody_nu(freq * u.GHz, tdust * u.K).cgs.value d = dist * 1e3 * pc # Radius (in unit of pc) radius = np.sqrt(smaj * smin) / 2 / 3600 / 180 * np.pi * d / pc # Mass m = 1e2 * flux * jy * d**2 / BT / kappa / msun # Number density density = m * msun / (4. / 3. * np.pi * (radius * pc)**3) / (2.8 * mp) # Sigmav of 2.33H sigmav = np.sqrt((sigmav * 1e5)**2 - kb * tgas / wmol / mp + kb * tgas / 2.33 / mp) / 1e5 # Virial alpha = 5 * (sigmav * 1e5)**2 * (radius * pc) / G / (m * msun) # Virial parameter with B-field, assume 1 mG B = 1 * 1e-3 # G rho = density * 2.8 * mp # g/cm3 alfven = B / np.sqrt(4 * np.pi * rho) alpha_B = 5 * ((sigmav * 1e5)**2 + (alfven)**2 / 6.) * (radius * pc) / G / (m * msun) return sigmav, radius, m, density, alpha, alfven * 1e-5, alpha_B
def I_total(nu, Te, tau, I0, eta): """ """ bnu = blackbody_nu(nu, Te) exp = np.exp(-tau) return bnu * eta * (1. - exp) + I0 * exp
def test_from_mag_fluxd0_B(self): # comapre with test_from_mag_bandpass from astropy.modeling.blackbody import blackbody_nu aper = 1 * u.arcsec eph = dict(rh=1.0 * u.au, delta=1.0 * u.au) fluxd0 = u.Quantity(3631, 'Jy') Tscale = 1.1 B = blackbody_nu(11.7 * u.um, 278 * Tscale * u.K) efrho = Efrho.from_mag(5, None, aper, eph, B=B, fluxd0=fluxd0) assert np.isclose(efrho.cm, 78750, rtol=0.001)
def calc_dmass(fluxes, freq, dist): Tdust = 20*u.K kappa0 = 2*u.cm**2/u.g nu0 = constants.c/(1.3*u.mm) Bnu = blackbody.blackbody_nu(freq, 20*u.K) Dmass = (fluxes*dist**2)/(kappa0*(freq/nu0)*Bnu) Dmass = (Dmass.decompose()).to(u.earthMass*u.sr) return Dmass
def model_function(self, x, **kwargs): """Modified black body warm component.""" assert hasattr(x, 'unit') assert 'nu0' in kwargs and hasattr(kwargs['nu0'], 'unit') assert 'beta' in kwargs and not hasattr(kwargs['beta'], 'unit') sigma = self.sigma_nu(x, rdg=1.E-2, mu=2.33) warm = self['size'] * blackbody_nu(x, self['T']) * \ (1. - np.exp(-self['N']*sigma)) * \ np.exp(-0.5 * (x/kwargs['nu0'])**kwargs['beta']) return warm
def surface_brightness(frequencies, temperature, density, beta): #kappa = (9.6 / ((160e-6) ** (-1 * beta))) * ((c.value/frequencies) ** (-1 * beta)) #(9.6 / (c.vlaue/(160e-6) ** (-1 * beta)) - c.value taken out. //// * ((c.value/frequencies) ** (-1 * beta)) = E_lambda in Gordon et al., 2014. Gorden Original kappa = (kappa_eff / ((160e-6)**(-1 * beta))) * ( (c.value / frequencies)**(-1 * beta) ) #(9.6 / (c.vlaue/(160e-6) ** (-1 * beta)) - c.value taken out. //// * ((c.value/frequencies) ** (-1 * beta)) = E_lambda in Gordon et al., 2014. First kappa_eff=9.6 replaced with 26 which is more suitable kappa_eff for C-rich AGB stars like this one at 160micron. For O rich we need kappa_eff=8.8 at 160 micron. S_nu = density * kappa * blackbody_nu(frequencies, temperature).to( u.Jy / (u.arcsec**2)).value #From Gordon et al., 2014. return S_nu
def generate_planck_blackbody(x, T_eff, frequency=None): # Generates a Planck SED ptype, unit = dimensions_check(T_eff, accepted_dims=[u'temperature']) ptype, unit = dimensions_check(x, accepted_dims=[u'length', u'frequency']) if ptype is None or unit is None: return None if (frequency is None and ptype == u'frequency') or frequency: y = blackbody_nu(x, T_eff) else: y = blackbody_lambda(x, T_eff) return y
def calculate_Snu(self, G0, nu): ''' calculate S_nu from simple dust model ''' import astropy.constants as const import astropy.units as unit from astropy.modeling.blackbody import blackbody_nu Tdust = self.Tdust * unit.K lam = (const.c / (nu * unit.GHz)).to(unit.um) Bnu = blackbody_nu(lam, Tdust) Snu = G0 * (Bnu * self.sigma / unit.cm**2).to('MJy/(sr*cm^2)').value return (Snu)
def energy_density_absorbed_by_CMB(): extinction_file = cfg.par.dustdir+cfg.par.dustfile mw_df = h5py.File(extinction_file,'r') mw_o = mw_df['optical_properties'] mw_df_nu = mw_o['nu']*u.Hz mw_df_chi = mw_o['chi']*u.cm**2/u.g b_nu = blackbody_nu(mw_df_nu,cfg.model.TCMB) #energy_density_absorbed = 4pi int b_nu * kappa_nu d_nu since b_nu #has units erg/s/cm^2/Hz/str and kappa_nu has units cm^2/g. this results in units erg/s/g steradians = 4*np.pi*u.sr energy_density_absorbed = (steradians*np.trapz( (b_nu*mw_df_chi),mw_df_nu)).to(u.erg/u.s/u.g) return energy_density_absorbed
def test_blackbody_synphot(): """Test that it is consistent with IRAF SYNPHOT BBFUNC.""" # Solid angle of solar radius at 1 kpc fac = np.pi * (const.R_sun / const.kpc)**2 * u.sr with np.errstate(all='ignore'): flux = blackbody_nu([100, 1, 1000, 1e4, 1e5] * u.AA, 5000) * fac assert flux.unit == FNU # Special check for overflow value (SYNPHOT gives 0) assert np.log10(flux[0].value) < -143 np.testing.assert_allclose( flux.value[1:], [0, 2.01950807e-34, 3.78584515e-26, 1.90431881e-27], rtol=0.01) # 1% accuracy
def test_blackbody_synphot(): """Test that it is consistent with IRAF SYNPHOT BBFUNC.""" # Solid angle of solar radius at 1 kpc fac = np.pi * (const.R_sun / const.kpc) ** 2 * u.sr with np.errstate(all='ignore'): flux = blackbody_nu([100, 1, 1000, 1e4, 1e5] * u.AA, 5000) * fac assert flux.unit == FNU # Special check for overflow value (SYNPHOT gives 0) assert np.log10(flux[0].value) < -143 np.testing.assert_allclose( flux.value[1:], [0, 2.01950807e-34, 3.78584515e-26, 1.90431881e-27], rtol=0.01) # 1% accuracy
def calculate_Snu(self, G0, nu): ''' calculate S_nu from MBB dust model ''' import astropy.constants as const import astropy.units as unit from astropy.modeling.blackbody import blackbody_nu Tdust = self.Tdust0 * (G0 / self.G0)**(1 / (4. + self.beta)) * unit.K lam = (const.c / (nu * unit.GHz)).to(unit.um) #lam0 = (const.c/(self.nu0*unit.GHz)).to(unit.um) Bnu = blackbody_nu(lam, Tdust) #Bnu0 = blackbody_nu(lam0,self.Tdust0) Snu = (nu / self.nu0)**self.beta * ( Bnu * self.sigma / unit.cm**2).to('MJy/(sr*cm^2)').value return (Snu)
def test_blackbody_scipy(): """Test Planck function. .. note:: Needs ``scipy`` to work. """ flux_unit = u.Watt / (u.m**2 * u.um) wave = np.logspace(0, 8, 100000) * u.AA temp = 100. * u.K with np.errstate(all='ignore'): bb_nu = blackbody_nu(wave, temp) * u.sr flux = bb_nu.to(flux_unit, u.spectral_density(wave)) / u.sr lum = wave.to(u.um) intflux = integrate.trapz(flux.value, x=lum.value) ans = const.sigma_sb * temp**4 / np.pi np.testing.assert_allclose(intflux, ans.value, rtol=0.01) # 1% accuracy
def test_blackbody_scipy(): """Test Planck function. .. note:: Needs ``scipy`` to work. """ flux_unit = u.Watt / (u.m ** 2 * u.um) wave = np.logspace(0, 8, 100000) * u.AA temp = 100. * u.K with np.errstate(all='ignore'): bb_nu = blackbody_nu(wave, temp) * u.sr flux = bb_nu.to(flux_unit, u.spectral_density(wave)) / u.sr lum = wave.to(u.um) intflux = integrate.trapz(flux.value, x=lum.value) ans = const.sigma_sb * temp ** 4 / np.pi np.testing.assert_allclose(intflux, ans.value, rtol=0.01) # 1% accuracy
def deriv(self, x, yunit, *args, **kwargs): self._update_values(*args) # Component warm = self.model_function(x, **kwargs).to(yunit) sigma = self.sigma_nu(x) # Blackbody functions bbwarm = blackbody_nu(x, self['T']) # Derivatives d_size = warm / self['size'] d_T = warm * deriv_planck(x, self['T']) / bbwarm d_T = d_T.to(yunit / self.units['T']) d_N = sigma * warm / (np.exp(sigma * self['N']) - 1.) d_N = d_N.to(yunit / self.units['N']) return [d_T, d_size, d_N]
def __call__(self, t=1., scale=1., index=1., dist=1., **kwargs): if self.redshift: z = dist dist = cosmo.luminosity_distance(z).to(u.m) freq = const.c.value / ((self.wavelength / (1. + z)) * 1e-6) else: dist = dist * u.pc.to(u.m) freq = const.c.value / (self.wavelength * 1e-6) #Simple bug catches for inputs to blackbody model #if scale <= 0.0: # print('Scale factor must be positive and non-zero.') #not relevant - scale is a log if t <= 0.0: print('Temperature must be positive and in Kelvin.') bb = blackbody.blackbody_nu(freq, t).to(u.Jy / u.sr).value bb = bb / dist**2 bb = bb * 10**(scale) * self.sigmaNormWave * ( (self.wavelength / self.normWave)**index) self.modelFlux = bb
def qminus_esin_fast(r, tempi, tempe, v): nuMin = 1.0e6 nuMax = 1.0e21 iter = 30 paso = np.power(nuMax / nuMin, 1.0 / float(iter - 1)) sum = 0.0 nu = nuMin theta = boltzmann * tempe / (electronMass * cLight2) ne = eDens(r, tempi, tempe, v) h = height(r, tempi, tempe) k_es = ne * thomson tau_es = 2.0 * k_es * h A = 1.0 + 4.0 * theta * (1.0 + 4.0 * theta) for i in range(iter): x = planck * nu / (electronMass * cLight2) / (3.0 * theta) bnu = blackbody_nu(nu, tempe).value bnu2 = 4.0 * np.pi * bnu xi = xiBremss(nu, r, tempi, tempe, v) + xiSync(nu, r, tempi, tempe, v) #k_nu = np.where(bnu2 > 1.0e-2*xi*h,xi/bnu2,50.0) k_nu = xi / bnu2 #l_eff = 1.0/np.sqrt(k_nu*(k_nu+k_es)) #tau_es = 2.0*k_es*np.where(l_eff<h,l_eff,h) s_exp = tau_es * (tau_es + 1.0) etaMax = 3.0 * boltzmann * tempe / (planck * nu) jm = np.log(etaMax) / np.log(A) gamma1 = sp.gammainc(jm + 1.0, A * s_exp) gamma2 = sp.gammainc(jm + 1.0, s_exp) aux2 = s_exp * (A - 1.0) #etaa = np.where(aux2<200.0,np.exp(aux2)*(1.0-gamma1)+etaMax*gamma2,etaMax*gamma2) etaa = np.exp(aux2) * (1.0 - gamma1) + etaMax * gamma2 tau_nu = np.sqrt(np.pi) / 2.0 * k_nu * h fluxx = 2.0*np.pi/np.sqrt(3.0) * bnu * \ (1.0-np.exp(-2.0*np.sqrt(3.0)*tau_nu)) dnu = nu * (np.sqrt(paso) - 1.0 / np.sqrt(paso)) sum += fluxx * etaa * dnu nu = nu * paso return sum * 2.0 / (np.sqrt(np.pi) * h)
def mass_jyperbeam(flux, beam, pixel_size, wave, t, kappa, distance): """ Takes flux in Jy/beam summed over some area and computes the mass using beam and pixel information Parameters: flux : float flux in Jy/beam beam : array like beam size in arcseconds pixel_size : number pixel size in arcseconds wave : float wavelength (m) t: float (optional) temperature (K) kappa: float dust opacity per unit mass (cm^2g^-1) distance: float distance to the object (pc) """ beam = beam * u.arcsec pixel_size = pixel_size * u.arcsec omega_beam = beam_solid_angle(beam) flux = (flux * u.Jy / u.beam).to( u.Jy / u.sr, equivalencies=u.beam_angular_area(omega_beam)) integrated_flux = flux * pixel_size**2 integrated_flux = integrated_flux.to(u.Jy) wave = wave * u.m t = t * u.K kappa = kappa * (u.cm**2 / u.g) distance = distance * (u.pc) B = blackbody_nu(wave.to(u.Hz, equivalencies=u.spectral()), t) B = B * u.sr m = (distance**2. * integrated_flux) / (kappa * B) m = m.to(ap.solMass) return m
def get_bb(day): # Get the blackbody curve on a certain day # what is the temp on that day? dat = Table.read("%s/physevol.dat" %data_dir, format='ascii.no_header') dt = dat['col2'] Ts = dat['col6'] * 10**3 T = Ts[np.argmin(np.abs(dt-day))] # what is the radius on that day? Rs = dat['col3'] * 1.5E13 # originally in AU R = Rs[np.argmin(np.abs(dt-day))] low_wl = 1928 # Angstroms, UVW2 hi_wl = 21900 # Angstroms, K-band c = 3E18 h = 4.136E-15 k = 1.38E-16 x = np.logspace(np.log10(c/hi_wl), np.log10(c/low_wl)) y = blackbody_nu(x, T) print("temp", T) return x, y, R
def deriv(self, x, yunit, *args): self._update_values(*args) # Components cold = self.model_function(x).to(yunit) # Blackbody functions bbcold = blackbody_nu(x, self['T']) # Derivatives d_size = cold / self['size'] d_T = cold * deriv_planck(x, self['T']) / bbcold d_T = d_T.to(yunit / self.units['T']) d_beta = -self['size'] * bbcold * \ np.exp(-(x/self['nu0'])**self['beta']) * \ (x/self['nu0'])**self['beta'] * np.log(x/self['nu0']) d_beta = d_beta.to(yunit) d_nu0 = -self['beta']*(x/self['nu0'])**self['beta'] * \ cold / (self['nu0']*(np.exp((x/self['nu0'])**self['beta'])-1.)) d_nu0 = d_nu0.to(yunit / self.units['nu0']) return [d_T, d_size, d_nu0, d_beta]
def test_monochromatic_inverse_compton(particle_dists): """ test IC monochromatic against khangulyan et al. """ from ..models import InverseCompton, PowerLaw PL = PowerLaw(1 / u.eV, 1 * u.TeV, 3) # compute a blackbody spectrum with 1 eV/cm3 at 30K from astropy.modeling.blackbody import blackbody_nu Ephbb = np.logspace(-3.5, -1.5, 100) * u.eV lambdabb = Ephbb.to('AA', equivalencies=u.equivalencies.spectral()) T = 30 * u.K w = 1 * u.eV / u.cm**3 bb = (blackbody_nu(lambdabb, T) * 2 * u.sr / c.cgs / Ephbb / hbar).to('1/(cm3 eV)') Ebbmax = Ephbb[np.argmax(Ephbb**2 * bb)] ar = (4 * sigma_sb / c).to('erg/(cm3 K4)') bb *= (w / (ar * T**4)).decompose() eopts = {'Eemax': 10000 * u.GeV, 'Eemin': 10 * u.GeV, 'nEed': 1000} IC_khang = InverseCompton(PL, seed_photon_fields=[['bb', T, w]], **eopts) IC_mono = InverseCompton(PL, seed_photon_fields=[['mono', Ebbmax, w]], **eopts) IC_bb = InverseCompton(PL, seed_photon_fields=[['bb2', Ephbb, bb]], **eopts) IC_bb_ene = InverseCompton( PL, seed_photon_fields=[['bb2', Ephbb, Ephbb**2 * bb]], **eopts) Eph = np.logspace(-1, 1, 3) * u.GeV assert_allclose(IC_khang.sed(Eph).value, IC_mono.sed(Eph).value, rtol=1e-2) assert_allclose(IC_khang.sed(Eph).value, IC_bb.sed(Eph).value, rtol=1e-2) assert_allclose(IC_khang.sed(Eph).value, IC_bb_ene.sed(Eph).value, rtol=1e-2)
def test_monochromatic_inverse_compton(particle_dists): """ test IC monochromatic against khangulyan et al. """ PL = PowerLaw(1 / u.eV, 1 * u.TeV, 3) # compute a blackbody spectrum with 1 eV/cm3 at 30K Ephbb = np.logspace(-3.5, -1.5, 100) * u.eV lambdabb = Ephbb.to("AA", equivalencies=u.equivalencies.spectral()) T = 30 * u.K w = 1 * u.eV / u.cm ** 3 bb = (blackbody_nu(lambdabb, T) * 2 * u.sr / c.cgs / Ephbb / hbar).to( "1/(cm3 eV)" ) Ebbmax = Ephbb[np.argmax(Ephbb ** 2 * bb)] ar = (4 * sigma_sb / c).to("erg/(cm3 K4)") bb *= (w / (ar * T ** 4)).decompose() eopts = {"Eemax": 10000 * u.GeV, "Eemin": 10 * u.GeV, "nEed": 1000} IC_khang = InverseCompton(PL, seed_photon_fields=[["bb", T, w]], **eopts) IC_mono = InverseCompton( PL, seed_photon_fields=[["mono", Ebbmax, w]], **eopts ) IC_bb = InverseCompton( PL, seed_photon_fields=[["bb2", Ephbb, bb]], **eopts ) IC_bb_ene = InverseCompton( PL, seed_photon_fields=[["bb2", Ephbb, Ephbb ** 2 * bb]], **eopts ) Eph = np.logspace(-1, 1, 3) * u.GeV assert_allclose(IC_khang.sed(Eph).value, IC_mono.sed(Eph).value, rtol=1e-2) assert_allclose(IC_khang.sed(Eph).value, IC_bb.sed(Eph).value, rtol=1e-2) assert_allclose( IC_khang.sed(Eph).value, IC_bb_ene.sed(Eph).value, rtol=1e-2 )
def test_blackbody_exceptions_and_warnings(): """Test exceptions.""" # Negative temperature with pytest.raises(ValueError) as exc: blackbody_nu(1000 * u.AA, -100) assert exc.value.args[0] == 'Temperature should be positive: -100.0 K' # Zero wavelength given for conversion to Hz with catch_warnings(AstropyUserWarning) as w: blackbody_nu(0 * u.AA, 5000) assert len(w) == 1 assert 'invalid' in w[0].message.args[0] # Negative wavelength given for conversion to Hz with catch_warnings(AstropyUserWarning) as w: blackbody_nu(-1. * u.AA, 5000) assert len(w) == 1 assert 'invalid' in w[0].message.args[0]