我有一个简单的程序,它的核心是一个浮动的二维数组,据说代表了气体浓度,我一直试图想出一个简单的算法来模拟向外扩展的气体,如云,最终结束在整个电网中到处都是相同浓度的气体。
例如,给定的州进展可能是: (为简单起见,使用整数)
开始状态
00000
00000
00900
00000
00000
算法一次通过后的状态
00000
01110
01110
01110
00000
另外一个pas应该给出一个5x5网格,所有网格都包含值0.36(9/25) 我已经在纸上试过了,但无论我如何尝试,我都无法绕过算法来做到这一点。
所以我的问题是,我应该如何着手尝试编写这种算法?我已经尝试了一些东西,应用卷积,试图依次取出每个网格单元并将其分发给它的邻居,但它们最终都会产生不良影响,例如最终以比我最初开始时更少的气体结束,或者所有气体运动都在一个方向,而不是从中心向外扩展。我真的无法理解它并且会感激任何帮助。
答案 0 :(得分:6)
如果不忽视对流或流体动力学/质量传递问题,这可能是扩散问题。如果从头开始解决,你可以从欧拉(固定控制体积)观点的质量和动量守恒方程开始。
这是一个暂时性问题,因此您需要执行集成以将状态从时间t(n)推进到t(n + 1)。你展示了一个网格,但没有关于你如何及时解决的问题。您尝试过哪种集成方案?明确?隐?曲柄尼科尔森?如果你不知道,你没有正确解决问题。
我真正喜欢这本书的一本书是S.W. Patankar的"Numerical Heat Transfer and Fluid Flow"。现在有点过时了,但我喜欢这种治疗方法。它在29年后仍然很好,但自从我阅读这个主题以来,可能会有更好的文本。对于第一次看到它的人来说,我认为这是平易近人的。
答案 1 :(得分:5)
在您给出的示例中,您的第二阶段的核心为1。通常扩散需要浓度梯度,因此大多数扩散相关技术在下一次迭代时不会改变中间的1(在第一次迭代之后它们也不会达到该状态,但是一旦你有了它就会更容易看到得到了一块相等的价值观)。但正如你帖子上的评论者所说,这不太可能是网络运动的原因。减少气体可能是边缘效应,但也可能是舍入误差的问题 - 将cpu设置为均匀的一半,并且总计气体并立即应用校正。
答案 2 :(得分:2)
看起来你正试图用Neumann边界条件(边缘绝缘)来实现热方程的有限差分求解器。关于这种事情有很多文献。 finite difference method上的维基百科页面描述了一种简单但稳定的方法,但是对于Dirichlet边界条件(边缘处的恒定密度)。修改边界条件的处理应该不会太困难。
答案 3 :(得分:1)
看起来你想要的东西就像平滑算法,常用于像Photoshop这样的程序,或旧学校的演示效果,就像这个简单的Flame Effect。
无论您使用何种算法,它都可能会帮助您double buffer您的阵列。
典型的平滑效果如下:
begin loop forever
For every x and y
{
b2[x,y] = (b1[x,y] + (b1[x+1,y]+b1[x-1,y]+b1[x,y+1]+b1[x,y-1])/8) / 2
}
swap b1 and b2
end loop forever
答案 4 :(得分:1)
见Tom Forsyth's Game Programming Gems article。看起来它符合您的要求,但如果没有,那么至少应该给您一些想法。
答案 5 :(得分:1)
为简单起见,这是1D的解决方案:
初始设置在原点()处的浓度为9,在所有其他正负坐标处的浓度为0.
初始状态: 0 0 0 0(9)0 0 0 0
查找下一个迭代值的算法是从相邻邻域的原点和平均电流浓度开始。原点值是边界情况,并且考虑原点值及其两个邻居同时进行平均,即3个值中的平均值。所有其他值在2个值中有效平均。
迭代1后: 0 0 0 3(3)3 0 0 0
迭代2后的: 0 0 1.5 1.5(3)1.5 1.5 0 0
迭代3后的: 0 .75 .75 2(2)2 .75 .75 0
迭代4后的: .375 .375 1.375 1.375(2)1.375 1.375 .375 .375
您在循环中执行这些迭代。每n次迭代输出状态。您可以引入一个时间常数来控制多少次迭代代表一秒钟的时钟。这也是整数坐标表示的长度单位的函数。对于给定的H / W系统,您可以根据经验调整此值。您还可以引入稳态容差值来控制程序何时“所有相邻值都在此容差范围内”或“迭代之间的值没有变化超过此容差”,因此算法已达到稳态解决方案。
答案 6 :(得分:0)
给定起始浓度的每次迭代的浓度可通过以下等式获得:
concentration = startingConcentration/(2*iter + 1)**2
iter是时间迭代。所以对你的例子来说。
startingConcentration = 9
iter = 0
concentration = 9/(2*0 + 1)**2 = 9
iter = 1
concentration = 9/(2*1 + 1)**2 = 1
iter = 2
concentration = 9/(2*2 + 1)**2 = 9/25 = .35
您可以在每个“时间步长”之后设置数组的值