Example #1
0
def synth(*args,**kwargs):
    """
    NAME:
       synth
    PURPOSE:
       Generate model APOGEE spectra using MOOG: this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'moogsynth' for a direct interface to MOOG
    INPUT ARGUMENTS:
       lists with abundances wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          linelist= (None) linelist to use; can be set to the path of a linelist file or to the name of an APOGEE linelist
          run_weedout= (False) if True, run MOOG weedout on the linelist first
          wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
          lib= ('kurucz_filled') spectral library
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere or to a model-atmosphere instance (if filename, needs to end in .mod)
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format
                 lib= ('kurucz_filled') model atmosphere library
                 dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
    OUTPUT:
       spectra (nspec,nwave)
    HISTORY:
       2015-03-15 - Written - Bovy (IAS)
    """
    run_weedout= kwargs.pop('run_weedout',False)
    # Check that we have the LSF and store the relevant keywords
    lsf= kwargs.pop('lsf','all')
    if isinstance(lsf,str):
        xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf)
        dxlsf= None
    else:
        xlsf= kwargs.pop('xlsf',None)
        dxlsf= kwargs.pop('dxlsf',None)
        if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array')
    vmacro= kwargs.pop('vmacro',6.)
    # Parse continuum-normalization keywords
    cont= kwargs.pop('cont','aspcap')
    # Setup the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    tmpModelAtmDir= False
    # Parse fparam, if present
    fparam= kwargs.pop('fparam',None)
    if not fparam is None:
        kwargs['teff']= fparam[paramIndx('TEFF')]
        kwargs['logg']= fparam[paramIndx('LOGG')]
        kwargs['metals']= fparam[paramIndx('METALS')]
        kwargs['am']= fparam[paramIndx('ALPHA')]
        kwargs['cm']= fparam[paramIndx('C')]
        kwargs['vm']= 10.**fparam[paramIndx('LOG10VDOP')]        
    if modelatm is None: # Setup a model atmosphere
        modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.),
                                          logg=kwargs.get('logg',2.5),
                                          metals=kwargs.get('metals',0.),
                                          am=kwargs.get('am',0.),
                                          cm=kwargs.get('cm',0.),
                                          dr=kwargs.get('dr',None))
    if isinstance(modelatm,str) and os.path.exists(modelatm):
        modelfilename= modelatm
    elif isinstance(modelatm,str):
        raise ValueError('modelatm= input is a non-existing filename')
    else: # model atmosphere instance
        # Need to write this instance to a file; we will run in a temp 
        # subdirectory of the current directory
        tmpDir= tempfile.mkdtemp(dir=os.getcwd())
        tmpModelAtmDir= True # need to remove this later
        modelfilename= os.path.join(tmpDir,'modelatm.mod')
        modelatm.writeto(modelfilename)
    kwargs['modelatm']= modelfilename
    try:
        # Check whether a MOOG version of the model atmosphere exists
        if not os.path.exists(modelfilename.replace('.mod','.org')):
            # Convert to MOOG format
            convert_modelAtmosphere(**kwargs)
        # Run weedout on the linelist first if requested
        if run_weedout:
            linelistfilename= modelfilename.replace('.mod','.lines')
            if not os.path.exists(linelistfilename):
                weedout(**kwargs)
            kwargs['linelist']= linelistfilename
        # Run MOOG synth for all abundances
        if len(args) == 0: #special case that there are *no* differences
            args= ([26,0.],)
        nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))])
        nsynth= numpy.amax(nsynths) #Take the longest abundance list
        nmoogwav= int((kwargs.get('wmax',_WMAX_DEFAULT)\
                           -kwargs.get('wmin',_WMIN_DEFAULT))\
                          /kwargs.get('dw',_DW_DEFAULT)+1)
        out= numpy.empty((nsynth,nmoogwav))
        # Check whether the number of syntheses is > 5 and run multiple 
        # MOOG instances if necessary, bc MOOG only does 5 at a time
        ninstances= int(numpy.ceil(nsynth/5.))
        for ii in range(ninstances):
            newargs= ()
            for jj in range(len(args)):
                tab= [args[jj][0]]
                if len(args[jj][5*ii+1:5*(ii+1)+1]) > 0:
                    tab.extend(args[jj][5*ii+1:5*(ii+1)+1])
                    newargs= newargs+(tab,)
            out[5*ii:5*(ii+1)]= moogsynth(*newargs,**kwargs)[1] 
            # We'll grab the wavelength grid from the continuum below
        # Now compute the continuum and multiply each c-norm spectrum with it
        mwav, cflux= moogsynth(doflux=True,**kwargs)
    except: raise
    finally:
        if tmpModelAtmDir: # need to remove this temporary directory
            os.remove(modelfilename)
        moogmodelfilename= modelfilename.replace('.mod','.org')
        if os.path.exists(moogmodelfilename):
            os.remove(moogmodelfilename)
        if run_weedout:
            os.remove(modelfilename.replace('.mod','.lines'))
        os.rmdir(tmpDir)
    out*= numpy.tile(cflux,(nsynth,1))
    # Now convolve with the LSF
    out= aplsf.convolve(mwav,out,
                        lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave= apStarWavegrid()
        baseline= numpy.polynomial.Polynomial.fit(mwav,cflux,4)
        ip= interpolate.InterpolatedUnivariateSpline(mwav,
                                                     cflux/baseline(mwav),
                                                     k=3)
        cflux= baseline(apWave)*ip(apWave)
        # Divide it out
        out/= numpy.tile(cflux,(nsynth,1))
    elif not cont is None:
        cflux= apcont.fit(out,numpy.ones_like(out),type=cont)
        out[cflux > 0.]/= cflux[cflux > 0.]
        out[cflux <= 0.]= numpy.nan
    return out
Example #2
0
def synth(*args, **kwargs):
    """
    NAME:
       synth
    PURPOSE:
       Generate model APOGEE spectra using MOOG: this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'moogsynth' for a direct interface to MOOG
    INPUT ARGUMENTS:
       lists with abundances wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          linelist= (None) linelist to use; can be set to the path of a linelist file or to the name of an APOGEE linelist
          run_weedout= (False) if True, run MOOG weedout on the linelist first
          wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
          lib= ('kurucz_filled') spectral library
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere or to a model-atmosphere instance (if filename, needs to end in .mod)
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format
                 lib= ('kurucz_filled') model atmosphere library
                 dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
    OUTPUT:
       spectra (nspec,nwave)
    HISTORY:
       2015-03-15 - Written - Bovy (IAS)
    """
    run_weedout = kwargs.pop('run_weedout', False)
    # Check that we have the LSF and store the relevant keywords
    lsf = kwargs.pop('lsf', 'all')
    if isinstance(lsf, str):
        xlsf, lsf = aplsf._load_precomp(dr=kwargs.get('dr', None), fiber=lsf)
        dxlsf = None
    else:
        xlsf = kwargs.pop('xlsf', None)
        dxlsf = kwargs.pop('dxlsf', None)
        if xlsf is None and dxlsf is None:
            raise ValueError(
                'xlsf= or dxlsf= input needs to be given if the LSF is given as an array'
            )
    vmacro = kwargs.pop('vmacro', 6.)
    # Parse continuum-normalization keywords
    cont = kwargs.pop('cont', 'aspcap')
    # Setup the model atmosphere
    modelatm = kwargs.pop('modelatm', None)
    tmpModelAtmDir = False
    # Parse fparam, if present
    fparam = kwargs.pop('fparam', None)
    if not fparam is None:
        kwargs['teff'] = fparam[paramIndx('TEFF')]
        kwargs['logg'] = fparam[paramIndx('LOGG')]
        kwargs['metals'] = fparam[paramIndx('METALS')]
        kwargs['am'] = fparam[paramIndx('ALPHA')]
        kwargs['cm'] = fparam[paramIndx('C')]
        kwargs['vm'] = 10.**fparam[paramIndx('LOG10VDOP')]
    if modelatm is None:  # Setup a model atmosphere
        modelatm = atlas9.Atlas9Atmosphere(teff=kwargs.get('teff', 4500.),
                                           logg=kwargs.get('logg', 2.5),
                                           metals=kwargs.get('metals', 0.),
                                           am=kwargs.get('am', 0.),
                                           cm=kwargs.get('cm', 0.),
                                           dr=kwargs.get('dr', None))
    if isinstance(modelatm, str) and os.path.exists(modelatm):
        modelfilename = modelatm
    elif isinstance(modelatm, str):
        raise ValueError('modelatm= input is a non-existing filename')
    else:  # model atmosphere instance
        # Need to write this instance to a file; we will run in a temp
        # subdirectory of the current directory
        tmpDir = tempfile.mkdtemp(dir=os.getcwd())
        tmpModelAtmDir = True  # need to remove this later
        modelfilename = os.path.join(tmpDir, 'modelatm.mod')
        modelatm.writeto(modelfilename)
    kwargs['modelatm'] = modelfilename
    try:
        # Check whether a MOOG version of the model atmosphere exists
        if not os.path.exists(modelfilename.replace('.mod', '.org')):
            # Convert to MOOG format
            convert_modelAtmosphere(**kwargs)
        # Run weedout on the linelist first if requested
        if run_weedout:
            linelistfilename = modelfilename.replace('.mod', '.lines')
            if not os.path.exists(linelistfilename):
                weedout(**kwargs)
            kwargs['linelist'] = linelistfilename
        # Run MOOG synth for all abundances
        if len(args) == 0:  #special case that there are *no* differences
            args = ([26, 0.], )
        nsynths = numpy.array([len(args[ii]) - 1 for ii in range(len(args))])
        nsynth = numpy.amax(nsynths)  #Take the longest abundance list
        nmoogwav= int((kwargs.get('wmax',_WMAX_DEFAULT)\
                           -kwargs.get('wmin',_WMIN_DEFAULT))\
                          /kwargs.get('dw',_DW_DEFAULT)+1)
        out = numpy.empty((nsynth, nmoogwav))
        # Check whether the number of syntheses is > 5 and run multiple
        # MOOG instances if necessary, bc MOOG only does 5 at a time
        ninstances = int(numpy.ceil(nsynth / 5.))
        for ii in range(ninstances):
            newargs = ()
            for jj in range(len(args)):
                tab = [args[jj][0]]
                if len(args[jj][5 * ii + 1:5 * (ii + 1) + 1]) > 0:
                    tab.extend(args[jj][5 * ii + 1:5 * (ii + 1) + 1])
                    newargs = newargs + (tab, )
            out[5 * ii:5 * (ii + 1)] = moogsynth(*newargs, **kwargs)[1]
            # We'll grab the wavelength grid from the continuum below
        # Now compute the continuum and multiply each c-norm spectrum with it
        mwav, cflux = moogsynth(doflux=True, **kwargs)
    except:
        raise
    finally:
        if tmpModelAtmDir:  # need to remove this temporary directory
            os.remove(modelfilename)
        moogmodelfilename = modelfilename.replace('.mod', '.org')
        if os.path.exists(moogmodelfilename):
            os.remove(moogmodelfilename)
        if run_weedout:
            os.remove(modelfilename.replace('.mod', '.lines'))
        os.rmdir(tmpDir)
    out *= numpy.tile(cflux, (nsynth, 1))
    # Now convolve with the LSF
    out = aplsf.convolve(mwav,
                         out,
                         lsf=lsf,
                         xlsf=xlsf,
                         dxlsf=dxlsf,
                         vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave = apStarWavegrid()
        baseline = numpy.polynomial.Polynomial.fit(mwav, cflux, 4)
        ip = interpolate.InterpolatedUnivariateSpline(mwav,
                                                      cflux / baseline(mwav),
                                                      k=3)
        cflux = baseline(apWave) * ip(apWave)
        # Divide it out
        out /= numpy.tile(cflux, (nsynth, 1))
    elif not cont is None:
        cflux = apcont.fit(out, numpy.ones_like(out), type=cont)
        out[cflux > 0.] /= cflux[cflux > 0.]
        out[cflux <= 0.] = numpy.nan
    return out
Example #3
0
def windows(*args,**kwargs):
    """
    NAME:
       windows
    PURPOSE:
       Generate model APOGEE spectra using MOOG in selected wavelength windows (but the whole APOGEE spectral range is returned): this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'moogsynth' for a direct interface to MOOG
    INPUT ARGUMENTS:
       Windows specification: Provide one of
          (1) Element string: the APOGEE windows for this element will be loaded
          (2) startindxs, endindxs= start and end indexes of the windows on the apStar wavelength grid
          (3) startlams, endlams= start and end wavelengths in \AA
       lists with abundance differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       BASELINE: you can specify the baseline spectrum to not always re-compute it
          baseline= baseline c-normalized spectrum on MOOG wavelength grid (obtained from moogsynth)
          mwav= MOOG wavelength grid (obtained from moogsynth)
          cflux= continuum flux from MOOG
          Typically, you can obtain these three keywords by doing (kwargs are the keywords you provide to this function as well)
          >>> baseline= moogsynth(**kwargs)[1]
          >>> mwav, cflux= moogsynth(doflux=True,**kwargs)
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          linelist= (None) linelist to use; if this is None, the code looks for a weed-out version of the linelist appropriate for the given model atmosphere
          run_weedout= (False) if True, run MOOG weedout on the linelist first
          wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits *for the whole spectrum* (not just the windows), step, and width of calculation (see MOOG)
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere or to a model-atmosphere instance (if filename, needs to end in .mod)
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format (
                 lib= ('kurucz_filled') model atmosphere library
                 dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
    OUTPUT:
       spectra (nspec,nwave)
    HISTORY:
       2015-03-18 - Written - Bovy (IAS)
    """
    # Pop some kwargs
    run_weedout= kwargs.pop('run_weedout',False)
    baseline= kwargs.pop('baseline',None)
    mwav= kwargs.pop('mwav',None)
    cflux= kwargs.pop('cflux',None)
    # Check that we have the LSF and store the relevant keywords
    lsf= kwargs.pop('lsf','all')
    if isinstance(lsf,str):
        xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf)
        dxlsf= None
    else:
        xlsf= kwargs.pop('xlsf',None)
        dxlsf= kwargs.pop('dxlsf',None)
        if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array')
    vmacro= kwargs.pop('vmacro',6.)
    # Parse continuum-normalization keywords
    cont= kwargs.pop('cont','aspcap')
    # Parse the wavelength regions
    apWave= apStarWavegrid()
    if isinstance(args[0],str): #element string given
        si,ei= apwindow.waveregions(args[0],pad=3,asIndex=True)
        args= args[1:]
    else:
        if isinstance(args[0][0],int): # assume index
            si,ei= args[0], args[1]
        else: # assume wavelengths in \AA
            sl,el= args[0], args[1]
            # Convert to index
            si, ei= [], []
            for s,e in zip(sl,el):
                # Find closest index into apWave
                si.append(numpy.argmin(numpy.fabs(s-apWave)))
                ei.append(numpy.argmin(numpy.fabs(e-apWave)))
        args= args[2:]
    # Setup the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    tmpModelAtmDir= False
    # Parse fparam, if present
    fparam= kwargs.pop('fparam',None)
    if not fparam is None:
        kwargs['teff']= fparam[0,paramIndx('TEFF')]
        kwargs['logg']= fparam[0,paramIndx('LOGG')]
        kwargs['metals']= fparam[0,paramIndx('METALS')]
        kwargs['am']= fparam[0,paramIndx('ALPHA')]
        kwargs['cm']= fparam[0,paramIndx('C')]
        kwargs['vm']= 10.**fparam[0,paramIndx('LOG10VDOP')]        
    if modelatm is None: # Setup a model atmosphere
        modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.),
                                          logg=kwargs.get('logg',2.5),
                                          metals=kwargs.get('metals',0.),
                                          am=kwargs.get('am',0.),
                                          cm=kwargs.get('cm',0.),
                                          dr=kwargs.get('dr',None))
    if isinstance(modelatm,str) and os.path.exists(modelatm):
        modelfilename= modelatm
    elif isinstance(modelatm,str):
        raise ValueError('modelatm= input is a non-existing filename')
    else: # model atmosphere instance
        # Need to write this instance to a file; we will run in a temp 
        # subdirectory of the current directory
        tmpDir= tempfile.mkdtemp(dir=os.getcwd())
        tmpModelAtmDir= True # need to remove this later
        modelfilename= os.path.join(tmpDir,'modelatm.mod')
        modelatm.writeto(modelfilename)
    kwargs['modelatm']= modelfilename
    try:
        # Check whether a MOOG version of the model atmosphere exists
        if not os.path.exists(modelfilename.replace('.mod','.org')):
            # Convert to MOOG format
            convert_modelAtmosphere(**kwargs)
        # Run weedout on the linelist first if requested
        if run_weedout:
            linelistfilename= modelfilename.replace('.mod','.lines')
            if not os.path.exists(linelistfilename):
                weedout(**kwargs)
            kwargs['linelist']= linelistfilename
        # Run MOOG synth for the whole wavelength range as a baseline, also contin
        if baseline is None:
            baseline= moogsynth(**kwargs)[1] 
        elif isinstance(baseline,tuple): #probably accidentally gave wav as well
            baseline= baseline[1]
        if mwav is None or cflux is None:
            mwav, cflux= moogsynth(doflux=True,**kwargs)
        # Convert the apStarWavegrid windows to moogWavegrid regions
        sm,em= [], []
        for start,end in zip(si,ei):
            sm.append(numpy.argmin(numpy.fabs(apWave[start]-mwav)))
            em.append(numpy.argmin(numpy.fabs(apWave[end]-mwav)))
        # Run MOOG synth for all abundances and all windows
        if len(args) == 0: #special case that there are *no* differences
            args= ([26,0.],)
        nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))])
        nsynth= numpy.amax(nsynths) #Take the longest abundance list
        out= numpy.tile(baseline,(nsynth,1))
        # Run all windows
        for start, end in zip(sm,em):
            kwargs['wmin']= mwav[start]
            kwargs['wmax']= mwav[end]
            # Check whether the number of syntheses is > 5 and run multiple 
            # MOOG instances if necessary, bc MOOG only does 5 at a time
            ninstances= int(numpy.ceil(nsynth/5.))
            for ii in range(ninstances):
                newargs= ()
                for jj in range(len(args)):
                    tab= [args[jj][0]]
                    if len(args[jj][5*ii+1:5*(ii+1)+1]) > 0:
                        tab.extend(args[jj][5*ii+1:5*(ii+1)+1])
                        newargs= newargs+(tab,)
                out[5*ii:5*(ii+1),start:end+1]= moogsynth(*newargs,**kwargs)[1] 
    except: raise
    finally:
        if tmpModelAtmDir: # need to remove this temporary directory
            os.remove(modelfilename)
        moogmodelfilename= modelfilename.replace('.mod','.org')
        if os.path.exists(moogmodelfilename):
            os.remove(moogmodelfilename)
        if run_weedout:
            os.remove(modelfilename.replace('.mod','.lines'))
        os.rmdir(tmpDir)
    # Now multiply each continuum-normalized spectrum with the continuum
    out*= numpy.tile(cflux,(nsynth,1))
    # Now convolve with the LSF
    out= aplsf.convolve(mwav,out,
                        lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave= apStarWavegrid()
        baseline= numpy.polynomial.Polynomial.fit(mwav,cflux,4)
        ip= interpolate.InterpolatedUnivariateSpline(mwav,
                                                     cflux/baseline(mwav),
                                                     k=3)
        cflux= baseline(apWave)*ip(apWave)
        # Divide it out
        out/= numpy.tile(cflux,(nsynth,1))
    elif not cont is None:
        cflux= apcont.fit(out,numpy.ones_like(out),type=cont)
        out[cflux > 0.]/= cflux[cflux > 0.]
        out[cflux <= 0.]= numpy.nan
    return out
Example #4
0
def synth(*args,**kwargs):
    """
    NAME:
       synth
    PURPOSE:
       Generate model APOGEE spectra using Turbospectrum: this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'turbosynth' for a direct interface to Turbospectrum
    INPUT ARGUMENTS:
       lists with abundances differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          air= (True) if True, perform the synthesis in air wavelengths (output is still in vacuum); set to False at your own risk, as Turbospectrum expects the linelist in air wavelengths!)
          Hlinelist= (None) Hydrogen linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist; if None, then we first search for the Hlinedata.vac in the APOGEE linelist directory (if air=False) or we use the internal Turbospectrum Hlinelist (if air=True)
          linelist= (None) molecular and atomic linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist, or lists of such files; if a single filename is given, the code will first search for files with extensions '.atoms', '.molec' or that start with 'turboatoms.' and 'turbomolec.'
          wmin, wmax, dw= (15000.000, 17000.000, 0.10000000) spectral synthesis limits and step
          costheta= (1.) cosine of the viewing angle
          lib= ('kurucz_filled') spectral library
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) model-atmosphere instance
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format
                 lib= ('kurucz_filled') model atmosphere library
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
    OUTPUT:
       spectra (nspec,nwave)
    HISTORY:
       2015-04-16 - Written - Bovy (IAS)
    """
    # Check that we have the LSF and store the relevant keywords
    lsf= kwargs.pop('lsf','all')
    if isinstance(lsf,str):
        xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf)
        dxlsf= None
    else:
        xlsf= kwargs.pop('xlsf',None)
        dxlsf= kwargs.pop('dxlsf',None)
        if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array')
    vmacro= kwargs.pop('vmacro',6.)
    # Parse continuum-normalization keywords
    cont= kwargs.pop('cont','aspcap')
    # Setup the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    # Parse fparam, if present
    fparam= kwargs.pop('fparam',None)
    if not fparam is None:
        kwargs['teff']= fparam[paramIndx('TEFF')]
        kwargs['logg']= fparam[paramIndx('LOGG')]
        kwargs['metals']= fparam[paramIndx('METALS')]
        kwargs['am']= fparam[paramIndx('ALPHA')]
        kwargs['cm']= fparam[paramIndx('C')]
        kwargs['vmicro']= 10.**fparam[paramIndx('LOG10VDOP')]        
    # Need to pass a model atmosphere instance to turbosynth (needs to be made
    # more efficient, because now turbosynth always write the atmosphere
    if modelatm is None: # Setup a model atmosphere
        modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.),
                                          logg=kwargs.get('logg',2.5),
                                          metals=kwargs.get('metals',0.),
                                          am=kwargs.get('am',0.),
                                          cm=kwargs.get('cm',0.),
                                          dr=kwargs.get('dr',None))
    if isinstance(modelatm,str) and os.path.exists(modelatm):
        raise ValueError('modelatm= input is an existing filename, but you need to give an Atmosphere object instead')
    elif isinstance(modelatm,str):
        raise ValueError('modelatm= input needs to be an Atmosphere instance')
    # Check temperature
    if modelatm._teff > 7000.:
        warnings.warn('Turbospectrum does not include all necessary physics to model stars hotter than about 7000 K; proceed with caution',RuntimeWarning)
    kwargs['modelatm']= modelatm
    try:
        # Run turbosynth for all abundances
        if len(args) == 0: #special case that there are *no* differences
            args= ([26,0.],)
        nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))])
        nsynth= numpy.amax(nsynths) #Take the longest abundance list
        nturbowav= int((kwargs.get('wmax',_WMAX_DEFAULT)\
                            -kwargs.get('wmin',_WMIN_DEFAULT))\
                           /kwargs.get('dw',_DW_DEFAULT)+1)
        out= numpy.empty((nsynth,nturbowav))
        for ii in range(nsynth):
            newargs= ()
            for jj in range(len(args)):
                tab= [args[jj][0]]
                if len(args[jj]) > ii+1:
                    tab.append(args[jj][ii+1])
                    newargs= newargs+(tab,)
            tmpOut= turbosynth(*newargs,**kwargs)
            out[ii]= tmpOut[2] # incl. continuum
        # wavelength grid from final one
        mwav= tmpOut[0]
    except: raise
    # If the synthesis was done in air, convert wavelength array
    if kwargs.get('air',True):
        mwav= numpy.array([air2vac(w) for w in list(mwav)])
    # Now convolve with the LSF
    out= aplsf.convolve(mwav,out,
                        lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave= apStarWavegrid()
        baseline= numpy.polynomial.Polynomial.fit(mwav,tmpOut[2]/tmpOut[1],4)
        ip= interpolate.InterpolatedUnivariateSpline(mwav,
                                                     tmpOut[2]/tmpOut[1]\
                                                         /baseline(mwav),
                                                     k=3)
        cflux= baseline(apWave)*ip(apWave)
        # Divide it out
        out/= numpy.tile(cflux,(nsynth,1))
    elif not cont is None:
        cflux= apcont.fit(out,numpy.ones_like(out),type=cont)
        out[cflux > 0.]/= cflux[cflux > 0.]
        out[cflux <= 0.]= numpy.nan
    return out
Example #5
0
def windows(*args, **kwargs):
    """
    NAME:
       windows
    PURPOSE:
       Generate model APOGEE spectra using MOOG in selected wavelength windows (but the whole APOGEE spectral range is returned): this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'moogsynth' for a direct interface to MOOG
    INPUT ARGUMENTS:
       Windows specification: Provide one of
          (1) Element string: the APOGEE windows for this element will be loaded
          (2) startindxs, endindxs= start and end indexes of the windows on the apStar wavelength grid
          (3) startlams, endlams= start and end wavelengths in \AA
       lists with abundance differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       BASELINE: you can specify the baseline spectrum to not always re-compute it
          baseline= baseline c-normalized spectrum on MOOG wavelength grid (obtained from moogsynth)
          mwav= MOOG wavelength grid (obtained from moogsynth)
          cflux= continuum flux from MOOG
          Typically, you can obtain these three keywords by doing (kwargs are the keywords you provide to this function as well)
          >>> baseline= moogsynth(**kwargs)[1]
          >>> mwav, cflux= moogsynth(doflux=True,**kwargs)
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          linelist= (None) linelist to use; if this is None, the code looks for a weed-out version of the linelist appropriate for the given model atmosphere
          run_weedout= (False) if True, run MOOG weedout on the linelist first
          wmin, wmax, dw, width= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits *for the whole spectrum* (not just the windows), step, and width of calculation (see MOOG)
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) can be set to the filename of a model atmosphere or to a model-atmosphere instance (if filename, needs to end in .mod)
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format (
                 lib= ('kurucz_filled') model atmosphere library
                 dr= (None) use model atmospheres from this data release
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
    OUTPUT:
       spectra (nspec,nwave)
    HISTORY:
       2015-03-18 - Written - Bovy (IAS)
    """
    # Pop some kwargs
    run_weedout = kwargs.pop('run_weedout', False)
    baseline = kwargs.pop('baseline', None)
    mwav = kwargs.pop('mwav', None)
    cflux = kwargs.pop('cflux', None)
    # Check that we have the LSF and store the relevant keywords
    lsf = kwargs.pop('lsf', 'all')
    if isinstance(lsf, str):
        xlsf, lsf = aplsf._load_precomp(dr=kwargs.get('dr', None), fiber=lsf)
        dxlsf = None
    else:
        xlsf = kwargs.pop('xlsf', None)
        dxlsf = kwargs.pop('dxlsf', None)
        if xlsf is None and dxlsf is None:
            raise ValueError(
                'xlsf= or dxlsf= input needs to be given if the LSF is given as an array'
            )
    vmacro = kwargs.pop('vmacro', 6.)
    # Parse continuum-normalization keywords
    cont = kwargs.pop('cont', 'aspcap')
    # Parse the wavelength regions
    apWave = apStarWavegrid()
    if isinstance(args[0], str):  #element string given
        si, ei = apwindow.waveregions(args[0], pad=3, asIndex=True)
        args = args[1:]
    else:
        if isinstance(args[0][0], int):  # assume index
            si, ei = args[0], args[1]
        else:  # assume wavelengths in \AA
            sl, el = args[0], args[1]
            # Convert to index
            si, ei = [], []
            for s, e in zip(sl, el):
                # Find closest index into apWave
                si.append(numpy.argmin(numpy.fabs(s - apWave)))
                ei.append(numpy.argmin(numpy.fabs(e - apWave)))
        args = args[2:]
    # Setup the model atmosphere
    modelatm = kwargs.pop('modelatm', None)
    tmpModelAtmDir = False
    # Parse fparam, if present
    fparam = kwargs.pop('fparam', None)
    if not fparam is None:
        kwargs['teff'] = fparam[0, paramIndx('TEFF')]
        kwargs['logg'] = fparam[0, paramIndx('LOGG')]
        kwargs['metals'] = fparam[0, paramIndx('METALS')]
        kwargs['am'] = fparam[0, paramIndx('ALPHA')]
        kwargs['cm'] = fparam[0, paramIndx('C')]
        kwargs['vm'] = 10.**fparam[0, paramIndx('LOG10VDOP')]
    if modelatm is None:  # Setup a model atmosphere
        modelatm = atlas9.Atlas9Atmosphere(teff=kwargs.get('teff', 4500.),
                                           logg=kwargs.get('logg', 2.5),
                                           metals=kwargs.get('metals', 0.),
                                           am=kwargs.get('am', 0.),
                                           cm=kwargs.get('cm', 0.),
                                           dr=kwargs.get('dr', None))
    if isinstance(modelatm, str) and os.path.exists(modelatm):
        modelfilename = modelatm
    elif isinstance(modelatm, str):
        raise ValueError('modelatm= input is a non-existing filename')
    else:  # model atmosphere instance
        # Need to write this instance to a file; we will run in a temp
        # subdirectory of the current directory
        tmpDir = tempfile.mkdtemp(dir=os.getcwd())
        tmpModelAtmDir = True  # need to remove this later
        modelfilename = os.path.join(tmpDir, 'modelatm.mod')
        modelatm.writeto(modelfilename)
    kwargs['modelatm'] = modelfilename
    try:
        # Check whether a MOOG version of the model atmosphere exists
        if not os.path.exists(modelfilename.replace('.mod', '.org')):
            # Convert to MOOG format
            convert_modelAtmosphere(**kwargs)
        # Run weedout on the linelist first if requested
        if run_weedout:
            linelistfilename = modelfilename.replace('.mod', '.lines')
            if not os.path.exists(linelistfilename):
                weedout(**kwargs)
            kwargs['linelist'] = linelistfilename
        # Run MOOG synth for the whole wavelength range as a baseline, also contin
        if baseline is None:
            baseline = moogsynth(**kwargs)[1]
        elif isinstance(baseline,
                        tuple):  #probably accidentally gave wav as well
            baseline = baseline[1]
        if mwav is None or cflux is None:
            mwav, cflux = moogsynth(doflux=True, **kwargs)
        # Convert the apStarWavegrid windows to moogWavegrid regions
        sm, em = [], []
        for start, end in zip(si, ei):
            sm.append(numpy.argmin(numpy.fabs(apWave[start] - mwav)))
            em.append(numpy.argmin(numpy.fabs(apWave[end] - mwav)))
        # Run MOOG synth for all abundances and all windows
        if len(args) == 0:  #special case that there are *no* differences
            args = ([26, 0.], )
        nsynths = numpy.array([len(args[ii]) - 1 for ii in range(len(args))])
        nsynth = numpy.amax(nsynths)  #Take the longest abundance list
        out = numpy.tile(baseline, (nsynth, 1))
        # Run all windows
        for start, end in zip(sm, em):
            kwargs['wmin'] = mwav[start]
            kwargs['wmax'] = mwav[end]
            # Check whether the number of syntheses is > 5 and run multiple
            # MOOG instances if necessary, bc MOOG only does 5 at a time
            ninstances = int(numpy.ceil(nsynth / 5.))
            for ii in range(ninstances):
                newargs = ()
                for jj in range(len(args)):
                    tab = [args[jj][0]]
                    if len(args[jj][5 * ii + 1:5 * (ii + 1) + 1]) > 0:
                        tab.extend(args[jj][5 * ii + 1:5 * (ii + 1) + 1])
                        newargs = newargs + (tab, )
                out[5 * ii:5 * (ii + 1),
                    start:end + 1] = moogsynth(*newargs, **kwargs)[1]
    except:
        raise
    finally:
        if tmpModelAtmDir:  # need to remove this temporary directory
            os.remove(modelfilename)
        moogmodelfilename = modelfilename.replace('.mod', '.org')
        if os.path.exists(moogmodelfilename):
            os.remove(moogmodelfilename)
        if run_weedout:
            os.remove(modelfilename.replace('.mod', '.lines'))
        os.rmdir(tmpDir)
    # Now multiply each continuum-normalized spectrum with the continuum
    out *= numpy.tile(cflux, (nsynth, 1))
    # Now convolve with the LSF
    out = aplsf.convolve(mwav,
                         out,
                         lsf=lsf,
                         xlsf=xlsf,
                         dxlsf=dxlsf,
                         vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave = apStarWavegrid()
        baseline = numpy.polynomial.Polynomial.fit(mwav, cflux, 4)
        ip = interpolate.InterpolatedUnivariateSpline(mwav,
                                                      cflux / baseline(mwav),
                                                      k=3)
        cflux = baseline(apWave) * ip(apWave)
        # Divide it out
        out /= numpy.tile(cflux, (nsynth, 1))
    elif not cont is None:
        cflux = apcont.fit(out, numpy.ones_like(out), type=cont)
        out[cflux > 0.] /= cflux[cflux > 0.]
        out[cflux <= 0.] = numpy.nan
    return out
Example #6
0
def runTarget(gridParam):
	locationID = gridParam.locationID
	apogeeID = gridParam.apogeeID

	badheader, header = apread.apStar(locationID, apogeeID, ext=0, header=True, dr='13')
	specs = apread.apStar(locationID, apogeeID, ext=1, header=False, dr='13')
	specerrs = apread.apStar(locationID, apogeeID, ext=2, header=False, dr='13')
	nvisits = header['NVISITS']
	gridParamVists = []
	for visit in range(1, nvisits + 1):
		print('Visit ' + str(visit) + '/' + str(nvisits))
		if nvisits is 1:
			spec = specs
			specerr = specerrs
		else:
			spec = specs[1 + nvisits]
			specerr = specerrs[ 1+ nvisits]
		
		aspec= np.reshape(spec,(1, len(spec)))
		aspecerr= np.reshape(specerr,(1, len(specerr)))
		cont= spec / continuum.fit(aspec, aspecerr, type='aspcap')[0]
		conterr = specerr / continuum.fit(aspec, aspecerr, type='aspcap')[0]
		
		gridParam = GridParam(locationID, apogeeID)
		gridParam.constructParams()
		gridParam.spec = bm.shiftFlux(cont, header['VHELIO' + str(visit)])
		gridParam.specErr = bm.shiftFlux(conterr, header['VHELIO' + str(visit)])
		gridParam.getRVs(visit)
		gridParam.visit = visit

		nSteps = 200
		sampler = MCMC(gridParam, nSteps=nSteps)
		circular_samples = sampler.chain[:, :, :].reshape((-1, 5))
		results = np.asarray(list(map(lambda v: (v[1], v[2]-v[1], v[1]-v[0]),
							zip(*np.percentile(circular_samples, [16, 50, 84], axis=0)))))
		
		fig, ax = plt.subplots(5, 1, sharex='col')
		for i in range(5):
			for j in range(len(sampler.chain[:, 0, i])):
				ax[i].plot(np.linspace(0, nSteps, num=nSteps), sampler.chain[j, :, i], 'k', alpha=0.2)
			ax[i].plot(np.linspace(0, nSteps, num=nSteps) , np.ones(nSteps)*results[i][0], 'b', lw=2)
		fig.set_figheight(20)
		fig.set_figwidth(15)
		if not os.path.exists('plots/walker/' + str(locationID) + '/' + str(apogeeID) + '/'):
			os.makedirs('plots/walker/' + str(locationID) + '/' + str(apogeeID) + '/')
		plt.savefig('plots/walker/' + str(locationID) + '/' + str(apogeeID) + '/' + str(visit) + '.png')

		plt.close('all')
		gridParam.modelParamA.teff = results[0][0]
		gridParam.modelParamB.teff = results[1][0]
		gridParam.modelParamB.fluxRatio = results[2][0]
		gridParam.modelParamA.rv = results[3][0]
		gridParam.modelParamB.rv = results[4][0]

		gridParam.chi2 = -1.0 * fitModel(None, gridParam, plot=True)
		gridParamVists.append(gridParam)
	

	if not os.path.exists('lists/chi2/' + str(locationID) + '/'):
		os.makedirs('lists/chi2/' + str(locationID) + '/')
	filename = 'lists/chi2/' + str(locationID) + '/' + str(apogeeID) + '.tbl'
	writeGridToFile(gridParamVists, filename=filename)
Example #7
0
def windows(*args,**kwargs):
    """
    NAME:
       windows
    PURPOSE:
       Generate model APOGEE spectra using Turbospectrum in selected wavelength windows (but the whole APOGEE spectral range is returned): this is a general routine that generates the non-continuum-normalized spectrum, convolves with the LSF and macrotubulence, and optionally continuum normalizes the output; use 'turbosynth' for a direct interface to Turbospectrum
    INPUT ARGUMENTS:
       Windows specification: Provide one of
          (1) Element string: the APOGEE windows for this element will be loaded
          (2) startindxs, endindxs= start and end indexes of the windows on the apStar wavelength grid
          (3) startlams, endlams= start and end wavelengths in \AA
       lists with abundance differences wrt the atmosphere (they don't all have to have the same length, missing ones are filled in with zeros):
          [Atomic number1,diff1_1,diff1_2,diff1_3,...,diff1_N]
          [Atomic number2,diff2_1,diff2_2,diff2_3,...,diff2_N]
          ...
          [Atomic numberM,diffM_1,diffM_2,diffM_3,...,diffM_N]
    INPUT KEYWORDS:
       BASELINE: you can specify the baseline spectrum and the continuous opacity to not always re-compute it
          baseline= baseline c-normalized spectrum on Turbospectrum wavelength grid (obtained from turbosynth)
          mwav= Turbospectrum wavelength grid (obtained from turbosynth)
          cflux= continuum flux from Turbospectrum
          modelopac= (None) 
                     (a) if set to an existing filename: assume babsma_lu has already been run and use this continuous opacity in bsyn_lu
                     (b) if set to a non-existing filename: store the continuous opacity in this file
          Typically, you can obtain these three keywords by doing (kwargs are the keywords you provide to this function as well, and includes modelopac='SOME FILENAME')
          >>> baseline= turbosynth(**kwargs)
          >>> mwav= baseline[0]
          >>> cflux= baseline[2]/baseline[1]
          >>> baseline= baseline[1]
       LSF:
          lsf= ('all') LSF to convolve with; output of apogee.spec.lsf.eval; sparsify for efficiency; if 'all' or 'combo' a pre-computed version will be downloaded from the web
          Either:
             xlsf= (None) pixel offset grid on which the LSF is computed (see apogee.spec.lsf.eval); unnecessary if lsf=='all' or 'combo'
             dxlsf= (None) spacing of pixel offsets
          vmacro= (6.) macroturbulence to apply
       CONTINUUM:
          cont= ('aspcap') continuum-normalization to apply:
             None: no continuum normalization
             'true': Use the true continuum
             'aspcap': Use the continuum normalization method of ASPCAP DR12
             'cannon': Normalize using continuum pixels derived from the Cannon
       SYNTHESIS:
          air= (True) if True, perform the synthesis in air wavelengths (output is still in vacuum); set to False at your own risk, as Turbospectrum expects the linelist in air wavelengths!)
          Hlinelist= (None) Hydrogen linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist; if None, then we first search for the Hlinedata.vac in the APOGEE linelist directory (if air=False) or we use the internal Turbospectrum Hlinelist (if air=True)
          linelist= (None) molecular and atomic linelists to use; can be set to the path of a linelist file or to the name of an APOGEE linelist, or lists of such files; if a single filename is given, the code will first search for files with extensions '.atoms', '.molec' or that start with 'turboatoms.' and 'turbomolec.'
          wmin, wmax, dw= (15000.000, 17000.000, 0.10000000, 7.0000000) spectral synthesis limits, step, and width of calculation (see MOOG)
          costheta= (1.) cosine of the viewing angle
       MODEL ATMOSPHERE PARAMETERS:
          Specify one of the following:
             (a) modelatm= (None) model-atmosphere instance
             (b) parameters of a KURUCZ model atmosphere:
                 (1) teff= (4500) Teff
                     logg= (2.5) logg
                     metals= (0.) metallicity
                     cm= (0.) carbon-enhancement
                     am= (0.) alpha-enhancement
                 (2) fparam= standard ASPCAP output format
                 lib= ('kurucz_filled') model atmosphere library
          vmicro= (2.) microturbulence (only used if the MOOG-formatted atmosphere is not found) (can also be part of fparam)
       MISCELLANEOUS:
          dr= return the path corresponding to this data release
          raw= (False) if True, return the raw turbosynth output
    OUTPUT:
       spectra (nspec,nwave)
       (wavelengths,cont-norm. spectrum, spectrum (nwave)) if raw == True
    HISTORY:
       2015-04-17 - Written - Bovy (IAS)
    """
    # Pop some kwargs
    baseline= kwargs.pop('baseline',None)
    mwav= kwargs.pop('mwav',None)
    cflux= kwargs.pop('cflux',None)
    raw= kwargs.pop('raw',False)
    # Check that we have the LSF and store the relevant keywords
    lsf= kwargs.pop('lsf','all')
    if isinstance(lsf,str):
        xlsf, lsf= aplsf._load_precomp(dr=kwargs.get('dr',None),fiber=lsf)
        dxlsf= None
    else:
        xlsf= kwargs.pop('xlsf',None)
        dxlsf= kwargs.pop('dxlsf',None)
        if xlsf is None and dxlsf is None: raise ValueError('xlsf= or dxlsf= input needs to be given if the LSF is given as an array')
    vmacro= kwargs.pop('vmacro',6.)
    # Parse continuum-normalization keywords
    cont= kwargs.pop('cont','aspcap')
    # Parse the wavelength regions
    apWave= apStarWavegrid()
    if isinstance(args[0],str): #element string given
        si,ei= apwindow.waveregions(args[0],pad=3,asIndex=True)
        args= args[1:]
    else:
        if isinstance(args[0][0],int): # assume index
            si,ei= args[0], args[1]
        else: # assume wavelengths in \AA
            sl,el= args[0], args[1]
            # Convert to index
            si, ei= [], []
            for s,e in zip(sl,el):
                # Find closest index into apWave
                si.append(numpy.argmin(numpy.fabs(s-apWave)))
                ei.append(numpy.argmin(numpy.fabs(e-apWave)))
        args= args[2:]
    # Setup the model atmosphere
    modelatm= kwargs.pop('modelatm',None)
    # Parse fparam, if present
    fparam= kwargs.pop('fparam',None)
    if not fparam is None:
        kwargs['teff']= fparam[0,paramIndx('TEFF')]
        kwargs['logg']= fparam[0,paramIndx('LOGG')]
        kwargs['metals']= fparam[0,paramIndx('METALS')]
        kwargs['am']= fparam[0,paramIndx('ALPHA')]
        kwargs['cm']= fparam[0,paramIndx('C')]
        kwargs['vmicro']= 10.**fparam[0,paramIndx('LOG10VDOP')]        
    # Need to pass a model atmosphere instance to turbosynth (needs to be made
    # more efficient, because now turbosynth always write the atmosphere
    if modelatm is None: # Setup a model atmosphere
        modelatm= atlas9.Atlas9Atmosphere(teff=kwargs.get('teff',4500.),
                                          logg=kwargs.get('logg',2.5),
                                          metals=kwargs.get('metals',0.),
                                          am=kwargs.get('am',0.),
                                          cm=kwargs.get('cm',0.),
                                          dr=kwargs.get('dr',None))
    if isinstance(modelatm,str) and os.path.exists(modelatm):
        raise ValueError('modelatm= input is an existing filename, but you need to give an Atmosphere object instead')
    elif isinstance(modelatm,str):
        raise ValueError('modelatm= input needs to be an Atmosphere instance')
    # Check temperature
    if modelatm._teff > 7000.:
        warnings.warn('Turbospectrum does not include all necessary physics to model stars hotter than about 7000 K; proceed with caution',RuntimeWarning)
    kwargs['modelatm']= modelatm
    try:
        rmModelopac= False
        if not 'modelopac' in kwargs:
            rmModelopac= True
            kwargs['modelopac']= tempfile.mktemp('mopac')
            # Make sure opacity is first calculated over the full wav. range
            kwargs['babsma_wmin']= 15000.
            kwargs['babsma_wmax']= 17000.
        elif 'modelopac' in kwargs and not isinstance(kwargs['modelopac'],str):
            raise ValueError('modelopac needs to be set to a filename')
        # Run synth for the whole wavelength range as a baseline
        if baseline is None or mwav is None or cflux is None:
            baseline= turbosynth(**kwargs)
            mwav= baseline[0]
            cflux= baseline[2]/baseline[1]
            baseline= baseline[1]
        elif isinstance(baseline,tuple): #probably accidentally gave the entire output of turbosynth
            mwav= baseline[0]
            cflux= baseline[2]/baseline[1]
            baseline= baseline[1]
        # Convert the apStarWavegrid windows to turboWavegrid regions
        sm,em= [], []
        for start,end in zip(si,ei):
            if kwargs.get('air',True):
                sm.append(numpy.argmin(numpy.fabs(vac2air(apWave[start])-mwav)))
                em.append(numpy.argmin(numpy.fabs(vac2air(apWave[end])-mwav)))
            else:
                sm.append(numpy.argmin(numpy.fabs(apWave[start]-mwav)))
                em.append(numpy.argmin(numpy.fabs(apWave[end]-mwav)))
        # Run Turbospectrum synth for all abundances and all windows
        if len(args) == 0: #special case that there are *no* differences
            args= ([26,0.],)
        nsynths= numpy.array([len(args[ii])-1 for ii in range(len(args))])
        nsynth= numpy.amax(nsynths) #Take the longest abundance list
        out= numpy.tile(baseline,(nsynth,1))
        # Run all windows
        for start, end in zip(sm,em):
            kwargs['wmin']= mwav[start]
            kwargs['wmax']= mwav[end]+0.001
            for ii in range(nsynth):
                newargs= ()
                for jj in range(len(args)):
                    tab= [args[jj][0]]
                    if len(args[jj]) > ii+1:
                        tab.append(args[jj][ii+1])
                        newargs= newargs+(tab,)
                tmpOut= turbosynth(*newargs,**kwargs)
                if numpy.isnan(tmpOut[1][-1]): 
                    # NaN returned for reasons that I don't understand
                    out[ii,start:end]= tmpOut[1][:-1]
                else:
                    out[ii,start:end+1]= tmpOut[1]
    except: raise
    finally:
        if rmModelopac and os.path.exists(kwargs['modelopac']):
            os.remove(kwargs['modelopac'])
            kwargs.pop('modelopac')
    # Now multiply each continuum-normalized spectrum with the continuum
    out*= numpy.tile(cflux,(nsynth,1))
    if raw: return (mwav,out/numpy.tile(cflux,(nsynth,1)),out)
    # If the synthesis was done in air, convert wavelength array
    if kwargs.get('air',True):
        mwav= numpy.array([air2vac(w) for w in list(mwav)])
    # Now convolve with the LSF
    out= aplsf.convolve(mwav,out,
                        lsf=lsf,xlsf=xlsf,dxlsf=dxlsf,vmacro=vmacro)
    # Now continuum-normalize
    if cont.lower() == 'true':
        # Get the true continuum on the apStar wavelength grid
        apWave= apStarWavegrid()
        baseline= numpy.polynomial.Polynomial.fit(mwav,cflux,4)
        ip= interpolate.InterpolatedUnivariateSpline(mwav,
                                                     cflux/baseline(mwav),
                                                     k=3)
        cflux= baseline(apWave)*ip(apWave)
        # Divide it out
        out/= numpy.tile(cflux,(nsynth,1))
    elif not cont is None:
        cflux= apcont.fit(out,numpy.ones_like(out),type=cont)
        out[cflux > 0.]/= cflux[cflux > 0.]
        out[cflux <= 0.]= numpy.nan
    return out
def targetGrid(gridParam, minimizedVisitParams, plot=True):
	'''
	The grid tests against ranging effective temperatures for both stars and the flux ratio of the
	secondary component. This is done by target.

	:param gridParam: [in/out] The GridParam of the target
	:param gridRes: [out] The visits that have the same paramters as the minimized chi2 visit
	:param plot: [in] If true makes plots to see intermediate steps (default=True)
	'''
	locationID = gridParam.locationID
	apogeeID = gridParam.apogeeID

	badheader, header = apread.apStar(locationID, apogeeID, ext=0, header=True)
	specs = apread.apStar(locationID, apogeeID, ext=1, header=False)
	specerrs = apread.apStar(locationID, apogeeID, ext=2, header=False)
	nvisits = header['NVISITS']
	
	# chi2 = np.full((nvisits, nrangeTeffA, nrangeTeffB, nrangeFluxRatio), -1.)
	#chi2 = np.full((nvisits, nrangeTeffA, nrangeTeffB, nrangeFluxRatio, nrangeRVA, nrangeRVB), -1.)
	ipg = ferre.Interpolator(lib='GK')
	ipf = ferre.Interpolator(lib='F')

	# Create file to store all the chi2 values
	path = 'lists/all_chi2/' + str(locationID) + '/'
	if not os.path.exists(path):
		os.makedirs(path)
	fn = open(path + apogeeID + '.lis', 'w')
	fn.write(gridParam.toStringHeader())
	timer = Timer()
	timeSum = 0.0
	allChi2 = []
	visitGridParamsBuffer = []
	for visit in range(1, nvisits + 1):
		timer.start()
		if (nvisits != 1):
			spec = specs[1+visit]
			specerr = specerrs[1+visit]
		else:
			spec = specs
			specerr = specerrs
		
		if (len(minimizedVisitParams) == 0):
			gridParam = GridParam(locationID, apogeeID)
			gridParam.constructParams()
			gridParam.getRVs(visit)
		else:
			gridParam = minimizedVisitParams[visit - 1]
		visitGridParamsBuffer.append(gridParam)
		
		# Prepare grid ranges
		rangeTeffA = np.arange(gridParam.minTeffA, gridParam.maxTeffA, gridParam.teffStepA)
		rangeTeffB = np.arange(gridParam.minTeffB, gridParam.maxTeffB, gridParam.teffStepB)
		rangeFluxRatio = np.arange(gridParam.minFluxRatio, gridParam.maxFluxRatio, gridParam.fluxStep)
		rangeRVA = np.arange(gridParam.minRVA, gridParam.maxRVA, gridParam.rvAStep)
		rangeRVB = np.arange(gridParam.minRVB, gridParam.maxRVB, gridParam.rvBStep)
		nrangeTeffA = len(rangeTeffA)
		nrangeTeffB = len(rangeTeffB)
		nrangeFluxRatio = len(rangeFluxRatio)
		nrangeRVA =len(rangeRVA)
		nrangeRVB =len(rangeRVB)

		chi2 = np.full((nrangeTeffA, nrangeTeffB, nrangeFluxRatio, nrangeRVA, nrangeRVB), -1.)
		print('Visit: ' + str(visit) ,'Grid dimensions: ' + str(chi2.shape))
		# Prep Spectra
		aspec= np.reshape(spec,(1, len(spec)))
		aspecerr= np.reshape(specerr,(1, len(specerr)))
		cont= spec / continuum.fit(aspec, aspecerr, type='aspcap')[0]
		conterr = specerr / continuum.fit(aspec, aspecerr, type='aspcap')[0]
		shiftedSpec = bm.shiftFlux(cont, header['VHELIO' + str(visit)])

		# Run grid
		for i in range(nrangeTeffA):
			gridParam.modelParamA.teff = rangeTeffA[i]
			componentA = bm.genComponent(gridParam.modelParamA, ipf, ipg)
			for j in range(nrangeTeffB):
				gridParam.modelParamB.teff = rangeTeffB[j]
				componentB = bm.genComponent(gridParam.modelParamB, ipf, ipg)
				for k in range(nrangeFluxRatio):
					gridParam.modelParamB.fluxRatio = rangeFluxRatio[k]
					componentBR = componentB * rangeFluxRatio[k]
					for l in range(nrangeRVA):
						gridParam.modelParamA.rv = rangeRVA[l]
						componentAS = bm.shiftFlux(componentA, rangeRVA[l])
						for m in range(nrangeRVB):
							gridParam.modelParamB.rv = rangeRVB[m]
							componentBS = bm.shiftFlux(componentBR, rangeRVB[m])
							binaryFlux = bm.combineFlux(componentAS, componentBS)
							chi2[i][j][k][l][m] = calcChi2(binaryFlux, shiftedSpec, conterr) / (len(binaryFlux) - 5.0)
							gridParam.chi2 = chi2[i][j][k][l][m]
							fn.write(gridParam.toString())
							if (plot is True):
								restLambda = splot.apStarWavegrid()
								BinPlot.plotDeltaVCheck(locationID, apogeeID, visit,
													[	[ restLambda, binaryFlux, 'blue', 'model' ],
														[ restLambda, cont, 'orange', 'unshifted' ],
														[ restLambda, shiftedSpec, 'green', 'shifted' ]],
														[gridParam.modelParamA.teff,gridParam.modelParamB.teff, gridParam.modelParamB.fluxRatio],
														'Delta V Shift', folder='grid_deltaVCheck')

		timeSum+=timer.end()
		allChi2.append(chi2)
	fn.close()

	print('Average visit time: ' + str(round(timeSum/nvisits, 2)) + str('s'))

	# Get minized values for each visit
	indices = None
	for i in range(nvisits):
		inds = getMinIndicies(allChi2[i])
		rangeTeffA = np.arange(visitGridParamsBuffer[i].minTeffA, visitGridParamsBuffer[i].maxTeffA, visitGridParamsBuffer[i].teffStepA)
		rangeTeffB = np.arange(visitGridParamsBuffer[i].minTeffB, visitGridParamsBuffer[i].maxTeffB, visitGridParamsBuffer[i].teffStepB)
		rangeFluxRatio = np.arange(visitGridParamsBuffer[i].minFluxRatio, visitGridParamsBuffer[i].maxFluxRatio, visitGridParamsBuffer[i].fluxStep)
		rangeRVA = np.arange(visitGridParamsBuffer[i].minRVA, visitGridParamsBuffer[i].maxRVA, visitGridParamsBuffer[i].rvAStep)
		rangeRVB = np.arange(visitGridParamsBuffer[i].minRVB, visitGridParamsBuffer[i].maxRVB, visitGridParamsBuffer[i].rvBStep)
		nrangeTeffA = len(rangeTeffA)
		nrangeTeffB = len(rangeTeffB)
		nrangeFluxRatio = len(rangeFluxRatio)
		nrangeRVA =len(rangeRVA)
		nrangeRVB =len(rangeRVB)
		visitGridParamsBuffer[i].setParams(i + 1, rangeTeffA[inds[0]], rangeTeffB[inds[1]], rangeFluxRatio[inds[2]],
					rangeRVA[inds[3]], rangeRVB[inds[4]], allChi2[i][inds[0]][inds[1]][inds[2]][inds[3]][inds[4]])

		if (indices is None):
			indices = [i + 1, inds, allChi2[i][inds[0]][inds[1]][inds[2]][inds[3]][inds[4]]]
		if (allChi2[i][inds[0]][inds[1]][inds[2]][inds[3]][inds[4]] < indices[2]):
			indices = [i + 1, inds, allChi2[i][inds[0]][inds[1]][inds[2]][inds[3]][inds[4]]]
	
	inds = getMinIndicies(allChi2)
	gridParam = visitGridParamsBuffer[inds[0]]
	return gridParam, visitGridParamsBuffer
def read_spectra(cluster,
                 teffmin=4000.,
                 teffmax=5000.,
                 cont_type='cannon',
                 cont_deg=4):
    """
    NAME:
       read_spectra
    PURPOSE:
       Read the APOGEE spectra and their errors for stars in a given cluster
    INPUT:
       cluster - Name of the cluster (name in one of the data files)
       teffmin= (4000.) minimum temperature
       teffmax= (5000.) maximum temperature
       cont_type = ('cannon') type of continuum normalization to perform
       cont_deg= (4) degree polynomial to fit for continuum normalization
    OUTPUT:
       (data, spec, specerr) - (full data structure, spectra [nspec,nlam], spectral uncertainties [nspec,nlam]) nlam=7214 on ASPCAP grid
    HISTORY:
       2015-08-13 - Written based on some older code - Bovy (UofT)
    """
    if cluster.upper() in _GCS:
        data = read_meszarosgcdata()
    else:
        data = read_caldata()
    # Cut to just this cluster and temperature range
    if 'rc' in cluster.lower():
        # Only for NGC 6819
        rc = True
        cluster = cluster[:-2]
    else:
        rc = False
    data = data[data['CLUSTER'] == cluster.upper()]
    data= data[(data['TEFF'] < teffmax)\
                   *(data['TEFF'] > teffmin)]
    if cluster.lower() == 'n6819':
        g4CN = good4CN(cluster, data)
        g4CN[10] = False  # another one, by hand!
        if rc:
            data = data[True - g4CN]  # Just those!
        else:
            data = data[g4CN]  # Just those!
    # Load all the spectra
    nspec = len(data)
    spec = numpy.zeros((nspec, 7214))
    specerr = numpy.zeros((nspec, 7214))
    # Setup bad pixel mask
    badcombpixmask= bitmask.badpixmask()\
        +2**bitmask.apogee_pixmask_int("SIG_SKYLINE")
    for ii in range(nspec):
        sys.stdout.write('\r' + "Loading spectrum %i / %i ...\r" %
                         (ii + 1, nspec))
        sys.stdout.flush()
        spec[ii] = apread.apStar(data['LOCATION_ID'][ii],
                                 data['ID'][ii],
                                 ext=1,
                                 header=False,
                                 aspcapWavegrid=True)[_COMBINED_INDEX]
        specerr[ii] = apread.apStar(data['LOCATION_ID'][ii],
                                    data['ID'][ii],
                                    ext=2,
                                    header=False,
                                    aspcapWavegrid=True)[_COMBINED_INDEX]
        # Inflate uncertainties for bad pixels
        mask = apread.apStar(data['LOCATION_ID'][ii],
                             data['ID'][ii],
                             ext=3,
                             header=False,
                             aspcapWavegrid=True)[_COMBINED_INDEX]
        specerr[ii,(mask & (badcombpixmask)) != 0]+=\
            100.*numpy.mean(spec[ii,True-numpy.isnan(spec[ii])])
        # Also inflate pixels with high SNR to 0.5%
        highsnr = spec[ii] / specerr[ii] > 200.
        specerr[ii, highsnr] = 0.005 * numpy.fabs(spec[ii, highsnr])
        # Continuum-normalize
        cont = continuum.fit(spec[ii],
                             specerr[ii],
                             type=cont_type,
                             deg=cont_deg)
        spec[ii] /= cont
        specerr[ii] /= cont
        specerr[ii, highsnr] = 0.005  # like standard APOGEE reduction
    sys.stdout.write('\r' + _ERASESTR + '\r')
    sys.stdout.flush()
    return (data, spec, specerr)
Example #10
0
nan_vals = [i for i in range(len(spec[0])) if np.isnan(spec[0][i])]
nan_ranges = [(nan_vals[i] + 1, nan_vals[i+1]) for i in range(len(nan_vals) - 1) if nan_vals[i+1]!=nan_vals[i]+1]

print(nan_ranges)
specChunk = spec[0][nan_ranges[0][0]:nan_ranges[0][1]]
errChunk = err[0][nan_ranges[0][0]:nan_ranges[0][1]]'''

aspec= apread.apStar(locationID, apogeeID, ext=1, header=False)[1]
aspecerr= apread.apStar(locationID, apogeeID, ext=2, header=False)[1]
# Input needs to be (nspec,nwave)
aspec= np.reshape(aspec,(1,len(aspec)))
aspecerr= np.reshape(aspecerr,(1,len(aspecerr)))
# Fit the continuum
from apogee.spec import continuum
cont= continuum.fit(aspec,aspecerr,type='aspcap')

cspec= apread.aspcapStar(locationID, apogeeID,ext=1,header=False)
import apogee.spec.plot as splot
splot.waveregions(aspec[0]/cont[0])
splot.waveregions(cspec,overplot=True)

'''params = ferre.fit(locationID, apogeeID,
							teff=teff1, fixteff=True,
							logg=logg, fixlogg=True,
							metals=metals, fixmetals=False,
							am=am, fixam=False,
							nm=nm, fixnm=False,
							cm=cm, fixcm=False,
							verbose=True)
'''
def read_spectra(cluster,teffmin=4000.,teffmax=5000.,cont_type='cannon',
                 cont_deg=4):
    """
    NAME:
       read_spectra
    PURPOSE:
       Read the APOGEE spectra and their errors for stars in a given cluster
    INPUT:
       cluster - Name of the cluster (name in one of the data files)
       teffmin= (4000.) minimum temperature
       teffmax= (5000.) maximum temperature
       cont_type = ('cannon') type of continuum normalization to perform
       cont_deg= (4) degree polynomial to fit for continuum normalization
    OUTPUT:
       (data, spec, specerr) - (full data structure, spectra [nspec,nlam], spectral uncertainties [nspec,nlam]) nlam=7214 on ASPCAP grid
    HISTORY:
       2015-08-13 - Written based on some older code - Bovy (UofT)
    """
    if cluster.upper() in _GCS:
        data= read_meszarosgcdata()
    else:
        data= read_caldata()
    # Cut to just this cluster and temperature range
    if 'rc' in cluster.lower():
        # Only for NGC 6819
        rc= True
        cluster= cluster[:-2]
    else:
        rc= False
    data= data[data['CLUSTER'] == cluster.upper()]
    data= data[(data['TEFF'] < teffmax)\
                   *(data['TEFF'] > teffmin)]
    if cluster.lower() == 'n6819':
        g4CN= good4CN(cluster,data)
        g4CN[10]= False # another one, by hand!
        if rc:
            data= data[True-g4CN] # Just those!
        else:
            data= data[g4CN] # Just those!
    # Load all the spectra
    nspec= len(data)
    spec= numpy.zeros((nspec,7214))
    specerr= numpy.zeros((nspec,7214))
    # Setup bad pixel mask
    badcombpixmask= bitmask.badpixmask()\
        +2**bitmask.apogee_pixmask_int("SIG_SKYLINE")
    for ii in range(nspec):
        sys.stdout.write('\r'+"Loading spectrum %i / %i ...\r" % (ii+1,nspec))
        sys.stdout.flush()
        spec[ii]= apread.apStar(data['LOCATION_ID'][ii],
                                data['ID'][ii],
                                ext=1,header=False,
                                aspcapWavegrid=True)[_COMBINED_INDEX]
        specerr[ii]= apread.apStar(data['LOCATION_ID'][ii],
                                   data['ID'][ii],
                                   ext=2,header=False,
                                   aspcapWavegrid=True)[_COMBINED_INDEX]
        # Inflate uncertainties for bad pixels
        mask= apread.apStar(data['LOCATION_ID'][ii],
                            data['ID'][ii],
                            ext=3,header=False,
                            aspcapWavegrid=True)[_COMBINED_INDEX]
        specerr[ii,(mask & (badcombpixmask)) != 0]+=\
            100.*numpy.mean(spec[ii,True-numpy.isnan(spec[ii])])
        # Also inflate pixels with high SNR to 0.5%
        highsnr= spec[ii]/specerr[ii] > 200.
        specerr[ii,highsnr]= 0.005*numpy.fabs(spec[ii,highsnr])
        # Continuum-normalize
        cont= continuum.fit(spec[ii],specerr[ii],type=cont_type,deg=cont_deg)
        spec[ii]/= cont
        specerr[ii]/= cont
        specerr[ii,highsnr]= 0.005 # like standard APOGEE reduction
    sys.stdout.write('\r'+_ERASESTR+'\r')
    sys.stdout.flush()
    return (data,spec,specerr)
apogeeID = "2M03441568+3231282"
restLambda = splot.apStarWavegrid()
visit = 1

badheader, header = apread.apStar(locationID, apogeeID, ext=0, header=True)

gridParam = GridParam(locationID, apogeeID)
gridParam.constructParams()

spec = apread.apStar(locationID, apogeeID, ext=1, header=False)[1 + visit]
specerr = apread.apStar(locationID, apogeeID, ext=2, header=False)[1 + visit]
# plt.plot(restLambda, spec)

aspec = np.reshape(spec, (1, len(spec)))
aspecerr = np.reshape(specerr, (1, len(specerr)))
cont = spec / continuum.fit(aspec, aspecerr, type="aspcap")[0]
conterr = specerr / continuum.fit(aspec, aspecerr, type="aspcap")[0]
shiftedSpec = bm.shiftFlux(cont, header["VHELIO" + str(visit)])
conterr = bm.shiftFlux(cont, header["VHELIO" + str(visit)])
BinPlot.plotDeltaVCheck(
    locationID,
    apogeeID,
    visit,
    [[restLambda, cont, "blue", "Data"]],
    [gridParam.modelParamA.teff, gridParam.modelParamB.teff],
    "",
    folder="model_gen",
)
# plt.plot(restLambda, cont)
# plt.show()
ipg = ferre.Interpolator(lib="GK")