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)搜索字幕生成,选择多语种那个就可以了 然后上传我们…

nginx常见问题——新手向

一.nginx命令不生效 nginx命令生效需要在指定目录下: /usr/local/nginx/sbin 二.nginx配置文件在哪 /usr/local/nginx/conf/nginx.conf 三.反向代理 如何实现简单的反向代理? 如www.abc.com 转到反向代理服务器192.111.111.111最终转发到127.0.0.1:8080…

10.XSS绕过之htmlspecialchars()函数

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

【PostgreSQL】启航PostgreSQL之旅:基础构建与环境配置

目录 PostgreSQL概述 核心特性 安装与配置 Linux环境安装示例 Windows环境安装 基本命令与界面介绍 命令行界面&#xff08;psql&#xff09; PostgreSQL概述 PostgreSQL&#xff0c;通常简称为Postgres&#xff0c;是一种开源的对象关系型数据库管理系统&#xff08;OR…

AI学习指南机器学习篇-随机森林(Random Forests)算法简介

AI学习指南机器学习篇-随机森林&#xff08;Random Forests&#xff09;算法简介 1. 引言 在机器学习领域&#xff0c;随机森林&#xff08;Random Forests&#xff09;是一种集成学习方法&#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; 如果将…

Android小技巧:利用动态代理自动切换线程

日常开发中&#xff0c;多线程编程是个难以避免的话题&#xff0c;开发者可以小心翼翼、谨慎地、严谨地编程来编写出高效的、安全的多线程程序&#xff0c;但是在长时间的维护中&#xff0c;难免因为其中某个人的某个疏忽而导致出现预料之外的并发问题&#xff0c;比如下面这个…

【XCharts插件】5-1、从Json中读取数据并更新图表案例(v3.0)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址QQ群:398291828大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 XCharts插件是一款基于UGUI的功能强大、易用、参数可配置的数据可视化图表插件。 【Unity3D…

区块链技术与数字货币

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;引入…

jetson 安装 Rustdesk失败

报错: rustdesk depends on gstreamer1.0-pipewire; however: Package gstreamer1.0-pipewire is not installed. 原因&#xff1a; 对于rustdesk&#xff0c;其1.2.3 版需要gstreamer1.0-pipewire软件包&#xff0c;但是此软件包仅适用于 Ubuntu 22.04、22.10、23.04 和 2…

Python数据分析入门:探索数据集

在数据科学领域&#xff0c;Python以其简洁的语法和强大的库支持&#xff0c;成为最受欢迎的编程语言之一。无论是数据清洗、探索性数据分析还是复杂的机器学习任务&#xff0c;Python都能提供相应的工具。本文将引导你使用Python进行简单的数据分析&#xff0c;以一个公开的数…

C语言 用下面的scanf函数输入数据,使a=3,b=7,x=8.5,y=71.82,c1=‘A’,c2=‘a’。在键盘上应该如何输入?

用下面的scanf函数输入数据&#xff0c;使a3&#xff0c;b7&#xff0c;x8.5&#xff0c;y71.82&#xff0c;c1‘A’,c2‘a’。在键盘上应该如何输入&#xff1f; #include<stdio.h> int main() { int a&#xff0c;b&#xff1b; float x,y; char c1,c2; scanf(“…