示例#1
0
def womcho(hop):
    """choose region of spectrum with wavelengths or mouse"""
    import matplotlib.pyplot as plt
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    wave = hop[0].wave.copy()
    flux = hop[0].flux.copy()
    var = hop[0].var.copy()
    print('Current A/pix is {}'.format(wave[1] - wave[0]))
    wave, flux, mode = womwaverange(wave, flux, 'none')
    indexblue = womget_element(hop[0].wave, wave[0])
    indexred = womget_element(hop[0].wave, wave[-1])
    var = var[indexblue:indexred + 1].copy()
    print('Overplotting chosen section')
    plt.cla()
    plt.plot(hop[0].wave, hop[0].flux, drawstyle='steps-mid')
    plt.plot(wave, flux, drawstyle='steps-mid')
    plt.xlabel('Wavelength')
    plt.ylabel('Flux')
    plt.title(hop[0].obname)
    hop[0].wave = wave.copy()
    hop[0].flux = flux.copy()
    hop[0].var = var.copy()
    ##FIX header for fits
    return hop
def womint(hop):
    """calculate intensity in given wavelength range"""
    import logging
    import numpy as np
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    print(' ')
    logging.info('Object is {}'.format(hop[0].obname))
    print(' ')
    print('Spectrum runs from {} to {}'.format(hop[0].wave[0],
                                               hop[0].wave[-1]))
    print(' ')
    print('This routine expects the spectrum to be in flambda units.')
    print('It also expects a linear wavelength scale.')
    print(' ')
    print('Choose general region of spectrum\n')
    nwave, nflux, mode = womwaverange(hop[0].wave, hop[0].flux, 'none')
    print('\nNow pick the exact range for the intensity calculation')
    wavint, fluxint, mode = womwaverange(nwave, nflux, mode)
    indexblue = womget_element(nwave, wavint[0])
    indexred = womget_element(nwave, wavint[-1])
    wdelt = nwave[1] - nwave[0]
    lineflux = np.sum(nflux[indexblue:indexred + 1]) * wdelt
    linefluxin = np.sum(nflux[indexblue + 1:indexred]) * wdelt
    linefluxout = np.sum(nflux[indexblue - 1:indexred + 2]) * wdelt
    print(' ')
    logging.info('FWZI (approximate): {}'.format(nwave[indexred] -
                                                 nwave[indexblue]))
    logging.info('Line flux (ergs/sec/cm^2): {}'.format(lineflux))
    logging.info('Line flux one pixel in: {}'.format(linefluxin))
    logging.info('Line flux one pixel out: {}'.format(linefluxout))
    logging.info('Note that flux may need to be scaled by 1e-15')
    logging.info('Average difference (between line flux and one pixel')
    avgdiff = (np.abs(linefluxin - lineflux) +
               np.abs(linefluxout - lineflux)) / 2.0
    logging.info('in or out): {}'.format(avgdiff))
    logging.info('As a percentage of line flux: {}'.format(100.0 * avgdiff /
                                                           lineflux))
    return hop
def womvelcho(hop):
    """select region of spectrum, put onto velocity scale"""
    import matplotlib.pyplot as plt
    import numpy as np
    import logging
    from tmath.wombat.inputter import inputter
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat.womscipyrebin import womscipyrebin
    wave=hop[0].wave.copy()
    flux=hop[0].flux.copy()
    var=hop[0].var.copy()
    nwave,nflux,mode=womwaverange(wave,flux,'none')
    wavebindex=womget_element(wave,nwave[0])
    waverindex=womget_element(wave,nwave[-1])
    nvar=var[wavebindex:waverindex+1].copy()
    binvec=np.arange(len(nwave))
    wavelog=np.log(nwave[0])+((np.log(nwave[-1])-np.log(nwave[0]))/len(nwave))*binvec
    wavelog=np.exp(wavelog)
    fluxlog=womscipyrebin(nwave,nflux,wavelog)
    varlog=womscipyrebin(nwave,nvar,wavelog)
    zp=wavelog[0]-1.0
    while (zp < wavelog[0]) or (zp > wavelog[-1]):
        zp=inputter('Enter the zero point for velocity (in angstroms): ','float',False)
    indexzp=womget_element(wavelog, zp)
    print(' ')
    logging.info('Zero at bin {}'.format(indexzp))
    logging.info('with lambda {}'.format(wavelog[indexzp]))
    print(' ')
    z=(wavelog - zp)/zp
    square=(z+1)*(z+1)
    wavekmsrel=((square-1.)/(square+1.))*299792.458
    kmsperbin=np.zeros(len(nwave))
    for i in range(1,len(nwave)):
        kmsperbin[i]=2.0*2.99792458e5*(wavelog[i]-wavelog[i-1])/\
                      (wavelog[i]+wavelog[i-1])
    kmsmean=np.mean(kmsperbin[1:])
    logging.info('Average km/s per bin: {}'.format(kmsmean))
    logging.info('km/s at bin 1: {}'.format(kmsperbin[1]))
    logging.info('km/s at bin n: {}'.format(kmsperbin[-1]))
    print(' ')
    wavekms=kmsmean*binvec+kmsmean/2.0
    indexzp=womget_element(wavekms,zp)
    wavekms=wavekms-wavekms[indexzp]
    hop[0].wave=wavekmsrel.copy()
    hop[0].flux=fluxlog.copy()
    hop[0].var=varlog.copy()
    return hop
示例#4
0
def womstat(hop):
    """print statistics of region of spectrum"""
    import scipy.stats as st
    import numpy as np
    from tmath.wombat.womwaverange import womwaverange
    print('\nObject is {}'.format(hop[0].obname))
    print('\nEnter range for statistics: ')
    wave, flux, mode = womwaverange(hop[0].wave, hop[0].flux, 'none')
    print('\nMean: {}'.format(np.mean(flux)))
    print('Variance: {}'.format(np.var(flux, ddof=1)))
    print('Std. Dev.: {}'.format(np.std(flux, ddof=1)))
    print('Mean Dev.: {}'.format(np.mean(np.abs(flux - np.mean(flux)))))
    print('S/N: {}'.format(np.mean(flux) / np.std(flux, ddof=1)))
    #this is IRAF definition for S/N
    print('Skewness: {}'.format(st.skew(flux)))
    print('Kurtosis: {}'.format(st.kurtosis(flux)))
    print('Median: {}'.format(np.median(flux)))
    print('No. points: {}'.format(len(flux)))
    return hop
示例#5
0
def womexam(hop):
    """print spectrum bin values"""
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat.yesno import yesno
    done = False
    while (not done):
        answer = 'y'
        wave, flux, mode = womwaverange(hop[0].wave, hop[0].flux, 'none')
        indexblue = womget_element(hop[0].wave, wave[0])
        indexred = womget_element(hop[0].wave, wave[-1])
        var = hop[0].var[indexblue:indexred + 1]
        if (len(wave) > 30):
            print('This will print out {} values'.format(len(wave)))
            print('Do you really want to do that?')
            answer = yesno('n')
        if (answer == 'y'):
            done = True
    print('\nWave    Flux')
    for i, _ in enumerate(wave):
        print('{} {} {}'.format(wave[i], flux[i], var[i]))
    return hop
def womblo(hop, fig):
    """blotch out bad data"""
    import logging
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.interpolate import splrep, splev
    from tmath.wombat.inputter_single import inputter_single
    from tmath.wombat.waveparse import waveparse
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat.yesno import yesno
    global nsplinepoints, tmpsplptsx, tmpsplptsy, pflag
    print('Select regions to blotch')
    wave = hop[0].wave.copy()
    flux = hop[0].flux.copy()
    done = False
    while (not done):
        plt.cla()
        plt.plot(wave, flux, drawstyle='steps-mid')
        plt.xlabel('Wavelength')
        plt.ylabel('Flux')
        plt.title(hop[0].obname)
        wavesub, fluxsub, mode = womwaverange(wave, flux, 'none')
        wavebind = womget_element(wave, wavesub[0])
        waverind = womget_element(wave, wavesub[-1])
        plt.cla()
        plt.plot(wave[wavebind:waverind+1],flux[wavebind:waverind+1], \
                 drawstyle='steps-mid')
        plt.xlabel('Wavelength')
        plt.ylabel('Flux')
        plt.title(hop[0].obname)
        plt.pause(0.01)
        print('Do you want to enter blotch wavelengths by hand (w),')
        print('mark points (m), fit a spline (s), or quit (q)?')
        choice = inputter_single('(w/m/s/q): ', 'wmsq')
        if (choice == 'w') or (choice == 'm'):
            blotchgood = False
            while (not blotchgood):
                wavechoicedone = False
                while (not wavechoicedone):
                    if (choice == 'w'):
                        waveselb, waveselr = waveparse()
                    else:
                        print('Mark the two endpoints of the blotch region')
                        endpoints = plt.ginput(2, timeout=-1)
                        waveselb = endpoints[0][0]
                        waveselr = endpoints[1][0]
                    if (waveselb > waveselr):
                        waveselb, waveselr = waveselr, waveselb
                    waveselbind = womget_element(wave, waveselb)
                    waveselrind = womget_element(wave, waveselr)
                    print(waveselb, waveselr, waveselbind, waveselrind)
                    if (waveselbind == 0) or (waveselrind == (len(wave) - 1)):
                        print('Wavelengths incorrect--too close to endpoints')
                    else:
                        wavechoicedone = True
                contblue = flux[waveselbind - 1]
                contred = flux[waveselrind + 1]
                delta = (contred - contblue) / (waveselrind - waveselbind + 1)
                fluxcor = flux.copy()
                for i in range(waveselbind, waveselrind + 1):
                    fluxcor[i] = contblue + (i - waveselbind + 1) * delta
                plt.plot(wave[wavebind:waverind+1],fluxcor[wavebind:waverind+1], \
                 drawstyle='steps-mid')
                plt.pause(0.01)
                print('Is this acceptable')
                answer = yesno('y')
                if (answer == 'y'):
                    flux = fluxcor.copy()
                    blotchgood = True
                    logging.info('File {} blotched from {} to {}'.format(
                        hop[0].obname, wave[waveselbind], wave[waveselrind]))
        elif (choice == 's'):
            xmin, xmax = plt.xlim()
            ymin, ymax = plt.ylim()
            plt.xlim([xmin, xmax])
            plt.ylim([ymin, ymax])
            nsplinepoints = 0
            tmpsplptsx = []
            tmpsplptsy = []

            spldone = False
            while (not spldone):
                plt.cla()
                plt.plot(wave[wavebind:waverind+1],flux[wavebind:waverind+1], \
                         drawstyle='steps-mid')
                if (len(tmpsplptsx) > 0):
                    plt.plot(tmpsplptsx, tmpsplptsy, 'ro')
                plt.xlabel('Wavelength')
                plt.ylabel('Flux')
                plt.title(hop[0].obname)
                plt.xlim([xmin, xmax])
                plt.ylim([ymin, ymax])
                cid = fig.canvas.mpl_connect('button_press_event', onclick)
                print('\nClick on continuum points for spline fit.')
                print(
                    'Spline will replace values between first and last point')
                print('Left button    = add point')
                print('Middle button  = delete point')
                print('Right button   = done\n')
                pflag = ''
                while (pflag != 'done'):
                    plt.pause(0.01)
                fig.canvas.mpl_disconnect(cid)

                splptsy = [z for _, z in sorted(zip(tmpsplptsx, tmpsplptsy))]
                splptsx = sorted(tmpsplptsx)
                spline = splrep(splptsx, splptsy, k=3)
                splblueindex = womget_element(wave, splptsx[0])
                splredindex = womget_element(wave, splptsx[-1])
                splwave = wave[splblueindex:splredindex + 1].copy()
                splineresult = splev(splwave, spline)
                fluxcor = flux.copy()
                fluxcor[splblueindex:splredindex + 1] = splineresult.copy()
                plt.plot(splwave, splineresult, drawstyle='steps-mid')
                print('Is this acceptable')
                answer = yesno('y')
                if (answer == 'y'):
                    flux = fluxcor.copy()
                    spldone = True
                    logging.info(
                        'File {} blotched  with spline from {} to {}'.format(
                            hop[0].obname, wave[splblueindex],
                            wave[splredindex]))
        else:
            done = True
        print('Do another region?')
        another = yesno('n')
        if (another == 'n'):
            done = True
    hop[0].flux = flux.copy()
    return hop
def womscale2match(hop):
    """scale one spectrum to match another"""
    import matplotlib.pyplot as plt
    import numpy as np
    import logging
    from tmath.wombat.inputter import inputter
    from tmath.wombat.inputter_single import inputter_single
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat import HOPSIZE
    print('This will scale one hopper to match another')
    done = False
    while (not done):
        hopnum1 = inputter('Enter first hopper: ', 'int', False)
        hopnum2 = inputter('Enter second hopper: ', 'int', False)
        if (hopnum1 < 1) or (hopnum1 > HOPSIZE) or (hopnum2 < 1) or \
           (hopnum2 > HOPSIZE):
            print('Hopper numbers must be in range 1-{}'.format(HOPSIZE))
        else:
            done = True
    if (hop[hopnum1].wave[0] != hop[hopnum2].wave[0]) or \
       (hop[hopnum1].wave[1] != hop[hopnum2].wave[1]) or \
       (hop[hopnum1].wave[-1] != hop[hopnum2].wave[-1]):
        print('Hoppers to not have the same wavelength scale!')
        return hop
    print('\nSpectra run from {} to {}'.format(hop[hopnum1].wave[0], \
                                             hop[hopnum1].wave[-1]))

    plt.cla()
    plt.plot(hop[hopnum1].wave,hop[hopnum1].flux,drawstyle='steps-mid', \
             color='k')
    plt.xlabel('Wavelength')
    plt.ylabel('Flux')
    plt.title(hop[hopnum1].obname)
    plt.plot(hop[hopnum2].wave,hop[hopnum2].flux,drawstyle='steps-mid', \
             color='r')
    print('\nHopper A in black, hopper B in red')
    print('\nChoose region to compute average')
    wave, flux, mode = womwaverange(hop[hopnum1].wave, hop[hopnum1].flux,
                                    'none')
    indexblue = womget_element(hop[hopnum1].wave, wave[0])
    indexred = womget_element(hop[hopnum1].wave, wave[-1])
    avg1 = np.mean(hop[hopnum1].flux[indexblue:indexred + 1])
    avg2 = np.mean(hop[hopnum2].flux[indexblue:indexred + 1])
    print('\n Hopper A: {}'.format(avg1))
    print('\n Hopper B: {}'.format(avg2))
    choice = inputter_single('Scale to (A) or (B) ', 'ab')
    print(' ')
    done = False
    while (not done):
        hopnum3 = inputter('Store scaled spec in which hopper? ', 'int', False)
        if (hopnum3 < 1) or (hopnum3 > HOPSIZE):
            print('Hopper numbers must be in range 1-{}'.format(HOPSIZE))
        else:
            done = True
    if (choice == 'a'):
        hop[hopnum3].flux = hop[hopnum2].flux * (avg1 / avg2).copy()
        print('Scale: {}'.format(avg1 / avg2))
        hop[hopnum3].obname = hop[hopnum2].obname
        hop[hopnum3].header = hop[hopnum2].header
        hop[hopnum3].var = hop[hopnum2].var * (avg1 / avg2).copy()
        lstring='File: {} scaled by {} to match {}'.format(hop[hopnum2], \
                                                           avg1/avg2, \
                                                           hop[hopnum1])
    else:
        hop[hopnum3].flux = hop[hopnum1].flux * (avg2 / avg1).copy()
        print('Scale: {}'.format(avg1 / avg2))
        hop[hopnum3].obname = hop[hopnum1].obname
        hop[hopnum3].header = hop[hopnum1].header
        hop[hopnum3].var = hop[hopnum1].var * (avg2 / avg1).copy()
        lstring='File: {} scaled by {} to match {}'.format(hop[hopnum1].obname, \
                                                           avg2/avg1, \
                                                           hop[hopnum2].obname)
    hop[hopnum3].wave = hop[hopnum1].wave.copy()
    logging.debug(lstring)
    return hop
示例#8
0
def womgau(hop):
    """fit gaussian to line"""
    import numpy as np
    import logging
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat.inputter import inputter
    from tmath.wombat.inputter_single import inputter_single
    from tmath.wombat.gauss import gauss
    from tmath.wombat.gauss_cont import gauss_cont
    from tmath.wombat.yesno import yesno
    print(' ')
    logging.info('Object is {}'.format(hop[0].obname))
    print(' ')
    print('Spectrum runs from {} to {}'.format(hop[0].wave[0],
                                               hop[0].wave[-1]))
    print(' ')
    print('This routine expects the spectrum to be in flambda units.')
    print('It also expects a linear wavelength scale.')
    print(' ')
    print('Choose general region of spectrum\n')
    nwave, nflux, mode = womwaverange(hop[0].wave, hop[0].flux, 'none')
    print('\nNow pick the exact range for the fit')
    waveint, fluxint, mode = womwaverange(nwave, nflux, mode)
    indexblue = womget_element(nwave, waveint[0])
    indexred = womget_element(nwave, waveint[-1])
    if (mode == 'w'):
        done = False
        while (not done):
            print(' ')
            wavecenter = inputter('Enter approximate center of Gaussian : ',
                                  'float', False)
            indexcenter = womget_element(waveint, wavecenter)
            if (indexcenter <= 0) or (wavecenter > waveint[-1]):
                print('Bad central wavelength, try again')
            else:
                done = True
    else:
        done = False
        while (not done):
            print('Mark the approximate center of the Gaussian')
            pickcent = plt.ginput(1, timeout=-1)
            indexcenter = womget_element(waveint, pickcent[0][0])
            print('\nApproximate center at {}'.format(waveint[indexcenter]))
            print('\nIs this OK?')
            answer = yesno('y')
            if (answer == 'y'):
                done = True
    weights = np.sqrt(hop[0].var[indexblue:indexred + 1])
    print(' ')
    continuum = inputter_single(
        'Do you want to fit gaussian with (c)ontinuum, or (n)o continuum? ',
        'cn')
    if (continuum == 'c'):
        p = [fluxint[indexcenter], waveint[indexcenter], 3.0, 1.0, waveint[0]]
        result = curve_fit(gauss_cont,
                           waveint,
                           fluxint,
                           sigma=weights,
                           p0=p,
                           absolute_sigma=True,
                           full_output=True)
    else:
        p = [fluxint[indexcenter], waveint[indexcenter], 3.0]
        result = curve_fit(gauss,
                           waveint,
                           fluxint,
                           sigma=weights,
                           p0=p,
                           absolute_sigma=True,
                           full_output=True)
    coefferr = np.sqrt(np.diag(result[1]))
    coeff = result[0]
    # make 'finer-grained' version of fit, 0.2A/pix for calculations
    wavecalc = np.arange(2 * 5 * 50 * abs(
        coeff[2])) * 0.2 + coeff[1] - 0.2 * 5 * 50 * abs(coeff[2])
    calccenter = womget_element(wavecalc, coeff[1])
    if (continuum == 'c'):
        fluxcalc = gauss_cont(wavecalc, *coeff)
        fluxcont = wavecalc * coeff[3] + coeff[4]
        fluxgaussian = fluxcalc - fluxcont
        linecont = fluxcont[calccenter]
    else:
        fluxcalc = gauss(wavecalc, *coeff)

    deltafit = wavecalc[1] - wavecalc[0]
    calcindexblue = womget_element(wavecalc, waveint[0])
    calcindexred = womget_element(wavecalc, waveint[-1])
    sumfluxcalc = np.sum(fluxcalc[calcindexblue:calcindexred + 1] * deltafit)
    sumallfluxcalc = np.sum(fluxcalc * deltafit)
    chi = (result[2]['fvec']**2).sum()
    redchi = chi / (len(waveint) - len(coeff))
    if (continuum == 'c'):
        sumfluxgaussian = np.sum(fluxgaussian[calcindexblue:calcindexred + 1] *
                                 deltafit)
        sumallfluxgaussian = np.sum(fluxgaussian * deltafit)
        sumfluxcont = np.sum(fluxcont[calcindexblue:calcindexred + 1] *
                             deltafit)
        sumallfluxcont = np.sum(fluxcont * deltafit)
        # propagate uncertainty (from old version) not sure this is correct
        height_pct = coefferr[0] / coeff[0]
        sigma_pct = coefferr[2] / coeff[2]
        flux_pct = np.sqrt(height_pct**2 + sigma_pct**2)
        sumfluxgaussiansig = sumfluxgaussian * flux_pct
        sumallfluxgaussiansig = sumallfluxgaussian * flux_pct
    plt.cla()
    plt.plot(nwave, nflux, drawstyle='steps-mid', color='k')
    plt.ylabel('Flux')
    plt.xlabel('Wavelength')
    xmin, xmax = plt.xlim()
    ymin, ymax = plt.ylim()
    plt.plot(wavecalc, fluxcalc, drawstyle='steps-mid', color='b')
    if (continuum == 'c'):
        plt.plot(wavecalc, fluxgaussian, drawstyle='steps-mid', color='r')
        plt.plot(wavecalc, fluxcont, drawstyle='steps-mid', color='g')
    plt.plot([waveint[0], waveint[0]], [ymin, ymax], color='k', linestyle='--')
    plt.plot([waveint[-1], waveint[-1]], [ymin, ymax],
             color='k',
             linestyle='--')
    plt.xlim([xmin, xmax])
    plt.ylim([ymin, ymax])
    logging.info('For object {} Gaussian fit'.format(hop[0].obname))
    if (continuum == 'c'):
        print(
            '\nData = Black, Fit = Blue, Continuum = Green, Fit-Continuum = Red\n'
        )
    else:
        print('\nData = Black, Fit = Blue\n')
    logging.info('Height      {:16.8f}+/-{:16.8f}'.format(
        coeff[0], coefferr[0]))
    logging.info('Center      {:16.8f}+/-{:16.8f}'.format(
        coeff[1], coefferr[1]))
    logging.info('Sigma       {:16.8f}+/-{:16.8f}'.format(
        coeff[2], coefferr[2]))
    if (continuum == 'c'):
        logging.info('Slope       {:16.8f}+/-{:16.8f}'.format(
            coeff[3], coefferr[3]))
        logging.info('Y-intercept {:16.8f}+/-{:16.8f}'.format(
            coeff[4], coefferr[4]))
        logging.info('FWHM        {:16.8f}+/-{:16.8f}'.format(
            2.35482 * np.abs(coeff[2]), 2.35482 * coefferr[2]))
        logging.info(
            'Flux between dotted lines (Gaussian): {:16.8f}+/-{:16.8f}'.format(
                sumfluxgaussian, sumfluxgaussiansig))
        logging.info('EW between dotted lines (Gaussian): {:16.8f}'.format(
            sumfluxgaussian / linecont))
        logging.info('Flux for full (Gaussian): {:16.8f}+/-{:16.8f}'.format(
            sumallfluxgaussian, sumallfluxgaussiansig))
        logging.info('EW for full (Gaussian): {:16.8f}'.format(
            sumallfluxgaussian / linecont))
        logging.info(
            'Continuum flux at line center: {:16.8f}'.format(linecont))
    logging.info('Chi^2: {}'.format(chi))
    logging.info('Reduced chi^2: {}'.format(redchi))
    logging.info('All fluxes might need to be scaled by 1e-15')
    print(' ')
    return hop
def womscalemany(hop):
    """scale many hoppers to one"""
    import matplotlib.pyplot as plt
    import numpy as np
    import logging
    from tmath.wombat.inputter import inputter
    from tmath.wombat.womwaverange import womwaverange
    from tmath.wombat.womget_element import womget_element
    from tmath.wombat import HOPSIZE
    print('This will scale many hoppers to one')
    done = False
    while (not done):
        hopnum1 = inputter('Enter fiducial hopper: ', 'int', False)
        if (hopnum1 < 1) or (hopnum1 > HOPSIZE):
            print('Hopper number must be in range 1-{}'.format(HOPSIZE))
        else:
            done = True
    hoplist = []
    hopnum2 = 0
    while (hopnum2 != 99):
        done = False
        while (not done):
            hopnum2 = inputter('Enter another hopper: (99 to end) ', 'int',
                               False)
            if (hopnum2 != 99):
                if (hopnum2 < 1) or (hopnum2 > HOPSIZE):
                    print(
                        'Hopper numbers must be in range 1-{}'.format(HOPSIZE))
                elif (len(hop[hopnum2].wave) == 0):
                    print('Nothing in that hopper')
                else:
                    hoplist.append(hopnum2)
                    done = True
                if (hopnum2 > 0) and (hopnum2 < 21) and \
                   (len(hop[hopnum2].wave) != 0):
                    if (hop[hopnum1].wave[0] != hop[hopnum2].wave[0])  \
                       or (hop[hopnum1].wave[1] != hop[hopnum2].wave[1]) \
                       or (hop[hopnum1].wave[-1] != hop[hopnum2].wave[-1]):
                        print('Hoppers to not have the same wavelength scale!')
                        return hop
            else:
                done = True
    print('\nSpectra run from {} to {}'.format(hop[hopnum1].wave[0], \
                                             hop[hopnum1].wave[-1]))

    plt.cla()
    plt.plot(hop[hopnum1].wave,hop[hopnum1].flux,drawstyle='steps-mid', \
             color='k')
    plt.xlabel('Wavelength')
    plt.ylabel('Flux')
    plt.title(hop[hopnum1].obname)
    print('\nPlotting fiducial spectrum')
    print('\nChoose region to compute average')
    wave, flux, mode = womwaverange(hop[hopnum1].wave, hop[hopnum1].flux,
                                    'none')
    indexblue = womget_element(hop[hopnum1].wave, wave[0])
    indexred = womget_element(hop[hopnum1].wave, wave[-1])
    avg1 = np.mean(hop[hopnum1].flux[indexblue:indexred + 1])
    print('Fiducial spectrum mean in range: {}'.format(avg1))
    for i, _ in enumerate(hoplist):
        print('{} {}'.format(i, hoplist[i]))
        avgloop = np.mean(hop[hoplist[i]].flux[indexblue:indexred + 1])
        print('Hopper {} mean in range: {}'.format(hoplist[i], avgloop))
        hop[hoplist[i]].flux = hop[hoplist[i]].flux * avg1 / avgloop
        hop[hoplist[i]].var = hop[hoplist[i]].var * avg1 / avgloop
        logging.debug('File: {} scaled by {} to match {}'.format(
            hop[hoplist[i]].obname, avg1 / avgloop, hop[hopnum1].obname))
    return hop