基于DeepCFD模型和CNN/U-Net模型的流场预测

1.遇到问题

计算流体力学(Computational fluid dynamics, CFD)通过对Navier-Stokes方程(简称N-S方程)的精确求解,能够精准获取流体在不同状态下的物理量分布详情,这些物理量包括但不限于密度、压力及速度等关键参数。以下图为例,展示了圆柱体周边二维非均匀稳定层流通道流动的模拟结果。

在某些复杂的应用场景中,如机翼优化和流体与结构相互作用方面,需要使用千万级甚至上亿的网格对问题进行建模,导致CFD的计算量非常巨大。因此,目前亟需发展出一种相比于传统CFD方法更高效,且可以保持计算精度的方法。

因此,使用数据驱动的机器学习方法,使用一小部分资源来生成这些模拟的精确近似是非常有吸引的。这些近似解决方案以低错误率为代价加速结果的潜力可以更有效地开发依赖 CFD 研究的产品。问题来了,提出DeepCFD网络模型,该如何设计网络模型来解决流体力学中流场的问题呢?数据集应该如何构造呢?

2.前情提要

1)流场问题

二维不可压缩流体的 Navier-Stokes方程:

假设非均匀稳态流动条件:

输入:障碍物、边界条件

输出:流体的 x 方向速度、y 方向速度和流体压强 p

障碍物:

基本形状(圆形、正方形、前向三角形、后向三角形和菱形),如 primitive。

生成器生成障碍物形状为sample1 ~ 3的 2D 河道流量数据集的障碍物。

边界条件:

如下图所示:

顺流方向的域尺寸为260 mm,垂直于流动方向的域尺寸为120 mm。

网格元素的数量根据所使用的形状而变化,但是对于大约 1 mm 的基本单元大小,平均单元数大约为30000。

边界条件保持固定,入口(左壁)的恒定径向速度为0.1 米/秒,出口(右壁)的梯度为零,顶部/底部和障碍物壁的边界条件无滑 ,层流动态粘度设置为 1 * 10^-4 m^2/s,中心差分方案(CDS)用于动量方程对流项和扩散项的离散化。

2)数据集

数据集使用原作者利用OpenFOAM计算的CFD算例,共981组,分为两个文件(dataX.pkl, dataY.pkl),两个文件大小都是152 MB,形状均为[981, 3, 172, 79]。dataX.pkl包括三种输入:障碍物的SDF、计算域边界的SDF和流动区域的标签;dataY.pkl包括三种输出:流体的x方向速度、y方向速度和流体压强。数据获取使用的计算网格为172×79。

数据集地址:Data_DeepCFD_数据集-飞桨AI Studio星河社区

或https://www.dropbox.com/s/kg0uxjnbhv390jv/Data_DeepCFD.7z?dl=0

数据效果图如下:

3)深度学习模型

Net网络CV领域中图像分割的算法,其主要特点是输入和输出的尺寸是一样的。

典型的U-Net网络如下图所示:

由于其网络结构“U”型而得名,是由卷积、下采样、上采样和拼接操作组成的编码器—解码器对称网络。

网络左半部分是输入路径,右半部分是输出路径。

3.解决方案

1)网络结构

网络结构:编译器-解码器,如下图:

a图是具有SDF和流动区域多类别标记的输入通道。b图是下采样卷积操作从输入中创建流几何的潜在表示。c图是上采样反卷积将LGR显示出特定的变量。

2)DeepCFD模型

DeepCFD U-Net网络:模仿U-Net网络,由卷积、下采样、上采样和拼接操作组成。

其中,实验中4种变形模型如下:

3)损失函数

其中,速度v是L2,压强是L1。

4)训练细节

最后选择是:kernel size = 5。

4.代码结构及参数说明

1)自定义代码结构

loss_func():定义了计算一个模型(model)和一组批次数据(batch)的损失的损失函数。

    def loss_func(model, batch):
        x, y = batch
        output = model(x)
        lossu = ((output[:,0,:,:] - y[:,0,:,:]) ** 
2).reshape((output.shape[0],1,output.shape[2],output.shape[3])) 
        lossv = ((output[:,1,:,:] - y[:,1,:,:]) ** 
2).reshape((output.shape[0],1,output.shape[2],output.shape[3])) 
        lossp = torch.abs((output[:,2,:,:] - 
y[:,2,:,:])).reshape((output.shape[0],1,output.shape[2],output.shape[3])) 
        loss = (lossu + lossv + lossp)/channels_weights
        return torch.sum(loss), output

split_tensors():将数据集(x,y)拆分成一定百分比的数据集和测试集

def split_tensors(*tensors, ratio):
    assert len(tensors) > 0
    split1, split2 = [], []
    count = len(tensors[0])。
    for tensor in tensors:
        assert len(tensor) == count
        split1.append(tensor[:int(len(tensor) * ratio)])
        split2.append(tensor[int(len(tensor) * ratio):])
    if len(tensors) == 1:        split1, split2 = split1[0], split2[0]
    return split1, split2

下方代码是一个用于在给定数据加载器上执行一个 epoch 的训练或者是验证的函数。

def epoch(scope, loader, on_batch=None, training=False):
    model = scope["model"]
    optimizer = scope["optimizer"]
    loss_func = scope["loss_func"]
    metrics_def = scope["metrics_def"]
    scope = copy.copy(scope)
    scope["loader"] = loader
    metrics_list = generate_metrics_list(metrics_def)
    total_loss = 0
    if training:
        model.train()
    else:
        model.eval()
    for tensors in loader:
        if "process_batch" in scope and scope["process_batch"] is not None:
            tensors = scope["process_batch"](tensors)
        if "device" in scope and scope["device"] is not None:
            tensors = [tensor.to(scope["device"]) for tensor in tensors]
        loss, output = loss_func(model, tensors)
        if training:
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        total_loss += loss.item()
        scope["batch"] = tensors
        scope["loss"] = loss
        scope["output"] = output
        scope["batch_metrics"] = {}
        for name, metric in metrics_def.items():
            value = metric["on_batch"](scope)
            scope["batch_metrics"][name] = value
            metrics_list[name].append(value)
        if on_batch is not None:
            on_batch(scope)
    scope["metrics_list"] = metrics_list
    metrics = {}
    for name in metrics_def.keys():
        scope["list"] = scope["metrics_list"][name]
        metrics[name] = metrics_def[name]["on_epoch"](scope)
    return total_loss, metrics

2)参数说明

参数

推荐值

额外说明

batch_size

64

批次大小,默认64

train_test_ratio

0.7

训练集占数据集的比例,0.7即训练集70%测试集30%

learning_rate

0.001

学习率

weight_decay

0.005

AdamW专用,若修改优化算法需要修改train.py

epochs

1000

训练轮数

kernel_size

5

卷积核大小

filters

8, 16, 32, 32

卷积层channel数目

batch_norm

0

批量正则化,0为False,1为True

weight_norm

0

权重正则化,0为False,1为True

data_path

./data

数据集路径,视具体情况设置

save_path

./result

模型和训练记录的保存路径,视具体情况设置

model_name

DeepCFD_965.pdparams

具体加载的模型名称,后缀不能省略

3)部分训练日志如下:

Epoch #1

        Train Loss = 884808909.0

        Train Total MSE = 10197.3000353043

        Train Ux MSE = 3405.3426083044824

        Train Uy MSE = 4334.0962839376825

        Train p MSE = 2457.8616943359375

        Validation Loss = 53205074.5

        Validation Total MSE = 1027.7523040254237

        Validation Ux MSE = 419.7688029661017

        Validation Uy MSE = 543.9674920550848

        Validation p MSE = 64.01604872881356

Epoch #2

        Train Loss = 75408434.25

        Train Total MSE = 603.198411591199

        Train Ux MSE = 277.9321616481414

        Train Uy MSE = 303.4222437021684

        Train p MSE = 21.843986488987337

        Validation Loss = 17892356.5

        Validation Total MSE = 312.7194186970339

        Validation Ux MSE = 169.64230501853814

        Validation Uy MSE = 140.46789757680085

        Validation p MSE = 2.6092084981627384

5.实验对比

1)误差对比

2)计算效果对比

3)效果展示

1)ground-truth CFD (simpleFOAM) 和 DeepCFD 预测之间的比较,显示了速度分量和压力场,以及基于圆的形状 1 周围流动的绝对误差。

2)ground-truth CFD (simpleFOAM) 和 DeepCFD 预测的比较,显示了速度分量和压力场,以及围绕基于方形的形状2的流动绝对误差。

3)ground-truth CFD (simpleFOAM) 和 DeepCFD 预测的比较,显示了速度分量和压力场,以及基于菱形的形状 1 周围流动的绝对误差。

<think>嗯,用户想用PINN来做二维剪切圆柱绕流的流场预测,这个课题挺有意思的。首先,我需要回顾一下PINN的基本原理步骤,确保自己理解正确。PINN结合了神经网络数据驱动的学习方法,同时融入物理方程作为约束,这样可以在数据不足的情况下也能保持物理一致性。 首先,用户的问题是关于二维剪切流的,也就是流体绕过圆柱体时的流动情况。这种情况下,Navier-Stokes方程是必须考虑的,尤其是不可压缩流的情况。我需要确定方程的具体形式,比如二维的NS方程,包括连续性方程动量方程。可能需要简化成稳态或非稳态的情况,取决于具体问题。 接下来,构建神经网络的结构。输入层应该是二维的空间坐标(x, y),可能还有时间t,如果是非稳态的话。输出层可能需要预测速度场(u, v)压力p。隐藏层的设计需要合理,层数神经元数量可能需要根据问题复杂度调整,不过通常从几层开始尝试。 然后,损失函数的组成是关键。PINN的损失通常包括数据损失、方程损失边界条件损失。数据损失如果有实验或模拟数据的话,可以用来监督;方程损失则是让网络满足NS方程的残差;边界条件比如圆柱表面的无滑移条件,周围流场的自由来流条件等。这些都需要用适当的数学表达式表达,并加权求作为总损失。 数据准备方面,用户可能需要生成或获取流场的数据。如果没有真实数据,可能需要用传统CFD方法(如OpenFOAM)生成一些数据作为监督学习的部分。同时,在计算域内随机采样点,用于计算方程损失。边界上的点也需要采样,以施加边界条件。 训练过程中,可能需要选择合适的优化器,比如Adam,并调整学习率。由于NS方程的非线性复杂性,训练可能会比较困难,可能需要自适应权重来平衡不同损失项的影响,防止某一部分的损失主导训练过程。 验证部分,用户需要将PINN的预测结果与CFD或实验数据对比,比如速度分布、涡脱落频率等参数。可视化流线图、涡量图等也是必要的,以直观评估预测效果。 可能遇到的挑战包括训练不稳定、收敛困难,这时候可能需要调整网络结构,增加层数或神经元,或者调整损失权重。另外,物理方程的实现要确保正确,特别是梯度的计算,可能需要用自动微分来处理。 用户提供的引用中提到了低雷诺数圆柱绕流,这可能意味着他们的案例雷诺数较低,层流状态,这样NS方程可能相对容易处理。但如果是高雷诺数,可能需要考虑湍流模型,不过PINN本身可能通过数据驱动来捕捉复杂流动。 最后,用户可能需要具体的代码示例,比如如何定义网络、损失函数,以及训练循环。不过现在需要避免使用代码块,所以应该用文字描述步骤。同时,生成的相关问题可能涉及如何选择网络结构、处理高雷诺数流动、数据获取方法等。 总之,步骤大致分为问题定义、方程确定、网络构建、损失函数设计、数据准备、训练优化、验证分析。需要确保每个环节都考虑到物理约束数据的有效利用,才能实现准确的流场预测。</think>### 分步解析:使用PINN实现二维剪切圆柱绕流的流场预测 #### 1. **问题定义与物理方程建立** 二维剪切圆柱绕流的控制方程为不可压缩Navier-Stokes方程: $$ \begin{cases} \frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} + v \frac{\partial u}{\partial y} = -\frac{1}{\rho} \frac{\partial p}{\partial x} + \nu \left( \frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2} \right) \\ \frac{\partial v}{\partial t} + u \frac{\partial v}{\partial x} + v \frac{\partial v}{\partial y} = -\frac{1}{\rho} \frac{\partial p}{\partial y} + \nu \left( \frac{\partial^2 v}{\partial x^2} + \frac{\partial^2 v}{\partial y^2} \right) \\ \frac{\partial u}{\partial x} + \frac{\partial v}{\partial y} = 0 \end{cases} $$ 其中$(u,v)$为速度分量,$p$为压力,$\nu$为运动黏度,$\rho$为密度[^1]。 #### 2. **神经网络架构设计** - **输入层**:空间坐标$(x,y)$时间$t$(非稳态问题) - **输出层**:预测物理量$(u,v,p)$ - **隐藏层**:建议采用6-8层全连接网络,每层50-100个神经元,激活函数优先选择$\tanh$或自适应激活函数 #### 3. **损失函数构造** 总损失函数包含四部分: $$ \mathcal{L} = \lambda_1 \mathcal{L}_{\text{data}} + \lambda_2 \mathcal{L}_{\text{eq}} + \lambda_3 \mathcal{L}_{\text{bc}} + \lambda_4 \mathcal{L}_{\text{ic}} $$ - **数据损失**:利用少量CFD/实验数据监督 $$ \mathcal{L}_{\text{data}} = \frac{1}{N_d} \sum_{i=1}^{N_d} \left( |u(x_i,y_i,t_i) - u_i|^2 + |v(x_i,y_i,t_i) - v_i|^2 \right) $$ - **方程损失**:强制满足NS方程残差 $$ \mathcal{L}_{\text{eq}} = \frac{1}{N_e} \sum_{i=1}^{N_e} \left( |f_1(x_i,y_i,t_i)|^2 + |f_2(x_i,y_i,t_i)|^2 + |f_3(x_i,y_i,t_i)|^2 \right) $$ - **边界条件损失**:圆柱表面无滑移条件、远场边界条件等 $$ \mathcal{L}_{\text{bc}} = \frac{1}{N_b} \sum_{i=1}^{N_b} \left( |u(x_i^b,y_i^b,t_i^b)|^2 + |v(x_i^b,y_i^b,t_i^b)|^2 \right) $$ - **初始条件损失**(非稳态问题需要) #### 4. **数据准备策略** - **计算域**:建议取圆柱直径$D$的15-20倍范围 - **采样方法**: - 圆柱表面密集采样(边界层效应) - 尾流区加密采样 - 使用拉丁超立方采样(LHS)生成训练点 - **数据增强**:可通过对称性、周期性等物理特性生成伪数据 #### 5. **训练优化技巧** - 采用自适应权重调整(如NTK权重法) - 使用学习率衰减策略(如指数衰减) - 优先训练边界条件损失项 - 引入涡量-流函数公式简化计算(可选) #### 6. **验证与后处理** - **定量验证**:对比阻力系数$C_D$、升力系数$C_L$、斯特劳哈尔数$St$ - **定性验证**:可视化流线图、涡量云图、压力分布 - **误差分析**:计算相对$L_2$误差: $$ \epsilon = \frac{\sqrt{\sum (u_{\text{PINN}} - u_{\text{CFD}})^2}}{\sqrt{\sum u_{\text{CFD}}^2}} $$ #### 7. **典型实施流程** 1. 使用OpenFOAM生成基准CFD数据[^2] 2. 构建PINN网络并初始化参数 3. 分阶段训练:先边界条件→再初始条件→最后全方程约束 4. 动态调整损失权重$\lambda_i$ 5. 验证模型在未训练区域的泛化能力
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FastCAE2022

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

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

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

打赏作者

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

抵扣说明:

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

余额充值