microproduct/atmosphericDelay-C-SAR/AtmosphericDelayTool.py

499 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#
# 大气延迟校正工具计算
# 参考https://github.com/insarlab/PyAPS
#
import os
import numpy as np
import scipy.interpolate as si
import netCDF4 as Nc
import scipy.interpolate as intp
import scipy.integrate as intg
from tool.algorithm.image.ImageHandle import ImageHandler
from tqdm import tqdm
# 声明常数
constdict = {}
k1 = 0.776 #(K/Pa)
k2 = 0.716 #(K/Pa)
k3 = 3750 #(K^2.Pa)
g = 9.81 #(m/s^2)
Rd = 287.05 #(J/Kg/K)
Rv = 461.495 #(J/Kg/K)
mma = 29.97 #(g/mol)
mmH = 2.0158 #(g/mol)
mmO = 16.0 #(g/mol)
Rho = 1000.0 #(kg/m^3)
a1w = 611.21 # hPa
a3w = 17.502 #
a4w = 32.19 # K
a1i = 611.21 # hPa
a3i = 22.587 #
a4i = -0.7 # K
T3 = 273.16 # K
Ti = 250.16 # K
nhgt = 300 # Number of levels for interpolation (OLD 151)
minAlt = -200.0
maxAlt = 50000.0
minAltP = -200.0
def correct_single_ifgram(ifg_path, phas_path, cor_dis_file):
data=ImageHandler.get_band_array(ifg_path,1)
tropo=ImageHandler.get_band_array(phas_path,1)
data =tropo - np.angle(data)
return data
def createpha(master_pha,aux_pha,wavelen,out_pha_path):
pha=master_pha-aux_pha
#pha=pha*-4. * np.pi / float( wavelen)
ImageHandler.write_imgArray(out_pha_path,pha)
return pha
class ERA:
""" 用于存储从ear 解析得到的参数"""
def __init__(self) -> None:
# 定义计算变量
self.lon_array=None
self.lat_array=None
self.level=None
self.t=None
self.r=None
self.z=None
pass
def read_nc(self,nc_file,Extent=None,level_list=None):
"""
function: 从气象数据中读取数组
"""
try:
nc_data_obj = Nc.Dataset(nc_file)
inform = nc_data_obj.variables
lon_array = inform['longitude'][:] # lon数组
lat_array = inform['latitude'][:] # lat数组
n_lat = lat_array.shape[0] # 经线列数量
n_lon = lon_array.shape[0] # 纬线行数量
level=np.array(inform["level"]) # pressure level in m 压力面
t = np.array(inform["t"]) # temp--k (1,37,latitude,longitude)
r = np.array(inform["r"]) # relative_humidity--% (1,37,latitude,longitude)
z = np.array(inform["z"]) # Geopotential--m**2 s**-2 (1,37,latitude,longitude)
if not Extent is None:
min_lat,max_lat,min_lon,max_lon=Extent
mask_lon= (lon_array>=min_lon)&(lon_array<=max_lon)
mask_lat= (lat_array>=min_lat)&(lat_array<=max_lat)
mask_lon=np.where(mask_lon==1)[0]
mask_lat=np.where(mask_lat==1)[0]
lat_array=lat_array[mask_lat]
lon_array=lat_array[mask_lon]
t=t[:,:,mask_lat,:][:,:,:,mask_lon]
r=r[:,:,mask_lat,:][:,:,:,mask_lon]
z=z[:,:,mask_lat,:][:,:,:,mask_lon]
if not level_list is None:
mask_level=[]
for l_item in level_list:
mask_level.append(np.where(level==l_item)[0][0])
level=level[mask_level]
t=t[:,mask_level,:,:]
r=r[:,mask_level,:,:]
z=z[:,mask_level,:,:]
# 根据
self.level=level
self.lat_array=lat_array
self.lon_array=lon_array
self.r=r
self.t=t
self.z=z
# log_info("level:\n{}".format(str(self.level)))
# log_info("lat_array:\n{}".format(str(self.lat_array)))
# log_info("lon_array:\n{}".format(str(self.lon_array)))
# log_info("r:\n{}".format(str(self.r)))
# log_info("t:\n{}".format(str(self.t)))
# log_info("z:\n{}".format(str(self.z))) # (1,level,lat,lon)
except Exception as e :
print(e)
# log_err(e)
# log_info("="*50)
return True
class AtomZtdDelay:
def __init__(self,atomdelay_path) -> None:
self.init_var()
self.const_var()
self.output=atomdelay_path
pass
def const_var(self):
self.lvls = np.array([1, 2, 3, 5, 7, 10, 20, 30, 50, 70, 100, 125,
150, 175,200, 225, 250, 300, 350, 400, 450,
500, 550, 600, 650, 700, 750, 775, 800, 825,
850, 875, 900, 925, 950, 975, 1000])
self.nlvls = len(self.lvls)
self.hgtscale = ((maxAlt - minAlt) / nhgt) / 0.703
self.bufspc = 1.2
self.alpha = Rv / Rd
def set_waveLen(self,wvl):
self.wvl=wvl
def set_incidenceAngle(self,inc_path):
local_angle_array = ImageHandler.get_band_array(inc_path, 1) # 获取局部入射角
self.inc=local_angle_array
def init_var(self):
self.deley_all=None
self.Dry_delay=None
self.Wet_delay=None
self.lon_arr=None
self.lat_arr=None
self.Pi=None
self.Ti=None
self.Vi=None
self.hgt=None
self.lvls=None
self.gph=None
self.tmp=None
self.vpr=None
self.dout=None
def load_npy(self,output):
# 加载数据
# log_info("="*50)
# log_info("加载预处理结果")
# log_info("{}:{}".format(os.path.join(output,'deley_all.npy'),os.path.exists(os.path.join(output,'deley_all.npy'))))
# log_info("{}:{}".format(os.path.join(output,'Dry_delay.npy'),os.path.exists(os.path.join(output,'Dry_delay.npy'))))
# log_info("{}:{}".format(os.path.join(output,'Wet_delay.npy'),os.path.exists(os.path.join(output,'Wet_delay.npy'))))
# log_info("{}:{}".format(os.path.join(output,'lon_arr.npy'),os.path.exists(os.path.join(output,'lon_arr.npy'))))
# log_info("{}:{}".format(os.path.join(output,'lat_arr.npy'),os.path.exists(os.path.join(output,'lat_arr.npy'))))
# log_info("{}:{}".format(os.path.join(output,'Pi.npy'),os.path.exists(os.path.join(output,'Pi.npy'))))
# log_info("{}:{}".format(os.path.join(output,'Ti.npy'),os.path.exists(os.path.join(output,'Ti.npy'))))
# log_info("{}:{}".format(os.path.join(output,'Vi.npy'),os.path.exists(os.path.join(output,'Vi.npy'))))
# log_info("{}:{}".format(os.path.join(output,'hgt.npy'),os.path.exists(os.path.join(output,'hgt.npy'))))
# log_info("{}:{}".format(os.path.join(output,'lvls.npy'),os.path.exists(os.path.join(output,'lvls.npy'))))
# log_info("{}:{}".format(os.path.join(output,'gph.npy'),os.path.exists(os.path.join(output,'gph.npy'))))
# log_info("{}:{}".format(os.path.join(output,'tmp.npy'),os.path.exists(os.path.join(output,'tmp.npy'))))
# log_info("{}:{}".format(os.path.join(output,'vpr.npy'),os.path.exists(os.path.join(output,'vpr.npy'))))
# log_info("{}:{}".format(os.path.join(output,'dout.npy'),os.path.exists(os.path.join(output,'dout.npy'))))
# log_info("="*50)
self.deley_all=np.load(os.path.join(output,'deley_all.npy'))
self.Dry_delay=np.load(os.path.join(output,'Dry_delay.npy'))
self.Wet_delay=np.load(os.path.join(output,'Wet_delay.npy'))
self.lon_arr=np.load(os.path.join(output,'lon_arr.npy'))
self.lat_arr=np.load(os.path.join(output,'lat_arr.npy'))
self.Pi=np.load(os.path.join(output,'Pi.npy'))
self.Ti=np.load(os.path.join(output,'Ti.npy'))
self.Vi=np.load(os.path.join(output,'Vi.npy'))
self.hgt=np.load(os.path.join(output,'hgt.npy'))
self.lvls=np.load(os.path.join(output,'lvls.npy')).tolist()
self.gph=np.load(os.path.join(output,'gph.npy'))
self.tmp=np.load(os.path.join(output,'tmp.npy'))
self.vpr=np.load(os.path.join(output,'vpr.npy'))
self.dout=np.load(os.path.join(output,'dlosout.npy'))
self.pha=np.load(os.path.join(output,'pha.npy'))
def save(self):
# 保存成临时结果
ImageHandler.write_imgArray(os.path.join(self.output,'deley_all.tiff'),self.deley_all)
# np.save(os.path.join(self.output,'Dry_delay.npy'),self.Dry_delay)
# np.save(os.path.join(self.output,'Wet_delay.npy'),self.Wet_delay)
# np.save(os.path.join(self.output,'lon_arr.npy'),np.array(self.lon_arr))
# np.save(os.path.join(self.output,'lat_arr.npy'),np.array(self.lat_arr))
# np.save(os.path.join(self.output,'Pi.npy'),self.Pi)
# np.save(os.path.join(self.output,'Ti.npy'),self.Ti)
# np.save(os.path.join(self.output,'Vi.npy'),self.Vi)
# np.save(os.path.join(self.output,'hgt.npy'),self.hgt)
# np.save(os.path.join(self.output,'lvls.npy'),np.array(self.lvls))
# np.save(os.path.join(self.output,'gph.npy'),self.gph)
# np.save(os.path.join(self.output,'tmp.npy'),self.tmp)
# np.save(os.path.join(self.output,'vpr.npy'),self.vpr)
ImageHandler.write_imgArray(os.path.join(self.output,'dlosout.tiff'),self.dout) # ztd
ImageHandler.write_imgArray(os.path.join(self.output,'pha.tiff'),self.pha)
def get_dem(self,dem_path):
dem_array=ImageHandler.get_band_array(dem_path,1)
self.dem=dem_array
return True
def get_lon_lat(self,reflect_lon_path,reflect_lat_path):
lon_table=ImageHandler.get_band_array(reflect_lon_path,1)
lat_table=ImageHandler.get_band_array(reflect_lat_path,1)
self.lon=lon_table
self.lat=lat_table
return True
def get_delay(self):
# log_info("计算相位")
minAltp=-200.0
lon_arr=self.lon
lat_arr=self.lat
# 根据行列号
min_lon=lon_arr.min()-self.bufspc
max_lon=lon_arr.max()+self.bufspc
min_lat=lat_arr.min()-self.bufspc
max_lat=lat_arr.max()+self.bufspc
# WGS [-180,-90,180,90]
# dem
shp=lon_arr.shape
lon_arr=lon_arr.reshape(-1)
if min_lon<0 and max_lon>0:
lon_arr[np.where(lon_arr<0)]=lon_arr[np.where(lon_arr<0)]+360
lon_arr=lon_arr.reshape(shp)
self.ny,self.nx=self.dem.shape
dout = np.zeros((self.ny, self.nx), dtype=np.float32)
intp_1d = si.interp1d(self.hgt, self.deley_all, kind='cubic', axis=-1)
self.dem[np.isnan(self.dem)] = minAltp
self.dem[self.dem < minAltp] = minAltp
self.mask=np.ones(self.dem.shape)
minH = np.max([np.nanmin(self.dem), self.hgt.min()])
maxH = int(np.nanmax(self.dem)) + 100.
kh = np.arange(minH,maxH)
self.Delfn_1m = intp_1d(kh)
self.alti = kh
# no reshape
Lonu = self.lon_arr[0,:]
Latu = self.lat_arr[:,0]
linearint = si.RegularGridInterpolator(
(Latu[::-1], Lonu,kh),
self.Delfn_1m[::-1,:,:],
method='linear',
bounds_error=False,
fill_value=0.0,
)
wvl=self.wvl
# Loop on the lines
pha=dout.copy()
# log_info("计算延迟值")
for m in tqdm(range(self.ny)):
# Get latitude and longitude arrays
lati = self.lat[m,:]*self.mask[m,:]
loni = self.lon[m,:]*self.mask[m,:]
# Remove negative values
# Remove NaN values
ii = np.where(np.isnan(lati))
jj = np.where(np.isnan(loni))
xx = np.union1d(ii,jj)
lati[xx]=0.0
loni[xx]=0.0
cinc = np.cos(self.inc[m,:]*np.pi/180.)
# Make the bilinear interpolation
D = self.dem[m,:]
val = linearint(np.vstack((lati, loni, D)).T)
val[xx] = np.nan
# save output
dout[m,:] = val
pha[m,:]=val*np.pi*4.0/(cinc*wvl)
self.dout=dout
self.pha= -1*pha
return pha
pass
def get_deley_dlf(self,nc_file):
# log_info("计算延迟路径")
[lon_array,lat_array, lvls, gph,tmp,vpr]=self.get_ear5_nc(nc_file)
lon_array,lat_array=np.meshgrid(lon_array,lat_array)
hgt = np.linspace(minAltP, gph.max().round(), nhgt)
[Pi,Ti,Vi]=self.intP2H(lvls,hgt,gph,tmp,vpr)
[Dry_delay,Wet_delay] = self.PTV2del(Pi,Ti,Vi,hgt)
deley_all = Dry_delay+Wet_delay
# 保存结果
self.deley_all=deley_all
self.Dry_delay=Dry_delay
self.Wet_delay=Wet_delay
self.lon_arr=lon_array
self.lat_arr=lat_array
self.Pi=Pi
self.Ti=Ti
self.Vi=Vi
self.hgt=hgt
self.lvls=lvls
self.gph=gph # 高度
self.tmp=tmp # 温度
self.vpr=vpr # 湿度
return True
def get_ear5_nc(self,nc_file,Extent=None):
era= ERA()
era.read_nc(nc_file,Extent,self.lvls)
lvls=self.lvls*100 # 转为 绝对压力
nlvls=len(era.level)
nlat=len(era.lat_array)
nlon=len(era.lon_array)
# 逐层分析
gph=1.0*era.z[0,:,:,:]/g
tmp=era.t[0,:,:,:]
vpr=era.r[0,:,:,:]
for i in range(nlvls):
esat = self.cc_era(tmp[i,:,:])
vpr[i,:,:]=(vpr[i,:,:]/100.0)*esat
#
return era.lon_array,era.lat_array, lvls, gph,tmp,vpr
def intP2H(self,lvls,hgt,gph,tmp,vpr):
# Interpolate pressure, temperature and Humidity of hgt
#minAlt = minAlt #Hardcoded parameter. -200.0
maxAlt_2 = gph.max().round()
nlat = gph.shape[1] #Number of stations
nlon = gph.shape[2]
nhgt = len(hgt) #Number of height points
Presi = np.zeros((nlat,nlon,nhgt))
Tempi = np.zeros((nlat,nlon,nhgt))
Vpri = np.zeros((nlat,nlon,nhgt))
for i in range(nlat):
for j in range(nlon):
temp = gph[:,i,j] #Obtaining height values
hx = temp.copy()
sFlag = False
eFlag = False
#Add point at start
if (hx.min() > minAlt): # -200.0
sFlag = True
#changed from 1 to 0 (-1 should also work), CL
hx = np.concatenate((hx,[minAlt-1]),axis = 0)
#Add point at end
if (hx.max() < maxAlt_2):
eFlag = True
#changed from 1 to 0 (-1 should also work), CL
hx = np.concatenate(([maxAlt_2+1],hx),axis=0)
#Splines needs monotonically increasing.
hx = -hx
#Interpolating pressure values
hy = lvls.copy()
if (sFlag == True):
val = hy[-1] +(hx[-1] - hx[-2])* (hy[-1] - hy[-2])/(hx[-2]-hx[-3])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate((hy,[val]),axis=0)
if (eFlag == True):
val = hy[0] - (hx[0] - hx[1]) * (hy[0] - hy[1])/(hx[1]-hx[2])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate(([val],hy),axis=0)
tck = intp.interp1d(hx,hy,kind='cubic')
#Again negative for consistency with hx
temp = tck(-hgt)
Presi[i,j,:] = temp.copy()
del temp
#Interpolating temperature
temp = tmp[:,i,j]
hy = temp.copy()
if (sFlag == True):
val = hy[-1] +(hx[-1] - hx[-2])* (hy[-1] - hy[-2])/(hx[-2]-hx[-3])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate((hy,[val]),axis=0)
if (eFlag == True):
val = hy[0] - (hx[0] - hx[1]) * (hy[0] - hy[1])/(hx[1]-hx[2])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate(([val],hy),axis=0)
tck = intp.interp1d(hx,hy,kind='cubic')
temp = tck(-hgt)
Tempi[i,j,:] = temp.copy()
del temp
#Interpolating vapor pressure
temp = vpr[:,i,j]
hy = temp.copy()
if (sFlag == True):
val = hy[-1] +(hx[-1] - hx[-2])* (hy[-1] - hy[-2])/(hx[-2]-hx[-3])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate((hy,[val]),axis=0)
if (eFlag == True):
val = hy[0] - (hx[0] - hx[1]) * (hy[0] - hy[1])/(hx[1]-hx[2])
#changed from 1 to 0 (-1 should also work), CL
hy = np.concatenate(([val],hy),axis=0)
tck = intp.interp1d(hx,hy,kind='cubic')
temp = tck(-hgt)
Vpri[i,j,:] = temp.copy()
del temp
return Presi,Tempi,Vpri
def PTV2del(self,Presi,Tempi,Vpri,hgt):
'''Computes the delay function given Pressure, Temperature and Vapor pressure.
Args:
* Presi (np.ndarray) : Pressure at height levels.
* Tempi (np.ndarray) : Temperature at height levels.
* Vpri (np.ndarray) : Vapor pressure at height levels.
* hgt (np.ndarray) : Height levels.
* cdict (np.ndarray) : Dictionary of constants.
Returns:
* DDry2 (np.ndarray) : Dry component of atmospheric delay.
* DWet2 (np.ndarray) : Wet component of atmospheric delay.
.. note::
Computes refractive index at each altitude and integrates the delay using cumtrapz.'''
nhgt = len(hgt) #Number of height points
nlat = Presi.shape[0] #Number of stations
nlon = Presi.shape[1]
WonT = Vpri/Tempi
WonT2 = WonT/Tempi
#Dry delay
DDry2 = np.zeros((nlat,nlon,nhgt))
DDry2[:,:,:] = k1*Rd*(Presi[:,:,:] - Presi[:,:,-1][:,:,np.newaxis])*1.0e-6/g
#Wet delay
S1 = intg.cumtrapz(WonT,x=hgt,axis=-1)
val = 2*S1[:,:,-1]-S1[:,:,-2]
val = val[:,:,None]
S1 = np.concatenate((S1,val),axis=-1)
del WonT
S2 = intg.cumtrapz(WonT2,x=hgt,axis=-1)
val = 2*S2[:,:,-1]-S2[:,:,-2]
val = val[:,:,None]
S2 = np.concatenate((S2,val),axis=-1)
DWet2 = -1.0e-6*((k2-k1*Rd/Rv)*S1+k3*S2)
for i in range(nlat):
for j in range(nlon):
DWet2[i,j,:] = DWet2[i,j,:] - DWet2[i,j,-1]
return DDry2,DWet2
def cc_era(self,tmp):
shp=tmp.shape
tmp=tmp.reshape(-1)
esatw = a1w*np.exp(a3w*(tmp-T3)/(tmp-a4w))
esati = a1i*np.exp(a3i*(tmp-T3)/(tmp-a4i))
result = np.zeros(esati.shape)
mask_T3=tmp>=T3
mask_Ti=tmp<=Ti
mask_wgt=(mask_T3+mask_Ti)==0
mask_T3=np.where(mask_T3==1)
mask_Ti=np.where(mask_Ti==1)
mask_wgt=np.where(mask_wgt==1)
result[mask_T3]=esatw[mask_T3]
result[mask_Ti]=esati[mask_Ti]
result[mask_wgt]=esati[mask_wgt]+(esatw[mask_wgt]-esati[mask_wgt])*np.square((tmp[mask_wgt]-Ti)/(T3-Ti))
result=result.reshape(shp)
return result