root / TrouNoir / TrouNoir.py @ 199
Historique | Voir | Annoter | Télécharger (11,73 ko)
1 |
#!/usr/bin/env python
|
---|---|
2 |
#
|
3 |
# TrouNoir 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 PIL import Image |
17 |
import time,string |
18 |
from numpy.random import randint as nprnd |
19 |
import sys |
20 |
import getopt |
21 |
import matplotlib.pyplot as plt |
22 |
|
23 |
KERNEL_CODE=string.Template("""
|
24 |
|
25 |
#define PI (float)3.14159265359
|
26 |
#define nbr 200
|
27 |
|
28 |
float atanp(float x,float y)
|
29 |
{
|
30 |
float angle;
|
31 |
|
32 |
angle=atan2(y,x);
|
33 |
|
34 |
if (angle<0)
|
35 |
{
|
36 |
angle+=(float)2.e0f*PI;
|
37 |
}
|
38 |
|
39 |
return angle;
|
40 |
}
|
41 |
|
42 |
float f(float v)
|
43 |
{
|
44 |
return v;
|
45 |
}
|
46 |
|
47 |
float g(float u,float m,float b)
|
48 |
{
|
49 |
return (3.*m/b*pow(u,2)-u);
|
50 |
}
|
51 |
|
52 |
|
53 |
void calcul(float *us,float *vs,float up,float vp,
|
54 |
float h,float m,float b)
|
55 |
{
|
56 |
float c0,c1,c2,c3,d0,d1,d2,d3;
|
57 |
|
58 |
c0=h*f(vp);
|
59 |
c1=h*f(vp+c0/2.);
|
60 |
c2=h*f(vp+c1/2.);
|
61 |
c3=h*f(vp+c2);
|
62 |
d0=h*g(up,m,b);
|
63 |
d1=h*g(up+d0/2.,m,b);
|
64 |
d2=h*g(up+d1/2.,m,b);
|
65 |
d3=h*g(up+d2,m,b);
|
66 |
|
67 |
*us=up+(c0+2.*c1+2.*c2+c3)/6.;
|
68 |
*vs=vp+(d0+2.*d1+2.*d2+d3)/6.;
|
69 |
}
|
70 |
|
71 |
void rungekutta(float *ps,float *us,float *vs,
|
72 |
float pp,float up,float vp,
|
73 |
float h,float m,float b)
|
74 |
{
|
75 |
calcul(us,vs,up,vp,h,m,b);
|
76 |
*ps=pp+h;
|
77 |
}
|
78 |
|
79 |
float decalage_spectral(float r,float b,float phi,
|
80 |
float tho,float m)
|
81 |
{
|
82 |
return (sqrt(1-3*m/r)/(1+sqrt(m/pow(r,3))*b*sin(tho)*sin(phi)));
|
83 |
}
|
84 |
|
85 |
float spectre(float rf,int q,float b,float db,
|
86 |
float h,float r,float m,float bss)
|
87 |
{
|
88 |
float flx;
|
89 |
int fi;
|
90 |
|
91 |
fi=(int)(rf*nbr/bss);
|
92 |
flx=pow(r/m,q)*pow(rf,4)*b*db*h;
|
93 |
return(flx);
|
94 |
}
|
95 |
|
96 |
float spectre_cn(float rf,float b,float db,
|
97 |
float h,float r,float m,float bss)
|
98 |
{
|
99 |
float flx;
|
100 |
float nu_rec,nu_em,qu,v,temp,temp_em,flux_int,m_point,planck,c,k;
|
101 |
int fi,posfreq;
|
102 |
|
103 |
planck=6.62e-34;
|
104 |
k=1.38e-23;
|
105 |
temp=3.e7;
|
106 |
m_point=1.e14;
|
107 |
v=1.-3./r;
|
108 |
|
109 |
qu=1/sqrt(1-3./r)/sqrt(r)*(sqrt(r)-sqrt(6.)+sqrt(3.)/2.*log((sqrt(r)+sqrt(3.))/(sqrt(r)-sqrt(3.))*(sqrt(6.)-sqrt(3.))/(sqrt(6.)+sqrt(3.))));
|
110 |
|
111 |
temp_em=temp*sqrt(m)*exp(0.25*log(m_point))*exp(-0.75*log(r))*
|
112 |
exp(-0.125*log(v))*exp(0.25*log(qu));
|
113 |
|
114 |
flux_int=0;
|
115 |
flx=0;
|
116 |
|
117 |
for (fi=1;fi<nbr;fi++)
|
118 |
{
|
119 |
nu_em=bss*fi/nbr;
|
120 |
nu_rec=nu_em*rf;
|
121 |
posfreq=1./bss*nu_rec*nbr;
|
122 |
if ((posfreq>0)&&(posfreq<nbr))
|
123 |
{
|
124 |
flux_int=2*planck/9.e16f*pow(nu_em,3)/(exp(planck*nu_em/k/temp_em)-1.)*pow(rf,3)*b*db*h;
|
125 |
flx+=flux_int;
|
126 |
}
|
127 |
}
|
128 |
return(flx);
|
129 |
}
|
130 |
|
131 |
void impact(float phi,float r,float b,float tho,float m,
|
132 |
float *zp,float *fp,
|
133 |
int q,float db,
|
134 |
float h,float bss,int raie)
|
135 |
{
|
136 |
float flx,rf;
|
137 |
|
138 |
rf=decalage_spectral(r,b,phi,tho,m);
|
139 |
|
140 |
if (raie==0)
|
141 |
{
|
142 |
flx=spectre(rf,q,b,db,h,r,m,bss);
|
143 |
}
|
144 |
else
|
145 |
{
|
146 |
flx=spectre_cn(rf,b,db,h,r,m,bss);
|
147 |
}
|
148 |
|
149 |
*zp=1./rf;
|
150 |
*fp=flx;
|
151 |
|
152 |
}
|
153 |
|
154 |
__kernel void EachPixel(__global float *MyImage)
|
155 |
{
|
156 |
uint xi=(uint)get_global_id(0);
|
157 |
uint yi=(uint)get_global_id(1);
|
158 |
uint sizex=(uint)get_global_size(0);
|
159 |
uint sizey=(uint)get_global_size(1);
|
160 |
|
161 |
// Perform trajectory for each pixel
|
162 |
|
163 |
float m,rs,ri,re,tho,ro;
|
164 |
int q;
|
165 |
|
166 |
float bss,stp;
|
167 |
int nmx,dim;
|
168 |
float d,bmx,db,b,h;
|
169 |
float up,vp,pp;
|
170 |
float us,vs,ps;
|
171 |
float rp[2000];
|
172 |
float zmx,fmx,zen,fen;
|
173 |
float flux_tot,impc_tot;
|
174 |
float phi,thi,thx,phd,php,nr,r;
|
175 |
int ni,ii,i,imx,j,n,tst,dist,raie,pc,fcl,zcl;
|
176 |
int nh;
|
177 |
int ExitOnImpact;
|
178 |
float zp,fp;
|
179 |
|
180 |
m=1.;
|
181 |
rs=2.*m;
|
182 |
ri=3.*rs;
|
183 |
re=12.;
|
184 |
ro=100.;
|
185 |
//tho=PI/180.*80;
|
186 |
tho=PI/180.*0.;
|
187 |
q=-2;
|
188 |
dist=1;
|
189 |
raie=0;
|
190 |
|
191 |
nmx=(float)sizex/2.;
|
192 |
stp=0.5;
|
193 |
// Autosize for image
|
194 |
bmx=1.25*re;
|
195 |
b=0.;
|
196 |
thx=asin(bmx/ro);
|
197 |
pc=0;
|
198 |
|
199 |
h=PI/5.e2f;
|
200 |
|
201 |
// set origin as center of image
|
202 |
float x=(float)xi-(float)(sizex/2)+(float)5e-1f;
|
203 |
float y=(float)(sizey/2)-(float)yi-(float)5e-1f;
|
204 |
// angle extracted from cylindric symmetry
|
205 |
phi=atanp(x,y);
|
206 |
phd=atanp(cos(phi)*sin(tho),cos(tho));
|
207 |
|
208 |
if (dist==1)
|
209 |
{
|
210 |
db=bmx/nmx;
|
211 |
// impact parameter
|
212 |
b=sqrt(x*x+y*y)*(float)2.e0f/(float)sizex*bmx;
|
213 |
up=0.;
|
214 |
vp=1.;
|
215 |
}
|
216 |
else
|
217 |
{
|
218 |
b=sqrt(x*x+y*y)*(float)2.e0f/(float)sizex*bmx;
|
219 |
thi=asin(b/ro);
|
220 |
db=bmx/nmx;
|
221 |
up=sin(thi);
|
222 |
vp=cos(thi);
|
223 |
}
|
224 |
|
225 |
pp=0.;
|
226 |
nh=0;
|
227 |
|
228 |
rungekutta(&ps,&us,&vs,pp,up,vp,h,m,b);
|
229 |
|
230 |
rp[nh]=fabs(b/us);
|
231 |
|
232 |
ExitOnImpact=0;
|
233 |
|
234 |
do
|
235 |
{
|
236 |
nh++;
|
237 |
pp=ps;
|
238 |
up=us;
|
239 |
vp=vs;
|
240 |
rungekutta(&ps,&us,&vs,pp,up,vp,h,m,b);
|
241 |
rp[nh]=fabs(b/us);
|
242 |
ExitOnImpact = (((fmod(pp,PI)<fmod(phd,PI))&&(fmod(ps,PI)>fmod(phd,PI)))||((fmod(ps,PI)<fmod(phd,PI))&&(fmod(pp,PI)>fmod(phd,PI))))&&(rp[nh]>ri)&&(rp[nh]<re)?1:0;
|
243 |
|
244 |
} while ((rp[nh]>=rs)&&(rp[nh]<=rp[0])&&(ExitOnImpact==0));
|
245 |
|
246 |
if (ExitOnImpact==1) {
|
247 |
impact(phi,rp[nh-1],b,tho,m,&zp,&fp,q,db,h,bss,raie);
|
248 |
}
|
249 |
else
|
250 |
{
|
251 |
zp=0.;
|
252 |
}
|
253 |
|
254 |
//
|
255 |
MyImage[yi+sizex*xi]=(float)zp;
|
256 |
|
257 |
barrier(CLK_LOCAL_MEM_FENCE);
|
258 |
|
259 |
}
|
260 |
""")
|
261 |
|
262 |
def ImageOutput(sigma,prefix): |
263 |
Max=sigma.max() |
264 |
Min=sigma.min() |
265 |
|
266 |
# Normalize value as 8bits Integer
|
267 |
SigmaInt=(255*(sigma-Min)/(Max-Min)).astype('uint8') |
268 |
image = Image.fromarray(SigmaInt) |
269 |
image.save("%s.jpg" % prefix)
|
270 |
|
271 |
def BlackHole(MyImage,Device): |
272 |
|
273 |
kernel_params = {} |
274 |
|
275 |
# Je detecte un peripherique GPU dans la liste des peripheriques
|
276 |
Id=0
|
277 |
HasXPU=False
|
278 |
for platform in cl.get_platforms(): |
279 |
for device in platform.get_devices(): |
280 |
if Id==Device:
|
281 |
XPU=device |
282 |
print "CPU/GPU selected: ",device.name.lstrip() |
283 |
HasXPU=True
|
284 |
Id+=1
|
285 |
|
286 |
if HasXPU==False: |
287 |
print "No XPU #%i found in all of %i devices, sorry..." % (Device,Id-1) |
288 |
sys.exit() |
289 |
|
290 |
ctx = cl.Context([XPU]) |
291 |
queue = cl.CommandQueue(ctx, |
292 |
properties=cl.command_queue_properties.PROFILING_ENABLE) |
293 |
|
294 |
BlackHoleCL = cl.Program(ctx,KERNEL_CODE.substitute(kernel_params)).build() |
295 |
|
296 |
# Je recupere les flag possibles pour les buffers
|
297 |
mf = cl.mem_flags |
298 |
|
299 |
print(MyImage) |
300 |
|
301 |
# Program based on Kernel2
|
302 |
MyImageCL = cl.Buffer(ctx, mf.WRITE_ONLY | mf.COPY_HOST_PTR, hostbuf=MyImage) |
303 |
|
304 |
start_time=time.time() |
305 |
|
306 |
CLLaunch=BlackHoleCL.EachPixel(queue,(MyImage.shape[0],MyImage.shape[1]),None,MyImageCL) |
307 |
|
308 |
CLLaunch.wait() |
309 |
elapsed = time.time()-start_time |
310 |
print("Elapsed %f: " % elapsed)
|
311 |
|
312 |
cl.enqueue_copy(queue,MyImage,MyImageCL).wait() |
313 |
|
314 |
print(MyImage) |
315 |
MyImageCL.release() |
316 |
|
317 |
ImageOutput(MyImage,"TrouNoir")
|
318 |
return(elapsed)
|
319 |
|
320 |
if __name__=='__main__': |
321 |
|
322 |
GpuStyle = 'OpenCL'
|
323 |
Mass = 1.
|
324 |
# Internal Radius 3 times de Schwarzschild Radius
|
325 |
InternalRadius=6.*Mass
|
326 |
#
|
327 |
ExternalRadius=12.
|
328 |
#
|
329 |
ObserverDistance=100.
|
330 |
# Angle with normal to disc 10 degrees
|
331 |
Angle = numpy.pi/180.*(90.-10.) |
332 |
# Radiation of disc : BlackBody or Monochromatic
|
333 |
BlackBody = True
|
334 |
# Camera : Angular Camera or plate with the size of camera
|
335 |
AngularCamera = True
|
336 |
# Size of image
|
337 |
Size=256
|
338 |
# Variable Type
|
339 |
VariableType='FP32'
|
340 |
# ?
|
341 |
q=-2
|
342 |
|
343 |
HowToUse='%s -h [Help] -b [BlackBodyEmission] -c [AngularCamera] -s <SizeInPixels> -m <Mass> -i <DiscInternalRadius> -x <DiscExternalRadius> -o <ObservatorDistance> -a <AngleAboveDisc> -d <DeviceId> -g <CUDA/OpenCL> -t <FP32/FP64>'
|
344 |
|
345 |
try:
|
346 |
opts, args = getopt.getopt(sys.argv[1:],"hbcs:m:i:x:o:a:d:g:t:",["blackbody","camera","size=","mass=","internal=","external=","observer=","angle=","device=","gpustyle=","variabletype="]) |
347 |
except getopt.GetoptError:
|
348 |
print(HowToUse % sys.argv[0])
|
349 |
sys.exit(2)
|
350 |
|
351 |
# List of Devices
|
352 |
Devices=[] |
353 |
Alu={} |
354 |
|
355 |
for opt, arg in opts: |
356 |
if opt == '-h': |
357 |
print(HowToUse % sys.argv[0])
|
358 |
|
359 |
print("\nInformations about devices detected under OpenCL API:")
|
360 |
# For PyOpenCL import
|
361 |
try:
|
362 |
import pyopencl as cl |
363 |
Id=0
|
364 |
for platform in cl.get_platforms(): |
365 |
for device in platform.get_devices(): |
366 |
#deviceType=cl.device_type.to_string(device.type)
|
367 |
deviceType="xPU"
|
368 |
print("Device #%i from %s of type %s : %s" % (Id,platform.vendor.lstrip(),deviceType,device.name.lstrip()))
|
369 |
Id=Id+1
|
370 |
|
371 |
except:
|
372 |
print("Your platform does not seem to support OpenCL")
|
373 |
|
374 |
print("\nInformations about devices detected under CUDA API:")
|
375 |
# For PyCUDA import
|
376 |
try:
|
377 |
import pycuda.driver as cuda |
378 |
cuda.init() |
379 |
for Id in range(cuda.Device.count()): |
380 |
device=cuda.Device(Id) |
381 |
print("Device #%i of type GPU : %s" % (Id,device.name()))
|
382 |
print
|
383 |
except:
|
384 |
print("Your platform does not seem to support CUDA")
|
385 |
|
386 |
sys.exit() |
387 |
|
388 |
elif opt in ("-d", "--device"): |
389 |
# Devices.append(int(arg))
|
390 |
Device=int(arg)
|
391 |
elif opt in ("-g", "--gpustyle"): |
392 |
GpuStyle = arg |
393 |
elif opt in ("-t", "--variabletype"): |
394 |
VariableType = arg |
395 |
elif opt in ("-s", "--size"): |
396 |
Size = int(arg)
|
397 |
elif opt in ("-m", "--mass"): |
398 |
Mass = float(arg)
|
399 |
elif opt in ("-i", "--internal"): |
400 |
InternalRadius = float(arg)
|
401 |
elif opt in ("-e", "--external"): |
402 |
ExternalRadius = float(arg)
|
403 |
elif opt in ("-o", "--observer"): |
404 |
ObserverDistance = float(arg)
|
405 |
elif opt in ("-a", "--angle"): |
406 |
Angle = numpy.pi/180.*(90.-float(arg)) |
407 |
elif opt in ("-b", "--blackbody"): |
408 |
BlackBody = True
|
409 |
elif opt in ("-c", "--camera"): |
410 |
AngularCamera = True
|
411 |
|
412 |
print("Device Identification selected : %s" % Device)
|
413 |
print("GpuStyle used : %s" % GpuStyle)
|
414 |
print("VariableType : %s" % VariableType)
|
415 |
print("Size : %i" % Size)
|
416 |
print("Mass : %f" % Mass)
|
417 |
print("Internal Radius : %f" % InternalRadius)
|
418 |
print("External Radius : %f" % ExternalRadius)
|
419 |
print("Observer Distance : %f" % ObserverDistance)
|
420 |
print("Angle with normal of (in radians) : %f" % Angle)
|
421 |
print("Black Body Disc Emission (monochromatic instead) : %s" % BlackBody)
|
422 |
print("Angular Camera (dimension of object instead) : %s" % AngularCamera)
|
423 |
|
424 |
if GpuStyle=='CUDA': |
425 |
print("\nSelection of CUDA device")
|
426 |
try:
|
427 |
# For PyCUDA import
|
428 |
import pycuda.driver as cuda |
429 |
|
430 |
cuda.init() |
431 |
for Id in range(cuda.Device.count()): |
432 |
device=cuda.Device(Id) |
433 |
print("Device #%i of type GPU : %s" % (Id,device.name()))
|
434 |
if Id in Devices: |
435 |
Alu[Id]='GPU'
|
436 |
|
437 |
except ImportError: |
438 |
print("Platform does not seem to support CUDA")
|
439 |
|
440 |
if GpuStyle=='OpenCL': |
441 |
print("\nSelection of OpenCL device")
|
442 |
try:
|
443 |
# For PyOpenCL import
|
444 |
import pyopencl as cl |
445 |
Id=0
|
446 |
for platform in cl.get_platforms(): |
447 |
for device in platform.get_devices(): |
448 |
#deviceType=cl.device_type.to_string(device.type)
|
449 |
deviceType="xPU"
|
450 |
print("Device #%i from %s of type %s : %s" % (Id,platform.vendor.lstrip().rstrip(),deviceType,device.name.lstrip().rstrip()))
|
451 |
|
452 |
if Id in Devices: |
453 |
# Set the Alu as detected Device Type
|
454 |
Alu[Id]=deviceType |
455 |
Id=Id+1
|
456 |
except ImportError: |
457 |
print("Platform does not seem to support OpenCL")
|
458 |
|
459 |
# print(Devices,Alu)
|
460 |
|
461 |
# MyImage=numpy.where(numpy.random.zeros(Size,Size)>0,1,-1).astype(numpy.float32)
|
462 |
MyImage=numpy.zeros((Size,Size),dtype=numpy.float32) |
463 |
|
464 |
print(MyImage) |
465 |
|
466 |
duration=BlackHole(MyImage,Device) |
467 |
|
468 |
|