def plot_bestFit_Spectrum(spec, clr, specs, atmfile, filters, kurucz, tepfile, outflux, data, uncert, direct): ''' Plot Transit spectrum ''' # get star data R_star, T_star, sma, gstar = bf.get_starData(tepfile) # get surface gravity grav, Rp = mat.get_g(tepfile) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp / R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) # read best-fit spectrum output file, take wn and spectra values (head, tail) = os.path.split(outflux) specwn, bestspectrum = rt.readspectrum(direct + '/' + tail, wn=True) # convert wn to wl specwl = 1e4 / specwn # number of filters nfilters = len(filters) # read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation meanwn = [] # Filter mean wavenumber for i in np.arange(nfilters): # read filter: filtwaven, filttransm = w.readfilter(filters[i]) meanwn.append(np.sum(filtwaven * filttransm) / sum(filttransm)) # resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # convert mean wn to mean wl meanwl = 1e4 / np.asarray(meanwn) # band-integrate the flux-ratio or modulation: bandflux = np.zeros(nfilters, dtype='d') bandmod = np.zeros(nfilters, dtype='d') for i in np.arange(nfilters): fluxrat = (bestspectrum[wnindices[i]] / istarfl[i]) * rprs * rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) bandmod[i] = w.bandintegrate(bestspectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # stellar spectrum on specwn: sinterp = si.interp1d(starwn, starfl) sflux = sinterp(specwn) frat = bestspectrum / sflux * rprs * rprs ###################### plot figure ############################# plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default': 'rm'}) #matplotlib.rcParams.update({'fontsize': 10,}) matplotlib.rcParams.update({ 'axes.labelsize': 16, #'text.fontsize': 10, 'legend.fontsize': 14, 'xtick.labelsize': 20, 'ytick.labelsize': 20, }) plt.figure(2, (8.5, 5)) plt.clf() #plt.xlim(0.60, 5.5) #plt.xlim(min(specwl),max(specwl)) # plot eclipse spectrum #gfrat = gaussf(frat, 0) plt.semilogx(specwl, frat * 1e3, clr, lw=1.5, label="Spectrum", linewidth=4) #cornflowerblue, lightskyblue #plt.errorbar(meanwl, data*1e3, uncert*1e3, fmt="ko", label="Data", alpha=0.7) plt.errorbar(meanwl, data * 1e3, uncert * 1e3, fmt=".", color='k', zorder=100, capsize=2, capthick=1, label="Data", alpha=0.7) #plt.plot(meanwl, bandflux*1e3, "ko", label="model") plt.ylabel(r"$F_p/F_s$ (10$^{-3}$)", fontsize=24) leg = plt.legend(loc="upper left") #leg.draw_frame(False) leg.get_frame().set_alpha(0.5) ax = plt.subplot(111) ax.set_xscale('log') ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter()) ax.set_xticks([0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0]) ax.set_xticklabels(["0.7", "", "", "1.0", "2.0", "3.0", "4.0", "5.0"]) plt.xlabel(r"${\rm Wavelength\ \ (um)}$", fontsize=24) nfilters = len(filters) # plot filter bandpasses for i in np.arange(nfilters - 15): (head, tail) = os.path.split(filters[i]) lbl = tail[:-4] # read filter: wn, respons = w.readfilter(filters[i]) respons = respons / 3 - 0.4 wl = 10000.0 / wn #plt.plot(wl, respons, color='crimson', linewidth =1) if lbl == 'spitzer_irac1_sa' or lbl == 'spitzer_irac2_sa': respons = respons * 2 + 0.4 plt.plot(wl, respons, color='grey', linewidth=1, alpha=0.5) #plt.plot(wl, respons*2, color='orangered', linewidth =1) elif lbl == 'Wang-Hband' or lbl == 'Wang-Kband': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) elif lbl == 'VLT_1190' or lbl == 'VLT_2090': plt.plot(wl, respons, color='grey', linewidth=2, alpha=0.5) #plt.plot(wl, respons, color='firebrick', linewidth =2) elif lbl == 'GROND_K_JB' or lbl == 'GROND_i_JB': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) elif lbl == 'Zhou_Ks': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) plt.ylim(-0.4, 7) plt.text(1.9, 3, specs, color=clr, fontsize=26) ###################### INSET PT and ABUN FIGURE #################### b = plt.axes([.21, .45, .14, .24]) # read atmfile molecules, pres, temp, abundances = mat.readatm(atmfile) plt.semilogy(temp, pres, color='r', linewidth=3) plt.xlim(1000, 2200) plt.ylim(max(pres), min(pres)) b.minorticks_off() yticks = [1e2, 1e1, 1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5] ylabels = [ "10$^{2}$", "", "10$^{0}$", "", "10$^{-2}$", "", "10$^{-4}$", "" ] plt.yticks(yticks, ylabels, fontsize=8) xticks = [1000, 1200, 1400, 1600, 1800, 2000, 2200] xlabels = ["", "1200", "", "", "1800", ""] plt.xticks(xticks, xlabels, fontsize=12) plt.xlabel('T (K)', fontsize=12) plt.ylabel('P (bar)', fontsize=12) # ############################## SECOND INSET ABUN c = plt.axes([.35, .45, .14, .24]) # Sets the second argument given as the species names species = spec # Open the atmospheric file and read f = open(atmfile, 'r') lines = np.asarray(f.readlines()) f.close() # Get molecules names imol = np.where(lines == "#SPECIES\n")[0][0] + 1 molecules = lines[imol].split() nmol = len(molecules) for m in np.arange(nmol): molecules[m] = molecules[m].partition('_')[0] nspec = 1 # Populate column numbers for requested species and # update list of species if order is not appropriate columns = [] spec = [] for i in np.arange(nmol): if molecules[i] == species: columns.append(i + 3) # defines p, T +2 or rad, p, T +3 spec.append(species) # Convert spec to tuple spec = tuple(spec) # Concatenate spec with pressure for data and columns data = tuple(np.concatenate((['p'], spec))) usecols = tuple(np.concatenate( ([1], columns))) # defines p as 0 columns, or p as 1 columns # Load all data for all interested species data = np.loadtxt(atmfile, dtype=float, comments='#', delimiter=None, \ converters=None, skiprows=13, usecols=usecols, unpack=True) plt.loglog(data[1], data[0], '-', color=clr, \ linewidth=3) plt.ylim(max(pres), min(pres)) c.minorticks_off() yticks = [1e2, 1e1, 1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5] ylabels = [] plt.yticks(yticks, ylabels) plt.xlim(1e-12, 1e-2) xticks = [1e-11, 1e-9, 1e-7, 1e-5, 1e-3] xlabels = ["10$^{-11}$", "", "10$^{-5}$", "", "10$^{-3}$"] plt.xticks(xticks, xlabels, fontsize=12) plt.xlabel('Mix. fraction', fontsize=12) plt.subplots_adjust(bottom=0.16) spec = spec[0] print(spec) plt.savefig(spec + "_transSpec_new.png") plt.savefig(spec + "_transSpec_new.ps")
def plot_bestFit_Spectrum(filters, kurucz, tepfile, solution, output, data, uncert, date_dir, fs=15): ''' Plot BART best-model spectrum Parameters ---------- filters : list, strings. Paths to filter files corresponding to data. kurucz : string. Path to Kurucz stellar model file. tepfile : string. Path to Transiting ExoPlanet (TEP) file. solution: string. Observing geometry. 'eclipse' or 'transit'. output : string. Best-fit spectrum output file name. data : 1D array. Eclipse or transit depths. uncert : 1D array. Uncertainties for data values. date_dir: string. Path to directory where the plot will be saved. fs : int. Font size for plots. ''' # get star data R_star, T_star, sma, gstar = get_starData(tepfile) # get surface gravity grav, Rp = mat.get_g(tepfile) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp / R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) # read best-fit spectrum output file, take wn and spectra values if solution == 'eclipse': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit eclipse spectrum figure.") elif solution == 'transit': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit modulation spectrum figure.") # convert wn to wl specwl = 1e4 / specwn # number of filters nfilters = len(filters) # read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation meanwn = [] # Filter mean wavenumber for i in np.arange(nfilters): # read filter: filtwaven, filttransm = w.readfilter(filters[i]) meanwn.append(np.sum(filtwaven * filttransm) / sum(filttransm)) # resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # convert mean wn to mean wl meanwl = 1e4 / np.asarray(meanwn) # band-integrate the flux-ratio or modulation: bandflux = np.zeros(nfilters, dtype='d') bandmod = np.zeros(nfilters, dtype='d') for i in np.arange(nfilters): fluxrat = (bestspectrum[wnindices[i]] / istarfl[i]) * rprs * rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) bandmod[i] = w.bandintegrate(bestspectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # stellar spectrum on specwn: sinterp = si.interp1d(starwn, starfl) sflux = sinterp(specwn) frat = bestspectrum / sflux * rprs * rprs # plot figure plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default': 'rm'}) matplotlib.rcParams.update({'font.size': fs - 2}) plt.figure(3, (8.5, 6)) plt.clf() # depending on solution plot eclipse or modulation spectrum if solution == 'eclipse': gfrat = gaussf(frat, 2) plt.semilogx(specwl, gfrat * 1e3, "b", lw=1.5, label="Best-fit") plt.errorbar(meanwl, data * 1e3, uncert * 1e3, fmt="or", label="data") plt.plot(meanwl, bandflux * 1e3, "ok", label="model", alpha=1.0) plt.ylabel(r"$F_p/F_s$ (10$^{-3}$)", fontsize=fs) elif solution == 'transit': gmodel = gaussf(bestspectrum, 2) plt.semilogx(specwl, gmodel, "b", lw=1.5, label="Best-fit") plt.errorbar(meanwl, data, uncert, fmt="or", label="data") plt.plot(meanwl, bandmod, "ok", label="model", alpha=0.5) plt.ylabel(r"$(R_p/R_s)^2$", fontsize=fs) leg = plt.legend(loc="best") leg.get_frame().set_alpha(0.5) ax = plt.subplot(111) ax.set_xscale('log') plt.xlabel("${\\rm Wavelength\ \ (\u03bcm)}$", fontsize=fs) #plt.xticks(size=fs) #plt.yticks(size=fs) formatter = matplotlib.ticker.FuncFormatter( lambda y, _: '{:.8g}'.format(y)) ax.get_xaxis().set_major_formatter(formatter) ax.get_xaxis().set_minor_formatter(formatter) plt.xlim(min(specwl), max(specwl)) plt.savefig(date_dir + "BART-bestFit-Spectrum.png") plt.close()
def main(comm): """ This is a hacked version of MC3's func.py. This function directly call's the modeling function for the BART project. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-06-25 patricio Added support for inner-MPI loop. """ # Parse arguments: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get parameters from configuration file: cfile = args.config_file if cfile: config = ConfigParser.SafeConfigParser() config.optionxform = str config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} parser = argparse.ArgumentParser(parents=[cparser]) parser.add_argument("--func", dest="func", type=mu.parray, action="store", default=None) parser.add_argument("--indparams", dest="indparams", type=mu.parray, action="store", default=[]) parser.add_argument("--params", dest="params", type=mu.parray, action="store", default=None, help="Model-fitting parameters [default: %(default)s]") parser.add_argument("--molfit", dest="molfit", type=mu.parray, action="store", default=None, help="Molecules fit [default: %(default)s]") parser.add_argument("--Tmin", dest="Tmin", type=float, action="store", default=400.0, help="Lower Temperature boundary [default: %(default)s]") parser.add_argument("--Tmax", dest="Tmax", type=float, action="store", default=3000.0, help="Higher Temperature boundary [default: %(default)s]") parser.add_argument("--quiet", action="store_true", help="Set verbosity level to minimum", dest="quiet") # Input-Converter Options: group = parser.add_argument_group("Input Converter Options") group.add_argument("--atmospheric_file", action="store", help="Atmospheric file [default: %(default)s]", dest="atmfile", type=str, default=None) group.add_argument("--PTtype", action="store", help="PT profile type.", dest="PTtype", type=str, default="none") #choices=('line', 'madhu')) group.add_argument("--tint", action="store", help="Internal temperature of the planet [default: " "%(default)s].", dest="tint", type=float, default=100.0) # transit Options: group = parser.add_argument_group("transit Options") group.add_argument("--config", action="store", help="transit configuration file [default: %(default)s]", dest="config", type=str, default=None) # Output-Converter Options: group = parser.add_argument_group("Output Converter Options") group.add_argument("--filter", action="store", help="Waveband filter name [default: %(default)s]", dest="filter", type=mu.parray, default=None) group.add_argument("--tep_name", action="store", help="A TEP file [default: %(default)s]", dest="tep_name", type=str, default=None) group.add_argument("--kurucz_file", action="store", help="Stellar Kurucz file [default: %(default)s]", dest="kurucz", type=str, default=None) group.add_argument("--solution", action="store", help="Solution geometry [default: %(default)s]", dest="solution", type=str, default="None", choices=('transit', 'eclipse')) parser.set_defaults(**defaults) args2, unknown = parser.parse_known_args(remaining_argv) # Quiet all threads except rank 0: rank = comm.Get_rank() verb = rank == 0 # Get (Broadcast) the number of parameters and iterations from MPI: array1 = np.zeros(2, np.int) mu.comm_bcast(comm, array1) npars, niter = array1 # ::::::: Initialize the Input converter :::::::::::::::::::::::::: atmfile = args2.atmfile molfit = args2.molfit PTtype = args2.PTtype params = args2.params tepfile = args2.tep_name tint = args2.tint Tmin = args2.Tmin Tmax = args2.Tmax solution = args2.solution # Solution type # Extract necessary values from the TEP file: tep = rd.File(tepfile) # Stellar temperature in K: tstar = float(tep.getvalue('Ts')[0]) # Stellar radius (in meters): rstar = float(tep.getvalue('Rs')[0]) * c.Rsun # Semi-major axis (in meters): sma = float(tep.getvalue( 'a')[0]) * sc.au # Planetary radius (in meters): rplanet = float(tep.getvalue('Rp')[0]) * c.Rjup # Planetary mass (in kg): mplanet = float(tep.getvalue('Mp')[0]) * c.Mjup # Number of fitting parameters: nfree = len(params) # Total number of free parameters nmolfit = len(molfit) # Number of molecular free parameters nradfit = int(solution == 'transit') # 1 for transit, 0 for eclipse nPT = nfree - nmolfit - nradfit # Number of PT free parameters # Read atmospheric file to get data arrays: species, pressure, temp, abundances = mat.readatm(atmfile) # Reverse pressure order (for PT to work): pressure = pressure[::-1] nlayers = len(pressure) # Number of atmospheric layers nspecies = len(species) # Number of species in the atmosphere mu.msg(verb, "There are {:d} layers and {:d} species.".format(nlayers, nspecies)) # Find index for Hydrogen and Helium: species = np.asarray(species) iH2 = np.where(species=="H2")[0] iHe = np.where(species=="He")[0] # Get H2/He abundance ratio: ratio = (abundances[:,iH2] / abundances[:,iHe]).squeeze() # Find indices for the metals: imetals = np.where((species != "He") & (species != "H2"))[0] # Index of molecular abundances being modified: imol = np.zeros(nmolfit, dtype='i') for i in np.arange(nmolfit): imol[i] = np.where(np.asarray(species) == molfit[i])[0] # Pressure-Temperature profile: PTargs = [PTtype] if PTtype == "line": # Planetary surface gravity (in cm s-2): gplanet = 100.0 * sc.G * mplanet / rplanet**2 # Additional PT arguments: PTargs += [rstar, tstar, tint, sma, gplanet] # Allocate arrays for receiving and sending data to master: freepars = np.zeros(nfree, dtype='d') profiles = np.zeros((nspecies+1, nlayers), dtype='d') # This are sub-sections of profiles, containing just the temperature and # the abundance profiles, respectively: tprofile = profiles[0, :] aprofiles = profiles[1:,:] # Store abundance profiles: for i in np.arange(nspecies): aprofiles[i] = abundances[:, i] # ::::::: Spawn transit code ::::::::::::::::::::::::::::::::::::: # # transit configuration file: transitcfile = args2.tconfig # FINDME: Find a way to set verb to the transit subprocesses. # Silence all threads except rank 0: # if verb == 0: # rargs = ["--quiet"] # else: # rargs = [] # Initialize the transit python module: transit_args = ["transit", "-c", transitcfile] trm.transit_init(len(transit_args), transit_args) # Get wavenumber array from transit: nwave = trm.get_no_samples() specwn = trm.get_waveno_arr(nwave) # ::::::: Output Converter ::::::::::::::::::::::::::::::::::::::: ffile = args2.filter # Filter files kurucz = args2.kurucz # Kurucz file # Log10(stellar gravity) gstar = float(tep.getvalue('loggstar')[0]) # Planet-to-star radius ratio: rprs = rplanet / rstar mu.msg(verb, "OCON FLAG 10: {}, {}, {}".format(tstar, gstar, rprs)) nfilters = len(ffile) # Number of filters: # FINDME: Separate filter/stellar interpolation? # Get stellar model: starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, tstar, gstar) # Read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation for i in np.arange(nfilters): # Read filter: filtwaven, filttransm = w.readfilter(ffile[i]) # Check that filter boundaries lie within the spectrum wn range: if filtwaven[0] < specwn[0] or filtwaven[-1] > specwn[-1]: mu.exit(message="Wavenumber array ({:.2f} - {:.2f} cm-1) does not " "cover the filter[{:d}] wavenumber range ({:.2f} - {:.2f} " "cm-1).".format(specwn[0], specwn[-1], i, filtwaven[0], filtwaven[-1])) # Resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) mu.msg(verb, "OCON FLAG 67: mean star flux: %.3e"%np.mean(strfl)) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # Allocate arrays for receiving and sending data to master: spectrum = np.zeros(nwave, dtype='d') bandflux = np.zeros(nfilters, dtype='d') # Allocate array to receive parameters from MPI: params = np.zeros(npars, np.double) # :::::: Main MCMC Loop :::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: while niter >= 0: niter -= 1 # Receive parameters from MCMC: mu.comm_scatter(comm, params) #mu.msg(verb, "ICON FLAG 71: incon pars: {:s}". # format(str(params).replace("\n", ""))) # Input converter calculate the profiles: try: tprofile[:] = pt.PT_generator(pressure, params[0:nPT], PTargs)[::-1] except ValueError: mu.msg(verb, 'Input parameters give non-physical profile.') # FINDME: what to do here? # If the temperature goes out of bounds: if np.any(tprofile < Tmin) or np.any(tprofile > Tmax): print("Out of bounds") mu.comm_gather(comm, -np.ones(nfilters), MPI.DOUBLE) continue #mu.msg(verb, "T pars: \n{}\n".format(PTargs)) mu.msg(verb-20, "Temperature profile: {}".format(tprofile)) # Scale abundance profiles: for i in np.arange(nmolfit): m = imol[i] # Use variable as the log10: aprofiles[m] = abundances[:, m] * 10.0**params[nPT+nradfit+i] # Update H2, He abundances so sum(abundances) = 1.0 in each layer: q = 1.0 - np.sum(aprofiles[imetals], axis=0) aprofiles[iH2] = ratio * q / (1.0 + ratio) aprofiles[iHe] = q / (1.0 + ratio) # print("qH2O: {}, Qmetals: {}, QH2: {} p: {}".format(params[nPT], # q[50], profiles[iH2+1,50], profiles[:,50])) # Set the 'surface' level: if solution == "transit": trm.set_radius(params[nPT]) if rank == 1: print("Iteration: {:05}".format(niter)) # Let transit calculate the model spectrum: spectrum = trm.run_transit(profiles.flatten(), nwave) # Output converter band-integrate the spectrum: # Calculate the band-integrated intensity per filter: for i in np.arange(nfilters): if solution == "eclipse": fluxrat = (spectrum[wnindices[i]]/istarfl[i]) * rprs*rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) elif solution == "transit": bandflux[i] = w.bandintegrate(spectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # Send resutls back to MCMC: #mu.msg(verb, "OCON FLAG 95: Flux band integrated ({})".format(bandflux)) #mu.msg(verb, "{}".format(params[nPT:])) mu.comm_gather(comm, bandflux, MPI.DOUBLE) #mu.msg(verb, "OCON FLAG 97: Sent results back to MCMC") # :::::: End main Loop ::::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Close communications and disconnect: mu.comm_disconnect(comm) mu.msg(verb, "FUNC FLAG 99: func out") # Close the transit communicators: trm.free_memory() mu.msg(verb, "FUNC FLAG OUT ~~ 100 ~~")
def main(comm): """ This is a hacked version of MC3's func.py. This function directly call's the modeling function for the BART project. """ # Parse arguments: cparser = argparse.ArgumentParser( description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get parameters from configuration file: cfile = args.config_file if cfile: config = ConfigParser.SafeConfigParser() config.optionxform = str config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} parser = argparse.ArgumentParser(parents=[cparser]) parser.add_argument("--func", dest="func", type=mu.parray, action="store", default=None) parser.add_argument("--indparams", dest="indparams", type=mu.parray, action="store", default=[]) parser.add_argument("--params", dest="params", type=mu.parray, action="store", default=None, help="Model-fitting parameters [default: %(default)s]") parser.add_argument("--molfit", dest="molfit", type=mu.parray, action="store", default=None, help="Molecules fit [default: %(default)s]") parser.add_argument( "--Tmin", dest="Tmin", type=float, action="store", default=400.0, help="Lower Temperature boundary [default: %(default)s]") parser.add_argument( "--Tmax", dest="Tmax", type=float, action="store", default=3000.0, help="Higher Temperature boundary [default: %(default)s]") parser.add_argument("--quiet", action="store_true", help="Set verbosity level to minimum", dest="quiet") # Input-Converter Options: group = parser.add_argument_group("Input Converter Options") group.add_argument("--atmospheric_file", action="store", help="Atmospheric file [default: %(default)s]", dest="atmfile", type=str, default=None) group.add_argument("--PTtype", action="store", help="PT profile type.", dest="PTtype", type=str, default="none") group.add_argument("--tint", action="store", help="Internal temperature of the planet [default: " "%(default)s].", dest="tint", type=float, default=100.0) # transit Options: group = parser.add_argument_group("transit Options") group.add_argument( "--config", action="store", help="transit configuration file [default: %(default)s]", dest="config", type=str, default=None) # Output-Converter Options: group = parser.add_argument_group("Output Converter Options") group.add_argument("--filters", action="store", help="Waveband filter name [default: %(default)s]", dest="filters", type=mu.parray, default=None) group.add_argument("--tep_name", action="store", help="A TEP file [default: %(default)s]", dest="tep_name", type=str, default=None) group.add_argument("--kurucz_file", action="store", help="Stellar Kurucz file [default: %(default)s]", dest="kurucz", type=str, default=None) group.add_argument("--solution", action="store", help="Solution geometry [default: %(default)s]", dest="solution", type=str, default="None", choices=('transit', 'eclipse')) parser.set_defaults(**defaults) args2, unknown = parser.parse_known_args(remaining_argv) # Quiet all threads except rank 0: rank = comm.Get_rank() verb = rank == 0 # Get (Broadcast) the number of parameters and iterations from MPI: array1 = np.zeros(2, np.int) mu.comm_bcast(comm, array1) npars, niter = array1 # ::::::: Initialize the Input converter :::::::::::::::::::::::::: atmfile = args2.atmfile molfit = args2.molfit PTtype = args2.PTtype params = args2.params tepfile = args2.tep_name tint = args2.tint Tmin = args2.Tmin Tmax = args2.Tmax solution = args2.solution # Solution type # Dictionary of functions to calculate temperature for PTtype PTfunc = { 'iso': pt.PT_iso, 'line': pt.PT_line, 'madhu_noinv': pt.PT_NoInversion, 'madhu_inv': pt.PT_Inversion } # Extract necessary values from the TEP file: tep = rd.File(tepfile) # Stellar temperature in K: tstar = float(tep.getvalue('Ts')[0]) # Stellar radius (in meters): rstar = float(tep.getvalue('Rs')[0]) * c.Rsun # Semi-major axis (in meters): sma = float(tep.getvalue('a')[0]) * sc.au # Planetary radius (in meters): rplanet = float(tep.getvalue('Rp')[0]) * c.Rjup # Planetary mass (in kg): mplanet = float(tep.getvalue('Mp')[0]) * c.Mjup # Number of fitting parameters: nfree = len(params) # Total number of free parameters nmolfit = len(molfit) # Number of molecular free parameters nradfit = int(solution == 'transit') # 1 for transit, 0 for eclipse nPT = nfree - nmolfit - nradfit # Number of PT free parameters # Read atmospheric file to get data arrays: species, pressure, temp, abundances = mat.readatm(atmfile) # Reverse pressure order (for PT to work): pressure = pressure[::-1] nlayers = len(pressure) # Number of atmospheric layers nspecies = len(species) # Number of species in the atmosphere mu.msg(verb, "There are {:d} layers and {:d} species.".format(nlayers, nspecies)) # Find index for Hydrogen and Helium: species = np.asarray(species) iH2 = np.where(species == "H2")[0] iHe = np.where(species == "He")[0] # Get H2/He abundance ratio: ratio = (abundances[:, iH2] / abundances[:, iHe]).squeeze() # Find indices for the metals: imetals = np.where((species != "He") & (species != "H2") & \ (species != "H-") & (species != 'e-'))[0] # Index of molecular abundances being modified: imol = np.zeros(nmolfit, dtype='i') for i in np.arange(nmolfit): imol[i] = np.where(np.asarray(species) == molfit[i])[0] # Pressure-Temperature profile: if PTtype == "line": # Planetary surface gravity (in cm s-2): gplanet = 100.0 * sc.G * mplanet / rplanet**2 # Additional PT arguments: PTargs = [rstar, tstar, tint, sma, gplanet] else: PTargs = None # Allocate arrays for receiving and sending data to master: freepars = np.zeros(nfree, dtype='d') profiles = np.zeros((nspecies + 1, nlayers), dtype='d') # This are sub-sections of profiles, containing just the temperature and # the abundance profiles, respectively: tprofile = profiles[0, :] aprofiles = profiles[1:, :] # Store abundance profiles: for i in np.arange(nspecies): aprofiles[i] = abundances[:, i] # ::::::: Spawn transit code ::::::::::::::::::::::::::::::::::::: # # transit configuration file: transitcfile = args2.tconfig # Initialize the transit python module: transit_args = ["transit", "-c", transitcfile] trm.transit_init(len(transit_args), transit_args) # Get wavenumber array from transit: nwave = trm.get_no_samples() specwn = trm.get_waveno_arr(nwave) # ::::::: Output Converter ::::::::::::::::::::::::::::::::::::::: ffile = args2.filters # Filter files kurucz = args2.kurucz # Kurucz file # Log10(stellar gravity) gstar = float(tep.getvalue('loggstar')[0]) # Planet-to-star radius ratio: rprs = rplanet / rstar nfilters = len(ffile) # Number of filters: # FINDME: Separate filter/stellar interpolation? # Get stellar model: starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, tstar, gstar) # Read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation for i in np.arange(nfilters): # Read filter: filtwaven, filttransm = w.readfilter(ffile[i]) # Check that filter boundaries lie within the spectrum wn range: if filtwaven[0] < specwn[0] or filtwaven[-1] > specwn[-1]: mu.exit(message="Wavenumber array ({:.2f} - {:.2f} cm-1) does not " "cover the filter[{:d}] wavenumber range ({:.2f} - {:.2f} " "cm-1).".format(specwn[0], specwn[-1], i, filtwaven[0], filtwaven[-1])) # Resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # Allocate arrays for receiving and sending data to master: spectrum = np.zeros(nwave, dtype='d') bandflux = np.zeros(nfilters, dtype='d') # Allocate array to receive parameters from MPI: params = np.zeros(npars, np.double) # :::::: Main MCMC Loop :::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: while niter >= 0: niter -= 1 # Receive parameters from MCMC: mu.comm_scatter(comm, params) # Check for the MCMC-end flag: if params[0] == np.inf: break # Input converter calculate the profiles: try: tprofile[:] = pt.PT_generator(pressure, params[0:nPT], PTfunc[PTtype], PTargs)[::-1] except ValueError: mu.msg(verb, 'Input parameters give non-physical profile.') # FINDME: what to do here? # If the temperature goes out of bounds: if np.any(tprofile < Tmin) or np.any(tprofile > Tmax): mu.comm_gather(comm, -np.ones(nfilters), MPI.DOUBLE) continue # Scale abundance profiles: for i in np.arange(nmolfit): m = imol[i] # Use variable as the log10: aprofiles[m] = abundances[:, m] * 10.0**params[nPT + nradfit + i] # Update H2, He abundances so sum(abundances) = 1.0 in each layer: q = 1.0 - np.sum(aprofiles[imetals], axis=0) if np.any(q < 0.0): mu.comm_gather(comm, -np.ones(nfilters), MPI.DOUBLE) continue aprofiles[iH2] = ratio * q / (1.0 + ratio) aprofiles[iHe] = q / (1.0 + ratio) # Set the 'surface' level: if solution == "transit": trm.set_radius(params[nPT]) # Let transit calculate the model spectrum: spectrum = trm.run_transit(profiles.flatten(), nwave) # Calculate the band-integrated intensity per filter: for i in np.arange(nfilters): if solution == "eclipse": fluxrat = (spectrum[wnindices[i]] / istarfl[i]) * rprs * rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) elif solution == "transit": bandflux[i] = w.bandintegrate(spectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # Send resutls back to MCMC: mu.comm_gather(comm, bandflux, MPI.DOUBLE) # :::::: End main Loop ::::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Close communications and disconnect: mu.comm_disconnect(comm) trm.free_memory()
def plot_bestFit_Spectrum(filters, kurucz, tepfile, solution, output, data, uncert, date_dir): ''' Plot BART best-model spectrum ''' # get star data R_star, T_star, sma, gstar = get_starData(tepfile) # get surface gravity grav, Rp = mat.get_g(tepfile) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp/R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) # read best-fit spectrum output file, take wn and spectra values if solution == 'eclipse': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit eclipse spectrum figure.") elif solution == 'transit': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit modulation spectrum figure.") # convert wn to wl specwl = 1e4/specwn # number of filters nfilters = len(filters) # read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation meanwn = [] # Filter mean wavenumber for i in np.arange(nfilters): # read filter: filtwaven, filttransm = w.readfilter(filters[i]) meanwn.append(np.sum(filtwaven*filttransm)/sum(filttransm)) # resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # convert mean wn to mean wl meanwl = 1e4/np.asarray(meanwn) # band-integrate the flux-ratio or modulation: bandflux = np.zeros(nfilters, dtype='d') bandmod = np.zeros(nfilters, dtype='d') for i in np.arange(nfilters): fluxrat = (bestspectrum[wnindices[i]]/istarfl[i]) * rprs*rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) bandmod[i] = w.bandintegrate(bestspectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # stellar spectrum on specwn: sinterp = si.interp1d(starwn, starfl) sflux = sinterp(specwn) frat = bestspectrum/sflux * rprs * rprs # plot figure plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default':'rm'}) matplotlib.rcParams.update({'font.size':10}) plt.figure(3, (8.5, 5)) plt.clf() # depending on solution plot eclipse or modulation spectrum if solution == 'eclipse': gfrat = gaussf(frat, 2) plt.semilogx(specwl, gfrat*1e3, "b", lw=1.5, label="Best-fit") plt.errorbar(meanwl, data*1e3, uncert*1e3, fmt="or", label="data") plt.plot(meanwl, bandflux*1e3, "ok", label="model", alpha=1.0) plt.ylabel(r"$F_p/F_s$ (10$^{3}$)", fontsize=12) elif solution == 'transit': gmodel = gaussf(bestspectrum, 2) plt.semilogx(specwl, gmodel, "b", lw=1.5, label="Best-fit") # Check units! plt.errorbar(meanwl, data, uncert, fmt="or", label="data") plt.plot(meanwl, bandmod, "ok", label="model", alpha=0.5) plt.ylabel(r"$(R_p/R_s)^2$", fontsize=12) leg = plt.legend(loc="lower right") leg.get_frame().set_alpha(0.5) ax = plt.subplot(111) ax.set_xscale('log') plt.xlabel(r"${\rm Wavelength\ \ (um)}$", fontsize=12) ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter()) ax.set_xticks(np.arange(min(specwl),max(specwl),1)) plt.xlim(min(specwl),max(specwl)) plt.savefig(date_dir + "BART-bestFit-Spectrum.png")
def plot_bestFit_Spectrum(filters, kurucz, tepfile, solution, output, data, uncert, date_dir): ''' Plot BART best-model spectrum ''' # get star data R_star, T_star, sma, gstar = get_starData(tepfile) # get surface gravity grav, Rp = mat.get_g(tepfile) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp/R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) # read best-fit spectrum output file, take wn and spectra values if solution == 'eclipse': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit eclipse spectrum figure.") elif solution == 'transit': specwn, bestspectrum = rt.readspectrum(date_dir + output, wn=True) # print on screen print(" Plotting BART best-fit modulation spectrum figure.") # convert wn to wl specwl = 1e4/specwn # number of filters nfilters = len(filters) # read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation meanwn = [] # Filter mean wavenumber for i in np.arange(nfilters): # read filter: filtwaven, filttransm = w.readfilter(filters[i]) meanwn.append(np.sum(filtwaven*filttransm)/sum(filttransm)) # resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # convert mean wn to mean wl meanwl = 1e4/np.asarray(meanwn) # band-integrate the flux-ratio or modulation: bandflux = np.zeros(nfilters, dtype='d') bandmod = np.zeros(nfilters, dtype='d') for i in np.arange(nfilters): fluxrat = (bestspectrum[wnindices[i]]/istarfl[i]) * rprs*rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) bandmod[i] = w.bandintegrate(bestspectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # stellar spectrum on specwn: sinterp = si.interp1d(starwn, starfl) sflux = sinterp(specwn) frat = bestspectrum/sflux * rprs * rprs # plot figure plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default':'rm'}) matplotlib.rcParams.update({'font.size':10}) plt.figure(3, (8.5, 5)) plt.clf() # depending on solution plot eclipse or modulation spectrum if solution == 'eclipse': gfrat = gaussf(frat, 2) plt.semilogx(specwl, gfrat*1e3, "b", lw=1.5, label="Best-fit") plt.errorbar(meanwl, data*1e3, uncert*1e3, fmt="or", label="data") plt.plot(meanwl, bandflux*1e3, "ok", label="model", alpha=1.0) plt.ylabel(r"$F_p/F_s$ (10$^{3}$)", fontsize=12) elif solution == 'transit': gmodel = gaussf(bestspectrum, 2) plt.semilogx(specwl, gmodel, "b", lw=1.5, label="Best-fit") # Check units! plt.errorbar(meanwl, data, uncert, fmt="or", label="data") plt.plot(meanwl, bandmod, "ok", label="model", alpha=0.5) plt.ylabel(r"$(R_p/R_s)^2$", fontsize=12) leg = plt.legend(loc="lower right") leg.get_frame().set_alpha(0.5) ax = plt.subplot(111) ax.set_xscale('log') plt.xlabel(r"${\rm Wavelength\ \ (um)}$", fontsize=12) ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter()) ax.set_xticks(np.arange(round(min(specwl)),max(specwl),1)) plt.xlim(min(specwl),max(specwl)) plt.savefig(date_dir + "BART-bestFit-Spectrum.png")
3.90000000e-05, 3.80000000e-05, 3.60000000e-05, 3.70000000e-05, 3.30000000e-05, 3.40000000e-05, 3.00000000e-05, 3.60000000e-05, 3.60000000e-05, 3.30000000e-05, 3.50000000e-05, 3.60000000e-05, 3.70000000e-05, 4.20000000e-05]) # get star data R_star, T_star, sma, gstar = bf.get_starData(tep_name) # get surface gravity grav, Rp = mat.get_g(tep_name) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp/R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) ###################### plot figure ############################# plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default':'rm'}) matplotlib.rcParams.update({'axes.labelsize': 16, 'xtick.labelsize': 14, 'ytick.labelsize': 14,}) fig= plt.figure(figsize=(8.5, 5)) plt.ylabel(r"$F_p/F_s$ (10$^{-3}$)", fontsize=14) plt.xlabel(r"${\rm Wavelength\ \ (um)}$", fontsize=14) ######################################### for each spectrum separately
def plot_bestFit_Spectrum(low, high, xtic, xlab, spec, clr, specs, atmfile, filters, kurucz, tepfile, outflux, data, uncert, direct): ''' Plot Transit spectrum ''' # get star data R_star, T_star, sma, gstar = bf.get_starData(tepfile) # get surface gravity grav, Rp = mat.get_g(tepfile) # convert Rp to m Rp = Rp * 1000 # ratio planet to star rprs = Rp / R_star # read kurucz file starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, T_star, gstar) # read best-fit spectrum output file, take wn and spectra values (head, tail) = os.path.split(outflux) specwn, bestspectrum = rt.readspectrum(direct + '/' + tail, wn=True) # convert wn to wl specwl = 1e4 / specwn # number of filters nfilters = len(filters) # read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation meanwn = [] # Filter mean wavenumber for i in np.arange(nfilters): # read filter: filtwaven, filttransm = w.readfilter(filters[i]) meanwn.append(np.sum(filtwaven * filttransm) / sum(filttransm)) # resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # convert mean wn to mean wl meanwl = 1e4 / np.asarray(meanwn) # band-integrate the flux-ratio or modulation: bandflux = np.zeros(nfilters, dtype='d') bandmod = np.zeros(nfilters, dtype='d') for i in np.arange(nfilters): fluxrat = (bestspectrum[wnindices[i]] / istarfl[i]) * rprs * rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) bandmod[i] = w.bandintegrate(bestspectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # stellar spectrum on specwn: sinterp = si.interp1d(starwn, starfl) sflux = sinterp(specwn) frat = bestspectrum / sflux * rprs * rprs ###################### plot figure ############################# plt.rcParams["mathtext.default"] = 'rm' matplotlib.rcParams.update({'mathtext.default': 'rm'}) matplotlib.rcParams.update({ 'axes.labelsize': 16, 'xtick.labelsize': 20, 'ytick.labelsize': 20, }) plt.figure(2, (8.5, 5)) plt.clf() # smooth the spectrum a fit gfrat = gaussf(frat, 2) # plot eclipse spectrum plt.semilogx(specwl, gfrat * 1e3, clr, lw=1.5, label="Spectrum", linewidth=4) plt.errorbar(meanwl, data * 1e3, uncert * 1e3, fmt="ko", label="Data", alpha=0.7) plt.ylabel(r"$F_p/F_s$ (10$^{-3}$)", fontsize=24) leg = plt.legend(loc="upper left") leg.get_frame().set_alpha(0.5) ax = plt.subplot(111) ax.set_xscale('log') plt.xlabel(r"${\rm Wavelength\ \ (um)}$", fontsize=24) ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter()) plt.gca().xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter()) ax.set_xticks([0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0]) ax.set_xticklabels(["0.7", "", "", "1.0", "2.0", "3.0", "4.0", "5.0"]) plt.xlim(min(specwl), max(specwl)) nfilters = len(filters) # plot filter bandpasses for i in np.arange(nfilters - 15): (head, tail) = os.path.split(filters[i]) lbl = tail[:-4] # read filter: wn, respons = w.readfilter(filters[i]) respons = respons / 3 - 0.4 wl = 10000.0 / wn #plt.plot(wl, respons, color='crimson', linewidth =1) if lbl == 'spitzer_irac1_sa' or lbl == 'spitzer_irac2_sa': respons = respons * 2 + 0.4 plt.plot(wl, respons, color='grey', linewidth=1, alpha=0.5) #plt.plot(wl, respons*2, color='orangered', linewidth =1) elif lbl == 'Wang-Hband' or lbl == 'Wang-Kband': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) elif lbl == 'VLT_1190' or lbl == 'VLT_2090': plt.plot(wl, respons, color='grey', linewidth=2, alpha=0.5) #plt.plot(wl, respons, color='firebrick', linewidth =2) elif lbl == 'GROND_K_JB' or lbl == 'GROND_i_JB': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) elif lbl == 'Zhou_Ks': plt.plot(wl, respons, 'grey', linewidth=1, alpha=0.5) plt.ylim(-0.4, 7) plt.text(1.9, 3, specs, color=clr, fontsize=26) plt.subplots_adjust(bottom=0.20) plt.savefig(spec + "_BestFit-transSpec.png") plt.savefig(spec + "_BestFit-transSpec.ps")
def noiseup(snr, planetfile, filters, geometry, outdir, outpre, kuruczfile, mass=0.806, radius=0.756, temp=5000., planetrad=1.138, seed=0): """ This function takes an input star and planet spectrum and computes transit/eclipse depths with photon noise, as observed by a JWST-like telescope. Inputs ------ snr : float. Desired SNR value. planetfile: string. Path/to/file of the planet's spectrum. filters : list, strings. Paths/to/filter files. geometry : string. Viewing geometry. 'eclipse' or 'transit' outdir : string. Path/to/directory/ where the outputs will be saved. outpre : string. Prefix to use for all saved out files. kuruczfile: string. Path/to/file of the Kurucz stellar model. mass : float. Mass of the host star [M_sun] radius : float. Radius of the host star [R_sun] temp : float. Temperature of the host star [K] planetrad : float. Radius of the planet [R_jup] seed : int. Seed for random number generation. Outputs ------- Four text files are produced: - list of filers - noiseless spectrum - noised spectrum - uncertainties on noised spectrum Notes ----- The default values are based on the HD 189733 system. The default `ecltime` value comes from https://academic.oup.com/mnras/article/395/1/335/1746726/Secondary-radio-eclipse-of-the-transiting-planet Revisions --------- 2017-11-15 Ryan Original implementation 2018-04-18 Michael Added transit calculations 2019-06-06 Michael Reworked into function, incorporated into BARTTest 2020-08-08 Michael Simplified computation """ # Set the random seed for reproducibility np.random.seed(seed=seed) # Make sure `outdir` has trailing slash: if outdir[-1] != '/': outdir = outdir + '/' # Constants in CGS units G = const.G.cgs.value h = const.h.cgs.value c = const.c.cgs.value Msun = const.M_sun.cgs.value Rsun = const.R_sun.cgs.value pc2cm = const.pc.cgs.value Rjup = const.R_jup.cgs.value # Convert system parameters mass *= Msun radius *= Rsun planetrad *= Rjup rprs = planetrad / radius #ratio of planet/star radii # Temperature and log(g) of star logg = np.log10(G * mass / radius**2) #log g (cm/s2) # Read and interpolate Kurucz grid, planet spectrum starfl, starwn, tmodel, gmodel = wine.readkurucz(kuruczfile, temp, logg) planetwn, planetfl = rt.readspectrum(planetfile) # Initialize arrays for band-integrated spectrum and mean wavelength bandflux = np.zeros(len(filters)) meanwn = np.zeros(len(filters)) nifilter = [] wnindices = [] istarfl = [] # interpolated stellar flux # Read filters. Resample to planetwn for i in np.arange(len(filters)): filtwn, filttransm = wine.readfilter(filters[i]) meanwn[i] = np.mean(filtwn) nifilt, strfl, wnind = wine.resample(planetwn, filtwn, filttransm, starwn, starfl) nifilter.append(nifilt) wnindices.append(wnind) istarfl.append(strfl) # Loop over each filter file, read the file, interpolate to the # wavelength array, and integrate over the bandpass, weighted by the # filter. for i in np.arange(len(filters)): # integrate over the bandpass if geometry == "eclipse": fluxrat = (planetfl[wnindices[i]] / istarfl[i]) * rprs * rprs bandflux[i] = wine.bandintegrate(fluxrat, planetwn, nifilter[i], wnindices[i]) elif geometry == "transit": bandflux[i] = wine.bandintegrate(planetfl[wnindices[i]], planetwn, nifilter[i], wnindices[i]) # Uncertainty unc = bandflux / snr # Save out files # Save filter file paths for BART with open(outdir + outpre + 'filters.txt', 'w') as f: for i in range(len(filters)): f.write('../00inputs/filters/' + \ os.path.basename(filters[i]) + '\n') if geometry == 'eclipse': strname = 'ecl' elif geometry == 'transit': strname = 'tra' # Save noised depths to a file with open(outdir + outpre + strname + 'depths.txt', 'w') as f: for i in range(len(depths)): f.write(str(bandflux[i]) + '\n') # Save uncertainties to a file with open(outdir + outpre + strname + 'uncs.txt', 'w') as f: for i in range(len(unc)): f.write(str(unc[i]) + '\n')
def noiseup(kuruczfile, planetfile, filters, geometry, outdir, outpre, mass=0.806, radius=0.756, temp=5000., planetrad=1.138, distance=19.3, diameter=650., ecltime=1.827, seed=0): """ This function takes an input star and planet spectrum and computes transit/eclipse depths with photon noise, as observed by a JWST-like telescope. Inputs ------ kuruczfile: string. Path/to/file of the Kurucz stellar model. planetfile: string. Path/to/file of the planet's spectrum. filters : list, strings. Paths/to/filter files. geometry : string. Viewing geometry. 'eclipse' or 'transit' outdir : string. Path/to/directory/ where the outputs will be saved. outpre : string. Prefix to use for all saved out files. mass : float. Mass of the host star [M_sun] radius : float. Radius of the host star [R_sun] temp : float. Temperature of the host star [K] planetrad : float. Radius of the planet [R_jup] distance : float. Distance to planetary system [pc] diameter : float. Telescope diameter [cm] ecltime : float. Duration of the secondary eclipse [hours] seed : int. Seed for random number generation. Outputs ------- Four files are produced: - - - - Notes ----- The default values are based on the HD 189733 system. The default `ecltime` value comes from https://academic.oup.com/mnras/article/395/1/335/1746726/Secondary-radio-eclipse-of-the-transiting-planet Revisions --------- 2017-11-15 Ryan Original implementation 2018-04-18 Michael Added transit calculations 2019-06-06 Michael Reworked into function, incorporated into BARTTest """ # Set the random seed for reproducibility np.random.seed(seed=seed) # Make sure `outdir` has trailing slash: if outdir[-1] != '/': outdir = outdir + '/' # Constants in CGS units G = const.G.cgs.value h = const.h.cgs.value c = const.c.cgs.value Msun = const.M_sun.cgs.value Rsun = const.R_sun.cgs.value pc2cm = const.pc.cgs.value Rjup = const.R_jup.cgs.value # Convert system parameters mass *= Msun radius *= Rsun planetrad *= Rjup distance *= pc2cm ecltime *= 3600 #hours --> seconds # Temperature and log(g) of star logg = np.log10(G * mass / radius**2) #log g (cm/s2) # Read and interpolate Kurucz grid, planet spectrum starfl, starwn, tmodel, gmodel = wine.readkurucz(kuruczfile, temp, logg) planetwn, planetfl = rt.readspectrum(planetfile) nifilter = [] wnindices = [] # Multiply by 4pi steradians, surface area # Planetary spectrum is already integrated over steradians sPower = starfl * (4 * np.pi * radius**2) pPower = planetfl * (4 * np.pi * planetrad**2) # Multiply by eclipse duration sEnergy = sPower * ecltime pEnergy = pPower * ecltime # Spread out over distance sEdensity = sEnergy / (4 * np.pi * distance**2) pEdensity = pEnergy / (4 * np.pi * distance**2) # Multiply by telescope area (total energy received) sSED = sEdensity * np.pi * (diameter/2.)**2. pSED = pEdensity * np.pi * (diameter/2.)**2. # Interpolate stellar SED sSEDinterp = si.interp1d(starwn, sSED) isSED = sSEDinterp(planetwn) if geometry == 'transit': # Interpolate stellar flux starflinterp = si.interp1d(starwn, starfl) istarfl = starflinterp(planetwn) # Initialize arrays for band-integrated energy and mean wavelength bandintegratedstar = np.zeros(len(filters)) bandintegratedplanet = np.zeros(len(filters)) meanwn = np.zeros(len(filters)) # Read filters. Resample to planetwn for i in np.arange(len(filters)): filtwn, filttransm = wine.readfilter(filters[i]) meanwn[i] = np.mean(filtwn) nifilt, rsSED, wnind = wine.resample(planetwn, filtwn, filttransm, starwn, sSED) nifilter.append(nifilt) wnindices.append(wnind) # Loop over each filter file, read the file, interpolate to the # wavelength array, and integrate over the bandpass, weighted by the # filter. for i in np.arange(len(filters)): # integrate over the bandpass bandintegratedstar[i] = wine.bandintegrate( isSED[wnindices[i][0]], planetwn, nifilter[i], wnindices[i]) if geometry == 'eclipse': bandintegratedplanet[i] = wine.bandintegrate( pSED[wnindices[i][0]], planetwn, nifilter[i], wnindices[i]) elif geometry == 'transit': bandintegratedplanet[i] = wine.bandintegrate( planetfl[wnindices[i][0]], planetwn, nifilter[i], wnindices[i]) else: print("Invalid `geometry` specification.\n") sys.exit() # Divide by photon energy to get number of photons (counts) # Find total photon signal sphotons = bandintegratedstar / (h * meanwn * c) if geometry == 'eclipse': pphotons = bandintegratedplanet / (h * meanwn * c) phot_tot = sphotons + pphotons else: phot_tot = sphotons #planet flux is negligible in transit geometry # Multiply by 1 minus the transit depth = signal during transit phot_tot_rat = phot_tot * (1. - bandintegratedplanet) # Noise it up poisson_tot = phot_tot**(.5) poisson_s = sphotons**(.5) if geometry == 'eclipse': poisson_p = pphotons**(.5) noise = np.random.normal(0, poisson_tot) # Add noise to the band-integrated photon counts noisedpts = phot_tot + noise noisedplanet = pphotons + noise noisedstar = sphotons + noise # Calculate eclipse depths depths = noisedplanet / phot_tot # Calculate eclipse depth uncertainty unc = phot_tot/sphotons * ((poisson_tot/phot_tot)**2 + \ (poisson_s /sphotons)**2)**(.5) else: poisson_tot_rat = (phot_tot_rat)**(.5) # Propagate error unc = phot_tot_rat / phot_tot * \ ((poisson_tot_rat / phot_tot_rat)**2 + \ (poisson_tot / phot_tot )**2)**(.5) noise = np.random.normal(0, poisson_tot_rat) / phot_tot_rat depths = bandintegratedplanet + noise # Save out files # Save filter file paths for BART with open(outdir+outpre+'filters.txt', 'w') as f: for i in range(len(filters)): f.write('../00inputs/filters/' + \ os.path.basename(filters[i]) + '\n') if geometry == 'eclipse': # Save depths to a file with open(outdir+outpre+'ecldepths.txt', 'w') as f: for i in range(len(depths)): f.write(str(depths[i]) + '\n') # Save uncertainties to a file with open(outdir+outpre+'ecluncs.txt', 'w') as f: for i in range(len(unc)): f.write(str(unc[i]) + '\n') # Save noiseless depths with open(outdir+outpre+'ecl_noiseless.txt', 'w') as f: for i in range(len(filters)): f.write(str(pphotons[i]/phot_tot[i]) + '\n') else: # Save depths to a file with open(outdir+outpre+'tradepths.txt', 'w') as f: for i in range(len(depths)): f.write(str(depths[i]) + '\n') # Save uncertainties to a file with open(outdir+outpre+'trauncs.txt', 'w') as f: for i in range(len(unc)): f.write(str(unc[i]) + '\n') # Save noiseless depths with open(outdir+outpre+'tra_noiseless.txt', 'w') as f: for i in range(len(filters)): f.write(str(bandintegratedplanet[i]) + '\n')