Statistiques
| Révision :

root / Ising / GPU / Ising2D-GPU-Global.py @ 308

Historique | Voir | Annoter | Télécharger (8,9 ko)

1
#!/usr/bin/env python
2
#
3
# Ising2D model using PyOpenCL 
4
#
5
# CC BY-NC-SA 2011 : <emmanuel.quemener@ens-lyon.fr> 
6
#
7
# Thanks to Andreas Klockner for PyOpenCL:
8
# http://mathema.tician.de/software/pyopencl
9
# 
10
# Interesting links:
11
# http://viennacl.sourceforge.net/viennacl-documentation.html
12
# http://enja.org/2011/02/22/adventures-in-pyopencl-part-1-getting-started-with-python/
13

    
14
import pyopencl as cl
15
import numpy
16
from numpy.random import randint as nprnd
17
from PIL import Image
18
import time
19
import sys
20
import getopt
21
import matplotlib.pyplot as plt
22

    
23
# 2097152 on HD5850 (with 1GB of RAM)
24
#  262144 on GT218
25
#STEP=262144
26
#STEP=1048576
27
#STEP=2097152
28
#STEP=4194304
29
#STEP=8388608
30
STEP=16777216
31

    
32
KERNEL_CODE="""
33

34
// Marsaglia RNG very simple implementation
35

36
#define znew (z=36969*(z&65535)+(z>>16))
37
#define wnew (w=18000*(w&65535)+(w>>16))
38
#define MWC ((znew<<16)+wnew )
39
#define MWCfp MWC * 2.328306435454494e-10f
40

41
__kernel void MainLoop(__global int *s,float J,float B,float T,uint size,
42
                       uint iterations,uint seed_w,uint seed_z)
43
{
44
   uint z=seed_z;
45
   uint w=seed_w;
46

47
   for (uint i=0;i<iterations;i++) {
48

49
      uint x=(uint)(MWC%size) ;
50
      uint y=(uint)(MWC%size) ;
51

52
      int p=s[x+size*y];
53

54
      int d=s[x+size*((y+1)%size)];
55
      int u=s[x+size*((y-1)%size)];
56
      int l=s[((x-1)%size)+size*y];
57
      int r=s[((x+1)%size)+size*y];
58

59
      float DeltaE=p*(2.0f*J*(u+d+l+r)+B);
60

61
      int factor=((DeltaE < 0.0f) || (MWCfp < exp(-DeltaE/T))) ? -1:1;
62
      s[x%size+size*(y%size)] = factor*p;
63
      // barrier(CLK_GLOBAL_MEM_FENCE);
64
   }
65
   barrier(CLK_GLOBAL_MEM_FENCE);
66
   
67
}
68
"""
69

    
70
def ImageOutput(sigma,prefix):
71
        
72
        Max=sigma.max()
73
        Min=sigma.min()
74
        
75
        # Normalize value as 8bits Integer
76
        SigmaInt=(255*(sigma-Min)/(Max-Min)).astype('uint8')
77
        image = Image.fromarray(SigmaInt)
78
        image.save("%s.jpg" % prefix)
79
        
80
def Metropolis(sigma,J,B,T,iterations,Device):
81
                
82
        # Initialisation des variables en les CASTant correctement
83
    
84
        # Je detecte un peripherique GPU dans la liste des peripheriques
85
    Id=1
86
    HasXPU=False
87
    for platform in cl.get_platforms():
88
        for device in platform.get_devices():
89
            if Id==Device:
90
                XPU=device
91
                print "CPU/GPU selected: ",device.name.lstrip()
92
                HasXPU=True
93
            Id+=1
94

    
95
    if HasXPU==False:
96
        print "No XPU #%i found in all of %i devices, sorry..." % (Device,Id-1)
97
        sys.exit()
98
     
99
    # Je cree le contexte et la queue pour son execution
100
    ctx = cl.Context([XPU])
101
    queue = cl.CommandQueue(ctx,
102
        properties=cl.command_queue_properties.PROFILING_ENABLE)
103

    
104
        # Je recupere les flag possibles pour les buffers
105
    mf = cl.mem_flags
106
        
107
    sigmaCL = cl.Buffer(ctx, mf.WRITE_ONLY|mf.COPY_HOST_PTR,hostbuf=sigma)
108

    
109
    MetropolisCL = cl.Program(ctx,KERNEL_CODE).build(
110
        options = "-cl-mad-enable -cl-fast-relaxed-math")
111

    
112
    i=0
113
    step=STEP
114
    duration=0.
115
        
116
    while (step*i < iterations):
117
        # Call OpenCL kernel
118
        # (1,) is global work size (only 1 work size)
119
        # (1,) is local work size
120
        # sigmaCL is lattice translated in CL format
121
        # step is number of iterations
122
        
123
        start_time=time.time()
124
        CLLaunch=MetropolisCL.MainLoop(queue,(1,),None,
125
                                                sigmaCL,
126
                                                numpy.float32(J),numpy.float32(B),
127
                                                numpy.float32(T),
128
                                                numpy.uint32(sigma.shape[0]),
129
                                                numpy.uint32(step),
130
                                                numpy.uint32(nprnd(2**32)),
131
                                                numpy.uint32(nprnd(2**32)))
132
        CLLaunch.wait()
133
        # Does not seem to work under AMD/ATI
134
        # elapsed = 1e-9*(CLLaunch.profile.end - CLLaunch.profile.start)
135
        elapsed = time.time()-start_time
136
        print "Iteration %i with T=%f and %i iterations in %f: " % (i,T,step,elapsed)
137
        if LAPIMAGE:
138
            cl.enqueue_copy(queue, sigma, sigmaCL).wait()
139
            ImageOutput(sigma,"Ising2D_GPU_Global_%i_%1.1f_%.3i_Lap" %  
140
                (SIZE,T,i))
141
        i=i+1
142
        duration=duration+elapsed
143

    
144
        cl.enqueue_copy(queue, sigma, sigmaCL).wait()
145
        sigmaCL.release()
146
        
147
        return(duration)
148

    
149
def Magnetization(sigma,M):
150
    return(numpy.sum(sigma)/(sigma.shape[0]*sigma.shape[1]*1.0))
151

    
152
def Energy(sigma,J,B):
153
    # Copier et caster 
154
    E=numpy.copy(sigma).astype(numpy.float32)
155

    
156
    # Appel par slice
157
    E[1:-1,1:-1]=E[1:-1,1:-1]*(2.0*J*(E[:-2,1:-1]+E[2:,1:-1]+
158
                                          E[1:-1,:-2]+E[1:-1,2:])+B)
159

    
160
    # Bien nettoyer la peripherie
161
    E[:,0]=0
162
    E[:,-1]=0
163
    E[0,:]=0
164
    E[-1,:]=0
165

    
166
    Energy=numpy.sum(E)
167

    
168
    return(Energy/(E.shape[0]*E.shape[1]*1.0))
169

    
170
def CriticalT(T,E):
171

    
172
    Epoly=numpy.poly1d(numpy.polyfit(T,E,T.size/3))
173
    dEpoly=numpy.diff(Epoly(T))
174
    dEpoly=numpy.insert(dEpoly,0,0)
175
    return(T[numpy.argmin(dEpoly)])
176

    
177
def DisplayCurves(T,E,M,J,B):
178

    
179
    plt.xlabel("Temperature")
180
    plt.ylabel("Energy")
181

    
182
    Experience,=plt.plot(T,E,label="Energy") 
183

    
184
    plt.legend()
185
    plt.show()
186

    
187
if __name__=='__main__':
188

    
189
    # Set defaults values
190
    # Coupling factor
191
    J=1.
192
    # External Magnetic Field is null
193
    B=0.
194
    # Size of Lattice
195
    Size=256
196
    # Default Temperatures (start, end, step)
197
    Tmin=0.1
198
    Tmax=5
199
    Tstep=0.1
200
    # Default Number of Iterations
201
    Iterations=Size*Size*Size
202
    # Default Device is first
203
    Device=1
204

    
205
    # Curves is True to print the curves
206
    Curves=False
207

    
208
    OCL_vendor={}
209
    OCL_type={}
210
    OCL_description={}
211

    
212
    try:
213
        import pyopencl as cl
214
 
215
        print "\nHere are available OpenCL devices:"
216
        Id=1
217
        for platform in cl.get_platforms():
218
            for device in platform.get_devices():
219
                OCL_vendor[Id]=platform.vendor.lstrip().rstrip()
220
                #OCL_type[Id]=cl.device_type.to_string(device.type)
221
                OCL_type[Id]="xPU"
222
                OCL_description[Id]=device.name.lstrip().rstrip()
223
                print "* Device #%i from %s of type %s : %s" % (Id,OCL_vendor[Id],OCL_type[Id],OCL_description[Id])
224
                Id=Id+1
225
        OCL_MaxDevice=Id-1
226
        print
227
        
228
    except ImportError:
229
        print "Your platform does not seem to support OpenCL"
230
        sys.exit(0)   
231
    
232
    try:
233
        opts, args = getopt.getopt(sys.argv[1:],"hcj:b:z:i:s:e:p:d:",["coupling=","magneticfield=","size=","iterations=","tempstart=","tempend=","tempstep=","units",'device='])
234
    except getopt.GetoptError:
235
        print '%s -d <Device Id> -j <Coupling Factor> -b <Magnetic Field> -z <Size of Square Lattice> -i <Iterations> -s <Minimum Temperature> -e <Maximum Temperature> -p <steP Temperature> -c (Print Curves)' % sys.argv[0]
236
        sys.exit(2)
237
    
238
    for opt, arg in opts:
239
        if opt == '-h':
240
            print '%s -d <Device Id> -j <Coupling Factor> -b <Magnetic Field> -z <Size of Square Lattice> -i <Iterations> -s <Minimum Temperature> -e <Maximum Temperature> -p <steP Temperature> -c (Print Curves)' % sys.argv[0]
241
            sys.exit()
242
        elif opt == '-c':
243
            Curves=True
244
        elif opt in ("-d", "--device"):
245
            Device = int(arg)
246
            if Device>OCL_MaxDevice:
247
                "Device #%s seems not to be available !"
248
                sys.exit()
249
        elif opt in ("-j", "--coupling"):
250
            J = float(arg)
251
        elif opt in ("-b", "--magneticfield"):
252
            B = float(arg)
253
        elif opt in ("-s", "--tempmin"):
254
            Tmin = float(arg)
255
        elif opt in ("-e", "--tempmax"):
256
            Tmax = arg
257
        elif opt in ("-p", "--tempstep"):
258
            Tstep = numpy.uint32(arg)
259
        elif opt in ("-i", "--iterations"):
260
            Iterations = int(arg)
261
        elif opt in ("-z", "--size"):
262
            Size = int(arg)
263

    
264
    print "Here are parameters of simulation:"
265
    print "* Device selected #%s: %s of type %s from %s" % (Device,OCL_description[Device],OCL_type[Device],OCL_vendor[Device])
266
    print "* Coupling Factor J : %s" % J
267
    print "* Magnetic Field B :  %s" % B
268
    print "* Size of lattice : %sx%s" % (Size,Size)
269
    print "* Iterations : %s" % Iterations
270
    print "* Temperatures from %s to %s by %s" % (Tmin,Tmax,Tstep)
271

    
272
    LAPIMAGE=False
273
        
274
    if Iterations<STEP:
275
        STEP=Iterations
276
    
277
    sigmaIn=numpy.where(numpy.random.randn(Size,Size)>0,1,-1).astype        (numpy.int32)
278
        
279
    ImageOutput(sigmaIn,"Ising2D_GPU_Global_%i_Initial" % (Size))
280

    
281
    Trange=numpy.arange(Tmin,Tmax+Tstep,Tstep)
282

    
283
    E=[]
284
    M=[]
285

    
286
    for T in Trange:
287
             sigma=numpy.copy(sigmaIn)
288
            duration=Metropolis(sigma,J,B,T,Iterations,Device)
289
            E=numpy.append(E,Energy(sigma,J,B))
290
            M=numpy.append(M,Magnetization(sigma,B))            
291
            ImageOutput(sigma,"Ising2D_GPU_Global_%i_%1.1f_Final" % (Size,T))
292
            print "GPU Time : %f" % (duration)
293
            print "Total Energy at Temperature %f : %f" % (T,E[-1])
294
            print "Total Magnetization at Temperature %f : %f" % (T,M[-1])
295

    
296
    # Save output
297
    numpy.savez("Ising2D_GPU_Global_%i_%.8i" % (Size,Iterations),(Trange,E,M))
298
    
299
    # Estimate Critical temperature
300
    print "The critical temperature on %ix%i lattice with J=%f, B=%f is %f " % (Size,Size,J,B,CriticalT(Trange,E))
301

    
302
    if Curves:
303
        DisplayCurves(Trange,E,M,J,B)
304