修改python模块引用方式
这个提交包含在:
可执行文件
+370
@@ -0,0 +1,370 @@
|
||||
import numpy as np
|
||||
from scipy.interpolate import Akima1DInterpolator
|
||||
from scipy.optimize import curve_fit
|
||||
from netCDF4 import Dataset
|
||||
from ProfileDataType import Profile
|
||||
|
||||
'''
|
||||
************************************************************
|
||||
该模块用于从数据库中, 获取剖面信息
|
||||
************************************************************
|
||||
'''
|
||||
|
||||
# 时间段标识
|
||||
timeDict = {
|
||||
# 全年平均
|
||||
'Annual': '00',
|
||||
# 1-12月
|
||||
'January': '01',
|
||||
'February': '02',
|
||||
'March': '03',
|
||||
'April': '04',
|
||||
'May': '05',
|
||||
'June': '06',
|
||||
'July': '07',
|
||||
'August': '08',
|
||||
'September': '09',
|
||||
'October': '10',
|
||||
'November': '11',
|
||||
'December': '12',
|
||||
# 北半球四季
|
||||
'Winter': '13',
|
||||
'Spring': '14',
|
||||
'Summer': '15',
|
||||
'Autumn': '16'
|
||||
}
|
||||
|
||||
|
||||
# def MunkFormula(z, v1, epsilon, z1):
|
||||
# eta = 2*(z-z1)/z1
|
||||
# return v1*(1+epsilon*(np.exp(-eta)+eta-1))
|
||||
|
||||
def soundSpeed(tem, sal, dep):
|
||||
'''
|
||||
声速计算公式
|
||||
'''
|
||||
# C = 1449.2 + 4.6*T - 0.055*T^2 + 0.00029*T^3 + (1.34 - 0.01*T)(S-35) + 0.017*D
|
||||
# 式中:T为海⽔测点的温度,单位为℃;S为海⽔测点的盐度,单位为‰;D为海⽔测点的深度,单位为m。
|
||||
vel = 1449.2 + 4.6*tem - 0.055*tem*tem + 0.00029 * \
|
||||
tem*tem*tem + (1.34 - 0.01*tem) * \
|
||||
(sal-35.0) + 0.017*dep
|
||||
return vel
|
||||
|
||||
|
||||
class DataBase():
|
||||
"""
|
||||
获取数据库中的剖面信息
|
||||
"""
|
||||
|
||||
def __init__(self,ETOPO1Path,STpath):
|
||||
print(ETOPO1Path)
|
||||
# 打开ETOPO1数据
|
||||
fileETOPO1 = ETOPO1Path + '/ETOPO1_Bed_g_gmt4.nc'
|
||||
dataETOPO1 = Dataset(fileETOPO1)
|
||||
# 获取ETOPO1网格
|
||||
self.latGrid1 = dataETOPO1.variables['y'][:]
|
||||
self.lonGrid1 = dataETOPO1.variables['x'][:]
|
||||
# 获取海深数据
|
||||
self.botGrid = -dataETOPO1.variables['z'][:]
|
||||
self.STPath=STpath
|
||||
return
|
||||
|
||||
def clearVar(self):
|
||||
"""
|
||||
清空变量
|
||||
"""
|
||||
self.botDep = None
|
||||
self.salRawPf = None
|
||||
self.temRawPf = None
|
||||
self.velRawPf = None
|
||||
self.velInterpPf = None
|
||||
self.velExtPf = None
|
||||
self.velFullPf = None
|
||||
self.isValid = True
|
||||
return
|
||||
|
||||
def set_timePeriod(self, timeIndex):
|
||||
"""
|
||||
设置时间段
|
||||
"""
|
||||
timeIndex = '01'
|
||||
self.timeIndex = timeIndex
|
||||
# 打开WOA18数据
|
||||
fileWOA18sal = self.STPath + '/woa18_A5B7_s' + timeIndex + '_04.nc'
|
||||
fileWOA18tem = self.STPath + '/woa18_A5B7_t' + timeIndex + '_04.nc'
|
||||
dataWOA18Sal = Dataset(fileWOA18sal)
|
||||
dataWOA18Tem = Dataset(fileWOA18tem)
|
||||
# 获取WOA18网格
|
||||
self.latGrid2 = dataWOA18Sal.variables['lat'][:]
|
||||
self.lonGrid2 = dataWOA18Sal.variables['lon'][:]
|
||||
# 获取深度数据
|
||||
self.depthGrid = dataWOA18Sal.variables['depth'][:]
|
||||
# 获取盐度数据
|
||||
self.salGrid = np.squeeze(dataWOA18Sal.variables['s_an'][:])
|
||||
# 获取温度数据
|
||||
self.temGrid = np.squeeze(
|
||||
dataWOA18Tem.variables['t_an'][:])
|
||||
self.clearVar()
|
||||
return
|
||||
|
||||
def set_coord(self, lat, lon):
|
||||
"""
|
||||
设置坐标
|
||||
"""
|
||||
self.lat = lat
|
||||
self.lon = lon
|
||||
self.clearVar()
|
||||
return
|
||||
|
||||
def interpBilinear(self, latId, lonId, dataGrid, dataTpye):
|
||||
"""
|
||||
双线性插值
|
||||
"""
|
||||
latId0 = int(np.ceil(latId))
|
||||
lonId0 = int(np.ceil(lonId))
|
||||
a = latId - latId0
|
||||
b = lonId - lonId0
|
||||
if (dataTpye == 1):
|
||||
data0 = dataGrid[latId0, lonId0]
|
||||
data1 = dataGrid[latId0+1, lonId0]
|
||||
data2 = dataGrid[latId0+1, lonId0+1]
|
||||
data3 = dataGrid[latId0, lonId0+1]
|
||||
else:
|
||||
data0 = dataGrid[:, latId0, lonId0]
|
||||
data1 = dataGrid[:, latId0+1, lonId0]
|
||||
data2 = dataGrid[:, latId0+1, lonId0+1]
|
||||
data3 = dataGrid[:, latId0, lonId0+1]
|
||||
data01 = (1-a)*data0+a*data1
|
||||
data32 = (1-a)*data3+a*data2
|
||||
data = (1-b)*data01+b*data32
|
||||
return data
|
||||
|
||||
def normCoord(self, latGrid, lonGrid):
|
||||
"""
|
||||
坐标单位化
|
||||
"""
|
||||
lat0 = latGrid[0]
|
||||
lon0 = lonGrid[0]
|
||||
dlat = latGrid[1]-latGrid[0]
|
||||
dlon = lonGrid[1]-lonGrid[0]
|
||||
latId = (self.lat - lat0)/dlat
|
||||
lonId = (self.lon - lon0)/dlon
|
||||
return (latId, lonId)
|
||||
|
||||
def get_bottomDepth(self):
|
||||
"""
|
||||
获得海底深度
|
||||
"""
|
||||
if (self.botDep == None):
|
||||
# 单位化经纬度
|
||||
(latId, lonId) = self.normCoord(self.latGrid1, self.lonGrid1)
|
||||
# 获取网格点海深
|
||||
self.botDep = self.interpBilinear(latId, lonId, self.botGrid, 1)
|
||||
return self.botDep
|
||||
|
||||
def get_salRawProfile(self):
|
||||
"""
|
||||
获得原始盐度剖面
|
||||
"""
|
||||
if (self.salRawPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
# 单位化经纬度
|
||||
(latId, lonId) = self.normCoord(self.latGrid2, self.lonGrid2)
|
||||
# 获取盐度剖面信息
|
||||
sal = self.interpBilinear(latId, lonId, self.salGrid, 2)
|
||||
# 获取有效数据段
|
||||
dep = self.depthGrid[sal.mask == False]
|
||||
sal = sal[sal.mask == False]
|
||||
dep = dep.flatten()
|
||||
sal = sal.flatten()
|
||||
# 若为空,则为无效数据
|
||||
if sal.size <= 1:
|
||||
self.isValid = False
|
||||
# 剖面赋值
|
||||
salRawPf = Profile()
|
||||
salRawPf.set_data(dep, sal)
|
||||
salRawPf.set_coord(self.lat, self.lon)
|
||||
salRawPf.set_bottomDepth(botDep)
|
||||
self.salRawPf = salRawPf
|
||||
return self.salRawPf
|
||||
|
||||
def get_temRawProfile(self):
|
||||
"""
|
||||
获得原始温度剖面
|
||||
"""
|
||||
if (self.temRawPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
# 单位化经纬度
|
||||
(latId, lonId) = self.normCoord(self.latGrid2, self.lonGrid2)
|
||||
# 获取温度剖面信息
|
||||
tem = self.interpBilinear(latId, lonId, self.temGrid, 2)
|
||||
# 获取有效数据段
|
||||
dep = self.depthGrid[tem.mask == False]
|
||||
tem = tem[tem.mask == False]
|
||||
dep = dep.flatten()
|
||||
tem = tem.flatten()
|
||||
# 若为空,则为无效数据
|
||||
if tem.size <= 1:
|
||||
self.isValid = False
|
||||
# 剖面赋值
|
||||
temRawPf = Profile()
|
||||
temRawPf.set_data(dep, tem)
|
||||
temRawPf.set_coord(self.lat, self.lon)
|
||||
temRawPf.set_bottomDepth(botDep)
|
||||
self.temRawPf = temRawPf
|
||||
return self.temRawPf
|
||||
|
||||
def get_velRawProfile(self):
|
||||
"""
|
||||
获得原始声速剖面
|
||||
"""
|
||||
if (self.velRawPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
# 获取温盐深数据
|
||||
dep = self.get_salRawProfile().x
|
||||
sal = self.get_salRawProfile().y
|
||||
tem = self.get_temRawProfile().y
|
||||
# 计算声速
|
||||
if self.isValid == True:
|
||||
vel = soundSpeed(tem, sal, dep)
|
||||
else:
|
||||
dep = np.array([0])
|
||||
vel = np.array([0])
|
||||
# 剖面赋值
|
||||
velRawPf = Profile()
|
||||
velRawPf.set_data(dep, vel)
|
||||
velRawPf.set_coord(self.lat, self.lon)
|
||||
velRawPf.set_bottomDepth(botDep)
|
||||
self.velRawPf = velRawPf
|
||||
return self.velRawPf
|
||||
|
||||
def get_velInterpProfile(self):
|
||||
"""
|
||||
获得插值后的声速剖面
|
||||
将非等距离采样填充为深度间隔为1m的序列, 并应用Akima插值算法, 对数据进行插值
|
||||
"""
|
||||
if (self.velInterpPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
# 获得原始声速剖面数据
|
||||
dep = self.get_velRawProfile().x
|
||||
vel = self.get_velRawProfile().y
|
||||
if self.isValid == True:
|
||||
# 对剖面进行垂向插值处理,将非等距离采样填充为深度间隔为1m的序列
|
||||
depInterp = np.arange(0, dep[-1]+1, 1)
|
||||
# 应用Akima插值算法,对数据进行插值
|
||||
func = Akima1DInterpolator(dep, vel)
|
||||
velInterp = func(depInterp)
|
||||
else:
|
||||
depInterp = np.array([0])
|
||||
velInterp = np.array([0])
|
||||
# 剖面赋值
|
||||
velInterpPf = Profile()
|
||||
velInterpPf.set_data(depInterp, velInterp)
|
||||
velInterpPf.set_coord(self.lat, self.lon)
|
||||
velInterpPf.set_bottomDepth(botDep)
|
||||
self.velInterpPf = velInterpPf
|
||||
return self.velInterpPf
|
||||
|
||||
def get_velExtProfile(self):
|
||||
"""
|
||||
获得延拓后的声速剖面
|
||||
"""
|
||||
if (self.velExtPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
if self.isValid == True:
|
||||
# 获得原始声速剖面数据
|
||||
dep = self.get_velRawProfile().x
|
||||
vel = self.get_velRawProfile().y
|
||||
# 获得剖面最低处温盐值
|
||||
tem = self.get_temRawProfile().y[-1]
|
||||
sal = self.get_salRawProfile().y[-1]
|
||||
# 延拓部分深度序列
|
||||
depExt = np.arange(dep[-1]+1, botDep+1)
|
||||
# 按照声速公式延拓,假设温盐不变,仅深度变化
|
||||
velExt = soundSpeed(tem, sal, depExt)
|
||||
else:
|
||||
depExt = np.array([0])
|
||||
velExt = np.array([0])
|
||||
# 剖面赋值
|
||||
velExtPf = Profile()
|
||||
velExtPf.set_data(depExt, velExt)
|
||||
velExtPf.set_coord(self.lat, self.lon)
|
||||
velExtPf.set_bottomDepth(botDep)
|
||||
self.velExtPf = velExtPf
|
||||
return self.velExtPf
|
||||
|
||||
def get_velFullProfile(self):
|
||||
'''
|
||||
获得全海深声速剖面
|
||||
'''
|
||||
if (self.velFullPf == None):
|
||||
botDep = self.get_bottomDepth()
|
||||
if self.isValid == True:
|
||||
# 插值后的速度剖面
|
||||
depInterp = self.get_velInterpProfile().x
|
||||
velInterp = self.get_velInterpProfile().y
|
||||
# 延拓后的速度剖面
|
||||
depExt = self.get_velExtProfile().x
|
||||
velExt = self.get_velExtProfile().y
|
||||
# 全海深声速剖面
|
||||
depFull = np.concatenate((depInterp, depExt))
|
||||
velFull = np.concatenate((velInterp, velExt))
|
||||
else:
|
||||
depFull = np.array([0])
|
||||
velFull = np.array([0])
|
||||
# 剖面赋值
|
||||
velFullPf = Profile()
|
||||
velFullPf.set_data(depFull, velFull)
|
||||
velFullPf.set_coord(self.lat, self.lon)
|
||||
velFullPf.set_bottomDepth(botDep)
|
||||
self.velFullPf = velFullPf
|
||||
return self.velFullPf
|
||||
|
||||
def export_velFullProfile_txt(self, filePath):
|
||||
'''
|
||||
速度剖面导出txt文件
|
||||
'''
|
||||
velPf = self.get_velFullProfile()
|
||||
lat = velPf.lat
|
||||
lon = velPf.lon
|
||||
botDep = velPf.botDep
|
||||
dep = velPf.x
|
||||
vel = velPf.y
|
||||
# 导出文本
|
||||
line1 = 'lat[degree north], {0:>7.4f}, lon[degree east], {1:>7.4f}, BottomDepth[m], {2:>5.0f}\n'.format(
|
||||
lat, lon, botDep)
|
||||
line2 = 'depth[m], velocity[m/s]'
|
||||
np.savetxt(filePath, np.stack((dep, vel), -1),
|
||||
fmt='%.5e', delimiter=',', comments='', header=line1+line2)
|
||||
|
||||
def export_velFullProfile_nc(self, filePath):
|
||||
'''
|
||||
速度剖面导出nc文件
|
||||
'''
|
||||
velPf = self.get_velFullProfile()
|
||||
lat = velPf.lat
|
||||
lon = velPf.lon
|
||||
botDep = velPf.botDep
|
||||
dep = velPf.x
|
||||
vel = velPf.y
|
||||
|
||||
data = Dataset(filePath, 'w', format='NETCDF4')
|
||||
data.createDimension('lon', 1)
|
||||
data.createDimension('lat', 1)
|
||||
data.createDimension('botDep', 1)
|
||||
data.createDimension('dep', dep.size)
|
||||
data.createDimension('vel', vel.size)
|
||||
|
||||
data.createVariable('lon', 'f', ('lon'))
|
||||
data.createVariable('lat', 'f', ('lat'))
|
||||
data.createVariable('botDep', 'f', ('botDep'))
|
||||
data.createVariable('dep', 'f', ('dep'))
|
||||
data.createVariable('vel', 'f', ('vel'))
|
||||
|
||||
data.variables['lat'][:] = lat
|
||||
data.variables['lon'][:] = lon
|
||||
data.variables['botDep'][:] = botDep
|
||||
data.variables['dep'][:] = dep
|
||||
data.variables['vel'][:] = vel
|
||||
|
||||
data.close()
|
||||
在新工单中引用
屏蔽一个用户