update
This commit is contained in:
@ -16,13 +16,13 @@ class model_info_2d(object):
|
|||||||
dx : float = None,
|
dx : float = None,
|
||||||
dy : float = None,
|
dy : float = None,
|
||||||
lowerleft : list = None,
|
lowerleft : list = None,
|
||||||
center : list = None,
|
|
||||||
nt : int = None,
|
nt : int = None,
|
||||||
dt : float = None,
|
dt : float = None,
|
||||||
var_list : list = None,
|
var_list : list = None,
|
||||||
type : str = None,
|
type : str = None,
|
||||||
globe : ccrs.Globe = None,
|
globe : ccrs.Globe = None,
|
||||||
debug : int = 0,
|
debug : int = 0,
|
||||||
|
center : list = None,
|
||||||
rotate_deg : Union[int, float] = 0,
|
rotate_deg : Union[int, float] = 0,
|
||||||
rotate_poi : list = None,
|
rotate_poi : list = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -67,6 +67,11 @@ class model_info_2d(object):
|
|||||||
2024-12-18 10:11:55 Sola v0.0.6 增加了与墨卡托投影相关的计算内容
|
2024-12-18 10:11:55 Sola v0.0.6 增加了与墨卡托投影相关的计算内容
|
||||||
2025-04-06 16:39:26 Sola v0.0.7 增加提供网格中心坐标计算网格的功能(优先级低于左下角坐标)
|
2025-04-06 16:39:26 Sola v0.0.7 增加提供网格中心坐标计算网格的功能(优先级低于左下角坐标)
|
||||||
2025-04-06 16:45:22 Sola v0.0.8 增加坐标旋转功能
|
2025-04-06 16:45:22 Sola v0.0.8 增加坐标旋转功能
|
||||||
|
修改的关键在于:
|
||||||
|
1. 在将经纬度转化为网格的时候, 围绕中心对网格进行偏移旋转, 需要增加一步后处理
|
||||||
|
2. 在将网格转化为经纬度的时候, 需要先将输入的网格ID旋转回去, 再计算其经纬度
|
||||||
|
设计的网格旋转函数需要保证旋转前后中心位置不变,各网格相对位置不变即可
|
||||||
|
注意, 这里输入的左下角坐标与通过中心计算的左下角坐标均为旋转前的
|
||||||
测试记录:
|
测试记录:
|
||||||
2022-09-28 16:28:10 Sola v2 新的简化网格生成方法测试完成, 结果与旧版一致
|
2022-09-28 16:28:10 Sola v2 新的简化网格生成方法测试完成, 结果与旧版一致
|
||||||
2022-09-28 18:27:59 Sola v2 测试了使用proj_LC投影的相关方法, 网格与WRF一致
|
2022-09-28 18:27:59 Sola v2 测试了使用proj_LC投影的相关方法, 网格与WRF一致
|
||||||
@ -89,22 +94,29 @@ class model_info_2d(object):
|
|||||||
center_x, center_y = 0, 0
|
center_x, center_y = 0, 0
|
||||||
zero_lon, zero_lat = ccrs.PlateCarree().transform_point(
|
zero_lon, zero_lat = ccrs.PlateCarree().transform_point(
|
||||||
center_x-self.dx*(self.nx-1)/2, center_y-self.dy*(self.ny-1)/2, self.projection)
|
center_x-self.dx*(self.nx-1)/2, center_y-self.dy*(self.ny-1)/2, self.projection)
|
||||||
self.lowerleft = [zero_lon, zero_lat]
|
self.lowerleft = [zero_lon, zero_lat] # 旋转前的左下角坐标
|
||||||
else:
|
else:
|
||||||
if len(lowerleft) == 2:
|
if len(lowerleft) == 2:
|
||||||
self.lowerleft = lowerleft # 左下角坐标(经纬度)
|
self.lowerleft = lowerleft # 旋转前的左下角坐标(经纬度)
|
||||||
else:
|
else:
|
||||||
|
# 这是考虑输入的左下角坐标不是经纬度, 而是某个投影系下的坐标位置, 所以先将其转化为经纬度
|
||||||
zero_lon, zero_lat = ccrs.PlateCarree().transform_point(\
|
zero_lon, zero_lat = ccrs.PlateCarree().transform_point(\
|
||||||
lowerleft[0], lowerleft[1], lowerleft[2])
|
lowerleft[0], lowerleft[1], lowerleft[2])
|
||||||
self.lowerleft = [zero_lon, zero_lat]
|
self.lowerleft = [zero_lon, zero_lat] # 旋转前的左下角经纬度
|
||||||
self.lowerleft_projxy = self.projection.transform_point(
|
self.lowerleft_projxy = self.projection.transform_point(
|
||||||
self.lowerleft[0], self.lowerleft[1],
|
self.lowerleft[0], self.lowerleft[1],
|
||||||
ccrs.PlateCarree()
|
ccrs.PlateCarree()
|
||||||
) # 计算投影下的坐标
|
) # 计算投影下的xy坐标
|
||||||
self.rotate = 0 if rotate_deg is None else np.deg2rad(rotate_deg)
|
self.rotate = 0 if rotate_deg is None else np.deg2rad(rotate_deg) # 计算旋转的弧度(输入是角度)
|
||||||
if rotate_poi is None:
|
if rotate_poi is None:
|
||||||
self.rotate_poi_x, self.rotate_poi_y = 0, 0
|
# 如果没有给定围绕旋转的点位, 则围绕网格中心进行旋转, 注意这里是 (x, y), 而不是 (ix, iy)
|
||||||
|
# 注意需要考虑如果指定的网格中心和投影中心不一致的情况
|
||||||
|
if not center is None:
|
||||||
|
self.rotate_poi_x, self.rotate_poi_y = center_x, center_y
|
||||||
|
else:
|
||||||
|
self.rotate_poi_x, self.rotate_poi_y = self.lowerleft_projxy[0] + (self.nx - 1)*self.dx, self.lowerleft_projxy[1] + (self.ny - 1)*self.dy
|
||||||
else:
|
else:
|
||||||
|
# 如果
|
||||||
self.rotate_poi_x, self.rotate_poi_y = self.projection.transform_point(*rotate_poi, ccrs.PlateCarree())
|
self.rotate_poi_x, self.rotate_poi_y = self.projection.transform_point(*rotate_poi, ccrs.PlateCarree())
|
||||||
finally:
|
finally:
|
||||||
if debug > 0:
|
if debug > 0:
|
||||||
@ -116,6 +128,7 @@ class model_info_2d(object):
|
|||||||
2022-09-28 11:05:09 Sola 更新为识别传入的对象类型, 判断是否可迭代
|
2022-09-28 11:05:09 Sola 更新为识别传入的对象类型, 判断是否可迭代
|
||||||
2022-09-28 15:21:07 Sola 增加对proj是否包含相应方法的识别
|
2022-09-28 15:21:07 Sola 增加对proj是否包含相应方法的识别
|
||||||
2022-09-28 18:25:24 Sola 修正正常情况下未输出ix, iy的bug
|
2022-09-28 18:25:24 Sola 修正正常情况下未输出ix, iy的bug
|
||||||
|
2025-04-06 20:33:29 Sola 加入坐标旋转的判断
|
||||||
"""
|
"""
|
||||||
# 如果是可迭代对象, 则丢给对应的功能处理
|
# 如果是可迭代对象, 则丢给对应的功能处理
|
||||||
if hasattr(original_x, '__iter__'):
|
if hasattr(original_x, '__iter__'):
|
||||||
@ -132,10 +145,10 @@ class model_info_2d(object):
|
|||||||
# 调用proj的方法计算经纬度
|
# 调用proj的方法计算经纬度
|
||||||
ix, iy = self.projection.grid_id_float(lon, lat)
|
ix, iy = self.projection.grid_id_float(lon, lat)
|
||||||
else: # 如果投影方法本身不具备计算网格ID的方法, 那就手动计算网格
|
else: # 如果投影方法本身不具备计算网格ID的方法, 那就手动计算网格
|
||||||
x, y = self.projection.transform_point(
|
x, y = self.projection.transform_point(original_x, original_y, original_proj)
|
||||||
original_x, original_y, original_proj)
|
|
||||||
ix = (x - self.lowerleft_projxy[0])/self.dx
|
ix = (x - self.lowerleft_projxy[0])/self.dx
|
||||||
iy = (y - self.lowerleft_projxy[1])/self.dy
|
iy = (y - self.lowerleft_projxy[1])/self.dy
|
||||||
|
ix, iy = self.rotate_grid_revise(ix, iy)
|
||||||
return ix, iy
|
return ix, iy
|
||||||
|
|
||||||
def grid_id(self, original_x, original_y, original_proj=ccrs.PlateCarree()):
|
def grid_id(self, original_x, original_y, original_proj=ccrs.PlateCarree()):
|
||||||
@ -161,6 +174,7 @@ class model_info_2d(object):
|
|||||||
2022-09-28 16:40:27 Sola 增加将输入数组转化为numpy数组的功能, 防止传入列表
|
2022-09-28 16:40:27 Sola 增加将输入数组转化为numpy数组的功能, 防止传入列表
|
||||||
2022-10-19 18:52:25 Sola 修正了除错距离的bug
|
2022-10-19 18:52:25 Sola 修正了除错距离的bug
|
||||||
2023-03-18 15:39:06 Sola 在计算前, 先将数组展开到1维, 返回时折叠
|
2023-03-18 15:39:06 Sola 在计算前, 先将数组展开到1维, 返回时折叠
|
||||||
|
2025-04-06 20:33:12 Sola 加入坐标旋转的判断
|
||||||
注意事项:
|
注意事项:
|
||||||
当前存在一个bug, 输入的投影必须是cartopy的投影, 否则无法计算经纬度,
|
当前存在一个bug, 输入的投影必须是cartopy的投影, 否则无法计算经纬度,
|
||||||
但是是否有必要在自己写的proj中加入该功能? 需要考虑
|
但是是否有必要在自己写的proj中加入该功能? 需要考虑
|
||||||
@ -186,6 +200,7 @@ class model_info_2d(object):
|
|||||||
ix_array = ((ix_array - self.lowerleft_projxy[0])/ self.dx).T
|
ix_array = ((ix_array - self.lowerleft_projxy[0])/ self.dx).T
|
||||||
iy_array = ((iy_array - self.lowerleft_projxy[1])/ self.dy).T
|
iy_array = ((iy_array - self.lowerleft_projxy[1])/ self.dy).T
|
||||||
ix_array, iy_array = fold_array(ix_array, iy_array, shape)
|
ix_array, iy_array = fold_array(ix_array, iy_array, shape)
|
||||||
|
ix_array, iy_array = self.rotate_grid_revise(ix_array, iy_array)
|
||||||
return ix_array, iy_array
|
return ix_array, iy_array
|
||||||
|
|
||||||
def grid_ids(self, original_x_array, original_y_array,
|
def grid_ids(self, original_x_array, original_y_array,
|
||||||
@ -205,13 +220,16 @@ class model_info_2d(object):
|
|||||||
通过网格id获取经纬度坐标
|
通过网格id获取经纬度坐标
|
||||||
2022-09-28 16:03:27 Sola 增加判断传入的是数值还是数组的功能
|
2022-09-28 16:03:27 Sola 增加判断传入的是数值还是数组的功能
|
||||||
2022-09-28 16:05:07 Sola 增加判断proj是否有计算网格的功能
|
2022-09-28 16:05:07 Sola 增加判断proj是否有计算网格的功能
|
||||||
|
2025-04-06 20:32:55 Sola 加入坐标旋转的判断
|
||||||
"""
|
"""
|
||||||
if hasattr(ix, '__iter__'): # 如果传入的是可迭代对象, 则调用相应功能
|
if hasattr(ix, '__iter__'): # 如果传入的是可迭代对象, 则调用相应功能
|
||||||
lon, lat = self.grid_lonlats(ix, iy)
|
lon, lat = self.grid_lonlats(ix, iy)
|
||||||
else: # 如果不是, 则由本函数继续运算
|
else: # 如果不是, 则由本函数继续运算
|
||||||
|
ix, iy = self.rotate_grid(ix, iy)
|
||||||
if hasattr(self.projection, 'grid_lonlat'): # 如果投影本身可以计算
|
if hasattr(self.projection, 'grid_lonlat'): # 如果投影本身可以计算
|
||||||
lon, lat = self.projection.grid_lonlat(ix, iy) # 计算网格对应经纬度
|
lon, lat = self.projection.grid_lonlat(ix, iy) # 计算网格对应经纬度
|
||||||
else: # 如果投影不能根据网格ID计算经纬度, 则手动计算
|
else: # 如果投影不能根据网格ID计算经纬度, 则手动计算
|
||||||
|
# 这里则是根据网格计算了在给定投影下的坐标XY,然后将其转化为经纬度
|
||||||
x = self.lowerleft_projxy[0] + ix * self.dx
|
x = self.lowerleft_projxy[0] + ix * self.dx
|
||||||
y = self.lowerleft_projxy[1] + iy * self.dy
|
y = self.lowerleft_projxy[1] + iy * self.dy
|
||||||
lon, lat = ccrs.PlateCarree().transform_point(x, y, self.projection)
|
lon, lat = ccrs.PlateCarree().transform_point(x, y, self.projection)
|
||||||
@ -224,8 +242,10 @@ class model_info_2d(object):
|
|||||||
2022-09-28 16:08:38 Sola 简化原本的网格计算, 使用转置的方式代替判断返回数组长度
|
2022-09-28 16:08:38 Sola 简化原本的网格计算, 使用转置的方式代替判断返回数组长度
|
||||||
2022-09-28 16:40:27 Sola 增加将输入数组转化为numpy数组的功能, 防止传入列表
|
2022-09-28 16:40:27 Sola 增加将输入数组转化为numpy数组的功能, 防止传入列表
|
||||||
2023-03-18 15:39:06 Sola 在计算前, 先将数组展开到1维, 返回时折叠
|
2023-03-18 15:39:06 Sola 在计算前, 先将数组展开到1维, 返回时折叠
|
||||||
|
2025-04-06 20:33:56 Sola 加入坐标旋转的判断
|
||||||
"""
|
"""
|
||||||
ix_array, iy_array, shape = flat_array(np.array(ix_array), np.array(iy_array))
|
ix_array, iy_array, shape = flat_array(np.array(ix_array), np.array(iy_array))
|
||||||
|
ix_array, iy_array = self.rotate_grid(ix_array, iy_array)
|
||||||
if hasattr(self.projection, 'grid_lonlats'):
|
if hasattr(self.projection, 'grid_lonlats'):
|
||||||
lon_array, lat_array = self.projection.grid_lonlats(ix_array, iy_array)
|
lon_array, lat_array = self.projection.grid_lonlats(ix_array, iy_array)
|
||||||
else:
|
else:
|
||||||
@ -312,6 +332,8 @@ class model_info_2d(object):
|
|||||||
central_longitude=self.projection.stdlon,
|
central_longitude=self.projection.stdlon,
|
||||||
globe = self.globe
|
globe = self.globe
|
||||||
)
|
)
|
||||||
|
elif self.projection.__class__.__base__ is ccrs.Projection:
|
||||||
|
proj = self.projection
|
||||||
else:
|
else:
|
||||||
proj = ccrs.PlateCarree(globe = self.globe)
|
proj = ccrs.PlateCarree(globe = self.globe)
|
||||||
return proj
|
return proj
|
||||||
@ -334,7 +356,7 @@ class model_info_2d(object):
|
|||||||
"""
|
"""
|
||||||
if cx is None:
|
if cx is None:
|
||||||
cx, cy, dx, dy = self.nx/2, self.ny/2, self.nx/2, self.ny/2
|
cx, cy, dx, dy = self.nx/2, self.ny/2, self.nx/2, self.ny/2
|
||||||
XLON, XLAT = self.get_grid()
|
# XLON, XLAT = self.get_grid()
|
||||||
# ys, ye, xs, xe = np.floor(cy-dy), np.ceil(cy+dy), np.floor(cx-dx), np.ceil(cx+dx)
|
# ys, ye, xs, xe = np.floor(cy-dy), np.ceil(cy+dy), np.floor(cx-dx), np.ceil(cx+dx)
|
||||||
lon_start, _ = self.grid_lonlat(cx-dx*ratio, cy)
|
lon_start, _ = self.grid_lonlat(cx-dx*ratio, cy)
|
||||||
lon_end, _ = self.grid_lonlat(cx+dx*ratio, cy)
|
lon_end, _ = self.grid_lonlat(cx+dx*ratio, cy)
|
||||||
@ -356,14 +378,53 @@ class model_info_2d(object):
|
|||||||
def is_in_domain(self, origin_x, origin_y, use_float=False):
|
def is_in_domain(self, origin_x, origin_y, use_float=False):
|
||||||
"""
|
"""
|
||||||
用于判断坐标(经纬度)是否在模式网格范围内
|
用于判断坐标(经纬度)是否在模式网格范围内
|
||||||
|
Update:
|
||||||
|
2025-05-05 00:13:01 Sola 修正使用浮点数计算时的问题
|
||||||
"""
|
"""
|
||||||
if use_float:
|
if use_float:
|
||||||
ix, iy = self.grid_id_float(origin_x, origin_y)
|
ix, iy = self.grid_id_float(origin_x, origin_y)
|
||||||
else:
|
else:
|
||||||
ix, iy = self.grid_id(origin_x, origin_y)
|
ix, iy = self.grid_id(origin_x, origin_y)
|
||||||
result = (0 <= ix) & (ix < self.nx) & (0 <= iy) & (iy < self.ny)
|
result = (0 <= ix) & (ix <= self.nx - 1) & (0 <= iy) & (iy <= self.ny - 1)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def rotate_xy(self, x, y, rotate_rad=None):
|
||||||
|
rotate_rad = self.rotate if rotate_rad is None else rotate_rad
|
||||||
|
x_new, y_new = rotate_xy(x, y, self.rotate_poi_x, self.rotate_poi_y, rotate_rad)
|
||||||
|
return x_new, y_new
|
||||||
|
|
||||||
|
def rotate_xy_revise(self, x, y, rotate_rad=None):
|
||||||
|
rotate_rad = self.rotate if rotate_rad is None else rotate_rad
|
||||||
|
x_new, y_new = rotate_xy(x, y, self.rotate_poi_x, self.rotate_poi_y, -rotate_rad)
|
||||||
|
return x_new, y_new
|
||||||
|
|
||||||
|
def rotate_grid(self, ix, iy, rotate_rad=None):
|
||||||
|
rotate_rad = self.rotate if rotate_rad is None else rotate_rad
|
||||||
|
if np.sum(np.abs(rotate_rad % (np.pi*2)) > 1e-8):
|
||||||
|
x, y = self.lowerleft_projxy[0] + ix*self.dx, self.lowerleft_projxy[1] + iy*self.dy
|
||||||
|
x_new, y_new = self.rotate_xy(x, y, rotate_rad)
|
||||||
|
ix_new, iy_new = (x_new - self.lowerleft_projxy[0])/self.dx, (y_new - self.lowerleft_projxy[1])/self.dy
|
||||||
|
else:
|
||||||
|
ix_new, iy_new = ix, iy
|
||||||
|
return ix_new, iy_new
|
||||||
|
|
||||||
|
def rotate_grid_revise(self, ix, iy, rotate_rad=None):
|
||||||
|
rotate_rad = self.rotate if rotate_rad is None else rotate_rad
|
||||||
|
if np.sum(np.abs(rotate_rad % (np.pi*2)) > 1e-8):
|
||||||
|
x, y = self.lowerleft_projxy[0] + ix*self.dx, self.lowerleft_projxy[1] + iy*self.dy
|
||||||
|
x_new, y_new = self.rotate_xy_revise(x, y, rotate_rad)
|
||||||
|
ix_new, iy_new = (x_new - self.lowerleft_projxy[0])/self.dx, (y_new - self.lowerleft_projxy[1])/self.dy
|
||||||
|
else:
|
||||||
|
ix_new, iy_new = ix, iy
|
||||||
|
return ix_new, iy_new
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_xy(xx, yy, cx, cy, rad):
|
||||||
|
xx_offset = (xx - cx)*np.cos(rad) - (yy - cy)*np.sin(rad)
|
||||||
|
yy_offset = (xx - cx)*np.sin(rad) + (yy - cy)*np.cos(rad)
|
||||||
|
xx_new, yy_new = cx + xx_offset, cy + yy_offset
|
||||||
|
return xx_new, yy_new
|
||||||
|
|
||||||
def flat_array(
|
def flat_array(
|
||||||
x : np.ndarray,
|
x : np.ndarray,
|
||||||
y : np.ndarray
|
y : np.ndarray
|
||||||
@ -448,4 +509,4 @@ def from_ctl(file: str) -> model_info_2d:
|
|||||||
proj = proj_LC(dx=dx, dy=dy, truelat1=truelat1, truelat2=truelat2, lat1=lat1, lon1=lon1,
|
proj = proj_LC(dx=dx, dy=dy, truelat1=truelat1, truelat2=truelat2, lat1=lat1, lon1=lon1,
|
||||||
knowni=knowi, knownj=knowj, stdlon=stdlon, nx=nx, ny=ny)
|
knowni=knowi, knownj=knowj, stdlon=stdlon, nx=nx, ny=ny)
|
||||||
model = model_info_2d(proj=proj, nx=nx, ny=ny, dx=dx, dy=dy, lowerleft=proj.grid_lonlat(0, 0))
|
model = model_info_2d(proj=proj, nx=nx, ny=ny, dx=dx, dy=dy, lowerleft=proj.grid_lonlat(0, 0))
|
||||||
return model
|
return model
|
@ -297,6 +297,12 @@ class proj_MERC(proj_info):
|
|||||||
lon = (i - self.knowni) * np.rad2deg(self.dlon) + self.lon1
|
lon = (i - self.knowni) * np.rad2deg(self.dlon) + self.lon1
|
||||||
lon = (lon + 180) % 360 - 180
|
lon = (lon + 180) % 360 - 180
|
||||||
return lon, lat
|
return lon, lat
|
||||||
|
|
||||||
|
def transform_point(self, lon, lat, proj_useless=None):
|
||||||
|
"""返回对应经纬度坐标的网格坐标(m)"""
|
||||||
|
ix, iy = self.llij(lon, lat)
|
||||||
|
cx, cy = self.llij(self.stdlon, self.truelat1)
|
||||||
|
return (ix - cx) * self.dx, (iy - cy) * self.dy
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user