这是我为自己创建的一个简单的逻辑编程和优化练习法,偶然发现了它。
我有一个简单方案的数值模拟。考虑一些储液器(或电容器)Cm
,该储液器经常随着压力而上升。让我们将其当前状态称为Vm
:
根据以下逻辑,它的输出端有一个可以打开或关闭的阀或闸G
:
Vm
超过某个阈值时,将其命名为Vopen
:Vm > Vopen
Ia
大于某些Ihold
:Ia > IHold
我正在对此进行数值ODE求解,即在每个(相等,较小)的时间步dt处确定Vm
和Ia
。有以下三种变体:
float Vm=0.0, Ia=0.0, Vopen, Ihold, Ra, dt;
int G=0;
Vm = Vm + (-Ia*G)*dt;
G |= (Vm > Vopen);
Ia = Ia + (Vm*Ra*G)*dt;
G &= (Ia > Ihold);
int Gv; // temporary var
Vm = Vm + (-Ia*G)*dt;
Gv = (Vm > Vopen) ? 1 : G;
Ia = Ia + (Vm*Ra*Gv)*dt;
G = (Ia > Ihold) ? Gv : 0;
// cache new state first
float Vm1 = Vm + (-Ia*G)*dt;
float Ia1 = Ia + (Vm*Ra*G)*dt;
// update memory
G = ( Vm1 > Vopen ) || (( Ia1 > Ihold ) && G);
Vm = Vm1;
Ia = Ia1; // not nesesary to cache, done for readibility
PS。我正在尝试针对SSE优化它,然后(单独)针对OpenCL(如果有优化提示)
PPS。对于那些好奇的人,这里是my working simulator,涉及此门(html / js)
答案 0 :(得分:1)
从整体上讲,它们是相同的,应该都能满足您的需求。
您的序列号将产生半步。这意味着,如果将其分解为离散描述,则V(t)可以描述为I(t)之前的1/2 dt。第一个将使G在每个半步中变化,第二个将G与I同步。但是由于您不评估中间的G并不重要。 V也没有真正的问题,我相距半步,但您应牢记,但也许应该使用矢量{V(t),(I(t-1)+ I(t ))/ 2,G(t)}。
并行代码将使它们全部处于同一时间步。
对于纯线性问题,直接积分是一个很好的解决方案。高阶ode求解器不会为您买任何东西。纯线性系统的状态空间表示仅以不同的方式编写相同的直接积分。
对于SIMD优化,无需做任何准备。您需要逐步评估,因为您要按V更新I和按I更新V。这意味着您无法并行运行这些步骤,这使得不可能进行许多有趣的优化。