2

I created a CPU Parallel.For loop in my code as follow:

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;
        });

The above code works fine and run on my CPU cores.

Want I want to do it to convert this code to a GPU For loop using "Alea GPU" library. So i tried the following:

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;
        });
    }

You can see that it is the exact same code as above but with Parallel.For changed for Gpu.Default.For. But when I run it I get the following error:

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]

I am not sure how to solve this error. Any help would be appreciated.

Update on what I tried after comments by NineBerry:

So it turns out the problem might be the Vector2 type because it might use properties. So I created my own struct which use Fields like so:

        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;

The rest of the code is pretty much the same as before. But I still get the same "i32 is not struct type." error.

Same error if I ditch all struct and use arrays of float instead:

    float[] m;
    float[] pX;
    float[] pY;
    float[] pnewX;
    float[] pnewY;
    float[] vX;
    float[] vY;

Code dump as per comment. Creating a new instance of the class should make it run. You will need to install nuget ALEA and ALEA.FODY . Also I think you need FSharp.Core to run 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;

        });
    }

}

}
Maxter
  • 716
  • 7
  • 15

1 Answers1

5

This is probably because you use the X and Y properties of the Vector2 struct type. Alea does not support properties according to the documentation:

Note that the current version of Alea GPU only supports fields in structs but not properties

See also Alea: "i32 is not struct type

NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • Ok so changing every Vertoc2[] to 2 float[] should work. I will try that and report back. Thank you – Maxter Sep 12 '18 at 13:09
  • Ok so I changed the type Vector2[] to a custom struct with no properties but I still have the same error. I will update my question with the new types – Maxter Sep 12 '18 at 23:05
  • Also changed all struct to arrays of floats and it'S not working (sorry for my last comment saying it worked, it was premature) – Maxter Sep 12 '18 at 23:37