Skip to content
Snippets Groups Projects
n-body.py 31.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    NBody Demonstrator implemented in OpenCL, rendering OpenGL
    
    By default, rendering in OpenGL is disabled. Add -g option to activate.
    
    Part of matrix programs from: https://forge.cbp.ens-lyon.fr/svn/bench4gpu/
    
    
    CC BY-NC-SA 2011 : Emmanuel QUEMENER <emmanuel.quemener@gmail.com>
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    Cecill v2 : Emmanuel QUEMENER <emmanuel.quemener@gmail.com>
    
    Thanks to Andreas Klockner for PyOpenCL:
    http://mathema.tician.de/software/pyopencl
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    """
    import getopt
    import sys
    import time
    import numpy as np
    import pyopencl as cl
    
    import pyopencl.array
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    from numpy.random import randint as nprnd
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    def DictionariesAPI():
    
        Marsaglia = {"CONG": 0, "SHR3": 1, "MWC": 2, "KISS": 3}
        Computing = {"FP32": 0, "FP64": 1}
        Interaction = {"Force": 0, "Potential": 1}
        Artevasion = {"None": 0, "NegExp": 1, "CorRad": 2}
        return (Marsaglia, Computing, Interaction, Artevasion)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
    
    BlobOpenCL = """
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    #define TFP32 0
    #define TFP64 1
    
    #define TFORCE 0
    #define TPOTENTIAL 1
    
    #define NONE 0
    #define NEGEXP 1
    #define CORRAD 2
    
    #if TYPE == TFP32
    #define MYFLOAT4 float4
    #define MYFLOAT8 float8
    #define MYFLOAT float
    #define DISTANCE fast_distance
    #else
    #define MYFLOAT4 double4
    #define MYFLOAT8 double8
    #define MYFLOAT double
    #define DISTANCE distance
    #if defined(cl_khr_fp64)  // Khronos extension available?
    #pragma OPENCL EXTENSION cl_khr_fp64 : enable
    #endif
    #endif
    
    #define znew  ((zmwc=36969*(zmwc&65535)+(zmwc>>16))<<16)
    #define wnew  ((wmwc=18000*(wmwc&65535)+(wmwc>>16))&65535)
    #define MWC   (znew+wnew)
    #define SHR3  (jsr=(jsr=(jsr=jsr^(jsr<<17))^(jsr>>13))^(jsr<<5))
    #define CONG  (jcong=69069*jcong+1234567)
    #define KISS  ((MWC^CONG)+SHR3)
    
    #define MWCfp (MYFLOAT)(MWC * 2.3283064365386963e-10f)
    #define KISSfp (MYFLOAT)(KISS * 2.3283064365386963e-10f)
    #define SHR3fp (MYFLOAT)(SHR3 * 2.3283064365386963e-10f)
    #define CONGfp (MYFLOAT)(CONG * 2.3283064365386963e-10f)
    
    #define PI (MYFLOAT)3.141592653589793238e0f
    
    #define SMALL_NUM (MYFLOAT)1.e-9f
    
    #define CoreRadius (MYFLOAT)(1.e0f)
    
    // Create my own Distance implementation: distance buggy on Oland AMD chipset
    
    MYFLOAT MyDistance(MYFLOAT4 n,MYFLOAT4 m)
    {
        private MYFLOAT x2,y2,z2;
        x2=n.s0-m.s0;
        x2*=x2;
        y2=n.s1-m.s1;
        y2*=y2;
        z2=n.s2-m.s2;
        z2*=z2;
        return(sqrt(x2+y2+z2));
    }
    
    // Potential between 2 m,n bodies
    MYFLOAT PairPotential(MYFLOAT4 m,MYFLOAT4 n)
    #if ARTEVASION == NEGEXP
    // Add exp(-r) to numerator to avoid divergence for low distances
    {
        MYFLOAT r=DISTANCE(n,m);
        return((-1.e0f+exp(-r))/r);
    }
    #elif ARTEVASION == CORRAD
    // Add Core Radius to avoid divergence for low distances
    {
        MYFLOAT r=DISTANCE(n,m);
        return(-1.e0f/sqrt(r*r+CoreRadius*CoreRadius));
    }
    #else
    // Classical potential in 1/r
    {
    //    return((MYFLOAT)(-1.e0f)/(MyDistance(m,n)));
        return((MYFLOAT)(-1.e0f)/(DISTANCE(n,m)));
    }
    #endif
    
    // Interaction based of Force as gradient of Potential
    MYFLOAT4 Interaction(MYFLOAT4 m,MYFLOAT4 n)
    #if INTERACTION == TFORCE
    #if ARTEVASION == NEGEXP
    
    // Force gradient of potential, set as (1-exp(-r))/r
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    {
        private MYFLOAT r=MyDistance(n,m);
        private MYFLOAT num=1.e0f+exp(-r)*(r-1.e0f);
        return((n-m)*num/(MYFLOAT)(r*r*r));
    }
    #elif ARTEVASION == CORRAD
    
    // Force gradient of potential, (Core Radius) set as 1/sqrt(r**2+CoreRadius**2)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    {
        private MYFLOAT r=MyDistance(n,m);
        private MYFLOAT den=sqrt(r*r+CoreRadius*CoreRadius);
        return((n-m)/(MYFLOAT)(den*den*den));
    }
    #else
    // Simplest implementation of force (equals to acceleration)
    // seems to bo bad (numerous artevasions)
    // MYFLOAT4 InteractionForce(MYFLOAT4 m,MYFLOAT4 n)
    {
        private MYFLOAT r=MyDistance(n,m);
        return((n-m)/(MYFLOAT)(r*r*r));
    }
    #endif
    #else
    // Force definited as gradient of potential
    // Estimate potential and proximate potential to estimate force
    {
        // 1/1024 seems to be a good factor: larger one provides bad results
        private MYFLOAT epsilon=(MYFLOAT)(1.e0f/1024);
        private MYFLOAT4 er=normalize(n-m);
        private MYFLOAT4 dr=er*(MYFLOAT)epsilon;
    
        return(er/epsilon*(PairPotential(m,n)-PairPotential(m+dr,n)));
    }
    #endif
    
    MYFLOAT AtomicPotential(__global MYFLOAT4* clDataX,int gid)
    {
        private MYFLOAT potential=(MYFLOAT)0.e0f;
    
        private MYFLOAT4 x=clDataX[gid];
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for (int i=0;i<get_global_size(0);i++)
        {
            if (gid != i)
            potential+=PairPotential(x,clDataX[i]);
        }
    
        barrier(CLK_GLOBAL_MEM_FENCE);
        return(potential);
    }
    
    
    MYFLOAT AtomicPotentialCoM(__global MYFLOAT4* clDataX,__global MYFLOAT4* clCoM,int gid) // # noqa: E501
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    {
        return(PairPotential(clDataX[gid],clCoM[0]));
    }
    
    // Elements from : http://doswa.com/2009/01/02/fourth-order-runge-kutta-numerical-integration.html
    
    MYFLOAT8 AtomicRungeKutta(__global MYFLOAT4* clDataInX,__global MYFLOAT4* clDataInV,int gid,MYFLOAT dt)
    {
        private MYFLOAT4 a0,v0,x0,a1,v1,x1,a2,v2,x2,a3,v3,x3,a4,v4,x4,xf,vf;
        MYFLOAT4 DT=dt*(MYFLOAT4)(1.e0f,1.e0f,1.e0f,1.e0f);
    
        a0=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        v0=(MYFLOAT4)clDataInV[gid];
        x0=(MYFLOAT4)clDataInX[gid];
    
        int N = get_global_size(0);
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for (private int i=0;i<N;i++)
        {
            if (gid != i)
            a0+=Interaction(x0,clDataInX[i]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        a1=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        v1=a0*dt+v0;
        x1=v0*dt+x0;
        for (private int j=0;j<N;j++)
        {
            if (gid != j)
            a1+=Interaction(x1,clDataInX[j]);
        }
    
        a2=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        v2=a1*(MYFLOAT)(dt/2.e0f)+v0;
        x2=v1*(MYFLOAT)(dt/2.e0f)+x0;
        for (private int k=0;k<N;k++)
        {
            if (gid != k)
            a2+=Interaction(x2,clDataInX[k]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        a3=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        v3=a2*(MYFLOAT)(dt/2.e0f)+v0;
        x3=v2*(MYFLOAT)(dt/2.e0f)+x0;
        for (private int l=0;l<N;l++)
        {
            if (gid != l)
            a3+=Interaction(x3,clDataInX[l]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        a4=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        v4=a3*dt+v0;
        x4=v3*dt+x0;
        for (private int m=0;m<N;m++)
        {
            if (gid != m)
            a4+=Interaction(x4,clDataInX[m]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        xf=x0+dt*(v1+(MYFLOAT)2.e0f*(v2+v3)+v4)/(MYFLOAT)6.e0f;
        vf=v0+dt*(a1+(MYFLOAT)2.e0f*(a2+a3)+a4)/(MYFLOAT)6.e0f;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        return((MYFLOAT8)(xf.s0,xf.s1,xf.s2,0.e0f,vf.s0,vf.s1,vf.s2,0.e0f));
    }
    
    MYFLOAT8 AtomicHeun(__global MYFLOAT4* clDataInX,__global MYFLOAT4* clDataInV,int gid,MYFLOAT dt)
    {
        private MYFLOAT4 x0,v0,a0,x1,v1,a1,xf,vf;
        MYFLOAT4 Dt=dt*(MYFLOAT4)(1.e0f,1.e0f,1.e0f,1.e0f);
    
        x0=(MYFLOAT4)clDataInX[gid];
        v0=(MYFLOAT4)clDataInV[gid];
        a0=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
    
        for (private int i=0;i<get_global_size(0);i++)
        {
            if (gid != i)
            a0+=Interaction(x0,clDataInX[i]);
        }
    
        a1=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
        //v1=v0+dt*a0;
        //x1=x0+dt*v0;
        v1=dt*a0+v0;
        x1=dt*v0+x0;
    
        for (private int j=0;j<get_global_size(0);j++)
        {
            if (gid != j)
            a1+=Interaction(x1,clDataInX[j]);
        }
    
        vf=v0+dt*(a0+a1)/(MYFLOAT)2.e0f;
        xf=x0+dt*(v0+v1)/(MYFLOAT)2.e0f;
    
        return((MYFLOAT8)(xf.s0,xf.s1,xf.s2,0.e0f,vf.s0,vf.s1,vf.s2,0.e0f));
    }
    
    MYFLOAT8 AtomicImplicitEuler(__global MYFLOAT4* clDataInX,__global MYFLOAT4* clDataInV,int gid,MYFLOAT dt)
    {
        MYFLOAT4 x0,v0,a,xf,vf;
    
        x0=(MYFLOAT4)clDataInX[gid];
        v0=(MYFLOAT4)clDataInV[gid];
        a=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
    
        for (private int i=0;i<get_global_size(0);i++)
        {
            if (gid != i)
              a+=Interaction(x0,clDataInX[i]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        vf=v0+dt*a;
        xf=x0+dt*vf;
    
        return((MYFLOAT8)(xf.s0,xf.s1,xf.s2,0.e0f,vf.s0,vf.s1,vf.s2,0.e0f));
    }
    
    MYFLOAT8 AtomicExplicitEuler(__global MYFLOAT4* clDataInX,__global MYFLOAT4* clDataInV,int gid,MYFLOAT dt)
    {
        MYFLOAT4 x0,v0,a,xf,vf;
    
        x0=(MYFLOAT4)clDataInX[gid];
        v0=(MYFLOAT4)clDataInV[gid];
        a=(MYFLOAT4)(0.e0f,0.e0f,0.e0f,0.e0f);
    
        for (private int i=0;i<get_global_size(0);i++)
        {
            if (gid != i)
            a+=Interaction(x0,clDataInX[i]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        vf=v0+dt*a;
        xf=x0+dt*v0;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        return((MYFLOAT8)(xf.s0,xf.s1,xf.s2,0.e0f,vf.s0,vf.s1,vf.s2,0.e0f));
    }
    
    
    __kernel void InBallSplutterPoints(__global MYFLOAT4* clDataX,
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                                       MYFLOAT diameter,uint seed_z,uint seed_w)
    {
        private int gid=get_global_id(0);
        private uint zmwc=seed_z+gid;
        private uint wmwc=seed_w+(gid+1)%2;
        private MYFLOAT Heat;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for (int i=0;i<gid;i++)
        {
            Heat=MWCfp;
        }
    
    // More accurate distribution based on spherical coordonates
    // Disactivated because of AMD Oland GPU crash on launch
    //     private MYFLOAT Radius,Theta,Phi,PosX,PosY,PosZ,SinTheta;
    //     Radius=MWCfp*diameter/2.e0f;
    //     Theta=(MYFLOAT)acos((float)(-2.e0f*MWCfp+1.0e0f));
    //     Phi=(MYFLOAT)(2.e0f*PI*MWCfp);
    //     SinTheta=sin((float)Theta);
    //     PosX=cos((float)Phi)*Radius*SinTheta;
    //     PosY=sin((float)Phi)*Radius*SinTheta;
    //     PosZ=cos((float)Theta)*Radius;
    //     clDataX[gid]=(MYFLOAT4)(PosX,PosY,PosZ,0.e0f);
    
        private MYFLOAT Radius=diameter/2.e0f;
        private MYFLOAT Length=diameter;
        private MYFLOAT4 Position;
        while (Length>Radius) {
           Position=(MYFLOAT4)((MWCfp-0.5e0f)*diameter,(MWCfp-0.5e0f)*diameter,(MWCfp-0.5e0f)*diameter,0.e0f);
           Length=(MYFLOAT)length((MYFLOAT4)Position);
        }
    
    
        clDataX[gid]=Position;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        barrier(CLK_GLOBAL_MEM_FENCE);
    }
    
    
    __kernel void InBoxSplutterPoints(__global MYFLOAT4* clDataX, MYFLOAT box,
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                                 uint seed_z,uint seed_w)
    {
        int gid=get_global_id(0);
        uint zmwc=seed_z+gid;
        uint wmwc=seed_w-gid;
        private MYFLOAT Heat;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for (int i=0;i<gid;i++)
        {
            Heat=MWCfp;
        }
    
        clDataX[gid]=(MYFLOAT4)((MWCfp-0.5e0f)*box,(MWCfp-0.5e0f)*box,(MWCfp-0.5e0f)*box,0.e0f);
    
        barrier(CLK_GLOBAL_MEM_FENCE);
    }
    
    __kernel void SplutterStress(__global MYFLOAT4* clDataX,__global MYFLOAT4* clDataV,__global MYFLOAT4* clCoM, MYFLOAT velocity,uint seed_z,uint seed_w)
    {
        int gid = get_global_id(0);
        MYFLOAT N = (MYFLOAT)get_global_size(0);
        uint zmwc=seed_z+(uint)gid;
        uint wmwc=seed_w-(uint)gid;
        MYFLOAT4 CrossVector,SpeedVector,FromCoM;
        MYFLOAT Heat,ThetaA,PhiA,ThetaB,PhiB,Length,tA,tB,Polar;
    
        for (int i=0;i<gid;i++)
        {
            Heat=MWCfp;
        }
    
        // cast to float for sin,cos are NEEDED by Mesa FP64 implementation!
        // Implemention on AMD Oland are probably broken in float
    
        FromCoM=(MYFLOAT4)(clDataX[gid]-clCoM[0]);
        Length=length(FromCoM);
        //Theta=acos(FromCoM.z/Length);
        //Phi=atan(FromCoM.y/FromCoM.x);
        // First tangential vector to sphere of length radius
        ThetaA=acos(FromCoM.x/Length)+5.e-1f*PI;
        PhiA=atan(FromCoM.y/FromCoM.z);
        // Second tangential vector to sphere of length radius
        ThetaB=acos((float)(FromCoM.x/Length));
        PhiB=atan((float)(FromCoM.y/FromCoM.z))+5.e-1f*PI;
        // (x,y) random coordonates to plane tangential to sphere
        Polar=MWCfp*2.e0f*PI;
        tA=cos((float)Polar);
        tB=sin((float)Polar);
    
        // Exception for 2 particules to ovoid shifting
        if (get_global_size(0)==2) {
           CrossVector=(MYFLOAT4)(1.e0f,1.e0f,1.e0f,0.e0f);
        } else {
           CrossVector.s0=tA*cos((float)ThetaA)+tB*cos((float)ThetaB);
           CrossVector.s1=tA*sin((float)ThetaA)*sin((float)PhiA)+tB*sin((float)ThetaB)*sin((float)PhiB);
           CrossVector.s2=tA*sin((float)ThetaA)*cos((float)PhiA)+tB*sin((float)ThetaB)*cos((float)PhiB);
           CrossVector.s3=0.e0f;
        }
    
        if (velocity<SMALL_NUM) {
           SpeedVector=(MYFLOAT4)normalize(cross(FromCoM,CrossVector))*sqrt((-AtomicPotential(clDataX,gid)/(MYFLOAT)2.e0f));
        }
        else
        {
    
           SpeedVector=(MYFLOAT4)((MWCfp-5e-1f)*velocity,(MWCfp-5e-1f)*velocity,
                                  (MWCfp-5e-1f)*velocity,0.e0f);
        }
        clDataV[gid]=SpeedVector;
        barrier(CLK_GLOBAL_MEM_FENCE);
    }
    
    __kernel void RungeKutta(__global MYFLOAT4* clDataX,__global MYFLOAT4* clDataV,MYFLOAT h)
    {
        private int gid = get_global_id(0);
        private MYFLOAT8 clDataGid;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        clDataGid=AtomicRungeKutta(clDataX,clDataV,gid,h);
        barrier(CLK_GLOBAL_MEM_FENCE);
        clDataX[gid]=clDataGid.s0123;
        clDataV[gid]=clDataGid.s4567;
    }
    
    __kernel void Heun(__global MYFLOAT4* clDataX,__global MYFLOAT4* clDataV,MYFLOAT h)
    {
        private int gid = get_global_id(0);
        private MYFLOAT8 clDataGid;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        clDataGid=AtomicHeun(clDataX,clDataV,gid,h);
        barrier(CLK_GLOBAL_MEM_FENCE);
        clDataX[gid]=clDataGid.s0123;
        clDataV[gid]=clDataGid.s4567;
    }
    
    __kernel void ImplicitEuler(__global MYFLOAT4* clDataX,__global MYFLOAT4* clDataV,MYFLOAT h)
    {
        private int gid = get_global_id(0);
        private MYFLOAT8 clDataGid;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        clDataGid=AtomicImplicitEuler(clDataX,clDataV,gid,h);
        barrier(CLK_GLOBAL_MEM_FENCE);
        clDataX[gid]=clDataGid.s0123;
        clDataV[gid]=clDataGid.s4567;
    }
    
    __kernel void ExplicitEuler(__global MYFLOAT4* clDataX,__global MYFLOAT4* clDataV,MYFLOAT h)
    {
        private int gid = get_global_id(0);
    
        private MYFLOAT8 clDataGid;
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        clDataGid=AtomicExplicitEuler(clDataX,clDataV,gid,h);
        barrier(CLK_GLOBAL_MEM_FENCE);
        clDataX[gid]=clDataGid.s0123;
        clDataV[gid]=clDataGid.s4567;
    }
    
    __kernel void CoMPotential(__global MYFLOAT4* clDataX,__global MYFLOAT4* clCoM,__global MYFLOAT* clPotential)
    {
        int gid = get_global_id(0);
    
        clPotential[gid]=PairPotential(clDataX[gid],clCoM[0]);
    }
    
    __kernel void Potential(__global MYFLOAT4* clDataX,__global MYFLOAT* clPotential)
    {
        int gid = get_global_id(0);
    
        MYFLOAT potential=(MYFLOAT)0.e0f;
    
        MYFLOAT4 x=clDataX[gid];
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for (int i=0;i<get_global_size(0);i++)
        {
            if (gid != i)
            potential+=PairPotential(x,clDataX[i]);
        }
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        barrier(CLK_GLOBAL_MEM_FENCE);
        clPotential[gid]=potential*(MYFLOAT)5.e-1f;
    }
    
    __kernel void CenterOfMass(__global MYFLOAT4* clDataX,__global MYFLOAT4* clCoM,int Size)
    {
    
        MYFLOAT4 CoM=clDataX[0];
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        for (int i=1;i<Size;i++)
        {
            CoM+=clDataX[i];
        }
    
        barrier(CLK_GLOBAL_MEM_FENCE);
        clCoM[0]=(MYFLOAT4)(CoM.s0,CoM.s1,CoM.s2,0.e0f)/(MYFLOAT)Size;
    }
    
    __kernel void Kinetic(__global MYFLOAT4* clDataV,__global MYFLOAT* clKinetic)
    {
        int gid = get_global_id(0);
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        barrier(CLK_GLOBAL_MEM_FENCE);
        MYFLOAT d=(MYFLOAT)length(clDataV[gid]);
        clKinetic[gid]=(MYFLOAT)5.e-1f*(MYFLOAT)(d*d);
    }
    
    """
    
    
    
    def MainOpenCL(clDataX, clDataV, Step, Method):
        time_start = time.time()
        if Method == "RungeKutta":
            CLLaunch = MyRoutines.RungeKutta(
                queue, (Number, 1), None, clDataX, clDataV, Step
            )
        elif Method == "ExplicitEuler":
            CLLaunch = MyRoutines.ExplicitEuler(
                queue, (Number, 1), None, clDataX, clDataV, Step
            )
        elif Method == "Heun":
            CLLaunch = MyRoutines.Heun(queue, (Number, 1), None, clDataX, clDataV, Step)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            CLLaunch = MyRoutines.ImplicitEuler(
                queue, (Number, 1), None, clDataX, clDataV, Step
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        CLLaunch.wait()
    
        Elapsed = time.time() - time_start
        return Elapsed
    
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    def display(*args):
    
        global MyDataX, MyDataV, clDataX, clDataV, Step, Method, Number, Iterations, \
                Durations, Verbose, SpeedRendering
    
        gl.glClearColor(0.0, 0.0, 0.0, 0.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)
        gl.glColor3f(1.0, 1.0, 1.0)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        MainOpenCL(clDataX, clDataV, Step, Method)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        if SpeedRendering:
            cl.enqueue_copy(queue, MyDataV, clDataV)
    
            MyDataV.reshape(Number, 4)[:, 3] = 1
            gl.glVertexPointerf(MyDataV.reshape(Number, 4))
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
            cl.enqueue_copy(queue, MyDataX, clDataX)
    
            MyDataX.reshape(Number, 4)[:, 3] = 1
            gl.glVertexPointerf(MyDataX.reshape(Number, 4))
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        if Verbose:
    
            print("Positions for #%s iteration: %s" % (Iterations, MyDataX))
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            sys.stdout.write(".")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            sys.stdout.flush()
    
        Durations = np.append(Durations, MainOpenCL(clDataX, clDataV, Step, Method))
        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
        gl.glDrawArrays(gl.GL_POINTS, 0, Number)
        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
        gl.glFlush()
        Iterations += 1
        glut.glutSwapBuffers()
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    def halt():
        pass
    
    
    
    def keyboard(k, x, y):
        global ViewRZ, SpeedRendering
        LC_Z = glut.as_8_bit("z")
        UC_Z = glut.as_8_bit("Z")
        Plus = glut.as_8_bit("+")
        Minus = glut.as_8_bit("-")
        Switch = glut.as_8_bit("s")
    
        Zoom = 1
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        if k == LC_Z:
            ViewRZ += 1.0
        elif k == UC_Z:
            ViewRZ -= 1.0
        elif k == Plus:
            Zoom *= 2.0
        elif k == Minus:
            Zoom /= 2.0
        elif k == Switch:
            if SpeedRendering:
    
                SpeedRendering = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            else:
    
                SpeedRendering = True
        elif ord(k) == 27:  # Escape
            glut.glutLeaveMainLoop()
            return False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
            return
    
        gl.glRotatef(ViewRZ, 0.0, 0.0, 1.0)
        gl.glScalef(Zoom, Zoom, Zoom)
        glut.glutPostRedisplay()
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
    def special(k, x, y):
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        global ViewRX, ViewRY
    
    
        Step = 1.0
        if k == glut.GLUT_KEY_UP:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            ViewRX += Step
    
        elif k == glut.GLUT_KEY_DOWN:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            ViewRX -= Step
    
        elif k == glut.GLUT_KEY_LEFT:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            ViewRY += Step
    
        elif k == glut.GLUT_KEY_RIGHT:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            ViewRY -= Step
        else:
            return
    
        gl.glRotatef(ViewRX, 1.0, 0.0, 0.0)
        gl.glRotatef(ViewRY, 0.0, 1.0, 0.0)
        glut.glutPostRedisplay()
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    def setup_viewport():
        global SizeOfBox
    
        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadIdentity()
        gl.glOrtho(-SizeOfBox, SizeOfBox, -SizeOfBox, SizeOfBox, -SizeOfBox, SizeOfBox)
        glut.glutPostRedisplay()
    
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    def reshape(w, h):
    
        gl.glViewport(0, 0, w, h)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        setup_viewport()
    
    
    
    if __name__ == "__main__":
    
        global Number, Step, clDataX, clDataV, MyDataX, MyDataV, Method, SizeOfBox, \
                Iterations, Verbose, Durations
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # ValueType
    
        ValueType = "FP32"
    
        class MyFloat(np.float32):
            pass
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        #    clType8=cl_array.vec.float8
        # Set defaults values
    
        np.set_printoptions(precision=2)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Id of Device : 1 is for first find !
    
        Device = 0
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Number of bodies is integer
    
        Number = 2
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Number of iterations (for standalone execution)
    
        Iterations = 10
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Size of shape
    
        SizeOfShape = MyFloat(1.0)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Initial velocity of particules
    
        Velocity = MyFloat(1.0)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Step
    
        Step = MyFloat(1.0 / 32)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Method of integration
    
        Method = "ImplicitEuler"
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # InitialRandom
    
        InitialRandom = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # RNG Marsaglia Method
    
        RNG = "MWC"
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Viriel Distribution of stress
    
        VirielStress = True
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Verbose
    
        Verbose = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # OpenGL real time rendering
    
        OpenGL = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Speed rendering
    
        SpeedRendering = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Counter ArtEvasions Measures (artefact evasion)
    
        CoArEv = "None"
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Shape to distribute
    
        Shape = "Ball"
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Type of Interaction
    
        InterType = "Force"
    
        HowToUse = "%s -h [Help] -r [InitialRandom] -g [OpenGL] -e [VirielStress] -o [Verbose] -p [Potential] -x <None|NegExp|CorRad> -d <DeviceId> -n <NumberOfParticules> -i <Iterations> -z <SizeOfBoxOrBall> -v <Velocity> -s <Step> -b <Ball|Box> -m <ImplicitEuler|RungeKutta|ExplicitEuler|Heun> -t <FP32|FP64>"  # noqa: E501
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        try:
    
            opts, args = getopt.getopt(
                sys.argv[1:],
                "rpgehod:n:i:z:v:s:m:t:b:x:",
                [
                    "random",
                    "potential",
                    "coarev",
                    "opengl",
                    "viriel",
                    "verbose",
                    "device=",
                    "number=",
                    "iterations=",
                    "size=",
                    "velocity=",
                    "step=",
                    "method=",
                    "valuetype=",
                    "shape=",
                ],
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        except getopt.GetoptError:
            print(HowToUse % sys.argv[0])
            sys.exit(2)
    
        for opt, arg in opts:
    
            if opt == "-h":
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                print(HowToUse % sys.argv[0])
    
                print("\nInformations about devices detected under OpenCL:")
                try:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                    for platform in cl.get_platforms():
                        for device in platform.get_devices():
                            # Failed now because of POCL implementation
    
                            # deviceType=cl.device_type.to_string(device.type)
                            deviceType = "xPU"
                            print(
                                "Device #%i from %s of type %s : %s"
                                % (
                                    Id,
                                    platform.vendor.lstrip(),
                                    deviceType,
                                    device.name.lstrip(),
                                )
                            )
                            Id = Id + 1
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                    sys.exit()
                except ImportError:
                    print("Your platform does not seem to support OpenCL")
                    sys.exit()
    
            elif opt in ("-t", "--valuetype"):
    
                if arg == "FP64":
    
                    class MyFloat(np.float64):
                        pass
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                else:
    
    
                    class MyFloat(np.float32):
                        pass
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                ValueType = arg
            elif opt in ("-d", "--device"):
    
                Device = int(arg)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-m", "--method"):
    
                Method = arg
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-b", "--shape"):
    
                Shape = arg
                if Shape != "Ball" or Shape != "Box":
                    print("Wrong argument: set to Ball")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-n", "--number"):
    
                Number = int(arg)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-i", "--iterations"):
    
                Iterations = int(arg)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-z", "--size"):
    
                SizeOfShape = MyFloat(arg)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-v", "--velocity"):
    
                Velocity = MyFloat(arg)
                VirielStress = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-s", "--step"):
    
                Step = MyFloat(arg)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-r", "--random"):
    
                InitialRandom = True
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-c", "--check"):
    
                CheckEnergies = True
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-e", "--viriel"):
    
                VirielStress = True
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-g", "--opengl"):
    
                OpenGL = True
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-p", "--potential"):
    
                InterType = "Potential"
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-x", "--coarev"):
    
                CoArEv = arg
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            elif opt in ("-o", "--verbose"):
    
                Verbose = True
    
        SizeOfShape = np.sqrt(MyFloat(SizeOfShape * Number))
        Velocity = MyFloat(Velocity)
        Step = MyFloat(Step)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        print("Device choosed : %s" % Device)
        print("Number of particules : %s" % Number)
        print("Size of Shape : %s" % SizeOfShape)
        print("Initial velocity : %s" % Velocity)
        print("Step of iteration : %s" % Step)
        print("Number of iterations : %s" % Iterations)
        print("Method of resolution : %s" % Method)
        print("Initial Random for RNG Seed : %s" % InitialRandom)
        print("ValueType is : %s" % ValueType)
        print("Viriel distribution of stress : %s" % VirielStress)
        print("OpenGL real time rendering : %s" % OpenGL)
        print("Speed rendering : %s" % SpeedRendering)
        print("Interaction type : %s" % InterType)
        print("Counter Artevasion type : %s" % CoArEv)
    
    
        # Create Numpy array of CL vector with 8 FP32
        MyCoM = np.zeros(4, dtype=MyFloat)
        MyDataX = np.zeros(Number * 4, dtype=MyFloat)
        MyDataV = np.zeros(Number * 4, dtype=MyFloat)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        MyPotential = np.zeros(Number, dtype=MyFloat)
        MyKinetic = np.zeros(Number, dtype=MyFloat)
    
    
        Marsaglia, Computing, Interaction, Artevasion = DictionariesAPI()
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        # Scan the OpenCL arrays
    
        Id = 0
        HasXPU = False
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        for platform in cl.get_platforms():
            for device in platform.get_devices():
    
                if Id == Device:
                    PlatForm = platform
                    XPU = device
                    print("CPU/GPU selected: ", device.name.lstrip())
                    print("Platform selected: ", platform.name)
                    HasXPU = True
                Id += 1
    
        if not HasXPU:
            print("No XPU #%i found in all of %i devices, sorry..." % (Device, Id - 1))
            sys.exit()
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        # Create Context
        try:
            ctx = cl.Context([XPU])
    
            queue = cl.CommandQueue(
                ctx, properties=cl.command_queue_properties.PROFILING_ENABLE
            )
        except Exception:
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            print("Crash during context creation")
    
        # Build all routines used for the computing
    
    
        # BuildOptions="-cl-mad-enable -cl-kernel-arg-info -cl-fast-relaxed-math -cl-std=CL1.2 -DTRNG=%i -DTYPE=%i" % (Marsaglia[RNG],Computing[ValueType])  # noqa: E501
        BuildOptions = "-cl-mad-enable -cl-fast-relaxed-math -DTRNG=%i -DTYPE=%i -DINTERACTION=%i -DARTEVASION=%i" % (  # noqa: E501
            Marsaglia[RNG],
            Computing[ValueType],
            Interaction[InterType],
            Artevasion[CoArEv],
        )
    
        if (
            "Intel" in PlatForm.name
            or "Experimental" in PlatForm.name
            or "Clover" in PlatForm.name
            or "Portable" in PlatForm.name
        ):
            MyRoutines = cl.Program(ctx, BlobOpenCL).build(options=BuildOptions)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            MyRoutines = cl.Program(ctx, BlobOpenCL).build(
                options=BuildOptions + " -cl-strict-aliasing"
            )
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        mf = cl.mem_flags
        # Read/Write approach for buffering
        clDataX = cl.Buffer(ctx, mf.READ_WRITE, MyDataX.nbytes)
        clDataV = cl.Buffer(ctx, mf.READ_WRITE, MyDataV.nbytes)
        clPotential = cl.Buffer(ctx, mf.READ_WRITE, MyPotential.nbytes)
        clKinetic = cl.Buffer(ctx, mf.READ_WRITE, MyKinetic.nbytes)
        clCoM = cl.Buffer(ctx, mf.READ_WRITE, MyCoM.nbytes)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # Write/HostPointer approach for buffering
        # clDataX = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=MyDataX)
        # clDataV = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=MyDataV)
    
        # clPotential = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=MyPotential)  # noqa: E501
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        # clKinetic = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=MyKinetic)
        # clCoM = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=MyCoM)
    
    
        print("All particles superimposed.")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        # Set particles to RNG points
        if InitialRandom:
    
            seed_w = np.uint32(nprnd(2 ** 32))
            seed_z = np.uint32(nprnd(2 ** 32))
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            seed_w = np.uint32(19710211)
            seed_z = np.uint32(20081010)
    
        if Shape == "Ball":
            MyRoutines.InBallSplutterPoints(
                queue, (Number, 1), None, clDataX, SizeOfShape, seed_w, seed_z
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            MyRoutines.InBoxSplutterPoints(
                queue, (Number, 1), None, clDataX, SizeOfShape, seed_w, seed_z
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        print("All particules distributed")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        CLLaunch = MyRoutines.CenterOfMass(
            queue, (1, 1), None, clDataX, clCoM, np.int32(Number)
        )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        CLLaunch.wait()
    
        cl.enqueue_copy(queue, MyCoM, clCoM)
        print("Center Of Mass estimated: (%s,%s,%s)" % (MyCoM[0], MyCoM[1], MyCoM[2]))
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        if VirielStress:
    
            CLLaunch = MyRoutines.SplutterStress(
                queue,
                (Number, 1),
                None,
                clDataX,
                clDataV,
                clCoM,
                MyFloat(0.0),
                np.uint32(110271),
                np.uint32(250173),
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            CLLaunch = MyRoutines.SplutterStress(
                queue,
                (Number, 1),
                None,
                clDataX,
                clDataV,
                clCoM,
                Velocity,
                np.uint32(110271),
                np.uint32(250173),
            )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        CLLaunch.wait()
    
    
        print("All particules stressed")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        CLLaunch = MyRoutines.Potential(queue, (Number, 1), None, clDataX, clPotential)
        CLLaunch = MyRoutines.Kinetic(queue, (Number, 1), None, clDataV, clKinetic)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        CLLaunch.wait()
    
        cl.enqueue_copy(queue, MyPotential, clPotential)
        cl.enqueue_copy(queue, MyKinetic, clKinetic)
        print(
            "Energy estimated: Viriel=%s Potential=%s Kinetic=%s\n"
            % (
                np.sum(MyPotential) + 2 * np.sum(MyKinetic),
                np.sum(MyPotential),
                np.sum(MyKinetic),
            )
        )
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
        if SpeedRendering:
    
            SizeOfBox = max(2 * MyKinetic)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
    
            SizeOfBox = SizeOfShape
    
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        if OpenGL:
    
            print("\tTiny documentation to interact OpenGL rendering:\n")
            print("\t<Left|Right> Rotate around X axis")
            print("\t  <Up|Down>  Rotate around Y axis")
            print("\t   <z|Z>     Rotate around Z axis")
            print("\t   <-|+>     Unzoom/Zoom")
            print("\t    <s>      Toggle to display Positions or Velocities")
            print("\t   <Esc>     Quit\n")
    
        wall_time_start = time.time()
    
        Durations = np.array([], dtype=MyFloat)
        print("Starting!")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        if OpenGL:
    
            import OpenGL.GL as gl
            import OpenGL.GLUT as glut
    
            global ViewRX, ViewRY, ViewRZ
            Iterations = 0
            ViewRX, ViewRY, ViewRZ = 0.0, 0.0, 0.0
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            # Launch OpenGL Loop
    
            glut.glutInit(sys.argv)
            glut.glutInitDisplayMode(glut.GLUT_DOUBLE | glut.GLUT_RGB)
            glut.glutSetOption(glut.GLUT_ACTION_ON_WINDOW_CLOSE,
                    glut.GLUT_ACTION_CONTINUE_EXECUTION)
            glut.glutInitWindowSize(512, 512)
            glut.glutCreateWindow(b"NBodyGL")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            setup_viewport()
    
            glut.glutReshapeFunc(reshape)
            glut.glutDisplayFunc(display)
            glut.glutIdleFunc(display)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
            #   glutMouseFunc(mouse)
    
            glut.glutSpecialFunc(special)
            glut.glutKeyboardFunc(keyboard)
            glut.glutMainLoop()
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
        else:
            for iteration in range(Iterations):
    
                Elapsed = MainOpenCL(clDataX, clDataV, Step, Method)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                if Verbose:
                    # print("Duration of #%s iteration: %s" % (iteration,Elapsed))
                    cl.enqueue_copy(queue, MyDataX, clDataX)
    
                    print("Positions for #%s iteration: %s" % (iteration, MyDataX))
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                else:
    
                    sys.stdout.write(".")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
                    sys.stdout.flush()
    
                Durations = np.append(Durations, Elapsed)
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        print("\nEnding!")
    
    Emmanuel QUEMENER's avatar
    Emmanuel QUEMENER committed
    
    
        MyRoutines.CenterOfMass(queue, (1, 1), None, clDataX, clCoM, np.int32(Number))
        CLLaunch = MyRoutines.Potential(queue, (Number, 1), None, clDataX, clPotential)
        CLLaunch = MyRoutines.Kinetic(queue, (Number, 1), None, clDataV, clKinetic)
        CLLaunch.wait()
        cl.enqueue_copy(queue, MyCoM, clCoM)
        cl.enqueue_copy(queue, MyPotential, clPotential)
        cl.enqueue_copy(queue, MyKinetic, clKinetic)