Ejemplo n.º 1
0
    def __init__(self,
                 tract,
                 patch,
                 objId,
                 catId=0,
                 visits=[],
                 pfsConfigIds=[],
                 nVisit=None,
                 pfsVisitHash=0x0):
        if visits:
            self.visits = visits
            self.nVisit = len(visits)
            self.pfsVisitHash = calculate_pfsVisitHash(visits)

            if nVisit and nVisit != self.nVisit:
                raise RuntimeError(
                    "Number of visits provided (== %d) != nVisit (== %d)" %
                    (nVisit, self.nVisit))
            if pfsVisitHash and pfsVisitHash != self.pfsVisitHash:
                raise RuntimeError(
                    "pfsVisitHash provided (== 0x%08x) != nVisit (== 0x%08x)" %
                    (pfsVisitHash, self.pfsVisitHash))
        else:
            self.nVisit = nVisit if nVisit else 1
            self.visits = None
            self.pfsVisitHash = pfsVisitHash

        if pfsConfigIds:
            self.pfsConfigIds = pfsConfigIds
        else:
            self.pfsConfigIds = None

        self.tract = tract
        self.patch = patch
        self.catId = catId
        self.objId = objId

        self.lam = None
        self.flux = None
        self.fluxTbl = self.FluxTbl(None)
        self.mask = None
        self.sky = None

        self.covar = None
        self.covar2 = None
    def __init__(self, tract, patch, objId, catId=0, visits=[], pfsConfigIds=[], 
                 nVisit=None, pfsVisitHash=0x0):
        if visits:
            self.visits = visits
            self.nVisit = len(visits)
            self.pfsVisitHash = calculate_pfsVisitHash(visits)

            if nVisit and nVisit != self.nVisit:
                raise RuntimeError("Number of visits provided (== %d) != nVisit (== %d)" % 
                                    (nVisit, self.nVisit))
            if pfsVisitHash and pfsVisitHash != self.pfsVisitHash:
                raise RuntimeError("pfsVisitHash provided (== 0x%08x) != nVisit (== 0x%08x)" % 
                                   (pfsVisitHash, self.pfsVisitHash))
        else:
            self.nVisit = nVisit if nVisit else 1
            self.visits = None
            self.pfsVisitHash = pfsVisitHash
            
        if pfsConfigIds:
            self.pfsConfigIds = pfsConfigIds
        else:
            self.pfsConfigIds = None
            
        self.tract = tract
        self.patch = patch
        self.catId = catId
        self.objId = objId

        self.lam = None
        self.flux = None
        self.fluxTbl = self.FluxTbl(None)
        self.mask = None
        self.sky = None
        
        self.covar = None
        self.covar2 = None
Ejemplo n.º 3
0
def makePfsObject(objId, pfsArms, catId=0, lambdaMin=350, lambdaMax=1260, dLambda=0.1):
    """Create a PfsObject from a list of PfsArmSet objects"""
    visits = [aset.visit for aset in pfsArms]
    #
    # Check that all the pfsArmSets are consistent
    #
    pfsConfig = None
    for aset in pfsArms:
        for arm in aset.data.values():
            fiberIdx = np.where(arm.pfsConfig.objId == objId)[0]
            if len(fiberIdx):
                fiberIdx = fiberIdx[0]
            else:
                raise RuntimeError("Object 0x%x is not present in pfsArm file for "
                                   "visit %d, spectrograph %d%s" %
                                   (objId, aset.visit, arm.spectrograph, arm.arm))

        if pfsConfig:
            assert (pfsConfig.tract, pfsConfig.patch) == (aset.pfsConfig.tract, aset.pfsConfig.patch)
        else:
            pfsConfig = aset.pfsConfig
            tract = pfsConfig.tract[fiberIdx]
            patch = pfsConfig.patch[fiberIdx]

    if False:
        pfsVisitHash = calculate_pfsVisitHash(visits)  # noqa: F841 (never used)
    pfsObject = PfsObject(tract, patch, objId, catId, visits=visits)
    pfsObject.pfsConfigIds = []         # we'll set them from the pfsArm files

    pfsObject.lam = lambdaMin + dLambda*np.arange(int((lambdaMax - lambdaMin)/dLambda), dtype=np.float32)
    #
    # Start by interpolating all the data onto the single uniform sampling
    #
    armFlux = {}
    armVariance = {}
    armSky = {}
    armMask = {}

    for aset in pfsArms:
        visit = aset.visit
        armFlux[visit] = {}
        armVariance[visit] = {}
        armMask[visit] = {}
        armSky[visit] = {}

        for arm in aset.data.values():
            pfsObject.pfsConfigIds.append(arm.pfsConfigId)
            fiberIdx = np.where(arm.pfsConfig.objId == objId)[0]
            if len(fiberIdx):
                fiberIdx = fiberIdx[0]
            else:
                raise RuntimeError("Object 0x%x is not present in pfsArm file for "
                                   "visit %d, spectrograph %d%s" %
                                   (objId, visit, arm.spectrograph, arm.arm))
            #
            # how to interpolate
            #
            kwargs = dict(kind='linear',
                          bounds_error=False,
                          fill_value=0,
                          copy=True,
                          # assume_sorted=True
                          )

            armFlux[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.flux[fiberIdx],
                                               **kwargs)(pfsObject.lam)
            armSky[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.sky[fiberIdx],
                                              **kwargs)(pfsObject.lam)
            kwargs.update(fill_value=np.inf)
            armVariance[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.covar[fiberIdx][0],
                                                   **kwargs)(pfsObject.lam)
            kwargs.update(fill_value=PfsArm.flags["NODATA"], kind='nearest')
            armMask[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.mask[fiberIdx],
                                               **kwargs)(pfsObject.lam)
            armMask[visit][arm.arm] = armMask[visit][arm.arm].astype(arm.mask[fiberIdx].dtype)

    pfsObject.flux = np.zeros_like(pfsObject.lam)
    pfsObject.covar = np.zeros(3*len(pfsObject.lam)).reshape(3, len(pfsObject.lam))
    pfsObject.mask = np.zeros_like(pfsObject.lam, dtype=np.int32)
    pfsObject.sky = np.zeros_like(pfsObject.lam)

    weights = np.zeros_like(pfsObject.lam)
    #
    # Average together all the arm data
    #
    for aset in pfsArms:
        visit = aset.visit
        for arm in aset.data:
            w = 1/armVariance[visit][arm]
            pfsObject.flux += w*armFlux[visit][arm]
            pfsObject.sky += w*armSky[visit][arm]
            pfsObject.mask |= np.where(w > 0, armMask[visit][arm], 0)
            weights += w

    noData = (weights == 0)
    pfsObject.flux /= np.where(noData, 1, weights)
    pfsObject.flux[noData] = np.nan

    pfsObject.sky /= np.where(noData, 1, weights)
    pfsObject.sky[noData] = np.nan

    pfsObject.mask[noData] = PfsArm.flags["NODATA"]

    with np.errstate(divide='ignore'):
        pfsObject.covar[0] = np.where(weights == 0, np.inf, 1/weights)
        pfsObject.covar[1] = np.where(weights == 0, np.inf, 0)
        pfsObject.covar[2] = np.where(weights == 0, np.inf, 0)
    #
    # Set the coarse-grained covariance
    #
    # For now, we'll just set it from the diagonal part of covar, binned into NCOARSE pieces
    #
    C = np.zeros((pfsObject.NCOARSE, pfsObject.NCOARSE))
    pfsObject.covar2 = C

    binsize = len(pfsObject.lam)//pfsObject.NCOARSE
    idx = (np.arange(len(pfsObject.lam))//binsize).astype(int)

    goodData = np.logical_not(noData)
    for j in range(pfsObject.NCOARSE):
        x = pfsObject.covar[0][np.logical_and(goodData, idx == j)]
        C[j, j] = x.sum()/np.sqrt(len(x))
    #
    # Now the best-estimate flux at the native resolution of the pfsArm files
    #
    overlaps = []
    arms = pfsArms[0].data
    if 'b' in arms and 'r' in arms:
        overlaps.append(('b', 'r'))
    if 'r' in arms and 'n' in arms:
        overlaps.append(('r', 'n'))

    fluxTbl = collections.OrderedDict()
    fiberIdx = np.where(list(arms.values())[0].pfsConfig.objId == objId)[0][0]  # we checked existence above

    if not overlaps:
        for armStr in arms:
            fluxTbl[armStr] = PfsObject.FluxTbl(arms[armStr].lam[fiberIdx])
    else:
        #
        # how to interpolate
        #
        kwargs = dict(kind='linear',
                      bounds_error=False,
                      copy=True,
                      # assume_sorted=True
                      )
        firstLam = None                  # the first wavelength to include from previous overlap
        for a1, a2 in overlaps:
            var2 = interp1d(arms[a2].lam[fiberIdx], arms[a2].covar[fiberIdx][0],
                            fill_value=np.inf, **kwargs)(arms[a1].lam[fiberIdx])
            #
            # Set an array to the values where the covariance is less in a1 than a2
            #
            # Because the covariances are a bit noisy where the arms cross, and
            # because the interpolation giving var2 can smooth things, use all
            # the points to the left of the last acceptable value
            useA1 = arms[a1].covar[fiberIdx][0] < var2
            lastGoodIdx = np.argwhere(useA1)[-1][-1]
            useA1 = np.where(np.arange(len(useA1)) <= lastGoodIdx, True, False)
            #
            # Remember the first wavelength that we should use from the next overlap
            #
            if firstLam:
                useA1 = np.logical_and(useA1, arms[a1].lam[fiberIdx] >= firstLam)
                firstLam = None

            fluxTbl[a1] = PfsObject.FluxTbl(arms[a1].lam[fiberIdx][useA1])
            #
            # set firstLam for the next overlap
            #
            if lastGoodIdx < len(useA1) - 1:   # we want at least one value from a2
                firstLam = arms[a1].lam[fiberIdx][lastGoodIdx + 1]
        #
        # include the last arm
        #
        a1 = overlaps[-1][1]
        useA1 = np.ones_like(useA1)
        if firstLam:
            useA1 = np.logical_and(useA1, arms[a1].lam[fiberIdx] >= firstLam)
            firstLam = None

        fluxTbl[a1] = PfsObject.FluxTbl(arms[a1].lam[fiberIdx][useA1])
    #
    # OK, we have the range of wavelengths that we want to use,
    # so interpolate the data onto those wavelengths (arm by arm) and average
    #
    assert len(fluxTbl) == len(pfsArms[0].data)
    for armStr in fluxTbl:
        armFlux = {}
        armVariance = {}
        armMask = {}

        for aset in pfsArms:
            arm = aset.data[armStr]
            fiberIdx = np.where(arm.pfsConfig.objId == objId)[0][0]  # we checked existence above
            #
            # how to interpolate
            #
            kwargs = dict(kind='linear',
                          bounds_error=False,
                          copy=True,
                          # assume_sorted=True
                          )

            armFlux[arm] = interp1d(arm.lam[fiberIdx], arm.flux[fiberIdx],
                                    fill_value=0, **kwargs)(fluxTbl[armStr].lam)
            armVariance[arm] = interp1d(arm.lam[fiberIdx], arm.covar[fiberIdx][0],
                                        fill_value=np.inf, **kwargs)(fluxTbl[armStr].lam)
            kwargs.update(fill_value=PfsArm.flags["NODATA"], kind='nearest')
            armMask[arm] = interp1d(arm.lam[fiberIdx], arm.mask[fiberIdx], **kwargs)(fluxTbl[armStr].lam)
            armMask[arm] = armMask[arm].astype(arm.mask[fiberIdx].dtype)

        weights = np.zeros_like(fluxTbl[armStr].lam)
        #
        # Average together all the arm data
        #
        for aset in pfsArms:
            visit = aset.visit
            w = 1/armVariance[arm]
            fluxTbl[armStr].flux += w*armFlux[arm]
            fluxTbl[armStr].mask |= np.where(w > 0, armMask[arm], 0)

            weights += w

        noData = (weights == 0)
        fluxTbl[armStr].flux /= np.where(noData, 1, weights)
        fluxTbl[armStr].flux[noData] = np.nan

        with np.errstate(divide='ignore'):
            fluxTbl[armStr].fluxVariance = np.where(weights == 0, np.inf, 1/weights)
    #
    # The PfsObject.FluxTbl isn't actually quite what we need, as it's N separate FluxTbl
    # objects rather than one covering all the arms.  Fix this
    #
    nPoint = np.sum(len(ft.flux) for ft in fluxTbl.values())
    lam = np.empty(nPoint, dtype=np.float32)
    pfsObject.fluxTbl = PfsObject.FluxTbl(lam)

    i0 = 0
    for ft in fluxTbl.values():
        i1 = i0 + len(ft.lam)
        pfsObject.fluxTbl.lam[i0:i1] = ft.lam
        pfsObject.fluxTbl.flux[i0:i1] = ft.flux
        pfsObject.fluxTbl.mask[i0:i1] = ft.mask
        pfsObject.fluxTbl.fluxVariance[i0:i1] = ft.fluxVariance
        i0 = i1

    return pfsObject
def makePfsObject(tract, patch, objId, pfsArms, catId=0, lambdaMin=350, lambdaMax=1260, dLambda=0.1):
    """Create a PfsObject from a list of PfsArmSet objects"""
    visits = [aset.visit for aset in pfsArms]
    nVisit = len(pfsArms)
    pfsVisitHash = calculate_pfsVisitHash(visits)
    pfsObject = PfsObject(tract, patch, objId, catId, visits=visits)
    pfsObject.pfsConfigIds = []         # we'll set them from the pfsArm files

    pfsObject.lam = lambdaMin + dLambda*np.arange(int((lambdaMax - lambdaMin)/dLambda),
                                                  dtype=np.float32)    
    #
    # Start by interpolating all the data onto the single uniform sampling
    #
    armFlux = {}
    armVariance = {}
    armSky = {}
    armMask = {}

    for aset in pfsArms:
        visit = aset.visit
        armFlux[visit] = {}
        armVariance[visit] = {}
        armMask[visit] = {}
        armSky[visit] = {}

        for arm in aset.data.values():
            pfsObject.pfsConfigIds.append(arm.pfsConfigId)
            fiberIdx = np.where(arm.pfsConfig.objId == objId)[0]
            if len(fiberIdx):
                fiberIdx = fiberIdx[0]
            else:
                raise RuntimeError("Object 0x%x is not present in pfsArm file for " 
                                   "visit %d, spectrograph %d%s" %
                                    (objId, visit, arm.spectrograph, arm.arm))
            #
            # how to interpolate
            #
            kwargs = dict(kind='linear', 
                          bounds_error=False,
                          fill_value=0,
                          copy=True,
                          # assume_sorted=True
                          )
            
            armFlux[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.flux[fiberIdx],
                                               **kwargs)(pfsObject.lam)
            armSky[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.sky[fiberIdx],
                                               **kwargs)(pfsObject.lam)
            kwargs.update(fill_value=np.inf)
            armVariance[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.covar[fiberIdx][0],
                                               **kwargs)(pfsObject.lam)
            kwargs.update(fill_value=PfsArm.flags["NODATA"], kind='nearest')
            armMask[visit][arm.arm] = interp1d(arm.lam[fiberIdx], arm.mask[fiberIdx],
                                               **kwargs)(pfsObject.lam)
            armMask[visit][arm.arm] = armMask[visit][arm.arm].astype(arm.mask[fiberIdx].dtype)

    pfsObject.flux = np.zeros_like(pfsObject.lam)
    pfsObject.covar = np.zeros(3*len(pfsObject.lam)).reshape(3, len(pfsObject.lam))
    pfsObject.mask = np.zeros_like(pfsObject.lam, dtype=np.int32)
    pfsObject.sky = np.zeros_like(pfsObject.lam)

    weights = np.zeros_like(pfsObject.lam)
    #
    # Average together all the arm data
    #
    for aset in pfsArms:
        visit = aset.visit
        for arm in aset.data:
            w = 1/armVariance[visit][arm]
            pfsObject.flux += w*armFlux[visit][arm]
            pfsObject.sky += w*armSky[visit][arm]
            pfsObject.mask |= np.where(w > 0, armMask[visit][arm], 0)
            weights += w
            
    noData = (weights == 0)
    pfsObject.flux /= np.where(noData, 1, weights)
    pfsObject.flux[noData] = np.nan

    pfsObject.sky /= np.where(noData, 1, weights)
    pfsObject.sky[noData] = np.nan
    
    pfsObject.mask[noData] = PfsArm.flags["NODATA"]

    with np.errstate(divide='ignore'):
        pfsObject.covar[0] = np.where(weights == 0, np.inf, 1/weights)
        pfsObject.covar[1] = np.where(weights == 0, np.inf, 0)
        pfsObject.covar[2] = np.where(weights == 0, np.inf, 0)
    #
    # Set the coarse-grained covariance
    #
    # For now, we'll just set it from the diagonal part of covar, binned into NCOARSE pieces
    #
    C = np.zeros((pfsObject.NCOARSE, pfsObject.NCOARSE))
    pfsObject.covar2 = C
    
    binsize = len(pfsObject.lam)//pfsObject.NCOARSE
    idx = (np.arange(len(pfsObject.lam))/binsize).astype(int)

    goodData = np.logical_not(noData)
    for j in range(pfsObject.NCOARSE):
        x = pfsObject.covar[0][np.logical_and(goodData, idx == j)]
        C[j, j] = x.sum()/np.sqrt(len(x))
    #
    # Now the best-estimate flux at the native resolution of the pfsArm files
    #
    overlaps = []
    arms = pfsArms[0].data
    if 'b' in arms and 'r' in arms:
        overlaps.append(('b', 'r'))
    if 'r' in arms and 'n' in arms:
        overlaps.append(('r', 'n'))

    fluxTbl = collections.OrderedDict()
    fiberIdx = np.where(arms.values()[0].pfsConfig.objId == objId)[0][0]  # we checked existence above
    
    if not overlaps:
        for armStr in arms:
            fluxTbl[armStr] = PfsObject.FluxTbl(arms[armStr].lam[fiberIdx])
    else:
        #
        # how to interpolate
        #
        kwargs = dict(kind='linear', 
                      bounds_error=False,
                      copy=True,
                      # assume_sorted=True
                      )
        firstLam = None                  # the first wavelength to include from previous overlap
        for a1, a2 in overlaps:
            var2 = interp1d(arms[a2].lam[fiberIdx], arms[a2].covar[fiberIdx][0],
                            fill_value=np.inf, **kwargs)(arms[a1].lam[fiberIdx])
            #
            # Set an array to the values where the covariance is less in a1 than a2
            #
            # Because the covariances are a bit noisy where the arms cross, and 
            # because the interpolation giving var2 can smooth things, use all
            # the points to the left of the last acceptable value
            useA1 = arms[a1].covar[fiberIdx][0] < var2
            lastGoodIdx = np.argwhere(useA1)[-1][-1]
            useA1 = np.where(np.arange(len(useA1)) <= lastGoodIdx, True, False)
            #
            # Remember the first wavelength that we should use from the next overlap
            #
            if firstLam:
                useA1 = np.logical_and(useA1, arms[a1].lam[fiberIdx] >= firstLam)
                firstLam = None
                
            fluxTbl[a1] = PfsObject.FluxTbl(arms[a1].lam[fiberIdx][useA1])
            #
            # set firstLam for the next overlap
            #
            if lastGoodIdx < len(useA1) - 1:   # we want at least one value from a2
                firstLam = arms[a1].lam[fiberIdx][lastGoodIdx + 1]
        #
        # include the last arm
        #
        a1 = overlaps[-1][1]
        useA1 = np.ones_like(useA1)
        if firstLam:
            useA1 = np.logical_and(useA1, arms[a1].lam[fiberIdx] >= firstLam)
            firstLam = None
                
        fluxTbl[a1] = PfsObject.FluxTbl(arms[a1].lam[fiberIdx][useA1])
    #
    # OK, we have the range of wavelengths that we want to use,
    # so interpolate the data onto those wavelengths (arm by arm) and average
    #
    assert len(fluxTbl) == len(pfsArms[0].data)
    for armStr in fluxTbl:
        armFlux = {}
        armVariance = {}
        armMask = {}

        for aset in pfsArms:
            arm = aset.data[armStr]
            fiberIdx = np.where(arm.pfsConfig.objId == objId)[0][0]  # we checked existence above
            #
            # how to interpolate
            #
            kwargs = dict(kind='linear', 
                          bounds_error=False,
                          copy=True,
                          # assume_sorted=True
                          )
            
            armFlux[arm] = interp1d(arm.lam[fiberIdx], arm.flux[fiberIdx],
                                               fill_value=0, **kwargs)(fluxTbl[armStr].lam)
            armVariance[arm] = interp1d(arm.lam[fiberIdx], arm.covar[fiberIdx][0],
                                               fill_value=np.inf, **kwargs)(fluxTbl[armStr].lam)
            kwargs.update(fill_value=PfsArm.flags["NODATA"], kind='nearest')
            armMask[arm] = interp1d(arm.lam[fiberIdx], arm.mask[fiberIdx],**kwargs)(fluxTbl[armStr].lam)
            armMask[arm] = armMask[arm].astype(arm.mask[fiberIdx].dtype)

        weights = np.zeros_like(fluxTbl[armStr].lam)
        #
        # Average together all the arm data
        #
        for aset in pfsArms:
            visit = aset.visit
            w = 1/armVariance[arm]
            fluxTbl[armStr].flux += w*armFlux[arm]
            fluxTbl[armStr].mask |= np.where(w > 0, armMask[arm], 0)

            weights += w
                
        noData = (weights == 0)
        fluxTbl[armStr].flux /= np.where(noData, 1, weights)
        fluxTbl[armStr].flux[noData] = np.nan

        with np.errstate(divide='ignore'):
            fluxTbl[armStr].fluxVariance = np.where(weights == 0, np.inf, 1/weights)
    #
    # The PfsObject.FluxTbl isn't actually quite what we need, as it's N separate FluxTbl
    # objects rather than one covering all the arms.  Fix this
    #
    nPoint = np.sum(len(ft.flux) for ft in fluxTbl.values())
    lam = np.empty(nPoint, dtype=np.float32)
    pfsObject.fluxTbl = PfsObject.FluxTbl(lam)
    
    i0 = 0
    for ft in fluxTbl.values():
        i1 = i0 + len(ft.lam)
        pfsObject.fluxTbl.lam[i0:i1] = ft.lam
        pfsObject.fluxTbl.flux[i0:i1] = ft.flux
        pfsObject.fluxTbl.mask[i0:i1] = ft.mask
        pfsObject.fluxTbl.fluxVariance[i0:i1] = ft.fluxVariance
        i0 = i1

    return pfsObject