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.

529 lines
20 KiB
Python

import configparser, sys, os, shutil
import main_utils as utils
import pyecharts.options as opts
from pyecharts.charts import Scatter
from pyecharts.charts import Geo
from pyecharts.faker import Faker
from pyecharts.globals import ChartType
from pyecharts.commons.utils import JsCode
import numpy as np
# 获取当前文件的父目录的绝对路径
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 SurfaceCharacteristicSimulation import main as surMain
from Utils import utils as globalUtils
inputDir = "input"
inputFileList = [
"input_surface.txt",
"input_toa.txt",
"input.nc",
"input.tif",
"Lat.txt",
"Lon.txt",
"SA.txt",
"SZ.txt",
"VA.txt",
"VZ.txt",
]
(
surInputFilePath,
toaInputFilePath,
ncFilePath,
tifFilePath,
surLatFilePath,
surLonFilePath,
surSAFilePath,
surSZFilePath,
surVAFilePath,
surVZFilePath,
) = [os.path.join(inputDir, x) for x in inputFileList]
# 读取配置文件
def readConfigure():
# 创建ConfigParser对象
config = configparser.ConfigParser()
# 读取配置文件
config.read("config.ini", encoding="utf-8")
# 获取配置项的值
lonProximityDistance = float(
config.get("ProximityRelation", "lonProximityDistance")
)
latProximityDistance = float(
config.getint("ProximityRelation", "latProximityDistance")
)
distanceProximityDistance = float(
config.get("ProximityRelation", "distanceProximityDistance")
)
taskNum = int(config.get("Task", "taskNum"))
if taskNum < 0:
taskNum = 0
return (
lonProximityDistance,
latProximityDistance,
distanceProximityDistance,
taskNum,
)
# 找到 surCoordinate 中的每个点s落到 nc文件坐标网格中的格子G并且确定s与G中距离最近的点
def surToNC(
ncLatList: list,
ncLonList: list,
surLatList: list,
surLonList: list,
distanceProximityDistance: float,
):
ncLatOrderList = sorted(ncLatList)
ncLonOrderList = sorted(ncLonList)
# 拿到nc中距离地表给的经纬度点中距离不超过100米的点
ncPointSelectedList = []
surPointSelectedList = []
for index, surLon in enumerate(surLonList):
# 地表配置中的1个点(surLon, surLat)
surLat = surLatList[index]
# 得到 lon 在nc中的最接近的 左值和右值
surLonLeftValue, surLonRightValue = utils.getLRValue(surLon, ncLonOrderList)
# 得到 lat 在nc中的最接近的 左值和右值
surLatLeftValue, surLatRightValue = utils.getLRValue(surLat, ncLatOrderList)
minPoint, minDistance = utils.getNearestPoint(
(surLat, surLon),
[surLonLeftValue, surLonRightValue],
[surLatLeftValue, surLatRightValue],
)
if minDistance is not None and minDistance < distanceProximityDistance:
surPointSelectedList.append((surLat, surLon))
ncPointSelectedList.append(minPoint)
return ncPointSelectedList, surPointSelectedList
# 找到nc和tif的对应关系
def ncToTif(
ncPointSelectedList: list,
surPointSelectedList: list,
tifLatList: list,
tifLonList: list,
distanceProximityDistance: float,
):
ncPointFinalSelectedList = []
tifPointFinalSelectedList = []
surPointFinalSelectedList = []
for index, point in enumerate(ncPointSelectedList):
ncLat, ncLon = point
# 得到 lon 在 tif 中的最接近的 左值和右值
tifLonLeftValue, tifLonRightValue = utils.getLRValue(ncLon, tifLonList)
# 得到 lat 在 tif 中的最接近的 左值和右值,注意
tifLatLeftValue, tifLatRightValue = utils.getLRValue(ncLat, sorted(tifLatList))
minPoint, minDistance = utils.getNearestPoint(
(ncLat, ncLon),
[tifLonLeftValue, tifLonRightValue],
[tifLatLeftValue, tifLatRightValue],
)
if minDistance is not None and minDistance < distanceProximityDistance:
ncPointFinalSelectedList.append(point)
surPointFinalSelectedList.append(surPointSelectedList[index])
tifPointFinalSelectedList.append(minPoint)
return (
ncPointFinalSelectedList,
tifPointFinalSelectedList,
surPointFinalSelectedList,
)
# 读取大气结果文件
def readTOAResult(filePath: str):
data = []
with open(filePath, "r", encoding="utf-8") as file:
lines = file.readlines()
for index, line in enumerate(lines):
if index == 0:
continue
data.append([float(x) for x in line.split(" ")])
return data
# 运行一次后,处理后处理的文件
def handleOutput(lon: float, lat: float, index: int):
# 地表的输入文件
surInputFile = "surfaceModule/input.txt"
# 地表的输出文件
surOutputFile = "surfaceModule/output.txt"
# 大气的输入文件
toaInputFile = "input_para.txt"
# 大气的输出文件
toaOutputFile = "TOASimu.txt"
# 如果目标不存在则创建
if not os.path.isdir("output"):
globalUtils.mkDir("output")
# 拷贝文件
shutil.copy(surInputFile, f"output/{index}_input_surface.txt")
shutil.copy(surOutputFile, f"output/{index}_output_surface.txt")
shutil.copy(toaInputFile, f"output/{index}_input_toa.txt")
shutil.copy(toaOutputFile, f"output/{index}_output_toa.txt")
# 生成散点图
data = readTOAResult(toaOutputFile)
data.sort(key=lambda x: x[0])
x_data = [d[0] for d in data]
y_data = [d[1] for d in data]
(
Scatter(init_opts=opts.InitOpts(width="100%", height="100%"))
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name="",
y_axis=y_data,
symbol_size=10,
label_opts=opts.LabelOpts(is_show=False),
)
.set_series_opts()
.set_global_opts(
xaxis_opts=opts.AxisOpts(
type_="value", splitline_opts=opts.SplitLineOpts(is_show=True)
),
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
# tooltip_opts=opts.TooltipOpts(is_show=False),
title_opts=opts.TitleOpts(title="TOA散点图"),
tooltip_opts=opts.TooltipOpts(
# trigger="item"
formatter=JsCode(
"function (params) {return params.value[0] + ' : ' + params.value[1];}"
)
),
)
.render(f"output/{index}_scatter_chart.html")
)
# 修改html支持全屏和自适应
with open(f"output/{index}_scatter_chart.html", "r") as file:
data = file.read()
# 设置全屏大小
data = data.replace(
"</head>",
"<style>html, body{width: 100%;height: 100%;margin:0px;}</style>\n</head>",
)
with open(f"output/{index}_scatter_chart.html", "w", encoding="utf-8") as file:
file.write(data)
# 返回坐标和rgb值对应关系
return generateCoordinateRGB(f"output/{index}_output_toa.txt")
# 生成一个坐标的热力图颜色,提取 445565670nm 三个数值,组成 RGB 图
def generateCoordinateRGB(outputFilePath: str):
rgbValueList = []
with open(outputFilePath, "r") as file:
lines = file.readlines()
for index, content in enumerate(lines):
if index == 0:
continue
valueList = content.split(" ")
band, toa = (float(x) for x in valueList)
if band == 0.445 or band == 0.565 or band == 0.67:
rgbValueList.append(toa)
return (x for x in rgbValueList)
# 画热力图
# valueList: [(value445: float, value565: float, value670: float)]
def renderReflectance(pointList: list, valueList: list):
# 构造热力图的values
# [(lon, lat), ......]
coordinates = pointList
# [100,200, ......]
# values = list(np.full(len(valueList), 0.5))
values = [(i + 1) * 100 for i in range(len(valueList))]
# [['Point 0', 100], ['Point 1', 200], ......]值都是1靠颜色去区分
dataPairs = [[f"Point {i}", (i + 1) * 100] for i in range(len(valueList))]
# 根据valueList生成color['#aabbcc', ......]
colors = utils.normalizedColor(valueList)
# 初始化
geo = Geo(init_opts=opts.InitOpts(width="100%", height="100%"))
# 添加点到地图上第一个参数是名称和dataPairs中对应后面2个是lon, lat
for index, coordinate in enumerate(coordinates):
geo.add_coordinate(f"Point {index}", coordinate[0], coordinate[1])
geo.add_schema(maptype="world")
geo.add(
"地理反射率图",
data_pair=dataPairs,
type_=ChartType.EFFECT_SCATTER,
)
geo.set_series_opts(
label_opts=opts.LabelOpts(is_show=False),
effect_opts=opts.EffectOpts(color=colors),
)
geo.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(values)), # 设置热力值范围
title_opts=opts.TitleOpts(title="地理反射率图"),
tooltip_opts=opts.TooltipOpts(
formatter=JsCode(
"function (params) {return params.value[0] + ' , ' + params.value[1];}"
)
),
)
htmlFilePath = "output/geo_reflectance.html"
# 渲染地图
geo.render(htmlFilePath)
# 修改html支持全屏和自适应
with open(htmlFilePath, "r") as file:
data = file.read()
# 设置全屏大小
data = data.replace(
"</head>",
"<style>html, body{width: 100%;height: 100%;margin:0px;}</style>\n</head>",
)
with open(htmlFilePath, "w", encoding="utf-8") as file:
file.write(data)
pass
# 读取坐标和数据,渲染热力图
def renderWorldReflectance():
pointList = []
valueList = []
with open("output/heatMapValueList.txt", "r") as file:
lines = file.readlines()
for line in lines:
values = [float(x) for x in line.split(" ")]
if len(values) == 5:
pointList.append((values[0], values[1]))
valueList.append((values[2], values[3], values[4]))
renderReflectance(pointList, valueList)
# 主函数
def main():
# renderWorldReflectance()
# return
# python main.py E:\Share\output\WorkingDir\test10\SurfaceCharacteristicSimulation E:\Share\output\WorkingDir\test10\AtmosphericRadiativeTransport
# python main.py E:\01-Projects\01-CAE-FullLink\output\workingDir\test06\SurfaceCharacteristicSimulation E:\01-Projects\01-CAE-FullLink\output\workingDir\test06\AtmosphericRadiativeTransport
# 第1个参数是 项目中地表模块的目录第2个参数是项目中大气模块的目录
# 从地表模块中读取参数文件包括input_surface.txt、Lat.txt、Lon.txt、SA.txt、SZ.txt、VA.txt、VZ.txt 复制到 input目录下
# 从大气模块中读取参数文件包括input_toa.txt、input.nc、input.tif到input目录下
projectSurfaceDir = sys.argv[1]
projectTOADir = sys.argv[2]
if not utils.initInputFiles(projectSurfaceDir, projectTOADir):
return
# 读取 地表参数文件input_surface.txt获取公共的参数month、wavestart、waveend
surMonth, surWavestart, surWaveend = utils.readInputSurface(surInputFilePath)
# 读取 大气参数文件input_toa.txt获取公共的参数aodmodel、atmodel
toaAodmodel, toaAtmmodel = utils.readInputTOA(toaInputFilePath)
globalUtils.printWithFlush(toaAodmodel, toaAtmmodel)
if None in [surMonth, surWavestart, surWaveend, toaAodmodel, toaAtmmodel]:
globalUtils.printWithFlush("surface: month wavestart waveend and toa: aodmodel atmodel has None!")
return
# 读取地表文件的经纬度
surLonList, surLatList, surSZList, surVZList, surSAList, surVAList = (
utils.readSurfaceCoordinate(
surLatFilePath,
surLonFilePath,
surSAFilePath,
surSZFilePath,
surVAFilePath,
surVZFilePath,
)
)
globalUtils.saveDataToJSON([float(x) for x in surLonList], "tmp/json-sur-lon.json")
globalUtils.saveDataToJSON([float(x) for x in surLatList], "tmp/json-sur-lat.json")
# 读取nc文件的经纬度、tcw和tco3
# ncLonList: 0 ~ 359.75,需要进行修正到 -180 ~ 180
# ncLatList: 90 ~ -90
ncLonList, ncLatList, tcwMatrix, tco3Matrix = utils.readNC(ncFilePath)
ncLonList = [float(x - 180) for x in ncLonList]
ncLatList = [float(x) for x in ncLatList]
globalUtils.saveDataToJSON([float(x) for x in ncLonList], "tmp/json-nc-lon.json")
globalUtils.saveDataToJSON([float(x) for x in ncLatList], "tmp/json-nc-lat.json")
# 读取配置文件
lonProximityDistance, latProximityDistance, distanceProximityDistance, taskNum = (
readConfigure()
)
# 第1步找到 surCoordinate 中的每个点s落到 nc文件坐标网格中的格子G并且确定s与G中距离最近的点
ncPointSelectedList, surPointSelectedList = surToNC(
ncLatList, ncLonList, surLatList, surLonList, distanceProximityDistance
)
# globalUtils.printWithFlush('nc points: ', len(ncPointSelectedList))
# globalUtils.printWithFlush('sur points: ', len(surPointSelectedList))
# globalUtils.saveDataToJSON([(float(x[0]), float(x[1])) for x in ncPointSelectedList],'json-nc-point.json')
# globalUtils.saveDataToJSON([(float(x[0]), float(x[1])) for x in surPointSelectedList], 'json-sur-point.json')
# 第4步计算 tif 文件中的点距离nc中点不超过100米的点
# tif的lon区间值范围应该在 -180 ~ 180可能有超过的范围需要修正一下
# tif的lat区间值范围应该在 90 ~ -90可能有超过的范围需要修正一下
tifLonList, tifLatList, aodMatrix = utils.readTif(tifFilePath)
tifLonList = [
-180 if x < -180 else 180 if x > 180 else float(x) for x in tifLonList
]
tifLatList = [-90 if x < -90 else 90 if x > 90 else float(x) for x in tifLatList]
# globalUtils.saveDataToJSON(tifLonList,'json-tif-lon.json')
# globalUtils.saveDataToJSON(tifLatList, 'json-tif-lat.json')
# nc中的点在tif的格子中最邻近的点
ncPointFinalSelectedList, tifPointFinalSelectedList, surPointFinalSelectedList = (
ncToTif(
ncPointSelectedList,
surPointSelectedList,
tifLatList,
tifLonList,
distanceProximityDistance,
)
)
# globalUtils.printWithFlush('nc final points: ', len(ncPointFinalSelectedList))
# globalUtils.printWithFlush('sur final points: ', len(surPointFinalSelectedList))
# globalUtils.printWithFlush('tif final points: ', len(tifPointFinalSelectedList))
# globalUtils.saveDataToJSON(surPointFinalSelectedList,'json-point-sur.json')
# globalUtils.saveDataToJSON(ncPointFinalSelectedList, 'json-point-nc.json')
# globalUtils.saveDataToJSON(tifPointFinalSelectedList, 'json-point-tif.json')
# 找出 surPointFinalSelectedList 中点对应的参数包括sz,vz,sa,va,wavestart,waveend
surParamValueList = []
for point in surPointFinalSelectedList:
lat, lon = point
# 找到lat在 surLatList 的位置,然后提取这个位置上的 sz,vz,sa,va
index = surLatList.index(lat)
surParamValueList.append(
(surSZList[index], surVZList[index], surSAList[index], surVAList[index])
)
# 找出 ncPointFinalSelectedList 中点 对应的 tcv水汽 和 tco3臭氧
# ncLonList, ncLatList, tcwMatrix, tco3Matrix
ncParamValueList = []
for index, point in enumerate(ncPointFinalSelectedList):
lat, lon = point
lonIndex = ncLonList.index(lon)
latIndex = ncLatList.index(lat)
ncParamValueList.append(
(tcwMatrix[latIndex][lonIndex], tco3Matrix[latIndex][lonIndex])
)
# 找出 tifPointFinalSelectedList 中点 对应的 aod大气光学厚度
# tifLonList,tifLatList,aodMatrix
tifParamValueList = []
for index, point in enumerate(tifPointFinalSelectedList):
lat, lon = point
lonIndex = tifLonList.index(lon)
latIndex = tifLatList.index(lat)
tifParamValueList.append(aodMatrix[latIndex][lonIndex])
globalUtils.printWithFlush(f"surParamValueList: {len(surParamValueList)}")
globalUtils.printWithFlush(f"ncParamValueList: {len(ncParamValueList)}")
globalUtils.printWithFlush(f"tifParamValueList: {len(tifParamValueList)}")
globalUtils.printWithFlush("pre process over!")
# 第一步,组成大气辐射需要的参数:
# sz vz sa va 来自 surParamValueList
# wavestart waveend 来自 地表的参数文件 ok
# aodmodel atmodel 来自 大气的参数文件 ok
# aod wv ozone 来自 ncParamValueList 和 tifParamValueList
# inputpath 根据第二步生成
surDir = "surfaceModule"
surfaceModuleDir = os.path.abspath("surfaceModule")
globalUtils.rmPath("output")
# 热力图数据准备
heatMapValueList = []
for index, surParamDict in enumerate(surParamValueList):
if index == taskNum:
break
sz, vz, sa, va = surParamDict
aod = tifParamValueList[index]
wv, ozone = ncParamValueList[index]
lat, lon = surPointFinalSelectedList[index]
globalUtils.rmDir(surDir)
globalUtils.mkDir(surDir)
# 生成大气参数文件中需要的地表参数文件
utils.writeSurfaceInputFile(
os.path.join(surDir, "input.txt"),
surMonth,
lon,
lat,
sz,
vz,
sa,
va,
surWavestart,
surWaveend,
)
globalUtils.printWithFlush("+++++++++++++++gen sur input.txt")
# 第一步,先执行地表,得到结果文件
surMain.test(surfaceModuleDir)
globalUtils.printWithFlush("+++++++++++++++surface run over")
# 第二步拷贝地表的结果文件到input下
surOutputFile = os.path.join(surfaceModuleDir, "output.txt")
globalUtils.printWithFlush(surOutputFile)
if not os.path.isfile(surOutputFile):
continue
# 第三步,构造大气辐射传输参数文件
utils.writeTOAInputFile(
"input_para.txt",
sz,
vz,
sa,
va,
surWavestart,
surWaveend,
toaAodmodel,
toaAtmmodel,
aod,
wv,
ozone,
surOutputFile,
)
globalUtils.printWithFlush("+++++++++++++++gen toa input.txt")
utils.executeCompute()
globalUtils.printWithFlush("+++++++++++++++toa run over")
# 处理结果文件将input_para.txt和TOASimu.txt进行编号命名后拷贝到output中
rgb445, rgb565, rgb670 = handleOutput(lon, lat, index)
heatMapValueList.append((lon, lat, rgb445, rgb565, rgb670))
# 将 heatMapValueList 保持到'output/heatMapValueList.txt'中
with open("output/heatMapValueList.txt", "w", encoding="utf-8") as file:
for arr in heatMapValueList:
file.write(" ".join([str(x) for x in arr]) + "\n")
# 制作热力图保存到output中
renderWorldReflectance()
# 将结果文件夹复制到大气项目目录下output目录下
projectOutputDir = os.path.join(projectTOADir, "output")
# 删除项目目录下旧的结果文件
globalUtils.rmPath(projectOutputDir)
# 将结果拷贝到目的目录
shutil.copytree("output", projectOutputDir)
return
if __name__ == "__main__":
try:
# 尝试执行的代码块
main()
except Exception as e:
# 捕获除了ZeroDivisionError外的所有异常
globalUtils.printWithFlush("发生异常:", str(e))
finally:
# 无论是否发生异常,最终都会执行该代码块
globalUtils.printWithFlush("求解执行完毕!")