Exemple #1
0
def compute_full_sim(dictinput):
    """Top level function to set up exoplanet obs. for JW
    
    Function to set up explanet observations for JWST only and 
    compute simulated spectrum. It uses STScI's Pandeia to compute 
    instrument throughputs and WebbPSF to compute PSFs. 
    
    Parameters
    ----------
    dictinput : dict
        dictionary containing instrument parameters and exoplanet specific 
        parameters. {"pandeia_input":dict1, "pandexo_input":dict1}
    
    Returns
    -------
    dict
        large dictionary with 1d, 2d simualtions, timing info, instrument info, warnings
    
    Examples
    --------  
      
    >>> from pandexo.engine.jwst import compute_full_sim 
    >>> from pandexo.engine.justplotit import jwst_1d_spec
    >>> a = compute_full_sim({"pandeia_input": pandeiadict, "pandexo_input":exodict})
    >>> jwst_1d_spec(a)
    .. image:: 1d_spec.png
    
    Notes
    -----
    It is much easier to run simulations through either **run_online** or **justdoit**. **justdoit** contains functions to create input dictionaries and **run_online** contains web forms to create input dictionaries.
    
    See Also
    -------- 
        pandexo.engine.justdoit.run_pandexo : Best function for running pandexo runs
        pandexo.engine.run_online : Allows running functions through online interface
    """
    pandeia_input = dictinput['pandeia_input']
    pandexo_input = dictinput['pandexo_input']

    #define the calculation we'll be doing
    if pandexo_input['planet']['w_unit'] == 'sec':
        calculation = 'phase_spec'
    else:
        calculation = pandexo_input['calculation'].lower()

    #which instrument
    instrument = pandeia_input['configuration']['instrument']['instrument']
    conf = pandeia_input['configuration']

    #if optimize is in the ngroups section, this will throw an error
    #so create temp conf with 2 groups
    try:
        i = InstrumentFactory(config=conf)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()
    except:
        conf_temp = deepcopy(conf)
        conf_temp['detector']['ngroup'] = 2
        i = InstrumentFactory(config=conf_temp)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()

    #detector parameters
    fullwell = det_pars['fullwell']
    rn = det_pars['rn']
    sat_level = pandexo_input['observation']['sat_level'] / 100.0 * fullwell
    mingroups = det_pars['mingroups']

    #exposure parameters
    tframe = exp_pars.tframe
    nframe = exp_pars.nframe
    nskip = exp_pars.nskip

    #parameteres needed from exo_input
    mag = pandexo_input['star']['mag']

    noccultations = pandexo_input['observation']['noccultations']
    R = pandexo_input['observation']['R']
    #amount of exposure time out-of-occultation, as a fraction of in-occ time
    expfact_out = pandexo_input['observation']['fraction']
    noise_floor = pandexo_input['observation']['noise_floor']

    #get stellar spectrum and in transit spec
    star_spec = create.outTrans(pandexo_input['star'])
    both_spec = create.bothTrans(star_spec, pandexo_input['planet'])
    out_spectrum = np.array([both_spec['wave'], both_spec['flux_out_trans']])

    #get transit duration from phase curve or from input
    if calculation == 'phase_spec':
        transit_duration = max(both_spec['time']) - min(both_spec['time'])
    else:
        transit_duration = pandexo_input['planet']['transit_duration']

    #add to pandeia input
    pandeia_input['scene'][0]['spectrum']['sed']['spectrum'] = out_spectrum

    if isinstance(pandeia_input["configuration"]["detector"]["ngroup"],
                  (float, int)):
        m = {
            "ngroup": pandeia_input["configuration"]["detector"]["ngroup"],
            "tframe": tframe,
            "nframe": nframe,
            "mingroups": mingroups,
            "nskip": nskip
        }
    else:
        #run pandeia once to determine max exposure time per int and get exposure params
        print("Optimization Reqested: Computing Duty Cycle")
        m = {
            "maxexptime_per_int":
            compute_maxexptime_per_int(pandeia_input, sat_level),
            "tframe":
            tframe,
            "nframe":
            nframe,
            "mingroups":
            mingroups,
            "nskip":
            nskip
        }
        print("Finished Duty Cycle Calc")

    #calculate all timing info
    timing, flags = compute_timing(m, transit_duration, expfact_out,
                                   noccultations)

    #Simulate out trans and in transit
    print("Starting Out of Transit Simulation")
    out = perform_out(pandeia_input, pandexo_input, timing, both_spec)

    #extract extraction area before dict conversion
    extraction_area = out.extraction_area
    out = out.as_dict()
    out.pop('3d')
    print("End out of Transit")

    #this kind of redundant going to compute inn from out instead
    #keep perform_in but change inputs to (out, timing, both_spec)
    print("Starting In Transit Simulation")
    inn = perform_in(pandeia_input, pandexo_input, timing, both_spec, out,
                     calculation)
    print("End In Transit")

    #compute warning flags for timing info
    warnings = add_warnings(out, timing, sat_level, flags, instrument)

    compNoise = ExtractSpec(inn, out, rn, extraction_area, timing)

    #slope method is pandeia's pure noise calculation (taken from SNR)
    #contains correlated noise, RN, dark current, sky,
    #uses MULTIACCUM formula so we deviated from this.
    #could eventually come back to this if Pandeia adopts First-Last formula
    if calculation == 'slope method':
        #Extract relevant info from pandeia output (1d curves and wavelength)
        #extracted flux in units of electron/s
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_slope_method()

    #derives noise from 2d postage stamps. Doing this results in a higher
    #1d flux rate than the Pandeia gets from extracting its own.
    #this should be used to benchmark Pandeia's 1d extraction
    elif calculation == '2d extract':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_2d_extract()

    #this is the noise calculation that PandExo uses online. It derives
    #its own calculation of readnoise and does not use MULTIACUMM
    #noise formula
    elif calculation == 'fml':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_f_minus_l()

    elif calculation == 'phase_spec':
        result = compNoise.run_phase_spec()
        w = result['time']
    else:
        result = None
        raise Exception('WARNING: Calculation method not found.')

    varin = result['var_in_1d']
    varout = result['var_out_1d']
    extracted_flux_out = result['photon_out_1d']
    extracted_flux_inn = result['photon_in_1d']

    #bin the data according to user input
    if R != None:
        wbin = bin_wave_to_R(w, R)
        photon_out_bin = uniform_tophat_sum(wbin, w, extracted_flux_out)
        photon_in_bin = uniform_tophat_sum(wbin, w, extracted_flux_inn)
        var_in_bin = uniform_tophat_sum(wbin, w, varin)
        var_out_bin = uniform_tophat_sum(wbin, w, varout)
    else:
        wbin = w
        photon_out_bin = extracted_flux_out
        photon_in_bin = extracted_flux_inn
        var_in_bin = varin
        var_out_bin = varout

    #calculate total variance
    var_tot = var_in_bin + var_out_bin
    error = np.sqrt(var_tot)

    #calculate error on spectrum
    error_spec = error / photon_out_bin

    #Add in user specified noise floor
    error_spec_nfloor = add_noise_floor(noise_floor, wbin, error_spec)

    #add in random noise for the simulated spectrum
    rand_noise = np.sqrt(
        (var_in_bin + var_out_bin)) * (np.random.randn(len(wbin)))
    raw_spec = (photon_out_bin - photon_in_bin) / photon_out_bin
    sim_spec = (photon_out_bin - photon_in_bin + rand_noise) / photon_out_bin

    #if secondary tranist, multiply spectra by -1
    if pandexo_input['planet']['f_unit'] == 'fp/f*':
        sim_spec = -1.0 * sim_spec
        raw_spec = -1.0 * raw_spec

    #package processed data
    binned = {
        'wave': wbin,
        'spectrum': raw_spec,
        'spectrum_w_rand': sim_spec,
        'error_w_floor': error_spec_nfloor
    }

    unbinned = {
        'flux_out': extracted_flux_out,
        'flux_in': extracted_flux_inn,
        'var_in': varin,
        'var_out': varout,
        'wave': w,
        'error_no_floor': np.sqrt(varin + varout) / extracted_flux_out
    }

    result_dict = as_dict(out, both_spec, binned, timing, mag, sat_level,
                          warnings, pandexo_input['planet']['f_unit'],
                          unbinned, calculation)

    return result_dict
Exemple #2
0
def compute_full_sim(dictinput): 
    """Top level function to set up exoplanet obs. for JW
    
    Function to set up explanet observations for JWST only and 
    compute simulated spectrum. It uses STScI's Pandeia to compute 
    instrument throughputs and WebbPSF to compute PSFs. 
    
    Parameters
    ----------
    dictinput : dict
        dictionary containing instrument parameters and exoplanet specific 
        parameters. {"pandeia_input":dict1, "pandexo_input":dict1}
    
    Returns
    -------
    dict
        large dictionary with 1d, 2d simualtions, timing info, instrument info, warnings
    
    Examples
    --------  
      
    >>> from .pandexo.engine.jwst import compute_full_sim 
    >>> from .pandexo.engine.justplotit import jwst_1d_spec
    >>> a = compute_full_sim({"pandeia_input": pandeiadict, "pandexo_input":exodict})
    >>> jwst_1d_spec(a)
    .. image:: 1d_spec.png
    
    Notes
    -----
    It is much easier to run simulations through either **run_online** or **justdoit**. **justdoit** contains functions to create input dictionaries and **run_online** contains web forms to create input dictionaries.
    
    See Also
    -------- 
        pandexo.engine.justdoit.run_pandexo : Best function for running pandexo runs
        pandexo.engine.run_online : Allows running functions through online interface
    """
    pandeia_input = dictinput['pandeia_input']
    pandexo_input = dictinput['pandexo_input']    	
	
    #define the calculation we'll be doing 
    if pandexo_input['planet']['w_unit'] == 'sec':
        calculation = 'phase_spec'
    else: 
        calculation = pandexo_input['calculation'].lower()

    #which instrument 
    instrument = pandeia_input['configuration']['instrument']['instrument']
    conf = pandeia_input['configuration']
    
    #if optimize is in the ngroups section, this will throw an error 
    #so create temp conf with 2 groups 
    try:
        i = InstrumentFactory(config=conf)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()
    except: 
        conf_temp = deepcopy(conf) 
        conf_temp['detector']['ngroup'] = 2 
        i = InstrumentFactory(config=conf_temp)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()
        
    #detector parameters
    fullwell = det_pars['fullwell'] #from pandeia data
    rn = det_pars['rn']
    sat_unit = pandexo_input['observation']['sat_unit']

    if sat_unit =='%':
        sat_level = pandexo_input['observation']['sat_level']/100.0*fullwell
    elif sat_unit =='e':
        sat_level = pandexo_input['observation']['sat_level']
    else: 
        raise Exception("Saturation Level Needs Units: % fullwell or Electrons ")

    mingroups = det_pars['mingroups']
    
    #exposure parameters 
    tframe = exp_pars.tframe
    nframe = exp_pars.nframe
    nskip = exp_pars.nskip
    
    #parameteres needed from exo_input
    mag = pandexo_input['star']['mag']
    
    
    noccultations = pandexo_input['observation']['noccultations']
    R = pandexo_input['observation']['R']

    noise_floor = pandexo_input['observation']['noise_floor']

    
    #get stellar spectrum and in transit spec
    star_spec = create.outTrans(pandexo_input['star'])
    #get rstar if user calling from grid 
    both_spec = create.bothTrans(star_spec, pandexo_input['planet'], star=pandexo_input['star'])
    out_spectrum = np.array([both_spec['wave'], both_spec['flux_out_trans']])
    
    #get transit duration from phase curve or from input 
    if calculation == 'phase_spec': 
        transit_duration = max(both_spec['time']) - min(both_spec['time'])
    else: 
        #convert to seconds, then remove quantity and convert back to float 
        transit_duration = float((pandexo_input['planet']['transit_duration']*u.Unit(pandexo_input['planet']['td_unit'])).to(u.second)/u.second)

    #amount of exposure time out-of-occultation, as a fraction of in-occ time 
    try:
        expfact_out = pandexo_input['observation']['fraction'] 
        print("WARNING: key input fraction has been replaced with new 'baseline option'. See notebook example")
        pandexo_input['observation']['baseline'] = pandexo_input['observation']['fraction'] 
        pandexo_input['observation']['baseline_unit'] ='frac'
    except:
        if pandexo_input['observation']['baseline_unit'] =='frac':
            expfact_out = pandexo_input['observation']['baseline'] 
        elif pandexo_input['observation']['baseline_unit'] =='total':
            expfact_out = transit_duration/( pandexo_input['observation']['baseline'] - transit_duration)
        elif pandexo_input['observation']['baseline_unit'] =='total_hrs':
            expfact_out = transit_duration/( pandexo_input['observation']['baseline']*3600.0 - transit_duration)
        else: 
            raise Exception("Wrong units for baseine: either 'frac' or 'total' or 'total_hrs' accepted")

    #add to pandeia input 
    pandeia_input['scene'][0]['spectrum']['sed']['spectrum'] = out_spectrum
    
    if isinstance(pandeia_input["configuration"]["detector"]["ngroup"], (float,int)):
        m = {"ngroup":pandeia_input["configuration"]["detector"]["ngroup"], "tframe":tframe,
            "nframe":nframe,"mingroups":mingroups,"nskip":nskip}
    else:
        #run pandeia once to determine max exposure time per int and get exposure params
        print("Optimization Reqested: Computing Duty Cycle")
        m = {"maxexptime_per_int":compute_maxexptime_per_int(pandeia_input, sat_level) , 
            "tframe":tframe,"nframe":nframe,"mingroups":mingroups,"nskip":nskip}
        print("Finished Duty Cycle Calc")

    #calculate all timing info
    timing, flags = compute_timing(m,transit_duration,expfact_out,noccultations)
    
    #Simulate out trans and in transit
    print("Starting Out of Transit Simulation")
    out = perform_out(pandeia_input, pandexo_input,timing, both_spec)
    
    #extract extraction area before dict conversion
    extraction_area = out.extraction_area
    out = out.as_dict()
    out.pop('3d')
    print("End out of Transit")

    #Remove effects of Quantum Yield from shot noise 
    out = remove_QY(out, instrument)

    #this kind of redundant going to compute inn from out instead 
    #keep perform_in but change inputs to (out, timing, both_spec)
    print("Starting In Transit Simulation")
    inn = perform_in(pandeia_input, pandexo_input,timing, both_spec, out, calculation)
    print("End In Transit")
    


    #compute warning flags for timing info 
    warnings = add_warnings(out, timing, sat_level/fullwell, flags, instrument) 

    compNoise = ExtractSpec(inn, out, rn, extraction_area, timing)
    
    #slope method is pandeia's pure noise calculation (taken from SNR)
    #contains correlated noise, RN, dark current, sky, 
    #uses MULTIACCUM formula so we deviated from this. 
    #could eventually come back to this if Pandeia adopts First-Last formula
    if calculation == 'slope method': 
        #Extract relevant info from pandeia output (1d curves and wavelength) 
        #extracted flux in units of electron/s
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_slope_method()

    #derives noise from 2d postage stamps. Doing this results in a higher 
    #1d flux rate than the Pandeia gets from extracting its own. 
    #this should be used to benchmark Pandeia's 1d extraction  
    elif calculation == '2d extract':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_2d_extract()
    
    #this is the noise calculation that PandExo uses online. It derives 
    #its own calculation of readnoise and does not use MULTIACUMM 
    #noise formula  
    elif calculation == 'fml':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_f_minus_l()
    
    elif calculation == 'phase_spec':
        result = compNoise.run_phase_spec()
        w = result['time']
    else:
        result = None
        raise Exception('WARNING: Calculation method not found.')
        
    varin = result['var_in_1d']
    varout = result['var_out_1d']
    extracted_flux_out = result['photon_out_1d']
    extracted_flux_inn = result['photon_in_1d']

        
    #bin the data according to user input 
    if R != None: 
        wbin = bin_wave_to_R(w, R)
        photon_out_bin = uniform_tophat_sum(wbin, w,extracted_flux_out)
        wbin = wbin[photon_out_bin > 0 ]
        photon_in_bin = uniform_tophat_sum(wbin,w, extracted_flux_inn)
        photon_in_bin = photon_in_bin[photon_out_bin > 0 ]
        var_in_bin = uniform_tophat_sum(wbin, w,varin)
        var_in_bin = var_in_bin[photon_out_bin > 0 ]
        var_out_bin = uniform_tophat_sum(wbin,w, varout)
        var_out_bin = var_out_bin[photon_out_bin > 0 ]
        photon_out_bin = photon_out_bin
    else: 
        wbin = w
        photon_out_bin = extracted_flux_out
        wbin = wbin[photon_out_bin>0]
        photon_in_bin = extracted_flux_inn
        photon_in_bin = photon_in_bin[photon_out_bin>0]
        var_in_bin = varin
        var_in_bin = var_in_bin[photon_out_bin>0]
        var_out_bin = varout
        var_out_bin = var_out_bin[photon_out_bin>0]
        photon_out_bin = photon_out_bin[photon_out_bin>0]
        
    
    if calculation == 'phase_spec':
        to = (timing["APT: Num Groups per Integration"]-1)*tframe
        ti = (timing["APT: Num Groups per Integration"]-1)*tframe
    else: 
        #otherwise error propagation and account for different 
        #times in transit and out 
        to = result['on_source_out']
        ti = result['on_source_in']
        
    var_tot = (to/ti/photon_out_bin)**2.0 * var_in_bin + (photon_in_bin*to/ti/photon_out_bin**2.0)**2.0 * var_out_bin
    error_spec = np.sqrt(var_tot)
        
    #factor in occultations to noise 
    nocc = timing['Number of Transits']
    error_spec = error_spec / np.sqrt(nocc)
        
    #Add in user specified noise floor 
    error_spec_nfloor = add_noise_floor(noise_floor, wbin, error_spec) 

    #add in random noise for the simulated spectrum 
    np.random.seed()
    rand_noise= error_spec_nfloor*(np.random.randn(len(wbin)))
    raw_spec = (photon_out_bin/to-photon_in_bin/ti)/(photon_out_bin/to)
    sim_spec = raw_spec + rand_noise 
    
    #if secondary tranist, multiply spectra by -1 
    if pandexo_input['planet']['f_unit'] == 'fp/f*':
        sim_spec = -1.0*sim_spec
        raw_spec = -1.0*raw_spec    
   
    #package processed data
    finalspec = {'wave':wbin,
              'spectrum': raw_spec,
              'spectrum_w_rand':sim_spec,
              'error_w_floor':error_spec_nfloor}
    
    rawstuff = {
                'electrons_out':photon_out_bin*nocc, 
                'electrons_in':photon_in_bin*nocc,
                'var_in':var_in_bin*nocc, 
                'var_out':var_out_bin*nocc,
                'e_rate_out':photon_out_bin/to,
                'e_rate_in':photon_out_bin/ti,
                'wave':wbin,
                'error_no_floor':error_spec, 
                'rn[out,in]':result['rn[out,in]'],
                'bkg[out,in]':result['bkg[out,in]']
                }
 
    result_dict = as_dict(out,both_spec ,finalspec, 
                timing, mag, sat_level, warnings,
                pandexo_input['planet']['f_unit'], rawstuff,calculation)

    return result_dict 
Exemple #3
0
def compute_full_sim(dictinput): 
    """Top level function to set up exoplanet obs. for JW
    
    Function to set up explanet observations for JWST only and 
    compute simulated spectrum. It uses STScI's Pandeia to compute 
    instrument throughputs and WebbPSF to compute PSFs. 
    
    Parameters
    ----------
    dictinput : dict
        dictionary containing instrument parameters and exoplanet specific 
        parameters. {"pandeia_input":dict1, "pandexo_input":dict1}
    
    Returns
    -------
    dict
        large dictionary with 1d, 2d simualtions, timing info, instrument info, warnings
    
    Examples
    --------  
      
    >>> from pandexo.engine.jwst import compute_full_sim 
    >>> from pandexo.engine.justplotit import jwst_1d_spec
    >>> a = compute_full_sim({"pandeia_input": pandeiadict, "pandexo_input":exodict})
    >>> jwst_1d_spec(a)
    .. image:: 1d_spec.png
    
    Notes
    -----
    It is much easier to run simulations through either **run_online** or **justdoit**. **justdoit** contains functions to create input dictionaries and **run_online** contains web forms to create input dictionaries.
    
    See Also
    -------- 
        pandexo.engine.justdoit.run_pandexo : Best function for running pandexo runs
        pandexo.engine.run_online : Allows running functions through online interface
    """
    pandeia_input = dictinput['pandeia_input']
    pandexo_input = dictinput['pandexo_input']    	
	
    #define the calculation we'll be doing 
    if pandexo_input['planet']['w_unit'] == 'sec':
        calculation = 'phase_spec'
    else: 
        calculation = pandexo_input['calculation'].lower()

    #which instrument 
    instrument = pandeia_input['configuration']['instrument']['instrument']
    conf = pandeia_input['configuration']
    
    #if optimize is in the ngroups section, this will throw an error 
    #so create temp conf with 2 groups 
    try:
        i = InstrumentFactory(config=conf)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()
    except: 
        conf_temp = deepcopy(conf) 
        conf_temp['detector']['ngroup'] = 2 
        i = InstrumentFactory(config=conf_temp)
        det_pars = i.get_detector_pars()
        exp_pars = i.get_exposure_pars()
        
    #detector parameters
    fullwell = det_pars['fullwell']
    rn = det_pars['rn']
    sat_level = pandexo_input['observation']['sat_level']/100.0*fullwell
    mingroups = det_pars['mingroups']
    
    #exposure parameters 
    tframe = exp_pars.tframe
    nframe = exp_pars.nframe
    nskip = exp_pars.nskip
    
    #parameteres needed from exo_input
    mag = pandexo_input['star']['mag']
    
    
    noccultations = pandexo_input['observation']['noccultations']
    R = pandexo_input['observation']['R']
    #amount of exposure time out-of-occultation, as a fraction of in-occ time 
    expfact_out = pandexo_input['observation']['fraction'] 
    noise_floor = pandexo_input['observation']['noise_floor']

    
    #get stellar spectrum and in transit spec
    star_spec = create.outTrans(pandexo_input['star'])
    both_spec = create.bothTrans(star_spec, pandexo_input['planet'])
    out_spectrum = np.array([both_spec['wave'], both_spec['flux_out_trans']])
    
    #get transit duration from phase curve or from input 
    if calculation == 'phase_spec': 
        transit_duration = max(both_spec['time']) - min(both_spec['time'])
    else: 
        transit_duration = pandexo_input['planet']['transit_duration']

    #add to pandeia input 
    pandeia_input['scene'][0]['spectrum']['sed']['spectrum'] = out_spectrum
    
    if isinstance(pandeia_input["configuration"]["detector"]["ngroup"], (float,int)):
        m = {"ngroup":pandeia_input["configuration"]["detector"]["ngroup"], "tframe":tframe,
            "nframe":nframe,"mingroups":mingroups,"nskip":nskip}
    else:
        #run pandeia once to determine max exposure time per int and get exposure params
        print("Optimization Reqested: Computing Duty Cycle")
        m = {"maxexptime_per_int":compute_maxexptime_per_int(pandeia_input, sat_level) , 
            "tframe":tframe,"nframe":nframe,"mingroups":mingroups,"nskip":nskip}
        print("Finished Duty Cycle Calc")

    #calculate all timing info
    timing, flags = compute_timing(m,transit_duration,expfact_out,noccultations)
    
    #Simulate out trans and in transit
    print("Starting Out of Transit Simulation")
    out = perform_out(pandeia_input, pandexo_input,timing, both_spec)
    
    #extract extraction area before dict conversion
    extraction_area = out.extraction_area
    out = out.as_dict()
    out.pop('3d')
    print("End out of Transit")

    #Remove effects of Quantum Yield from shot noise 
    out = remove_QY(out, instrument)

    #this kind of redundant going to compute inn from out instead 
    #keep perform_in but change inputs to (out, timing, both_spec)
    print("Starting In Transit Simulation")
    inn = perform_in(pandeia_input, pandexo_input,timing, both_spec, out, calculation)
    print("End In Transit")
    


    #compute warning flags for timing info 
    warnings = add_warnings(out, timing, sat_level/fullwell, flags, instrument) 

    compNoise = ExtractSpec(inn, out, rn, extraction_area, timing)
    
    #slope method is pandeia's pure noise calculation (taken from SNR)
    #contains correlated noise, RN, dark current, sky, 
    #uses MULTIACCUM formula so we deviated from this. 
    #could eventually come back to this if Pandeia adopts First-Last formula
    if calculation == 'slope method': 
        #Extract relevant info from pandeia output (1d curves and wavelength) 
        #extracted flux in units of electron/s
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_slope_method()

    #derives noise from 2d postage stamps. Doing this results in a higher 
    #1d flux rate than the Pandeia gets from extracting its own. 
    #this should be used to benchmark Pandeia's 1d extraction  
    elif calculation == '2d extract':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_2d_extract()
    
    #this is the noise calculation that PandExo uses online. It derives 
    #its own calculation of readnoise and does not use MULTIACUMM 
    #noise formula  
    elif calculation == 'fml':
        w = out['1d']['extracted_flux'][0]
        result = compNoise.run_f_minus_l()
    
    elif calculation == 'phase_spec':
        result = compNoise.run_phase_spec()
        w = result['time']
    else:
        result = None
        raise Exception('WARNING: Calculation method not found.')
        
    varin = result['var_in_1d']
    varout = result['var_out_1d']
    extracted_flux_out = result['photon_out_1d']
    extracted_flux_inn = result['photon_in_1d']

        
    #bin the data according to user input 
    if R != None: 
        wbin = bin_wave_to_R(w, R)
        photon_out_bin = uniform_tophat_sum(wbin, w,extracted_flux_out)
        wbin = wbin[photon_out_bin > 0 ]
        photon_in_bin = uniform_tophat_sum(wbin,w, extracted_flux_inn)
        photon_in_bin = photon_in_bin[photon_out_bin > 0 ]
        var_in_bin = uniform_tophat_sum(wbin, w,varin)
        var_in_bin = var_in_bin[photon_out_bin > 0 ]
        var_out_bin = uniform_tophat_sum(wbin,w, varout)
        var_out_bin = var_out_bin[photon_out_bin > 0 ]
        photon_out_bin = photon_out_bin
    else: 
        wbin = w
        photon_out_bin = extracted_flux_out
        wbin = wbin[photon_out_bin>0]
        photon_in_bin = extracted_flux_inn
        photon_in_bin = photon_in_bin[photon_out_bin>0]
        var_in_bin = varin
        var_in_bin = var_in_bin[photon_out_bin>0]
        var_out_bin = varout
        var_out_bin = var_out_bin[photon_out_bin>0]
        photon_out_bin = photon_out_bin[photon_out_bin>0]
    
    if calculation == 'phase_spec':
        to = timing["APT: Num Groups per Integration"]*tframe
        ti = timing["APT: Num Groups per Integration"]*tframe
    else: 
        #otherwise error propagation and account for different 
        #times in transit and out 
        to = result['on_source_out']
        ti = result['on_source_in']
        
    var_tot = (to/ti/photon_out_bin)**2.0 * var_in_bin + (photon_in_bin*to/ti/photon_out_bin**2.0)**2.0 * var_out_bin
    error_spec = np.sqrt(var_tot)
        
    #factor in occultations to noise 
    nocc = timing['Number of Transits']
    error_spec = error_spec / np.sqrt(nocc)
        
    #Add in user specified noise floor 
    error_spec_nfloor = add_noise_floor(noise_floor, wbin, error_spec) 

    #add in random noise for the simulated spectrum 
    rand_noise= error_spec_nfloor*(np.random.randn(len(wbin)))
    raw_spec = (photon_out_bin/to-photon_in_bin/ti)/(photon_out_bin/to)
    sim_spec = raw_spec + rand_noise 
    
    #if secondary tranist, multiply spectra by -1 
    if pandexo_input['planet']['f_unit'] == 'fp/f*':
        sim_spec = -1.0*sim_spec
        raw_spec = -1.0*raw_spec    
   
    #package processed data
    finalspec = {'wave':wbin,
              'spectrum': raw_spec,
              'spectrum_w_rand':sim_spec,
              'error_w_floor':error_spec_nfloor}
    
    rawstuff = {
                'electrons_out':photon_out_bin*nocc, 
                'electrons_in':photon_in_bin*nocc,
                'var_in':varin*nocc, 
                'var_out':varout*nocc,
                'e_rate_out':photon_out_bin/to,
                'e_rate_in':photon_out_bin/ti,
                'wave':w,
                'error_no_floor':error_spec, 
                'rn[out,in]':result['rn[out,in]'],
                'bkg[out,in]':result['bkg[out,in]']
                }
 
    result_dict = as_dict(out,both_spec ,finalspec, 
                timing, mag, sat_level, warnings,
                pandexo_input['planet']['f_unit'], rawstuff,calculation)

    return result_dict