# 二维网格基础 本教程介绍 `meshkernel` 库的基本用法。 `meshkernel` 可以创建和操作多种网格。 最常见的应用涉及二维非结构网格,因此本教程重点介绍这类网格。 [返回示例目录](index.md) 以下保留原笔记本的代码和已保存输出;转换过程中未重新执行代码。 首先导入所需的库。 ```python import matplotlib.pyplot as plt import numpy as np from meshkernel import GeometryList, MakeGridParameters, MeshKernel, ProjectionType ``` `meshkernel` 提供了一组便捷方法,用于创建常见网格。 这里使用 `curvilinear_compute_rectangular_grid` 方法创建一个简单的曲线网格。该方法的完整参数请参阅相应文档。 ```python mk = MeshKernel() make_grid_parameters = MakeGridParameters() make_grid_parameters.num_columns = 3 make_grid_parameters.num_rows = 2 make_grid_parameters.angle = 0.0 make_grid_parameters.origin_x = 0.0 make_grid_parameters.origin_y = 0.0 make_grid_parameters.block_size_x = 1.0 make_grid_parameters.block_size_y = 1.0 mk.curvilinear_compute_rectangular_grid(make_grid_parameters) ``` 将曲线网格转换为非结构网格,并获取生成的 `mesh2d`。 ```python mk.curvilinear_convert_to_mesh2d() ``` ```python mesh2d_input = mk.mesh2d_get() ``` `Mesh2D` 有三个必需属性,仅凭它们就可以完整描述任意非结构网格。 前两个属性是 `node_x` 和 `node_y`,它们是一维 `double` 数组,用来描述节点的位置,如下图所示。 ```python fig, ax = plt.subplots() # 绘制白色点,仅用于调整图的显示范围 ax.plot(mesh2d_input.node_x, mesh2d_input.node_y, "ow") # 为节点编号 for i in range(mesh2d_input.node_x.size): ax.annotate( int(i), xy=(mesh2d_input.node_x[i], mesh2d_input.node_y[i]), ha="center", va="center", fontsize=12, color="blue", ) ``` ![单元格 9 的绘图输出](images/01_mesh2d_basics_9_0.png) 第三个必需属性是 `edge_nodes`,它描述组成各条边的节点索引。 每两个索引表示一条边。因此,在本例中,0–4、1–5、2–6 等索引对分别表示一条边。 ```python mesh2d_input.edge_nodes ``` ```text array([ 0, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11], dtype=int32) ``` 结合这三个参数即可绘制网格。 ```python fig, ax = plt.subplots() mesh2d_input.plot_edges(ax, color="blue") ``` ![单元格 13 的绘图输出](images/01_mesh2d_basics_13_0.png) 要与 `meshkernel` 库交互,首先创建一个 `MeshKernel` 类实例。 构造函数的 `projection` 参数用于指定网格采用笛卡尔坐标(`ProjectionType.CARTESIAN`)还是球面坐标(`ProjectionType.SPHERICAL`)。 ```python mk = MeshKernel(projection=ProjectionType.CARTESIAN) ``` 每个实例都维护各自的状态,可以通过对应的获取和设置方法访问这些状态。 ```python mk.mesh2d_set(mesh2d_input) ``` ```python mesh2d_output_0 = mk.mesh2d_get() ``` 刚才设置了 `mesh2d`,随后立即将它取出,期间没有要求 `meshkernel` 执行其他操作。 设置 `mesh2d` 后,`meshkernel` 已计算出网格面数据和边的坐标。 ```python fig, ax = plt.subplots() mesh2d_output_0.plot_faces(ax) # 在网格面中心标注面索引 for face_index, (face_x, face_y) in enumerate( zip(mesh2d_output_0.face_x, mesh2d_output_0.face_y) ): ax.text(face_x, face_y, face_index, ha="center", va="center", fontsize=22) ``` ![单元格 20 的绘图输出](images/01_mesh2d_basics_20_0.png) `meshkernel` 还会查找边的中点,并将其作为属性添加到 `Mesh2D` 类中。 ```python fig, ax = plt.subplots() ax.plot(mesh2d_output_0.edge_x, mesh2d_output_0.edge_y, "."); ``` ![单元格 22 的绘图输出](images/01_mesh2d_basics_22_0.png) 目前网格看起来仍然是结构化的。接下来添加几个节点,改变它的结构。 ```python node_index_0 = mk.mesh2d_insert_node(4.0, 1.5) node_index_1 = mk.mesh2d_insert_node(4.0, 2.5) ``` 还需要将新增节点连接起来,否则 `meshkernel` 会将未连接的节点清理掉。 ```python edge_index_0 = mk.mesh2d_insert_edge(7, node_index_0) edge_index_1 = mk.mesh2d_insert_edge(node_index_0, node_index_1) edge_index_3 = mk.mesh2d_insert_edge(node_index_1, 11) ``` 获取更新后的状态。 ```python mesh2d_output_1 = mk.mesh2d_get() ``` 绘制输出网格,可以看到 `meshkernel` 已立即识别出一个新的网格面。 ```python fig, ax = plt.subplots() mesh2d_output_1.plot_faces(ax) # 在网格面中心标注面索引 for face_index, (face_x, face_y) in enumerate( zip(mesh2d_output_1.face_x, mesh2d_output_1.face_y) ): ax.text(face_x, face_y, face_index, ha="center", va="center", fontsize=22) ``` ![单元格 30 的绘图输出](images/01_mesh2d_basics_30_0.png) 也可以删除节点。 ```python mk.mesh2d_delete_node(node_index_1) mesh2d_output_2 = mk.mesh2d_get() ``` 网格重新变成六个面,但仍留有一条悬挂边。 ```python fig, ax = plt.subplots() mesh2d_output_2.plot_edges(ax, color="blue") ``` ![单元格 34 的绘图输出](images/01_mesh2d_basics_34_0.png) 悬挂边通常是不需要的,因此 `meshkernel` 提供了处理它们的方法。首先,可以统计悬挂边的数量。 ```python hanging_edges = mk.mesh2d_get_hanging_edges() assert hanging_edges.size == 1 ``` `meshkernel` 还可以查找并删除悬挂边。 ```python mk.mesh2d_delete_hanging_edges() mesh2d_output_3 = mk.mesh2d_get() ``` 删除悬挂边后,网格恢复到最初的状态。 ```python fig, ax = plt.subplots() mesh2d_output_3.plot_edges(ax, color="blue") ``` ![单元格 40 的绘图输出](images/01_mesh2d_basics_40_0.png)