def load_iso(): Zs = numpy.arange(0.0005, 0.0605, 0.0005) return isodist.PadovaIsochrone(type='sdss-2mass', parsec=True, Z=Zs)
def __init__(self, loggmin=None, loggmax=None, imfmodel='lognormalChabrier2001', Z=None, expsfh=False, band='Ks', dontgather=False, basti=False, parsec=True, minage=None, maxage=10., jkmin=None, stage=None, eta=None): """ NAME: __init__ PURPOSE: initialize isocmodel INPUT: Z= metallicity (if not set, use flat prior in Z over all Z; can be list) loggmin= if set, cut logg at this minimum loggmax= if set, cut logg at this maximum, if 'rc', then this is the function of teff and z appropriate for the APOGEE RC sample imfmodel= (default: 'lognormalChabrier2001') IMF model to use (see isodist.imf code for options) band= band to use for M_X (JHK) expsfh= if True, use an exponentially-declining star-formation history (can be set to a decay time-scale in Gyr) dontgather= if True, don't gather surrounding Zs basti= if True, use Basti isochrones (if False, use PARSEC) parsec= if True (=default), use PARSEC isochrones, if False, use Padova stage= if True, only use this evolutionary stage minage= (None) minimum log10 of age/yr maxage= (10.) maximum log10 of age/yr jkmin= (None) if set, only consider J-Ks greater than this eta= (None) mass-loss efficiency parameter OUTPUT: object HISTORY: 2012-11-07 - Written - Bovy (IAS) """ self._band = band self._loggmin = loggmin self._loggmax = loggmax if isinstance(expsfh, (int, float, numpy.float32, numpy.float64)): self._expsfh = expsfh elif expsfh: self._expsfh = 8. else: self._expsfh = False self._Z = Z self._imfmodel = imfmodel self._basti = basti self._eta = eta if isinstance(loggmax, str) and loggmax.lower() == 'rc': from apogee.samples.rc import loggteffcut #Read isochrones if basti: zs = numpy.array([ 0.0001, 0.0003, 0.0006, 0.001, 0.002, 0.004, 0.008, 0.01, 0.0198, 0.03, 0.04 ]) elif parsec: zs = numpy.arange(0.0005, 0.06005, 0.0005) else: zs = numpy.arange(0.0005, 0.03005, 0.0005) if Z is None: Zs = zs elif isinstance(Z, float): if basti or dontgather: Zs = [Z] elif Z < 0.001 or Z > 0.0295: Zs = [Z] elif Z < 0.0015 or Z > 0.029: Zs = [Z - 0.0005, Z, Z + 0.0005] #build up statistics elif Z < 0.01: Zs = [Z - 0.001, Z - 0.0005, Z, Z + 0.0005, Z + 0.001] #build up statistics else: Zs = [Z - 0.0005, Z, Z + 0.0005] #build up statistics if basti: p = isodist.BastiIsochrone(Z=Zs, eta=eta) else: p = isodist.PadovaIsochrone(Z=Zs, parsec=parsec, eta=eta) if basti: #Force BaSTI to have equal age sampling lages = list(numpy.log10(numpy.arange(0.1, 1., 0.1)) + 9.) lages.extend(list(numpy.log10(numpy.arange(1.0, 10.5, 0.5)) + 9.)) lages = numpy.array(lages) #Get relevant data sample = [] weights = [] massweights = [] loggs = [] teffs = [] pmasses = [] plages = [] pjks = [] for logage in p.logages(): if logage > maxage: continue if not minage is None and logage < minage: continue if basti and numpy.sum((logage == lages)) == 0: continue for zz in range(len(Zs)): thisiso = p(logage, Zs[zz], asrecarray=True, stage=stage) if len(thisiso.M_ini) == 0: continue #Calculate int_IMF for this IMF model if not imfmodel == 'lognormalChabrier2001': #That would be the default if imfmodel == 'exponentialChabrier2001': int_IMF = isodist.imf.exponentialChabrier2001( thisiso.M_ini, int=True) elif imfmodel == 'kroupa2003': int_IMF = isodist.imf.kroupa2003(thisiso.M_ini, int=True) elif imfmodel == 'chabrier2003': int_IMF = isodist.imf.chabrier2003(thisiso.M_ini, int=True) else: raise IOError( "imfmodel option not understood (non-existing model)" ) elif basti: int_IMF = isodist.imf.lognormalChabrier2001(thisiso.M_ini, int=True) else: int_IMF = thisiso.int_IMF dN = (numpy.roll(int_IMF, -1) - int_IMF) / (int_IMF[-1] - int_IMF[0]) / 10**(logage - 7.) dmass = thisiso.M_ini * ( numpy.roll(int_IMF, -1) - int_IMF) / numpy.sum( (thisiso.M_ini * (numpy.roll(int_IMF, -1) - int_IMF))[:-1]) / 10**( logage - 7.) for ii in range(1, len(int_IMF) - 1): if basti: JK = 0.996 * (thisiso.J[ii] - thisiso.K[ii]) + 0.00923 else: JK = thisiso.J[ii] - thisiso.Ks[ii] if not jkmin is None and JK < jkmin: continue if band.lower() == 'h': if basti: raise NotImplementedError( "'H' not implemented for BaSTI yet") J = JK + thisiso.K[ii] - 0.044 H = J - (0.980 * (thisiso.J[ii] - thisiso.H[ii]) - 0.045) else: H = thisiso.H[ii] elif band.lower() == 'j': if basti: raise NotImplementedError( "'J' not implemented for BaSTI yet") J = JK + thisiso.K[ii] - 0.044 else: H = thisiso.J[ii] elif band.lower() == 'k' or band.lower() == 'ks': if basti: H = thisiso.K[ii] - 0.046 else: H = thisiso.Ks[ii] if JK < 0.3 \ or (isinstance(loggmax,str) and loggmax == 'rc' and (thisiso['logg'][ii] > loggteffcut(10.**thisiso['logTe'][ii],Zs[zz],upper=True))) \ or (not isinstance(loggmax,str) and not loggmax is None and thisiso['logg'][ii] > loggmax) \ or (not loggmin is None and thisiso['logg'][ii] < loggmin): continue if dN[ii] > 0.: sample.append([JK, H]) loggs.append([thisiso.logg[ii]]) teffs.append([10.**thisiso.logTe[ii]]) pmasses.append(thisiso.M_ini[ii]) plages.append(logage) pjks.append(JK) if basti: #BaSTI is sampled uniformly in age, not logage, but has a finer sampling below 1 Gyr if logage < 9.: if self._expsfh: weights.append(dN[ii] / 5. * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) massweights.append( dmass[ii] / 5. * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) else: weights.append(dN[ii] / 5.) massweights.append(dmass[ii] / 5.) else: if self._expsfh: weights.append(dN[ii] * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) massweights.append(dmass[ii] * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) else: weights.append(dN[ii]) massweights.append(dmass[ii]) else: if self._expsfh: weights.append( dN[ii] * 10**(logage - 7.) * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) massweights.append( dmass[ii] * 10**(logage - 7.) * numpy.exp( (10.**(logage - 7.)) / self._expsfh / 100.)) #e.g., Binney (2010) else: weights.append(dN[ii] * 10**(logage - 7.)) massweights.append(dmass[ii] * 10**(logage - 7.)) else: continue #no use in continuing here #Form array sample = numpy.array(sample) loggs = numpy.array(loggs) teffs = numpy.array(teffs) pmasses = numpy.array(pmasses) plages = numpy.array(plages) - 9. pjks = numpy.array(pjks) weights = numpy.array(weights) massweights = numpy.array(massweights) #Cut out low weights if False: indx = (weights > 10.**-5. * numpy.sum(weights)) else: indx = numpy.ones(len(weights), dtype='bool') self._sample = sample[indx, :] self._weights = weights[indx] self._massweights = massweights[indx] self._loggs = loggs[indx] self._teffs = teffs[indx] self._masses = pmasses[indx] self._lages = plages[indx] self._jks = pjks[indx] #Setup KDE self._kde = dens_kde.densKDE( self._sample, w=self._weights, h=2. * self._sample.shape[0]**(-1. / 5.), #h='scott', kernel='biweight', variable=True, variablenitt=3, variableexp=0.5) return None
def imf_h_jk(plotfile,Z=None,dwarf=False,log=False,h=12.,basti=False, dartmouth=False,kroupa=False): #Read isochrones if basti: zs= numpy.array([0.0001,0.0003,0.0006,0.001,0.002,0.004,0.008, 0.01,0.0198,0.03,0.04]) elif dartmouth: zs= isodist.FEH2Z(numpy.array([-2.5,-2.,-1.5,-1.,-0.5,0.,0.2,0.3,0.5])) else: zs= numpy.arange(0.0005,0.03005,0.0005) if Z is None: Zs= zs elif not basti and not dartmouth: if Z < 0.01: Zs= [Z-0.001,Z-0.0005,Z,Z+0.0005,Z+0.001] #build up statistics else: Zs= [Z-0.0005,Z,Z+0.0005] #build up statistics else: Zs= [Z] if basti: p= isodist.BastiIsochrone(Z=Zs) elif dartmouth: p= isodist.DartmouthIsochrone(feh=isodist.Z2FEH(Zs),onlyold=True) else: p= isodist.PadovaIsochrone(Z=Zs) #Get relevant data sample= [] weights= [] for logage in p.logages(): for z in Zs: thisiso= p(logage,z) if basti: mini= thisiso['M_ini'] elif dartmouth: mini= thisiso['M'] else: mini= thisiso['M_ini'] if basti: int_IMF= isodist.imf.lognormalChabrier2001(thisiso['M_ini'], int=True) dmpm= numpy.roll(int_IMF,-1)-int_IMF elif dartmouth: int_IMF= isodist.imf.lognormalChabrier2001(thisiso['M'], int=True) dmpm= numpy.roll(int_IMF,-1)-int_IMF else: if kroupa: int_IMF= isodist.imf.kroupa2003(thisiso['M_ini'],int=True) dmpm= numpy.roll(int_IMF,-1)-int_IMF else: dmpm= numpy.roll(thisiso['int_IMF'],-1)-thisiso['int_IMF'] for ii in range(1,len(mini)-1): if basti: JK= thisiso['J'][ii]-thisiso['K'][ii] else: JK= thisiso['J'][ii]-thisiso['Ks'][ii] H= thisiso['H'][ii] if JK < 0.: # or thisiso['logg'][ii] > 3.5: continue if dmpm[ii] > 0.: if basti: sample.append([thisiso['J'][ii]-thisiso['K'][ii], thisiso['H'][ii]]) else: sample.append([thisiso['J'][ii]-thisiso['Ks'][ii], thisiso['H'][ii]]) if dartmouth: if logage > numpy.log10(5.)+9.: weights.append(2.*dmpm[ii]) #Dartmouth are linearly spaced, but spacing is bigger at > 5 Gyr else: weights.append(dmpm[ii]) #Dartmouth are linearly spaced? else: weights.append(dmpm[ii]*10**(logage-7.)) #weights.append(dmpm[ii]*10**(logage-7.)*numpy.exp((10.**(logage-7.))/800.)) else: continue #no use in continuing here #Form array sample= numpy.array(sample) weights= numpy.array(weights) #Histogram if dwarf: hist, edges= numpy.histogramdd(sample,weights=weights,bins=51, range=[[0.,1.6],[2.,9.]]) else: hist, edges= numpy.histogramdd(sample,weights=weights,bins=49, range=[[0.3,1.6],[-11.,2]]) #Normalize each J-K for ii in range(len(hist[:,0])): hist[ii,:]/= numpy.nanmax(hist[ii,:])/numpy.nanmax(hist) rev= copy.copy(hist[ii,::-1]) #reverse, but in one go does not always work hist[ii,:]= rev #Plot bovy_plot.bovy_print() if log: hist= numpy.log(hist) bovy_plot.bovy_dens2d(hist.T,origin='lower',cmap='gist_yarg', xrange=[edges[0][0],edges[0][-1]], yrange=[edges[1][-1],edges[1][0]], aspect=(edges[0][-1]-edges[0][0])/float(edges[1][-1]-edges[1][0]), xlabel=r'$(J-K_s)_0\ [\mathrm{mag}]$', ylabel=r'$M_H\ [\mathrm{mag}]$', interpolation='nearest') #Add extinction arrow djk= 0.45 dh= 1.55/1.5*djk from matplotlib.patches import FancyArrowPatch ax=pyplot.gca() ax.add_patch(FancyArrowPatch((1.,-2.),(1+djk,-2+dh), arrowstyle='->',mutation_scale=20,fill=True, lw=1.25)) bovy_plot.bovy_text(1.05,-2.05,r'$\mathrm{extinction}$', rotation=-math.atan(1.5/1.55*1.3/13.)/math.pi*180., size=14.) #Add color cut bovy_plot.bovy_plot([0.5,0.5],[-20.,20.],'--',color='0.6',overplot=True) ax.add_patch(FancyArrowPatch((0.5,-6.),(0.7,-6.), arrowstyle='->',mutation_scale=20,fill=True, lw=1.25,ls='dashed',color='0.6')) bovy_plot.bovy_text(0.43,-8.,r'$\mathrm{APOGEE\ color\ cut}$',rotation=90., size=14.) #Add twin y axis ax= pyplot.gca() def my_formatter(x, pos): """distance in kpc for m=h""" xs= 10.**((h-x)/5.-2.) return r'$%.0f$' % xs def my_formatter2(x, pos): """distance in kpc for m=h""" xs= 10.**((h-x)/5.+1.) return r'$%.0f$' % xs ax2= pyplot.twinx() if dwarf: major_formatter = FuncFormatter(my_formatter2) else: major_formatter = FuncFormatter(my_formatter) ax2.yaxis.set_major_formatter(major_formatter) ystep= ax.yaxis.get_majorticklocs() ystep= ystep[1]-ystep[0] ax2.yaxis.set_minor_locator(MultipleLocator(ystep/5.)) ax2.yaxis.tick_right() ax2.yaxis.set_label_position('right') ymin, ymax= ax.yaxis.get_view_interval() ax2.yaxis.set_view_interval(ymin,ymax,ignore=True) if dwarf: ax2.set_ylabel('$\mathrm{distance\ for}\ H_0\ =\ %.1f\ [\mathrm{pc}]$' % h) else: ax2.set_ylabel('$\mathrm{distance\ for}\ H_0\ =\ %.1f\ [\mathrm{kpc}]$' % h) xstep= ax.xaxis.get_majorticklocs() xstep= xstep[1]-xstep[0] ax2.xaxis.set_minor_locator(MultipleLocator(xstep/5.)) if Z is None: bovy_plot.bovy_end_print(plotfile) else: bovy_plot.bovy_text(r'$Z\ =\ %.3f$' % Z,top_right=True,size=14.) bovy_plot.bovy_end_print(plotfile) return None
def generate_isogrid(): """ generate a recarray with all the entries from PARSEC isochrones in isodist """ zs = np.arange(0.0005, 0.0605, 0.0005) zlist = [] for i in range(len(zs)): zlist.append(format(zs[i], '.4f')) iso = isodist.PadovaIsochrone(type='2mass-spitzer-wise', Z=zs, parsec=True) logages = [] mets = [] js = [] hs = [] ks = [] loggs = [] teffs = [] imf = [] deltam = [] M_ini = [] M_act = [] logL iso_logages = iso._logages iso_Zs = iso._ZS for i in tqdm.tqdm(range(len(iso_logages))): for j in range(len(iso_Zs)): thisage = iso_logages[i] thisZ = iso_Zs[j] thisiso = iso(thisage, Z=thisZ) so = np.argsort(thisiso['M_ini']) loggs.extend(thisiso['logg'][so][1:]) logages.extend(thisiso['logage'][so][1:]) mets.extend(np.ones(len(thisiso['H'][so]) - 1) * thisZ) js.extend(thisiso['J'][so][1:]) hs.extend(thisiso['H'][so][1:]) ks.extend(thisiso['Ks'][so][1:]) teffs.extend(thisiso['logTe'][so][1:]) imf.extend(thisiso['int_IMF'][so][1:]) deltam.extend(thisiso['int_IMF'][so][1:] - thisiso['int_IMF'][so][:-1]) M_ini.extend(thisiso['M_ini'][so][1:]) M_act.extend(thisiso['M_act'][so][1:]) logL.extend(thisiso['logL'][so][1:]) logages = np.array(logages) mets = np.array(mets) js = np.array(js) hs = np.array(hs) ks = np.array(ks) loggs = np.array(loggs) teffs = 10**np.array(teffs) imf = np.array(imf) deltam = np.array(deltam) M_ini = np.array(M_ini) M_act = np.array(M_act) logL = np.array(logL) rec = np.recarray(len(deltam), dtype=[('logageyr', float), ('Z', float), ('J', float), ('H', float), ('K', float), ('logg', float), ('teff', float), ('int_IMF', float), ('deltaM', float), ('M_ini', float), ('M_act', float), ('logL', float)]) rec['logageyr'] = logages rec['Z'] = mets rec['J'] = js rec['H'] = hs rec['K'] = ks rec['logg'] = loggs rec['teff'] = teffs rec['int_IMF'] = imf rec['deltaM'] = deltam rec['M_ini'] = M_ini rec['M_act'] = M_act rec['logL'] = logL return rec
def __init__(self, dwarf=False, imfmodel='lognormalChabrier2001', Z=None, interpolate=False, expsfh=False, marginalizefeh=False, glon=None, dontgather=False, loggmax=None, basti=False): """ NAME: __init__ PURPOSE: initialize isomodel INPUT: Z= metallicity (if not set, use flat prior in Z over all Z; can be list) dwarf= (default: False) if True, use dwarf part imfmodel= (default: 'lognormalChabrier2001') IMF model to use (see isodist.imf code for options) interpolate= (default: False) if True, interpolate the binned representation expsfh= if True, use an exponentially-declining star-formation history marginalizefeh= if True, marginalize over the FeH distribution along line of sight glon glon - galactic longitude in rad of los for marginalizefeh dontgather= if True, don't gather surrounding Zs loggmax= if set, cut logg at this maximum basti= if True, use Basti isochrones (if False, use Padova) OUTPUT: object HISTORY: 2012-02-17 - Written - Bovy (IAS) """ #Read isochrones if basti: zs = numpy.array([ 0.0001, 0.0003, 0.0006, 0.001, 0.002, 0.004, 0.008, 0.01, 0.0198, 0.03, 0.04 ]) else: zs = numpy.arange(0.0005, 0.03005, 0.0005) if marginalizefeh: Zs = numpy.arange(0.008, 0.031, 0.001) dFeHdZ = 1. / Zs pZs = feh_l(glon, isodist.Z2FEH(Zs)) * dFeHdZ elif Z is None: Zs = zs elif isinstance(Z, float): if basti or dontgather: Zs = [Z] elif Z < 0.001 or Z > 0.0295: Zs = [Z] elif Z < 0.0015 or Z > 0.029: Zs = [Z - 0.0005, Z, Z + 0.0005] #build up statistics elif Z < 0.01: Zs = [Z - 0.001, Z - 0.0005, Z, Z + 0.0005, Z + 0.001] #build up statistics else: Zs = [Z - 0.0005, Z, Z + 0.0005] #build up statistics if basti: p = isodist.BastiIsochrone(Z=Zs) else: p = isodist.PadovaIsochrone(Z=Zs) #Get relevant data sample = [] weights = [] for logage in p.logages(): for zz in range(len(Zs)): thisiso = p(logage, Zs[zz], asrecarray=True) #Calculate int_IMF for this IMF model if not imfmodel == 'lognormalChabrier2001': #That would be the default if imfmodel == 'exponentialChabrier2001': int_IMF = isodist.imf.exponentialChabrier2001( thisiso.M_ini, int=True) elif imfmodel == 'kroupa2003': int_IMF = isodist.imf.kroupa2003(thisiso.M_ini, int=True) elif imfmodel == 'chabrier2003': int_IMF = isodist.imf.chabrier2003(thisiso.M_ini, int=True) else: raise IOError( "imfmodel option not understood (non-existing model)" ) elif basti: int_IMF = isodist.imf.lognormalChabrier2001(thisiso.M_ini, int=True) else: int_IMF = thisiso.int_IMF dN = numpy.roll(int_IMF, -1) - int_IMF for ii in range(1, len(int_IMF) - 1): if basti: JK = thisiso.J[ii] - thisiso.K[ii] else: JK = thisiso.J[ii] - thisiso.Ks[ii] H = thisiso.H[ii] if JK < 0.3 or (not loggmax is None and thisiso['logg'][ii] > loggmax): continue if dN[ii] > 0.: sample.append([JK, H]) if marginalizefeh: if H < (11. / -1.3 * (JK - 0.3)): weights.append( 0. ) #HACK TO GET RID OF UNWANTED BRIGHT POINTS elif expsfh: weights.append(pZs[zz] * dN[ii] * 10**(logage - 7.) * numpy.exp( (10.**(logage - 7.)) / 800.)) #e.g., Binney (2010) else: weights.append(pZs[zz] * dN[ii] * 10**(logage - 7.)) else: if expsfh: weights.append(dN[ii] * 10**(logage - 7.) * numpy.exp( (10.**(logage - 7.)) / 800.)) #e.g., Binney (2010) else: weights.append(dN[ii] * 10**(logage - 7.)) else: continue #no use in continuing here #Form array sample = numpy.array(sample) weights = numpy.array(weights) self._sample = sample self._weights = weights #Histogram self._jkmin, self._jkmax = 0.3, 1.6 if dwarf: self._hmin, self._hmax = 2., 9. self._nbins = 51 else: self._hmin, self._hmax = -11., 2. self._nbins = 26 #49 self._djk = (self._jkmax - self._jkmin) / float(self._nbins) self._dh = (self._hmax - self._hmin) / float(self._nbins) self._hist, self._edges = numpy.histogramdd( sample, weights=weights, bins=self._nbins, range=[[self._jkmin, self._jkmax], [self._hmin, self._hmax]]) #Save self._Zs = Zs self._interpolate = interpolate self._dwarf = dwarf self._loghist = numpy.log(self._hist) self._loghist[( self._hist == 0.)] = -numpy.finfo(numpy.dtype(numpy.float64)).max if interpolate: #Form histogram grid jks = numpy.linspace(self._jkmin + self._djk / 2., self._jkmax - self._djk / 2., self._nbins) hs = numpy.linspace(self._hmin + self._dh / 2., self._hmax - self._dh / 2., self._nbins) self._interpolatedhist = scipy.interpolate.RectBivariateSpline( jks, hs, self._hist, bbox=[self._jkmin, self._jkmax, self._hmin, self._hmax], s=0.) #raise NotImplementedError("'interpolate=True' option for isomodel not implemented yet") return None
import numpy as np import matplotlib.pyplot as plt import isodist import os import glob import pickle from tqdm import tqdm ISO_PATH = os.getenv('ISODIST_DATA') #load isochrones path = ISO_PATH + '/parsec-sdss-2mass/' Zs = [float(file[79:85]) for file in glob.glob(os.path.join(path, '*.dat.gz'))] isochrone = isodist.PadovaIsochrone(Z=Zs, parsec=True) logages = isochrone.logages() logages = logages[logages >= 8.] Zs = isochrone.Zs() #Generate isochrone grid def isochrone_grid(logages, Zs, imf): grid = [] for lage in tqdm(range(len(logages))): for met in Zs: #print 'generating grid entry for Age='+str(round((10**lage)/1e9,1))+'Gyr and Fe/H='+str(round(isodist.Z2FEH(met),2))+'...' iso = isochrone(logages[lage], Z=met) H_iso = iso['H'][1:] M_iso = iso['M_ini'][1:] logg_iso = iso['logg'][1:] J_K_iso = iso['J'][1:] - iso['Ks'][1:]