文号
t79550
阅读
28049
回复
8
收藏
6
用浏览器做CFD
2016/04/10
IP:广东
现代浏览器可以高效地运行js程序,可以方便的绘图,所以这次我用html+js,向大家示范一个简单的CFD程序。
QQ截图20160410143903.jpg

上面这个水池是最终效果。先别急,往下看。

=====这是分隔线=====

首先,我们要建立这池水的简化模型。
假设这池水,液面的垂直速度足够小(水面足够平缓),可以作如下简化:
1. 可以用一维数组,描述从左到右液面高度。
2. 液面只传递纵波。
3. 有黏度参数,“液柱”之间有损耗

首先要初始化液面高度数组,随便填充点啥吧
var buffer = []
for(var i=0;i<128;i++){   buffer.push(.5*i); buffer init }< code></128;i++){>

仿真的每一步,都要计算多个参数,下面列出。

1. 液体在重力作用下,如果两个相邻的液柱有高度差,较高的液柱会受到向下的压力,较矮的液柱会受到向上的压力。简单的讲,设两个相邻液柱的液面高度差为delta_h, F 正比于 delta_h。

    //calculate force
    for(var i=0;i<buffer.length;i++)     {       if(i>0){
        //not start of array.
        forcebuffer[i] += buffer[i-1]-buffer[i];
      }
      if(i<buffer.length-1){          not end of array.         forcebuffer[i] +="buffer[i+1]-buffer[i];"       }     } < code></buffer.length-1){></buffer.length;i++)>


2. 液体具有质量,根据 F=ma, 加速度正比于受力,故速度正比于受力的积分。下面的代码将受力乘以一个因子,积分为速度。

//calculate vertical velocity
    for(var i=0;i<buffer.length;i++){       velocitybuffer[i] +="forcebuffer[i]" * .2;     } < code></buffer.length;i++){>


3. 液体具有黏度,可以近似认为两条液柱之间存在剪切力。
QQ截图20160410151001.jpg

看不懂也无所谓,结论就是:这个力正比于两条相邻液柱的相对速度。
因此,在上一段代码中,加入通过速度计算剪切力的项:

//calculate vertical velocity
    for(var i=0;i<buffer.length;i++){       var f="0;"       if(i>0&&i<buffer.length-1)       {         f="velocitybuffer[i+1]-velocitybuffer[i]"         + velocitybuffer[i-1]-velocitybuffer[i]         f*="0.2;" viscosity factor       }       forcebuffer[i] +="f;"       velocitybuffer[i] * .2;     } < code></buffer.length-1)></buffer.length;i++){>

其中的0.2,可用于控制液体黏度。黏度较低的液体,可以让高频振荡随液面传递得更远(衰减得更慢)。


4. 我们都知道1/2mv^2的公式:能量正比于速度的平方。在我们的简化模型中,没有模拟液体内部各种紊流,自然也就无法模拟这部分能量的损耗,但我们知道这种损耗在真实液体中是存在的。因此,我用了一个衰减因子(0.99)逐步衰减速度。相比不衰减的情况,水面在受到扰动后会逐渐趋于平静。

for(var i=0;i<buffer.length;i++){       velocitybuffer[i] *="  0.99;" damping     } < code></buffer.length;i++){>


5. 液面高度是对液面垂直速度的积分。这个很简单。
    //calculate vertical height
    for(var i=0;i<buffer.length;i++){       buffer[i] +="velocitybuffer[i]*0.5;"     } < code></buffer.length;i++){>

到此,一步仿真就结束了。


我使用了Chart.js控件来展示水池,因此我需要不断地将buffer[]的内容发给图表,然后刷新图表,以产生动画效果。
    //update chart
    for(var i=0;i<buffer.length;i++){       mynewchart.datasets[0].points[i].value="buffer[i];"     }     mynewchart.update();< code></buffer.length;i++){>


我通过定时器设定每秒仿真50步。
var timer = setInterval('step_on()',20)


水面一定要添加扰动才好玩,怎么添加扰动呢?我做了一个随机扰动函数,按一次按钮扰动一次。
function drop(){ //random drop on surface
  var m = Math.floor(Math.random()*10)+3;
  var i = Math.floor(Math.random()*(buffer.length-m))
  var k = Math.random()*90;
  for(var n=i;n<i+m;n++){     buffer[n]="k+Math.random()*10;"   } }< code></i+m;n++){>


最终效果:
QQ截图20160410152953.jpg


html和js源文件下载:在浏览器中可以直接运行

attachment icon HomemadeCFD.zip 13.87KB ZIP 151次下载
[ 修改于10年8个月前 - 2016/04/11 17:30:34 ]
novakon作者
10年8个月前IP:广东
815842
1楼
下载zip文件,解压得到html文件,用编辑器打开即可看到全部代码。
引用
评论
10年8个月前IP:澳大利亚
815845
2楼
真厉害 现在浏览器的脚本都可以做这么牛逼了
引用
评论
10年8个月前IP:陕西
815876
3楼
或许还可以试试用WebGL呈现下三维的情况。

js目前还是适合做一些轻量的应用,毕竟这玩意压缩后很适合网络传输。
比较繁重的运算任务扔给服务器。
引用
评论
novakon作者
10年8个月前IP:广东
815879
4楼
引用 drzzm32:
或许还可以试试用WebGL呈现下三维的情况。

js目前还是适合做一些轻量的应用,毕竟这玩意压缩后很适合网络传输。
比较繁重的运算任务扔给服务器。
WebGL需要比较繁琐的初始化,以及图形编程,用现成控件省事一点。但我有时间一定会做一个WebGL的版本。

话说,有谁愿意做一个命令行版本?
引用
评论
10年7个月前IP:广西
818686
5楼
波速跟液体深度有关吗?
引用
评论
10年7个月前IP:广西
818687
6楼
下载压缩包 下不了 点击链接就出乱码
引用
评论
novakon作者
10年7个月前IP:广东
818700
7楼
引用 迪纳米斯:
波速跟液体深度有关吗?
在这个程序中是无关的(假定水无限深)。
引用
评论
10年7个月前IP:广西
818701
8楼
程序很棒,如果水深曲线可以调整、还有位置可以定义、可以定义扰动波形频率幅度阻尼、这样就更有波浪槽的效果了。甚至比波浪槽还好用 。
模拟个海啸木有问题。
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的