现代浏览器可以高效地运行js程序,可以方便的绘图,所以这次我用html+js,向大家示范一个简单的CFD程序。
首先,我们要建立这池水的简化模型。
假设这池水,液面的垂直速度足够小(水面足够平缓),可以作如下简化:
可以用一维数组,描述从左到右液面高度。
液面只传递纵波。
有黏度参数,“液柱”之间有损耗
首先要初始化液面高度数组
<code class="lang-js">var buffer = []
for(var i=0;i<128;i++){ buffer.push(.5*i); buffer init }< code></128;i++){></code>
仿真的每一步,都要计算多个参数,下面列出。
1.液体在重力作用下,如果两个相邻的液柱有高度差,较高的液柱会受到向下的压力,较矮的液柱会受到向上的压力。简单的讲,设两个相邻液柱的液面高度差为delta_h, F 正比于 delta_h。
<code class="lang-js">
//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++)></code>
2.液体具有黏度,可以近似认为两条液柱之间存在剪切力。
看不懂也无所谓,结论就是:这个力正比于两条相邻液柱的相对速度。
因此,在上一段代码中,加入通过速度计算剪切力的项:
<code class="lang-js">
//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++){></code>
其中的0.2,可用于控制液体黏度。黏度较低的液体,可以让高频振荡随液面传递得更远(衰减得更慢)。
我们都知道1/2mv^2的公式:能量正比于速度的平方。在我们的简化模型中,没有模拟液体内部各种紊流,自然也就无法模拟这部分能量的损耗,但我们知道这种损耗在真实液体中是存在的。因此,我用了一个衰减因子(0.99)逐步衰减速度。相比不衰减的情况,水面在受到扰动后会逐渐趋于平静。
<code class="lang-js">
for(var i=0;i<buffer.length;i++){ velocitybuffer[i] *=" 0.99;" damping } < code></buffer.length;i++){></code>
5.液面高度是对液面垂直速度的积分。这个很简单。
<code class="lang-js"> //calculate vertical height
for(var i=0;i<buffer.length;i++){ buffer[i] +="velocitybuffer[i]*0.5;" } < code></buffer.length;i++){></code>
到此,一步仿真就结束了。
我通过定时器设定每秒仿真50步。
<code class="lang-js">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++){></code>