2

我在代码中创建了一个 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;

        });
    }

}

}
4

1 回答 1

5

这可能是因为您使用了结构类型的XandY属性。根据文档Vector2,Alea 不支持属性:

请注意,当前版本的 Alea GPU 仅支持结构中的字段,但不支持属性

另请参阅Alea:“i32 不是结构类型

于 2018-09-12T01:41:29.587 回答