神经算子在流体模拟中的应用

神经算子(Neural Operators)是一类学习无限维函数空间之间映射的深度学习方法。与传统算子(如偏微分方程求解器)相比,神经算子可以学习复杂的物理映射,并在推理时快速评估。本章介绍神经算子在计算流体力学中的核心方法和应用。

1. 从偏微分方程到神经算子

1.1 问题定义

考虑参数化偏微分方程族:

其中 是参数(如边界条件、物理系数), 是解。神经算子的目标是学习映射:

传统方法需要针对每个 求解一次PDE,而神经算子学习这个映射,实现”一次训练,多次推理”。

1.2 算子学习方法对比

方法特点计算复杂度
传统求解器有限元/有限差分 per query
物理信息NN逐点预测 per query
神经算子学习算子 per query
FNO频域学习
DeepONet分支-主干网

2. Fourier神经算子(FNO)

2.1 核心思想

FNO在频域学习 PDE 解算子,利用傅里叶变换的高效计算:

其中 是傅里叶变换, 是学习的频域变换核(谱层)。1

2.2 FNO架构

class SpectralConv2D(nn.Module):
    """谱卷积层"""
    def __init__(self, in_channels, out_channels, modes1, modes2):
        super().__init__()
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.modes1 = modes1  # 截断模式数
        self.modes2 = modes2
        
        # 可学习的频域权重
        self.weights = nn.Parameter(
            torch.randn(in_channels, out_channels, modes1, modes2, 2)
        )
    
    def forward(self, x):
        # x: (batch, channels, x, y)
        batch, channels, x_dim, y_dim = x.shape
        
        # 傅里叶变换
        x_ft = torch.fft.rfft2(x)
        
        # 在频域应用权重(仅截断模式)
        out_ft = torch.zeros(batch, self.out_channels, 
                            x_dim, y_dim // 2 + 1, device=x.device)
        
        # 取截断模式
        out_ft[:, :, :self.modes1, :self.modes2] = self._apply_weight(x_ft)
        
        # 逆傅里叶变换
        return torch.fft.irfft2(out_ft, s=(x_dim, y_dim))
 
 
class FNO2D(nn.Module):
    """2D FNO"""
    def __init__(self, modes, width, n_layers):
        super().__init__()
        self.fc0 = nn.Linear(3, width)  # 输入: (x, y, u)
        
        self.spectral_layers = nn.ModuleList([
            SpectralConv2D(width, width, modes, modes)
            for _ in range(n_layers)
        ])
        self.bn_layers = nn.ModuleList([
            nn.BatchNorm2D(width)
            for _ in range(n_layers)
        ])
        
        self.fc1 = nn.Linear(width, 128)
        self.fc2 = nn.Linear(128, 1)
    
    def forward(self, x):
        x = self.fc0(x).permute(0, 3, 1, 2)  # (B, W, H, W) -> (B, W, H, W)
        
        for spec, bn in zip(self.spectral_layers, self.bn_layers):
            x = spec(x) + x  # 残差连接
            x = F.gelu(bn(x))
        
        x = x.permute(0, 2, 3, 1)
        return self.fc2(F.gelu(self.fc1(x)))

2.3 FNO在Navier-Stokes中的应用

Navier-Stokes方程是流体模拟的核心:

FNO可以直接学习速度场的时间演化:

训练策略

  1. 短期预测 步预测,训练多个自回归步骤
  2. 长期稳定性:混合损失:
  3. 数据增强:随机初始条件、随机粘度
def train_fno_navier_stokes(model, dataloader, n_steps=10):
    """训练FNO预测Navier-Stokes流"""
    optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(...)
    
    for epoch in range(num_epochs):
        for u0, u_target in dataloader:
            # 短期预测
            u_pred = model(u0)
            loss = MSE(u_pred, u_target)
            
            # 长期自回归预测
            u_seq = [u0]
            u_cur = u0
            for _ in range(n_steps - 1):
                u_cur = model(u_cur)
                u_seq.append(u_cur)
            
            # 长期损失
            loss_long = sum(MSE(u_seq[i], u_target_seq[i]) 
                          for i in range(n_steps))
            
            loss_total = loss + 0.1 * loss_long
            loss_total.backward()
            optimizer.step()

3. DeepONet深度算子网络

3.1 分支-主干架构

DeepONet采用分支-主干(Branch-Trunk)架构:

  • 分支网络(Branch):编码输入函数
  • 主干网络(Trunk):编码空间坐标
  • 输出:分支和主干输出的点积

3.2 DeepONet for Darcy Flow

Darcy方程描述多孔介质流动:

其中 是渗透率(输入函数), 是压力(输出函数)。

class DeepONet(nn.Module):
    def __init__(self, branch_layers, trunk_layers, p=100):
        super().__init__()
        self.p = p  # 分支/主干网络维度
        
        # 分支网络:编码渗透率函数
        self.branch = nn.Sequential(
            nn.Linear(input_dim, 100),
            nn.GELU(),
            nn.Linear(100, 200),
            nn.GELU(),
            nn.Linear(200, p)
        )
        
        # 主干网络:编码空间坐标
        self.trunk = nn.Sequential(
            nn.Linear(2, 100),  # (x, y) 坐标
            nn.GELU(),
            nn.Linear(100, 200),
            nn.GELU(),
            nn.Linear(200, p)
        )
    
    def forward(self, a, y):
        # a: (batch, sensor_points, input_dim) - 渗透率传感器值
        # y: (batch, query_points, 2) - 查询点坐标
        
        # 聚合分支输出
        b = torch.mean(self.branch(a), dim=1)  # (batch, p)
        
        # 主干网络
        t = self.trunk(y)  # (batch, query_points, p)
        
        # 点积
        return torch.sum(b.unsqueeze(1) * t, dim=2)  # (batch, query_points)

3.3 DeepONet for Navier-Stokes

对于Navier-Stokes,DeepONet可以学习流场的算子映射:

传感器点选择:选择有物理意义的点(如边界、特征位置)

def train_deeponet_navier_stokes(model, train_data, val_data):
    """DeepONet训练Navier-Stokes"""
    branch_input, trunk_input, u_target = train_data
    
    # 分支输入:初始条件和物理参数
    branch_out = model.branch(branch_input)
    
    # 主干输入:目标空间坐标
    trunk_out = model.trunk(trunk_input)
    
    # 算子输出
    u_pred = torch.einsum('bp,bqp->bq', branch_out, trunk_out)
    
    loss = MSE(u_pred, u_target)
    loss.backward()

4. GraphONet与图结构

4.1 非结构化网格

传统FNO/DeepONet主要处理规则网格,GraphONet处理非结构化网格:

class GraphONet(nn.Module):
    """图神经算子"""
    def __init__(self, node_dim, edge_dim, hidden_dim, n_layers):
        super().__init__()
        self.node_encoder = nn.Linear(node_dim, hidden_dim)
        self.edge_encoder = nn.Linear(edge_dim, hidden_dim)
        
        self.message_passing = nn.ModuleList([
            MessagePassingLayer(hidden_dim)
            for _ in range(n_layers)
        ])
        
        self.decoder = nn.Sequential(
            nn.Linear(hidden_dim, hidden_dim),
            nn.GELU(),
            nn.Linear(hidden_dim, 1)
        )
    
    def forward(self, graph):
        x, edge_index, edge_attr = graph.x, graph.edge_index, graph.edge_attr
        
        x = self.node_encoder(x)
        
        for mp in self.message_passing:
            x = mp(x, edge_index, edge_attr)
        
        return self.decoder(x)

4.2 在流体模拟中的应用

GraphONet在以下场景有优势:

  1. 复杂几何:飞机、汽车周围的流场
  2. 自适应网格:不同区域精度不同
  3. 动态域:可变形边界问题

5. 与传统CFD的对比

5.1 计算效率

方法训练成本推理成本精度
DNS-基准
LES-
RANS-中等
FNO
DeepONet

5.2 泛化能力

神经算子的一个关键优势是零样本泛化:训练于有限参数范围,可以外推到未见过的参数:

  1. 粘度泛化:训练于 ,测试于
  2. 雷诺数泛化:训练于低Re,预测高Re流场
  3. 几何泛化:训练于简单几何,测试于复杂几何(GraphONet)

5.3 物理约束

为保证物理一致性,可加入约束:

  1. 无散度约束:通过投影层或分支网络编码
  2. 能量守恒:Hamiltonian损失
  3. 对称性约束:等变网络架构

6. 前沿进展

6.1 自适应神经算子

  • Adaptive FNO:动态调整频域模式数
  • Multi-scale DeepONet:处理多尺度问题
  • Hierarchical Operators:金字塔式算子

6.2 Transformer-based Operators

  • OFormer:Operator Transformer架构
  • NOAH:神经算子与注意力结合
  • Fourier Token Mixer:频域token混合

6.3 实际应用

  1. 天气预报:短临降水预测
  2. 工业设计:快速流体仿真
  3. 数字孪生:实时流场预测

参考文献

Footnotes

  1. Li, Z., Kovachki, N., Azizzadenesheli, K., Liu, B., Bhattacharya, K., Stuart, A., & Anandkumar, A. (2021). Fourier neural operator for parametric partial differential equations. ICLR.