我在代码中创建了一个 CPU Parallel.For 循环,如下所示:
Vector2[] p;
Vector2[] pnew;
Vector2[] v;
float[] m;
Parallel.For(0, N, i =>
{
double dx;
double dy;
double invr;
double invr3;
double f;
double ax;
double ay;
double eps = 0.02;
ax = 0;
ay = 0;
for (int j = 0; j < N; j++)
{
dx = p[j].X - p[i].X;
dy = p[j].Y - p[i].Y;
invr =1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
invr3 = invr * invr * invr;
f = m[j] * m[i] * invr3;
ax += f * dx;
ay += f * dy;
}
pnew[i].X = (float)(p[i].X + dt * v[i].X + 0.5 * dt * dt * ax); /* save new position of particle "i" */
pnew[i].Y = (float)(p[i].Y + dt * v[i].Y + 0.5 * dt * dt * ay);
v[i].X += dt * (float)ax; /* update velocity of particle "i" */
v[i].Y += dt * (float)ay;
});
上面的代码工作正常,可以在我的 CPU 内核上运行。
希望我想使用“Alea GPU”库将此代码转换为 GPU For 循环。所以我尝试了以下方法:
Vector2[] p;
Vector2[] pnew;
Vector2[] v;
float[] m;
[GpuManaged]
public void calculForceGPU()
{
Gpu.Default.For(0, N + 1, i =>
{
double dx;
double dy;
double invr;
double invr3;
double f;
double ax;
double ay;
double eps = 0.02;
ax = 0;
ay = 0;
for (int j = 0; j < N; j++)
{
dx = p[j].X - p[i].X;
dy = p[j].Y - p[i].Y;
invr = 1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
invr3 = invr * invr * invr;
f = m[j] * m[i] * invr3;
ax += f * dx;
ay += f * dy;
}
pnew[i].X = (float)(p[i].X + dt * v[i].X + 0.5 * dt * dt * ax); /* save new position of particle "i" */
pnew[i].Y = (float)(p[i].Y + dt * v[i].Y + 0.5 * dt * dt * ay);
v[i].X += dt * (float)ax; /* update velocity of particle "i" */
v[i].Y += dt * (float)ay;
});
}
您可以看到它与上面的代码完全相同,但将 Parallel.For 更改为 Gpu.Default.For。但是当我运行它时,我收到以下错误:
i32 is not struct type.
Source location stack:
-> in C:\Users\...\Simulation.cs(628,21-628,42)
-> at ....Simulation.[Void <calculForceGPU>b__36_0(Int32)]
-> at Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32,
System.Action`1[System.Int32])]
-> at defining runtime32 (sm52,32bit)
Loading method as kernel:
-> Method: Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32,
System.Action`1[System.Int32])]
-> InstanceOpt: <None>
-> Argument.#0: 0
-> Argument.#1: 1025
-> Argument.#2: System.Action`1[System.Int32]
Getting or loading method as kernel:
-> Method: Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32,
System.Action`1[System.Int32])]
-> InstanceOpt: <None>
-> Argument.#0: 0
-> Argument.#1: 1025
-> Argument.#2: System.Action`1[System.Int32]
我不知道如何解决这个错误。任何帮助,将不胜感激。
更新我在 NineBerry 评论后尝试的内容:
所以事实证明问题可能是 Vector2 类型,因为它可能使用属性。所以我创建了自己的结构,它使用如下字段:
struct Vector2Struct
{
public float X;
public float Y;
public Vector2Struct(float x, float y)
{
X = x;
Y = y;
}
}
Vector2Struct[] p;
Vector2Struct[] pnew;
Vector2Struct[] v;
float[] m;
其余的代码与以前几乎相同。但我仍然得到相同的“i32 不是结构类型”。错误。
如果我放弃所有结构并改用浮点数组,则会出现同样的错误:
float[] m;
float[] pX;
float[] pY;
float[] pnewX;
float[] pnewY;
float[] vX;
float[] vY;
根据评论转储代码。创建该类的新实例应使其运行。您将需要安装 nuget ALEA 和 ALEA.FODY 。另外我认为你需要 FSharp.Core 来运行 Alea
using System;
using Alea;
using Alea.Parallel;
namespace GalaxyTest
{
public class Simulation
{
// param
object[] param;
// masses
float[] m;
float[] pX;
float[] pY;
float[] pnewX;
float[] pnewY;
float[] vX;
float[] vY;
// data
static int N;
double ratioPM;
double ratioMasse;
int Np;
int Nm;
int distribution;
int simulType;
float dt = 0.01F;
double eps = 0.02;
float Rrp = 1;
float Rrm = 10;
public Simulation() //Constructor
{
Initializer();
updatePointGPUAlea();
}
private void Initializer()
{
// Settings
N = 1024;
ratioPM = 0.25;
ratioMasse = 1;
Np = 256;
Nm = 769;
distribution = 0;
simulType = 1;
// vector Initialisation
pX = new float[N];
pY = new float[N];
pnewX = new float[N];
pnewY = new float[N];
vX = new float[N];
vY = new float[N];
m = new float[N];
// compute masses
for (int i = 0; i < Np; i++)
{
m[i] = 1;
}
for (int i = Np; i < Nm; i++)
{
m[i] = -1 * (float)ratioMasse;
}
Random r = new Random();
double R;
double teta;
double Rp;
double Rn;
float signe1, signe2, signe3, signe4;
// Init pos = random shell
for (int i = 0; i < N; i++)
{
Rp = 2.61;
Rn = 45;
teta = r.NextDouble() * 2 * Math.PI;
signe1 = Math.Sign(r.NextDouble() - 0.5);
signe2 = Math.Sign(r.NextDouble() - 0.5);
signe3 = Math.Sign(r.NextDouble() - 0.5);
signe4 = Math.Sign(r.NextDouble() - 0.5);
if (m[i] > 0)
{
pX[i] = (float)(Rp * Math.Cos(teta)) + 400 / 2;
pY[i] = (float)(Rp * Math.Sin(teta)) + 400 / 2;
vX[i] = (float)(r.NextDouble() * Rrp * signe1 + Math.Sqrt(Np) / 12 * 3 * Math.Sin(teta) * (0.4 - 1 / Math.Sqrt(10 + Rp)) * 3);
vY[i] = (float)(r.NextDouble() * Rrp * signe2 - Math.Sqrt(Np) / 12 * 3 * Math.Cos(teta) * (0.4 - 1 / Math.Sqrt(10 + Rp)) * 3);
}
else
{
pX[i] = (float)(Rn * Math.Cos(teta)) + 400 / 2;
pY[i] = (float)(Rn * Math.Sin(teta)) + 400 / 2;
vX[i] = (float)r.NextDouble() * Rrm * signe3;
vY[i] = (float)r.NextDouble() * Rrm * signe4;
}
}
}
public void updatePointGPUAlea()
{
calculForceGPU();
for (int i = 0; i < N; i++)
{
// Update de la position
pX[i] = pnewX[i];
pY[i] = pnewY[i];
}
}
[GpuManaged]
public void calculForceGPU()
{
Gpu.Default.For(0, N + 1, i =>
{
double dx;
double dy;
double invr;
double invr3;
double f;
double ax;
double ay;
ax = 0;
ay = 0;
for (int j = 0; j < N; j++)
{
dx = pX[j] - pX[i];
dy = pY[j] - pY[i];
invr = 1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
invr3 = invr * invr * invr;
f = m[j] * m[i] * invr3;
ax += f * dx;
ay += f * dy;
}
pnewX[i] = (float)(pX[i] + dt * vX[i] + 0.5 * dt * dt * ax); /* save new position of particle "i" */
pnewY[i] = (float)(pY[i] + dt * vY[i] + 0.5 * dt * dt * ay);
vX[i] += dt * (float)ax; /* update velocity of particle "i" */
vY[i] += dt * (float)ay;
});
}
}
}