使用 Python 实现随机中点位移法生成逼真的裂隙面

裂隙面在地质学、岩石力学、计算机图形学等领域有着广泛的应用。它们的随机性和分形特性使得模拟真实裂隙面成为一项重要的研究课题。本文将通过 Python ,结合经典的 随机中点位移法( Random Midpoint Displacement , RMD ),逐步创建一个二维的随机裂隙面,并详细解析每一步代码的实现过程。

先看下效果图:
在这里插入图片描述


一、随机中点位移法简介

1. 什么是随机中点位移法?

随机中点位移法是一种简单且高效的分形生成算法。它的基本思想是从一个大尺度开始,通过不断细化网格,并在每次细化时为中间点添加随机扰动,从而生成具有大尺度结构和小尺度细节的表面。

这一方法的特点是:

  • 高效性:算法复杂度较低,适合生成大规模的表面。
  • 随机性:通过随机扰动,模拟自然界中裂隙、地形等不规则表面的特性。
  • 分形特性:生成的结果具有分形维数,能很好地模拟自然界的粗糙表面。

2. 应用领域

  • 地质学:生成裂隙面,用于研究地下水流动、岩石的强度和稳定性。
  • 计算机图形学:生成自然地貌(如山脉、地形)或粗糙材质。
  • 工程应用:模拟裂隙网络,分析裂隙对渗透率的影响。

二、 Python 代码实现

让我们直接进入代码部分,并通过逐行详解,帮助你全面掌握随机中点位移法的实现。


1. 导入必要的库

import numpy as np
import matplotlib.pyplot as plt
  • numpy :用于处理多维数组和数学计算。我们将借助它来创建二维数组并进行随机数生成。
  • matplotlib.pyplot :用于可视化生成的裂隙面。这是 Python 中非常强大的绘图库。

2. 函数定义:随机中点位移法核心逻辑

def midpoint_displacement_2d(size, roughness, seed=None):
    """
    使用随机中点位移法生成二维粗糙裂隙面。

    参数:
    - size: 裂隙面的网格尺寸(必须是2的幂次方+1,例如65, 129, 257等)。
    - roughness: 粗糙度参数,控制表面的起伏程度。
    - seed: 随机数种子,用于生成可重复的结果。

    返回值:
    - surface: 生成的二维裂隙面。
    """

函数说明

  • size :二维数组的大小,必须为 2^n + 1 (如 129 , 257 等)。这种结构使网格能够在每次迭代中被整齐地细分。
  • roughness :粗糙度参数,控制生成裂隙面的起伏程度。值越大,表面越粗糙;值越小,表面越平滑。
  • seed :随机数种子,用于确保生成的结果是可重复的。指定种子后,每次运行都会生成相同的裂隙面。

3. 设置随机数种子

    if seed is not None:
        np.random.seed(seed)

解释

  • 如果用户提供了 seed 值,那么我们使用 np.random.seed(seed) 设置随机数生成器的种子。
  • 这样可以确保生成的随机数序列是固定的,从而保证结果的可重复性。

4. 初始化二维裂隙面

    surface = np.zeros((size, size))
  • np.zeros((size, size)) :创建一个大小为 (size, size) 的二维数组,初始值全为 0
  • 这个数组将表示裂隙面的高度值,每一个元素对应网格的一个节点。

5. 初始化网格的四个顶点

    surface[0, 0] = np.random.uniform(-1, 1)
    surface[0, -1] = np.random.uniform(-1, 1)
    surface[-1, 0] = np.random.uniform(-1, 1)
    surface[-1, -1] = np.random.uniform(-1, 1)

解释

  • 随机为二维数组的四个角点赋值,值范围为 [-1, 1]
  • 这四个顶点值将作为整个裂隙面生成的初始条件。

6. 初始化步长

    step_size = size - 1

解释

  • 设置初始步长为 size - 1
  • 步长是指当前迭代中,用于分割网格的大小。在每次迭代中,步长会减半,从而逐步细化网格。

7. 开始迭代生成裂隙面

    while step_size > 1:
        half_step = step_size // 2

解释

  • 使用 while 循环,直到步长小于或等于 1
  • 在每次循环中,计算半步长 half_step = step_size // 2 ,用于在网格的中点和边界点之间插值。

8. 钻石步( Diamond Step )

        for x in range(0, size - 1, step_size):
            for y in range(0, size - 1, step_size):
                avg = (
                    surface[x, y]
                    + surface[x + step_size, y]
                    + surface[x, y + step_size]
                    + surface[x + step_size, y + step_size]
                ) / 4
                surface[x + half_step, y + half_step] = avg + np.random.uniform(-1, 1) * roughness

说明

  • 目标:为每个网格单元的中心点生成一个新值。
  • avg :计算当前网格四个顶点的平均值。
  • np.random.uniform(-1, 1) * roughness :添加一个随机扰动,其幅度由 roughness 控制。
  • 更新后的值存储在网格的中心点位置 surface[x + half_step, y + half_step]

9. 方形步( Square Step )

        for x in range(0, size - 1, half_step):
            for y in range((x + half_step) % step_size, size - 1, step_size):
                avg = 0
                count = 0
                if x - half_step >= 0:
                    avg += surface[x - half_step, y]
                    count += 1
                if x + half_step < size:
                    avg += surface[x + half_step, y]
                    count += 1
                if y - half_step >= 0:
                    avg += surface[x, y - half_step]
                    count += 1
                if y + half_step < size:
                    avg += surface[x, y + half_step]
                    count += 1
                surface[x, y] = avg / count + np.random.uniform(-1, 1) * roughness

说明

  • 目标:为网格的每条边界点生成一个新值。
  • 通过计算边界点相邻的点的平均值,并添加随机扰动,为边界点赋值。

10. 更新步长和粗糙度

        step_size //= 2
        roughness /= 2

说明

  • 每次迭代后,步长减半,逐步细化网格。
  • 同时,降低随机扰动幅度(粗糙度),使得细节更平滑。

11. 返回最终结果

    return surface

说明

  • 返回生成的裂隙面(二维数组)。

12. 调用函数并可视化结果

size = 129
roughness = 1.0
seed = 42
surface = midpoint_displacement_2d(size, roughness, seed)

plt.figure(figsize=(10, 8))
plt.imshow(surface, cmap='terrain', origin='upper')
plt.colorbar(label="Height")
plt.title("Random Midpoint Displacement Surface")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.show()

说明

  • 参数:
    - size=129 :网格大小为 129 × 129
    - roughness=1.0 :初始粗糙度。
    - seed=42 :随机种子,用于生成可复现的结果。
  • 使用 matplotlib 绘制结果:
    - imshow :展示二维裂隙面。
    - cmap='terrain' :用地形色彩映射模拟裂隙表面。

三、完整代码

import numpy as np
import matplotlib.pyplot as plt

def midpoint_displacement_2d(size, roughness, seed=None):
    """
    使用随机中点位移法生成二维粗糙裂隙面。

    参数:
    - size: 裂隙面的网格尺寸(必须是2的幂次方+1,例如65, 129, 257等)。
    - roughness: 粗糙度参数,控制表面的起伏程度。
    - seed: 随机数种子,用于生成可重复的结果。

    返回值:
    - surface: 生成的二维裂隙面。
    """
    if seed is not None:
        np.random.seed(seed)

    # 初始化一个二维数组,并将四个顶点随机赋值
    surface = np.zeros((size, size))
    surface[0, 0] = np.random.uniform(-1, 1)
    surface[0, -1] = np.random.uniform(-1, 1)
    surface[-1, 0] = np.random.uniform(-1, 1)
    surface[-1, -1] = np.random.uniform(-1, 1)

    step_size = size - 1  # 初始步长
    while step_size > 1:
        half_step = step_size // 2

        # 钻石步:计算中点值
        for x in range(0, size - 1, step_size):
            for y in range(0, size - 1, step_size):
                avg = (
                    surface[x, y]
                    + surface[x + step_size, y]
                    + surface[x, y + step_size]
                    + surface[x + step_size, y + step_size]
                ) / 4
                surface[x + half_step, y + half_step] = avg + np.random.uniform(-1, 1) * roughness

        # 方形步:计算边点值
        for x in range(0, size - 1, half_step):
            for y in range((x + half_step) % step_size, size - 1, step_size):
                avg = 0
                count = 0
                if x - half_step >= 0:
                    avg += surface[x - half_step, y]
                    count += 1
                if x + half_step < size:
                    avg += surface[x + half_step, y]
                    count += 1
                if y - half_step >= 0:
                    avg += surface[x, y - half_step]
                    count += 1
                if y + half_step < size:
                    avg += surface[x, y + half_step]
                    count += 1
                surface[x, y] = avg / count + np.random.uniform(-1, 1) * roughness

        # 缩小步长,并降低粗糙度比例
        step_size //= 2
        roughness /= 2

    return surface


# 参数设置
size = 129  # 网格尺寸(2^n + 1,例如65, 129, 257)
roughness = 1.0  # 粗糙度系数
seed = 42  # 随机种子(可选)

# 生成裂隙面
surface = midpoint_displacement_2d(size, roughness, seed)

# 绘制裂隙面
plt.figure(figsize=(10, 8))
plt.imshow(surface, cmap='terrain', origin='upper')
plt.colorbar(label="Height")
plt.title("Random Midpoint Displacement Surface")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.show()


四、结果展示与分析

运行上述代码后,你将看到一个二维裂隙面,具有随机的高低起伏,形似真实的自然裂隙。裂隙面的粗糙度参数和网格分辨率可以根据需要调整,以满足不同的应用场景。

在这里插入图片描述


五、扩展与应用

1. 三维裂隙面生成

将此方法扩展到三维数组,可以生成更加复杂的三维裂隙网络。

2. 工程领域应用

模拟裂隙对流体流动的影响,分析裂隙面在接触力学中的作用。

3. 性能优化

使用并行计算或 GPU 加速,可以快速生成高分辨率的裂隙面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挣扎的蓝藻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值