Beispiel #1
0
def MakeFrameMask(data,frame):
    pixelSize = data['pixelSize']
    scalex = pixelSize[0]/1000.
    scaley = pixelSize[1]/1000.
    blkSize = 512
    Nx,Ny = data['size']
    nXBlks = (Nx-1)/blkSize+1
    nYBlks = (Ny-1)/blkSize+1
    tam = ma.make_mask_none(data['size'])
    for iBlk in range(nXBlks):
        iBeg = iBlk*blkSize
        iFin = min(iBeg+blkSize,Nx)
        for jBlk in range(nYBlks):
            jBeg = jBlk*blkSize
            jFin = min(jBeg+blkSize,Ny)                
            nI = iFin-iBeg
            nJ = jFin-jBeg
            tax,tay = np.mgrid[iBeg+0.5:iFin+.5,jBeg+.5:jFin+.5]         #bin centers not corners
            tax = np.asfarray(tax*scalex,dtype=np.float32)
            tay = np.asfarray(tay*scaley,dtype=np.float32)
            tamp = ma.make_mask_none((1024*1024))
            tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(),
                tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True  #switch to exclude around frame
            if tamp.shape:
                tamp = np.reshape(tamp[:nI*nJ],(nI,nJ))
                tam[iBeg:iFin,jBeg:jFin] = ma.mask_or(tamp[0:nI,0:nJ],tam[iBeg:iFin,jBeg:jFin])
            else:
                tam[iBeg:iFin,jBeg:jFin] = True
    return tam.T
Beispiel #2
0
def MakeFrameMask(data, frame):
    pixelSize = data['pixelSize']
    scalex = pixelSize[0] / 1000.
    scaley = pixelSize[1] / 1000.
    blkSize = 512
    Nx, Ny = data['size']
    nXBlks = (Nx - 1) / blkSize + 1
    nYBlks = (Ny - 1) / blkSize + 1
    tam = ma.make_mask_none(data['size'])
    for iBlk in range(nXBlks):
        iBeg = iBlk * blkSize
        iFin = min(iBeg + blkSize, Nx)
        for jBlk in range(nYBlks):
            jBeg = jBlk * blkSize
            jFin = min(jBeg + blkSize, Ny)
            nI = iFin - iBeg
            nJ = jFin - jBeg
            tax, tay = np.mgrid[iBeg + 0.5:iFin + .5,
                                jBeg + .5:jFin + .5]  #bin centers not corners
            tax = np.asfarray(tax * scalex, dtype=np.float32)
            tay = np.asfarray(tay * scaley, dtype=np.float32)
            tamp = ma.make_mask_none((1024 * 1024))
            tamp = ma.make_mask(
                pm.polymask(
                    nI * nJ, tax.flatten(), tay.flatten(), len(frame), frame,
                    tamp)[:nI * nJ]) - True  #switch to exclude around frame
            if tamp.shape:
                tamp = np.reshape(tamp[:nI * nJ], (nI, nJ))
                tam[iBeg:iFin,
                    jBeg:jFin] = ma.mask_or(tamp[0:nI, 0:nJ], tam[iBeg:iFin,
                                                                  jBeg:jFin])
            else:
                tam[iBeg:iFin, jBeg:jFin] = True
    return tam.T
Beispiel #3
0
def Make2ThetaAzimuthMap(data, masks, iLim, jLim,
                         times):  #most expensive part of integration!
    'Needs a doc string'
    #transforms 2D image from x,y space to 2-theta,azimuth space based on detector orientation
    pixelSize = data['pixelSize']
    scalex = pixelSize[0] / 1000.
    scaley = pixelSize[1] / 1000.

    tay, tax = np.mgrid[iLim[0] + 0.5:iLim[1] + .5,
                        jLim[0] + .5:jLim[1] + .5]  #bin centers not corners
    tax = np.asfarray(tax * scalex, dtype=np.float32)
    tay = np.asfarray(tay * scaley, dtype=np.float32)
    nI = iLim[1] - iLim[0]
    nJ = jLim[1] - jLim[0]
    t0 = time.time()
    #make position masks here
    frame = masks['Frames']
    tam = ma.make_mask_none((nI, nJ))
    if frame:
        tamp = ma.make_mask_none((1024 * 1024))
        tamp = ma.make_mask(
            pm.polymask(
                nI * nJ, tax.flatten(), tay.flatten(), len(frame), frame,
                tamp)[:nI * nJ]) - True  #switch to exclude around frame
        tam = ma.mask_or(tam.flatten(), tamp)
    polygons = masks['Polygons']
    for polygon in polygons:
        if polygon:
            tamp = ma.make_mask_none((1024 * 1024))
            tamp = ma.make_mask(
                pm.polymask(nI * nJ, tax.flatten(), tay.flatten(),
                            len(polygon), polygon, tamp)[:nI * nJ])
            tam = ma.mask_or(tam.flatten(), tamp)
    if tam.shape: tam = np.reshape(tam, (nI, nJ))
    spots = masks['Points']
    for X, Y, diam in spots:
        tamp = ma.getmask(
            ma.masked_less((tax - X)**2 + (tay - Y)**2, (diam / 2.)**2))
        tam = ma.mask_or(tam, tamp)
    times[0] += time.time() - t0
    t0 = time.time()
    TA = np.array(GetTthAzmG(
        tax, tay,
        data))  #includes geom. corr. as dist**2/d0**2 - most expensive step
    times[1] += time.time() - t0
    TA[1] = np.where(TA[1] < 0, TA[1] + 360, TA[1])
    return np.array(
        TA), tam  #2-theta, azimuth & geom. corr. arrays & position mask
Beispiel #4
0
def Make2ThetaAzimuthMap(data,masks,iLim,jLim,times): #most expensive part of integration!
    'Needs a doc string'
    #transforms 2D image from x,y space to 2-theta,azimuth space based on detector orientation
    pixelSize = data['pixelSize']
    scalex = pixelSize[0]/1000.
    scaley = pixelSize[1]/1000.
    
    tay,tax = np.mgrid[iLim[0]+0.5:iLim[1]+.5,jLim[0]+.5:jLim[1]+.5]         #bin centers not corners
    tax = np.asfarray(tax*scalex,dtype=np.float32)
    tay = np.asfarray(tay*scaley,dtype=np.float32)
    nI = iLim[1]-iLim[0]
    nJ = jLim[1]-jLim[0]
    t0 = time.time()
    #make position masks here
    frame = masks['Frames']
    tam = ma.make_mask_none((nI,nJ))
    if frame:
        tamp = ma.make_mask_none((1024*1024))
        tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(),
            tay.flatten(),len(frame),frame,tamp)[:nI*nJ])-True  #switch to exclude around frame
        tam = ma.mask_or(tam.flatten(),tamp)
    polygons = masks['Polygons']
    for polygon in polygons:
        if polygon:
            tamp = ma.make_mask_none((1024*1024))
            tamp = ma.make_mask(pm.polymask(nI*nJ,tax.flatten(),
                tay.flatten(),len(polygon),polygon,tamp)[:nI*nJ])
            tam = ma.mask_or(tam.flatten(),tamp)
    if tam.shape: tam = np.reshape(tam,(nI,nJ))
    spots = masks['Points']
    for X,Y,diam in spots:
        tamp = ma.getmask(ma.masked_less((tax-X)**2+(tay-Y)**2,(diam/2.)**2))
        tam = ma.mask_or(tam,tamp)
    times[0] += time.time()-t0
    t0 = time.time()
    TA = np.array(GetTthAzmG(tax,tay,data))     #includes geom. corr. as dist**2/d0**2 - most expensive step
    times[1] += time.time()-t0
    TA[1] = np.where(TA[1]<0,TA[1]+360,TA[1])
    return np.array(TA),tam           #2-theta, azimuth & geom. corr. arrays & position mask
Beispiel #5
0
 def test_hardmask(self):
     # Test hardmask
     base = self.base.copy()
     mbase = base.view(mrecarray)
     mbase.harden_mask()
     self.assertTrue(mbase._hardmask)
     mbase.mask = nomask
     assert_equal_records(mbase._mask, base._mask)
     mbase.soften_mask()
     self.assertTrue(not mbase._hardmask)
     mbase.mask = nomask
     # So, the mask of a field is no longer set to nomask...
     assert_equal_records(mbase._mask, ma.make_mask_none(base.shape, base.dtype))
     self.assertTrue(ma.make_mask(mbase["b"]._mask) is nomask)
     assert_equal(mbase["a"]._mask, mbase["b"]._mask)
Beispiel #6
0
 def test_hardmask(self):
     # Test hardmask
     base = self.base.copy()
     mbase = base.view(mrecarray)
     mbase.harden_mask()
     assert_(mbase._hardmask)
     mbase.mask = nomask
     assert_equal_records(mbase._mask, base._mask)
     mbase.soften_mask()
     assert_(not mbase._hardmask)
     mbase.mask = nomask
     # So, the mask of a field is no longer set to nomask...
     assert_equal_records(mbase._mask, ma.make_mask_none(base.shape, base.dtype))
     assert_(ma.make_mask(mbase["b"]._mask) is nomask)
     assert_equal(mbase["a"]._mask, mbase["b"]._mask)
def getWeightedAvg(a, neighbourArray):
	kernSize = 2
	kernel = utils.gauss_kern(kernSize)	  
	pixVal = np.zeros((a.shape)) #initialising, pixel value for inpainting
	weightSum = np.zeros((a.shape)) #initialising, value for later normalisation
	#for pixels further away from the edges:
	maxNeighbours = np.max(neighbourArray)
	print np.max(neighbourArray)
	neighbours = ((-2, -2), (-2, -1), (-2, 0), (-2, 1), (-2, 2), (-1, -2), (-1, -1), (-1, 0), (-1, 1), (-1, 2), (0, -2), (0, -1), (0, 1), (0, 2), (1, -2), (1, -1), (1, 0), (1, 1), (1, 2), (2, -2), (2, -1), (2, 0), (2, 1), (2, 2))
	a_reduced = a[2:-2, 2:-2].copy()
	maxNMask = ma.make_mask_none((a.shape))
	
	maxNMask[np.where(neighbourArray == maxNeighbours)] = 1
	print a_reduced.shape
	for hor_shift,vert_shift in neighbours:
	    #if not np.any(a.mask): break
	    a_shifted = np.roll(a_reduced, shift = hor_shift, axis = 1)
	    a_shifted = np.roll(a_shifted, shift = vert_shift, axis = 0)
	    idx=~a_shifted.mask*maxNMask[2:-2, 2:-2]

	    weightSum = weightSum + kernel[2-vert_shift, 2-hor_shift]
	    pixVal[idx] = pixVal[idx]+ a_shifted[idx]*kernel[2-vert_shift, 2-hor_shift]
	b = a.copy()
	b[idx] = np.divide(pixVal[idx], weightSum[idx])    
	edgesTop = a[0:2, :]
	edgesLeft = a[:, 0:2]
	edgesRight = a[:, -1:-3:-1]
	edgesBottom = a[-1:-3:-1, :]
	for i in range(0, 3):
		for j in range(0, a.shape[1]):
			if neighbourArray[i, j] == maxNeighbours:
				b[i, j] = getWeightedAvgEdges(inputArray, i, j)
	for i in range(a.shape[0] - 2, a.shape[0]):
		for j in range(0, a.shape[1]):
			if neighbourArray[i, j] == maxNeighbours:
				b[i, j] = getWeightedAvgEdges(inputArray, i, j)	
	for i in range(0, a.shape[0]):
		for j in range(0, 3):
			if neighbourArray[i, j] == maxNeighbours:
				b[i, j] = getWeightedAvgEdges(inputArray, i, j)
	for i in range(0, a.shape[0]):
		for j in range(a.shape[1] - 2, a.shape[1]):
			if neighbourArray[i, j] == maxNeighbours:
				b[i, j] = getWeightedAvgEdges(inputArray, i, j)														
	return b
Beispiel #8
0
 def __array_finalize__(self, obj):
     # Make sure we have a _fieldmask by default ..
     _mask = getattr(obj, "_mask", None)
     if _mask is None:
         objmask = getattr(obj, "_mask", nomask)
         _dtype = ndarray.__getattribute__(self, "dtype")
         if objmask is nomask:
             _mask = ma.make_mask_none(self.shape, dtype=_dtype)
         else:
             mdescr = ma.make_mask_descr(_dtype)
             _mask = narray([tuple([m] * len(mdescr)) for m in objmask], dtype=mdescr).view(recarray)
     # Update some of the attributes
     _dict = self.__dict__
     _dict.update(_mask=_mask, _fieldmask=_mask)
     self._update_from(obj)
     if _dict["_baseclass"] == ndarray:
         _dict["_baseclass"] = recarray
     return
Beispiel #9
0
 def __array_finalize__(self, obj):
     # Make sure we have a _fieldmask by default
     _mask = getattr(obj, '_mask', None)
     if _mask is None:
         objmask = getattr(obj, '_mask', nomask)
         _dtype = ndarray.__getattribute__(self, 'dtype')
         if objmask is nomask:
             _mask = ma.make_mask_none(self.shape, dtype=_dtype)
         else:
             mdescr = ma.make_mask_descr(_dtype)
             _mask = narray([tuple([m] * len(mdescr)) for m in objmask],
                            dtype=mdescr).view(recarray)
     # Update some of the attributes
     _dict = self.__dict__
     _dict.update(_mask=_mask)
     self._update_from(obj)
     if _dict['_baseclass'] == ndarray:
         _dict['_baseclass'] = recarray
     return
Beispiel #10
0
def ImageRecalibrate(self, data, masks):
    'Needs a doc string'
    import ImageCalibrants as calFile
    print 'Image recalibration:'
    time0 = time.time()
    pixelSize = data['pixelSize']
    scalex = 1000. / pixelSize[0]
    scaley = 1000. / pixelSize[1]
    pixLimit = data['pixLimit']
    cutoff = data['cutoff']
    data['rings'] = []
    data['ellipses'] = []
    if not data['calibrant']:
        print 'no calibration material selected'
        return True
    skip = data['calibskip']
    dmin = data['calibdmin']
    Bravais, SGs, Cells = calFile.Calibrants[data['calibrant']][:3]
    HKL = []
    for bravais, sg, cell in zip(Bravais, SGs, Cells):
        A = G2lat.cell2A(cell)
        if sg:
            SGData = G2spc.SpcGroup(sg)[1]
            hkl = G2pwd.getHKLpeak(dmin, SGData, A)
            HKL += hkl
        else:
            hkl = G2lat.GenHBravais(dmin, bravais, A)
            HKL += hkl
    HKL = G2lat.sortHKLd(HKL, True, False)
    varyList = [item for item in data['varyList'] if data['varyList'][item]]
    parmDict = {
        'dist': data['distance'],
        'det-X': data['center'][0],
        'det-Y': data['center'][1],
        'tilt': data['tilt'],
        'phi': data['rotation'],
        'wave': data['wavelength'],
        'dep': data['DetDepth']
    }
    Found = False
    wave = data['wavelength']
    frame = masks['Frames']
    tam = ma.make_mask_none(self.ImageZ.shape)
    if frame:
        tam = ma.mask_or(tam, MakeFrameMask(data, frame))
    for iH, H in enumerate(HKL):
        if debug: print H
        dsp = H[3]
        tth = 2.0 * asind(wave / (2. * dsp))
        if tth + abs(data['tilt']) > 90.:
            print 'next line is a hyperbola - search stopped'
            break
        ellipse = GetEllipse(dsp, data)
        Ring = makeRing(dsp, ellipse, pixLimit, cutoff, scalex, scaley,
                        ma.array(self.ImageZ, mask=tam))
        if Ring:
            if iH >= skip:
                data['rings'].append(np.array(Ring))
            data['ellipses'].append(copy.deepcopy(ellipse + ('r', )))
            Found = True
        elif not Found:  #skipping inner rings, keep looking until ring found
            continue
        else:  #no more rings beyond edge of detector
            data['ellipses'].append([])
            continue


#            break
    rings = np.concatenate((data['rings']), axis=0)
    chisq = FitDetector(rings, varyList, parmDict)
    data['wavelength'] = parmDict['wave']
    data['distance'] = parmDict['dist']
    data['center'] = [parmDict['det-X'], parmDict['det-Y']]
    data['rotation'] = np.mod(parmDict['phi'], 360.0)
    data['tilt'] = parmDict['tilt']
    data['DetDepth'] = parmDict['dep']
    data['chisq'] = chisq
    N = len(data['ellipses'])
    data['ellipses'] = []  #clear away individual ellipse fits
    for H in HKL[:N]:
        ellipse = GetEllipse(H[3], data)
        data['ellipses'].append(copy.deepcopy(ellipse + ('b', )))
    print 'calibration time = ', time.time() - time0
    G2plt.PlotImage(self, newImage=True)
    return True
Beispiel #11
0
def ImageRecalibrate(self,data,masks):
    'Needs a doc string'
    import ImageCalibrants as calFile
    print 'Image recalibration:'
    time0 = time.time()
    pixelSize = data['pixelSize']
    scalex = 1000./pixelSize[0]
    scaley = 1000./pixelSize[1]
    pixLimit = data['pixLimit']
    cutoff = data['cutoff']
    data['rings'] = []
    data['ellipses'] = []
    if not data['calibrant']:
        print 'no calibration material selected'
        return True    
    skip = data['calibskip']
    dmin = data['calibdmin']
    Bravais,SGs,Cells = calFile.Calibrants[data['calibrant']][:3]
    HKL = []
    for bravais,sg,cell in zip(Bravais,SGs,Cells):
        A = G2lat.cell2A(cell)
        if sg:
            SGData = G2spc.SpcGroup(sg)[1]
            hkl = G2pwd.getHKLpeak(dmin,SGData,A)
            HKL += hkl
        else:
            hkl = G2lat.GenHBravais(dmin,bravais,A)
            HKL += hkl
    HKL = G2lat.sortHKLd(HKL,True,False)
    varyList = [item for item in data['varyList'] if data['varyList'][item]]
    parmDict = {'dist':data['distance'],'det-X':data['center'][0],'det-Y':data['center'][1],
        'tilt':data['tilt'],'phi':data['rotation'],'wave':data['wavelength'],'dep':data['DetDepth']}
    Found = False
    wave = data['wavelength']
    frame = masks['Frames']
    tam = ma.make_mask_none(self.ImageZ.shape)
    if frame:
        tam = ma.mask_or(tam,MakeFrameMask(data,frame))
    for iH,H in enumerate(HKL):
        if debug:   print H 
        dsp = H[3]
        tth = 2.0*asind(wave/(2.*dsp))
        if tth+abs(data['tilt']) > 90.:
            print 'next line is a hyperbola - search stopped'
            break
        ellipse = GetEllipse(dsp,data)
        Ring = makeRing(dsp,ellipse,pixLimit,cutoff,scalex,scaley,ma.array(self.ImageZ,mask=tam))
        if Ring:
            if iH >= skip:
                data['rings'].append(np.array(Ring))
            data['ellipses'].append(copy.deepcopy(ellipse+('r',)))
            Found = True
        elif not Found:         #skipping inner rings, keep looking until ring found 
            continue
        else:                   #no more rings beyond edge of detector
            data['ellipses'].append([])
            continue
#            break
    rings = np.concatenate((data['rings']),axis=0)
    chisq = FitDetector(rings,varyList,parmDict)
    data['wavelength'] = parmDict['wave']
    data['distance'] = parmDict['dist']
    data['center'] = [parmDict['det-X'],parmDict['det-Y']]
    data['rotation'] = np.mod(parmDict['phi'],360.0)
    data['tilt'] = parmDict['tilt']
    data['DetDepth'] = parmDict['dep']
    data['chisq'] = chisq
    N = len(data['ellipses'])
    data['ellipses'] = []           #clear away individual ellipse fits
    for H in HKL[:N]:
        ellipse = GetEllipse(H[3],data)
        data['ellipses'].append(copy.deepcopy(ellipse+('b',)))    
    print 'calibration time = ',time.time()-time0
    G2plt.PlotImage(self,newImage=True)        
    return True
Beispiel #12
0
def find_bad_pixels(files, hot_threshold=np.inf, var_factor=5.0, chipgaps=False, read_fun=read_cbf):
    """Return a mask where pixels determined as dead or hot are masked."""

    # Reject pixel if the sum of this pixel in all frames is less than this
    dead_threshold = 1
    # Reject if ratio of pixel value to median filtered value exceeds this
    # in all frames
    medfilt_var_const = 3.0
    # Reject if ratio of pixel value to median filtered value exceeds this
    # even in a single frame
    medfilt_var_gross = 6.0
    # Curvature threshold above which deviates from median are not rejected
    laplace_threshold = 500.0


    # Laplace operator with diagonals, see
    # http://en.wikipedia.org/wiki/Discrete_Laplace_operator
    laplace = np.ones((3,3), dtype=np.float64)
    laplace[1,1] = -8.0

    f0 = read_fun(files[0])
    s = f0.im.shape
    modules = match_shape_to_pilatus(s)
    if modules is None:
        warnings.warn("Frame shape does not match any Pilatus. Not using a gap mask.")
        a_gaps = np.zeros(s, dtype=np.bool)
    else:
        a_gaps = np.logical_not(pilatus_gapmask(modules, chipgaps=chipgaps))
    # Boolean arrays of various invalid pixels (logical_not of a mask!)
    # Pixels above hot_threshold
    a_hots = ma.make_mask_none((s[0], s[1]))
    # Pixels always deviating from median filtered
    a_medf = np.ones((s[0], s[1]), dtype=np.bool)
    # Pixels grossly deviating from median filtered, even in a single frame
    a_gross = np.zeros((s[0], s[1]), dtype=np.bool)

    Asum = np.zeros((s[0], s[1]), dtype=np.float64)
    Asumsq = np.zeros((s[0], s[1]), dtype=np.float64)
    for i in range(0,len(files)):
        print(files[i])
        tim = (read_fun(files[i])).im.astype(np.float64)
        Asum += tim
        Asumsq += tim**2.0
        a_hots = bool_add(a_hots, (tim > hot_threshold))
        mfilt = scipy.signal.medfilt2d(tim, kernel_size=5)
        # Pixels where curvature is less than threshold
        lapm = (np.abs(scipy.signal.convolve2d(mfilt, laplace, mode='same',
            boundary='symm')) < laplace_threshold)
        absdev = np.abs(tim - mfilt)
        # Pixels deviating somewhat from median, not in curved regions
        mrej = (medfilt_var_const < (absdev/(mfilt+1))) * lapm
        a_medf = a_medf * mrej
        # Pixels deviating grossly from median filtered
        a_gross = bool_add(a_gross, (medfilt_var_gross < (absdev/(mfilt+1))) * lapm)

    sA = Asum
    mA = Asum / float(len(files))
    Esq = Asumsq / float(len(files))
    vA = Esq - mA**2

    a_consts = bool_sub((vA == 0),  a_gaps)
#    a_randoms = ((var_factor*vA) > mA)
    a_randoms = False # Something strange with variance, disabling for now
    a_deads = bool_sub((sA < dead_threshold),  a_gaps)
    # total bads outside gaps
    a_bads = reduce(bool_add, [a_consts, a_randoms, a_hots, a_deads, a_medf, a_gross])

    print("Frame has %dx%d = %d pixels" % (s[0], s[1], s[0]*s[1]))
    print("%d invalid pixels in module gaps" % (np.sum(a_gaps)))
    nconsts = np.sum(a_consts)
    print("%d constant pixels outside gaps, %d are >= %d" % \
            (nconsts, (nconsts - np.sum(a_deads)), dead_threshold))
#    print("Found %d pixels with variance larger than %f * mean" % (np.sum(m_randoms), var_factor))
    print("%d hot (count > %e) pixels" % (np.sum(a_hots), hot_threshold))
    print("%d pixels consistently deviating from median" % (np.sum(a_medf)))
    print("%d pixels grossly deviating from median" % (np.sum(a_gross)))
    print("Total of %d bad pixels outside of gaps" % (np.sum(a_bads)))
    mask = np.ones((s[0], s[1]), dtype=np.bool)
    mask = bool_sub(mask, bool_add(a_bads, a_gaps))
    print("Mask has a total of %d bad pixels" % (np.sum(mask == False)))

    return mask
Beispiel #13
0
def press2alt(arg, P0=None, T0=None, missing=1e+20, invert=0):
    """Calculate elevation given pressure (or vice versa).

    Calculations are made assuming that the temperature distribution
    follows the 1976 Standard Atmosphere.  Technically the standard
    atmosphere defines temperature distribution as a function of
    geopotential altitude, and this routine actually calculates geo-
    potential altitude rather than geometric altitude.


    Method Positional Argument:
    * arg:  Numeric floating point vector of any shape and size, or a
      Numeric floating point scalar.  If invert=0 (the default), arg 
      is air pressure [hPa].  If invert=1, arg is elevation [m].


    Method Keyword Arguments:
    * P0:  Pressure [hPa] at the surface (altitude equals 0).  Numeric 
      floating point vector of same size and shape as arg or a scalar.
      Default of keyword is set to None, in which case the routine 
      uses the value of instance attribute sea_level_press (converted
      to hPa) from the AtmConst class.  Keyword value is used if the 
      keyword is set in the function call.  This keyword cannot have 
      any missing values.

    * T0:  Temperature [K] at the surface (altitude equals 0).  Numeric 
      floating point vector of same size and shape as arg or a scalar.  
      Default of keyword is set to None, in which case the routine uses 
      the value of instance attribute sea_level_temp from the AtmConst
      class.  Keyword value is used if the keyword is set in the func-
      tion call.  This keyword cannot have any missing values.

    * missing:  If arg has missing values, this is the missing value 
      value.  Floating point scalar.  Default is 1e+20.

    * invert:  If set to 1, function calculates pressure [hPa] from 
      altitude [m].  In that case, positional input variable arg is 
      altitude [m] and the output is pressure [hPa].  Default value of 
      invert=0, which means the function calculates altitude given 
      pressure.


    Output:
    * If invert=0 (the default), output is elevation [m] at each 
      element of arg, relative to the surface.  If invert=1, output
      is the air pressure [hPa].  Numeric floating point array of 
      the same size and shape as arg.

      If there are any missing values in output, those values are set 
      to the value in argument missing from the input.  If there are 
      missing values in the output due to math errors and missing is 
      set to None, output will fill those missing values with the MA 
      default value of 1e+20.


    References:
    * Carmichael, Ralph (2003):  "Definition of the 1976 Standard Atmo-
      sphere to 86 km," Public Domain Aeronautical Software (PDAS).
      URL:  http://www.pdas.com/coesa.htm.

    * Wallace, J. M., and P. V. Hobbs (1977): Atmospheric Science:
      An Introductory Survey.  San Diego, CA:  Academic Press, ISBN
      0-12-732950-1, pp. 60-61.


    Examples:

    (1) Calculating altitude given pressure:

    >>> from press2alt import press2alt
    >>> import Numeric as N
    >>> press = N.array([200., 350., 850., 1e+20, 50.])
    >>> alt = press2alt(press, missing=1e+20)
    >>> ['%.7g' % alt[i] for i in range(5)]
    ['11783.94', '8117.19', '1457.285', '1e+20', '20575.96']

    (2) Calculating pressure given altitude:

    >>> alt = N.array([0., 10000., 15000., 20000., 50000.])
    >>> press = press2alt(alt, missing=1e+20, invert=1)
    >>> ['%.7g' % press[i] for i in range(5)]
    ['1013.25', '264.3589', '120.443', '54.74718', '0.7593892']

    (3) Input is a Numeric floating point scalar, and using a keyword
        set surface pressure to a different scalar:

    >>> alt = press2alt(N.array(850.), P0=1000.)
    >>> ['%.7g' % alt[0]]
    ['1349.778']
    """
    import numpy.ma as MA
    import numpy as N
    from atmconst import AtmConst
    #from is_numeric_float import is_numeric_float

    #- Check input is of the correct type:

    #if is_numeric_float(arg) != 1:
    #    raise TypeError, "press2alt:  Arg not Numeric floating"

    #- Import general constants and set additional constants.  h1_std
    #  is the lower limit of the Standard Atmosphere layer geopoten-
    #  tial altitude [m], h2_std is the upper limit [m] of the layer,
    #  and dT/dh is the temperature gradient (i.e. negative of the
    #  lapse rate) [K/m]:

    const = AtmConst()

    h1_std = N.array([0., 11., 20., 32., 47., 51., 71.]) * 1000.
    h2_std = N.array(MA.concatenate([h1_std[1:], [84.852 * 1000.]]))
    dTdh_std = N.array([-6.5, 0.0, 1.0, 2.8, 0.0, -2.8, -2.0]) / 1000.

    #- Prep arrays for masked array calculation and set conditions
    #  at sea-level.  Pressures are in hPa and temperatures in K.
    #  Sea-level conditions arrays are same shape/size as P_or_z.
    #  If input argument is a scalar, make the local variable used
    #  for calculations a 1-element vector:

    if missing == None: P_or_z = MA.masked_array(arg)
    else: P_or_z = MA.masked_values(arg, missing, copy=0)

    if P_or_z.shape == ():
        P_or_z = MA.reshape(P_or_z, (1, ))

    if P0 == None:
        P0_use = MA.zeros(P_or_z.shape) \
               + (const.sea_level_press / 100.)
    else:
        P0_use = MA.zeros(P_or_z.shape) \
               + MA.masked_array(P0)

    if T0 == None:
        T0_use = MA.zeros(P_or_z.shape) \
               + const.sea_level_temp
    else:
        T0_use = MA.zeros(P_or_z.shape) \
               + MA.masked_array(T0)

    #- Calculate P and T for the boundaries of the 7 layers of the
    #  Standard Atmosphere for the given P0 and T0 (layer 0 goes from
    #  P0 to P1, layer 1 from P1 to P2, etc.).  These are given as
    #  8 element dictionaries P_std and T_std where the key is the
    #  location (P_std[0] is at the bottom of layer 0, P_std[1] is the
    #  top of layer 0 and bottom of layer 1, ... and P_std[7] is the
    #  top of layer 6).  Remember P_std and T_std are dictionaries but
    #  dTdh_std, h1_std, and h2_std are vectors:

    P_std = {0: P0_use}
    T_std = {0: T0_use}

    for i in range(len(h1_std)):
        P_std[i+1] = _pfromz_MA( h2_std[i], -dTdh_std[i] \
                               , P_std[i], T_std[i], h1_std[i] )
        T_std[i + 1] = T_std[i] + (dTdh_std[i] * (h2_std[i] - h1_std[i]))

    #- Test input is within Standard Atmosphere limits:

    if invert == 0:
        tmp = MA.where(P_or_z < P_std[len(h1_std)], 1, 0)
        if MA.sum(MA.ravel(tmp)) > 0:
            raise ValueError, "press2alt:  Pressure out-of-range"
    else:
        tmp = MA.where(P_or_z > MA.maximum(h2_std), 1, 0)
        if MA.sum(MA.ravel(tmp)) > 0:
            raise ValueError, "press2alt:  Altitude out-of-range"

    #- What layer number is each element of P_or_z in?

    P_or_z_layer = 0  #MA.zeros(P_or_z.shape)

    #if invert == 0:
    #    for i in range(len(h1_std)):
    #        tmp = MA.where( MA.logical_and( (P_or_z <= P_std[i]) \
    #                                      , (P_or_z >  P_std[i+1]) ) \
    #                      , i, 0 )
    #        P_or_z_layer += tmp
    #else:
    #    for i in range(len(h1_std)):
    #        tmp = MA.where( MA.logical_and( (P_or_z >= h1_std[i]) \
    #                                      , (P_or_z <  h2_std[i]) ) \
    #                      , i, 0 )
    #        P_or_z_layer += tmp

    #- Fill in the bottom-of-the-layer variables and the lapse rate
    #  for the layers that the levels are in.  The *_actual variables
    #  are the values of dTdh, P_bott, etc. for each element in the
    #  P_or_z_flat array:

    P_or_z_flat = MA.ravel(P_or_z)
    if P_or_z_flat.mask() == None:
        P_or_z_flat_mask = MA.make_mask_none(P_or_z_flat.shape)
    else:
        P_or_z_flat_mask = P_or_z_flat.mask()

    P_or_z_layer_flat = MA.ravel(P_or_z_layer)
    dTdh_actual = MA.zeros(P_or_z_flat.shape)
    P_bott_actual = MA.zeros(P_or_z_flat.shape)
    T_bott_actual = MA.zeros(P_or_z_flat.shape)
    z_bott_actual = MA.zeros(P_or_z_flat.shape)

    for i in xrange(MA.size(P_or_z_flat)):
        if P_or_z_flat_mask[i] != 1:
            layer_number = P_or_z_layer_flat[i]
            dTdh_actual[i] = dTdh_std[layer_number]
            P_bott_actual[i] = MA.ravel(P_std[layer_number])[i]
            T_bott_actual[i] = MA.ravel(T_std[layer_number])[i]
            z_bott_actual[i] = h1_std[layer_number]
        else:
            dTdh_actual[i] = MA.masked
            P_bott_actual[i] = MA.masked
            T_bott_actual[i] = MA.masked
            z_bott_actual[i] = MA.masked

    #- Calculate pressure/altitude from altitude/pressure (output is
    #  a flat array):

    if invert == 0:
        output = _zfromp_MA( P_or_z_flat, -dTdh_actual \
                           , P_bott_actual, T_bott_actual, z_bott_actual )
    else:
        output = _pfromz_MA( P_or_z_flat, -dTdh_actual \
                           , P_bott_actual, T_bott_actual, z_bott_actual )

    #- Return output as same shape as input positional argument:

    return MA.filled(MA.reshape(output, arg.shape), missing)
import numpy as np
import numpy.ma as ma

ma.make_mask_none((3, ))
dtype = np.dtype({'names': ['foo', 'bar'], 'formats': [np.float32, np.int]})

ma.make_mask_none((3, ), dtype=dtype)
Beispiel #15
0
def press2alt(arg, P0=None, T0=None, missing=1e+20, invert=0):
    """Calculate elevation given pressure (or vice versa).

    Calculations are made assuming that the temperature distribution
    follows the 1976 Standard Atmosphere.  Technically the standard
    atmosphere defines temperature distribution as a function of
    geopotential altitude, and this routine actually calculates geo-
    potential altitude rather than geometric altitude.


    Method Positional Argument:
    * arg:  Numeric floating point vector of any shape and size, or a
      Numeric floating point scalar.  If invert=0 (the default), arg 
      is air pressure [hPa].  If invert=1, arg is elevation [m].


    Method Keyword Arguments:
    * P0:  Pressure [hPa] at the surface (altitude equals 0).  Numeric 
      floating point vector of same size and shape as arg or a scalar.
      Default of keyword is set to None, in which case the routine 
      uses the value of instance attribute sea_level_press (converted
      to hPa) from the AtmConst class.  Keyword value is used if the 
      keyword is set in the function call.  This keyword cannot have 
      any missing values.

    * T0:  Temperature [K] at the surface (altitude equals 0).  Numeric 
      floating point vector of same size and shape as arg or a scalar.  
      Default of keyword is set to None, in which case the routine uses 
      the value of instance attribute sea_level_temp from the AtmConst
      class.  Keyword value is used if the keyword is set in the func-
      tion call.  This keyword cannot have any missing values.

    * missing:  If arg has missing values, this is the missing value 
      value.  Floating point scalar.  Default is 1e+20.

    * invert:  If set to 1, function calculates pressure [hPa] from 
      altitude [m].  In that case, positional input variable arg is 
      altitude [m] and the output is pressure [hPa].  Default value of 
      invert=0, which means the function calculates altitude given 
      pressure.


    Output:
    * If invert=0 (the default), output is elevation [m] at each 
      element of arg, relative to the surface.  If invert=1, output
      is the air pressure [hPa].  Numeric floating point array of 
      the same size and shape as arg.

      If there are any missing values in output, those values are set 
      to the value in argument missing from the input.  If there are 
      missing values in the output due to math errors and missing is 
      set to None, output will fill those missing values with the MA 
      default value of 1e+20.


    References:
    * Carmichael, Ralph (2003):  "Definition of the 1976 Standard Atmo-
      sphere to 86 km," Public Domain Aeronautical Software (PDAS).
      URL:  http://www.pdas.com/coesa.htm.

    * Wallace, J. M., and P. V. Hobbs (1977): Atmospheric Science:
      An Introductory Survey.  San Diego, CA:  Academic Press, ISBN
      0-12-732950-1, pp. 60-61.


    Examples:

    (1) Calculating altitude given pressure:

    >>> from press2alt import press2alt
    >>> import Numeric as N
    >>> press = N.array([200., 350., 850., 1e+20, 50.])
    >>> alt = press2alt(press, missing=1e+20)
    >>> ['%.7g' % alt[i] for i in range(5)]
    ['11783.94', '8117.19', '1457.285', '1e+20', '20575.96']

    (2) Calculating pressure given altitude:

    >>> alt = N.array([0., 10000., 15000., 20000., 50000.])
    >>> press = press2alt(alt, missing=1e+20, invert=1)
    >>> ['%.7g' % press[i] for i in range(5)]
    ['1013.25', '264.3589', '120.443', '54.74718', '0.7593892']

    (3) Input is a Numeric floating point scalar, and using a keyword
        set surface pressure to a different scalar:

    >>> alt = press2alt(N.array(850.), P0=1000.)
    >>> ['%.7g' % alt[0]]
    ['1349.778']
    """
    import numpy as N
    import numpy.ma as MA
    #jfp was import MA
    #jfp was import Numeric as N
    from atmconst import AtmConst
    from is_numeric_float import is_numeric_float


    #- Check input is of the correct type:

    if is_numeric_float(arg) != 1:
        raise TypeError, "press2alt:  Arg not Numeric floating"


    #- Import general constants and set additional constants.  h1_std
    #  is the lower limit of the Standard Atmosphere layer geopoten-
    #  tial altitude [m], h2_std is the upper limit [m] of the layer,
    #  and dT/dh is the temperature gradient (i.e. negative of the
    #  lapse rate) [K/m]:

    const = AtmConst()

    h1_std   = N.array([0., 11., 20., 32., 47., 51., 71.]) * 1000.
    h2_std   = N.array( MA.concatenate([h1_std[1:], [84.852*1000.]]) )
    dTdh_std = N.array([-6.5, 0.0, 1.0, 2.8, 0.0, -2.8, -2.0]) / 1000.


    #- Prep arrays for masked array calculation and set conditions
    #  at sea-level.  Pressures are in hPa and temperatures in K.
    #  Sea-level conditions arrays are same shape/size as P_or_z.
    #  If input argument is a scalar, make the local variable used
    #  for calculations a 1-element vector:

    if missing == None: P_or_z = MA.masked_array(arg)
    else:               P_or_z = MA.masked_values(arg, missing, copy=0)

    if P_or_z.shape == ():
        P_or_z = MA.reshape(P_or_z, (1,))

    if P0 == None:
        #jfp was P0_use = MA.zeros(P_or_z.shape, typecode=MA.Float) \
        P0_use = MA.zeros(P_or_z.shape) \
               + (const.sea_level_press / 100.)
    else:
        #jfp was P0_use = MA.zeros(P_or_z.shape, typecode=MA.Float) \
        P0_use = MA.zeros(P_or_z.shape) \
               + MA.masked_array(P0)

    if T0 == None:
        #jfp was T0_use = MA.zeros(P_or_z.shape, typecode=MA.Float) \
        T0_use = MA.zeros(P_or_z.shape) \
               + const.sea_level_temp
    else:
        #jfp was T0_use = MA.zeros(P_or_z.shape, typecode=MA.Float) \
        T0_use = MA.zeros(P_or_z.shape) \
               + MA.masked_array(T0)


    #- Calculate P and T for the boundaries of the 7 layers of the
    #  Standard Atmosphere for the given P0 and T0 (layer 0 goes from
    #  P0 to P1, layer 1 from P1 to P2, etc.).  These are given as
    #  8 element dictionaries P_std and T_std where the key is the
    #  location (P_std[0] is at the bottom of layer 0, P_std[1] is the
    #  top of layer 0 and bottom of layer 1, ... and P_std[7] is the
    #  top of layer 6).  Remember P_std and T_std are dictionaries but
    #  dTdh_std, h1_std, and h2_std are vectors:

    P_std = {0:P0_use}
    T_std = {0:T0_use}

    for i in range(len(h1_std)):
        P_std[i+1] = _pfromz_MA( h2_std[i], -dTdh_std[i] \
                               , P_std[i], T_std[i], h1_std[i] )
        T_std[i+1] = T_std[i] + ( dTdh_std[i] * (h2_std[i]-h1_std[i]) )

    #- Test input is within Standard Atmosphere limits:

    if invert == 0:
        tmp = MA.where(P_or_z < P_std[len(h1_std)], 1, 0)
        if MA.sum(MA.ravel(tmp)) > 0:
            raise ValueError, "press2alt:  Pressure out-of-range"
    else:
        tmp = MA.where(P_or_z > MA.maximum(h2_std), 1, 0)
        if MA.sum(MA.ravel(tmp)) > 0:
            raise ValueError, "press2alt:  Altitude out-of-range"


    #- What layer number is each element of P_or_z in?

    P_or_z_layer = MA.zeros(P_or_z.shape)

    if invert == 0:
        for i in range(len(h1_std)):
            tmp = MA.where( MA.logical_and( (P_or_z <= P_std[i]) \
                                          , (P_or_z >  P_std[i+1]) ) \
                          , i, 0 )
            P_or_z_layer += tmp
    else:
        for i in range(len(h1_std)):
            tmp = MA.where( MA.logical_and( (P_or_z >= h1_std[i]) \
                                          , (P_or_z <  h2_std[i]) ) \
                          , i, 0 )
            P_or_z_layer += tmp


    #- Fill in the bottom-of-the-layer variables and the lapse rate
    #  for the layers that the levels are in.  The *_actual variables 
    #  are the values of dTdh, P_bott, etc. for each element in the
    #  P_or_z_flat array:

    P_or_z_flat = MA.ravel(P_or_z)
    P_or_z_flat_mask = P_or_z_flat.mask
    if P_or_z_flat.mask==False:
        P_or_z_flat_mask = MA.make_mask_none(P_or_z_flat.shape)
    #jfp was:
    #if P_or_z_flat.mask() == None:
    #    P_or_z_flat_mask = MA.make_mask_none(P_or_z_flat.shape)
    #else:
    #    P_or_z_flat_mask = P_or_z_flat.mask()

    P_or_z_layer_flat = MA.ravel(P_or_z_layer)
    #jfp was dTdh_actual       = MA.zeros(P_or_z_flat.shape, typecode=MA.Float)
    #jfp was P_bott_actual     = MA.zeros(P_or_z_flat.shape, typecode=MA.Float)
    #jfp was T_bott_actual     = MA.zeros(P_or_z_flat.shape, typecode=MA.Float)
    #jfp was z_bott_actual     = MA.zeros(P_or_z_flat.shape, typecode=MA.Float)
    dTdh_actual       = MA.zeros(P_or_z_flat.shape)
    P_bott_actual     = MA.zeros(P_or_z_flat.shape)
    T_bott_actual     = MA.zeros(P_or_z_flat.shape)
    z_bott_actual     = MA.zeros(P_or_z_flat.shape)

    for i in xrange(MA.size(P_or_z_flat)):
        if P_or_z_flat_mask[i] != 1:
            layer_number     = P_or_z_layer_flat[i]
            dTdh_actual[i]   = dTdh_std[layer_number]
            P_bott_actual[i] = MA.ravel(P_std[layer_number])[i]
            T_bott_actual[i] = MA.ravel(T_std[layer_number])[i]
            z_bott_actual[i] = h1_std[layer_number]
        else:
            dTdh_actual[i]   = MA.masked
            P_bott_actual[i] = MA.masked
            T_bott_actual[i] = MA.masked
            z_bott_actual[i] = MA.masked


    #- Calculate pressure/altitude from altitude/pressure (output is
    #  a flat array):
    
    if invert == 0:
        output = _zfromp_MA( P_or_z_flat, -dTdh_actual \
                           , P_bott_actual, T_bott_actual, z_bott_actual )
    else:
        output = _pfromz_MA( P_or_z_flat, -dTdh_actual \
                           , P_bott_actual, T_bott_actual, z_bott_actual )


    #- Return output as same shape as input positional argument:

    return MA.filled( MA.reshape(output, arg.shape), missing )