Files
mkdocs/doc/meshkernelpy/examples/01_mesh2d_basics.md
T
2026-10-10 21:56:35 +08:00

5.7 KiB

二维网格基础

本教程介绍 meshkernel 库的基本用法。

meshkernel 可以创建和操作多种网格。

最常见的应用涉及二维非结构网格,因此本教程重点介绍这类网格。

返回示例目录

以下保留原笔记本的代码和已保存输出;转换过程中未重新执行代码。

首先导入所需的库。

import matplotlib.pyplot as plt
import numpy as np

from meshkernel import GeometryList, MakeGridParameters, MeshKernel, ProjectionType

meshkernel 提供了一组便捷方法,用于创建常见网格。

这里使用 curvilinear_compute_rectangular_grid 方法创建一个简单的曲线网格。该方法的完整参数请参阅相应文档。

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。

mk.curvilinear_convert_to_mesh2d()
mesh2d_input = mk.mesh2d_get()

Mesh2D 有三个必需属性,仅凭它们就可以完整描述任意非结构网格。

前两个属性是 node_x 和 node_y,它们是一维 double 数组,用来描述节点的位置,如下图所示。

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 的绘图输出

第三个必需属性是 edge_nodes,它描述组成各条边的节点索引。

每两个索引表示一条边。因此,在本例中,0–4、1–5、2–6 等索引对分别表示一条边。

mesh2d_input.edge_nodes
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)

结合这三个参数即可绘制网格。

fig, ax = plt.subplots()
mesh2d_input.plot_edges(ax, color="blue")

单元格 13 的绘图输出

要与 meshkernel 库交互,首先创建一个 MeshKernel 类实例。

构造函数的 projection 参数用于指定网格采用笛卡尔坐标(ProjectionType.CARTESIAN)还是球面坐标(ProjectionType.SPHERICAL)。

mk = MeshKernel(projection=ProjectionType.CARTESIAN)

每个实例都维护各自的状态,可以通过对应的获取和设置方法访问这些状态。

mk.mesh2d_set(mesh2d_input)
mesh2d_output_0 = mk.mesh2d_get()

刚才设置了 mesh2d,随后立即将它取出,期间没有要求 meshkernel 执行其他操作。

设置 mesh2d 后,meshkernel 已计算出网格面数据和边的坐标。

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 的绘图输出

meshkernel 还会查找边的中点,并将其作为属性添加到 Mesh2D 类中。

fig, ax = plt.subplots()
ax.plot(mesh2d_output_0.edge_x, mesh2d_output_0.edge_y, ".");

单元格 22 的绘图输出

目前网格看起来仍然是结构化的。接下来添加几个节点,改变它的结构。

node_index_0 = mk.mesh2d_insert_node(4.0, 1.5)
node_index_1 = mk.mesh2d_insert_node(4.0, 2.5)

还需要将新增节点连接起来,否则 meshkernel 会将未连接的节点清理掉。

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)

获取更新后的状态。

mesh2d_output_1 = mk.mesh2d_get()

绘制输出网格,可以看到 meshkernel 已立即识别出一个新的网格面。

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 的绘图输出

也可以删除节点。

mk.mesh2d_delete_node(node_index_1)
mesh2d_output_2 = mk.mesh2d_get()

网格重新变成六个面,但仍留有一条悬挂边。

fig, ax = plt.subplots()
mesh2d_output_2.plot_edges(ax, color="blue")

单元格 34 的绘图输出

悬挂边通常是不需要的,因此 meshkernel 提供了处理它们的方法。首先,可以统计悬挂边的数量。

hanging_edges = mk.mesh2d_get_hanging_edges()
assert hanging_edges.size == 1

meshkernel 还可以查找并删除悬挂边。

mk.mesh2d_delete_hanging_edges()
mesh2d_output_3 = mk.mesh2d_get()

删除悬挂边后,网格恢复到最初的状态。

fig, ax = plt.subplots()
mesh2d_output_3.plot_edges(ax, color="blue")

单元格 40 的绘图输出