def test_plot_schechter(): phiStar = 1.8e-3 MStar = -20.04 alpha = -1.71 LStar = magnitudes.L_nu_from_magAB(MStar) mags = numpy.arange(-22, -11.0, 0.5) lums = magnitudes.L_nu_from_magAB(mags) phi_L = schechterL(lums, phiStar, alpha, LStar) phi_M = schechterM(mags, phiStar, alpha, MStar) L_L = schechterCumuLL(lums, phiStar, alpha, LStar) L_M = schechterCumuLM(mags, phiStar, alpha, MStar) phi_L_func = lambda l: l * schechterL(l, phiStar, alpha, LStar) L_L_num = utils.logquad(phi_L_func, lums, 1e35)[0] L_L_num2 = utils.vecquad(phi_L_func, lums, 1e29)[0] phi_M_func = lambda m: (magnitudes.L_nu_from_magAB(m) * schechterM( m, phiStar, alpha, MStar)) L_M_num2 = utils.vecquad(phi_M_func, -25, mags)[0] Ltot_L = schechterTotLL(phiStar, alpha, LStar) Ltot_M = schechterTotLM(phiStar, alpha, MStar) pylab.figure() pylab.subplot(221) pylab.plot(lums, lums * lums * phi_L) pylab.xscale('log') pylab.yscale('log') pylab.ylabel(r'$ L^2 \Phi_L$') pylab.subplot(222) pylab.plot(mags, -mags * lums * phi_M) pylab.yscale('log') pylab.ylabel(r'$ -M L \Phi_M$') pylab.subplot(223) pylab.plot(lums, Ltot_L - L_L) pylab.plot(lums, L_M) pylab.plot(lums, L_L_num, '--') pylab.plot(lums, L_L_num2, ':') pylab.plot(lums, L_M_num2, 'x') pylab.axhline(y=Ltot_L) pylab.axhline(y=Ltot_M) pylab.xscale('log') pylab.yscale('log') pylab.subplot(224) pylab.plot(mags, Ltot_M - L_M) pylab.plot(mags, L_L) pylab.plot(mags, L_L_num, '--') pylab.plot(mags, L_L_num2, ':') pylab.plot(mags, L_M_num2, 'x') pylab.axhline(y=Ltot_L) pylab.axhline(y=Ltot_M) pylab.yscale('log')
def schechterCumuLM(magnitudeAB, phiStar, alpha, MStar): """Integrate luminosity in galaxies brighter than magnitudeAB. Uses an analytical formula. """ LStar = magnitudes.L_nu_from_magAB(MStar) lum = magnitudes.L_nu_from_magAB(magnitudeAB) return schechterCumuLL(lum, phiStar, alpha, LStar)
def schechterTotLM(phiStar, alpha, MStar): """Integrate total luminosity in galaxies. Uses an analytical formula. """ LStar = magnitudes.L_nu_from_magAB(MStar) return schechterTotLL(phiStar, alpha, LStar)
def test_sfr(): """Check that M = -18 -> SFR ~ 1 Msun/yr. From Oesch et al (2009 ApJ 690 1350). """ mag = -18 lum = magnitudes.L_nu_from_magAB(mag) sfr = luminosityfunction.sfr_from_L_nu(lum) print("M = %.3g -> L_nu = %.3g erg/s/Hz -> SFR = %.3g Msun/yr" % (mag, lum, sfr)) assert numpy.round(sfr) == 1
def test_sfrd(): """ Check conversion of Lmin -> SFRD. At z=7: Lmin = 0.2 L*z=6 -> Mmin=-18.5 -> log(rho/erg/s/Hz/Mpc^3)=25.5 -> SFRD = 10^-2.32 Msun/yr^-1/Mpc^-3. From Oesch et al (2009 ApJ 690 1350). """ cosmo = cparam.WMAP7_BAO_H0_mean(flat=True) # # From Bouwens 2008ApJ...686..230B # lfhist = luminosityfunction.LFHistory(params=luminosityfunction.B2008, # **cosmo) # mStarz6 = lfhist.params_z(6.0)['MStar'] alpha = -1.74 mStarz6 = -20.24 mStarz7 = -19.7 phiStar = 1.4e-3 lStarz6 = magnitudes.L_nu_from_magAB(mStarz6) lmin = 0.2 * lStarz6 magmin = magnitudes.magnitude_AB_from_L_nu(lmin) ltot = luminosityfunction.schechterCumuLM(magnitudeAB=magmin, MStar=mStarz7, phiStar=phiStar, alpha=alpha) sfrd = luminosityfunction.sfr_from_L_nu(ltot) print """Lmin = 0.2 L*z=6 -> Lmin/erg/s/Hz = %.3g -> Mmin = %.3g -> log(rho/(erg/s/Hz/Mpc^3)) = %.3g -> log(SFRD/(MSun/yr)) = %.3g"""\ % (lmin, magmin, numpy.log10(ltot), numpy.log10(sfrd)) ltotz6 = luminosityfunction.schechterCumuLM(magnitudeAB=magmin, MStar=mStarz6, phiStar=phiStar, alpha=alpha) print "luminosity density increase from z=7 to z=6 is %.2g percent." \ % (100 * (1. - ltot/ltotz6)) assert numpy.abs(numpy.round(1. - ltot/ltotz6, 1) - 0.5) < 0.1 assert numpy.round(magmin, 1) == -18.5 assert numpy.abs(numpy.round(numpy.log10(ltot), 1) - 25.5) < 0.2 assert numpy.abs(numpy.round(numpy.log10(sfrd), 1) - -2.32) < 0.05
def find_galaxy_list(map_path, airmass_threshold=airmass_thresholdp, completeness=completenessp, credzone=0.99): #loading the map: try: skymap = hp.read_map(map_path, field=None, verbose=False) except Exception as e: from smtplib import SMTP msg = '''Subject: Failed to Read LVC Sky Map From: Super N. Ova <*****@*****.**> To: [email protected] FITS file: {} Exception: {}'''.format(map_path, e) s = SMTP('localhost') s.sendmail('*****@*****.**', ['*****@*****.**'], msg) s.quit() print 'Failed to read sky map. Sending email.' return if isinstance(skymap, tuple) and len(skymap) == 4: prob, distmu, distsigma, distnorm = skymap else: print 'No distance information available. Cannot produce galaxy list.' return #loading the galaxy catalog. this one contains only RA, DEC, distance, Bmag galax = np.load("glade_RA_DEC.npy") #map parameters: npix = len(prob) nside = hp.npix2nside(npix) #galaxy parameters(RA, DEC to theta, phi): galax = (galax[np.where(galax[:, 2] > 0), :])[0] #no distance<0 theta = 0.5 * np.pi - np.pi * (galax[:, 1]) / 180 phi = np.deg2rad(galax[:, 0]) d = np.array(galax[:, 2]) #converting galaxy coordinates to map pixels: ipix = hp.ang2pix(nside, theta, phi) maxprobcoord_tup = hp.pix2ang(nside, np.argmax(prob)) maxprobcoord = [0, 0] maxprobcoord[0] = np.rad2deg(0.5 * np.pi - maxprobcoord_tup[0]) maxprobcoord[1] = np.rad2deg(maxprobcoord_tup[1]) #finding given percent probability zone(default is 99%): probcutoff = 1 probsum = 0 npix99 = 0 sortedprob = np.sort(prob) while probsum < credzone: probsum = probsum + sortedprob[-1] probcutoff = sortedprob[-1] sortedprob = sortedprob[:-1] npix99 = npix99 + 1 area = npix99 * hp.nside2pixarea(nside, degrees=True) #################################################### #calculating probability for galaxies by the localization map: p = prob[ipix] distp = ( norm(distmu[ipix], distsigma[ipix]).pdf(d) * distnorm[ipix] ) # * d**2)#/(norm(distmu[ipix], distsigma[ipix]).pdf(distmu[ipix]) * distnorm[ipix] * distmu[ipix]**2) #cuttoffs- 99% of probability by angles and 3sigma by distance: inddistance = np.where( np.abs(d - distmu[ipix]) < nsigmas_in_d * distsigma[ipix]) indcredzone = np.where(p >= probcutoff) doMassCuttoff = True #if no galaxies if (galax[np.intersect1d(indcredzone, inddistance)]).size == 0: while probsum < 0.99995: if sortedprob.size == 0: break probsum = probsum + sortedprob[-1] probcutoff = sortedprob[-1] sortedprob = sortedprob[:-1] npix99 = npix99 + 1 inddistance = np.where(np.abs(d - distmu[ipix]) < 5 * distsigma[ipix]) indcredzone = np.where(p >= probcutoff) doMassCuttoff = False ipix = ipix[np.intersect1d(indcredzone, inddistance)] p = p[np.intersect1d(indcredzone, inddistance)] p = (p * (distp[np.intersect1d(indcredzone, inddistance)])) ##d**2? galax = galax[np.intersect1d(indcredzone, inddistance)] if galax.size == 0: print "no galaxies in field" print "99.995% of probability is ", npix99 * hp.nside2pixarea( nside, degrees=True), "deg^2" print "peaking at [RA,DEC](deg) = ", maxprobcoord return # normalized luminosity to account for mass: luminosity = mag.L_nu_from_magAB(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) luminosityNorm = luminosity / np.sum(luminosity) luminositynormalization = np.sum(luminosity) normalization = np.sum(p * luminosityNorm) #taking 50% of mass (missingpiece is the area under the schecter function between l=inf and the brightest galaxy in the field. #if the brightest galaxy in the field is fainter than the schecter function cutoff- no cutoff is made. #while the number of galaxies in the field is smaller than minGalaxies- we allow for fainter galaxies, until we take all of them. missingpiece = gammaincc( alpha + 2, 10**(-(min(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) - MB_star) / 2.5) ) ##no galaxies brighter than this in the field- so don't count that part of the Schechter function while doMassCuttoff: MB_max = MB_star + 2.5 * np.log10( gammaincinv(alpha + 2, completeness + missingpiece)) if ( min(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) - MB_star ) > 0: #if the brightest galaxy in the field is fainter then cutoff brightness- don't cut by brightness MB_max = 100 brightest = np.where(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5)) < MB_max) # print MB_max if len(brightest[0]) < minGalaxies: if completeness >= 0.9: #tried hard enough. just take all of them completeness = 1 # just to be consistent. doMassCuttoff = False else: completeness = (completeness + (1. - completeness) / 2) else: #got enough galaxies galax = galax[brightest] p = p[brightest] luminosityNorm = luminosityNorm[brightest] doMassCuttoff = False #accounting for distance absolute_sensitivity = sensitivity - 5 * np.log10(galax[:, 2] * (10**5)) absolute_sensitivity_lum = mag.f_nu_from_magAB(absolute_sensitivity) distanceFactor = np.zeros(galax.shape[0]) distanceFactor[:] = ((maxL - absolute_sensitivity_lum) / (maxL - minL)) distanceFactor[mindistFactor > (maxL - absolute_sensitivity_lum) / (maxL - minL)] = mindistFactor distanceFactor[absolute_sensitivity_lum < minL] = 1 distanceFactor[absolute_sensitivity > maxL] = mindistFactor #sorting glaxies by probability ii = np.argsort(p * luminosityNorm * distanceFactor)[::-1] ####counting galaxies that constitute 50% of the probability(~0.5*0.98) sum = 0 galaxies50per = 0 observable50per = 0 #how many of the galaxies in the top 50% of probability are observable. sum_seen = 0 enough = True while sum < 0.5: if galaxies50per >= len(ii): enough = False break sum = sum + (p[ii[galaxies50per]] * luminosityNorm[ii[galaxies50per]]) / float(normalization) sum_seen = sum_seen + ( p[ii[galaxies50per]] * luminosityNorm[ii[galaxies50per]] * distanceFactor[ii[galaxies50per]]) / float(normalization) galaxies50per = galaxies50per + 1 #event stats: # # Ngalaxies_50percent = number of galaxies consisting 50% of probability (including luminosity but not distance factor) # actual_percentage = usually arround 50 # seen_percentage = if we include the distance factor- how much are the same galaxies worth # 99percent_area = area of map in [deg^2] consisting 99% (using only the map from LIGO) stats = { "Ngalaxies_50percent": galaxies50per, "actual_percentage": sum * 100, "seen_percentage": sum_seen, "99percent_area": area } #creating sorted galaxy list, containing info. each entry is (RA, DEC, distance(Mpc), Bmag, score, distance factor(between 0-1)) #score is normalized so that all the galaxies in the field sum to 1 (before luminosity cutoff) galaxylist = np.ndarray((galax.shape[0], 6)) ngalaxtoshow = 500 # SET NO. OF BEST GALAXIES TO USE if len(ii) > ngalaxtoshow: n = ngalaxtoshow else: n = len(ii) #adding to galaxy table database for i in range(ii.shape[0])[:n]: ind = ii[i] galaxylist[i, :] = [ galax[ind, 0], galax[ind, 1], galax[ind, 2], galax[ind, 3], (p * luminosityNorm / normalization)[ind], distanceFactor[ind] ] lvc_galaxy_dict = { 'voeventid': '(SELECT MAX(id) from voevent_lvc)', 'score': (p * luminosityNorm / normalization)[ind], 'gladeid': '(SELECT id from glade WHERE ra0={:f} AND dec0={:f})'.format( galax[ind, 0], galax[ind, 1]) } insert_values('lvc_galaxies', lvc_galaxy_dict) return galaxylist #, stats
def select_gladegalaxy_accordingto_luminosity(galaxytable, doMassCuttoff=True, completeness=0.5, minGalaxies=100): ##if galaxy number less than 500, don't do mass cut if len(galaxytable) < 500: doMassCuttoff = False # schecter function parameters: alpha = -1.07 MB_star = -20.7 # random slide from https://www.astro.umd.edu/~richard/ASTRO620/LumFunction-pp.pdf but not really...? from scipy.special import gammaincc from scipy.special import gammaincinv # normalized luminosity to account for mass: luminosity = mag.L_nu_from_magAB(galaxytable['Bmag'] - 5 * np.log10(galaxytable['disMpc'] * (10**5))) Slum = luminosity / np.sum(luminosity) galaxytable.add_column(Column(Slum, name='S_lum')) # taking 50% of mass (missingpiece is the area under the schecter function between l=inf and the brightest galaxy in the field. # if the brightest galaxy in the field is fainter than the schecter function cutoff- no cutoff is made. # while the number of galaxies in the field is smaller than minGalaxies- we allow for fainter galaxies, until we take all of them. # no galaxies brighter than this in the field- so don't count that part of the Schechter function missingpiece = gammaincc( alpha + 2, 10**(-(min(galaxytable['Bmag'] - 5 * np.log10(galaxytable['disMpc'] * (10**5))) - MB_star) / 2.5)) while doMassCuttoff: MB_max = MB_star + 2.5 * np.log10( gammaincinv(alpha + 2, completeness + missingpiece)) if (min(galaxytable['Bmag'] - 5 * np.log10(galaxytable['disMpc'] * (10**5))) - MB_star) > 0: # if the brightest galaxy in the field is fainter then cutoff brightness- don't cut by brightness MB_max = 100 brightest = np.where( galaxytable['Bmag'] - 5 * np.log10(galaxytable['disMpc'] * (10**5)) < MB_max) print('MB_max: ', MB_max) if len(brightest[0]) < minGalaxies: if completeness >= 0.9: # tried hard enough. just take all of them completeness = 1 # just to be consistent. doMassCuttoff = False else: completeness = (completeness + (1. - completeness) / 2) else: # got enough galaxies galaxytable = galaxytable[brightest] doMassCuttoff = False print(len(galaxytable), ' galaxies are selected!') ##great, we can now return the new result, need redo the normalization if any galaxy was cut galaxytable['S_lum'] = galaxytable['S_lum'] / np.sum(galaxytable['S_lum']) galaxytable['S_total'] = ( galaxytable['S_total'] * galaxytable['S_lum']) / np.sum( galaxytable['S_total'] * galaxytable['S_lum']) indextmp = np.argsort(galaxytable['S_total'])[::-1] galaxytable = galaxytable[indextmp] return galaxytable
def find_galaxy_list(map_path, airmass_threshold=airmass_thresholdp, completeness=completenessp, credzone=0.99): #loading the map: prob, distmu, distsigma, distnorm = hp.read_map(map_path, field=[0, 1, 2, 3], verbose=False) #loading the galaxy catalog. this one contains only RA, DEC, distance, Bmag galax = np.load("glade_RA_DEC.npy") #map parameters: npix = len(prob) nside = hp.npix2nside(npix) #galaxy parameters(RA, DEC to theta, phi): galax = (galax[np.where(galax[:, 2] > 0), :])[0] #no distance<0 theta = 0.5 * np.pi - np.pi * (galax[:, 1]) / 180 phi = np.deg2rad(galax[:, 0]) d = np.array(galax[:, 2]) #converting galaxy coordinates to map pixels: ipix = hp.ang2pix(nside, theta, phi) #finding given percent probability zone(default is 99%): #################################################### probcutoff = 1 probsum = 0 sortedprob = np.sort(prob) while probsum < credzone: probsum = probsum + sortedprob[-1] probcutoff = sortedprob[-1] sortedprob = sortedprob[:-1] #################################################### #calculating probability for galaxies by the localization map: p = prob[ipix] distp = ( norm(distmu[ipix], distsigma[ipix]).pdf(d) * distnorm[ipix] ) # * d**2)#/(norm(distmu[ipix], distsigma[ipix]).pdf(distmu[ipix]) * distnorm[ipix] * distmu[ipix]**2) #cuttoffs- 99% of probability by angles and 3sigma by distance: inddistance = np.where( np.abs(d - distmu[ipix]) < nsigmas_in_d * distsigma[ipix]) indcredzone = np.where(p >= probcutoff) galax = galax[np.intersect1d(indcredzone, inddistance)] ipix = ipix[np.intersect1d(indcredzone, inddistance)] p = p[np.intersect1d(indcredzone, inddistance)] p = (p * (distp[np.intersect1d(indcredzone, inddistance)])) ##d**2? # normalized luminosity to account for mass: luminosity = mag.L_nu_from_magAB(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) luminosityNorm = luminosity / np.sum(luminosity) normalization = np.sum(p * luminosityNorm) #taking 50% of mass (missingpiece is the area under the schecter function between l=inf and the brightest galaxy in the field. #if the brightest galaxy in the field is fainter than the schecter function cutoff- no cutoff is made. #while the number of galaxies in the field is smaller than minGalaxies- we allow for fainter galaxies, until we take all of them. missingpiece = gammaincc( alpha + 2, 10**(-(min(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) - MB_star) / 2.5) ) ##no galaxies brighter than this in the field- so don't count that part of the Schechter function doMassCuttoff = True while doMassCuttoff: MB_max = MB_star + 2.5 * np.log10( gammaincinv(alpha + 2, completeness + missingpiece)) if ( min(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5))) - MB_star ) > 0: #if the brightest galaxy in the field is fainter then cutoff brightness- don't cut by brightness MB_max = 100 brightest = np.where(galax[:, 3] - 5 * np.log10(galax[:, 2] * (10**5)) < MB_max) # print MB_max if len(brightest[0]) < minGalaxies: if completeness >= 0.9: #tried hard enough. just take all of them completeness = 1 # just to be consistent. doMassCuttoff = False else: completeness = (completeness + (1. - completeness) / 2) else: #got enough galaxies galax = galax[brightest] p = p[brightest] luminosityNorm = luminosityNorm[brightest] doMassCuttoff = False #including observation constraints. (uses code in observational_const.py) indices = get_observables(galax, airmass_threshold) haleakalaObservable = indices['indHal'] sidingSpringObservable = indices['indSS'] #sorting glaxies by probability ii = np.argsort(p * luminosityNorm)[::-1] ####counting galaxies that constitute 50% of the probability(~0.5*0.98) sum = 0 galaxies50per = 0 observable50per = 0 #how many of the galaxies in the top 50% of probability are observable. enough = True while sum < 0.5: if galaxies50per >= len(ii): enough = False break sum = sum + (p[ii[galaxies50per]] * luminosityNorm[ii[galaxies50per]]) / float(normalization) if ii[galaxies50per] in haleakalaObservable or ii[ galaxies50per] in sidingSpringObservable: observable50per = observable50per + 1 galaxies50per = galaxies50per + 1 #### #creating sorted galaxy list, containing info on #ngalaxtoshow. each entry is (RA, DEC, distance(Mpc), Bmag, score) #score is normalized so that all the galaxies in the field sum to 1 (before luminosity cutoff) galaxylist = np.ndarray((ngalaxtoshow, 5)) ###uncomment to include only observable galaxies. # i=0 # n=0 # while i<ngalaxtoshow and n<galax.shape[0]: # ind = ii[n] # if ind in haleakalaObservable or ind in sidingSpringObservable: # galaxylist[i,:] = [galax[ind, 0], galax[ind, 1], galax[ind,2], galax[ind,3], (p*luminosityNorm/normalization)[ind]] # i = i+1 # n = n+1 for i in range(ngalaxtoshow): ind = ii[i] galaxylist[i, :] = [ galax[ind, 0], galax[ind, 1], galax[ind, 2], galax[ind, 3], (p * luminosityNorm / normalization)[ind] ] return galaxylist #[:i,:]#uncomment to include only observable galaxies. ########################################################################################################## #to call function with commandline: # print find_galaxy_list(sys.argv[1])