副产品技法

标题六面体体积

这段代码在干一件非常基础但至关重要的事:计算每个网格格子的体积

在流体力学模拟中,空间被切分成很多小格子(网格)。要计算格子里有多少气体、能量怎么变化,首先必须知道每个格子有多大(体积)

由于网格可能是扭曲的(比如贴合飞机机翼的曲面网格),格子不是标准的正方体,不能直接用 长×宽×高 计算。这段代码用几何分解法来精确计算任意形状六面体的体积。

复制代码
```python
#********************************************************************
#      calculate volume of cells
#********************************************************************
@ti.kernel
def CVOL():      
    VOLMIN[None] = 1.0E7  # 初始化最小体积为一个极大值
    
    # 遍历所有内部网格单元 (1 to NX)
    for I, J, K in ti.ndrange((1, NX + 1), (1, NY + 1), (1, NZ + 1)):
        # --- 计算辅助向量 SI (基于面 J方向) ---
        # 这里的逻辑是将网格单元分割成四面体,利用向量叉乘计算面积分量
        DX1 = XYZ[I, J + 1, K + 1][0] - XYZ[I, J, K][0]
        DY1 = XYZ[I, J + 1, K + 1][1] - XYZ[I, J, K][1]
        DZ1 = XYZ[I, J + 1, K + 1][2] - XYZ[I, J, K][2]
        DX2 = XYZ[I, J, K + 1][0] - XYZ[I, J + 1, K][0]
        DY2 = XYZ[I, J, K + 1][1] - XYZ[I, J + 1, K][1]
        DZ2 = XYZ[I, J, K + 1][2] - XYZ[I, J + 1, K][2]
        # 叉乘得到面积向量分量
        SIX = 0.5 * (DY1 * DZ2 - DZ1 * DY2)
        SIY = 0.5 * (DZ1 * DX2 - DX1 * DZ2)
        SIZ = 0.5 * (DX1 * DY2 - DY1 * DX2)

        # --- 计算辅助向量 SJ (基于面 I方向) ---
        DX1 = XYZ[I + 1, J, K + 1][0] - XYZ[I, J, K][0]
        DY1 = XYZ[I + 1, J, K + 1][1] - XYZ[I, J, K][1]
        DZ1 = XYZ[I + 1, J, K + 1][2] - XYZ[I, J, K][2]
        DX2 = XYZ[I + 1, J, K][0] - XYZ[I, J, K + 1][0]
        DY2 = XYZ[I + 1, J, K][1] - XYZ[I, J, K + 1][1]
        DZ2 = XYZ[I + 1, J, K][2] - XYZ[I, J, K + 1][2]
        SJX = 0.5 * (DY1 * DZ2 - DZ1 * DY2)
        SJY = 0.5 * (DZ1 * DX2 - DX1 * DZ2)
        SJZ = 0.5 * (DX1 * DY2 - DY1 * DX2)

        # --- 计算辅助向量 SK (基于面 K方向) ---
        DX1 = XYZ[I + 1, J + 1, K][0] - XYZ[I, J, K][0]
        DY1 = XYZ[I + 1, J + 1, K][1] - XYZ[I, J, K][1]
        DZ1 = XYZ[I + 1, J + 1, K][2] - XYZ[I, J, K][2]
        DX2 = XYZ[I, J + 1, K][0] - XYZ[I + 1, J, K][0]
        DY2 = XYZ[I, J + 1, K][1] - XYZ[I + 1, J, K][1]
        DZ2 = XYZ[I, J + 1, K][2] - XYZ[I + 1, J, K][2]
        SKX = 0.5 * (DY1 * DZ2 - DZ1 * DY2)
        SKY = 0.5 * (DZ1 * DX2 - DX1 * DZ2)
        SKZ = 0.5 * (DX1 * DY2 - DY1 * DX2)

        # --- 汇总面积分量 ---
        SX = SIX + SJX + SKX
        SY = SIY + SJY + SKY
        SZ = SIZ + SJZ + SKZ
        
        # --- 计算体积 ---
        # 利用体积分解算法:V = (对角向量 · 总面积向量) / 3
        XT1 = XYZ[I + 1, J + 1, K + 1][0] - XYZ[I, J, K][0]
        YT1 = XYZ[I + 1, J + 1, K + 1][1] - XYZ[I, J, K][1]
        ZT1 = XYZ[I + 1, J + 1, K + 1][2] - XYZ[I, J, K][2]
        VOL[I, J, K] = (XT1 * SX + YT1 * SY + ZT1 * SZ) / 3.0

        # 容错检查:体积不能为负或零
        if VOL[I, J, K] <= 0.0:
            out.write('NEGATIVE VOLUME')
            out.write('I,J,K',I,J,K)
            exit
     
        # 更新全场最小体积
        if VOL[I, J, K] <= VOLMIN[None]:
            VOLMIN[None] = VOL[I, J, K]


---

## 🧊 一、核心目标:算一个"歪箱子"的体积

每个网格单元是一个**六面体**(8个顶点,像被捏变形的魔方):

    (I+1,J+1,K+1) ________ (I,J+1,K+1)
                   /|      /|
                  / |     / |
     (I+1,J,K+1) /__|____/   |
        |    |  (I+1,J+1,K) |  |
        |    | /   |    |   | (I,J,K+1)
        |    |/    |    |   | /
        |    /_____|____|___|/
     (I+1,J,K)    (I,J,K)  (I,J+1,K)


**问题**:这个箱子是歪的,怎么算体积?

**答案**:把它切成几个**四面体**(三角锥),分别算体积再相加。

---

## 🔧 二、代码三步走

### 第1步:计算三个方向的"面积向量" (SI, SJ, SK)

代码里分了三大段,分别计算 `SI`、`SJ`、`SK`。

**通俗理解**:
想象你站在格子的一个角 `(I,J,K)`,看向三个相邻的面:
- **SI**:J-K 平面的对角面(类似"侧面")
- **SJ**:I-K 平面的对角面(类似"正面")
- **SK**:I-J 平面的对角面(类似"底面")

**计算方法**(以 SI 为例):
```python
# 向量1:从 (I,J,K) 到 (I,J+1,K+1) 的对角线
DX1 = XYZ[I, J+1, K+1] - XYZ[I, J, K]

# 向量2:从 (I,J+1,K) 到 (I,J,K+1) 的另一条对角线
DX2 = XYZ[I, J, K+1] - XYZ[I, J+1, K]

# 叉乘 → 得到垂直于这个面的"面积向量"
SIX = 0.5 * (DY1*DZ2 - DZ1*DY2)  # X方向分量
SIY = 0.5 * (DZ1*DX2 - DX1*DZ2)  # Y方向分量
SIZ = 0.5 * (DX1*DY2 - DY1*DX2)  # Z方向分量

为什么叉乘?

  • 两个向量的叉乘 = 它们围成的平行四边形的面积
  • 乘以 0.5 = 变成三角形的面积
  • 结果是一个向量,方向垂直于这个面

第2步:把三个面积向量加起来

python 复制代码
SX = SIX + SJX + SKX
SY = SIY + SJY + SKY
SZ = SIZ + SJZ + SKZ

通俗理解

把三个方向的"面"拼起来,形成一个包围盒的总表面积向量


第3步:用"对角线·面积"算体积

python 复制代码
# 主对角线:从 (I,J,K) 到 (I+1,J+1,K+1)
XT1 = XYZ[I+1, J+1, K+1][0] - XYZ[I, J, K][0]
YT1 = XYZ[I+1, J+1, K+1][1] - XYZ[I, J, K][1]
ZT1 = XYZ[I+1, J+1, K+1][2] - XYZ[I, J, K][2]

# 体积 = (对角线向量 · 总面积向量) / 3
VOL[I, J, K] = (XT1*SX + YT1*SY + ZT1*SZ) / 3.0

为什么除以3?

  • 这是四面体体积公式 :V=13×底面积×高V = \frac{1}{3} \times \text{底面积} \times \text{高}V=31×底面积×高
  • 点乘 (XT1*SX + ...) 相当于算"高"
  • 整个六面体被分解成了多个四面体,最终等效为这个公式

📐 三、几何原理图解

复制代码
          顶点7
         /|   /|
       /  | /  |
     顶点3---顶点6
     |  / |  / |
     | /  | /  顶点5
     |/   |/   /
     顶点0---顶点4
            /
          顶点1,2 (隐藏)

六面体体积 = 5个四面体体积之和
           = (对角线 · 面积向量) / 3

⚠️ 四、容错检查

python 复制代码
if VOL[I, J, K] <= 0.0:
    out.write('NEGATIVE VOLUME')
    exit

为什么检查?

  • 如果网格画得太扭曲,顶点顺序错了,体积可能算出负数
  • 体积为负或零 → 网格无效 → 程序必须停止,否则后续计算全错
python 复制代码
if VOL[I, J, K] <= VOLMIN[None]:
    VOLMIN[None] = VOL[I, J, K]

记录最小体积

  • 用于后续判断时间步长(体积越小,时间步长要越短,否则计算不稳定)

🎯 五、一句话总结

这段代码把每个扭曲的六面体网格切成多个四面体,用向量叉乘和点乘的几何方法,精确计算每个格子的体积,并检查网格质量是否合格。


📊 类比帮助理解

代码操作 现实生活类比
XYZ[I,J,K] 测量房间8个角的坐标
向量叉乘 用两根尺子量墙面的面积
向量点乘 量房间的"高度"
除以3 三角锥体积公式
负体积检查 检查房间是不是"翻面"了(建模错误)
记录最小体积 找到最小的房间,决定空调功率
相关推荐
小哈蒙德12 分钟前
基于deepSeekV4Pro(thinking)研究pointPillar的历程
python·算法
兰令水13 分钟前
topcode【随机算法题】【2026.5.16打卡-java版本】
java·数据结构·算法
Shan120514 分钟前
广度优先搜索之层序遍历
数据结构·算法·宽度优先
SilentSamsara21 分钟前
自定义上下文管理器实战:数据库连接池、文件锁与超时控制
开发语言·python·算法·青少年编程
吃着火锅x唱着歌29 分钟前
LeetCode 503.下一个更大元素II
算法·leetcode·职场和发展
_深海凉_32 分钟前
LeetCode热题100-将有序数组转换为二叉搜索树
数据结构·算法·leetcode
KaMeidebaby42 分钟前
卡梅德生物技术快报|单克隆抗体人源化 PEG 修饰质控方法体系构建与验证
服务器·前端·数据库·人工智能·算法·百度·新浪微博
不知名的老吴1 小时前
二叉树的遍历算法之先序遍历
算法
liu****1 小时前
第16届国赛蓝桥杯大赛C/C++大学B组
c语言·数据结构·c++·算法·蓝桥杯
SimpleLearingAI1 小时前
大模型推理框架总结解析
算法