def test_metallicity(): """ Test isochrone generation at different metallicities """ # Define isochrone parameters logAge = np.log10(5 * 10**6.) AKs = 0.8 dist = 4000 evo_model = evolution.MISTv1() atm_func = atmospheres.get_phoenixv16_atmosphere red_law = reddening.RedLawHosek18b() filt_list = ['wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m'] # Start with a solar metallicity isochrone metallicity = 0.0 # Make Isochrone object, with high mass_sampling to decrease compute time my_iso = synthetic.IsochronePhot(logAge, AKs, dist, metallicity=metallicity, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=10) # Test isochrone properties assert my_iso.points.meta['METAL_IN'] == 0.0 assert os.path.exists('iso_6.70_0.80_04000_p00.fits') # Now for non-solar metallicity metallicity = -1.5 # Make Isochrone object, with high mass_sampling to decrease compute time my_iso = synthetic.IsochronePhot(logAge, AKs, dist, metallicity=metallicity, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=10) metal_act = np.log10(0.00047 / 0.0142) # For Mist isochrones # Test isochrone properties assert my_iso.points.meta['METAL_IN'] == -1.5 assert my_iso.points.meta['METAL_ACT'] == metal_act assert os.path.exists('iso_6.70_0.80_04000_m15.fits') return
def test_IsochronePhot(plot=False): from popstar import synthetic as syn logAge = 6.7 AKs = 2.7 distance = 4000 filt_list = ['wfc3,ir,f127m', 'nirc2,J'] mass_sampling = 1 startTime = time.time() iso = syn.IsochronePhot(logAge, AKs, distance, filters=filt_list, mass_sampling=mass_sampling) endTime = time.time() print('Test completed in: %d seconds' % (endTime - startTime)) # Typically takes 120 seconds if file is regenerated. # Limited by pysynphot.Icat call in atmospheres.py assert iso.points.meta['LOGAGE'] == logAge assert iso.points.meta['AKS'] == AKs assert iso.points.meta['DISTANCE'] == distance assert len(iso.points) > 100 assert 'm_nirc2_J' in iso.points.colnames if plot: plt.figure(1) iso.plot_CMD('mag814w', 'mag160w') plt.figure(2) iso.plot_mass_magnitude('mag160w') return
def time_test_cluster(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar import reddening from popstar.imf import imf from popstar.imf import multiplicity logAge = 6.7 AKs = 2.7 distance = 4000 cluster_mass = 10**4 startTime = time.time() evo = evolution.MergedBaraffePisaEkstromParsec() atm_func = atm.get_merged_atmosphere red_law = reddening.RedLawNishiyama09() filt_list = ['nirc2,J', 'nirc2,Kp'] iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) imf_limits = np.array([0.07, 0.5, 150]) imf_powers = np.array([-1.3, -2.35]) multi = multiplicity.MultiplicityUnresolved() my_imf = imf.IMF_broken_powerlaw(imf_limits, imf_powers, multiplicity=multi) print('Constructed IMF with multiples: %d seconds' % (time.time() - startTime)) cluster = syn.ResolvedCluster(iso, my_imf, cluster_mass) print('Constructed cluster: %d seconds' % (time.time() - startTime)) return
def __init__(self, age=3.9e6, ext=2.63, dist=7.971e3, met=0.0, phase=None, use_atm_func='merged'): log_age = np.log10(age) self.log_age = log_age self.A_Ks = ext self.dist = dist self.met = met # Evolution/Atmosphere Models evo_model = evolution.MISTv1() if use_atm_func == 'merged': atm_func = atmospheres.get_merged_atmosphere elif use_atm_func == 'phoenix': atm_func = atmospheres.get_phoenixv16_atmosphere # Extinction law red_law = reddening.RedLawNoguerasLara18() self.ext_alpha = 2.30 ## Calculate extinctions implied by isochrone extinction self.A_B = self.A_Ks * (lambda_Ks / lambda_B)**self.ext_alpha self.A_R = self.A_Ks * (lambda_Ks / lambda_R)**self.ext_alpha # Create an isochhrone with the given parameters self.iso_curAge = synthetic.IsochronePhot(self.log_age, self.A_Ks, self.dist, evo_model=evo_model, atm_func=atm_func, red_law=red_law, metallicity=self.met, filters=self.filt_list) # Save out specific stellar parameter columns needed ## If needing specific phase, draw it out before saving if phase is not None: phase_check = np.where( self.iso_curAge.points['phase'] == mist_phase_dict[phase]) else: phase_check = np.where(self.iso_curAge.points['phase'] >= -1) self.iso_mass_init = self.iso_curAge.points['mass'][phase_check] self.iso_mass = self.iso_curAge.points['mass_current'][phase_check] self.iso_rad = (self.iso_curAge.points['R'][phase_check]).to(u.solRad) self.iso_lum = self.iso_curAge.points['L'][phase_check] self.iso_teff = self.iso_curAge.points['Teff'][phase_check] self.iso_mag_B = self.iso_curAge.points['m_ubv_B'][phase_check] self.iso_mag_R = self.iso_curAge.points['m_ubv_R'][phase_check] self.iso_rad_min = np.min(self.iso_rad).value self.iso_rad_max = np.max(self.iso_rad).value
def animate_ages(): # Define isochrone parameters dist = 4000 # distance in parsecs AKs = 1.0 # Ks filter extinction in mags logAge = np.arange(6, 9, 0.05) # Age in log(years) # Define extinction law and filters redlaw = reddening.RedLawCardelli(3.1) # Rv = 3.1 evo_model = evolution.MISTv1() filt_list = ['nirc2,J', 'nirc2,Kp'] plt.figure(1) for aa in range(len(logAge)): iso = synthetic.IsochronePhot(logAge[aa], AKs, dist, filters=filt_list, red_law=redlaw, evo_model=evo_model, mass_sampling=3) plt.clf() plt.plot(iso.points['m_nirc2_J'] - iso.points['m_nirc2_Kp'], iso.points['m_nirc2_J']) plt.xlabel('J - Kp') plt.ylabel('J') plt.gca().invert_yaxis() plt.title('Age = 10^{0:.2f}'.format(logAge[aa])) plt.xlim(1, 3) plt.ylim(28, 6) plt.savefig( '/u/jlu/doc/present/2020_06_ucb_lunch/iso_age_{0:.2f}.png'.format( logAge[aa]))
def make_sim_cluster(): work_dir = '/u/jlu/work/gc/jwst/2018_03_19/' ages = [4e6, 1e8, 8e9] cluster_mass = [1e4, 1e4, 1e7] AKs = 2.7 deltaAKs = 1.0 distance = 8000 mass_sampling = 5 isochrones = [] clusters = [] evo = evolution.MergedBaraffePisaEkstromParsec() atm_func = atm.get_merged_atmosphere red_law = reddening.RedLawHosek18() multi = multiplicity.MultiplicityUnresolved() imf_mass_limits = np.array([0.07, 0.5, 1, np.inf]) imf_powers_old = np.array([-1.3, -2.3, -2.3]) imf_powers_yng = np.array([-1.3, -1.8, -1.8]) my_imf_old = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers_old, multiplicity=multi) my_imf_yng = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers_yng, multiplicity=multi) # Test all filters filt_list = [ 'wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m', 'acs,wfc1,f814w', 'wfc3,ir,f125w', 'wfc3,ir,f160w', 'jwst,F090W', 'jwst,F115W', 'jwst,F164N', 'jwst,F187N', 'jwst,F212N', 'jwst,F323N', 'jwst,F405N', 'jwst,F466N', 'jwst,F470N', 'jwst,F140M', 'jwst,F162M', 'jwst,F182M', 'jwst,F210M', 'jwst,F250M', 'jwst,F300M', 'jwst,F335M', 'jwst,F360M', 'jwst,F410M', 'jwst,F430M', 'jwst,F460M', 'jwst,F480M', 'nirc2,J', 'nirc2,H', 'nirc2,Kp', 'nirc2,Lp', 'nirc2,Ms' ] startTime = time.time() for ii in range(len(ages)): logAge = np.log10(ages[ii]) iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=mass_sampling, iso_dir=work_dir) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) if ii < 2: imf_ii = my_imf_yng else: imf_ii = my_imf_old cluster = syn.ResolvedClusterDiffRedden(iso, imf_ii, cluster_mass[ii], deltaAKs) # Save generated clusters to file. save_file_fmt = '{0}/clust_{1:.2f}_{2:4.2f}_{3:4s}.fits' save_file_txt = save_file_fmt.format(work_dir, logAge, AKs, str(distance).zfill(5)) save_file = open(save_file_txt, 'wb') pickle.dump(cluster, save_file) return return
def test_phot_consistency(filt='all'): """ Test photometric consistency of generated isochrone (IsochronePhot) against pre-generated isochrone with native filter sampling. Requires consistency to within 0.005 mag. Base isochrone is at 5 Myr, AKs = 0, 1000 pc, mass_sampling=10 Paramters: ---------- filt: 'all', 'hst', 'vista', 'decam', 'ps1', 'jwst' Specify what filter set you want to test """ from astropy.table import Table import os # Load pre-generated isochrone, located in popstar tests directory direct = os.path.dirname(__file__) orig = Table.read(direct + '/iso_6.70_0.00_01000.fits', format='fits') # Generate new isochrone with popstar code if filt == 'all': filt_list = [ 'wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m', 'acs,wfc1,f814w', 'wfc3,ir,f125w', 'wfc3,ir,f160w', 'decam,y', 'decam,i', 'decam,z', 'decam,u', 'decam,g', 'decam,r', 'vista,Y', 'vista,Z', 'vista,J', 'vista,H', 'vista,Ks', 'ps1,z', 'ps1,g', 'ps1,r', 'ps1,i', 'ps1,y', 'jwst,F070W', 'jwst,F090W', 'jwst,F115W', 'jwst,F140M', 'jwst,F150W', 'jwst,F150W2', 'jwst,F162M', 'jwst,F164N', 'jwst,F182M', 'jwst,F187N', 'jwst,F200W', 'jwst,F212N', 'jwst,F210M', 'jwst,F250M', 'jwst,F277W', 'jwst,F300M', 'jwst,F322W2', 'jwst,F323N', 'jwst,F335M', 'jwst,F356W', 'jwst,F360M', 'jwst,F405N', 'jwst,F410M', 'jwst,F430M', 'jwst,F444W', 'jwst,F460M', 'jwst,F466N', 'jwst,F470N', 'jwst,F480M', 'nirc2,J', 'nirc2,H', 'nirc2,Kp', 'nirc2,K', 'nirc2,Lp', 'nirc2,Hcont', 'nirc2,FeII', 'nirc2,Brgamma', 'jg,J', 'jg,H', 'jg,K', 'nirc1,K', 'nirc1_H', 'ctio_osiris,K', 'ctio_osiris,H', 'naco,H', 'naco,Ks', 'ztf,g', 'ztf,r', 'ztf,i' ] elif filt == 'decam': filt_list = [ 'decam,y', 'decam,i', 'decam,z', 'decam,u', 'decam,g', 'decam,r' ] elif filt == 'vista': filt_list = ['vista,Y', 'vista,Z', 'vista,J', 'vista,H', 'vista,Ks'] elif filt == 'ps1': filt_list = ['ps1,z', 'ps1,g', 'ps1,r', 'ps1,i', 'ps1,y'] elif filt == 'jwst': filt_list = [ 'jwst,F070W', 'jwst,F090W', 'jwst,F115W', 'jwst,F140M', 'jwst,F150W', 'jwst,F150W2', 'jwst,F162M', 'jwst,F164N', 'jwst,F182M', 'jwst,F187N', 'jwst,F200W', 'jwst,F212N', 'jwst,F210M', 'jwst,F250M', 'jwst,F277W', 'jwst,F300M', 'jwst,F322W2', 'jwst,F323N', 'jwst,F335M', 'jwst,F356W', 'jwst,F360M', 'jwst,F405N', 'jwst,F410M', 'jwst,F430M', 'jwst,F444W', 'jwst,F460M', 'jwst,F466N', 'jwst,F470N', 'jwst,F480M' ] elif filt == 'hst': filt_list = [ 'wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m', 'acs,wfc1,f814w', 'wfc3,ir,f125w', 'wfc3,ir,f160w' ] elif filt == 'nirc2': filt_list = [ 'nirc2,J', 'nirc2,H', 'nirc2,Kp', 'nirc2,K', 'nirc2,Lp', 'nirc2,Ms', 'nirc2,Hcont', 'nirc2,FeII', 'nirc2,Brgamma' ] elif filt == 'jg': filt_list = ['jg,J', 'jg,H', 'jg,K'] elif filt == 'ztf': filt_list = ['ztf,g', 'ztf,r', 'ztf,i'] elif filt == 'misc': filt_list = [ 'nirc1,K', 'nirc1,H', 'ctio_osiris,K', 'ctio_osiris,H', 'naco,H', 'naco,Ks' ] print('Making isochrone') iso = synthetic.IsochronePhot(6.7, 0, 1000, mass_sampling=10, filters=filt_list, rebin=True) iso = iso.points # First find masses that are the same foo = [] for ii in iso['mass']: tmp = np.where(orig['mass'] == ii)[0][0] foo.append(tmp) assert len(foo) == len(iso) orig = orig[foo] # Identify the photometry columns cols = list(iso.keys()) idx = [] for ii in range(len(cols)): if cols[ii].startswith('mag'): idx.append(ii) mag_cols = np.array(cols)[idx] # Test the consistency of each column with the original isochrone for ii in mag_cols: orig_mag = orig[ii] new_mag = iso[ii] np.testing.assert_allclose(orig_mag, new_mag, rtol=0.01, err_msg="{0} failed".format(ii)) # Also report median abs difference diff = abs(orig_mag - new_mag) print(('{0} median abs diff: {1}'.format(ii, np.median(diff)))) print(('Phot consistency test successful for {0}'.format(filt))) # Remove iso file we just wrote, since it was only a test os.remove('iso_6.70_0.00_01000.fits') return
def time_test_mass_match(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar.imf import imf from popstar.imf import multiplicity log_age = 6.7 AKs = 2.7 distance = 4000 cluster_mass = 5e3 imf_in = imf.Kroupa_2001(multiplicity=None) start_time = time.time() iso = syn.IsochronePhot(log_age, AKs, distance) iso_masses = iso.points['mass'] print('Generated iso masses in {0:.0f} s'.format(time.time() - start_time)) start_time = time.time() star_masses, isMulti, compMass, sysMass = imf_in.generate_cluster( cluster_mass) print('Generated cluster masses in {0:.0f} s'.format(time.time() - start_time)) def match_model_masses1(isoMasses, starMasses): indices = np.empty(len(starMasses), dtype=int) for ii in range(len(starMasses)): theMass = starMasses[ii] dm = np.abs(isoMasses - theMass) mdx = dm.argmin() # Model mass has to be within 10% of the desired mass if (dm[mdx] / theMass) > 0.1: indices[ii] = -1 else: indices[ii] = mdx return indices def match_model_masses2(isoMasses, starMasses): isoMasses_tmp = isoMasses.reshape((len(isoMasses), 1)) kdt = KDTree(isoMasses_tmp) starMasses_tmp = starMasses.reshape((len(starMasses), 1)) q_results = kdt.query(starMasses_tmp, k=1) indices = q_results[1] dm_frac = np.abs(starMasses - isoMasses[indices]) / starMasses idx = np.where(dm_frac > 0.1)[0] indices[idx] = -1 return indices print('Test #1 START') start_time = time.time() idx1 = match_model_masses1(iso_masses, star_masses) stop_time = time.time() print('Test #1 STOPPED after {0:.0f} seconds'.format(stop_time - start_time)) print('Test #2 START') start_time = time.time() idx2 = match_model_masses2(iso_masses, star_masses) stop_time = time.time() print('Test #2 STOPPED after {0:.0f} seconds'.format(stop_time - start_time)) return
def test_ifmr_multiplicity(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar import reddening from popstar import ifmr from popstar.imf import imf from popstar.imf import multiplicity # Define cluster parameters logAge = 9.7 AKs = 0.0 distance = 1000 cluster_mass = 1e6 mass_sampling = 5 # Test all filters filt_list = ['nirc2,Kp', 'nirc2,H', 'nirc2,J'] startTime = time.time() evo = evolution.MISTv1() atm_func = atm.get_merged_atmosphere ifmr_obj = ifmr.IFMR() red_law = reddening.RedLawNishiyama09() iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=mass_sampling) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) # Now to create the cluster. imf_mass_limits = np.array([0.07, 0.5, 1, np.inf]) imf_powers = np.array([-1.3, -2.3, -2.3]) ########## # Start without multiplicity and IFMR ########## my_imf1 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=None) print('Constructed IMF: %d seconds' % (time.time() - startTime)) cluster1 = syn.ResolvedCluster(iso, my_imf1, cluster_mass, ifmr=ifmr_obj) clust1 = cluster1.star_systems print('Constructed cluster: %d seconds' % (time.time() - startTime)) ########## # Test with multiplicity and IFMR ########## multi = multiplicity.MultiplicityUnresolved() my_imf2 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=multi) print('Constructed IMF with multiples: %d seconds' % (time.time() - startTime)) cluster2 = syn.ResolvedCluster(iso, my_imf2, cluster_mass, ifmr=ifmr_obj) clust2 = cluster2.star_systems comps2 = cluster2.companions print('Constructed cluster with multiples: %d seconds' % (time.time() - startTime)) ########## # Tests ########## # Check that we have black holes, neutron stars, and white dwarfs in both. assert len(np.where(clust1['phase'] == 101)) > 0 # WD assert len(np.where(clust2['phase'] == 101)) > 0 assert len(np.where(clust1['phase'] == 102)) > 0 # NS assert len(np.where(clust2['phase'] == 102)) > 0 assert len(np.where(clust1['phase'] == 103)) > 0 # BH assert len(np.where(clust2['phase'] == 103)) > 0 # Now check that we have companions that are WDs, NSs, and BHs assert len(np.where(comps2['phase'] == 101)) > 0 assert len(np.where(comps2['phase'] == 102)) > 0 assert len(np.where(comps2['phase'] == 103)) > 0 # Make sure no funky phase designations (due to interpolation effects) # slipped through idx = np.where((clust1['phase'] > 5) & (clust1['phase'] < 101) & (clust1['phase'] != 9)) idx2 = np.where((comps2['phase'] > 5) & (comps2['phase'] < 101) & (comps2['phase'] != 9)) assert len(idx[0]) == 0 return
def test_iso_wave(): """ Test to make sure isochrones generated have spectra with the proper wavelength range, and that the user has control over that wavelength range (propagated through IsochronePhot) """ # Define isochrone parameters logAge = np.log10(5 * 10**6.) # Age in log(years) AKs = 0.8 # extinction in mags dist = 4000 # distance in parsec # Define evolution/atmosphere models and extinction law (optional) evo_model = evolution.MergedBaraffePisaEkstromParsec() atm_func = atmospheres.get_merged_atmosphere red_law = reddening.RedLawHosek18b() # Also specify filters for synthetic photometry (optional). Here we use # the HST WFC3-IR F127M, F139M, and F153M filters filt_list = ['wfc3,ir,f127m'] # First, let's make sure the vega spectrum has the proper limits vega = synthetic.Vega() assert np.min(vega.wave) == 995 assert np.max(vega.wave) == 100200 # Make Isochrone object. Will use wave_range = [3000,52000]. # Make sure range matches to resolution of atmosphere. wave_range1 = [3000, 52000] my_iso = synthetic.IsochronePhot(logAge, AKs, dist, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=10, wave_range=wave_range1, recomp=True) test = my_iso.spec_list[0] assert np.min(test.wave) == 3010 assert np.max(test.wave) == 51900 # Now let's try changing the wave range. Is it carried through # properly? wave_range2 = [1200, 90000] my_iso = synthetic.IsochronePhot(logAge, AKs, dist, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=10, wave_range=wave_range2, recomp=True) test2 = my_iso.spec_list[0] assert np.min(test2.wave) == 1205 assert np.max(test2.wave) == 89800 # Does the error exception catch the bad wave_range? wave_range3 = [1200, 1000000] try: my_iso = synthetic.IsochronePhot(logAge, AKs, dist, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=10, wave_range=wave_range3, recomp=True) print( 'WAVE TEST FAILED!!! Should have crashed here, wavelength range out of bounds' ) pdb.set_trace() except: print('Wavelength out of bound condition passed. Test is good') pass return
def test_cluster_mass(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar import reddening from popstar import ifmr from popstar.imf import imf from popstar.imf import multiplicity # Define cluster parameters logAge = 6.7 AKs = 2.4 distance = 4000 cluster_mass = 10**5. mass_sampling = 5 # Test filters filt_list = ['nirc2,J', 'nirc2,Kp'] startTime = time.time() # Define evolution/atmosphere models and extinction law evo = evolution.MISTv1() atm_func = atmospheres.get_merged_atmosphere red_law = reddening.RedLawHosek18b() iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=mass_sampling) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) # Now to create the cluster. imf_mass_limits = np.array([0.2, 0.5, 1, 120.0]) imf_powers = np.array([-1.3, -2.3, -2.3]) # IFMR my_ifmr = ifmr.IFMR() ########## # Start without multiplicity ########## my_imf1 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=None) print('Constructed IMF: %d seconds' % (time.time() - startTime)) cluster1 = syn.ResolvedCluster(iso, my_imf1, cluster_mass, ifmr=my_ifmr) clust1 = cluster1.star_systems print('Constructed cluster: %d seconds' % (time.time() - startTime)) # Check that the total mass is within tolerance of input mass cluster_mass_out = clust1['systemMass'].sum() assert np.abs(cluster_mass_out - cluster_mass) < 200.0 # within 200 Msun of desired mass. print('Cluster Mass: IN = ', cluster_mass, " OUT = ", cluster_mass_out) ########## # Test with multiplicity ########## multi = multiplicity.MultiplicityUnresolved() my_imf2 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=multi) print('Constructed IMF with multiples: %d seconds' % (time.time() - startTime)) cluster2 = syn.ResolvedCluster(iso, my_imf2, cluster_mass, ifmr=my_ifmr) clust2 = cluster2.star_systems print('Constructed cluster with multiples: %d seconds' % (time.time() - startTime)) # Check that the total mass is within tolerance of input mass cluster_mass_out = clust2['systemMass'].sum() assert np.abs(cluster_mass_out - cluster_mass) < 200.0 # within 200 Msun of desired mass. print('Cluster Mass: IN = ', cluster_mass, " OUT = ", cluster_mass_out) return
def test_IsochronePhot(plot=False): from popstar import synthetic as syn from popstar import evolution, atmospheres, reddening logAge = 6.7 AKs = 2.7 distance = 4000 filt_list = ['wfc3,ir,f127m', 'nirc2,J'] mass_sampling = 1 iso_dir = 'iso/' evo_model = evolution.MISTv1() atm_func = atmospheres.get_merged_atmosphere redlaw = reddening.RedLawNishiyama09() startTime = time.time() iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo_model, atm_func=atm_func, red_law=redlaw, filters=filt_list, mass_sampling=mass_sampling, iso_dir=iso_dir) endTime = time.time() print('IsochronePhot generated in: %d seconds' % (endTime - startTime)) # Typically takes 120 seconds if file is regenerated. # Limited by pysynphot.Icat call in atmospheres.py assert iso.points.meta['LOGAGE'] == logAge assert iso.points.meta['AKS'] == AKs assert iso.points.meta['DISTANCE'] == distance assert len(iso.points) > 100 assert 'm_nirc2_J' in iso.points.colnames if plot: plt.figure(1) iso.plot_CMD('mag814w', 'mag160w') plt.figure(2) iso.plot_mass_magnitude('mag160w') # Finally, let's test the isochronePhot file generation assert os.path.exists('{0}/iso_{1:.2f}_{2:4.2f}_{3:4s}_p00.fits'.format( iso_dir, logAge, AKs, str(distance).zfill(5))) # Check 1: If we try to remake the isochrone, does it read the file rather than # making a new one iso_new = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo_model, atm_func=atm_func, red_law=redlaw, filters=filt_list, mass_sampling=mass_sampling, iso_dir=iso_dir) assert iso_new.recalc == False # Check 2: If we change evo model, atmo model, or redlaw, # does IsochronePhot regenerate the isochrone and overwrite the existing one? evo2 = evolution.MergedBaraffePisaEkstromParsec() mass_sampling = 20 iso_new = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo2, atm_func=atm_func, red_law=redlaw, filters=filt_list, mass_sampling=mass_sampling, iso_dir=iso_dir) assert iso_new.recalc == True redlaw2 = reddening.RedLawHosek18b() iso_new = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo2, atm_func=atm_func, red_law=redlaw2, filters=filt_list, mass_sampling=mass_sampling, iso_dir=iso_dir) assert iso_new.recalc == True atm2 = atmospheres.get_castelli_atmosphere iso_new = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo2, atm_func=atm2, red_law=redlaw2, filters=filt_list, mass_sampling=mass_sampling, iso_dir=iso_dir) assert iso_new.recalc == True return
def test_ResolvedCluster(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar import reddening from popstar.imf import imf from popstar.imf import multiplicity # Define cluster parameters logAge = 6.7 AKs = 2.4 distance = 4000 cluster_mass = 10**5. mass_sampling=5 # Test all filters filt_list = ['wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m', 'acs,wfc1,f814w', 'wfc3,ir,f125w', 'wfc3,ir,f160w', 'decam,y', 'decam,i', 'decam,z', 'decam,u', 'decam,g', 'decam,r', 'vista,Y', 'vista,Z', 'vista,J', 'vista,H', 'vista,Ks', 'ps1,z', 'ps1,g', 'ps1,r', 'ps1,i', 'ps1,y', 'jwst,F090W', 'jwst,F164N', 'jwst,F212N', 'jwst,F323N', 'jwst,F466N', 'nirc2,J', 'nirc2,H', 'nirc2,Kp', 'nirc2,K', 'nirc2,Lp', 'nirc2,Ms', 'nirc2,Hcont', 'nirc2,FeII', 'nirc2,Brgamma', 'jg,J', 'jg,H', 'jg,K'] startTime = time.time() evo = evolution.MergedBaraffePisaEkstromParsec() atm_func = atm.get_merged_atmosphere red_law = reddening.RedLawNishiyama09() iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=mass_sampling) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) # Now to create the cluster. imf_mass_limits = np.array([0.07, 0.5, 1, np.inf]) imf_powers = np.array([-1.3, -2.3, -2.3]) ########## # Start without multiplicity ########## my_imf1 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=None) print('Constructed IMF: %d seconds' % (time.time() - startTime)) cluster1 = syn.ResolvedCluster(iso, my_imf1, cluster_mass) clust1 = cluster1.star_systems print('Constructed cluster: %d seconds' % (time.time() - startTime)) plt.figure(3) plt.clf() plt.plot(clust1['m_nirc2_J'] - clust1['m_nirc2_Kp'], clust1['m_nirc2_J'], 'r.') plt.plot(iso.points['m_nirc2_J'] - iso.points['m_nirc2_Kp'], iso.points['m_nirc2_J'], 'c.') plt.gca().invert_yaxis() # *** Visual Inspections: *** # - check that points (red) fall between isochrone points (blue) ########## # Test with multiplicity ########## multi = multiplicity.MultiplicityUnresolved() my_imf2 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=multi) print('Constructed IMF with multiples: %d seconds' % (time.time() - startTime)) cluster2 = syn.ResolvedCluster(iso, my_imf2, cluster_mass) clust2 = cluster2.star_systems print('Constructed cluster with multiples: %d seconds' % (time.time() - startTime)) ########## # Plots ########## # Plot an IR CMD and compare cluster members to isochrone. plt.figure(1) plt.clf() plt.plot(clust1['m_nirc2_J'] - clust1['m_nirc2_Kp'], clust1['m_nirc2_J'], 'r.') plt.plot(clust2['m_nirc2_J'] - clust2['m_nirc2_Kp'], clust2['m_nirc2_J'], 'b.') plt.plot(iso.points['m_nirc2_J'] - iso.points['m_nirc2_Kp'], iso.points['m_nirc2_J'], 'c-') plt.gca().invert_yaxis() plt.xlabel('J - Kp (mag)') plt.ylabel('J (mag') # Plot a mass-magnitude relationship. plt.figure(2) plt.clf() plt.semilogx(clust1['mass'], clust1['m_nirc2_J'], 'r.') plt.semilogx(clust2['mass'], clust2['m_nirc2_J'], 'r.') plt.gca().invert_yaxis() plt.xlabel('Mass (Msun)') plt.ylabel('J (mag)') # # Plot the spectrum of the most massive star # idx = cluster.mass.argmax() # plt.clf() # plt.plot(cluster.stars[idx].wave, cluster.stars[idx].flux, 'k.') # # Plot an integrated spectrum of the whole cluster. # wave, flux = cluster.get_integrated_spectrum() # plt.clf() # plt.plot(wave, flux, 'k.') return
def likelihood(cube, ndim, nparams): ########## # Priors (I think order matters) ########## parName = [ 'distance', 'LogAge', 'AKs', 'dAKs', 'alpha1', 'alpha2', 'mbreak', 'Mcl' ] par, par_prior_logp = get_prior_info(cube, parName) sysMass = np.zeros(len(t)) ########## # Load up the model cluster. ########## imf_mass_limits = np.array([imf_mmin, par['mbreak'], imf_mmax]) imf_powers = np.array([par['alpha2'], par['alpha1']]) imf_multi = None new_imf = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, imf_multi) print 'Getting Isochrone' new_iso = synthetic.IsochronePhot(par['LogAge'], par['AKs'], par['distance'], evo_model=evo_model, atm_func=atm_func, red_law=red_law) print 'Getting Cluster' cluster = synthetic.ResolvedClusterDiffRedden(new_iso, new_imf, Mcl_sim, par['dAKs'], red_law=red_law) # Convert simulated cluster into agnitude-color-color histogram mag = cluster.star_systems['mag160w'] col1 = cluster.star_systems['mag814w'] - mag col2 = cluster.star_systems['mag125w'] - mag data = np.array([mag, col1, col2]).T bins = np.array([bins_mag, bins_col1, bins_col2]) H_sim_c, edges = np.histogramdd(data, bins=bins, normed=True) H_sim = H_sim_c * completeness_map # Convert Observed cluster into magnitude-color-color histogram mag = t['m_2010_F160W'] col1 = t['m_2005_F814W'] - t['m_2010_F160W'] col2 = t['m_2010_F125W'] - t['m_2010_F160W'] data = np.array([mag, col1, col2]).T bins = np.array([bins_mag, bins_col1, bins_col2]) H_obs, edges = np.histogramdd(data, bins=bins) # Plotting extent = (bins_col1[0], bins_col2[-1], bins_mag[0], bins_mag[-1]) py.figure(1) py.clf() py.imshow(H_sim_c.sum(axis=2), extent=extent) py.gca().invert_yaxis() py.colorbar() py.axis('tight') py.title('Sim Complete') py.figure(2) py.clf() py.imshow(H_sim.sum(axis=2), extent=extent) py.gca().invert_yaxis() py.colorbar() py.axis('tight') py.title('Sim Incomplete') py.figure(3) py.clf() py.imshow(H_obs.sum(axis=2), extent=extent) py.gca().invert_yaxis() py.colorbar() py.axis('tight') py.title('Obs Incomplete') py.figure(4) py.clf() py.imshow(completeness_map.mean(axis=2), extent=extent, vmin=0, vmax=1) py.gca().invert_yaxis() py.colorbar() py.axis('tight') py.title('Completeness Map') pdb.set_trace() mcc_cluster = 1 print likei.sum() return likei.sum()
import numpy as np import pandas as pd from astropy.io import ascii from astropy.io import fits import matplotlib.pyplot as plt from popstar import synthetic, evolution, atmospheres, reddening, ifmr from popstar.imf import imf, multiplicity # Define isochrone parameters logAge = 9.6 # Age in log(years) AKs = 0 # extinction in mags dist = 1000 # distance in parsec metallicities = [-1] # Metallicity in [M/H] # Define evolution/atmosphere models and extinction law evo_model = evolution.MISTv1() atm_func = atmospheres.get_merged_atmosphere red_law = reddening.RedLawHosek18b() # Also specify filters for synthetic photometry (optional). Here we use # the HST WFC3-IR F127M, F139M, and F153M filters filt_list = ['wfc3,ir,f127m', 'wfc3,ir,f139m', 'wfc3,ir,f153m'] # Make Isochrone object. Note that is calculation will take a few minutes, unless the # isochrone has been generated previously. for metallicity in metallicities: my_iso = synthetic.IsochronePhot(logAge, AKs, dist, metallicity=metallicity, evo_model=evo_model, atm_func=atm_func, red_law=red_law, filters=filt_list) print(my_iso.save_file)
def test_ResolvedClusterDiffRedden(): from popstar import synthetic as syn from popstar import atmospheres as atm from popstar import evolution from popstar import reddening from popstar.imf import imf from popstar.imf import multiplicity logAge = 6.7 AKs = 2.4 distance = 4000 cluster_mass = 10**5. deltaAKs = 0.05 mass_sampling = 5 # Test filters filt_list = ['nirc2,J', 'nirc2,Kp'] startTime = time.time() evo = evolution.MergedBaraffePisaEkstromParsec() atm_func = atm.get_merged_atmosphere red_law = reddening.RedLawNishiyama09() iso = syn.IsochronePhot(logAge, AKs, distance, evo_model=evo, atm_func=atm_func, red_law=red_law, filters=filt_list, mass_sampling=mass_sampling) print('Constructed isochrone: %d seconds' % (time.time() - startTime)) imf_mass_limits = np.array([0.07, 0.5, 1, np.inf]) imf_powers = np.array([-1.3, -2.3, -2.3]) ########## # Start without multiplicity ########## my_imf1 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=None) print('Constructed IMF: %d seconds' % (time.time() - startTime)) cluster1 = syn.ResolvedClusterDiffRedden(iso, my_imf1, cluster_mass, deltaAKs) clust1 = cluster1.star_systems print('Constructed cluster: %d seconds' % (time.time() - startTime)) assert len(clust1) > 0 plt.figure(3) plt.clf() plt.plot(clust1['m_nirc2_J'] - clust1['m_nirc2_Kp'], clust1['m_nirc2_J'], 'r.') plt.plot(iso.points['m_nirc2_J'] - iso.points['m_nirc2_Kp'], iso.points['m_nirc2_J'], 'c.') plt.gca().invert_yaxis() # *** Visual Inspections: *** # - check that points (red) fall between isochrone points (blue) ########## # Test with multiplicity ########## multi = multiplicity.MultiplicityUnresolved() my_imf2 = imf.IMF_broken_powerlaw(imf_mass_limits, imf_powers, multiplicity=multi) print('Constructed IMF with multiples: %d seconds' % (time.time() - startTime)) cluster2 = syn.ResolvedClusterDiffRedden(iso, my_imf2, cluster_mass, deltaAKs) clust2 = cluster2.star_systems print('Constructed cluster with multiples: %d seconds' % (time.time() - startTime)) assert len(clust2) > 0 assert len(cluster2.companions) > 0 assert np.sum(clust2['N_companions']) == len(cluster2.companions) ########## # Plots ########## # Plot an IR CMD and compare cluster members to isochrone. plt.figure(1) plt.clf() plt.plot(clust1['m_nirc2_J'] - clust1['m_nirc2_Kp'], clust1['m_nirc2_J'], 'r.') plt.plot(clust2['m_nirc2_J'] - clust2['m_nirc2_Kp'], clust2['m_nirc2_J'], 'b.') plt.plot(iso.points['m_nirc2_J'] - iso.points['m_nirc2_Kp'], iso.points['m_nirc2_J'], 'c-') plt.gca().invert_yaxis() plt.xlabel('J - Kp (mag)') plt.ylabel('J (mag') # Plot a mass-magnitude relationship. plt.figure(2) plt.clf() plt.semilogx(clust1['mass'], clust1['m_nirc2_J'], 'r.') plt.semilogx(clust2['mass'], clust2['m_nirc2_J'], 'r.') plt.gca().invert_yaxis() plt.xlabel('Mass (Msun)') plt.ylabel('J (mag)') return
def __init__(self, age=3.9e6, ext=2.63, dist=7.971e3, met=0.0, phase=None, use_atm_func='merged'): log_age = np.log10(age) self.log_age = log_age self.A_Ks = ext self.dist = dist self.met = met # Evolution/Atmosphere Models evo_model = evolution.MISTv1() if use_atm_func == 'merged': atm_func = atmospheres.get_merged_atmosphere elif use_atm_func == 'castelli': atm_fun = atmospheres.get_castelli_atmosphere elif use_atm_func == 'phoenix': atm_func = atmospheres.get_phoenixv16_atmosphere # Extinction law red_law = reddening.RedLawNoguerasLara18() self.ext_alpha = 2.30 ## Calculate extinctions implied by isochrone extinction self.A_Lp = self.A_Ks * (lambda_Ks / lambda_Lp)**self.ext_alpha self.A_Kp = self.A_Ks * (lambda_Ks / lambda_Kp)**self.ext_alpha self.A_H = self.A_Ks * (lambda_Ks / lambda_H)**self.ext_alpha # Create an isochrone with the given parameters self.iso_curAge = synthetic.IsochronePhot(self.log_age, self.A_Ks, self.dist, evo_model=evo_model, atm_func=atm_func, red_law=red_law, metallicity=self.met, filters=self.filt_list) ## Create another isochrone for absolute mags / passband luminosities self.iso_absMag = synthetic.IsochronePhot(self.log_age, 0.0, 10.0, evo_model=evo_model, atm_func=atm_func, red_law=red_law, metallicity=self.met, filters=self.filt_list) # Save out specific stellar parameter columns needed ## If needing specific phase, draw it out before saving if phase is not None: phase_check = np.where( self.iso_curAge.points['phase'] == mist_phase_dict[phase]) else: phase_check = np.where(self.iso_curAge.points['phase'] >= -1) self.iso_mass_init = (self.iso_curAge.points['mass'][phase_check]).to( u.solMass) self.iso_mass = self.iso_curAge.points['mass_current'][phase_check] self.iso_rad = (self.iso_curAge.points['R'][phase_check]).to(u.solRad) self.iso_lum = self.iso_curAge.points['L'][phase_check] self.iso_teff = self.iso_curAge.points['Teff'][phase_check] self.iso_logg = self.iso_curAge.points['logg'][phase_check] self.iso_mag_Lp = self.iso_curAge.points['m_nirc2_Lp'][phase_check] self.iso_mag_Kp = self.iso_curAge.points['m_nirc2_Kp'][phase_check] self.iso_mag_H = self.iso_curAge.points['m_nirc2_H'][phase_check] ## Stellar parameters from the absolute magnitude isochrones self.iso_absMag_mass_init = self.iso_absMag.points['mass'][phase_check] self.iso_absMag_mass = self.iso_absMag.points['mass_current'][ phase_check] self.iso_absMag_rad = (self.iso_absMag.points['R'][phase_check]).to( u.solRad) self.iso_absMag_Lp = self.iso_absMag.points['m_nirc2_Lp'][phase_check] self.iso_absMag_Kp = self.iso_absMag.points['m_nirc2_Kp'][phase_check] self.iso_absMag_H = self.iso_absMag.points['m_nirc2_H'][phase_check] ## Maximum bounds on the radius in isochrone self.iso_rad_min = np.min(self.iso_rad).value self.iso_rad_max = np.max(self.iso_rad).value ## Maximum bounds on the initial mass in isochrone self.iso_mass_init_min = np.min(self.iso_mass_init).value self.iso_mass_init_max = np.max(self.iso_mass_init).value