Я создал цикл 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;
});
Приведенный выше код работает нормально и работает на ядрах моего процессора.
Хочу сделать это, чтобы преобразовать этот код в цикл GPU For с использованием библиотеки "Alea GPU". Поэтому я попробовал следующее:
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;
});
}
}
}