def test_blackbody_exceptions_and_warnings(): """Test exceptions.""" # Negative temperature with pytest.raises(ValueError) as exc: bb = BlackBody(-100 * u.K) bb(1.0 * u.micron) assert exc.value.args[0] == "Temperature should be positive: [-100.] K" bb = BlackBody(5000 * u.K) # Zero wavelength given for conversion to Hz with pytest.warns(AstropyUserWarning, match='invalid') as w: bb(0 * u.AA) assert len(w) == 3 # 2 of these are RuntimeWarning from zero divide # Negative wavelength given for conversion to Hz with pytest.warns(AstropyUserWarning, match='invalid') as w: bb(-1.0 * u.AA) assert len(w) == 1 # Test that a non surface brightness converatable scale unit with pytest.raises(ValueError) as exc: bb = BlackBody(5000 * u.K, scale=1.0 * u.Jy) bb(1.0 * u.micron) assert exc.value.args[0] == "scale units not surface brightness: Jy"
def test_blackbody_input_units(): SLAM = u.erg / (u.cm**2 * u.s * u.AA * u.sr) SNU = u.erg / (u.cm**2 * u.s * u.Hz * u.sr) b_lam = BlackBody(3000 * u.K, scale=1 * SLAM) assert (b_lam.input_units['x'] == u.AA) b_nu = BlackBody(3000 * u.K, scale=1 * SNU) assert (b_nu.input_units['x'] == u.Hz)
def test_blackbody_array_temperature(): """Regression test to make sure that the temperature can be an array.""" multibb = BlackBody([100, 200, 300] * u.K) flux = multibb(1.2 * u.mm) np.testing.assert_allclose(flux.value, [1.804908e-12, 3.721328e-12, 5.638513e-12], rtol=1e-5) flux = multibb([2, 4, 6] * u.mm) np.testing.assert_allclose(flux.value, [6.657915e-13, 3.420677e-13, 2.291897e-13], rtol=1e-5) multibb = BlackBody(np.ones(4) * u.K) flux = multibb(np.ones((3, 4)) * u.mm) assert flux.shape == (3, 4)
def test_blackbody_evaluate(temperature): b = BlackBody(temperature=temperature, scale=1.0) assert_quantity_allclose(b(1.4 * u.micron), 486787299458.15656 * u.MJy / u.sr) assert_quantity_allclose(b(214.13747 * u.THz), 486787299458.15656 * u.MJy / u.sr)
def test_blackbody_dimensionless_fit(): T = 3000 * u.K r = 1e14 * u.cm DL = 100 * u.Mpc scale = np.pi * (r / DL)**2 bb1 = BlackBody(temperature=T, scale=scale) bb2 = BlackBody(temperature=T, scale=scale.to_value(u.dimensionless_unscaled)) fitter = LevMarLSQFitter() wav = np.array([0.5, 5, 10]) * u.micron fnu = np.array([1, 10, 5]) * u.Jy / u.sr bb1_fit = fitter(bb1, wav, fnu, maxiter=1000) bb2_fit = fitter(bb2, wav, fnu, maxiter=1000) assert(bb1_fit.temperature == bb2_fit.temperature)
def test_blackbody_fit(): fitter = LevMarLSQFitter() b = BlackBody(3000 * u.K, scale=5e-17 * u.Jy / u.sr) wav = np.array([0.5, 5, 10]) * u.micron fnu = np.array([1, 10, 5]) * u.Jy / u.sr b_fit = fitter(b, wav, fnu, maxiter=1000) assert_quantity_allclose(b_fit.temperature, 2840.7438355865065 * u.K) assert_quantity_allclose(b_fit.scale, 5.803783292762381e-17 * u.Jy / u.sr)
def test_blackbody_dimensionless(): """Test support for dimensionless (but not unscaled) units for scale""" T = 3000 * u.K r = 1e14 * u.cm DL = 100 * u.Mpc scale = np.pi * (r / DL)**2 bb1 = BlackBody(temperature=T, scale=scale) # even though we passed scale with units, we should be able to evaluate with unitless bb1.evaluate(0.5, T.value, scale.to_value(u.dimensionless_unscaled)) bb2 = BlackBody(temperature=T, scale=scale.to_value(u.dimensionless_unscaled)) bb2.evaluate(0.5, T.value, scale.to_value(u.dimensionless_unscaled)) # bolometric flux for both cases should be equivalent assert(bb1.bolometric_flux == bb2.bolometric_flux)
def test_blackbody_return_units(): # return of evaluate has no units when temperature has no units b = BlackBody(1000.0 * u.K, scale=1.0) assert not isinstance(b.evaluate(1.0 * u.micron, 1000.0, 1.0), u.Quantity) # return has "standard" units when scale has no units b = BlackBody(1000.0 * u.K, scale=1.0) assert isinstance(b(1.0 * u.micron), u.Quantity) assert b(1.0 * u.micron).unit == u.erg / (u.cm**2 * u.s * u.Hz * u.sr) # return has scale units when scale has units b = BlackBody(1000.0 * u.K, scale=1.0 * u.MJy / u.sr) assert isinstance(b(1.0 * u.micron), u.Quantity) assert b(1.0 * u.micron).unit == u.MJy / u.sr
def test_blackbody_overflow(): """Test Planck function with overflow.""" photlam = u.photon / (u.cm**2 * u.s * u.AA) wave = [0.0, 1000.0, 100000.0, 1e55] # Angstrom temp = 10000.0 # Kelvin with np.errstate(all="ignore"): bb = BlackBody(temperature=temp * u.K, scale=1.0) bb_lam = bb(wave) * u.sr flux = bb_lam.to(photlam, u.spectral_density(wave * u.AA)) / u.sr # First element is NaN, last element is very small, others normal assert np.isnan(flux[0]) assert np.log10(flux[-1].value) < -134 np.testing.assert_allclose(flux.value[1:-1], [0.00046368, 0.04636773], rtol=1e-3) # 0.1% accuracy in PHOTLAM/sr with np.errstate(all="ignore"): flux = bb(1.0 * u.AA) assert flux.value == 0
def test_blackbody_fit(fitter): fitter = fitter() if isinstance(fitter, TRFLSQFitter) or isinstance(fitter, DogBoxLSQFitter): rtol = 0.54 atol = 1e-15 else: rtol = 1e-7 atol = 0 b = BlackBody(3000 * u.K, scale=5e-17 * u.Jy / u.sr) wav = np.array([0.5, 5, 10]) * u.micron fnu = np.array([1, 10, 5]) * u.Jy / u.sr b_fit = fitter(b, wav, fnu, maxiter=1000) assert_quantity_allclose(b_fit.temperature, 2840.7438355865065 * u.K, rtol=rtol) assert_quantity_allclose(b_fit.scale, 5.803783292762381e-17, atol=atol)
def test_blackbody_sefanboltzman_law(): b = BlackBody(293.0 * u.K) assert_quantity_allclose(b.bolometric_flux, 133.02471751812573 * u.W / (u.m * u.m))
def test_blackbody_weins_law(): b = BlackBody(293.0 * u.K) assert_quantity_allclose(b.lambda_max, 9.890006672986939 * u.micron) assert_quantity_allclose(b.nu_max, 17.22525080856469 * u.THz)
def fit_gm(): import numpy as np import matplotlib.pyplot as plt lnorm = 20 nwave = 800 # files = glob.glob('SED_J13/*RES') # files = glob.glob('SED_C11/*RES') # #files = glob.glob('SED_DL07/*RES') # # du = np.zeros((nwave, len(files))) # # for i, file in enumerate(files): # dust = np.loadtxt(file, skiprows=8) # w, f = dust[:,0], dust[:,1] # print(file, len(w)) # plt.plot(w, f/np.interp(lnorm, w, f), label=file, alpha=0.5) # du[:,i] = f/np.interp(lnorm, w, f) # du_wave = w # Magdis mag = np.loadtxt('ms.txt') mag_wave = mag[:, 0] mag_flux = mag[:, 1:] for i in range(10): mag_flux[:, i] /= np.interp(lnorm, mag_wave, mag_flux[:, i]) #plt.plot(mag_wave, mag_flux[:,i], color='k', alpha=0.8) ### By hand, blackbodies following da Cunha + Magphys from astropy.modeling.physical_models import BlackBody import astropy.units as u from astropy.constants import c # Eazy for wavelength grid ez = np.loadtxt('templates/fsps_full/fsps_QSF_12_v3_001.dat') wave_grid = ez[:, 0] / 1.e4 nwave = len(wave_grid) # PAH template. C11 dies down quickly file = 'SED_C11/SED_C11_100.RES' #file = 'SED_DL07/SED_DL07_100.RES' dust = np.loadtxt(file, skiprows=8) du_wave, du_pah = dust[:, 0], dust[:, 1] comps = [np.interp(wave_grid, du_wave, du_pah)] nu = (c / (wave_grid * u.um)).to(u.Hz) # equilibrium components, da Cunha # modified black-bodies, extra factor of 1 turns from Fnu to nu Fnu # cold for t in np.arange(20, 40): comps.append( BlackBody(temperature=t * u.K)(wave_grid * u.um) * nu**(1 + 2.0)) #warm for t in np.arange(30, 80): comps.append( BlackBody(temperature=t * u.K)(wave_grid * u.um) * nu**(1 + 1.5)) # Hot for t in [130, 250]: comps.append( BlackBody(temperature=t * u.K)(wave_grid * u.um) * nu**(1 + 1)) _A = np.array(comps).T nc = _A.shape[1] for i in range(nc): _A[:, i] /= np.interp(lnorm, wave_grid, _A[:, i]) ####### mag_int = np.zeros((nwave, 10)) clip = (wave_grid > 4.) & (wave_grid < 5000) models_flam = mag_int * 0. for i in range(10): mag_int[:, i] = np.interp(wave_grid, mag_wave, mag_flux[:, i]) _a = nnls(_A[clip, :], mag_int[clip, i]) model = _A.dot(_a[0]) norm = np.trapz(model / wave_grid, wave_grid) pl = plt.plot(wave_grid, mag_int[:, i] / norm, linewidth=4, alpha=0.2) plt.plot(wave_grid[clip], mag_int[clip, i] / norm, linewidth=4, alpha=0.8, color=pl[0].get_color()) plt.plot(wave_grid, model / norm, linewidth=3, color='w', alpha=0.8) plt.plot(wave_grid, model / norm, linewidth=1, color=pl[0].get_color(), alpha=0.8) mflam = model / wave_grid mflam /= np.trapz(mflam, wave_grid) models_flam[:, i] = mflam fp = open(f'templates/magdis/magdis_{i+1:02d}.txt', 'w') np.savetxt( fp, np.array([wave_grid * 1.e4, mflam]).T, header= 'wave flam\n wave: A, flux: flam \nnormalized to unit energy', fmt='%.5e') fp.close() # components # plt.plot(wave_grid, (_A*_a[0]), linewidth=1, color='k', alpha=0.2) plt.loglog() plt.xlim(0.2, 5000) plt.ylim(1.e-6, 10) plt.grid() plt.savefig('templates/magdis/magdis_fit.png')
import numpy as np import astropy.units as u from scipy.integrate import quad, simps from astropy.constants import G, sigma_sb from astropy.modeling.physical_models import BlackBody from .filters import filters from .blackbody import bb_interpolator from .limbdark import ld_interpolator from .gravitydark import gdark_interpolator, beta_interpolator from .massradius import mr_interpolator from .rochedistortion import roche_interpolator from dust_extinction.parameter_averages import F19 bb = BlackBody() def get_Tbb(teff, logg, band, instrument='ucam', star_type='WD', source='Claret'): """ Interpolates Teff to Tbb tables for a given filter band ('u', 'g', 'r', 'i', or 'z') for PHOENIX main-sequence models (star_type='MS') or Bergeron & Gianninas white dwarf models (star_type='WD'). """ if star_type == 'WD' and source == 'Claret': T_bb = float(bb_interpolator['WD_Claret'][instrument][band](teff, logg)) elif star_type == 'WD' and source == 'Bergeron': T_bb = float(bb_interpolator['WD'][instrument][band](teff, logg)) else: T_bb = float(bb_interpolator[star_type][instrument][band](teff, logg))