马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
做离散相模拟的朋友应该都遇到过这个问题—— 你想模拟空化气泡的生成,但气泡该在哪冒出来?晶体该从哪析出?这些位置不是固定的,而是随流场瞬态变化的。 传统的做法是什么?手动划分几个 injection surface,硬编码几个位置,祈祷算出来的结果别太离谱。 但物理不是这样的。 真实场景中,成核位置是由局部压力、温度、相分数等条件实时决定的——它应该是一个动态筛选 + 随机采样的过程。 所以我写了 DynamicParticlesInjector。 它是怎么工作的?整个算法分五步,逻辑非常直接: 第一步:各进程各自收集候选单元 每个并行进程遍历自己负责的网格,逐个检查单元是否满足用户设定的物理条件。比如"温度低于接近温度"——满足条件的,就把它的质心坐标存下来。候选数量不确定?没关系,数组初始分配 128 个位置,不够就翻倍扩容,总能装下。因此这个算法是不需要操心数组容量不够的问题,但如果网格容量比较大,还是建议给一个较大的值(2^n),避免多次翻倍。 第二步:所有候选坐标汇总到主节点 并行计算下,网格分散在各个计算节点上。主节点(进程 0)依次向其他节点发出信号,其他节点收到后将本地的候选坐标发回。一轮点对点通信下来,主节点就拿到了全场的候选池。 第三步:主节点随机采样 主节点从全局候选池中随机抽取指定数量(P_NUM)的位置。采样是有放回的——但在实际工程中,候选池动辄几十上百万个单元,只采十来个,重复概率极低(百万取十,重复概率约万分之一),完全可以忽略。如果候选单元数少于要采的粒子数,采样数会自动降为候选单元数,不会出错。 第四步:采样结果广播到所有节点 这一步是并行通信的关键。Fluent UDF 没有直接暴露 MPI 广播函数,那怎么让所有节点拿到相同的结果?这里用了一个稳定的技巧——全局求和代替广播:只有主节点持有采样坐标的值,其他节点对应位置全是零。对全体做一次 PRF_GRSUM,零加非零等于非零,所有节点就同时拿到了完全相同的坐标。这个方法在各个 Fluent 版本上都兼容,通信开销也微乎其微。 第五步:重定位粒子 每个节点拿到采样坐标后,遍历自己负责的注射源粒子——前 N 个粒子移到采样坐标上,多余的粒子标记移除。因为所有节点拿到的是同一组坐标,而 group/cone 注射源的粒子集中在同一个节点上,所以最终恰好有 N 个粒子被精确放置在采样位置,不多不少。 下一个时间步,整个过程重新来一遍。 候选池变了,采样位置跟着变,粒子的注入位置自然跟着流场走——这才是动态成核该有的样子。 核心优势- 无需预定义注入区域 — 粒子自动出现在满足物理条件的地方
- 完全并行化 — 自动跨进程通信,大规模并行算例直接用
- 一行代码定制条件 — 把 if (center[1] > 0) 换成你的判断,比如 C_P(c,t) < P_sat
- 采样自适应 — 有效单元不够时自动降采样,不会报错
适用场景空化成核、晶体析出、气泡生成、溶质沉淀——任何"核从哪里来"的动态成核问题。
|