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
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
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
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