You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

412 lines
12 KiB
Python

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.

import numpy as np
import json, os, shutil, bisect, subprocess, sys, time
from geopy.distance import geodesic
from netCDF4 import Dataset
from osgeo import gdal
# 获取当前文件的父目录的绝对路径
current_dir = os.path.dirname(os.path.abspath(__file__))
# 获取父目录的绝对路径
parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir))
# 将父目录添加到 Python 模块搜索路径中
sys.path.append(parent_dir)
from Utils import utils as globalUtils
# 求2个数组的交集
def intersection(list1, list2):
set1 = set(list1)
set2 = set(list2)
return list(set1 & set2)
# 读取一个文件的内容,文件的格式是 “10,20,30.....”
def readValueListFromTxt(filePath):
valueList = []
with open(filePath, "r") as file:
for line in file:
value = [float(x) for x in line.split(",")]
valueList += value
return valueList
# 测试矩阵
def matriTest():
# 两个示例数组
array1 = [1, 2, 3]
array2 = [4, 5, 6]
# 将数组转换为NumPy数组
array1_np = np.array(array1)
array2_np = np.array(array2)
# 创建矩阵其中每一行分别是数组1和数组2
matrix = np.vstack((array1_np, array2_np))
print("Matrix:")
print(matrix)
pass
# 计算一个数组中与目标值差值绝对值最小的值
def calClosestValue(target, arrList: list):
# 定义数组和目标值
arr = np.array(arrList)
# 计算数组中每个元素与目标值的绝对差值
differences = np.abs(arr - target)
# 找到差值最小的元素的索引
minDifferenceIndex = np.argmin(differences)
# 获取差值最小的元素
closestValue = arr[minDifferenceIndex]
return closestValue
# 找到最近的值
def searchNearest(sourceList: list, computeList: list) -> list:
closestValueList = []
for v in sourceList:
closestValueList.append(calClosestValue(v, computeList))
return closestValueList
# 计算2个点的地理距离
def calDistance(pointA, pointB) -> float:
return geodesic(pointA, pointB).miles # 使用geodesic计算距离
# 读取nc文件内容
def readNC(ncFilePath: str):
print(os.getcwd())
print(ncFilePath)
# 打开 .nc 文件,'r 表示只读
ncData = Dataset(ncFilePath, "r")
# 查看文件的维度
print("Dimensions:", ncData.dimensions)
# 查看文件的变量
print("Variables:", list(ncData.variables.keys()))
# # 获取所有的变量名称
# variables = ncData.variables.keys()
# # 根据变量名称获取数据
longitude = ncData.variables["longitude"][:]
latitude = ncData.variables["latitude"][:]
print("longitude ", len(longitude))
print("latitude ", len(latitude))
print("tco3 ", len(ncData.variables["tco3"][:]))
print("tcw ", len(ncData.variables["tcw"][:]))
tco3Matrix = ncData.variables["tco3"][0]
# 是 721 个元素的数组
print(len(tco3Matrix))
# 每个元素是 1440 长度的数组
print(len(tco3Matrix[0]))
tcwMatrix = ncData.variables["tcw"][0]
# 是 721 个元素的数组
print(len(tcwMatrix[0]))
# 每个元素是 1440 长度的数组
print(len(tcwMatrix[0]))
# 获取特定变量的值
# variable_name = 'temperature'
# variable_values = nc_file.variables[variable_name][:] # 这里假设 'temperature' 是文件中的一个变量名
# 关闭 .nc 文件
ncData.close()
return list(longitude), list(latitude), tcwMatrix, tco3Matrix
# 读取tif文件内容
def readTif(tifFilePath: str):
dataset = gdal.Open(tifFilePath)
band = dataset.GetRasterBand(1)
if dataset is not None:
# 获取tif文件的投影和变换信息用于将像素位置转化为地理坐标
print("Projection: ", dataset.GetProjection())
geotransform = dataset.GetGeoTransform()
print("GeoTransform: ", geotransform)
# 对第一波段的数据进行读取(这里假定大气数据在第一波段)
band = dataset.GetRasterBand(1)
aodMatrix = band.ReadAsArray()
nrows, ncols = aodMatrix.shape
# 计算每一个像素对应的经纬度
longitude_left_upper = geotransform[0]
latitude_left_upper = geotransform[3]
# 纬度是-90 到 90
if latitude_left_upper > 90:
latitude_left_upper = 90
x_resolution = geotransform[1] # x像素分辨率
y_resolution = geotransform[5] # y像素分辨率这个值通常为负
# 根据左上角点坐标以及分辨率计算其他点坐标
lon_list = [longitude_left_upper + i * x_resolution for i in range(ncols)]
lat_list = [latitude_left_upper + i * y_resolution for i in range(nrows)]
print("lon_list", len(lon_list))
print("lat_list", len(lat_list))
# 在此可以根据计算得到的经纬度信息对大气数据进行处理
# 例如简单地输出数据的形状和基本统计信息
# print('Array shape: ', aodMatrix.shape)
# print('Min value: ', array.min())
# print('Max value: ', array.max())
# print('Mean value: ', array.mean())
return lon_list, lat_list, aodMatrix
else:
print("Could not open the tif file!")
pass
# 读取地表文件中的经纬度
def readSurfaceCoordinate(
latFilePath: str,
lonFilePath: str,
saFilePath: str,
szFilePath: str,
vaFilePath: str,
vzFilePath: str,
):
latList = readValueListFromTxt(latFilePath)
lonList = readValueListFromTxt(lonFilePath)
szList = readValueListFromTxt(szFilePath)
vzList = readValueListFromTxt(vzFilePath)
saList = readValueListFromTxt(saFilePath)
vaList = readValueListFromTxt(vaFilePath)
return lonList, latList, szList, vzList, saList, vaList
# 初始化输入参数文件
def initInputFiles(projectSurfaceDir: str, projectTOADir: str) -> bool:
# 地表的经纬度文件
surFileList = [
"input_surface.txt",
"Lat.txt",
"Lon.txt",
"SA.txt",
"SZ.txt",
"VA.txt",
"VZ.txt",
]
surFilePathList = [os.path.join(projectSurfaceDir, x) for x in surFileList]
# 大气的参数、nc和tif文件
toaFileList = ["input_toa.txt", "input.nc", "input.tif"]
toaFilePathList = [os.path.join(projectTOADir, x) for x in toaFileList]
# 判断这些文件是否存在如果有1个不存在进行报错
allInputFileList = surFilePathList + toaFilePathList
for inputFile in allInputFileList:
if not os.path.exists(inputFile):
print(f"{inputFile} is not exist!")
return False
# 本地input目录
inputDir = "input"
if not globalUtils.rmDir(inputDir):
return False
if not globalUtils.mkDir(inputDir):
return False
# 拷贝参数文件到目录下
for inputFile in allInputFileList:
if not globalUtils.copyFile(
inputFile, os.path.join(inputDir, os.path.basename(inputFile))
):
return False
return True
# 获取target在arr中的最接近左值和右值arr是正序排序
def getLRValue(target, arr: list):
# 使用bisect_left找到该数值应当插入的位置以维持有序
index = bisect.bisect_left(arr, target)
# 左邻近值
leftValue = arr[index - 1] if index > 0 else None
# 右邻近值
rightValue = arr[index] if index < len(arr) else None
return leftValue, rightValue
# 获取一个点在网格中的最接近点(网格的顶点)
# 注意左值和右值可能是None
def getNearestPoint(targetPoint, lonList, latList):
lonList = sorted([x for x in lonList if x is not None])
latList = sorted([x for x in latList if x is not None])
pointList = [(lat, lon) for lat in latList for lon in lonList]
# print(pointList)
if len(pointList) == 0:
return None, None
minPoint = None
minDistance = None
for point in pointList:
# print(targetPoint, point)
distance = calDistance(targetPoint, point)
if not minDistance or distance < minDistance:
minDistance = distance
minPoint = point
return minPoint, minDistance
def readInputSurface(inputSurfaceFilePath: str):
# 打开文件
with open(inputSurfaceFilePath, "r") as file:
# 使用readlines()方法读取所有行并将结果存储在lines列表中
lines = file.readlines()
# 检查文件是否至少有两行
if len(lines) >= 2:
# 选择第二行索引为1
secondLine = lines[1]
splitList = secondLine.split(",")
if len(splitList) == 3:
month, wavestart, waveend = (int(x) for x in tuple(splitList))
# print("第二行内容:", secondLine)
# print(month, wavestart, waveend)
return month, wavestart, waveend
return None, None, None
# return month, wavestart, waveend
def readInputTOA(inputTOAFilePath: str):
# return aodmodel, atmodel
# 打开文件
with open(inputTOAFilePath, "r") as file:
# 使用readlines()方法读取所有行并将结果存储在lines列表中
lines = file.readlines()
# 检查文件是否至少有两行
if len(lines) >= 2:
# 选择第二行索引为1
secondLine = lines[1]
splitList = [x for x in secondLine.split(" ") if x.strip()]
print(splitList)
if len(splitList) == 2:
aodmodel, atmmodel = (int(x) for x in tuple(splitList))
# print("第二行内容:", secondLine)
# print(month, wavestart, waveend)
return aodmodel, atmmodel
return None, None
# 大气每次运行需要一个地表参数文件
def writeSurfaceInputFile(
filePath: str,
month: int,
lon: float,
lat: float,
sz: float,
vz: float,
sa: float,
va: float,
wavestart: int,
waveend: int,
):
with open(filePath, "w") as file:
file.write("month,lon,lat,sz,vz,sa,va,wavestart,waveend\n")
file.write(f"{month},{lon},{lat},{sz},{vz},{sa},{va},{wavestart},{waveend}")
return filePath
# 大气每次运行需要一个地表参数文件
def writeTOAInputFile(
filePath: str,
sz: float,
vz: float,
sa: float,
va: float,
wavestart: int,
waveend: int,
aodmodel: int,
atmmodel: int,
aod: float,
wv: float,
ozone: float,
inputpath: str,
):
with open(filePath, "w") as file:
file.write(
"sz vz sa va wavestart waveend aodmodel atmmodel aod wv ozone inputpath\n"
)
file.write(
f"{sz} {vz} {sa} {va} {wavestart} {waveend} {aodmodel} {atmmodel} {aod} {wv/10} {ozone} {inputpath}"
)
return filePath
# 执行一次求解
def executeCompute():
# 先删除旧的output.txt
globalUtils.rmPath("TOASimu.txt")
# 启动求解任务
# result = subprocess.run(['AllSensorSimu.exe'])
process = subprocess.Popen(["AllSensorSimu.exe"])
# 等待2秒后关闭
while 1:
time.sleep(10)
if globalUtils.isFileOpen("TOASimu.txt"):
# 正在被其它程序写入,所以等待
print("writting TOASimu.txt")
else:
if process.poll() is None: # 如果进程还在运行,就终止它
process.kill()
print("write TOASimu.txt over!")
break
# 将一个数组归一化,非排序的数组,每个值都缩小到 [0,1]
def normalized(valueList: list):
arr = np.array(valueList)
return (arr - np.min(arr)) / (np.max(arr) - np.min(arr))
# 每个元素包含3个值分别对应rgb三个颜色
# valueList: [(value445: float, value565: float, value670: float)]
def normalizedColor(valueList: list):
# 第1步归一化
value445NormalizedList = list(normalized([float(x[0]) for x in valueList]))
value565NormalizedList = list(normalized([float(x[1]) for x in valueList]))
value670NormalizedList = list(normalized([float(x[2]) for x in valueList]))
# print(value445NormalizedList)
# 第二步归一化的值转化为255的16进制
valueRList = [
hex(int(x * 255))[2:].zfill(2) if not np.isnan(x) else "ff"
for x in value445NormalizedList
]
# print(valueRList)
# print(hex(int(value445NormalizedList[0] * 255))[2:].zfill(2))
valueGList = [
hex(int(x * 255))[2:].zfill(2) if not np.isnan(x) else "ff"
for x in value565NormalizedList
]
valueBList = [
hex(int(x * 255))[2:].zfill(2) if not np.isnan(x) else "ff"
for x in value670NormalizedList
]
return ["#" + "".join(item) for item in zip(valueRList, valueGList, valueBList)]