Beispiel #1
0
def test_params_named():
    #Test that the named tags correspond to the correct values in param according to PARAM_SYMBOL
    assert numpy.all(
        numpy.fabs(_DATA['PARAM'][:, paramIndx('teff')] - _DATA['TEFF']) < 10.
        **-10.), 'PARAM TEFF does not correspond to tag TEFF'
    assert numpy.all(
        numpy.fabs(_DATA['PARAM'][:, paramIndx('logg')] - _DATA['LOGG']) < 10.
        **-10.), 'PARAM LOGG does not correspond to tag LOGG'
    cnanIndx = (True - numpy.isnan(
        numpy.sqrt(_DATA['PARAM_COV'][:,
                                      paramIndx('teff'),
                                      paramIndx('teff')])))
    if numpy.sum(cnanIndx) > 0:
        assert numpy.all(
            numpy.fabs(
                numpy.sqrt(_DATA['PARAM_COV'][cnanIndx,
                                              paramIndx('teff'),
                                              paramIndx('teff')]) -
                _DATA['TEFF_ERR'][cnanIndx]) < 10.**-10.
        ), 'PARAM_COV TEFF does not correspond to tag TEFF_ERR'
    cnanIndx = (True - numpy.isnan(
        numpy.sqrt(_DATA['PARAM_COV'][:,
                                      paramIndx('logg'),
                                      paramIndx('logg')])))
    if numpy.sum(cnanIndx) > 0:
        assert numpy.all(
            numpy.fabs(
                numpy.sqrt(_DATA['PARAM_COV'][cnanIndx,
                                              paramIndx('logg'),
                                              paramIndx('logg')]) -
                _DATA['LOGG_ERR'][cnanIndx]) < 10.**-10.
        ), 'PARAM_COV LOGG does not correspond to tag LOGG_ERR'
    return None
Beispiel #2
0
def test_elem_named():
    #Test that the named tags for the elements correspond to the correct values in elem according to ELEM_SYMBOL 
    elems= ['C','N','O','Mg','Si','S','Ca','Ti',
            'Ni','Fe','Al','K','Na','V','Mn']
    ferreOverM= ['C','N','O','Mg','Si','S','Ca','Ti']
    for ii,elem in enumerate(elems):
        elemval= copy.copy(_DATA['ELEM'][:,elemIndx(elem)])
        if elem in ferreOverM: elemval+= _DATA['FPARAM'][:,paramIndx('metals')]
        #BOVY: What about the following?
        goodIndx= _DATA['FPARAM'][:,paramIndx('metals')] != -9999.
        assert numpy.all(numpy.fabs(elemval[goodIndx]-_DATA[elem.upper()+'_H'][goodIndx]) < 10.**-10.), 'ELEM value for %s_H does not agree with named tag' % elem 
    return None
def test_elem_named():
    #Test that the named tags for the elements correspond to the correct values in elem according to ELEM_SYMBOL 
    from apogee.tools import _ELEM_SYMBOL
    elems= [e.capitalize() for e in _ELEM_SYMBOL if e != 'ci' and e != 'tiii']
    ferreOverM= ['C','N','O','Mg','Si','S','Ca','Ti']
    for ii,elem in enumerate(elems):
        if elem == 'C' or elem == 'N' or elem == 'O': continue
        elemval= copy.copy(_DATA['ELEM'][:,elemIndx(elem)])
        if elem in ferreOverM: elemval+= _DATA['FPARAM'][:,paramIndx('metals')]
        #BOVY: What about the following?
        goodIndx= (_DATA['FPARAM'][:,paramIndx('metals')] != -9999.)\
            *(_DATA[elem.upper()+'_H'] != -9999.)
        assert numpy.all(numpy.fabs(elemval[goodIndx]-_DATA[elem.upper()+'_H'][goodIndx]) < 10.**-10.), 'ELEM value for %s_H does not agree with named tag' % elem 
    return None
Beispiel #4
0
def test_elem_named():
    #Test that the named tags for the elements correspond to the correct values in elem according to ELEM_SYMBOL 
    from apogee.tools import _ELEM_SYMBOL
    elems= [e.capitalize() for e in _ELEM_SYMBOL if e != 'ci' and e != 'tiii']
    ferreOverM= ['C','N','O','Mg','Si','S','Ca','Ti']
    for ii,elem in enumerate(elems):
        if elem == 'C' or elem == 'N' or elem == 'O': continue
        elemval= copy.copy(_DATA['ELEM'][:,elemIndx(elem)])
        if elem in ferreOverM: elemval+= _DATA['FPARAM'][:,paramIndx('metals')]
        #BOVY: What about the following?
        goodIndx= (_DATA['FPARAM'][:,paramIndx('metals')] != -9999.)\
            *(_DATA[elem.upper()+'_H'] != -9999.)
        assert numpy.all(numpy.fabs(elemval[goodIndx]-_DATA[elem.upper()+'_H'][goodIndx]) < 10.**-10.), 'ELEM value for %s_H does not agree with named tag' % elem 
    return None
Beispiel #5
0
def test_elem_calib_outsiderange_dwarfs():
    #Test that the elem calibration does not extend outside of the calibration
    #temperature range
    from apogee.tools import _ELEM_SYMBOL
    elems = [e.capitalize() for e in _ELEM_SYMBOL if e != 'ci' and e != 'tiii']
    TeffMin = 3800.
    TeffMax = 7500.
    dwarfs= (_DATA['FPARAM'][:,paramIndx('logg')] >= (2./1300.\
                 *(_DATA['FPARAM'][:,paramIndx('teff')]-3500.)+2.))\
                 +(_DATA['FPARAM'][:,paramIndx('logg')] >= 4.)\
                 +(_DATA['FPARAM'][:,paramIndx('teff')] >= 7000.)
    for elem in elems:
        calibDiff= _DATA['FELEM'][:,elemIndx(elem)]\
            -_DATA['ELEM'][:,elemIndx(elem)]
        #Only consider good stars for this element
        indx= ((_DATA['ASPCAPFLAG'] & 2**23) == 0)\
            *(_DATA['FPARAM'][:,paramIndx('teff')] > -1000.)\
            *dwarfs\
            *(_DATA['FELEM'][:,elemIndx(elem)] > -1000.)\
            *(_DATA['ELEM'][:,elemIndx(elem)] > -1000.)
        try:
            loTIndx = numpy.argmin(
                numpy.fabs(_DATA['FPARAM'][indx, paramIndx('teff')] - TeffMin))
        except ValueError:
            pass
        else:
            assert numpy.all(
                numpy.fabs(calibDiff[indx][
                    _DATA['FPARAM'][indx, paramIndx('teff')] < TeffMin] -
                           calibDiff[indx][loTIndx]) < 10.**-3.
            ), 'Calibration offset does not saturate below the minimum calibration temperature of %i for element %s' % (
                TeffMin, elem)
        try:
            hiTIndx = numpy.argmin(
                numpy.fabs(_DATA['FPARAM'][indx, paramIndx('teff')] - TeffMax))
        except ValueError:
            pass
        else:
            assert numpy.all(
                numpy.fabs(calibDiff[indx][
                    _DATA['FPARAM'][indx, paramIndx('teff')] > TeffMax] -
                           calibDiff[indx][hiTIndx]) < 10.**-2.
            ), 'Calibration offset does not saturate above the maximum calibration temperature of %i for element %s' % (
                TeffMax, elem)
    return None
Beispiel #6
0
def test_params_named():
    #Test that the named tags correspond to the correct values in param according to PARAM_SYMBOL
    assert numpy.all(numpy.fabs(_DATA['PARAM'][:,paramIndx('teff')]
                                -_DATA['TEFF']) < 10.**-10.), 'PARAM TEFF does not correspond to tag TEFF'
    assert numpy.all(numpy.fabs(_DATA['PARAM'][:,paramIndx('logg')]
                                -_DATA['LOGG']) < 10.**-10.), 'PARAM LOGG does not correspond to tag LOGG'
    cnanIndx= (True-numpy.isnan(numpy.sqrt(_DATA['PARAM_COV'][:,paramIndx('teff'),paramIndx('teff')])))
    if numpy.sum(cnanIndx) > 0:
        assert numpy.all(numpy.fabs(numpy.sqrt(_DATA['PARAM_COV'][cnanIndx,paramIndx('teff'),paramIndx('teff')])
                                    -_DATA['TEFF_ERR'][cnanIndx]) < 10.**-10.), 'PARAM_COV TEFF does not correspond to tag TEFF_ERR'
    cnanIndx= (True-numpy.isnan(numpy.sqrt(_DATA['PARAM_COV'][:,paramIndx('logg'),paramIndx('logg')])))
    if numpy.sum(cnanIndx) > 0:
        assert numpy.all(numpy.fabs(numpy.sqrt(_DATA['PARAM_COV'][cnanIndx,paramIndx('logg'),paramIndx('logg')])
                                    -_DATA['LOGG_ERR'][cnanIndx]) < 10.**-10.), 'PARAM_COV LOGG does not correspond to tag LOGG_ERR'
    return None
Beispiel #7
0
def test_elem_calib_outsiderange():
    #Test that the elem calibration does not extend outside of the calibration
    #temperature range
    elems= ['C','N','O','Mg','Si','S','Ca','Ti',
            'Ni','Fe','Al','K','Na','V','Mn']
    TeffMin= 3800.
    TeffMax= 5250.
    for elem in elems:
        calibDiff= _DATA['FELEM'][:,elemIndx(elem)]\
            -_DATA['ELEM'][:,elemIndx(elem)]
        #Only consider good stars for this element
        indx= ((_DATA['ASPCAPFLAG'] & 2**23) == 0)\
            *(_DATA['FPARAM'][:,paramIndx('teff')] > -1000.)\
            *(_DATA['FELEM'][:,elemIndx(elem)] > -1000.)\
            *(_DATA['ELEM'][:,elemIndx(elem)] > -1000.)
        loTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                         paramIndx('teff')]
                                         -TeffMin))
        hiTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                         paramIndx('teff')]
                                         -TeffMax))
        assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] < TeffMin]-calibDiff[indx][loTIndx]) < 10.**-3.), 'Calibration offset does not saturate below the minimum calibration temperature of %i for element %s' % (TeffMin,elem)
        assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] > TeffMax]-calibDiff[indx][hiTIndx]) < 10.**-2.), 'Calibration offset does not saturate above the maximum calibration temperature of %i for element %s' % (TeffMax,elem)
    return None
Beispiel #8
0
def test_elem_calib_outsiderange():
    #Test that the elem calibration does not extend outside of the calibration
    #temperature range
    elems= ['C','N','O','Mg','Si','S','Ca','Ti',
            'Ni','Fe','Al','K','Na','V','Mn']
    TeffMin= 3800.
    TeffMax= 5250.
    for elem in elems:
        calibDiff= _DATA['FELEM'][:,elemIndx(elem)]\
            -_DATA['ELEM'][:,elemIndx(elem)]
        #Only consider good stars for this element
        indx= ((_DATA['ASPCAPFLAG'] & 2**23) == 0)\
            *(_DATA['FPARAM'][:,paramIndx('teff')] > -1000.)\
            *(_DATA['FELEM'][:,elemIndx(elem)] > -1000.)\
            *(_DATA['ELEM'][:,elemIndx(elem)] > -1000.)
        loTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                         paramIndx('teff')]
                                         -TeffMin))
        hiTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                         paramIndx('teff')]
                                         -TeffMax))
        assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] < TeffMin]-calibDiff[indx][loTIndx]) < 10.**-3.), 'Calibration offset does not saturate below the minimum calibration temperature of %i for element %s' % (TeffMin,elem)
        assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] > TeffMax]-calibDiff[indx][hiTIndx]) < 10.**-2.), 'Calibration offset does not saturate above the maximum calibration temperature of %i for element %s' % (TeffMax,elem)
    return None
def test_elem_calib_outsiderange_dwarfs():
    #Test that the elem calibration does not extend outside of the calibration
    #temperature range
    from apogee.tools import _ELEM_SYMBOL
    elems= [e.capitalize() for e in _ELEM_SYMBOL if e != 'ci' and e != 'tiii']
    TeffMin= 3800.
    TeffMax= 7500.
    dwarfs= (_DATA['FPARAM'][:,paramIndx('logg')] >= (2./1300.\
                 *(_DATA['FPARAM'][:,paramIndx('teff')]-3500.)+2.))\
                 +(_DATA['FPARAM'][:,paramIndx('logg')] >= 4.)\
                 +(_DATA['FPARAM'][:,paramIndx('teff')] >= 7000.)
    for elem in elems:
        calibDiff= _DATA['FELEM'][:,elemIndx(elem)]\
            -_DATA['ELEM'][:,elemIndx(elem)]
        #Only consider good stars for this element
        indx= ((_DATA['ASPCAPFLAG'] & 2**23) == 0)\
            *(_DATA['FPARAM'][:,paramIndx('teff')] > -1000.)\
            *dwarfs\
            *(_DATA['FELEM'][:,elemIndx(elem)] > -1000.)\
            *(_DATA['ELEM'][:,elemIndx(elem)] > -1000.)
        try:
            loTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                             paramIndx('teff')]
                                             -TeffMin))
        except ValueError:
            pass
        else:
            assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] < TeffMin]-calibDiff[indx][loTIndx]) < 10.**-3.), 'Calibration offset does not saturate below the minimum calibration temperature of %i for element %s' % (TeffMin,elem)
        try:
            hiTIndx= numpy.argmin(numpy.fabs(_DATA['FPARAM'][indx,
                                                             paramIndx('teff')]
                                             -TeffMax))
        except ValueError:
            pass
        else:
            assert numpy.all(numpy.fabs(calibDiff[indx][_DATA['FPARAM'][indx,paramIndx('teff')] > TeffMax]-calibDiff[indx][hiTIndx]) < 10.**-2.), 'Calibration offset does not saturate above the maximum calibration temperature of %i for element %s' % (TeffMax,elem)
    return None
Beispiel #10
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
Beispiel #11
0
def make_rcsample(parser):
    options, args = parser.parse_args()
    savefilename = options.savefilename
    if savefilename is None:
        #Create savefilename if not given
        savefilename = os.path.join(
            appath._APOGEE_DATA, 'rcsample_' + appath._APOGEE_REDUX + '.fits')
        print("Saving to %s ..." % savefilename)
    #Read the base-sample
    data = apread.allStar(adddist=_ADDHAYDENDIST, rmdups=options.rmdups)
    #Remove a bunch of fields that we do not want to keep
    data = esutil.numpy_util.remove_fields(data, [
        'TARGET_ID', 'FILE', 'AK_WISE', 'SFD_EBV', 'SYNTHVHELIO_AVG',
        'SYNTHVSCATTER', 'SYNTHVERR', 'SYNTHVERR_MED', 'RV_TEFF', 'RV_LOGG',
        'RV_FEH', 'RV_ALPHA', 'RV_CARB', 'RV_CCFWHM', 'RV_AUTOFWHM',
        'SYNTHSCATTER', 'STABLERV_CHI2', 'STABLERV_RCHI2',
        'STABLERV_CHI2_PROB', 'CHI2_THRESHOLD', 'APSTAR_VERSION',
        'ASPCAP_VERSION', 'RESULTS_VERSION', 'WASH_M', 'WASH_M_ERR', 'WASH_T2',
        'WASH_T2_ERR', 'DDO51', 'DDO51_ERR', 'IRAC_3_6', 'IRAC_3_6_ERR',
        'IRAC_4_5', 'IRAC_4_5_ERR', 'IRAC_5_8', 'IRAC_5_8_ERR', 'IRAC_8_0',
        'IRAC_8_0_ERR', 'WISE_4_5', 'WISE_4_5_ERR', 'TARG_4_5', 'TARG_4_5_ERR',
        'WASH_DDO51_GIANT_FLAG', 'WASH_DDO51_STAR_FLAG', 'REDUCTION_ID',
        'SRC_H', 'PM_SRC'
    ])
    # More
    if appath._APOGEE_REDUX.lower() == 'l33':
        data = esutil.numpy_util.remove_fields(data, [
            'GAIA_SOURCE_ID', 'GAIA_PARALLAX', 'GAIA_PARALLAX_ERROR',
            'GAIA_PMRA', 'GAIA_PMRA_ERROR', 'GAIA_PMDEC', 'GAIA_PMDEC_ERROR',
            'GAIA_PHOT_G_MEAN_MAG', 'GAIA_PHOT_BP_MEAN_MAG',
            'GAIA_PHOT_RP_MEAN_MAG', 'GAIA_RADIAL_VELOCITY',
            'GAIA_RADIAL_VELOCITY_ERROR', 'GAIA_R_EST', 'GAIA_R_LO',
            'GAIA_R_HI', 'TEFF_SPEC', 'LOGG_SPEC'
        ])
    if not appath._APOGEE_REDUX.lower() == 'current' \
            and not 'l3' in appath._APOGEE_REDUX \
            and int(appath._APOGEE_REDUX[1:]) < 500:
        data = esutil.numpy_util.remove_fields(data, ['ELEM'])
    #Select red-clump stars
    jk = data['J0'] - data['K0']
    z = isodist.FEH2Z(data['METALS'], zsolar=0.017)
    if 'l31' in appath._APOGEE_REDUX:
        logg = data['LOGG']
    elif 'l30' in appath._APOGEE_REDUX:
        logg = data['LOGG']
    elif appath._APOGEE_REDUX.lower() == 'current' \
            or int(appath._APOGEE_REDUX[1:]) > 600:
        if False:
            #Use my custom logg calibration that's correct for the RC
            logg = (1. - 0.042) * data['FPARAM'][:, paramIndx('logg')] - 0.213
            lowloggindx = data['FPARAM'][:, paramIndx('logg')] < 1.
            logg[lowloggindx] = data['FPARAM'][lowloggindx,
                                               paramIndx('logg')] - 0.255
            hiloggindx = data['FPARAM'][:, paramIndx('logg')] > 3.8
            logg[hiloggindx] = data['FPARAM'][hiloggindx,
                                              paramIndx('logg')] - 0.3726
        else:
            #Use my custom logg calibration that's correct on average
            logg = (1. + 0.03) * data['FPARAM'][:, paramIndx('logg')] - 0.37
            lowloggindx = data['FPARAM'][:, paramIndx('logg')] < 1.
            logg[lowloggindx] = data['FPARAM'][lowloggindx,
                                               paramIndx('logg')] - 0.34
            hiloggindx = data['FPARAM'][:, paramIndx('logg')] > 3.8
            logg[hiloggindx] = data['FPARAM'][hiloggindx,
                                              paramIndx('logg')] - 0.256
    else:
        logg = data['LOGG']
    indx= (jk < 0.8)*(jk >= 0.5)\
        *(z <= 0.06)\
        *(z <= rcmodel.jkzcut(jk,upper=True))\
        *(z >= rcmodel.jkzcut(jk))\
        *(logg >= rcmodel.loggteffcut(data['TEFF'],z,upper=False))\
        *(logg+0.1*('l31' in appath._APOGEE_REDUX
                    or 'l33' in appath._APOGEE_REDUX) \
              <= rcmodel.loggteffcut(data['TEFF'],z,upper=True))
    data = data[indx]
    #Add more aggressive flag cut
    data = esutil.numpy_util.add_fields(data, [('ADDL_LOGG_CUT', numpy.int32)])
    data['ADDL_LOGG_CUT'] = (
        (data['TEFF'] - 4800.) / 1000. + 2.75) > data['LOGG']
    if options.loggcut:
        data = data[data['ADDL_LOGG_CUT'] == 1]
    print("Making catalog of %i objects ..." % len(data))
    #Add distances
    data = esutil.numpy_util.add_fields(data, [('RC_DIST', float),
                                               ('RC_DM', float),
                                               ('RC_GALR', float),
                                               ('RC_GALPHI', float),
                                               ('RC_GALZ', float)])
    rcd = rcmodel.rcdist()
    jk = data['J0'] - data['K0']
    z = isodist.FEH2Z(data['METALS'], zsolar=0.017)
    data['RC_DIST'] = rcd(jk, z, appmag=data['K0']) * options.distfac
    data['RC_DM'] = 5. * numpy.log10(data['RC_DIST']) + 10.
    XYZ = bovy_coords.lbd_to_XYZ(data['GLON'],
                                 data['GLAT'],
                                 data['RC_DIST'],
                                 degree=True)
    RphiZ = bovy_coords.XYZ_to_galcencyl(XYZ[:, 0],
                                         XYZ[:, 1],
                                         XYZ[:, 2],
                                         Xsun=8.15,
                                         Zsun=0.0208)
    R = RphiZ[:, 0]
    phi = RphiZ[:, 1]
    Z = RphiZ[:, 2]
    data['RC_GALR'] = R
    data['RC_GALPHI'] = phi
    data['RC_GALZ'] = Z
    #Save
    fitswrite(savefilename, data, clobber=True)
    # Add Tycho-2 matches
    if options.tyc2:
        data = esutil.numpy_util.add_fields(data, [('TYC2MATCH', numpy.int32),
                                                   ('TYC1', numpy.int32),
                                                   ('TYC2', numpy.int32),
                                                   ('TYC3', numpy.int32)])
        data['TYC2MATCH'] = 0
        data['TYC1'] = -1
        data['TYC2'] = -1
        data['TYC3'] = -1
        # Write positions
        posfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        resultfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        with open(posfilename, 'w') as csvfile:
            wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA', 'DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'], data[ii]['DEC']])
        # Send to CDS for matching
        result = open(resultfilename, 'w')
        try:
            subprocess.check_call([
                'curl', '-X', 'POST', '-F', 'request=xmatch', '-F',
                'distMaxArcsec=2', '-F', 'RESPONSEFORMAT=csv', '-F',
                'cat1=@%s' % os.path.basename(posfilename), '-F', 'colRA1=RA',
                '-F', 'colDec1=DEC', '-F', 'cat2=vizier:Tycho2',
                'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'
            ],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Directly match on input RA
        ma = numpy.loadtxt(resultfilename,
                           delimiter=',',
                           skiprows=1,
                           usecols=(1, 2, 7, 8, 9))
        iis = numpy.arange(len(data))
        mai = [iis[data['RA'] == ma[ii, 0]][0] for ii in range(len(ma))]
        data['TYC2MATCH'][mai] = 1
        data['TYC1'][mai] = ma[:, 2]
        data['TYC2'][mai] = ma[:, 3]
        data['TYC3'][mai] = ma[:, 4]
        os.remove(posfilename)
        os.remove(resultfilename)
    if not options.nostat:
        #Determine statistical sample and add flag
        apo = apogee.select.apogeeSelect()
        statIndx = apo.determine_statistical(data)
        mainIndx = apread.mainIndx(data)
        data = esutil.numpy_util.add_fields(data, [('STAT', numpy.int32),
                                                   ('INVSF', float)])
        data['STAT'] = 0
        data['STAT'][statIndx * mainIndx] = 1
        for ii in range(len(data)):
            if (statIndx * mainIndx)[ii]:
                data['INVSF'][ii] = 1. / apo(data['LOCATION_ID'][ii],
                                             data['H'][ii])
            else:
                data['INVSF'][ii] = -1.
    if options.nopm:
        fitswrite(savefilename, data, clobber=True)
        return None
    data = _add_proper_motions(data, savefilename)
    # Save
    fitswrite(savefilename, data, clobber=True)
    return None
Beispiel #12
0
def calibrate_logg_dr12(rgb=False):
    """Calibrate, using RC or RGV when rgb=True (the latter should reproduce the official calibration"""
    #Read the calibration file, APOKASC, and match them
    caldata= fitsio.read(os.path.join(os.getenv('APOGEE_DATA'),'cal_%s.fits' % os.getenv('APOGEE_REDUX')),1)
    apokasc= apread.apokasc()
    h=esutil.htm.HTM()
    m1,m2,d12 = h.match(caldata['RA'],caldata['DEC'],
                        apokasc['RA'],apokasc['DEC'],
                        2./3600.,maxmatch=1)
    caldata= caldata[m1]
    apokasc= apokasc[m2]
    #Select a decent calibration sample
    # Use stars that are definitely RGB or RC
    seismoState= numpy.char.strip(apokasc['SEISMO EVOL'])
    if rgb:
        indx= (seismoState == 'RGB') \
            + (seismoState == 'DWARF/SUBGIANT')
    else:
        indx= (seismoState == 'CLUMP')
    #Add low-logg giants of any kind
    indx+= (apokasc['KASC_RG_LOGG_SCALE_2'] < 2.)
    #rm bad data
    indx= (caldata['FPARAM'][:,paramIndx('logg')] > -1000.)
    indx*= (apokasc['KASC_RG_LOGG_SCALE_2'] > -1000.)
    #Apply limits
    indx*= (caldata['FPARAM'][:,paramIndx('logg')] > 1.)\
        *(caldata['FPARAM'][:,paramIndx('logg')] < 3.8)
    print "Using %i stars to calibrate logg ..." % numpy.sum(indx)
    #Now fit the difference
    fitOut= numpy.polyfit(caldata['FPARAM'][indx,paramIndx('logg')],
                          caldata['FPARAM'][indx,paramIndx('logg')]\
                              -apokasc['KASC_RG_LOGG_SCALE_2'][indx],
                          1)
    print fitOut
    if True:
        bovy_plot.bovy_print()
        bovy_plot.bovy_plot(caldata['FPARAM'][indx,paramIndx('logg')],
                            caldata['FPARAM'][indx,paramIndx('logg')]\
                                -apokasc['KASC_RG_LOGG_SCALE_2'][indx],
                            'k.',
                            xrange=[0.,5.],yrange=[-0.5,1.],
                            xlabel=r'$\log g_{\mathrm{ASPCAP}}$',
                            ylabel=r'$\log g_{\mathrm{ASPCAP}}-\log g_{\mathrm{seismo}}$')
        if not rgb:
            plotindx= (seismoState == 'RGB') \
                + (seismoState == 'DWARF/SUBGIANT')
        else:
            plotindx= (seismoState == 'CLUMP')
        plotindx*= (caldata['FPARAM'][:,paramIndx('logg')] > -1000.)
        plotindx*= (apokasc['KASC_RG_LOGG_SCALE_2'] > -1000.)
        bovy_plot.bovy_plot(caldata['FPARAM'][plotindx,paramIndx('logg')],
                            caldata['FPARAM'][plotindx,paramIndx('logg')]\
                                -apokasc['KASC_RG_LOGG_SCALE_2'][plotindx],
                            '.',color='0.65',overplot=True)
        xs= numpy.linspace(1.,3.8,1001)
        bovy_plot.bovy_plot(xs,fitOut[0]*xs+fitOut[1],'k-',overplot=True)
        bovy_plot.bovy_plot(xs,-0.14*xs+0.588,'k--',overplot=True)
        print numpy.amax(numpy.fabs(fitOut[0]*xs+fitOut[1]-(-0.14*xs+0.588)))
        print numpy.amax(numpy.fabs(fitOut[0]*xs+fitOut[1]-(-0.14*xs+0.588))[xs < 2.])
        bovy_plot.bovy_text(r'$\mathrm{diff} = %.3f \log g_{\mathrm{ASPCAP}} + %.3f$' % (fitOut[0],fitOut[1]),
                            bottom_left=True,fontsize=14.)
        bovy_plot.bovy_end_print('/Users/bovy/Desktop/test.png')
    return None
Beispiel #13
0
def make_rcsample(parser):
    options, args = parser.parse_args()
    savefilename = options.savefilename
    if savefilename is None:
        #Create savefilename if not given
        savefilename = os.path.join(
            appath._APOGEE_DATA, 'rcsample_' + appath._APOGEE_REDUX + '.fits')
        print("Saving to %s ..." % savefilename)
    #Read the base-sample
    data = apread.allStar(adddist=_ADDHAYDENDIST, rmdups=options.rmdups)
    #Remove a bunch of fields that we do not want to keep
    data = esutil.numpy_util.remove_fields(data, [
        'TARGET_ID', 'FILE', 'AK_WISE', 'SFD_EBV', 'SYNTHVHELIO_AVG',
        'SYNTHVSCATTER', 'SYNTHVERR', 'SYNTHVERR_MED', 'RV_TEFF', 'RV_LOGG',
        'RV_FEH', 'RV_ALPHA', 'RV_CARB', 'RV_CCFWHM', 'RV_AUTOFWHM',
        'SYNTHSCATTER', 'STABLERV_CHI2', 'STABLERV_RCHI2',
        'STABLERV_CHI2_PROB', 'CHI2_THRESHOLD', 'APSTAR_VERSION',
        'ASPCAP_VERSION', 'RESULTS_VERSION', 'WASH_M', 'WASH_M_ERR', 'WASH_T2',
        'WASH_T2_ERR', 'DDO51', 'DDO51_ERR', 'IRAC_3_6', 'IRAC_3_6_ERR',
        'IRAC_4_5', 'IRAC_4_5_ERR', 'IRAC_5_8', 'IRAC_5_8_ERR', 'IRAC_8_0',
        'IRAC_8_0_ERR', 'WISE_4_5', 'WISE_4_5_ERR', 'TARG_4_5', 'TARG_4_5_ERR',
        'WASH_DDO51_GIANT_FLAG', 'WASH_DDO51_STAR_FLAG', 'REDUCTION_ID',
        'SRC_H', 'PM_SRC'
    ])
    if not appath._APOGEE_REDUX.lower() == 'current' \
            and not 'l30' in appath._APOGEE_REDUX \
            and int(appath._APOGEE_REDUX[1:]) < 500:
        data = esutil.numpy_util.remove_fields(data, ['ELEM'])
    #Select red-clump stars
    jk = data['J0'] - data['K0']
    z = isodist.FEH2Z(data['METALS'], zsolar=0.017)
    if 'l30' in appath._APOGEE_REDUX:
        logg = data['LOGG']
    elif appath._APOGEE_REDUX.lower() == 'current' \
            or int(appath._APOGEE_REDUX[1:]) > 600:
        from apogee.tools import paramIndx
        if False:
            #Use my custom logg calibration that's correct for the RC
            logg = (1. - 0.042) * data['FPARAM'][:, paramIndx('logg')] - 0.213
            lowloggindx = data['FPARAM'][:, paramIndx('logg')] < 1.
            logg[lowloggindx] = data['FPARAM'][lowloggindx,
                                               paramIndx('logg')] - 0.255
            hiloggindx = data['FPARAM'][:, paramIndx('logg')] > 3.8
            logg[hiloggindx] = data['FPARAM'][hiloggindx,
                                              paramIndx('logg')] - 0.3726
        else:
            #Use my custom logg calibration that's correct on average
            logg = (1. + 0.03) * data['FPARAM'][:, paramIndx('logg')] - 0.37
            lowloggindx = data['FPARAM'][:, paramIndx('logg')] < 1.
            logg[lowloggindx] = data['FPARAM'][lowloggindx,
                                               paramIndx('logg')] - 0.34
            hiloggindx = data['FPARAM'][:, paramIndx('logg')] > 3.8
            logg[hiloggindx] = data['FPARAM'][hiloggindx,
                                              paramIndx('logg')] - 0.256
    else:
        logg = data['LOGG']
    indx= (jk < 0.8)*(jk >= 0.5)\
        *(z <= 0.06)\
        *(z <= rcmodel.jkzcut(jk,upper=True))\
        *(z >= rcmodel.jkzcut(jk))\
        *(logg >= rcmodel.loggteffcut(data['TEFF'],z,upper=False))\
        *(logg <= rcmodel.loggteffcut(data['TEFF'],z,upper=True))
    data = data[indx]
    #Add more aggressive flag cut
    data = esutil.numpy_util.add_fields(data, [('ADDL_LOGG_CUT', numpy.int32)])
    data['ADDL_LOGG_CUT'] = (
        (data['TEFF'] - 4800.) / 1000. + 2.75) > data['LOGG']
    if options.loggcut:
        data = data[data['ADDL_LOGG_CUT'] == 1]
    print("Making catalog of %i objects ..." % len(data))
    #Add distances
    data = esutil.numpy_util.add_fields(data, [('RC_DIST', float),
                                               ('RC_DM', float),
                                               ('RC_GALR', float),
                                               ('RC_GALPHI', float),
                                               ('RC_GALZ', float)])
    rcd = rcmodel.rcdist()
    jk = data['J0'] - data['K0']
    z = isodist.FEH2Z(data['METALS'], zsolar=0.017)
    data['RC_DIST'] = rcd(jk, z, appmag=data['K0']) * options.distfac
    data['RC_DM'] = 5. * numpy.log10(data['RC_DIST']) + 10.
    XYZ = bovy_coords.lbd_to_XYZ(data['GLON'],
                                 data['GLAT'],
                                 data['RC_DIST'],
                                 degree=True)
    R, phi, Z = bovy_coords.XYZ_to_galcencyl(XYZ[:, 0],
                                             XYZ[:, 1],
                                             XYZ[:, 2],
                                             Xsun=8.,
                                             Zsun=0.025)
    data['RC_GALR'] = R
    data['RC_GALPHI'] = phi
    data['RC_GALZ'] = Z
    #Save
    fitsio.write(savefilename, data, clobber=True)
    # Add Tycho-2 matches
    if options.tyc2:
        data = esutil.numpy_util.add_fields(data, [('TYC2MATCH', numpy.int32),
                                                   ('TYC1', numpy.int32),
                                                   ('TYC2', numpy.int32),
                                                   ('TYC3', numpy.int32)])
        data['TYC2MATCH'] = 0
        data['TYC1'] = -1
        data['TYC2'] = -1
        data['TYC3'] = -1
        # Write positions
        posfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        resultfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        with open(posfilename, 'w') as csvfile:
            wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA', 'DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'], data[ii]['DEC']])
        # Send to CDS for matching
        result = open(resultfilename, 'w')
        try:
            subprocess.check_call([
                'curl', '-X', 'POST', '-F', 'request=xmatch', '-F',
                'distMaxArcsec=2', '-F', 'RESPONSEFORMAT=csv', '-F',
                'cat1=@%s' % os.path.basename(posfilename), '-F', 'colRA1=RA',
                '-F', 'colDec1=DEC', '-F', 'cat2=vizier:Tycho2',
                'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'
            ],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Directly match on input RA
        ma = numpy.loadtxt(resultfilename,
                           delimiter=',',
                           skiprows=1,
                           usecols=(1, 2, 7, 8, 9))
        iis = numpy.arange(len(data))
        mai = [iis[data['RA'] == ma[ii, 0]][0] for ii in range(len(ma))]
        data['TYC2MATCH'][mai] = 1
        data['TYC1'][mai] = ma[:, 2]
        data['TYC2'][mai] = ma[:, 3]
        data['TYC3'][mai] = ma[:, 4]
        os.remove(posfilename)
        os.remove(resultfilename)
    if not options.nostat:
        #Determine statistical sample and add flag
        apo = apogee.select.apogeeSelect()
        statIndx = apo.determine_statistical(data)
        mainIndx = apread.mainIndx(data)
        data = esutil.numpy_util.add_fields(data, [('STAT', numpy.int32),
                                                   ('INVSF', float)])
        data['STAT'] = 0
        data['STAT'][statIndx * mainIndx] = 1
        for ii in range(len(data)):
            if (statIndx * mainIndx)[ii]:
                data['INVSF'][ii] = 1. / apo(data['LOCATION_ID'][ii],
                                             data['H'][ii])
            else:
                data['INVSF'][ii] = -1.
    if options.nopm:
        fitsio.write(savefilename, data, clobber=True)
        return None
    #Get proper motions, in a somewhat roundabout way
    pmfile = savefilename.split('.')[0] + '_pms.fits'
    if os.path.exists(pmfile):
        pmdata = fitsio.read(pmfile, 1)
    else:
        pmdata = numpy.recarray(
            len(data),
            formats=['f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'i4'],
            names=[
                'RA', 'DEC', 'PMRA', 'PMDEC', 'PMRA_ERR', 'PMDEC_ERR',
                'PMMATCH'
            ])
        # Write positions, again ...
        posfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        resultfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        with open(posfilename, 'w') as csvfile:
            wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA', 'DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'], data[ii]['DEC']])
        # Send to CDS for matching
        result = open(resultfilename, 'w')
        try:
            subprocess.check_call([
                'curl', '-X', 'POST', '-F', 'request=xmatch', '-F',
                'distMaxArcsec=4', '-F', 'RESPONSEFORMAT=csv', '-F',
                'cat1=@%s' % os.path.basename(posfilename), '-F', 'colRA1=RA',
                '-F', 'colDec1=DEC', '-F', 'cat2=vizier:UCAC4',
                'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'
            ],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Match back and only keep the closest one
        ma = numpy.loadtxt(resultfilename,
                           delimiter=',',
                           skiprows=1,
                           converters={
                               15: lambda s: float(s.strip() or -9999),
                               16: lambda s: float(s.strip() or -9999),
                               17: lambda s: float(s.strip() or -9999),
                               18: lambda s: float(s.strip() or -9999)
                           },
                           usecols=(4, 5, 15, 16, 17, 18))
        h = esutil.htm.HTM()
        m1, m2, d12 = h.match(data['RA'],
                              data['DEC'],
                              ma[:, 0],
                              ma[:, 1],
                              4. / 3600.,
                              maxmatch=1)
        pmdata['PMMATCH'] = 0
        pmdata['RA'] = data['RA']
        pmdata['DEC'] = data['DEC']
        pmdata['PMMATCH'][m1] = 1
        pmdata['PMRA'][m1] = ma[m2, 2]
        pmdata['PMDEC'][m1] = ma[m2, 3]
        pmdata['PMRA_ERR'][m1] = ma[m2, 4]
        pmdata['PMDEC_ERR'][m1] = ma[m2, 5]
        pmdata['PMMATCH'][(pmdata['PMRA'] == -9999) \
                          +(pmdata['PMDEC'] == -9999) \
                          +(pmdata['PMRA_ERR'] == -9999) \
                          +(pmdata['PMDEC_ERR'] == -9999)]= 0
        fitsio.write(pmfile, pmdata, clobber=True)
        #To make sure we're using the same format below
        pmdata = fitsio.read(pmfile, 1)
        os.remove(posfilename)
        os.remove(resultfilename)
    #Match proper motions
    try:  #These already exist currently, but may not always exist
        data = esutil.numpy_util.remove_fields(data, ['PMRA', 'PMDEC'])
    except ValueError:
        pass
    data = esutil.numpy_util.add_fields(data, [('PMRA', numpy.float),
                                               ('PMDEC', numpy.float),
                                               ('PMRA_ERR', numpy.float),
                                               ('PMDEC_ERR', numpy.float),
                                               ('PMMATCH', numpy.int32)])
    data['PMMATCH'] = 0
    h = esutil.htm.HTM()
    m1, m2, d12 = h.match(pmdata['RA'],
                          pmdata['DEC'],
                          data['RA'],
                          data['DEC'],
                          2. / 3600.,
                          maxmatch=1)
    data['PMRA'][m2] = pmdata['PMRA'][m1]
    data['PMDEC'][m2] = pmdata['PMDEC'][m1]
    data['PMRA_ERR'][m2] = pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR'][m2] = pmdata['PMDEC_ERR'][m1]
    data['PMMATCH'][m2] = pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx = data['PMMATCH'] == 1
    data['PMRA'][True - pmindx] = -9999.99
    data['PMDEC'][True - pmindx] = -9999.99
    data['PMRA_ERR'][True - pmindx] = -9999.99
    data['PMDEC_ERR'][True - pmindx] = -9999.99
    #Calculate Galactocentric velocities
    data = esutil.numpy_util.add_fields(data, [('GALVR', numpy.float),
                                               ('GALVT', numpy.float),
                                               ('GALVZ', numpy.float)])
    lb = bovy_coords.radec_to_lb(data['RA'], data['DEC'], degree=True)
    XYZ = bovy_coords.lbd_to_XYZ(lb[:, 0],
                                 lb[:, 1],
                                 data['RC_DIST'],
                                 degree=True)
    pmllpmbb = bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA'],
                                                 data['PMDEC'],
                                                 data['RA'],
                                                 data['DEC'],
                                                 degree=True)
    vxvyvz = bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                              pmllpmbb[:, 0],
                                              pmllpmbb[:, 1],
                                              lb[:, 0],
                                              lb[:, 1],
                                              data['RC_DIST'],
                                              degree=True)
    vR, vT, vZ = bovy_coords.vxvyvz_to_galcencyl(
        vxvyvz[:, 0],
        vxvyvz[:, 1],
        vxvyvz[:, 2],
        8. - XYZ[:, 0],
        XYZ[:, 1],
        XYZ[:, 2] + 0.025,
        vsun=[-11.1, 30.24 * 8.,
              7.25])  #Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR'] = vR
    data['GALVT'] = vT
    data['GALVZ'] = vZ
    data['GALVR'][True - pmindx] = -9999.99
    data['GALVT'][True - pmindx] = -9999.99
    data['GALVZ'][True - pmindx] = -9999.99
    #Get PPMXL proper motions, in a somewhat roundabout way
    pmfile = savefilename.split('.')[0] + '_pms_ppmxl.fits'
    if os.path.exists(pmfile):
        pmdata = fitsio.read(pmfile, 1)
    else:
        pmdata = numpy.recarray(
            len(data),
            formats=['f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'i4'],
            names=[
                'RA', 'DEC', 'PMRA', 'PMDEC', 'PMRA_ERR', 'PMDEC_ERR',
                'PMMATCH'
            ])
        # Write positions, again ...
        posfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        resultfilename = tempfile.mktemp('.csv', dir=os.getcwd())
        with open(posfilename, 'w') as csvfile:
            wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA', 'DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'], data[ii]['DEC']])
        # Send to CDS for matching
        result = open(resultfilename, 'w')
        try:
            subprocess.check_call([
                'curl', '-X', 'POST', '-F', 'request=xmatch', '-F',
                'distMaxArcsec=4', '-F', 'RESPONSEFORMAT=csv', '-F',
                'cat1=@%s' % os.path.basename(posfilename), '-F', 'colRA1=RA',
                '-F', 'colDec1=DEC', '-F', 'cat2=vizier:PPMXL',
                'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'
            ],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Match back and only keep the closest one
        ma = numpy.loadtxt(resultfilename,
                           delimiter=',',
                           skiprows=1,
                           converters={
                               15: lambda s: float(s.strip() or -9999),
                               16: lambda s: float(s.strip() or -9999),
                               17: lambda s: float(s.strip() or -9999),
                               18: lambda s: float(s.strip() or -9999)
                           },
                           usecols=(4, 5, 15, 16, 19, 20))
        h = esutil.htm.HTM()
        m1, m2, d12 = h.match(data['RA'],
                              data['DEC'],
                              ma[:, 0],
                              ma[:, 1],
                              4. / 3600.,
                              maxmatch=1)
        pmdata['PMMATCH'] = 0
        pmdata['RA'] = data['RA']
        pmdata['DEC'] = data['DEC']
        pmdata['PMMATCH'][m1] = 1
        pmdata['PMRA'][m1] = ma[m2, 2]
        pmdata['PMDEC'][m1] = ma[m2, 3]
        pmdata['PMRA_ERR'][m1] = ma[m2, 4]
        pmdata['PMDEC_ERR'][m1] = ma[m2, 5]
        pmdata['PMMATCH'][(pmdata['PMRA'] == -9999) \
                          +(pmdata['PMDEC'] == -9999) \
                          +(pmdata['PMRA_ERR'] == -9999) \
                          +(pmdata['PMDEC_ERR'] == -9999)]= 0
        fitsio.write(pmfile, pmdata, clobber=True)
        #To make sure we're using the same format below
        pmdata = fitsio.read(pmfile, 1)
        os.remove(posfilename)
        os.remove(resultfilename)
    #Match proper motions to ppmxl
    data = esutil.numpy_util.add_fields(data,
                                        [('PMRA_PPMXL', numpy.float),
                                         ('PMDEC_PPMXL', numpy.float),
                                         ('PMRA_ERR_PPMXL', numpy.float),
                                         ('PMDEC_ERR_PPMXL', numpy.float),
                                         ('PMMATCH_PPMXL', numpy.int32)])
    data['PMMATCH_PPMXL'] = 0
    h = esutil.htm.HTM()
    m1, m2, d12 = h.match(pmdata['RA'],
                          pmdata['DEC'],
                          data['RA'],
                          data['DEC'],
                          2. / 3600.,
                          maxmatch=1)
    data['PMRA_PPMXL'][m2] = pmdata['PMRA'][m1]
    data['PMDEC_PPMXL'][m2] = pmdata['PMDEC'][m1]
    data['PMRA_ERR_PPMXL'][m2] = pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR_PPMXL'][m2] = pmdata['PMDEC_ERR'][m1]
    data['PMMATCH_PPMXL'][m2] = pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx = data['PMMATCH_PPMXL'] == 1
    data['PMRA_PPMXL'][True - pmindx] = -9999.99
    data['PMDEC_PPMXL'][True - pmindx] = -9999.99
    data['PMRA_ERR_PPMXL'][True - pmindx] = -9999.99
    data['PMDEC_ERR_PPMXL'][True - pmindx] = -9999.99
    #Calculate Galactocentric velocities
    data = esutil.numpy_util.add_fields(data, [('GALVR_PPMXL', numpy.float),
                                               ('GALVT_PPMXL', numpy.float),
                                               ('GALVZ_PPMXL', numpy.float)])
    lb = bovy_coords.radec_to_lb(data['RA'], data['DEC'], degree=True)
    XYZ = bovy_coords.lbd_to_XYZ(lb[:, 0],
                                 lb[:, 1],
                                 data['RC_DIST'],
                                 degree=True)
    pmllpmbb = bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA_PPMXL'],
                                                 data['PMDEC_PPMXL'],
                                                 data['RA'],
                                                 data['DEC'],
                                                 degree=True)
    vxvyvz = bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                              pmllpmbb[:, 0],
                                              pmllpmbb[:, 1],
                                              lb[:, 0],
                                              lb[:, 1],
                                              data['RC_DIST'],
                                              degree=True)
    vR, vT, vZ = bovy_coords.vxvyvz_to_galcencyl(
        vxvyvz[:, 0],
        vxvyvz[:, 1],
        vxvyvz[:, 2],
        8. - XYZ[:, 0],
        XYZ[:, 1],
        XYZ[:, 2] + 0.025,
        vsun=[-11.1, 30.24 * 8.,
              7.25])  #Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR_PPMXL'] = vR
    data['GALVT_PPMXL'] = vT
    data['GALVZ_PPMXL'] = vZ
    data['GALVR_PPMXL'][True - pmindx] = -9999.99
    data['GALVT_PPMXL'][True - pmindx] = -9999.99
    data['GALVZ_PPMXL'][True - pmindx] = -9999.99
    #Save
    fitsio.write(savefilename, data, clobber=True)
    return None
Beispiel #14
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
Beispiel #15
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
Beispiel #16
0
def allStar(rmcommissioning=True,
            main=False,
            exclude_star_bad=False,
            exclude_star_warn=False,
            ak=True,
            akvers='targ',
            rmnovisits=False,
            adddist=False,
            distredux=None,
            rmdups=False,
            raw=False):
    """
    NAME:
       allStar
    PURPOSE:
       read the allStar file
    INPUT:
       rmcommissioning= (default: True) if True, only use data obtained after commissioning
       main= (default: False) if True, only select stars in the main survey
       exclude_star_bad= (False) if True, remove stars with the STAR_BAD flag set in ASPCAPFLAG
       exclude_star_warn= (False) if True, remove stars with the STAR_WARN flag set in ASPCAPFLAG
       ak= (default: True) only use objects for which dereddened mags exist
       akvers= 'targ' (default) or 'wise': use target AK (AK_TARG) or AK derived from all-sky WISE (AK_WISE)
       rmnovisits= (False) if True, remove stars with no good visits (to go into the combined spectrum); shouldn't be necessary
       adddist= (default: False) add distances (DR10/11 Hayden distances, DR12 combined distances)
       distredux= (default: DR default) reduction on which the distances are based
       rmdups= (False) if True, remove duplicates (very slow)
       raw= (False) if True, just return the raw file, read w/ fitsio
    OUTPUT:
       allStar data
    HISTORY:
       2013-09-06 - Written - Bovy (IAS)
    """
    filePath = path.allStarPath()
    if not os.path.exists(filePath):
        download.allStar()
    #read allStar file
    data = fitsio.read(path.allStarPath())
    if raw: return data
    #Remove duplicates, cache
    if rmdups:
        dupsFilename = path.allStarPath().replace('.fits', '-nodups.fits')
        if os.path.exists(dupsFilename):
            data = fitsio.read(dupsFilename)
        else:
            sys.stdout.write(
                '\r' +
                "Removing duplicates (might take a while) and caching the duplicate-free file ...\r"
            )
            sys.stdout.flush()
            data = remove_duplicates(data)
            #Cache this file for subsequent use of rmdups
            fitsio.write(dupsFilename, data, clobber=True)
            sys.stdout.write('\r' + _ERASESTR + '\r')
            sys.stdout.flush()
    #Some cuts
    if rmcommissioning:
        indx = numpy.array(
            ['apogee.n.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
        indx += numpy.array(
            ['apogee.s.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
        data = data[True - indx]
    if rmnovisits:
        indx = numpy.array([s.strip() != '' for s in data['VISITS']])
        data = data[indx]
    if main:
        indx = mainIndx(data)
        data = data[indx]
    if akvers.lower() == 'targ':
        aktag = 'AK_TARG'
    elif akvers.lower() == 'wise':
        aktag = 'AK_WISE'
    if ak:
        data = data[True - numpy.isnan(data[aktag])]
        data = data[(data[aktag] > -50.)]
    if exclude_star_bad:
        data = data[(data['ASPCAPFLAG'] & 2**23) == 0]
    if exclude_star_warn:
        data = data[(data['ASPCAPFLAG'] & 2**7) == 0]
    #Add dereddened J, H, and Ks
    aj = data[aktag] * 2.5
    ah = data[aktag] * 1.55
    if _ESUTIL_LOADED:
        data = esutil.numpy_util.add_fields(data,
                                            [('J0', float), ('H0', float),
                                             ('K0', float)])
        data['J0'] = data['J'] - aj
        data['H0'] = data['H'] - ah
        data['K0'] = data['K'] - data[aktag]
        data['J0'][(data[aktag] <= -50.)] = -9999.9999
        data['H0'][(data[aktag] <= -50.)] = -9999.9999
        data['K0'][(data[aktag] <= -50.)] = -9999.9999
    else:
        warnings.warn(
            "Extinction-corrected J,H,K not added because esutil is not installed",
            RuntimeWarning)
    #Add distances
    if adddist and _ESUTIL_LOADED:
        dist = fitsio.read(path.distPath(), 1)
        h = esutil.htm.HTM()
        m1, m2, d12 = h.match(dist['RA'],
                              dist['DEC'],
                              data['RA'],
                              data['DEC'],
                              2. / 3600.,
                              maxmatch=1)
        data = data[m2]
        dist = dist[m1]
        distredux = path._redux_dr()
        if distredux.lower() == 'v302' or distredux.lower() == path._DR10REDUX:
            data = esutil.numpy_util.add_fields(data, [('DM05', float),
                                                       ('DM16', float),
                                                       ('DM50', float),
                                                       ('DM84', float),
                                                       ('DM95', float),
                                                       ('DMPEAK', float),
                                                       ('DMAVG', float),
                                                       ('SIG_DM', float),
                                                       ('DIST_SOL', float),
                                                       ('SIG_DISTSOL', float)])
            data['DM05'] = dist['DM05']
            data['DM16'] = dist['DM16']
            data['DM50'] = dist['DM50']
            data['DM84'] = dist['DM84']
            data['DM95'] = dist['DM95']
            data['DMPEAK'] = dist['DMPEAK']
            data['DMAVG'] = dist['DMAVG']
            data['SIG_DM'] = dist['SIG_DM']
            data['DIST_SOL'] = dist['DIST_SOL'] / 1000.
            data['SIG_DISTSOL'] = dist['SIG_DISTSOL'] / 1000.
        elif distredux.lower() == path._DR11REDUX:
            data = esutil.numpy_util.add_fields(data, [('DISO', float),
                                                       ('DMASS', float),
                                                       ('DISO_GAL', float),
                                                       ('DMASS_GAL', float)])
            data['DISO'] = dist['DISO'][:, 1]
            data['DMASS'] = dist['DMASS'][:, 1]
            data['DISO_GAL'] = dist['DISO_GAL'][:, 1]
            data['DMASS_GAL'] = dist['DMASS_GAL'][:, 1]
        elif distredux.lower() == path._DR12REDUX:
            data = esutil.numpy_util.add_fields(
                data, [('HIP_PLX', float), ('HIP_E_PLX', float),
                       ('RC_DIST', float), ('APOKASC_DIST_DIRECT', float),
                       ('BPG_DIST1_MEAN', float), ('HAYDEN_DIST_PEAK', float),
                       ('SCHULTHEIS_DIST', float)])
            data['HIP_PLX'] = dist['HIP_PLX']
            data['HIP_E_PLX'] = dist['HIP_E_PLX']
            data['RC_DIST'] = dist['RC_dist_pc']
            data[
                'APOKASC_DIST_DIRECT'] = dist['APOKASC_dist_direct_pc'] / 1000.
            data['BPG_DIST1_MEAN'] = dist['BPG_dist1_mean']
            data['HAYDEN_DIST_PEAK'] = 10.**(dist['HAYDEN_distmod_PEAK'] / 5. -
                                             2.)
            data['SCHULTHEIS_DIST'] = dist['SCHULTHEIS_dist']
    elif adddist:
        warnings.warn(
            "Distances not added because matching requires the uninstalled esutil module",
            RuntimeWarning)
    if _ESUTIL_LOADED and (path._APOGEE_REDUX.lower() == 'current' \
                               or 'l30' in path._APOGEE_REDUX.lower() \
                               or int(path._APOGEE_REDUX[1:]) > 600):
        data = esutil.numpy_util.add_fields(data, [('METALS', float),
                                                   ('ALPHAFE', float)])
        data['METALS'] = data['PARAM'][:, paramIndx('metals')]
        data['ALPHAFE'] = data['PARAM'][:, paramIndx('alpha')]
    return data
Beispiel #17
0
def fit(spec,specerr,
        teff=4750.,logg=2.5,metals=0.,am=0.,nm=0.,cm=0.,vm=None,
        fixteff=False,fixlogg=False,fixmetals=False,fixam=False,fixcm=False,
        fixnm=False,fixvm=False,
        lib='GK',pca=True,sixd=True,dr=None,
        offile=None,
        inter=3,f_format=1,f_access=None,
        errbar=1,indini=[1,1,1,2,2,3],init=1,initcannon=False,
        verbose=False):
    """
    NAME:
       fit
    PURPOSE:
       Fit a model spectrum to a given data spectrum
    INPUT:
       Either:
          (1) location ID - single or list/array of location IDs
              APOGEE ID - single or list/array of APOGEE IDs; loads aspcapStar
          (2) spec - spectrum: can be (nwave) or (nspec,nwave)
              specerr - spectrum errors: can be (nwave) or (nspec,nwave)
       Input parameters (can be 1D arrays); only used when init=0
          teff= (4750.) Effective temperature (K)
          logg= (2.5) log10 surface gravity / cm s^-2
          metals= (0.) overall metallicity
          am= (0.) [alpha/M]
          nm= (0.) [N/M]
          cm= (0.) [C/M]
          vm= if using the 7D library, also specify the microturbulence
       Fit options:
          fixteff= (False) if True, fix teff at the input value
          fixlogg= (False) if True, fix logg at the input value
          fixmetals= (False) if True, fix metals at the input value
          fixam= (False) if True, fix am at the input value
          fixcm= (False) if True, fix cm at the input value
          fixnm= (False) if True, fix nm at the input value
          fixvm= (False) if True, fix vm at the input value (only if sixd is False)
       Library options:
          lib= ('GK') spectral library
          pca= (True) if True, use a PCA compressed library
          sixd= (True) if True, use the 6D library (w/o vm)
          dr= data release
       FERRE options:
          inter= (3) order of the interpolation
          errbar= (1) method for calculating the error bars
          indini= ([1,1,1,2,2,3]) how to initialize the search (int or array/list with ndim entries)
          init= (1) if 0, initialize the search at the parameters in the pfile
          f_format= (1) file format (0=ascii, 1=unf)
          f_access= (None) 0: load whole library, 1: use direct access (for small numbers of interpolations), None: automatically determine a good value (currently, 1)
       Other options:
          initcannon= (False) If True, initialize a single run by first running the Cannon using the default Cannon fit (sets init=0)
       Output options:
          offile= (None) if offile is set, the FERRE OFFILE is saved to this file, otherwise this file is removed
       verbose= (False) if True, run FERRE in verbose mode
    OUTPUT:
       best-fit parameters (nspec,nparams); in the same order as the FPARAM APOGEE data product
    HISTORY:
       2015-01-29 - Written - Bovy (IAS)
    """
    # Initialize using the Cannon?
    if initcannon:
        init= 0 # just run one fit using the Cannon as a starting guess
        initparams= cannon.polylabels(spec,specerr)
        if not fixteff: teff= initparams[:,0]
        if not fixlogg: logg= initparams[:,1]
        if not fixmetals: metals= initparams[:,2]
        if not fixam: am= initparams[:,3]
        if not fixcm: cm= numpy.zeros_like(initparams[:,0])
        if not fixnm: nm= numpy.zeros_like(initparams[:,0])
    # Make sure the Teff etc. have the right dimensionality
    if len(spec.shape) == 1:
        nspec= 1
    else:
        nspec= spec.shape[0]
    if nspec > 1 and isinstance(teff,float):
        teff= teff*numpy.ones(nspec)
    if nspec > 1 and isinstance(logg,float):
        logg= logg*numpy.ones(nspec)
    if nspec > 1 and isinstance(metals,float):
        metals= metals*numpy.ones(nspec)
    if nspec > 1 and isinstance(am,float):
        am= am*numpy.ones(nspec)
    if nspec > 1 and isinstance(nm,float):
        nm= nm*numpy.ones(nspec)
    if nspec > 1 and isinstance(cm,float):
        cm= cm*numpy.ones(nspec)
    if nspec > 1 and not vm is None and isinstance(vm,float):
        vm= vm*numpy.ones(nspec)
    if dr is None: dr= appath._default_dr()
    # Fix any of the parameters?
    indv= []
    indini= copy.copy(indini) # need to copy bc passed by reference
    if isinstance(indini,numpy.ndarray) and \
            ((not sixd and fixvm) or fixcm or fixnm or fixam or fixmetals \
                 or fixlogg or fixteff):
        indini= list(indini)
    if not sixd and not fixvm:
        indv.append(1)
    elif not sixd:
        if isinstance(indini,list): indini[0]= -1
    if not fixcm:
        indv.append(2-sixd)
    else:
        if isinstance(indini,list): indini[1-sixd]= -1
    if not fixnm:
        indv.append(3-sixd)
    else:
        if isinstance(indini,list): indini[2-sixd]= -1
    if not fixam:
        indv.append(4-sixd)
    else:
        if isinstance(indini,list): indini[3-sixd]= -1
    if not fixmetals:
        indv.append(5-sixd)
    else:
        if isinstance(indini,list): indini[4-sixd]= -1
    if not fixlogg:
        indv.append(6-sixd)
    else:
        if isinstance(indini,list): indini[5-sixd]= -1
    if not fixteff:
        indv.append(7-sixd)
    else:
        if isinstance(indini,list): indini[6-sixd]= -1
    if isinstance(indini,list):
        while -1 in indini: indini.remove(-1)
    # Setup temporary directory to run FERRE from
    tmpDir= tempfile.mkdtemp(dir='./')
    try:
        # First write the ipf file with the parameters
        write_ipf(tmpDir,teff,logg,metals,am,nm,cm,vm=vm)
        # Write the file with the fluxes and the flux errors
        write_ffile(tmpDir,spec,specerr=specerr)
        # Now write the input.nml file
        if f_access is None:
            f_access= 1
        write_input_nml(tmpDir,'input.ipf','output.dat',ndim=7-sixd,
                        nov=7-sixd-fixcm-fixnm-fixam-fixmetals\
                            -fixlogg-fixteff,
                        indv=indv,
                        synthfile=appath.ferreModelLibraryPath\
                            (lib=lib,pca=pca,sixd=sixd,dr=dr,
                             header=True,unf=False),
                        ffile='input.frd',erfile='input.err',
                        opfile='output.opf',
                        inter=inter,f_format=f_format,
                        errbar=errbar,indini=indini,init=init,
                        f_access=f_access)
        # Run FERRE
        run_ferre(tmpDir,verbose=verbose)
        # Read the output
        cols= (1,2,3,4,5,6)
        tmpOut= numpy.loadtxt(os.path.join(tmpDir,'output.opf'),usecols=cols)
        if len(spec.shape) == 1 or spec.shape[0] == 1:
            out= numpy.zeros((1,7))
            tmpOut= numpy.reshape(tmpOut,(1,7-sixd))
        else:
            out= numpy.zeros((nspec,7))
        out[:,paramIndx('TEFF')]= tmpOut[:,-1]
        out[:,paramIndx('LOGG')]= tmpOut[:,-2]
        out[:,paramIndx('METALS')]= tmpOut[:,-3]
        out[:,paramIndx('ALPHA')]= tmpOut[:,-4]
        out[:,paramIndx('N')]= tmpOut[:,-5]
        out[:,paramIndx('C')]= tmpOut[:,-6]
        if sixd and dr == '12':
            out[:,paramIndx('LOG10VDOP')]=\
                numpy.log10(2.478-0.325*out[:,paramIndx('LOGG')])
        else:
            out[:,paramIndx('LOG10VDOP')]= tmpOut[:,0]
        if not offile is None:
            os.rename(os.path.join(tmpDir,'output.dat'),offile)
    finally:
        # Clean up
        if os.path.exists(os.path.join(tmpDir,'input.ipf')):
            os.remove(os.path.join(tmpDir,'input.ipf'))
        if os.path.exists(os.path.join(tmpDir,'input.frd')):
            os.remove(os.path.join(tmpDir,'input.frd'))
        if os.path.exists(os.path.join(tmpDir,'input.err')):
            os.remove(os.path.join(tmpDir,'input.err'))
        if os.path.exists(os.path.join(tmpDir,'input.nml')):
            os.remove(os.path.join(tmpDir,'input.nml'))
        if os.path.exists(os.path.join(tmpDir,'output.dat')):
            os.remove(os.path.join(tmpDir,'output.dat'))
        if os.path.exists(os.path.join(tmpDir,'output.opf')):
            os.remove(os.path.join(tmpDir,'output.opf'))
        os.rmdir(tmpDir)
    return out
Beispiel #18
0
def make_rcsample(parser):
    options,args= parser.parse_args()
    savefilename= options.savefilename
    if savefilename is None:
        #Create savefilename if not given
        savefilename= os.path.join(appath._APOGEE_DATA,
                                   'rcsample_'+appath._APOGEE_REDUX+'.fits')
        print("Saving to %s ..." % savefilename)
    #Read the base-sample
    data= apread.allStar(adddist=_ADDHAYDENDIST,rmdups=options.rmdups)
    #Remove a bunch of fields that we do not want to keep
    data= esutil.numpy_util.remove_fields(data,
                                          ['TARGET_ID',
                                           'FILE',
                                           'AK_WISE',
                                           'SFD_EBV',
                                           'SYNTHVHELIO_AVG',
                                           'SYNTHVSCATTER',
                                           'SYNTHVERR',
                                           'SYNTHVERR_MED',
                                           'RV_TEFF',
                                           'RV_LOGG',
                                           'RV_FEH',
                                           'RV_ALPHA',
                                           'RV_CARB',
                                           'RV_CCFWHM',
                                           'RV_AUTOFWHM',
                                           'SYNTHSCATTER',
                                           'STABLERV_CHI2',
                                           'STABLERV_RCHI2',
                                           'STABLERV_CHI2_PROB',
                                           'CHI2_THRESHOLD',
                                           'APSTAR_VERSION',
                                           'ASPCAP_VERSION',
                                           'RESULTS_VERSION',
                                           'WASH_M',
                                           'WASH_M_ERR',
                                           'WASH_T2',
                                           'WASH_T2_ERR',
                                           'DDO51',
                                           'DDO51_ERR',
                                           'IRAC_3_6',
                                           'IRAC_3_6_ERR',
                                           'IRAC_4_5',
                                           'IRAC_4_5_ERR',
                                           'IRAC_5_8',
                                           'IRAC_5_8_ERR',
                                           'IRAC_8_0',
                                           'IRAC_8_0_ERR',
                                           'WISE_4_5',
                                           'WISE_4_5_ERR',
                                           'TARG_4_5',
                                           'TARG_4_5_ERR',
                                           'WASH_DDO51_GIANT_FLAG',
                                           'WASH_DDO51_STAR_FLAG',
                                           'REDUCTION_ID',
                                           'SRC_H',
                                           'PM_SRC'])
    if not appath._APOGEE_REDUX.lower() == 'current' \
            and not 'l30' in appath._APOGEE_REDUX \
            and int(appath._APOGEE_REDUX[1:]) < 500:
        data= esutil.numpy_util.remove_fields(data,
                                              ['ELEM'])
    #Select red-clump stars
    jk= data['J0']-data['K0']
    z= isodist.FEH2Z(data['METALS'],zsolar=0.017)
    if 'l30' in appath._APOGEE_REDUX:
        logg= data['LOGG']
    elif appath._APOGEE_REDUX.lower() == 'current' \
            or int(appath._APOGEE_REDUX[1:]) > 600:
        from apogee.tools import paramIndx
        if False:
            #Use my custom logg calibration that's correct for the RC
            logg= (1.-0.042)*data['FPARAM'][:,paramIndx('logg')]-0.213
            lowloggindx= data['FPARAM'][:,paramIndx('logg')] < 1.
            logg[lowloggindx]= data['FPARAM'][lowloggindx,paramIndx('logg')]-0.255
            hiloggindx= data['FPARAM'][:,paramIndx('logg')] > 3.8
            logg[hiloggindx]= data['FPARAM'][hiloggindx,paramIndx('logg')]-0.3726
        else:
            #Use my custom logg calibration that's correct on average
            logg= (1.+0.03)*data['FPARAM'][:,paramIndx('logg')]-0.37
            lowloggindx= data['FPARAM'][:,paramIndx('logg')] < 1.
            logg[lowloggindx]= data['FPARAM'][lowloggindx,paramIndx('logg')]-0.34
            hiloggindx= data['FPARAM'][:,paramIndx('logg')] > 3.8
            logg[hiloggindx]= data['FPARAM'][hiloggindx,paramIndx('logg')]-0.256
    else:
        logg= data['LOGG']
    indx= (jk < 0.8)*(jk >= 0.5)\
        *(z <= 0.06)\
        *(z <= rcmodel.jkzcut(jk,upper=True))\
        *(z >= rcmodel.jkzcut(jk))\
        *(logg >= rcmodel.loggteffcut(data['TEFF'],z,upper=False))\
        *(logg <= rcmodel.loggteffcut(data['TEFF'],z,upper=True))
    data= data[indx]
    #Add more aggressive flag cut
    data= esutil.numpy_util.add_fields(data,[('ADDL_LOGG_CUT',numpy.int32)])
    data['ADDL_LOGG_CUT']= ((data['TEFF']-4800.)/1000.+2.75) > data['LOGG']
    if options.loggcut:
        data= data[data['ADDL_LOGG_CUT'] == 1]
    print("Making catalog of %i objects ..." % len(data))
    #Add distances
    data= esutil.numpy_util.add_fields(data,[('RC_DIST', float),
                                             ('RC_DM', float),
                                             ('RC_GALR', float),
                                             ('RC_GALPHI', float),
                                             ('RC_GALZ', float)])
    rcd= rcmodel.rcdist()
    jk= data['J0']-data['K0']
    z= isodist.FEH2Z(data['METALS'],zsolar=0.017)
    data['RC_DIST']= rcd(jk,z,appmag=data['K0'])*options.distfac
    data['RC_DM']= 5.*numpy.log10(data['RC_DIST'])+10.
    XYZ= bovy_coords.lbd_to_XYZ(data['GLON'],
                                data['GLAT'],
                                data['RC_DIST'],
                                degree=True)
    R,phi,Z= bovy_coords.XYZ_to_galcencyl(XYZ[:,0],
                                          XYZ[:,1],
                                          XYZ[:,2],
                                          Xsun=8.,Zsun=0.025)
    data['RC_GALR']= R
    data['RC_GALPHI']= phi
    data['RC_GALZ']= Z
    #Save
    fitsio.write(savefilename,data,clobber=True)
    # Add Tycho-2 matches
    if options.tyc2:
        data= esutil.numpy_util.add_fields(data,[('TYC2MATCH',numpy.int32),
                                                 ('TYC1',numpy.int32),
                                                 ('TYC2',numpy.int32),
                                                 ('TYC3',numpy.int32)])
        data['TYC2MATCH']= 0
        data['TYC1']= -1
        data['TYC2']= -1
        data['TYC3']= -1
        # Write positions
        posfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        resultfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        with open(posfilename,'w') as csvfile:
            wr= csv.writer(csvfile,delimiter=',',quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA','DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'],data[ii]['DEC']])
        # Send to CDS for matching
        result= open(resultfilename,'w')
        try:
            subprocess.check_call(['curl',
                                   '-X','POST',
                                   '-F','request=xmatch',
                                   '-F','distMaxArcsec=2',
                                   '-F','RESPONSEFORMAT=csv',
                                   '-F','cat1=@%s' % os.path.basename(posfilename),
                                   '-F','colRA1=RA',
                                   '-F','colDec1=DEC',
                                   '-F','cat2=vizier:Tycho2',
                                   'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Directly match on input RA
        ma= numpy.loadtxt(resultfilename,delimiter=',',skiprows=1,
                          usecols=(1,2,7,8,9))
        iis= numpy.arange(len(data))
        mai= [iis[data['RA'] == ma[ii,0]][0] for ii in range(len(ma))]
        data['TYC2MATCH'][mai]= 1
        data['TYC1'][mai]= ma[:,2]
        data['TYC2'][mai]= ma[:,3]
        data['TYC3'][mai]= ma[:,4]
        os.remove(posfilename)
        os.remove(resultfilename)
    if not options.nostat:
        #Determine statistical sample and add flag
        apo= apogee.select.apogeeSelect()
        statIndx= apo.determine_statistical(data)
        mainIndx= apread.mainIndx(data)
        data= esutil.numpy_util.add_fields(data,[('STAT',numpy.int32),
                                                 ('INVSF',float)])
        data['STAT']= 0
        data['STAT'][statIndx*mainIndx]= 1
        for ii in range(len(data)):
            if (statIndx*mainIndx)[ii]:
                data['INVSF'][ii]= 1./apo(data['LOCATION_ID'][ii],
                                          data['H'][ii])
            else:
                data['INVSF'][ii]= -1.
    if options.nopm:
        fitsio.write(savefilename,data,clobber=True)       
        return None
    #Get proper motions, in a somewhat roundabout way
    pmfile= savefilename.split('.')[0]+'_pms.fits'
    if os.path.exists(pmfile):
        pmdata= fitsio.read(pmfile,1)
    else:
        pmdata= numpy.recarray(len(data),
                               formats=['f8','f8','f8','f8','f8','f8','i4'],
                               names=['RA','DEC','PMRA','PMDEC',
                                      'PMRA_ERR','PMDEC_ERR','PMMATCH'])
        # Write positions, again ...
        posfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        resultfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        with open(posfilename,'w') as csvfile:
            wr= csv.writer(csvfile,delimiter=',',quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA','DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'],data[ii]['DEC']])
        # Send to CDS for matching
        result= open(resultfilename,'w')
        try:
            subprocess.check_call(['curl',
                                   '-X','POST',
                                   '-F','request=xmatch',
                                   '-F','distMaxArcsec=4',
                                   '-F','RESPONSEFORMAT=csv',
                                   '-F','cat1=@%s' % os.path.basename(posfilename),
                                   '-F','colRA1=RA',
                                   '-F','colDec1=DEC',
                                   '-F','cat2=vizier:UCAC4',
                                   'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Match back and only keep the closest one
        ma= numpy.loadtxt(resultfilename,delimiter=',',skiprows=1,
                          converters={15: lambda s: float(s.strip() or -9999),
                                      16: lambda s: float(s.strip() or -9999),
                                      17: lambda s: float(s.strip() or -9999),
                                      18: lambda s: float(s.strip() or -9999)},
                          usecols=(4,5,15,16,17,18))
        h=esutil.htm.HTM()
        m1,m2,d12 = h.match(data['RA'],data['DEC'],
                            ma[:,0],ma[:,1],4./3600.,maxmatch=1)
        pmdata['PMMATCH']= 0
        pmdata['RA']= data['RA']
        pmdata['DEC']= data['DEC']
        pmdata['PMMATCH'][m1]= 1
        pmdata['PMRA'][m1]= ma[m2,2]
        pmdata['PMDEC'][m1]= ma[m2,3]
        pmdata['PMRA_ERR'][m1]= ma[m2,4]
        pmdata['PMDEC_ERR'][m1]= ma[m2,5]
        pmdata['PMMATCH'][(pmdata['PMRA'] == -9999) \
                          +(pmdata['PMDEC'] == -9999) \
                          +(pmdata['PMRA_ERR'] == -9999) \
                          +(pmdata['PMDEC_ERR'] == -9999)]= 0
        fitsio.write(pmfile,pmdata,clobber=True)
        #To make sure we're using the same format below
        pmdata= fitsio.read(pmfile,1)
        os.remove(posfilename)
        os.remove(resultfilename)
    #Match proper motions
    try: #These already exist currently, but may not always exist
        data= esutil.numpy_util.remove_fields(data,['PMRA','PMDEC'])
    except ValueError:
        pass
    data= esutil.numpy_util.add_fields(data,[('PMRA', numpy.float),
                                             ('PMDEC', numpy.float),
                                             ('PMRA_ERR', numpy.float),
                                             ('PMDEC_ERR', numpy.float),
                                             ('PMMATCH',numpy.int32)])
    data['PMMATCH']= 0
    h=esutil.htm.HTM()
    m1,m2,d12 = h.match(pmdata['RA'],pmdata['DEC'],
                        data['RA'],data['DEC'],
                        2./3600.,maxmatch=1)
    data['PMRA'][m2]= pmdata['PMRA'][m1]
    data['PMDEC'][m2]= pmdata['PMDEC'][m1]
    data['PMRA_ERR'][m2]= pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR'][m2]= pmdata['PMDEC_ERR'][m1]
    data['PMMATCH'][m2]= pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx= data['PMMATCH'] == 1
    data['PMRA'][True-pmindx]= -9999.99
    data['PMDEC'][True-pmindx]= -9999.99
    data['PMRA_ERR'][True-pmindx]= -9999.99
    data['PMDEC_ERR'][True-pmindx]= -9999.99
    #Calculate Galactocentric velocities
    data= esutil.numpy_util.add_fields(data,[('GALVR', numpy.float),
                                             ('GALVT', numpy.float),
                                             ('GALVZ', numpy.float)])
    lb= bovy_coords.radec_to_lb(data['RA'],data['DEC'],degree=True)
    XYZ= bovy_coords.lbd_to_XYZ(lb[:,0],lb[:,1],data['RC_DIST'],degree=True)
    pmllpmbb= bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA'],data['PMDEC'],
                                                data['RA'],data['DEC'],
                                                degree=True)
    vxvyvz= bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                             pmllpmbb[:,0],
                                             pmllpmbb[:,1],
                                             lb[:,0],lb[:,1],data['RC_DIST'],
                                             degree=True)
    vR, vT, vZ= bovy_coords.vxvyvz_to_galcencyl(vxvyvz[:,0],
                                                vxvyvz[:,1],
                                                vxvyvz[:,2],
                                                8.-XYZ[:,0],
                                                XYZ[:,1],
                                                XYZ[:,2]+0.025,
                                                vsun=[-11.1,30.24*8.,7.25])#Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR']= vR
    data['GALVT']= vT
    data['GALVZ']= vZ
    data['GALVR'][True-pmindx]= -9999.99
    data['GALVT'][True-pmindx]= -9999.99
    data['GALVZ'][True-pmindx]= -9999.99
    #Get PPMXL proper motions, in a somewhat roundabout way
    pmfile= savefilename.split('.')[0]+'_pms_ppmxl.fits'
    if os.path.exists(pmfile):
        pmdata= fitsio.read(pmfile,1)
    else:
        pmdata= numpy.recarray(len(data),
                               formats=['f8','f8','f8','f8','f8','f8','i4'],
                               names=['RA','DEC','PMRA','PMDEC',
                                      'PMRA_ERR','PMDEC_ERR','PMMATCH'])
        # Write positions, again ...
        posfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        resultfilename= tempfile.mktemp('.csv',dir=os.getcwd())
        with open(posfilename,'w') as csvfile:
            wr= csv.writer(csvfile,delimiter=',',quoting=csv.QUOTE_MINIMAL)
            wr.writerow(['RA','DEC'])
            for ii in range(len(data)):
                wr.writerow([data[ii]['RA'],data[ii]['DEC']])
        # Send to CDS for matching
        result= open(resultfilename,'w')
        try:
            subprocess.check_call(['curl',
                                   '-X','POST',
                                   '-F','request=xmatch',
                                   '-F','distMaxArcsec=4',
                                   '-F','RESPONSEFORMAT=csv',
                                   '-F','cat1=@%s' % os.path.basename(posfilename),
                                   '-F','colRA1=RA',
                                   '-F','colDec1=DEC',
                                   '-F','cat2=vizier:PPMXL',
                                   'http://cdsxmatch.u-strasbg.fr/xmatch/api/v1/sync'],
                                  stdout=result)
        except subprocess.CalledProcessError:
            os.remove(posfilename)
            if os.path.exists(resultfilename):
                result.close()
                os.remove(resultfilename)
        result.close()
        # Match back and only keep the closest one
        ma= numpy.loadtxt(resultfilename,delimiter=',',skiprows=1,
                          converters={15: lambda s: float(s.strip() or -9999),
                                      16: lambda s: float(s.strip() or -9999),
                                      17: lambda s: float(s.strip() or -9999),
                                      18: lambda s: float(s.strip() or -9999)},
                          usecols=(4,5,15,16,19,20))
        h=esutil.htm.HTM()
        m1,m2,d12 = h.match(data['RA'],data['DEC'],
                            ma[:,0],ma[:,1],4./3600.,maxmatch=1)
        pmdata['PMMATCH']= 0
        pmdata['RA']= data['RA']
        pmdata['DEC']= data['DEC']
        pmdata['PMMATCH'][m1]= 1
        pmdata['PMRA'][m1]= ma[m2,2]
        pmdata['PMDEC'][m1]= ma[m2,3]
        pmdata['PMRA_ERR'][m1]= ma[m2,4]
        pmdata['PMDEC_ERR'][m1]= ma[m2,5]
        pmdata['PMMATCH'][(pmdata['PMRA'] == -9999) \
                          +(pmdata['PMDEC'] == -9999) \
                          +(pmdata['PMRA_ERR'] == -9999) \
                          +(pmdata['PMDEC_ERR'] == -9999)]= 0
        fitsio.write(pmfile,pmdata,clobber=True)
        #To make sure we're using the same format below
        pmdata= fitsio.read(pmfile,1)
        os.remove(posfilename)
        os.remove(resultfilename)
    #Match proper motions to ppmxl
    data= esutil.numpy_util.add_fields(data,[('PMRA_PPMXL', numpy.float),
                                             ('PMDEC_PPMXL', numpy.float),
                                             ('PMRA_ERR_PPMXL', numpy.float),
                                             ('PMDEC_ERR_PPMXL', numpy.float),
                                             ('PMMATCH_PPMXL',numpy.int32)])
    data['PMMATCH_PPMXL']= 0
    h=esutil.htm.HTM()
    m1,m2,d12 = h.match(pmdata['RA'],pmdata['DEC'],
                        data['RA'],data['DEC'],
                        2./3600.,maxmatch=1)
    data['PMRA_PPMXL'][m2]= pmdata['PMRA'][m1]
    data['PMDEC_PPMXL'][m2]= pmdata['PMDEC'][m1]
    data['PMRA_ERR_PPMXL'][m2]= pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR_PPMXL'][m2]= pmdata['PMDEC_ERR'][m1]
    data['PMMATCH_PPMXL'][m2]= pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx= data['PMMATCH_PPMXL'] == 1
    data['PMRA_PPMXL'][True-pmindx]= -9999.99
    data['PMDEC_PPMXL'][True-pmindx]= -9999.99
    data['PMRA_ERR_PPMXL'][True-pmindx]= -9999.99
    data['PMDEC_ERR_PPMXL'][True-pmindx]= -9999.99
    #Calculate Galactocentric velocities
    data= esutil.numpy_util.add_fields(data,[('GALVR_PPMXL', numpy.float),
                                             ('GALVT_PPMXL', numpy.float),
                                             ('GALVZ_PPMXL', numpy.float)])
    lb= bovy_coords.radec_to_lb(data['RA'],data['DEC'],degree=True)
    XYZ= bovy_coords.lbd_to_XYZ(lb[:,0],lb[:,1],data['RC_DIST'],degree=True)
    pmllpmbb= bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA_PPMXL'],
                                                data['PMDEC_PPMXL'],
                                                data['RA'],data['DEC'],
                                                degree=True)
    vxvyvz= bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                             pmllpmbb[:,0],
                                             pmllpmbb[:,1],
                                             lb[:,0],lb[:,1],data['RC_DIST'],
                                             degree=True)
    vR, vT, vZ= bovy_coords.vxvyvz_to_galcencyl(vxvyvz[:,0],
                                                vxvyvz[:,1],
                                                vxvyvz[:,2],
                                                8.-XYZ[:,0],
                                                XYZ[:,1],
                                                XYZ[:,2]+0.025,
                                                vsun=[-11.1,30.24*8.,7.25])#Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR_PPMXL']= vR
    data['GALVT_PPMXL']= vT
    data['GALVZ_PPMXL']= vZ
    data['GALVR_PPMXL'][True-pmindx]= -9999.99
    data['GALVT_PPMXL'][True-pmindx]= -9999.99
    data['GALVZ_PPMXL'][True-pmindx]= -9999.99
    #Save
    fitsio.write(savefilename,data,clobber=True)
    return None
Beispiel #19
0
def allStar(rmcommissioning=True,
            main=False,
            exclude_star_bad=False,
            exclude_star_warn=False,
            ak=True,
            akvers='targ',
            rmnovisits=False,
            adddist=False,
            distredux=None,
            rmdups=False,
            raw=False):
    """
    NAME:
       allStar
    PURPOSE:
       read the allStar file
    INPUT:
       rmcommissioning= (default: True) if True, only use data obtained after commissioning
       main= (default: False) if True, only select stars in the main survey
       exclude_star_bad= (False) if True, remove stars with the STAR_BAD flag set in ASPCAPFLAG
       exclude_star_warn= (False) if True, remove stars with the STAR_WARN flag set in ASPCAPFLAG
       ak= (default: True) only use objects for which dereddened mags exist
       akvers= 'targ' (default) or 'wise': use target AK (AK_TARG) or AK derived from all-sky WISE (AK_WISE)
       rmnovisits= (False) if True, remove stars with no good visits (to go into the combined spectrum); shouldn't be necessary
       adddist= (default: False) add distances (DR10/11 Hayden distances, DR12 combined distances)
       distredux= (default: DR default) reduction on which the distances are based
       rmdups= (False) if True, remove duplicates (very slow)
       raw= (False) if True, just return the raw file, read w/ fitsio
    OUTPUT:
       allStar data
    HISTORY:
       2013-09-06 - Written - Bovy (IAS)
    """
    filePath= path.allStarPath()
    if not os.path.exists(filePath):
        download.allStar()
    #read allStar file
    data= fitsio.read(path.allStarPath())
    if raw: return data
    #Remove duplicates, cache
    if rmdups:
        dupsFilename= path.allStarPath().replace('.fits','-nodups.fits')
        if os.path.exists(dupsFilename):
            data= fitsio.read(dupsFilename)
        else:
            sys.stdout.write('\r'+"Removing duplicates (might take a while) and caching the duplicate-free file ...\r")
            sys.stdout.flush()
            data= remove_duplicates(data)
            #Cache this file for subsequent use of rmdups
            fitsio.write(dupsFilename,data,clobber=True)
            sys.stdout.write('\r'+_ERASESTR+'\r')
            sys.stdout.flush()
    #Some cuts
    if rmcommissioning:
        indx= numpy.array(['apogee.n.c' in s for s in data['APSTAR_ID']])
        indx+= numpy.array(['apogee.s.c' in s for s in data['APSTAR_ID']])
        data= data[True-indx]
    if rmnovisits:
        indx= numpy.array([s.strip() != '' for s in data['VISITS']])
        data= data[indx]
    if main:
        indx= mainIndx(data)
        data= data[indx]
    if akvers.lower() == 'targ':
        aktag= 'AK_TARG'
    elif akvers.lower() == 'wise':
        aktag= 'AK_WISE'
    if ak:
        data= data[True-numpy.isnan(data[aktag])]
        data= data[(data[aktag] > -50.)]
    if exclude_star_bad:
        data= data[(data['ASPCAPFLAG'] & 2**23) == 0]
    if exclude_star_warn:
        data= data[(data['ASPCAPFLAG'] & 2**7) == 0]
    #Add dereddened J, H, and Ks
    aj= data[aktag]*2.5
    ah= data[aktag]*1.55
    data= esutil.numpy_util.add_fields(data,[('J0', float),
                                             ('H0', float),
                                             ('K0', float)])
    data['J0']= data['J']-aj
    data['H0']= data['H']-ah
    data['K0']= data['K']-data[aktag]
    data['J0'][(data[aktag] <= -50.)]= -9999.9999
    data['H0'][(data[aktag] <= -50.)]= -9999.9999
    data['K0'][(data[aktag] <= -50.)]= -9999.9999
    #Add distances
    if adddist:
        dist= fitsio.read(path.distPath(),1)
        h=esutil.htm.HTM()
        m1,m2,d12 = h.match(dist['RA'],dist['DEC'],
                             data['RA'],data['DEC'],
                             2./3600.,maxmatch=1)
        data= data[m2]
        dist= dist[m1]
        distredux= path._redux_dr()
        if distredux.lower() == 'v302' or distredux.lower() == path._DR10REDUX:
            data= esutil.numpy_util.add_fields(data,[('DM05', float),
                                                     ('DM16', float),
                                                     ('DM50', float),
                                                     ('DM84', float),
                                                     ('DM95', float),
                                                     ('DMPEAK', float),
                                                     ('DMAVG', float),
                                                     ('SIG_DM', float),
                                                     ('DIST_SOL', float),
                                                     ('SIG_DISTSOL', float)])
            data['DM05']= dist['DM05']
            data['DM16']= dist['DM16']
            data['DM50']= dist['DM50']
            data['DM84']= dist['DM84']
            data['DM95']= dist['DM95']
            data['DMPEAK']= dist['DMPEAK']
            data['DMAVG']= dist['DMAVG']
            data['SIG_DM']= dist['SIG_DM']
            data['DIST_SOL']= dist['DIST_SOL']/1000.
            data['SIG_DISTSOL']= dist['SIG_DISTSOL']/1000.
        elif distredux.lower() == path._DR11REDUX:
            data= esutil.numpy_util.add_fields(data,[('DISO', float),
                                                     ('DMASS', float),
                                                     ('DISO_GAL', float),
                                                     ('DMASS_GAL', float)])
            data['DISO']= dist['DISO'][:,1]
            data['DMASS']= dist['DMASS'][:,1]
            data['DISO_GAL']= dist['DISO_GAL'][:,1]
            data['DMASS_GAL']= dist['DMASS_GAL'][:,1]
        elif distredux.lower() == path._DR12REDUX:
            data= esutil.numpy_util.add_fields(data,[('HIP_PLX', float),
                                                     ('HIP_E_PLX', float),
                                                     ('RC_DIST', float),
                                                     ('APOKASC_DIST_DIRECT', float),
                                                     ('BPG_DIST1_MEAN', float),
                                                     ('HAYDEN_DIST_PEAK', float),
                                                     ('SCHULTHEIS_DIST', float)])
            data['HIP_PLX']= dist['HIP_PLX']
            data['HIP_E_PLX']= dist['HIP_E_PLX']
            data['RC_DIST']= dist['RC_dist_pc']
            data['APOKASC_DIST_DIRECT']= dist['APOKASC_dist_direct_pc']/1000.
            data['BPG_DIST1_MEAN']= dist['BPG_dist1_mean']
            data['HAYDEN_DIST_PEAK']= 10.**(dist['HAYDEN_distmod_PEAK']/5.-2.)
            data['SCHULTHEIS_DIST']= dist['SCHULTHEIS_dist']
    if path._APOGEE_REDUX.lower() == 'current' \
            or int(path._APOGEE_REDUX[1:]) > 600:
        data= esutil.numpy_util.add_fields(data,[('METALS', float),
                                                 ('ALPHAFE', float)])
        data['METALS']= data['PARAM'][:,paramIndx('metals')]
        data['ALPHAFE']= data['PARAM'][:,paramIndx('alpha')]
    return data
Beispiel #20
0
def allStar(rmcommissioning=True,
            main=False,
            exclude_star_bad=False,
            exclude_star_warn=False,
            ak=True,
            akvers='targ',
            rmnovisits=False,
            use_astroNN=False,
            use_astroNN_abundances=False,
            use_astroNN_distances=False,          
            use_astroNN_ages=False,          
            adddist=False,
            distredux=None,
            rmdups=False,
            raw=False,
            mjd=58104,
            xmatch=None,**kwargs):
    """
    NAME:
       allStar
    PURPOSE:
       read the allStar file
    INPUT:
       rmcommissioning= (default: True) if True, only use data obtained after commissioning
       main= (default: False) if True, only select stars in the main survey
       exclude_star_bad= (False) if True, remove stars with the STAR_BAD flag set in ASPCAPFLAG
       exclude_star_warn= (False) if True, remove stars with the STAR_WARN flag set in ASPCAPFLAG
       ak= (default: True) only use objects for which dereddened mags exist
       akvers= 'targ' (default) or 'wise': use target AK (AK_TARG) or AK derived from all-sky WISE (AK_WISE)
       rmnovisits= (False) if True, remove stars with no good visits (to go into the combined spectrum); shouldn't be necessary
       use_astroNN= (False) if True, swap in astroNN (Leung & Bovy 2019a) parameters (get placed in, e.g., TEFF and TEFF_ERR), astroNN distances (Leung & Bovy 2019b), and astroNN ages (Mackereth, Bovy, Leung, et al. (2019)
       use_astroNN_abundances= (False) only swap in astroNN parameters and abundances, not distances and ages
       use_astroNN_distances= (False) only swap in astroNN distances, not  parameters and abundances and ages
       use_astroNN_ages= (False) only swap in astroNN ages, not  parameters and abundances and distances
       adddist= (default: False) add distances (DR10/11 Hayden distances, DR12 combined distances)
       distredux= (default: DR default) reduction on which the distances are based
       rmdups= (False) if True, remove duplicates (very slow)
       raw= (False) if True, just return the raw file, read w/ fitsio
       mjd= (58104) MJD of version for monthly internal pipeline runs
       xmatch= (None) uses gaia_tools.xmatch.cds to x-match to an external catalog (eg., Gaia DR2 for xmatch='vizier:I/345/gaia2') and caches the result for re-use; requires jobovy/gaia_tools
        +gaia_tools.xmatch.cds keywords 
    OUTPUT:
       allStar data[,xmatched table]
    HISTORY:
       2013-09-06 - Written - Bovy (IAS)
       2018-01-22 - Edited for new monthly pipeline runs - Bovy (UofT)
       2018-05-09 - Add xmatch - Bovy (UofT) 
       2018-10-20 - Add use_astroNN option - Bovy (UofT) 
       2018-02-15 - Add astroNN distances and corresponding options - Bovy (UofT) 
       2018-02-16 - Add astroNN ages and corresponding options - Bovy (UofT) 
    """
    filePath= path.allStarPath(mjd=mjd)
    if not os.path.exists(filePath):
        download.allStar(mjd=mjd)
    #read allStar file
    data= fitsread(path.allStarPath(mjd=mjd))
    #Add astroNN? astroNN file matched line-by-line to allStar, so match here
    # [ages file not matched line-by-line]
    if use_astroNN or kwargs.get('astroNN',False) or use_astroNN_abundances:
        _warn_astroNN_abundances()
        astroNNdata= astroNN()
        data= _swap_in_astroNN(data,astroNNdata)
    if use_astroNN or kwargs.get('astroNN',False) or use_astroNN_distances:
        _warn_astroNN_distances()
        astroNNdata= astroNNDistances()
        data= _add_astroNN_distances(data,astroNNdata)
    if use_astroNN or kwargs.get('astroNN',False) or use_astroNN_ages:
        _warn_astroNN_ages()
        astroNNdata= astroNNAges()
        data= _add_astroNN_ages(data,astroNNdata)
    if raw: return data
    #Remove duplicates, cache
    if rmdups:
        dupsFilename= path.allStarPath(mjd=mjd).replace('.fits','-nodups.fits')
        if os.path.exists(dupsFilename):
            data= fitsread(dupsFilename)
        else:
            sys.stdout.write('\r'+"Removing duplicates (might take a while) and caching the duplicate-free file ...\r")
            sys.stdout.flush()
            data= remove_duplicates(data)
            #Cache this file for subsequent use of rmdups
            fitswrite(dupsFilename,data,clobber=True)
            sys.stdout.write('\r'+_ERASESTR+'\r')
            sys.stdout.flush()
    if not xmatch is None:
        from gaia_tools.load import _xmatch_cds
        if rmdups:
            matchFilePath= dupsFilename
        else:
            matchFilePath= filePath
        if use_astroNN_ages:
            matchFilePath= matchFilePath.replace('rc-','rc-astroNN-ages-')
        ma,mai= _xmatch_cds(data,xmatch,filePath,**kwargs)
        data= data[mai]
    #Some cuts
    if rmcommissioning:
        try:
            indx= numpy.array(['apogee.n.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
            indx+= numpy.array(['apogee.s.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
        except TypeError:
            indx= numpy.array(['apogee.n.c' in s for s in data['APSTAR_ID']])
            indx+= numpy.array(['apogee.s.c' in s for s in data['APSTAR_ID']])
        data= data[True^indx]
        if not xmatch is None: ma= ma[True^indx]
    if rmnovisits:
        indx= numpy.array([s.strip() != '' for s in data['VISITS']])
        data= data[indx]
        if not xmatch is None: ma= ma[indx]
    if main:
        indx= mainIndx(data)
        data= data[indx]
        if not xmatch is None: ma= ma[indx]
    if akvers.lower() == 'targ':
        aktag= 'AK_TARG'
    elif akvers.lower() == 'wise':
        aktag= 'AK_WISE'
    if ak:
        if not xmatch is None: ma= ma[True^numpy.isnan(data[aktag])]
        data= data[True^numpy.isnan(data[aktag])]
        if not xmatch is None: ma= ma[(data[aktag] > -50.)]
        data= data[(data[aktag] > -50.)]
    if exclude_star_bad:
        if not xmatch is None: ma= ma[(data['ASPCAPFLAG'] & 2**23) == 0]
        data= data[(data['ASPCAPFLAG'] & 2**23) == 0]
    if exclude_star_warn:
        if not xmatch is None: ma= ma[(data['ASPCAPFLAG'] & 2**7) == 0]
        data= data[(data['ASPCAPFLAG'] & 2**7) == 0]
    #Add dereddened J, H, and Ks
    aj= data[aktag]*2.5
    ah= data[aktag]*1.55
    if _ESUTIL_LOADED:
        data= esutil.numpy_util.add_fields(data,[('J0', float),
                                                 ('H0', float),
                                                 ('K0', float)])
        data['J0']= data['J']-aj
        data['H0']= data['H']-ah
        data['K0']= data['K']-data[aktag]
        data['J0'][(data[aktag] <= -50.)]= -9999.9999
        data['H0'][(data[aktag] <= -50.)]= -9999.9999
        data['K0'][(data[aktag] <= -50.)]= -9999.9999
    else:
        warnings.warn("Extinction-corrected J,H,K not added because esutil is not installed",RuntimeWarning)
    #Add distances
    if adddist and _ESUTIL_LOADED:
        dist= fitsread(path.distPath(),1)
        h=esutil.htm.HTM()
        m1,m2,d12 = h.match(dist['RA'],dist['DEC'],
                             data['RA'],data['DEC'],
                             2./3600.,maxmatch=1)
        data= data[m2]
        if not xmatch is None: ma= ma[m2]
        dist= dist[m1]
        distredux= path._redux_dr()
        if distredux.lower() == 'v302' or distredux.lower() == path._DR10REDUX:
            data= esutil.numpy_util.add_fields(data,[('DM05', float),
                                                     ('DM16', float),
                                                     ('DM50', float),
                                                     ('DM84', float),
                                                     ('DM95', float),
                                                     ('DMPEAK', float),
                                                     ('DMAVG', float),
                                                     ('SIG_DM', float),
                                                     ('DIST_SOL', float),
                                                     ('SIG_DISTSOL', float)])
            data['DM05']= dist['DM05']
            data['DM16']= dist['DM16']
            data['DM50']= dist['DM50']
            data['DM84']= dist['DM84']
            data['DM95']= dist['DM95']
            data['DMPEAK']= dist['DMPEAK']
            data['DMAVG']= dist['DMAVG']
            data['SIG_DM']= dist['SIG_DM']
            data['DIST_SOL']= dist['DIST_SOL']/1000.
            data['SIG_DISTSOL']= dist['SIG_DISTSOL']/1000.
        elif distredux.lower() == path._DR11REDUX:
            data= esutil.numpy_util.add_fields(data,[('DISO', float),
                                                     ('DMASS', float),
                                                     ('DISO_GAL', float),
                                                     ('DMASS_GAL', float)])
            data['DISO']= dist['DISO'][:,1]
            data['DMASS']= dist['DMASS'][:,1]
            data['DISO_GAL']= dist['DISO_GAL'][:,1]
            data['DMASS_GAL']= dist['DMASS_GAL'][:,1]
        elif distredux.lower() == path._DR12REDUX:
            data= esutil.numpy_util.add_fields(data,[('HIP_PLX', float),
                                                     ('HIP_E_PLX', float),
                                                     ('RC_DIST', float),
                                                     ('APOKASC_DIST_DIRECT', float),
                                                     ('BPG_DIST1_MEAN', float),
                                                     ('HAYDEN_DIST_PEAK', float),
                                                     ('SCHULTHEIS_DIST', float)])
            data['HIP_PLX']= dist['HIP_PLX']
            data['HIP_E_PLX']= dist['HIP_E_PLX']
            data['RC_DIST']= dist['RC_dist_pc']
            data['APOKASC_DIST_DIRECT']= dist['APOKASC_dist_direct_pc']/1000.
            data['BPG_DIST1_MEAN']= dist['BPG_dist1_mean']
            data['HAYDEN_DIST_PEAK']= 10.**(dist['HAYDEN_distmod_PEAK']/5.-2.)
            data['SCHULTHEIS_DIST']= dist['SCHULTHEIS_dist']
    elif adddist:
        warnings.warn("Distances not added because matching requires the uninstalled esutil module",RuntimeWarning)
    if _ESUTIL_LOADED and (path._APOGEE_REDUX.lower() == 'current' \
                               or 'l3' in path._APOGEE_REDUX.lower() \
                               or int(path._APOGEE_REDUX[1:]) > 600):
        data= esutil.numpy_util.add_fields(data,[('METALS', float),
                                                 ('ALPHAFE', float)])
        data['METALS']= data['PARAM'][:,paramIndx('metals')]
        data['ALPHAFE']= data['PARAM'][:,paramIndx('alpha')]
    if not xmatch is None:
        return (data,ma)
    else:
        return data
Beispiel #21
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
Beispiel #22
0
def plot_afe_spectra(savename,plotname):
    # Load the data
    data= define_rcsample.get_rcsample()
    data= data[data['SNR'] > 200.]
    fehindx= (data['FE_H'] <= -0.35)*(data['FE_H'] > -0.45)
    fehdata= data[fehindx]
    # First compute the residuals and do the EM-PCA smoothing
    if not os.path.exists(savename):
        nspec= len(fehdata)
        spec= numpy.zeros((nspec,7214))
        specerr= numpy.zeros((nspec,7214))
        for ii in range(nspec):
            sys.stdout.write('\r'+"Loading spectrum %i / %i ...\r" % (ii+1,nspec))
            sys.stdout.flush()
            spec[ii]= apread.aspcapStar(fehdata['LOCATION_ID'][ii],
                                        fehdata['APOGEE_ID'][ii],
                                        ext=1,header=False,aspcapWavegrid=True)
            specerr[ii]= apread.aspcapStar(fehdata['LOCATION_ID'][ii],
                                           fehdata['APOGEE_ID'][ii],
                                           ext=2,header=False,
                                           aspcapWavegrid=True)
        teffs= fehdata['FPARAM'][:,paramIndx('teff')]
        loggs= fehdata['FPARAM'][:,paramIndx('logg')]
        metals= fehdata[define_rcsample._FEHTAG]
        cf, s, r= apcannon.quadfit(spec,specerr,
                                   teffs-4800.,loggs-2.85,metals+0.3,
                                   return_residuals=True)
        pr= numpy.zeros_like(r)
        # Deal w/ bad data
        _MAXERR= 0.02
        npca= 8
        pca_input= r
        pca_weights= (1./specerr**2.)
        pca_weights[pca_weights < 1./_MAXERR**2.]= 0. 
        nanIndx= numpy.isnan(pca_input) + numpy.isnan(pca_weights)
        pca_weights[nanIndx]= 0. 
        pca_input[nanIndx]= 0.
        # Run EM-PCA
        m= empca.empca(pca_input,pca_weights,nvec=npca,niter=25)#,silent=False)
        for jj in range(nspec):
            for kk in range(npca):
                pr[jj]+= m.coeff[jj,kk]*m.eigvec[kk]
        save_pickles(savename,pr,r,cf)
    else:
        with open(savename,'rb') as savefile:
            pr= pickle.load(savefile)
    # Now plot the various elements
    colormap= cm.seismic
    colorFunc= lambda afe: afe/0.25
    widths= [3.5,2.]
    yranges= [[-0.05,0.02],[-0.03,0.01]]
    for ee, elem in enumerate(['S','Ca1']):
        for ii in range(5):
            tindx= (fehdata[define_rcsample._AFETAG] > ii*0.05-0.025)\
                *(fehdata[define_rcsample._AFETAG] <= (ii+1)*0.05-0.025)
            args= (apstack.median(pr[tindx][:12]),elem,)
            kwargs= {'markLines':ii==4,
                     'yrange':yranges[ee],
                     'ylabel':'',
                     'cleanZero':False,
                     'zorder':int(numpy.floor(numpy.random.uniform()*5)),
                     'color':colormap(colorFunc(ii*0.05)),
                     'overplot':ii>0,
                     'fig_width':widths[ee]}
            if ii>0: kwargs.pop('fig_width')
            splot.windows(*args,**kwargs)
        bovy_plot.bovy_end_print(plotname.replace('ELEM',
                                                  elem.lower().capitalize()))
    # Also do Mg
    for ii in range(5):
        tindx= (fehdata[define_rcsample._AFETAG] > ii*0.05-0.025)\
            *(fehdata[define_rcsample._AFETAG] <= (ii+1)*0.05-0.025)
        args= (apstack.median(pr[tindx][:12]),)
        kwargs={'startindxs':[3012,3120,3990],
                'endindxs':[3083,3158,4012],
                'yrange':[-0.05,0.02],
                'ylabel':'',
                'cleanZero':False,
                '_markwav':[15745.017,15753.189,15770.055,15958.836],
                'zorder':int(numpy.floor(numpy.random.uniform()*5)),
                'color':colormap(colorFunc(ii*0.05)),
                'overplot':ii>0,
                'fig_width':4.5,
                'markLines':True}
        if ii>0: kwargs.pop('fig_width')
        if ii != 4: 
            kwargs.pop('_markwav')
            kwargs.pop('markLines')
        kwargs['_startendskip']= 0
        kwargs['_noxticks']= True
        kwargs['_labelwav']= True
        splot.waveregions(*args,**kwargs)                          
        bovy_plot.bovy_text(r'$\mathrm{Mg}$',
                            top_left=True,fontsize=10,backgroundcolor='w')
    bovy_plot.bovy_end_print(plotname.replace('ELEM','Mg'))
    # Also do Si
    for ii in range(5):
        tindx= (fehdata[define_rcsample._AFETAG] > ii*0.05-0.025)\
            *(fehdata[define_rcsample._AFETAG] <= (ii+1)*0.05-0.025)
        args= (apstack.median(pr[tindx][:12]),)
        kwargs={'startindxs':[4469, 4624,5171, 7205, 7843],
                'endindxs':[4488, 4644,5182, 7243, 7871],
                'yrange':[-0.05,0.02],
                'ylabel':'',
                'cleanZero':False,
                '_markwav':apwindow.lines('Si'),
                'zorder':int(numpy.floor(numpy.random.uniform()*5)),
                'color':colormap(colorFunc(ii*0.05)),
                'overplot':ii>0,
                'fig_width':6.,
                'markLines':True}
        if ii>0: kwargs.pop('fig_width')
        if ii != 4: 
            kwargs.pop('_markwav')
            kwargs.pop('markLines')
        kwargs['_startendskip']= 0
        kwargs['_noxticks']= True
        kwargs['_labelwav']= True
        splot.waveregions(*args,**kwargs)                          
        bovy_plot.bovy_text(r'$\mathrm{Si}$',
                            top_left=True,fontsize=10,backgroundcolor='w')
    bovy_plot.bovy_end_print(plotname.replace('ELEM','Si2'))
    # Also do Oxygen
    for ii in range(5):
        tindx= (fehdata[define_rcsample._AFETAG] > ii*0.05-0.025)\
            *(fehdata[define_rcsample._AFETAG] <= (ii+1)*0.05-0.025)
        args= (apstack.median(pr[tindx][:12]),)
        kwargs={'startlams':[15558,16242,16536,16720],
                'endlams':[15566,16250,16544,16728],
                'yrange':[-0.05,0.02],
                'ylabel':'',
                'cleanZero':False,
                '_markwav':[15562,16246,16539,16723.5],
                'zorder':int(numpy.floor(numpy.random.uniform()*5)),
                'color':colormap(colorFunc(ii*0.05)),
                'overplot':ii>0,
                'fig_width':5.,
                'markLines':True}
        if ii>0: kwargs.pop('fig_width')
        if ii != 4: 
            kwargs.pop('_markwav')
            kwargs.pop('markLines')
        kwargs['_startendskip']= 0
        kwargs['_noxticks']= True
        kwargs['_labelwav']= True
        splot.waveregions(*args,**kwargs)                          
        bovy_plot.bovy_text(r'$\mathrm{O}$',
                            top_left=True,fontsize=10,backgroundcolor='w')
    bovy_plot.bovy_end_print(plotname.replace('ELEM','O'))
    # Also do Ti
    for ii in range(5):
        tindx= (fehdata[define_rcsample._AFETAG] > ii*0.05-0.025)\
            *(fehdata[define_rcsample._AFETAG] <= (ii+1)*0.05-0.025)
        args= (apstack.median(pr[tindx][:12]),)
        kwargs={'startindxs':[1116,2100,2899],
                'endindxs':[1146,2124,2922],
                'yrange':[-0.05,0.02],
                'ylabel':'',
                'cleanZero':False,
                '_markwav':apwindow.lines('Ti'),
                'zorder':int(numpy.floor(numpy.random.uniform()*5)),
                'color':colormap(colorFunc(ii*0.05)),
                'overplot':ii>0,
                'fig_width':3.5,
                'markLines':True}
        if ii>0: kwargs.pop('fig_width')
        if ii != 4: 
            kwargs.pop('_markwav')
            kwargs.pop('markLines')
        kwargs['_startendskip']= 0
        kwargs['_noxticks']= True
        kwargs['_labelwav']= True
        splot.waveregions(*args,**kwargs)                          
        bovy_plot.bovy_text(r'$\mathrm{Ti}$',
                            top_left=True,fontsize=10,backgroundcolor='w')
    bovy_plot.bovy_end_print(plotname.replace('ELEM','Ti'))
    return None
Beispiel #23
0
def allStar(rmcommissioning=True,
            main=False,
            exclude_star_bad=False,
            exclude_star_warn=False,
            ak=True,
            akvers='targ',
            rmnovisits=False,
            use_astroNN=False,
            use_astroNN_abundances=False,
            use_astroNN_distances=False,
            use_astroNN_ages=False,
            adddist=False,
            distredux=None,
            rmdups=False,
            raw=False,
            mjd=58104,
            xmatch=None,
            **kwargs):
    """
    NAME:
       allStar
    PURPOSE:
       read the allStar file
    INPUT:
       rmcommissioning= (default: True) if True, only use data obtained after commissioning
       main= (default: False) if True, only select stars in the main survey
       exclude_star_bad= (False) if True, remove stars with the STAR_BAD flag set in ASPCAPFLAG
       exclude_star_warn= (False) if True, remove stars with the STAR_WARN flag set in ASPCAPFLAG
       ak= (default: True) only use objects for which dereddened mags exist
       akvers= 'targ' (default) or 'wise': use target AK (AK_TARG) or AK derived from all-sky WISE (AK_WISE)
       rmnovisits= (False) if True, remove stars with no good visits (to go into the combined spectrum); shouldn't be necessary
       use_astroNN= (False) if True, swap in astroNN (Leung & Bovy 2019a) parameters (get placed in, e.g., TEFF and TEFF_ERR), astroNN distances (Leung & Bovy 2019b), and astroNN ages (Mackereth, Bovy, Leung, et al. (2019)
       use_astroNN_abundances= (False) only swap in astroNN parameters and abundances, not distances and ages
       use_astroNN_distances= (False) only swap in astroNN distances, not  parameters and abundances and ages
       use_astroNN_ages= (False) only swap in astroNN ages, not  parameters and abundances and distances
       adddist= (default: False) add distances (DR10/11 Hayden distances, DR12 combined distances)
       distredux= (default: DR default) reduction on which the distances are based
       rmdups= (False) if True, remove duplicates (very slow)
       raw= (False) if True, just return the raw file, read w/ fitsio
       mjd= (58104) MJD of version for monthly internal pipeline runs
       xmatch= (None) uses gaia_tools.xmatch.cds to x-match to an external catalog (eg., Gaia DR2 for xmatch='vizier:I/345/gaia2') and caches the result for re-use; requires jobovy/gaia_tools
        +gaia_tools.xmatch.cds keywords 
    OUTPUT:
       allStar data[,xmatched table]
    HISTORY:
       2013-09-06 - Written - Bovy (IAS)
       2018-01-22 - Edited for new monthly pipeline runs - Bovy (UofT)
       2018-05-09 - Add xmatch - Bovy (UofT) 
       2018-10-20 - Add use_astroNN option - Bovy (UofT) 
       2018-02-15 - Add astroNN distances and corresponding options - Bovy (UofT) 
       2018-02-16 - Add astroNN ages and corresponding options - Bovy (UofT) 
    """
    filePath = path.allStarPath(mjd=mjd)
    if not os.path.exists(filePath):
        download.allStar(mjd=mjd)
    #read allStar file
    data = fitsread(path.allStarPath(mjd=mjd))
    #Add astroNN? astroNN file matched line-by-line to allStar, so match here
    # [ages file not matched line-by-line]
    if use_astroNN or kwargs.get('astroNN', False) or use_astroNN_abundances:
        _warn_astroNN_abundances()
        astroNNdata = astroNN()
        data = _swap_in_astroNN(data, astroNNdata)
    if use_astroNN or kwargs.get('astroNN', False) or use_astroNN_distances:
        _warn_astroNN_distances()
        astroNNdata = astroNNDistances()
        data = _add_astroNN_distances(data, astroNNdata)
    if use_astroNN or kwargs.get('astroNN', False) or use_astroNN_ages:
        _warn_astroNN_ages()
        astroNNdata = astroNNAges()
        data = _add_astroNN_ages(data, astroNNdata)
    if raw: return data
    #Remove duplicates, cache
    if rmdups:
        dupsFilename = path.allStarPath(mjd=mjd).replace(
            '.fits', '-nodups.fits')
        if os.path.exists(dupsFilename):
            data = fitsread(dupsFilename)
        else:
            sys.stdout.write(
                '\r' +
                "Removing duplicates (might take a while) and caching the duplicate-free file ...\r"
            )
            sys.stdout.flush()
            data = remove_duplicates(data)
            #Cache this file for subsequent use of rmdups
            fitswrite(dupsFilename, data, clobber=True)
            sys.stdout.write('\r' + _ERASESTR + '\r')
            sys.stdout.flush()
    if not xmatch is None:
        from gaia_tools.load import _xmatch_cds
        if rmdups:
            matchFilePath = dupsFilename
        else:
            matchFilePath = filePath
        if use_astroNN_ages:
            matchFilePath = matchFilePath.replace('rc-', 'rc-astroNN-ages-')
        ma, mai = _xmatch_cds(data, xmatch, filePath, **kwargs)
        data = data[mai]
    #Some cuts
    if rmcommissioning:
        try:
            indx = numpy.array(
                ['apogee.n.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
            indx += numpy.array(
                ['apogee.s.c'.encode('utf-8') in s for s in data['APSTAR_ID']])
        except TypeError:
            indx = numpy.array(['apogee.n.c' in s for s in data['APSTAR_ID']])
            indx += numpy.array(['apogee.s.c' in s for s in data['APSTAR_ID']])
        data = data[True ^ indx]
        if not xmatch is None: ma = ma[True ^ indx]
    if rmnovisits:
        indx = numpy.array([s.strip() != '' for s in data['VISITS']])
        data = data[indx]
        if not xmatch is None: ma = ma[indx]
    if main:
        indx = mainIndx(data)
        data = data[indx]
        if not xmatch is None: ma = ma[indx]
    if akvers.lower() == 'targ':
        aktag = 'AK_TARG'
    elif akvers.lower() == 'wise':
        aktag = 'AK_WISE'
    if ak:
        if not xmatch is None: ma = ma[True ^ numpy.isnan(data[aktag])]
        data = data[True ^ numpy.isnan(data[aktag])]
        if not xmatch is None: ma = ma[(data[aktag] > -50.)]
        data = data[(data[aktag] > -50.)]
    if exclude_star_bad:
        if not xmatch is None: ma = ma[(data['ASPCAPFLAG'] & 2**23) == 0]
        data = data[(data['ASPCAPFLAG'] & 2**23) == 0]
    if exclude_star_warn:
        if not xmatch is None: ma = ma[(data['ASPCAPFLAG'] & 2**7) == 0]
        data = data[(data['ASPCAPFLAG'] & 2**7) == 0]
    #Add dereddened J, H, and Ks
    aj = data[aktag] * 2.5
    ah = data[aktag] * 1.55
    if _ESUTIL_LOADED:
        data = esutil.numpy_util.add_fields(data,
                                            [('J0', float), ('H0', float),
                                             ('K0', float)])
        data['J0'] = data['J'] - aj
        data['H0'] = data['H'] - ah
        data['K0'] = data['K'] - data[aktag]
        data['J0'][(data[aktag] <= -50.)] = -9999.9999
        data['H0'][(data[aktag] <= -50.)] = -9999.9999
        data['K0'][(data[aktag] <= -50.)] = -9999.9999
    else:
        warnings.warn(
            "Extinction-corrected J,H,K not added because esutil is not installed",
            RuntimeWarning)
    #Add distances
    if adddist and _ESUTIL_LOADED:
        dist = fitsread(path.distPath(), 1)
        h = esutil.htm.HTM()
        m1, m2, d12 = h.match(dist['RA'],
                              dist['DEC'],
                              data['RA'],
                              data['DEC'],
                              2. / 3600.,
                              maxmatch=1)
        data = data[m2]
        if not xmatch is None: ma = ma[m2]
        dist = dist[m1]
        distredux = path._redux_dr()
        if distredux.lower() == 'v302' or distredux.lower() == path._DR10REDUX:
            data = esutil.numpy_util.add_fields(data, [('DM05', float),
                                                       ('DM16', float),
                                                       ('DM50', float),
                                                       ('DM84', float),
                                                       ('DM95', float),
                                                       ('DMPEAK', float),
                                                       ('DMAVG', float),
                                                       ('SIG_DM', float),
                                                       ('DIST_SOL', float),
                                                       ('SIG_DISTSOL', float)])
            data['DM05'] = dist['DM05']
            data['DM16'] = dist['DM16']
            data['DM50'] = dist['DM50']
            data['DM84'] = dist['DM84']
            data['DM95'] = dist['DM95']
            data['DMPEAK'] = dist['DMPEAK']
            data['DMAVG'] = dist['DMAVG']
            data['SIG_DM'] = dist['SIG_DM']
            data['DIST_SOL'] = dist['DIST_SOL'] / 1000.
            data['SIG_DISTSOL'] = dist['SIG_DISTSOL'] / 1000.
        elif distredux.lower() == path._DR11REDUX:
            data = esutil.numpy_util.add_fields(data, [('DISO', float),
                                                       ('DMASS', float),
                                                       ('DISO_GAL', float),
                                                       ('DMASS_GAL', float)])
            data['DISO'] = dist['DISO'][:, 1]
            data['DMASS'] = dist['DMASS'][:, 1]
            data['DISO_GAL'] = dist['DISO_GAL'][:, 1]
            data['DMASS_GAL'] = dist['DMASS_GAL'][:, 1]
        elif distredux.lower() == path._DR12REDUX:
            data = esutil.numpy_util.add_fields(
                data, [('HIP_PLX', float), ('HIP_E_PLX', float),
                       ('RC_DIST', float), ('APOKASC_DIST_DIRECT', float),
                       ('BPG_DIST1_MEAN', float), ('HAYDEN_DIST_PEAK', float),
                       ('SCHULTHEIS_DIST', float)])
            data['HIP_PLX'] = dist['HIP_PLX']
            data['HIP_E_PLX'] = dist['HIP_E_PLX']
            data['RC_DIST'] = dist['RC_dist_pc']
            data[
                'APOKASC_DIST_DIRECT'] = dist['APOKASC_dist_direct_pc'] / 1000.
            data['BPG_DIST1_MEAN'] = dist['BPG_dist1_mean']
            data['HAYDEN_DIST_PEAK'] = 10.**(dist['HAYDEN_distmod_PEAK'] / 5. -
                                             2.)
            data['SCHULTHEIS_DIST'] = dist['SCHULTHEIS_dist']
    elif adddist:
        warnings.warn(
            "Distances not added because matching requires the uninstalled esutil module",
            RuntimeWarning)
    if _ESUTIL_LOADED and (path._APOGEE_REDUX.lower() == 'current' \
                               or 'l3' in path._APOGEE_REDUX.lower() \
                               or int(path._APOGEE_REDUX[1:]) > 600):
        data = esutil.numpy_util.add_fields(data, [('METALS', float),
                                                   ('ALPHAFE', float)])
        data['METALS'] = data['PARAM'][:, paramIndx('metals')]
        data['ALPHAFE'] = data['PARAM'][:, paramIndx('alpha')]
    if not xmatch is None:
        return (data, ma)
    else:
        return data
Beispiel #24
0
def mcmc(spec,specerr,
         fparam=None,
         teff=4750.,logg=2.5,metals=0.,am=0.,nm=0.,cm=0.,vm=None,
         nsamples=1000,nwalkers=40,
         initsig=[20.,0.05,0.025,0.025,0.025,0.025,0.025],
         fixteff=False,fixlogg=False,fixmetals=False,fixam=False,fixcm=False,
         fixnm=False,fixvm=False,
         lib='GK',pca=True,sixd=True,dr=None,
         inter=3,f_format=1,f_access=None,
         verbose=False):
    """
    NAME:
       mcmc
    PURPOSE:
       Perform MCMC of the 6/7 parameter global fit of model spectra to a given data spectrum
    INPUT:
       Either:
          (1) location ID - single or list/array of location IDs
              APOGEE ID - single or list/array of APOGEE IDs; loads aspcapStar
          (2) spec - spectrum: can be (nwave) or (nspec,nwave)
              specerr - spectrum errors: can be (nwave) or (nspec,nwave)
       Input parameters (can be 1D arrays)
          Either:
             (1) fparam= (None) output of ferre.fit
             (2) teff= (4750.) Effective temperature (K)
                 logg= (2.5) log10 surface gravity / cm s^-2
                 metals= (0.) overall metallicity
                 am= (0.) [alpha/M]
                 nm= (0.) [N/M]
                 cm= (0.) [C/M]
                 vm= if using the 7D library, also specify the microturbulence
       MCMC options:
          nsamples= (1000) number of samples to get
          nwalkers= (40) number of ensemble walkers to use in the MCMC
          initsig= std. dev. of the initial ball of walkers around 
                   [Teff,logg,log10vmicro,metals,cm,nm,am]
                   specify log10vmicro even when using a 6D library
          fixteff= (True) if True, fix teff at the input value
          fixlogg= (True) if True, fix logg at the input value
          fixvm= (True) if True, fix vm at the input value (only if sixd is False)
          fixmetals= (None) if True, fix metals at the input value
          fixam= (None) if True, fix am at the input value
          fixcm= (None) if True, fix cm at the input value
          fixnm= (None) if True, fix nm at the input value
       Library options:
          lib= ('GK') spectral library
          pca= (True) if True, use a PCA compressed library
          sixd= (True) if True, use the 6D library (w/o vm)
          dr= data release
       FERRE options:
          inter= (3) order of the interpolation
          f_format= (1) file format (0=ascii, 1=unf)
          f_access= (None) 0: load whole library, 1: use direct access (for small numbers of interpolations), None: automatically determine a good value (currently, 1)
       verbose= (False) if True, run FERRE in verbose mode
    OUTPUT:
       TBD
    HISTORY:
       2015-04-08 - Written - Bovy (IAS)
    """
    # Parse fparam
    if not fparam is None:
        teff= fparam[:,paramIndx('TEFF')]
        logg= fparam[:,paramIndx('LOGG')]
        metals= fparam[:,paramIndx('METALS')]
        am= fparam[:,paramIndx('ALPHA')]
        nm= fparam[:,paramIndx('N')]
        cm= fparam[:,paramIndx('C')]
        if sixd:
            vm= None
        else:
            vm= fparam[:,paramIndx('LOG10VDOP')]        
    # Make sure the Teff etc. have the right dimensionality
    if len(spec.shape) == 1:
        nspec= 1
    else:
        raise ValueError("apogee.modelspec.ferre.mcmc only works for a single spectrum")
        nspec= spec.shape[0]
    if nspec > 1 and isinstance(teff,float):
        teff= teff*numpy.ones(nspec)
    if nspec > 1 and isinstance(logg,float):
        logg= logg*numpy.ones(nspec)
    if nspec > 1 and isinstance(metals,float):
        metals= metals*numpy.ones(nspec)
    if nspec > 1 and isinstance(am,float):
        am= am*numpy.ones(nspec)
    if nspec > 1 and isinstance(nm,float):
        nm= nm*numpy.ones(nspec)
    if nspec > 1 and isinstance(cm,float):
        cm= cm*numpy.ones(nspec)
    if nspec > 1 and not vm is None and isinstance(vm,float):
        vm= vm*numpy.ones(nspec)
    if dr is None: dr= appath._default_dr()
    # Setup the walkers
    ndim= 7-sixd-fixvm+sixd*fixvm-fixteff-fixlogg-fixmetals-fixam-fixcm-fixnm
    p0= []
    for ii in range(nwalkers):
        tp0= []
        # Teff
        if not fixteff:
            tteff= teff+numpy.random.normal()*initsig[0]
            if tteff > 6000.: tteff= 6000.
            if tteff < 3500.: tteff= 3500.
            tp0.append(tteff)
        # logg
        if not fixlogg:
            tlogg= logg+numpy.random.normal()*initsig[1]
            if logg > 5.: tlogg= 5.
            if logg < 0.: tlogg= 0.
            tp0.append(tlogg)
        # log10vmicro
        if not (fixvm or sixd):
            tvm= numpy.log10(vm)+numpy.random.normal()*initsig[2]
            if tvm > numpy.log10(8.0): tvm= numpy.log10(8.0)
            if tvm < numpy.log10(0.5): tvm= numpy.log10(0.5)
            tp0.append(tvm)
        # metals
        if not fixmetals:
            tmetals= metals+numpy.random.normal()*initsig[3]
            if metals > 0.5: tmetals= 0.5
            if metals < -2.5: tmetals= -2.5
            tp0.append(tmetals)
        # cm
        if not fixcm:
            tcm= cm+numpy.random.normal()*initsig[4]
            if cm > 1.0: tcm= 1.0
            if cm < -1.0: tcm= -1.
            tp0.append(tcm)
        # nm
        if not fixnm:
            tnm= nm+numpy.random.normal()*initsig[5]
            if nm > 0.5: tnm= 1.0
            if nm < -1.0: tnm= -1.0
            tp0.append(tnm)
        # am
        if not fixam:
            tam= am+numpy.random.normal()*initsig[6]
            if am > 0.5: tam= 1.0
            if am < -1.0: tam= -1.0
            tp0.append(tam)
        p0.append(numpy.array(tp0)[:,0])
    p0= numpy.array(p0)
    # Prepare the data
    dspec= numpy.tile(spec,(nwalkers,1))
    dspecerr= numpy.tile(specerr,(nwalkers,1))
    # Run MCMC
    sampler= apogee.util.emcee.EnsembleSampler(nwalkers,ndim,_mcmc_lnprob,
                                               args=[dspec,dspecerr,
                                                     teff,logg,vm,metals,
                                                     cm,nm,am,
                                                     fixteff,fixlogg,fixvm,
                                                     fixmetals,fixcm,fixnm,
                                                     fixam,sixd,pca,
                                                     dr,lib,
                                                     inter,f_format,f_access])
    # Burn-in 10% of nsamples
    pos, prob, state = sampler.run_mcmc(p0,nsamples//10)
    sampler.reset()
    # Run main MCMC
    sampler.run_mcmc(pos,nsamples)
    return sampler.flatchain
Beispiel #25
0
def elemfitall(*args,**kwargs):
    """
    NAME:
       elemfitall
    PURPOSE:
       Fit a model spectrum to a given data spectrum for all element windows
    INPUT:
       Either:
          (1) location ID - single or list/array of location IDs
              APOGEE ID - single or list/array of APOGEE IDs; loads aspcapStar
          (2) spec - spectrum: can be (nwave) or (nspec,nwave)
              specerr - spectrum errors: can be (nwave) or (nspec,nwave)
       estimate_err= (False) if True, estimate the error from Delta chi^2=1; only works for errors <~ 0.3 dex, code returns numpy.nan when error is larger
       Input parameters (can be 1D arrays); only used when init=0
          Either:
             (1) fparam= (None) output of ferre.fit
             (2) teff= (4750.) Effective temperature (K)
                 logg= (2.5) log10 surface gravity / cm s^-2
                 metals= (0.) overall metallicity
                 am= (0.) [alpha/M]
                 nm= (0.) [N/M]
                 cm= (0.) [C/M]
                 vm= if using the 7D library, also specify the microturbulence
       Fit options:
          fixteff= (True) if True, fix teff at the input value
          fixlogg= (True) if True, fix logg at the input value
          fixvm= (True) if True, fix vm at the input value (only if sixd is False)
       The following are set to False based on the element being fit (C -> fixcm=False, N -> fixnm=False, O,Mg,S,Si,Ca,Ti -> fixam=False, rest -> fixmetals=False)
          fixmetals= (None) if True, fix metals at the input value
          fixam= (None) if True, fix am at the input value
          fixcm= (None) if True, fix cm at the input value
          fixnm= (None) if True, fix nm at the input value
       Library options:
          lib= ('GK') spectral library
          pca= (True) if True, use a PCA compressed library
          sixd= (True) if True, use the 6D library (w/o vm)
          dr= data release
       FERRE options:
          inter= (3) order of the interpolation
          errbar= (1) method for calculating the error bars
          indini= ([1,1,1,2,2,3]) how to initialize the search (int or array/list with ndim entries)
          init= (0) if 0, initialize the search at the parameters in the pfile
          f_format= (1) file format (0=ascii, 1=unf)
          f_access= (None) 0: load whole library, 1: use direct access (for small numbers of interpolations), None: automatically determine a good value (currently, 1)
       Output options:
          offile= (None) if offile is set, the FERRE OFFILE is saved to this file, otherwise this file is removed
       verbose= (False) if True, run FERRE in verbose mode
    OUTPUT:
       dictionary with best-fit ELEM_H (nspec), contains e_ELEM when estimate_err; this does not include the (potentially correlated) error on METALS for those elements fit relative to Fe
    HISTORY:
       2015-03-01 - Written - Bovy (IAS)
    """
    # METALS for normalization
    if not kwargs.get('fparam',None) is None:
        metals= kwargs.get('fparam')[:,paramIndx('METALS')]
    else:
        metals= kwargs.get('metals',0.)
    # Run through and fit all elements
    out= {}
    for elem in _ELEM_SYMBOL:
        targs= args+(elem.capitalize(),)
        tefit= elemfit(*targs,**kwargs)
        if kwargs.get('estimate_err',False):
            tefit, terr= tefit
            out['e_'+elem.capitalize()]= terr
        if elem.lower() == 'c':
            tout= tefit[:,paramIndx('C')]+metals
        elif elem.lower() == 'n':
            tout= tefit[:,paramIndx('N')]+metals
        elif elem.lower() in ['o','mg','s','si','ca','ti']:
            tout= tefit[:,paramIndx('ALPHA')]+metals
        else:
            tout= tefit[:,paramIndx('METALS')]
        out[elem.capitalize()]= tout
    return out
Beispiel #26
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
Beispiel #27
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
Beispiel #28
0
def elemfit(spec,specerr,elem,
            fparam=None,
            teff=4750.,logg=2.5,metals=0.,am=0.,nm=0.,cm=0.,vm=None,
            fixteff=True,fixlogg=True,fixmetals=None,fixam=None,
            fixcm=None,
            fixnm=None,fixvm=True,
            estimate_err=False,
            lib='GK',pca=True,sixd=True,dr=None,
            offile=None,
            inter=3,f_format=1,f_access=None,
            errbar=1,indini=[1,1,1,2,2,3],init=0,
            verbose=False):
    """
    NAME:
       elemfit
    PURPOSE:
       Fit a model spectrum to a given data spectrum for a given element window
    INPUT:
       Either:
          (1) location ID - single or list/array of location IDs
              APOGEE ID - single or list/array of APOGEE IDs; loads aspcapStar
          (2) spec - spectrum: can be (nwave) or (nspec,nwave)
              specerr - spectrum errors: can be (nwave) or (nspec,nwave)
       elem - element to fit (e.g., 'Al')
       estimate_err= (False) if True, estimate the error from Delta chi^2=1; only works for errors <~ 0.3 dex, code returns numpy.nan when error is larger
       Input parameters (can be 1D arrays); only used when init=0
          Either:
             (1) fparam= (None) output of ferre.fit
             (2) teff= (4750.) Effective temperature (K)
                 logg= (2.5) log10 surface gravity / cm s^-2
                 metals= (0.) overall metallicity
                 am= (0.) [alpha/M]
                 nm= (0.) [N/M]
                 cm= (0.) [C/M]
                 vm= if using the 7D library, also specify the microturbulence
       Fit options:
          fixteff= (True) if True, fix teff at the input value
          fixlogg= (True) if True, fix logg at the input value
          fixvm= (True) if True, fix vm at the input value (only if sixd is False)
       The following are set to False based on the element being fit (C -> fixcm=False, N -> fixnm=False, O,Mg,S,Si,Ca,Ti -> fixam=False, rest -> fixmetals=False)
          fixmetals= (None) if True, fix metals at the input value
          fixam= (None) if True, fix am at the input value
          fixcm= (None) if True, fix cm at the input value
          fixnm= (None) if True, fix nm at the input value
       Library options:
          lib= ('GK') spectral library
          pca= (True) if True, use a PCA compressed library
          sixd= (True) if True, use the 6D library (w/o vm)
          dr= data release
       FERRE options:
          inter= (3) order of the interpolation
          errbar= (1) method for calculating the error bars
          indini= ([1,1,1,2,2,3]) how to initialize the search (int or array/list with ndim entries)
          init= (0) if 0, initialize the search at the parameters in the pfile
          f_format= (1) file format (0=ascii, 1=unf)
          f_access= (None) 0: load whole library, 1: use direct access (for small numbers of interpolations), None: automatically determine a good value (currently, 1)
       Output options:
          offile= (None) if offile is set, the FERRE OFFILE is saved to this file, otherwise this file is removed
       verbose= (False) if True, run FERRE in verbose mode
    OUTPUT:
       best-fit parameters (nspec,nparams); in the same order as the FPARAM APOGEE data product (fixed inputs are repeated in the output)
       if estimate_err: tuple with best-fit (see above) and error on the element abundance
    HISTORY:
       2015-02-27 - Written - Bovy (IAS)
    """
    # Parse fparam
    if not fparam is None:
        teff= fparam[:,paramIndx('TEFF')]
        logg= fparam[:,paramIndx('LOGG')]
        metals= fparam[:,paramIndx('METALS')]
        am= fparam[:,paramIndx('ALPHA')]
        nm= fparam[:,paramIndx('N')]
        cm= fparam[:,paramIndx('C')]
        if sixd:
            vm= None
        else:
            vm= fparam[:,paramIndx('LOG10VDOP')]        
    # Make sure the Teff etc. have the right dimensionality
    if len(spec.shape) == 1:
        nspec= 1
    else:
        nspec= spec.shape[0]
    if nspec > 1 and isinstance(teff,float):
        teff= teff*numpy.ones(nspec)
    if nspec > 1 and isinstance(logg,float):
        logg= logg*numpy.ones(nspec)
    if nspec > 1 and isinstance(metals,float):
        metals= metals*numpy.ones(nspec)
    if nspec > 1 and isinstance(am,float):
        am= am*numpy.ones(nspec)
    if nspec > 1 and isinstance(nm,float):
        nm= nm*numpy.ones(nspec)
    if nspec > 1 and isinstance(cm,float):
        cm= cm*numpy.ones(nspec)
    if nspec > 1 and not vm is None and isinstance(vm,float):
        vm= vm*numpy.ones(nspec)
    if dr is None: dr= appath._default_dr()
    # Set fixXX based on element being fit, first set None to True
    if fixcm is None: fixcm= True
    if fixnm is None: fixnm= True
    if fixam is None: fixam= True
    if fixmetals is None: fixmetals= True
    if elem.lower() == 'c':
        fixcm= False
    elif elem.lower() == 'n':
        fixnm= False
    elif elem.lower() in ['o','mg','s','si','ca','ti']:
        fixam= False
    else:
        fixmetals= False
    # Fix any of the parameters?
    indv= []
    indini= copy.copy(indini) # need to copy bc passed by reference
    if isinstance(indini,numpy.ndarray) and \
            ((not sixd and fixvm) or fixcm or fixnm or fixam or fixmetals \
                 or fixlogg or fixteff):
        indini= list(indini)
    if not sixd and not fixvm:
        indv.append(1)
    elif not sixd:
        if isinstance(indini,list): indini[0]= -1
    if not fixcm:
        indv.append(2-sixd)
    else:
        if isinstance(indini,list): indini[1-sixd]= -1
    if not fixnm:
        indv.append(3-sixd)
    else:
        if isinstance(indini,list): indini[2-sixd]= -1
    if not fixam:
        indv.append(4-sixd)
    else:
        if isinstance(indini,list): indini[3-sixd]= -1
    if not fixmetals:
        indv.append(5-sixd)
    else:
        if isinstance(indini,list): indini[4-sixd]= -1
    if not fixlogg:
        indv.append(6-sixd)
    else:
        if isinstance(indini,list): indini[5-sixd]= -1
    if not fixteff:
        indv.append(7-sixd)
    else:
        if isinstance(indini,list): indini[6-sixd]= -1
    if isinstance(indini,list):
        while -1 in indini: indini.remove(-1)
    if init == 0: indini= 0
    # Setup temporary directory to run FERRE from
    tmpDir= tempfile.mkdtemp(dir='./')
    try:
        # First write the ipf file with the parameters
        write_ipf(tmpDir,teff,logg,metals,am,nm,cm,vm=vm)
        # Write the file with the fluxes and the flux errors
        write_ffile(tmpDir,spec,specerr=specerr)
        # Now write the input.nml file
        if f_access is None:
            f_access= 1
        write_input_nml(tmpDir,'input.ipf','output.dat',ndim=7-sixd,
                        nov=7-sixd-fixcm-fixnm-fixam-fixmetals\
                            -fixlogg-fixteff,
                        indv=indv,
                        synthfile=appath.ferreModelLibraryPath\
                            (lib=lib,pca=pca,sixd=sixd,dr=dr,
                             header=True,unf=False),
                        ffile='input.frd',erfile='input.err',
                        opfile='output.opf',
                        inter=inter,f_format=f_format,
                        errbar=errbar,indini=indini,init=init,
                        f_access=f_access,
                        filterfile=apwindow.path(elem,dr=dr))
        # Run FERRE
        run_ferre(tmpDir,verbose=verbose)
        # Read the output
        cols= (1,2,3,4,5,6)
        tmpOut= numpy.loadtxt(os.path.join(tmpDir,'output.opf'),usecols=cols)
        if len(spec.shape) == 1 or spec.shape[0] == 1:
            out= numpy.zeros((1,7))
            tmpOut= numpy.reshape(tmpOut,(1,7-sixd))
        else:
            out= numpy.zeros((nspec,7))
        out[:,paramIndx('TEFF')]= tmpOut[:,-1]
        out[:,paramIndx('LOGG')]= tmpOut[:,-2]
        out[:,paramIndx('METALS')]= tmpOut[:,-3]
        out[:,paramIndx('ALPHA')]= tmpOut[:,-4]
        out[:,paramIndx('N')]= tmpOut[:,-5]
        out[:,paramIndx('C')]= tmpOut[:,-6]
        if sixd and dr == '12':
            out[:,paramIndx('LOG10VDOP')]=\
                numpy.log10(2.478-0.325*out[:,paramIndx('LOGG')])
        else:
            out[:,paramIndx('LOG10VDOP')]= tmpOut[:,0]
        if not offile is None:
            os.rename(os.path.join(tmpDir,'output.dat'),offile)
    finally:
        # Clean up
        if os.path.exists(os.path.join(tmpDir,'input.ipf')):
            os.remove(os.path.join(tmpDir,'input.ipf'))
        if os.path.exists(os.path.join(tmpDir,'input.frd')):
            os.remove(os.path.join(tmpDir,'input.frd'))
        if os.path.exists(os.path.join(tmpDir,'input.err')):
            os.remove(os.path.join(tmpDir,'input.err'))
        if os.path.exists(os.path.join(tmpDir,'input.nml')):
            os.remove(os.path.join(tmpDir,'input.nml'))
        if os.path.exists(os.path.join(tmpDir,'output.dat')):
            os.remove(os.path.join(tmpDir,'output.dat'))
        if os.path.exists(os.path.join(tmpDir,'output.opf')):
            os.remove(os.path.join(tmpDir,'output.opf'))
        os.rmdir(tmpDir)
    if estimate_err:
        # Determine the chi2 and the error
        elem_linspace= (-0.5,0.5,51)
        elems= numpy.linspace(*elem_linspace)
        c2= elemchi2(spec,specerr,elem,
                     elem_linspace=elem_linspace,
                     fparam=out,lib=lib,pca=pca,sixd=sixd,dr=dr,
                     inter=inter,f_format=f_format,f_access=f_access,
                     verbose=verbose)
        from scipy import interpolate, optimize
        outerr= numpy.empty(nspec)
        for ii in range(nspec):
            spl= \
                interpolate.InterpolatedUnivariateSpline(elems,
                                                         c2[ii]-numpy.amin(c2[ii]))
            try:
                ul= optimize.brentq(lambda x: spl(x)-1.,
                                    0.,elem_linspace[1]-0.01)
                ll= optimize.brentq(lambda x: spl(x)-1.,
                                    elem_linspace[0]+0.01,0.)
                outerr[ii]= (ul-ll)/2.
            except ValueError:
                outerr[ii]= numpy.nan
        return (out,outerr)
    else:
        return out
Beispiel #29
0
def make_rcsample(parser):
    options,args= parser.parse_args()
    savefilename= options.savefilename
    if savefilename is None:
        #Create savefilename if not given
        savefilename= os.path.join(appath._APOGEE_DATA,
                                   'rcsample_'+appath._APOGEE_REDUX+'.fits')
        print "Saving to %s ..." % savefilename
    #Read the base-sample
    data= apread.allStar(adddist=_ADDHAYDENDIST,rmdups=options.rmdups)
    #Remove a bunch of fields that we do not want to keep
    data= esutil.numpy_util.remove_fields(data,
                                          ['TARGET_ID',
                                           'FILE',
                                           'AK_WISE',
                                           'SFD_EBV',
                                           'SYNTHVHELIO_AVG',
                                           'SYNTHVSCATTER',
                                           'SYNTHVERR',
                                           'SYNTHVERR_MED',
                                           'RV_TEFF',
                                           'RV_LOGG',
                                           'RV_FEH',
                                           'RV_CCFWHM',
                                           'RV_AUTOFWHM',
                                           'SYNTHSCATTER',
                                           'CHI2_THRESHOLD',
                                           'APSTAR_VERSION',
                                           'ASPCAP_VERSION',
                                           'RESULTS_VERSION',
                                           'REDUCTION_ID',
                                           'SRC_H',
                                           'PM_SRC'])
    if not appath._APOGEE_REDUX.lower() == 'current' \
            and int(appath._APOGEE_REDUX[1:]) < 500:
        data= esutil.numpy_util.remove_fields(data,
                                              ['ELEM'])
    #Select red-clump stars
    jk= data['J0']-data['K0']
    z= isodist.FEH2Z(data['METALS'],zsolar=0.017)
    if appath._APOGEE_REDUX.lower() == 'current' \
            or int(appath._APOGEE_REDUX[1:]) > 600:
        from apogee.tools import paramIndx
        if False:
            #Use my custom logg calibration that's correct for the RC
            logg= (1.-0.042)*data['FPARAM'][:,paramIndx('logg')]-0.213
            lowloggindx= data['FPARAM'][:,paramIndx('logg')] < 1.
            logg[lowloggindx]= data['FPARAM'][lowloggindx,paramIndx('logg')]-0.255
            hiloggindx= data['FPARAM'][:,paramIndx('logg')] > 3.8
            logg[hiloggindx]= data['FPARAM'][hiloggindx,paramIndx('logg')]-0.3726
        else:
            #Use my custom logg calibration that's correct on average
            logg= (1.+0.03)*data['FPARAM'][:,paramIndx('logg')]-0.37
            lowloggindx= data['FPARAM'][:,paramIndx('logg')] < 1.
            logg[lowloggindx]= data['FPARAM'][lowloggindx,paramIndx('logg')]-0.34
            hiloggindx= data['FPARAM'][:,paramIndx('logg')] > 3.8
            logg[hiloggindx]= data['FPARAM'][hiloggindx,paramIndx('logg')]-0.256
    else:
        logg= data['LOGG']
    indx= (jk < 0.8)*(jk >= 0.5)\
        *(z <= 0.06)\
        *(z <= rcmodel.jkzcut(jk,upper=True))\
        *(z >= rcmodel.jkzcut(jk))\
        *(logg >= rcmodel.loggteffcut(data['TEFF'],z,upper=False))\
        *(logg <= rcmodel.loggteffcut(data['TEFF'],z,upper=True))
    data= data[indx]
    #Add more aggressive flag cut
    data= esutil.numpy_util.add_fields(data,[('ADDL_LOGG_CUT',numpy.int32)])
    data['ADDL_LOGG_CUT']= ((data['TEFF']-4800.)/1000.+2.75) > data['LOGG']
    if options.loggcut:
        data= data[data['ADDL_LOGG_CUT'] == 1]
    print "Making catalog of %i objects ..." % len(data)
    #Add distances
    data= esutil.numpy_util.add_fields(data,[('RC_DIST', float),
                                             ('RC_DM', float),
                                             ('RC_GALR', float),
                                             ('RC_GALPHI', float),
                                             ('RC_GALZ', float)])
    rcd= rcmodel.rcdist()
    jk= data['J0']-data['K0']
    z= isodist.FEH2Z(data['METALS'],zsolar=0.017)
    data['RC_DIST']= rcd(jk,z,appmag=data['K0'])*options.distfac
    data['RC_DM']= 5.*numpy.log10(data['RC_DIST'])+10.
    XYZ= bovy_coords.lbd_to_XYZ(data['GLON'],
                                data['GLAT'],
                                data['RC_DIST'],
                                degree=True)
    R,phi,Z= bovy_coords.XYZ_to_galcencyl(XYZ[:,0],
                                          XYZ[:,1],
                                          XYZ[:,2],
                                          Xsun=8.,Zsun=0.025)
    data['RC_GALR']= R
    data['RC_GALPHI']= phi
    data['RC_GALZ']= Z
    #Save
    fitsio.write(savefilename,data,clobber=True)
    if not options.nostat:
        #Determine statistical sample and add flag
        apo= apogee.select.apogeeSelect()
        statIndx= apo.determine_statistical(data)
        mainIndx= apread.mainIndx(data)
        data= esutil.numpy_util.add_fields(data,[('STAT',numpy.int32),
                                                 ('INVSF',float)])
        data['STAT']= 0
        data['STAT'][statIndx*mainIndx]= 1
        for ii in range(len(data)):
            if (statIndx*mainIndx)[ii]:
                data['INVSF'][ii]= 1./apo(data['LOCATION_ID'][ii],
                                          data['H'][ii])
            else:
                data['INVSF'][ii]= -1.
    if options.nopm:
        fitsio.write(savefilename,data,clobber=True)       
        return None
    #Get proper motions
    from astroquery.vizier import Vizier
    import astroquery
    from astropy import units as u
    import astropy.coordinates as coord
    pmfile= savefilename.split('.')[0]+'_pms.fits'
    if os.path.exists(pmfile):
        pmdata= fitsio.read(pmfile,1)
    else:
        pmdata= numpy.recarray(len(data),
                               formats=['f8','f8','f8','f8','f8','f8','i4'],
                               names=['RA','DEC','PMRA','PMDEC',
                                      'PMRA_ERR','PMDEC_ERR','PMMATCH'])
        rad= u.Quantity(4./3600.,u.degree)
        v= Vizier(columns=['RAJ2000','DEJ2000','pmRA','pmDE','e_pmRA','e_pmDE'])
        for ii in range(len(data)):
            #if ii > 100: break
            sys.stdout.write('\r'+"Getting pm data for point %i / %i" % (ii+1,len(data)))
            sys.stdout.flush()
            pmdata.RA[ii]= data['RA'][ii]
            pmdata.DEC[ii]= data['DEC'][ii]
            co= coord.ICRS(ra=data['RA'][ii],
                           dec=data['DEC'][ii],
                           unit=(u.degree, u.degree))
            trying= True
            while trying:
                try:
                    tab= v.query_region(co,rad,catalog='I/322') #UCAC-4 catalog
                except astroquery.exceptions.TimeoutError:
                    pass
                else:
                    trying= False
            if len(tab) == 0:
                pmdata.PMMATCH[ii]= 0
                print "Didn't find a match for %i ..." % ii
                continue
            else:
                pmdata.PMMATCH[ii]= len(tab)
                if len(tab[0]['pmRA']) > 1:
                    print "Found more than 1 match for %i ..." % ii
            try:
                pmdata.PMRA[ii]= float(tab[0]['pmRA'])
            except TypeError:
                jj= 1
                while len(tab[0]['pmRA']) > 1 and jj < 4: 
                    trad= u.Quantity((4.-jj)/3600.,u.degree)
                    trying= True
                    while trying:
                        try:
                            tab= v.query_region(co,trad,catalog='I/322') #UCAC-4 catalog
                        except astroquery.exceptions.TimeoutError:
                            pass
                        else:
                            trying= False
                    jj+= 1
                if len(tab) == 0:
                    pmdata.PMMATCH[ii]= 0
                    print "Didn't find a unambiguous match for %i ..." % ii
                    continue               
                pmdata.PMRA[ii]= float(tab[0]['pmRA'])
            pmdata.PMDEC[ii]= float(tab[0]['pmDE'])
            pmdata.PMRA_ERR[ii]= float(tab[0]['e_pmRA'])
            pmdata.PMDEC_ERR[ii]= float(tab[0]['e_pmDE'])
            if numpy.isnan(float(tab[0]['pmRA'])): pmdata.PMMATCH[ii]= 0
        sys.stdout.write('\r'+_ERASESTR+'\r')
        sys.stdout.flush()
        fitsio.write(pmfile,pmdata,clobber=True)
        #To make sure we're using the same format below
        pmdata= fitsio.read(pmfile,1)
    #Match proper motions
    try: #These already exist currently, but may not always exist
        data= esutil.numpy_util.remove_fields(data,['PMRA','PMDEC'])
    except ValueError:
        pass
    data= esutil.numpy_util.add_fields(data,[('PMRA', numpy.float),
                                             ('PMDEC', numpy.float),
                                             ('PMRA_ERR', numpy.float),
                                             ('PMDEC_ERR', numpy.float),
                                             ('PMMATCH',numpy.int32)])
    data['PMMATCH']= 0
    h=esutil.htm.HTM()
    m1,m2,d12 = h.match(pmdata['RA'],pmdata['DEC'],
                        data['RA'],data['DEC'],
                        2./3600.,maxmatch=1)
    data['PMRA'][m2]= pmdata['PMRA'][m1]
    data['PMDEC'][m2]= pmdata['PMDEC'][m1]
    data['PMRA_ERR'][m2]= pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR'][m2]= pmdata['PMDEC_ERR'][m1]
    data['PMMATCH'][m2]= pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx= data['PMMATCH'] == 1
    data['PMRA'][True-pmindx]= -9999.99
    data['PMDEC'][True-pmindx]= -9999.99
    data['PMRA_ERR'][True-pmindx]= -9999.99
    data['PMDEC_ERR'][True-pmindx]= -9999.99
    #Calculate Galactocentric velocities
    data= esutil.numpy_util.add_fields(data,[('GALVR', numpy.float),
                                             ('GALVT', numpy.float),
                                             ('GALVZ', numpy.float)])
    lb= bovy_coords.radec_to_lb(data['RA'],data['DEC'],degree=True)
    XYZ= bovy_coords.lbd_to_XYZ(lb[:,0],lb[:,1],data['RC_DIST'],degree=True)
    pmllpmbb= bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA'],data['PMDEC'],
                                                data['RA'],data['DEC'],
                                                degree=True)
    vxvyvz= bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                             pmllpmbb[:,0],
                                             pmllpmbb[:,1],
                                             lb[:,0],lb[:,1],data['RC_DIST'],
                                             degree=True)
    vR, vT, vZ= bovy_coords.vxvyvz_to_galcencyl(vxvyvz[:,0],
                                                vxvyvz[:,1],
                                                vxvyvz[:,2],
                                                8.-XYZ[:,0],
                                                XYZ[:,1],
                                                XYZ[:,2]+0.025,
                                                vsun=[-11.1,30.24*8.,7.25])#Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR']= vR
    data['GALVT']= vT
    data['GALVZ']= vZ
    data['GALVR'][True-pmindx]= -9999.99
    data['GALVT'][True-pmindx]= -9999.99
    data['GALVZ'][True-pmindx]= -9999.99
    #Get proper motions
    pmfile= savefilename.split('.')[0]+'_pms_ppmxl.fits'
    if os.path.exists(pmfile):
        pmdata= fitsio.read(pmfile,1)
    else:
        pmdata= numpy.recarray(len(data),
                               formats=['f8','f8','f8','f8','f8','f8','i4'],
                               names=['RA','DEC','PMRA','PMDEC',
                                      'PMRA_ERR','PMDEC_ERR','PMMATCH'])
        rad= u.Quantity(4./3600.,u.degree)
        v= Vizier(columns=['RAJ2000','DEJ2000','pmRA','pmDE','e_pmRA','e_pmDE'])
        for ii in range(len(data)):
            #if ii > 100: break
            sys.stdout.write('\r'+"Getting pm data for point %i / %i" % (ii+1,len(data)))
            sys.stdout.flush()
            pmdata.RA[ii]= data['RA'][ii]
            pmdata.DEC[ii]= data['DEC'][ii]
            co= coord.ICRS(ra=data['RA'][ii],
                           dec=data['DEC'][ii],
                           unit=(u.degree, u.degree))
            trying= True
            while trying:
                try:
                    tab= v.query_region(co,rad,catalog='I/317') #PPMXL catalog
                except astroquery.exceptions.TimeoutError:
                    pass
                else:
                    trying= False
            if len(tab) == 0:
                pmdata.PMMATCH[ii]= 0
                print "Didn't find a match for %i ..." % ii
                continue
            else:
                pmdata.PMMATCH[ii]= len(tab)
                if len(tab[0]['pmRA']) > 1:
                    pass
                    #print "Found more than 1 match for %i ..." % ii
            try:
                pmdata.PMRA[ii]= float(tab[0]['pmRA'])
            except TypeError:
                #Find nearest
                cosdists= numpy.zeros(len(tab[0]['pmRA']))
                for jj in range(len(tab[0]['pmRA'])):
                    cosdists[jj]= cos_sphere_dist(tab[0]['RAJ2000'][jj],
                                                  tab[0]['DEJ2000'][jj],
                                                  data['RA'][ii],
                                                  data['DEC'][ii])
                closest= numpy.argmax(cosdists)
                pmdata.PMRA[ii]= float(tab[0]['pmRA'][closest])
                pmdata.PMDEC[ii]= float(tab[0]['pmDE'][closest])
                pmdata.PMRA_ERR[ii]= float(tab[0]['e_pmRA'][closest])
                pmdata.PMDEC_ERR[ii]= float(tab[0]['e_pmDE'][closest])
                if numpy.isnan(float(tab[0]['pmRA'][closest])): pmdata.PMMATCH[ii]= 0
            else:
                pmdata.PMDEC[ii]= float(tab[0]['pmDE'])
                pmdata.PMRA_ERR[ii]= float(tab[0]['e_pmRA'])
                pmdata.PMDEC_ERR[ii]= float(tab[0]['e_pmDE'])
                if numpy.isnan(float(tab[0]['pmRA'])): pmdata.PMMATCH[ii]= 0
        sys.stdout.write('\r'+_ERASESTR+'\r')
        sys.stdout.flush()
        fitsio.write(pmfile,pmdata,clobber=True)
        #To make sure we're using the same format below
        pmdata= fitsio.read(pmfile,1)
    #Match proper motions to ppmxl
    data= esutil.numpy_util.add_fields(data,[('PMRA_PPMXL', numpy.float),
                                             ('PMDEC_PPMXL', numpy.float),
                                             ('PMRA_ERR_PPMXL', numpy.float),
                                             ('PMDEC_ERR_PPMXL', numpy.float),
                                             ('PMMATCH_PPMXL',numpy.int32)])
    data['PMMATCH_PPMXL']= 0
    h=esutil.htm.HTM()
    m1,m2,d12 = h.match(pmdata['RA'],pmdata['DEC'],
                        data['RA'],data['DEC'],
                        2./3600.,maxmatch=1)
    data['PMRA_PPMXL'][m2]= pmdata['PMRA'][m1]
    data['PMDEC_PPMXL'][m2]= pmdata['PMDEC'][m1]
    data['PMRA_ERR_PPMXL'][m2]= pmdata['PMRA_ERR'][m1]
    data['PMDEC_ERR_PPMXL'][m2]= pmdata['PMDEC_ERR'][m1]
    data['PMMATCH_PPMXL'][m2]= pmdata['PMMATCH'][m1].astype(numpy.int32)
    pmindx= data['PMMATCH_PPMXL'] == 1
    data['PMRA_PPMXL'][True-pmindx]= -9999.99
    data['PMDEC_PPMXL'][True-pmindx]= -9999.99
    data['PMRA_ERR_PPMXL'][True-pmindx]= -9999.99
    data['PMDEC_ERR_PPMXL'][True-pmindx]= -9999.99
    #Calculate Galactocentric velocities
    data= esutil.numpy_util.add_fields(data,[('GALVR_PPMXL', numpy.float),
                                             ('GALVT_PPMXL', numpy.float),
                                             ('GALVZ_PPMXL', numpy.float)])
    lb= bovy_coords.radec_to_lb(data['RA'],data['DEC'],degree=True)
    XYZ= bovy_coords.lbd_to_XYZ(lb[:,0],lb[:,1],data['RC_DIST'],degree=True)
    pmllpmbb= bovy_coords.pmrapmdec_to_pmllpmbb(data['PMRA_PPMXL'],
                                                data['PMDEC_PPMXL'],
                                                data['RA'],data['DEC'],
                                                degree=True)
    vxvyvz= bovy_coords.vrpmllpmbb_to_vxvyvz(data['VHELIO_AVG'],
                                             pmllpmbb[:,0],
                                             pmllpmbb[:,1],
                                             lb[:,0],lb[:,1],data['RC_DIST'],
                                             degree=True)
    vR, vT, vZ= bovy_coords.vxvyvz_to_galcencyl(vxvyvz[:,0],
                                                vxvyvz[:,1],
                                                vxvyvz[:,2],
                                                8.-XYZ[:,0],
                                                XYZ[:,1],
                                                XYZ[:,2]+0.025,
                                                vsun=[-11.1,30.24*8.,7.25])#Assumes proper motion of Sgr A* and R0=8 kpc, zo= 25 pc
    data['GALVR_PPMXL']= vR
    data['GALVT_PPMXL']= vT
    data['GALVZ_PPMXL']= vZ
    data['GALVR_PPMXL'][True-pmindx]= -9999.99
    data['GALVT_PPMXL'][True-pmindx]= -9999.99
    data['GALVZ_PPMXL'][True-pmindx]= -9999.99
    #Save
    fitsio.write(savefilename,data,clobber=True)
    return None
Beispiel #30
0
def elemchi2(spec,specerr,
             elem,elem_linspace=(-0.5,0.5,11),tophat=False,
             fparam=None,
             teff=4750.,logg=2.5,metals=0.,am=0.,nm=0.,cm=0.,vm=None,
             lib='GK',pca=True,sixd=True,dr=None,
             offile=None,
             inter=3,f_format=1,f_access=None,
             verbose=False):
    """
    NAME:
       elemchi2
    PURPOSE:
       Calculate the chi^2 for a given element
    INPUT:
       Either:
          (1) location ID - single or list/array of location IDs
              APOGEE ID - single or list/array of APOGEE IDs; loads aspcapStar
          (2) spec - spectrum: can be (nwave) or (nspec,nwave)
              specerr - spectrum errors: can be (nwave) or (nspec,nwave)
       elem - element to consider (e.g., 'Al')
       elem_linspace= ((-0.5,0.5,11)) numpy.linspace range of abundance, relative to the relevant value in fparam / metals,am,nm,cm
       tophat= (False) if True, don't use the value of weights, just use them to define windows that have weight equal to one
       Input parameters (can be 1D arrays)
          Either:
             (1) fparam= (None) output of ferre.fit
             (2) teff= (4750.) Effective temperature (K)
                 logg= (2.5) log10 surface gravity / cm s^-2
                 metals= (0.) overall metallicity
                 am= (0.) [alpha/M]
                 nm= (0.) [N/M]
                 cm= (0.) [C/M]
                 vm= if using the 7D library, also specify the microturbulence
       Library options:
          lib= ('GK') spectral library
          pca= (True) if True, use a PCA compressed library
          sixd= (True) if True, use the 6D library (w/o vm)
          dr= data release
       FERRE options:
          inter= (3) order of the interpolation
          f_format= (1) file format (0=ascii, 1=unf)
          f_access= (None) 0: load whole library, 1: use direct access (for small numbers of interpolations), None: automatically determine a good value (currently, 1)
       verbose= (False) if True, run FERRE in verbose mode
    OUTPUT:
       chi^2
    HISTORY:
       2015-03-12 - Written - Bovy (IAS)
    """
    # Parse fparam
    if not fparam is None:
        teff= fparam[:,paramIndx('TEFF')]
        logg= fparam[:,paramIndx('LOGG')]
        metals= fparam[:,paramIndx('METALS')]
        am= fparam[:,paramIndx('ALPHA')]
        nm= fparam[:,paramIndx('N')]
        cm= fparam[:,paramIndx('C')]
        if sixd:
            vm= None
        else:
            vm= fparam[:,paramIndx('LOG10VDOP')]        
    # parse spec, specerr input
    nspec= len(teff)
    if len(spec.shape) == 1:
        spec= numpy.reshape(spec,(1,spec.shape[0]))
        specerr= numpy.reshape(specerr,(1,specerr.shape[0]))
    # Read the weights
    if tophat:
        weights= apwindow.tophat(elem,apStarWavegrid=False,dr=dr)
    else:
        weights= apwindow.read(elem,apStarWavegrid=False,dr=dr)
        weights/= numpy.sum(weights)
    # Decide which parameter to vary
    nvelem= elem_linspace[2]
    var_elem= numpy.tile(numpy.linspace(*elem_linspace),(nspec,1))   
    if elem.lower() == 'c':
        cm= var_elem+numpy.tile(cm,(nvelem,1)).T
    elif elem.lower() == 'n':
        nm= var_elem+numpy.tile(nm,(nvelem,1)).T
    elif elem.lower() in ['o','mg','s','si','ca','ti']:
        am= var_elem+numpy.tile(am,(nvelem,1)).T
    else:
        metals= var_elem+numpy.tile(metals,(nvelem,1)).T
    # Upgrade dimensionality of other parameters for interpolate input
    teff= numpy.tile(teff,(nvelem,1)).T
    logg= numpy.tile(logg,(nvelem,1)).T
    if not sixd:
        vm= numpy.tile(vm,(nvelem,1)).T.flatten()
    if not elem.lower() == 'c':
        cm= numpy.tile(cm,(nvelem,1)).T
    if not elem.lower() == 'n':
        nm= numpy.tile(nm,(nvelem,1)).T
    if not elem.lower() in ['o','mg','s','si','ca','ti']:
        am= numpy.tile(am,(nvelem,1)).T
    if elem.lower() in ['c','n','o','mg','s','si','ca','ti']:
        metals= numpy.tile(metals,(nvelem,1)).T
    # Get interpolated spectra, [nspec,nwave]
    ispec= interpolate(teff.flatten(),logg.flatten(),metals.flatten(),
                       am.flatten(),nm.flatten(),cm.flatten(),vm=vm,
                       lib=lib,pca=pca,sixd=sixd,dr=dr,
                       inter=inter,f_format=f_format,f_access=f_access,
                       verbose=verbose,apStarWavegrid=False)
    dspec= numpy.tile(spec,(1,nvelem)).reshape((nspec*nvelem,spec.shape[1]))
    dspecerr= numpy.tile(specerr,
                         (1,nvelem)).reshape((nspec*nvelem,spec.shape[1]))
    tchi2= _chi2(ispec,dspec,dspecerr,numpy.tile(weights,(nspec*nvelem,1)))
    return numpy.reshape(tchi2,(nspec,nvelem))