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()
Ejemplo n.º 3
0
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 ~~")
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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")
Ejemplo n.º 6
0
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")
    # 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 eclipse spectrum
gfrat = gaussf(frat, 1)
plt.semilogx(specwl, gfrat*1e3, "slateblue", lw=1.5, label="Best-fit", alpha=0.6)
plt.errorbar(meanwl, data*1e3, uncert*1e3, fmt="ro", label="Data", alpha=0.8)
plt.plot(meanwl, bandflux*1e3, "ko", label="Model", alpha=1.0)
leg = plt.legend(loc="upper left")
leg.get_frame().set_alpha(0.5)
Ejemplo n.º 8
0
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")
Ejemplo n.º 9
0
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')