简介Basilisk 是流体力学与地球物理研究中广泛使用的开源数值模拟框架也是许多理工科博士生推进科研课题的核心工具。这份个人学习资源围绕 Basilisk 模拟实践系统梳理了 C 语言源码、Shell 脚本、数值方法与结果可视化等环节能够帮助正处于入门阶段或课题探索期的研究生解决环境配置、算例修改与批量仿真的常见问题。包内共 14 个文件整体大小约 508KB以 .c 求解器、.h 头文件、.sh 容器脚本和 Makefile 为主同时附带 README 说明、License 许可与效果示意图目录结构清晰便于按需提取。内容涉及有限体积法、OpenMP 并行计算、gnuplot/ParaView 可视化以及 Git 版本管理等关键技术bubble 系列算例代码和自动化容器脚本提供了可直接复用的实验模板。目前已有 211 人浏览学习该资源适合需要快速上手 Basilisk、借鉴完整模拟工作流的科研用户。1. 为什么博士课题要把CFD赌在Basilisk模拟上对一个做流体力学相关博士课题的人来说Basilisk模拟这四个字通常不是一个可选项里的名字而是意味着“把界面问题往死里算”默认状态下它就用自适应的四叉树网格守着VOF界面从单液滴松弛到气泡溃灭网格加密全自动走。我和很多同事选择它不是因为它比OpenFOAM更简单而是因为复杂界面问题的收敛精度和内存效率更好。代价也很直接源码要自己下载、环境变量要自己整理、算例要用C文件配制批量化运行通常交给Shell脚本来管。C Shell在这套工作流里会有特殊存在感因为不少学院机群的历史账户默认就是csh/tcsh切bash反而不顺。这篇博文就把从下载源码到批量跑完整条链路的实际操作说清楚。2. Basilisk下载与C Shell编译环境搭建2.1 下载哪些东西、源码目录长什么样Basilisk主体是一套C语言源码外加少量Python脚本用于把带宏的“类C文件”翻译成真正的C源码。下载这一步最忌讳只从网页点Zip包下载那样会丢掉子模块编译时根本找不到。常见做法是使用git克隆并同步子模块确保目录结构完整。mkdir -p ~/basilisk cd ~/basilisk git clone --recursive 官方仓库地址 basilisk cd basilisk ls -F参数说明--recursive会在克隆主仓库后把依赖的子模块一并拉取如果拉取中途断网不要急着重来执行git submodule update --init --recursive就能补齐缺失部分。克隆完成后ls里应当能看到basilisk/、examples/、doc/这样的目录其中basilisk/才是求解器本体。这里注意$HOME/basilisk和$HOME/basilisk/basilisk两层目录很容易绕晕后面所有环境变量都指向内层这个basilisk目录。依赖方面至少要有gcc、make、python3以及基础数学库和pkg-config。如果系统是CentOS系yum install gcc make python3 pkgconfig一条命令能省去大部分烦恼Ubuntu系对应的是apt-get install build-essential python3 pkg-config。磁盘预留20GB以上别看着源码只有几十MB真正占空间的是算例输出和自适应网格的临时文件。2.2 在C Shell里写死环境变量Basilisk的Makefile在设计上没有做“安装到系统路径”那一套它依赖一个叫BASILISK的环境变量来定位自己和规划编译输出。所以第一步不是运行./configure而是把环境变量写进C Shell的配置里。这里给出的是~/.cshrc的标准写法# ~/.cshrc setenv BASILISK $HOME/basilisk/basilisk setenv BASILISK_CFLAGS -O2 setenv CC gcc alias qcc make qcc配置说明BASILISK必须指向内层源码目录写错层级的表现通常是编译某个算例时报basilisk.h: No such file or directory。BASILISK_CFLAGS控制编译优化级别本地调试建议用-O2集群跑长算例时再改成-O3 -marchnative两者算出来的结果在同一参数下应当在后几位小数上才有差别。alias qcc这条不是必须的但对经常手敲编译命令的人能省事之后在算例目录里敲qcc 文件就能走Basilisk的完整预处理流程。写完配置后执行source ~/.cshrc或者直接重新登录一次用下面的命令确认变量已生效echo $BASILISK能打印出路径就说明Shell能抓到源码目录了。这里有个细节如果在bash里执行source ~/.cshrc大概率会报一堆语法错误因为setenv是C Shell的语法一定要先进入csh或tcsh。我一般会在账户根目录看一眼默认Shellecho $SHELL返回/bin/csh才继续往下走。2.3 最小化编译make 到 examples环境变量就绪后编译本身一点都不神秘。进入源码根目录让make根据自己的规则处理cd $BASILISK make -j4参数说明-j4表示4个编译线程并行本地如果只做小算例-j2也够编译机内存小于4GB时不要盲目加并行数Basilisk预处理阶段会同时展开多个模板线程太多容易卡顿。第一次编译输出的日志非常长建议用make -j4 ! build.log把信息写进文件失败时直接看文件尾部比在终端里往回翻页省事。编译完成后源码目录里会生成一堆辅助命令和链接库其中有qcc等脚本。为了验证整套链路的真实可用性我最常做的是编译官方示例把算例跑出曲线图来cd $BASILISK/examples make -j4这里不必把examples全部编完挑一个与博士课题最接近的比如界面流动类的单目录cd viscous-drop make能编译出一个可执行文件并正常启动就说明从下载到编译的整条链路已经被打通了。如果编译都过不去接下来不用急着深挖算例参数先看编译报错的原因绝大多数是缺少依赖头文件而不是代码本身的问题。3. 用C Shell封装一个Basilisk算例的完整跑批流程3.1 一个算例的最小文件结构Basilisk的算例目录通常只有两个文件.c源文件和Makefile。.c文件写的不是普通的C程序而是带Basilisk宏描述的“问题定义文件”所以它开头总是一串#include把要用的网格方法、方程组和界面方法都引进来。下面是一个标准的二维液滴松弛算例#include grid/multigrid.h #include navier-stokes/centered.h #include vof.h #include tension.h double sigma 0.1; double mu 0.01; int main() { init_grid (128); double R 0.2; fraction (f, sq(x) sq(y) - sq(R)); const face vector muv[] {mu, mu}; mu muv; f.sigma sigma; run(); }逻辑说明init_grid定义最粗网格层数fraction (f, expr)用解析表达式在网格上初始化液滴界面f1表示液相f0表示气相muv把动力粘度赋给整个计算域f.sigma设置表面张力系数。这些字段名不是随便写的f是VOF模块里默认的界面体积分数场sigma是表面张力参数。如果你照着某个教程抄了这段代码却运行报错先检查第6行附近的centered.h与vof.h的引入顺序Navier-Stokes求解器必须在VOF之前引入否则宏展开出来的物理量声明不全。3.2 C Shell脚本自动生成不同参数的算例博士研究里最常见的操作不是跑一个算例而是把某个参数从0.01扫到0.1每个值都要一组结果。手工复制目录、改参数、逐个编译很蠢也容易漏改字段。我一般会准备一个参数模板文件在里面写上占位符SIGMA再用C Shell的循环和sed把这个占位符替换成具体数值生成多个算例目录并行计算#!/bin/csh -f # 批量生成不同表面张力系数的算例 set template $BASILISK/templates/droplet.c set sigmas (0.05 0.10 0.20) foreach s ( $sigmas ) set d run_sigma_$s mkdir -p $d sed s/SIGMA/$s/ $template $d/droplet.c cp $BASILISK/templates/Makefile $d/ ( cd $d make droplet ! make_$s.log ./droplet ! run_$s.log ) end wait echo all batch jobs are done脚本说明foreach是C Shell的循环结构遍历括号里由空格隔开的参数列表每轮循环先建目录再用sed把模板里的SIGMA替换成当前参数最后一行用( ... ) 把每个算例放到后台子Shell里运行wait等所有子进程退出后再输出完成提示。注意!是C Shell里“强制覆盖重定向”的写法在bash里只会看到语法错误要改成。这里有一个并行度的陷阱如果你的计算节点只有16核sigmas列表里有20个值脚本会把20个进程全部拉起来CPU调度反而让每个算例都变慢。更稳的写法是控制并发数用jobs -p数一下后台进程数达到上限就先wait一组再继续set max_parallel 8 foreach s ( $sigmas ) set d run_sigma_$s # ... 生成算例目录 ... ( cd $d ./droplet ! run_$s.log ) set job_count jobs -p | wc -l if ( $job_count $max_parallel ) wait end wait参数说明jobs -p | wc -l统计当前Shell持有的后台任务数是C Shell脚本里控制并发最简单的方法。每启动一个算例后就检查一次达到8个就等待全部完成避免单机过载。3.3 接进本地nohup和集群调度前台运行长算例不是常态要么用nohup把任务挂在终端后面要么交给集群调度器。万一是远程登录跑的算例终端一断进程就没了所以脚本里直接这样写nohup nice -n 10 ./droplet ! run_$s.log 参数说明nohup让进程忽略挂断信号SSH断开也不会被杀nice -n 10降低进程优先级避免影响同机其他用户的作业。如果课题组的集群用的是PBS/TorqueC Shell脚本只需要多生成一个作业文件把编译好的二进制文件路径填进去再用qsub job.pbs提交。交给调度器之后算例的输入输出文件都要用绝对路径因为在C Shell里用cd进入某个目录后qsub不一定把那个工作目录带过去。4. Basilisk模拟的核心参数与排错经验4.1 MAXLEVEL 与自适应细化容差Basilisk最吸引人的地方在于网格自适应但很多人第一次使用时会误以为init_grid (128)里的128就是最终精度。实际上那个数字只决定最粗网格的单元数真正决定界面分辨率的叫MAXLEVEL在.c文件里这样设置init_grid (32); int MAXLEVEL 9;通常把这写进main()前面再配合adapt_wavelet事件在每一时间步里驱动加密event adapt (i) { adapt_wavelet ({u, f}, (double[]){0.01, 0.01, 0.001}, MAXLEVEL); }参数说明adapt_wavelet第一个参数是参与判据的场一般同时把速度场u和体积分数场f放进去第二个数组里的三个数字分别对应u.x、u.y、f三个场上允许的最大误差第三个数字是加密上限。误差值越小网格越密计算成本指数上升。我的经验是先从1e-2起步跑短时间再逐步收紧到1e-3不要一上来就0.0001。4.2 时间步长和物理参数会把解算崩掉Basilisk能自动决定时间步但上限由CFL和DT控制。CFL默认约0.5对大多数表面张力主导的算例已经够用但在高粘度比或高密度比的界面附近0.5会在界面波速上给出过大的步长使数值解在几个时间步内翻出NaN。通常在脚本里这样约束CFL 0.25; DT 1e-3;参数说明CFL0.25是把自动时间步减半为界面波和毛细波留出裕量DT1e-3相当于硬顶防止某些跳变的早期阶段步子迈太大。如果算例出现NaN我不会先去调边界条件而是先怀疑这两个值。另一方面f.sigma设置过大会让界面振荡在数值上无法被时间步分辨这时与其降低时间步不如检查表面张力特征时间尺度是否与网格尺寸匹配。4.3 常见报错与对策表把这几年积累的Bug类型列成一张表遇到问题直接按图像名字检索比逐行读日志快得多。现象可能原因处理办法编译时basilisk.h: No such file or directoryBASILISK环境变量未设置或路径指向外层目录执行echo $BASILISK确认指向内层源码目录运行时Segmentation fault网格规模超过内存或init_grid与MAXLEVEL配合不当降低MAXLEVEL到先用一半跑通输出数据全是 NaNCFL过高、sigma过大或粘度比极端将CFL降到0.25DT设置硬上限make找不到pkg-config缺少编译工具链安装pkg-config或pkgconf算例能跑但速度远低于预期自适应加密过于频繁调大adapt_wavelet容差数组里的误差值表格里最后一条容易被忽视。adapt_wavelet在每个时间步调用时都会重新评估整张网格如果三个误差阈值都设得很小适配过程的开销会超过计算本身。更合理的做法是每2或4个时间步调用一次自适应事件用if (i % 4 0)包住精度损失微小速度能提升30%以上。5. 把Basilisk模拟运行参数沉淀成可复现的博士研究记录博士课题做了半年最怕的不是算不完而是算完后说不清“这个图是哪个版本、哪组参数跑出来的”。Basilisk源码迭代频繁同一段算例代码在不同commit下跑出的界面形态可能在小数点后几位有差异。我在跑批脚本里塞进一个记录动作用C Shell生成meta文件随算例归档set commit git -C $BASILISK rev-parse --short HEAD set date date %Y%m%d_%H%M%S cat ! $d/meta.txt EOF simulation_commit: $commit simulation_start: $date sigma: $s maxlevel: 9 cfl: 0.25 EOF逻辑说明git rev-parse --short HEAD取当前Basilisk源码的短提交号date生成开始时间cat !用here-doc把关键参数写进文本。日后整理论文时每个算例目录里的meta.txt就是证据链复现不了可以反推到代码版本这个习惯比任何实验记录本都可靠。要验证某组结果是否可信在扫描参数时还要多写一个收敛对拍对关键参数跑一遍MAXLEVEL9再跑一遍MAXLEVEL10把界面位置的最大差值输出到compare.out。差值小于设定位数说明当前网格精度已经够用差值仍在一个量级上就说明算的是“网格依赖解”写论文前得把最高层级再提一档。检查这点只需要在整个批量结束后运行一个小循环foreach d (run_sigma_*) echo $d tail -n 1 $d/interface_mean.txt end这样每个参数目录的末行物理量一次性摊在屏幕上博士论文里的参数依赖图就靠这些数字拼出来。本文还有配套的精品资源点击获取