wps的domain转为shp矢量

wps的namelist制作、python出图和转矢量

简介

wps(WRF Preprocessing System)是中尺度数值天气预报系统WRF(Weather Research and Forecasting)的预处理系统。

wrf模型示意图

wps的安装地址在GitHub上:https://github.com/wrf-model/WPS

下载完成后,就可以进行WPS安装,教程请查看官网:https://www2.mmm.ucar.edu/wrf/OnLineTutorial/compilation_tutorial.php

在wps安装成功后,会得到三个编译软件分别为geogrid、ungrib和metgrid。分别的功能是:

  • geogrid处理下垫面数据;

  • ungrib是将不同格式的气象数据转为统一格式

  • metgrid会将气象数据统一"裁剪"下垫面数据的网格上。

这三个exe文件的控制参数都是由namelist.wps进行控制的。

我今天想介绍的主要内容为根据namelist.input反推domain的空间位置并导出shp矢量,其他东西只会简单介绍。

namelist参数含义

不要去看汉化后的博客,官网有详细解释的:https://www2.mmm.ucar.edu/wrf/users/namelist_best_prac_wps.html#io_form_geogrid

由于我们要根据namelist.wps反推domain的空间分布,由几个特别重要的的参数,官网没有详细解释,我这里做一下补充:

(1)每一个domain都是由格网组成的,每层的格网大小由dxdyparent_grid_ratio决定。

请注意,e_wee_sn代表的是格的端点数,它们如果为n,则对应的格子数目为n-1,如图所示(e_we不会只有3,只是距离):

(2)e_we和e_sn都是指在该层范围内分辨率下的格子数目,比如304就是d02每行拥有303个格子。


(3)i_parent_start是经度的指标,一般用X表示,数字代表的子域d02左下角和d01的左下角的x方向的水平方向格子数。特别需要注意,

i_parent_start所代表的格子数量是d01的,不是d02。

j_parent_start是纬度的指标,一般用Y标识,是垂直方向的格子数

domain坐标计算的原理

(1)d01层的平面坐标计算

ref_lon,ref_lat是d01的中心位置,此外,它还有个特殊的作用:在wps中所有网格都是在一个投影的平面坐标系中的,(ref_lon,ref_lat)代表了在平面坐标系下的原点(0,0)。如果我们以d01举例,求它的四个顶点的坐标,我们需要明确,在兰伯特投影下的平面坐标系单位是米,d01的格子横向长度为dx,d01的格子纵向长度为dy。现在我们就可以求出d01的四个顶点在投影的平面坐标系下的坐标。

(2)d02、d03层的平面坐标计算

上面一步,我们已经求得了d01的四个顶点的坐标值。

d02的坐标,我们需要根据d01的左下角的坐标求得。

由此,我们获得了d02的四个顶点在投影下的平面坐标。

在获得d02的左下角坐标之后,按照相同方法,我们可以获得d03的平面坐标。

自此,我们明白了wps的namelist.wps的平面坐标计算原理,开始写代码。计算坐标点的代码如下:

# 初始化网格域
def initialize_domains(e_we, e_sn, i_parent_start, j_parent_start, parent_id, parent_grid_ratio, dx, dy, ref_lat, ref_lon, truelat1, truelat2):domains = []# 坐标系详细信息# 兰伯特 坐标系信息proj_params = {'proj': 'lcc','lat_1': truelat1,'lat_2': truelat2,'lat_0': ref_lat,'lon_0': ref_lon,'x_0': 0,'y_0': 0,'datum': 'WGS84'}# 创建平面坐标系p_lcc = Proj(proj_params)# 计算d01的中心点平面坐标系的坐标x_center, y_center = p_lcc(ref_lon, ref_lat)print("x_center, y_center",x_center, y_center)for i in range(len(e_we)):if parent_id[i] == 1:# 针对d01if i == 0:parent_dx = dxparent_dy = dyparent_ref_lon = x_centerparent_ref_lat = y_centergrid_ratio = parent_grid_ratio[i]# 计算d01的左下角坐标d01_start_x = x_center - ((e_we[i] - 1) / 2) * parent_dxd01_start_y = y_center - ((e_sn[i] - 1) / 2) * parent_dy# 计算d01的平面坐标domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx, dy, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d01_start_y, d01_start_x, grid_ratio))# 针对d02else:parent_domain_idx = parent_id[i] - 1grid_ratio = parent_grid_ratio[i]parent_dx = dxparent_dy = dydx = dx / grid_ratiody = dy / grid_ratioparent_ref_lat = domains[parent_domain_idx][2]parent_ref_lon = domains[parent_domain_idx][0]# 计算d02的左下角坐标d02_start_x = domains[parent_domain_idx][0] + (i_parent_start[i] - 1) * parent_dxd02_start_y = domains[parent_domain_idx][2] + (j_parent_start[i] - 1) * parent_dy# 计算d02的经纬度domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx, dy, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d02_start_y, d02_start_x, grid_ratio))else:# 针对d03parent_domain_idx = parent_id[i] - 1grid_ratio = parent_grid_ratio[i]parent_dx = domains[parent_domain_idx][6]parent_dy = domains[parent_domain_idx][7]parent_ref_lat = domains[parent_domain_idx][2]parent_ref_lon = domains[parent_domain_idx][0]# 计算d03的左下角坐标d03_start_x = domains[parent_domain_idx][0] + (i_parent_start[i] - 1) * parent_dxd03_start_y = domains[parent_domain_idx][2] + (j_parent_start[i] - 1) * parent_dy# 计算d03的经纬度domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx / grid_ratio, dy / grid_ratio, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d03_start_y, d03_start_x, grid_ratio))return domains, proj_params# 计算网格的边界
def compute_boundaries(ref_lat, ref_lon, e_we, e_sn, dx, dy, i_start, j_start, parent_dx, parent_dy, d_start_y, d_start_x, grid_ratio):# 计算子网格的左下角坐标grid_start_lon = d_start_xgrid_start_lat = d_start_y# 计算右上角坐标grid_end_lon = grid_start_lon + (e_we - 1) * dxgrid_end_lat = grid_start_lat + (e_sn - 1) * dy# 各方向的坐标west = grid_start_lonsouth = grid_start_lateast = grid_end_lonnorth = grid_end_latgrid_center_lat = (south + north) / 2grid_center_lon = (west + east) / 2return west, east, south, north, grid_center_lat, grid_center_lon, dx, dy

python出图

# 绘制地图
def plot_map(domains, gdf_level1, gdf_level2, gdf_level3, truelat1, truelat2, stand_lon, proj_params):proj = ccrs.LambertConformal(central_longitude=stand_lon, standard_parallels=(truelat1, truelat2))fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': proj})# 绘制shapefile背景gdf_level1.to_crs(proj).plot(ax=ax, edgecolor='blue', facecolor='none', linewidth=1)  # 蓝色边框,空心gdf_level2.to_crs(proj).plot(ax=ax, edgecolor='red', facecolor='none', linewidth=1)   # 红色边框,空心gdf_level3.to_crs(proj).plot(ax=ax, edgecolor='black', facecolor='#43A7EE', linewidth=1)  # 黑色边框,RGB(67,167,238)填充# 创建坐标系对象crs_wgs84 = CRS.from_epsg(4326)  # 使用 EPSG 代码 4326 表示 WGS84 地理坐标系crs_lcc = CRS(proj_params)transformer = Transformer.from_crs(crs_lcc, crs_wgs84, always_xy=True)# 绘制每个嵌套网格的范围for i, (west, east, south, north, _, _, _, _) in enumerate(domains):# 将网格边界转换为经纬度# 左下west_lon_ZUO, south_lat_ZUO = transformer.transform(west, south)# 左上west_lon_ZUO2, north_lat_ZUO2 = transformer.transform(west, north)# 右上east_lon_YOU2, north_lat_YOU2 = transformer.transform(east, north)# 右下east_lon_YOU, south_lat_YOU = transformer.transform(east, south)# 打印经纬度范围print(f"Domain {i+1} bounds (west, east, south, north):")print(f"Longitude: {west_lon_ZUO} to {east_lon_YOU2}")print(f"Latitude: {south_lat_ZUO} to {north_lat_ZUO2}")# 使用 Polygon 创建每个网格的多边形,按照逆时针顺序连接点vertices = [(west_lon_ZUO, south_lat_ZUO), (east_lon_YOU, south_lat_YOU), (east_lon_YOU2, north_lat_YOU2), (west_lon_ZUO2, north_lat_ZUO2)]polygon = Polygon(vertices)ax.add_geometries([polygon], crs=ccrs.PlateCarree(), edgecolor='red' if i == 0 else 'blue' if i == 1 else 'green', facecolor='none', linewidth=2, label=f'Domain {i+1}')# 计算标注的位置(使用多边形的右上角点)lon_label, lat_label = east_lon_YOU2, north_lat_YOU2# 添加标注,并调整标注的位置ax.text(lon_label, lat_label, f'd0{i+1}', color='red', fontsize=12, ha='right', va='top', transform=ccrs.PlateCarree())# 转换 d01 的边界坐标到地理坐标west_d01, south_d01 = transformer.transform(domains[0][0], domains[0][2])east_d01, north_d01 = transformer.transform(domains[0][1], domains[0][3])print("west_d01, south_d01, east_d01, north_d01", west_d01, south_d01, east_d01, north_d01)# 设置显示范围,在经度和纬度方向上各自添加边距lon_margin = (east_d01 - west_d01) * 0.1  # 经度方向上的边距为d01经度范围的10%lat_margin = (north_d01 - south_d01) * 0.1  # 纬度方向上的边距为d01纬度范围的10%ax.set_extent([west_d01 - lon_margin, east_d01 + lon_margin, south_d01 - lat_margin, north_d01 + lat_margin], crs=ccrs.PlateCarree())# 添加海岸线和网格线ax.gridlines(draw_labels=True)plt.title('WRF Domains')plt.show()

我们加入研究区的矢量如下,出图效果如下:

namelist转矢量shp

既然我们已经知道d01到d03的坐标点,按照逆时针把矢量点串联起来,获得shp矢量。

# 输出d01到d03范围为shp
def output_domains_to_shapefile(domains, proj_params, output_shapefile_path):# 创建一个空的 GeoDataFrame,用于存储域的范围gdf_domains = gpd.GeoDataFrame(columns=['geometry', 'domain_id'], crs="EPSG:4326")# 创建坐标系对象crs_wgs84 = CRS.from_epsg(4326)  # 使用 EPSG 代码 4326 表示 WGS84 地理坐标系crs_lcc = CRS(proj_params)transformer = Transformer.from_crs(crs_lcc, crs_wgs84, always_xy=True)# 绘制每个嵌套网格的范围并添加到 GeoDataFramefor i, (west, east, south, north, _, _, _, _) in enumerate(domains):# 将网格边界转换为经纬度# 左下west_lon_ZUO, south_lat_ZUO = transformer.transform(west, south)# 左上west_lon_ZUO2, north_lat_ZUO2 = transformer.transform(west, north)# 右上east_lon_YOU2, north_lat_YOU2 = transformer.transform(east, north)# 右下east_lon_YOU, south_lat_YOU = transformer.transform(east, south)# 使用 Polygon 创建每个网格的多边形,按照逆时针顺序连接点vertices = [(west_lon_ZUO, south_lat_ZUO), (east_lon_YOU, south_lat_YOU), (east_lon_YOU2, north_lat_YOU2), (west_lon_ZUO2, north_lat_ZUO2)]polygon = Polygon(vertices)# 创建一个临时的 GeoDataFrametemp_gdf = gpd.GeoDataFrame([{'geometry': polygon, 'domain_id': f'Domain {i+1}'}], crs="EPSG:4326")# 使用 pd.concat 将临时的 GeoDataFrame 添加到主要的 GeoDataFrame 中gdf_domains = pd.concat([gdf_domains, temp_gdf], ignore_index=True)# 保存为 shapefilegdf_domains.to_file(output_shapefile_path, driver='ESRI Shapefile')

特别注意,我们需要最后生成的shp是wgs84坐标系,所以需要把平面坐标转回为wgs84坐标系。

完整代码

import re
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import geopandas as gpd
import pandas as pd
from shapely.geometry import Polygon
from pyproj import Proj,transform
from pyproj import CRS, Transformer# 提取单个参数的函数
def get_param(pattern, content, index=0):match = re.search(pattern, content)if match:return float(match.group(1))else:raise ValueError(f'Parameter {pattern} not found in namelist.wps')# 提取多个参数的函数
def get_params(pattern, content):match = re.search(pattern, content)if match:return [int(x) for x in match.group(1).split(',')]else:raise ValueError(f'Parameter {pattern} not found in namelist.wps')# 读取并解析namelist.wps文件
def parse_namelist(namelist_path):with open(namelist_path, 'r') as file:namelist_content = file.read()dx = get_param(r'dx\s*=\s*(\d+)', namelist_content)dy = get_param(r'dy\s*=\s*(\d+)', namelist_content)ref_lat = get_param(r'ref_lat\s*=\s*([-+]?\d*\.\d+|\d+)', namelist_content)ref_lon = get_param(r'ref_lon\s*=\s*([-+]?\d*\.\d+|\d+)', namelist_content)e_we = get_params(r'e_we\s*=\s*([\d,\s]+)', namelist_content)e_sn = get_params(r'e_sn\s*=\s*([\d,\s]+)', namelist_content)i_parent_start = get_params(r'i_parent_start\s*=\s*([\d,\s]+)', namelist_content)j_parent_start = get_params(r'j_parent_start\s*=\s*([\d,\s]+)', namelist_content)parent_id = get_params(r'parent_id\s*=\s*([\d,\s]+)', namelist_content)parent_grid_ratio = get_params(r'parent_grid_ratio\s*=\s*([\d,\s]+)', namelist_content)truelat1 = get_param(r'truelat1\s*=\s*([-+]?\d*\.\d+|\d+)', namelist_content)truelat2 = get_param(r'truelat2\s*=\s*([-+]?\d*\.\d+|\d+)', namelist_content)stand_lon = get_param(r'stand_lon\s*=\s*([-+]?\d*\.\d+|\d+)', namelist_content)return dx, dy, ref_lat, ref_lon, e_we, e_sn, i_parent_start, j_parent_start, parent_id, parent_grid_ratio, truelat1, truelat2, stand_lon# 初始化网格域
def initialize_domains(e_we, e_sn, i_parent_start, j_parent_start, parent_id, parent_grid_ratio, dx, dy, ref_lat, ref_lon, truelat1, truelat2):domains = []# 坐标系详细信息# 兰伯特 坐标系信息proj_params = {'proj': 'lcc','lat_1': truelat1,'lat_2': truelat2,'lat_0': ref_lat,'lon_0': ref_lon,'x_0': 0,'y_0': 0,'datum': 'WGS84'}# 创建平面坐标系p_lcc = Proj(proj_params)# 计算d01的中心点平面坐标系的坐标x_center, y_center = p_lcc(ref_lon, ref_lat)print("x_center, y_center",x_center, y_center)for i in range(len(e_we)):if parent_id[i] == 1:# 针对d01if i == 0:parent_dx = dxparent_dy = dyparent_ref_lon = x_centerparent_ref_lat = y_centergrid_ratio = parent_grid_ratio[i]# 计算d01的左下角坐标d01_start_x = x_center - ((e_we[i] - 1) / 2) * parent_dxd01_start_y = y_center - ((e_sn[i] - 1) / 2) * parent_dy# 计算d01的平面坐标domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx, dy, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d01_start_y, d01_start_x, grid_ratio))# 针对d02else:parent_domain_idx = parent_id[i] - 1grid_ratio = parent_grid_ratio[i]parent_dx = dxparent_dy = dydx = dx / grid_ratiody = dy / grid_ratioparent_ref_lat = domains[parent_domain_idx][2]parent_ref_lon = domains[parent_domain_idx][0]# 计算d02的左下角坐标d02_start_x = domains[parent_domain_idx][0] + (i_parent_start[i] - 1) * parent_dxd02_start_y = domains[parent_domain_idx][2] + (j_parent_start[i] - 1) * parent_dy# 计算d02的经纬度domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx, dy, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d02_start_y, d02_start_x, grid_ratio))else:# 针对d03parent_domain_idx = parent_id[i] - 1grid_ratio = parent_grid_ratio[i]parent_dx = domains[parent_domain_idx][6]parent_dy = domains[parent_domain_idx][7]parent_ref_lat = domains[parent_domain_idx][2]parent_ref_lon = domains[parent_domain_idx][0]# 计算d03的左下角坐标d03_start_x = domains[parent_domain_idx][0] + (i_parent_start[i] - 1) * parent_dxd03_start_y = domains[parent_domain_idx][2] + (j_parent_start[i] - 1) * parent_dy# 计算d03的经纬度domains.append(compute_boundaries(parent_ref_lat, parent_ref_lon, e_we[i], e_sn[i], dx / grid_ratio, dy / grid_ratio, i_parent_start[i], j_parent_start[i], parent_dx, parent_dy, d03_start_y, d03_start_x, grid_ratio))return domains, proj_params# 计算网格的边界
def compute_boundaries(ref_lat, ref_lon, e_we, e_sn, dx, dy, i_start, j_start, parent_dx, parent_dy, d_start_y, d_start_x, grid_ratio):# 计算子网格的左下角坐标grid_start_lon = d_start_xgrid_start_lat = d_start_y# 计算右上角坐标grid_end_lon = grid_start_lon + (e_we - 1) * dxgrid_end_lat = grid_start_lat + (e_sn - 1) * dy# 各方向的坐标west = grid_start_lonsouth = grid_start_lateast = grid_end_lonnorth = grid_end_latgrid_center_lat = (south + north) / 2grid_center_lon = (west + east) / 2return west, east, south, north, grid_center_lat, grid_center_lon, dx, dy# 绘制地图
def plot_map(domains, gdf_level1, gdf_level2, gdf_level3, truelat1, truelat2, stand_lon, proj_params):proj = ccrs.LambertConformal(central_longitude=stand_lon, standard_parallels=(truelat1, truelat2))fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': proj})# 绘制shapefile背景gdf_level1.to_crs(proj).plot(ax=ax, edgecolor='blue', facecolor='none', linewidth=1)  # 蓝色边框,空心gdf_level2.to_crs(proj).plot(ax=ax, edgecolor='red', facecolor='none', linewidth=1)   # 红色边框,空心gdf_level3.to_crs(proj).plot(ax=ax, edgecolor='black', facecolor='#43A7EE', linewidth=1)  # 黑色边框,RGB(67,167,238)填充# 创建坐标系对象crs_wgs84 = CRS.from_epsg(4326)  # 使用 EPSG 代码 4326 表示 WGS84 地理坐标系crs_lcc = CRS(proj_params)transformer = Transformer.from_crs(crs_lcc, crs_wgs84, always_xy=True)# 绘制每个嵌套网格的范围for i, (west, east, south, north, _, _, _, _) in enumerate(domains):# 将网格边界转换为经纬度# 左下west_lon_ZUO, south_lat_ZUO = transformer.transform(west, south)# 左上west_lon_ZUO2, north_lat_ZUO2 = transformer.transform(west, north)# 右上east_lon_YOU2, north_lat_YOU2 = transformer.transform(east, north)# 右下east_lon_YOU, south_lat_YOU = transformer.transform(east, south)# 打印经纬度范围print(f"Domain {i+1} bounds (west, east, south, north):")print(f"Longitude: {west_lon_ZUO} to {east_lon_YOU2}")print(f"Latitude: {south_lat_ZUO} to {north_lat_ZUO2}")# 使用 Polygon 创建每个网格的多边形,按照逆时针顺序连接点vertices = [(west_lon_ZUO, south_lat_ZUO), (east_lon_YOU, south_lat_YOU), (east_lon_YOU2, north_lat_YOU2), (west_lon_ZUO2, north_lat_ZUO2)]polygon = Polygon(vertices)ax.add_geometries([polygon], crs=ccrs.PlateCarree(), edgecolor='red' if i == 0 else 'blue' if i == 1 else 'green', facecolor='none', linewidth=2, label=f'Domain {i+1}')# 计算标注的位置(使用多边形的右上角点)lon_label, lat_label = east_lon_YOU2, north_lat_YOU2# 添加标注,并调整标注的位置ax.text(lon_label, lat_label, f'd0{i+1}', color='red', fontsize=12, ha='right', va='top', transform=ccrs.PlateCarree())# 转换 d01 的边界坐标到地理坐标west_d01, south_d01 = transformer.transform(domains[0][0], domains[0][2])east_d01, north_d01 = transformer.transform(domains[0][1], domains[0][3])print("west_d01, south_d01, east_d01, north_d01", west_d01, south_d01, east_d01, north_d01)# 设置显示范围,在经度和纬度方向上各自添加边距lon_margin = (east_d01 - west_d01) * 0.1  # 经度方向上的边距为d01经度范围的10%lat_margin = (north_d01 - south_d01) * 0.1  # 纬度方向上的边距为d01纬度范围的10%ax.set_extent([west_d01 - lon_margin, east_d01 + lon_margin, south_d01 - lat_margin, north_d01 + lat_margin], crs=ccrs.PlateCarree())# 添加海岸线和网格线ax.gridlines(draw_labels=True)plt.title('WRF Domains')plt.show()# 输出d01到d03范围为shp
def output_domains_to_shapefile(domains, proj_params, output_shapefile_path):# 创建一个空的 GeoDataFrame,用于存储域的范围gdf_domains = gpd.GeoDataFrame(columns=['geometry', 'domain_id'], crs="EPSG:4326")# 创建坐标系对象crs_wgs84 = CRS.from_epsg(4326)  # 使用 EPSG 代码 4326 表示 WGS84 地理坐标系crs_lcc = CRS(proj_params)transformer = Transformer.from_crs(crs_lcc, crs_wgs84, always_xy=True)# 绘制每个嵌套网格的范围并添加到 GeoDataFramefor i, (west, east, south, north, _, _, _, _) in enumerate(domains):# 将网格边界转换为经纬度# 左下west_lon_ZUO, south_lat_ZUO = transformer.transform(west, south)# 左上west_lon_ZUO2, north_lat_ZUO2 = transformer.transform(west, north)# 右上east_lon_YOU2, north_lat_YOU2 = transformer.transform(east, north)# 右下east_lon_YOU, south_lat_YOU = transformer.transform(east, south)# 使用 Polygon 创建每个网格的多边形,按照逆时针顺序连接点vertices = [(west_lon_ZUO, south_lat_ZUO), (east_lon_YOU, south_lat_YOU), (east_lon_YOU2, north_lat_YOU2), (west_lon_ZUO2, north_lat_ZUO2)]polygon = Polygon(vertices)# 创建一个临时的 GeoDataFrametemp_gdf = gpd.GeoDataFrame([{'geometry': polygon, 'domain_id': f'Domain {i+1}'}], crs="EPSG:4326")# 使用 pd.concat 将临时的 GeoDataFrame 添加到主要的 GeoDataFrame 中gdf_domains = pd.concat([gdf_domains, temp_gdf], ignore_index=True)# 保存为 shapefilegdf_domains.to_file(output_shapefile_path, driver='ESRI Shapefile')def main():# 读取namelist.wps文件read_path = r"E:\ruiduobao\namelis设置\namelist.wps"dx, dy, ref_lat, ref_lon, e_we, e_sn, i_parent_start, j_parent_start, parent_id, parent_grid_ratio, truelat1, truelat2, stand_lon = parse_namelist(read_path)# 初始化网格域domains, proj_params = initialize_domains(e_we, e_sn, i_parent_start, j_parent_start, parent_id, parent_grid_ratio, dx, dy, ref_lat, ref_lon, truelat1, truelat2)# 读取shapefileshapefile_path_level1 = r'E:\ruiduobao\数据和代码\行政区划\jiangsu.shp'shapefile_path_level2 = r'E:\ruiduobao\数据和代码\行政区划\xuzhou.shp'shapefile_path_level3 = r'E:\ruiduobao\数据和代码\行政区划\xuzhouxian.shp'# 加载shapefile到 GeoDataFramegdf_level1 = gpd.read_file(shapefile_path_level1)gdf_level2 = gpd.read_file(shapefile_path_level2)gdf_level3 = gpd.read_file(shapefile_path_level3)# 绘制地图plot_map(domains, gdf_level1, gdf_level2, gdf_level3, truelat1, truelat2, stand_lon, proj_params)# 输出d01到d03范围为shpoutput_shapefile_path = r'E:\ruiduobao\行政区划\wrf_domains_平面.shp'output_domains_to_shapefile(domains, proj_params, output_shapefile_path)if __name__ == '__main__':main()

最后,我们把生成的namelist.wps的矢量放到GIS软件中,就可以任意编辑了:

总结

这个代码看起来很简单,但我实际上搞了快两天才弄懂里面的原理,尴尬,故写一篇技术博客方便以后自己查阅。我主要遇到以下问题:

(1)一开始我是用wgs84的经纬度去计算的各个domain的空间位置的,但实际上会有偏移,因为每度随着纬度的不同是会变化的,需要放到平面坐标系中才会有正确的结果。

(2)我刚开始是计算每一个domain的中心点,但实际上这是比较傻的方法,因为i_parent_start等是从左下角开始计数的。

参考

https://github.com/wrf-model/WPS

https://www2.mmm.ucar.edu/wrf/OnLineTutorial/compilation_tutorial.php

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/34246.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

巴中市红色旅游地管理系统

摘 要 随着红色旅游的兴起,越来越多的人开始对巴中市的红色旅游地产生兴趣。巴中市作为中国革命的重要发源地之一,具有丰富的红色旅游资源。然而,目前巴中市红色旅游地的管理仍然存在许多问题,如信息不对称、资源利用效率低等。为…

Robust semi-supervised segmentationwith timestep ensembling diffusion models

时间步合成扩散模型的鲁棒半监督分割 摘要 医学图像分割是一项具有挑战性的任务,由于许多数据集的大小和注释的限制,使得分割更加困难。消噪扩散概率模型(DDPM)最近在模拟自然图像的分布方面显示出前景,并成功地应用于各种医学成像任务。这…

如何给小语种视频生成字幕

目前我们常看的有视频有中、英、日、韩这四种语言,如果我们想给其他的不常用的语言生成字幕怎么办?今天教大家如何给其他语言生成视频字幕文件 打开智游剪辑(zyjj.cc)搜索字幕生成,选择多语种那个就可以了 然后上传我们…

10.XSS绕过之htmlspecialchars()函数

XSS绕过之htmlspecialchars()函数 首先可以测试一下是否将字符被转移成html实体&#xff0c;输入字符测试 1111"<>$点击提交 查看页面元素代码&#xff0c;发现单引号不变&#xff0c;可以利用 重新输入攻击代码&#xff0c;用单引号闭合前面的&#xff0c;进…

python爬虫-爬虫的基础知识储备

爬虫就是一个不断的去抓去网页的程序&#xff0c;根据我们的需要得到我们想要的结果&#xff01;但我们又要让服务器感觉是我们人在通过浏览器浏览不是程序所为&#xff01;归根到底就是我们通过程序访问网站得到html代码&#xff0c;然后分析html代码获取有效内容的过程。下面…

【Python实战因果推断】1_因果效应异质性1

目录 From ATE to CATE Why Prediction Is Not the Answer CATE and ITE 本文将介绍应用于行业的因果推理中最有趣的发展&#xff1a;效应异质性。在此之前&#xff0c;你们了解的是一种治疗方法的一般影响。现在&#xff0c;你将专注于发现它如何对不同的人产生不同的影响。…

Java | Leetcode Java题解之第198题打家劫舍

题目&#xff1a; 题解&#xff1a; class Solution {public int rob(int[] nums) {if (nums null || nums.length 0) {return 0;}int length nums.length;if (length 1) {return nums[0];}int first nums[0], second Math.max(nums[0], nums[1]);for (int i 2; i <…

【Oracle篇】逻辑备份工具expdp(exp)/impdp(imp)和物理备份工具rman的区别和各自的使用场景总汇(第八篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

链表数组遍历输出的辨析(二者都含指针的情况下)----PTA期末复习题

输入输出三位学生的学号和信息 一开始我认为是指针&#xff0c;直接背了指针输出的方式&#xff1b;p;p!NULL;pp->next 这个是错误的 下面这个输出是正确的方式 分析怎么区分这两个 举个例子来 数组遍历&#xff1a; 链表遍历&#xff1a; 输出的结果&#xff1a; 如果将…

区块链技术与数字货币

1.起源 ➢中本聪(Satoshi Nakamoto), 2008 ➢比特币:一种点对点的电子现金系统 2.分布式账本技术原理 1.两个核心技术&#xff1a; ➢以链式区块组织账本数据实现账本数据的不可篡改 ➢分布式的可信记账机制 2.共识机制&#xff1a;由谁记账 ➢目的&#xff1a; ⚫ 解…

【数据结构(邓俊辉)学习笔记】二叉搜索树03——平衡

文章目录 1. 极端退化2. 平均高度3. 理想 适度4. 歧义 等价5. 等价变换 1. 极端退化 二叉搜索树为我们同时实现对数据集高效的静态操作以及动态操作打开了一扇新的大门。 正如我们所看到的&#xff0c;从策略上&#xff0c;BST可以视作是试图将此前的向量结构以及列表结构优…

SpringBoot整合MongoDB JPA使用

一、整合MongoDB SpringDataMongoDB是 SpringData家族成员之一&#xff0c;MongoDB的持久层框架&#xff0c;底层封装了 mongodb-driver。mongodb-driver 是 MongoDB官方推出的 Java连接 MongoDB的驱动包&#xff0c;相当于JDBC驱动。 SpringBoot整合 MongoDB&#xff0c;引入…

【Mac】XnViewMP for Mac(图片浏览查看器)及同类型软件介绍

软件介绍 XnViewMP 是一款多功能、跨平台的图像查看和管理软件&#xff0c;适用于 macOS、Windows 和 Linux 系统。它是经典 XnView 软件的增强版本&#xff0c;更加现代化且功能更强大。XnViewMP 支持数百种图像格式&#xff0c;并提供多种图像处理工具&#xff0c;使其成为摄…

【摄像头标定】使用kalibr进行双目摄像头标定(ros1、ros2)

使用kalibr进行双目摄像头标定 前言标定板标定①板端准备和录制②上位机准备和标定 前言 本文不是纯用ros1进行标定&#xff0c;需要ros1和ros2通信。给使用ros2进行开发&#xff0c;但又想用kalibr标定双目摄像头的小伙伴一个教程。本文双目摄像头的数据发布使用ros2&#xf…

收银系统源码-千呼新零售2.0【线上营销】

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货等连锁店使用。 详细介绍请查看&a…

Js逆向爬虫基础篇

这里写自定义目录标题 逆向技巧断点一 、请求入口定位1. 关键字搜索2. 请求堆栈3. hook4. JSON.stringify 二、响应入口定位&#xff1a;1. 关键字搜索2. hook3. JSON.parse 逆向技巧 断点 普通断点 条件断点 日志断点 XHR断点 一 、请求入口定位 1. 关键字搜索 key关…

办公软件的答案?ONLYOFFICE 桌面应用编辑器会是最好用的 Office 软件?ONLYOFFICE 桌面编辑器使用初体验

文章目录 &#x1f4cb;前言&#x1f3af;什么是 ONLYOFFICE&#x1f3af; 主要功能介绍及 8.1 新功能体验&#x1f3af; 在线体验&#x1f4dd;最后 &#x1f4cb;前言 提到办公软件&#xff0c;大家最常用的可能就是微软的 Microsoft Office 和国产的 WPS Office。这两款软件…

jenkins环境搭建--关于jenkins在Ubuntu下的安装篇(一)

在ubuntu下使用命令进行下载安装包&#xff1a; 关于jenkins的安装有多种&#xff0c;可以借助docker容器进行安装&#xff0c;也可以通过传统方法手动一步步的进行安装&#xff0c;以下介绍手动一步步的安装方法&#xff0c;后续我们将解释关于jenkins的相关配置以及实战使用…

欧盟指控苹果应用商店规则非法压制竞争,面临巨额罚款风险

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Excel 宏录制与VBA编程 —— 14、使用VBA处理Excel事件

简介 若希望特定事件处理程序在触发特定事件时运行&#xff0c;可以为 Application 对象编写事件处理程序。 Application 对象的事件处理程序是全局的&#xff0c;这意味着只要 Microsoft Excel 处于打开状态&#xff0c;事件处理程序将在发生相应的事件时运行&#xff0c;而不…