Statistiques
| Révision :

root / TrouNoir / TrouNoir.py @ 201

Historique | Voir | Annoter | Télécharger (12,35 ko)

1 199 equemene
#!/usr/bin/env python
2 199 equemene
#
3 199 equemene
# TrouNoir model using PyOpenCL
4 199 equemene
#
5 199 equemene
# CC BY-NC-SA 2011 : <emmanuel.quemener@ens-lyon.fr>
6 199 equemene
#
7 199 equemene
# Thanks to Andreas Klockner for PyOpenCL:
8 199 equemene
# http://mathema.tician.de/software/pyopencl
9 199 equemene
#
10 199 equemene
# Interesting links:
11 199 equemene
# http://viennacl.sourceforge.net/viennacl-documentation.html
12 199 equemene
# http://enja.org/2011/02/22/adventures-in-pyopencl-part-1-getting-started-with-python/
13 199 equemene
14 199 equemene
import pyopencl as cl
15 199 equemene
import numpy
16 199 equemene
from PIL import Image
17 199 equemene
import time,string
18 199 equemene
from numpy.random import randint as nprnd
19 199 equemene
import sys
20 199 equemene
import getopt
21 199 equemene
import matplotlib.pyplot as plt
22 199 equemene
23 199 equemene
KERNEL_CODE=string.Template("""
24 199 equemene

25 199 equemene
#define PI (float)3.14159265359
26 199 equemene
#define nbr 200
27 199 equemene

28 199 equemene
float atanp(float x,float y)
29 199 equemene
{
30 199 equemene
  float angle;
31 199 equemene

32 199 equemene
  angle=atan2(y,x);
33 199 equemene

34 199 equemene
  if (angle<0)
35 199 equemene
    {
36 199 equemene
      angle+=(float)2.e0f*PI;
37 199 equemene
    }
38 199 equemene

39 199 equemene
  return angle;
40 199 equemene
}
41 199 equemene

42 199 equemene
float f(float v)
43 199 equemene
{
44 199 equemene
  return v;
45 199 equemene
}
46 199 equemene

47 199 equemene
float g(float u,float m,float b)
48 199 equemene
{
49 199 equemene
  return (3.*m/b*pow(u,2)-u);
50 199 equemene
}
51 199 equemene

52 199 equemene

53 199 equemene
void calcul(float *us,float *vs,float up,float vp,
54 199 equemene
            float h,float m,float b)
55 199 equemene
{
56 199 equemene
  float c0,c1,c2,c3,d0,d1,d2,d3;
57 199 equemene

58 199 equemene
  c0=h*f(vp);
59 199 equemene
  c1=h*f(vp+c0/2.);
60 199 equemene
  c2=h*f(vp+c1/2.);
61 199 equemene
  c3=h*f(vp+c2);
62 199 equemene
  d0=h*g(up,m,b);
63 199 equemene
  d1=h*g(up+d0/2.,m,b);
64 199 equemene
  d2=h*g(up+d1/2.,m,b);
65 199 equemene
  d3=h*g(up+d2,m,b);
66 199 equemene

67 199 equemene
  *us=up+(c0+2.*c1+2.*c2+c3)/6.;
68 199 equemene
  *vs=vp+(d0+2.*d1+2.*d2+d3)/6.;
69 199 equemene
}
70 199 equemene

71 199 equemene
void rungekutta(float *ps,float *us,float *vs,
72 199 equemene
                float pp,float up,float vp,
73 199 equemene
                float h,float m,float b)
74 199 equemene
{
75 199 equemene
  calcul(us,vs,up,vp,h,m,b);
76 199 equemene
  *ps=pp+h;
77 199 equemene
}
78 199 equemene

79 199 equemene
float decalage_spectral(float r,float b,float phi,
80 199 equemene
                         float tho,float m)
81 199 equemene
{
82 199 equemene
  return (sqrt(1-3*m/r)/(1+sqrt(m/pow(r,3))*b*sin(tho)*sin(phi)));
83 199 equemene
}
84 199 equemene

85 199 equemene
float spectre(float rf,int q,float b,float db,
86 199 equemene
             float h,float r,float m,float bss)
87 199 equemene
{
88 199 equemene
  float flx;
89 199 equemene

90 201 equemene
  flx=pow(r/m,q)*pow(rf,4)*b;
91 199 equemene
  return(flx);
92 199 equemene
}
93 199 equemene

94 199 equemene
float spectre_cn(float rf,float b,float db,
95 199 equemene
                float h,float r,float m,float bss)
96 199 equemene
{
97 201 equemene
  double flx;
98 201 equemene
  double nu_rec,nu_em,qu,v,temp,temp_em,flux_int,m_point,planck,c,k,psc2,psk;
99 199 equemene
  int fi,posfreq;
100 199 equemene

101 199 equemene
  planck=6.62e-34;
102 199 equemene
  k=1.38e-23;
103 201 equemene
  psk=5.38e-11;
104 201 equemene
  psc2=7.35e-51;
105 199 equemene
  temp=3.e7;
106 199 equemene
  m_point=1.e14;
107 199 equemene
  v=1.-3./r;
108 199 equemene

109 201 equemene
  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 199 equemene

111 201 equemene
  temp_em=temp*sqrt(m)*exp(0.25*log(m_point))*exp(-0.75*log(r))*exp(-0.125*log(v))*exp(0.25*log(qu));
112 199 equemene

113 199 equemene
  flux_int=0;
114 199 equemene
  flx=0;
115 199 equemene

116 201 equemene
  for (fi=0;fi<nbr;fi++)
117 199 equemene
    {
118 201 equemene
      nu_em=bss*(float)fi/(float)nbr;
119 199 equemene
      nu_rec=nu_em*rf;
120 201 equemene
      posfreq=(int)(1./bss*nu_rec*(float)nbr);
121 199 equemene
      if ((posfreq>0)&&(posfreq<nbr))
122 199 equemene
        {
123 201 equemene
          //flux_int=2*planck/9.e16f*pow(nu_em,3)/(exp(planck*nu_em/k/temp_em)-1.)*pow(rf,3)*b*db*h;
124 201 equemene
          //flux_int=pow(nu_em,3)/(exp(planck*nu_em/k/temp_em)-1.)*pow(rf,3)*b;
125 201 equemene
          flux_int=2.*psc2*pow(nu_em,3)/(exp(psk*nu_em/temp_em)-1.)*pow(rf,3)*b;
126 199 equemene
          flx+=flux_int;
127 199 equemene
        }
128 199 equemene
    }
129 201 equemene
  //return(pow(rf,3)*b*temp_em);
130 201 equemene
  return((float)flx);
131 199 equemene
  return(flx);
132 199 equemene
}
133 199 equemene

134 199 equemene
void impact(float phi,float r,float b,float tho,float m,
135 199 equemene
            float *zp,float *fp,
136 199 equemene
            int q,float db,
137 199 equemene
            float h,float bss,int raie)
138 199 equemene
{
139 199 equemene
  float flx,rf;
140 199 equemene

141 199 equemene
  rf=decalage_spectral(r,b,phi,tho,m);
142 199 equemene

143 199 equemene
  if (raie==0)
144 199 equemene
    {
145 199 equemene
      flx=spectre(rf,q,b,db,h,r,m,bss);
146 199 equemene
    }
147 199 equemene
  else
148 199 equemene
    {
149 199 equemene
      flx=spectre_cn(rf,b,db,h,r,m,bss);
150 199 equemene
    }
151 199 equemene

152 199 equemene
  *zp=1./rf;
153 199 equemene
  *fp=flx;
154 199 equemene

155 199 equemene
}
156 199 equemene

157 201 equemene
__kernel void EachPixel(__global float *zImage,__global float *fImage)
158 199 equemene
{
159 199 equemene
   uint xi=(uint)get_global_id(0);
160 199 equemene
   uint yi=(uint)get_global_id(1);
161 199 equemene
   uint sizex=(uint)get_global_size(0);
162 199 equemene
   uint sizey=(uint)get_global_size(1);
163 199 equemene

164 199 equemene
   // Perform trajectory for each pixel
165 199 equemene

166 199 equemene
  float m,rs,ri,re,tho,ro;
167 199 equemene
  int q;
168 199 equemene

169 199 equemene
  float bss,stp;
170 199 equemene
  int nmx,dim;
171 199 equemene
  float d,bmx,db,b,h;
172 199 equemene
  float up,vp,pp;
173 199 equemene
  float us,vs,ps;
174 199 equemene
  float rp[2000];
175 199 equemene
  float zmx,fmx,zen,fen;
176 199 equemene
  float flux_tot,impc_tot;
177 199 equemene
  float phi,thi,thx,phd,php,nr,r;
178 199 equemene
  int ni,ii,i,imx,j,n,tst,dist,raie,pc,fcl,zcl;
179 199 equemene
  int nh;
180 199 equemene
  int ExitOnImpact;
181 199 equemene
  float zp,fp;
182 199 equemene

183 199 equemene
  m=1.;
184 199 equemene
  rs=2.*m;
185 199 equemene
  ri=3.*rs;
186 199 equemene
  re=12.;
187 199 equemene
  ro=100.;
188 199 equemene
  //tho=PI/180.*80;
189 200 equemene
  tho=PI/180.*80.;
190 199 equemene
  q=-2;
191 201 equemene
  dist=0;
192 199 equemene
  raie=0;
193 199 equemene

194 199 equemene
  nmx=(float)sizex/2.;
195 199 equemene
  stp=0.5;
196 199 equemene
  // Autosize for image
197 199 equemene
  bmx=1.25*re;
198 199 equemene
  b=0.;
199 199 equemene
  thx=asin(bmx/ro);
200 199 equemene
  pc=0;
201 199 equemene

202 201 equemene
  if (raie==0)
203 201 equemene
    {
204 201 equemene
      bss=2.;
205 201 equemene
    }
206 201 equemene
  else
207 201 equemene
    {
208 201 equemene
      bss=1.e6;
209 201 equemene
    }
210 201 equemene

211 199 equemene
  h=PI/5.e2f;
212 199 equemene

213 199 equemene
  // set origin as center of image
214 199 equemene
  float x=(float)xi-(float)(sizex/2)+(float)5e-1f;
215 201 equemene
  float y=(float)yi-(float)(sizey/2)+(float)5e-1f;
216 199 equemene
  // angle extracted from cylindric symmetry
217 199 equemene
  phi=atanp(x,y);
218 199 equemene
  phd=atanp(cos(phi)*sin(tho),cos(tho));
219 199 equemene

220 199 equemene
  if (dist==1)
221 199 equemene
  {
222 199 equemene
     db=bmx/nmx;
223 199 equemene
     // impact parameter
224 199 equemene
     b=sqrt(x*x+y*y)*(float)2.e0f/(float)sizex*bmx;
225 199 equemene
     up=0.;
226 199 equemene
     vp=1.;
227 199 equemene
  }
228 199 equemene
  else
229 199 equemene
  {
230 199 equemene
     b=sqrt(x*x+y*y)*(float)2.e0f/(float)sizex*bmx;
231 199 equemene
     thi=asin(b/ro);
232 199 equemene
     db=bmx/nmx;
233 199 equemene
     up=sin(thi);
234 199 equemene
     vp=cos(thi);
235 199 equemene
  }
236 199 equemene

237 199 equemene
  pp=0.;
238 199 equemene
  nh=0;
239 199 equemene

240 199 equemene
  rungekutta(&ps,&us,&vs,pp,up,vp,h,m,b);
241 199 equemene

242 199 equemene
  rp[nh]=fabs(b/us);
243 199 equemene

244 199 equemene
  ExitOnImpact=0;
245 199 equemene

246 199 equemene
  do
247 199 equemene
  {
248 199 equemene
     nh++;
249 199 equemene
     pp=ps;
250 199 equemene
     up=us;
251 199 equemene
     vp=vs;
252 199 equemene
     rungekutta(&ps,&us,&vs,pp,up,vp,h,m,b);
253 199 equemene
     rp[nh]=fabs(b/us);
254 200 equemene
     ExitOnImpact = ((fmod(pp,PI)<fmod(phd,PI))&&(fmod(ps,PI)>fmod(phd,PI)))&&(rp[nh]>ri)&&(rp[nh]<re)?1:0;
255 199 equemene

256 199 equemene
  } while ((rp[nh]>=rs)&&(rp[nh]<=rp[0])&&(ExitOnImpact==0));
257 199 equemene

258 199 equemene
  if (ExitOnImpact==1) {
259 199 equemene
     impact(phi,rp[nh-1],b,tho,m,&zp,&fp,q,db,h,bss,raie);
260 199 equemene
  }
261 199 equemene
  else
262 199 equemene
  {
263 199 equemene
     zp=0.;
264 201 equemene
     fp=0.;
265 199 equemene
  }
266 199 equemene

267 199 equemene
//
268 201 equemene
  zImage[yi+sizex*xi]=(float)zp;
269 201 equemene
  fImage[yi+sizex*xi]=(float)fp;
270 199 equemene

271 201 equemene
  barrier(CLK_GLOBAL_MEM_FENCE);
272 199 equemene

273 199 equemene
}
274 199 equemene
""")
275 199 equemene
276 199 equemene
def ImageOutput(sigma,prefix):
277 199 equemene
    Max=sigma.max()
278 199 equemene
    Min=sigma.min()
279 199 equemene
280 199 equemene
    # Normalize value as 8bits Integer
281 199 equemene
    SigmaInt=(255*(sigma-Min)/(Max-Min)).astype('uint8')
282 199 equemene
    image = Image.fromarray(SigmaInt)
283 199 equemene
    image.save("%s.jpg" % prefix)
284 199 equemene
285 201 equemene
def BlackHole(zImage,fImage,Device):
286 199 equemene
287 199 equemene
    kernel_params = {}
288 199 equemene
289 199 equemene
    # Je detecte un peripherique GPU dans la liste des peripheriques
290 199 equemene
    Id=0
291 199 equemene
    HasXPU=False
292 199 equemene
    for platform in cl.get_platforms():
293 199 equemene
        for device in platform.get_devices():
294 199 equemene
            if Id==Device:
295 199 equemene
                XPU=device
296 199 equemene
                print "CPU/GPU selected: ",device.name.lstrip()
297 199 equemene
                HasXPU=True
298 199 equemene
            Id+=1
299 199 equemene
300 199 equemene
    if HasXPU==False:
301 199 equemene
        print "No XPU #%i found in all of %i devices, sorry..." % (Device,Id-1)
302 199 equemene
        sys.exit()
303 199 equemene
304 199 equemene
    ctx = cl.Context([XPU])
305 199 equemene
    queue = cl.CommandQueue(ctx,
306 199 equemene
                            properties=cl.command_queue_properties.PROFILING_ENABLE)
307 199 equemene
308 199 equemene
    BlackHoleCL = cl.Program(ctx,KERNEL_CODE.substitute(kernel_params)).build()
309 199 equemene
310 199 equemene
    # Je recupere les flag possibles pour les buffers
311 199 equemene
    mf = cl.mem_flags
312 199 equemene
313 201 equemene
    print(zImage)
314 199 equemene
315 199 equemene
    # Program based on Kernel2
316 201 equemene
    zImageCL = cl.Buffer(ctx, mf.WRITE_ONLY | mf.COPY_HOST_PTR, hostbuf=zImage)
317 201 equemene
    fImageCL = cl.Buffer(ctx, mf.WRITE_ONLY | mf.COPY_HOST_PTR, hostbuf=fImage)
318 199 equemene
319 199 equemene
    start_time=time.time()
320 199 equemene
321 201 equemene
    CLLaunch=BlackHoleCL.EachPixel(queue,(numpy.int32(zImage.shape[0]),numpy.int32(zImage.shape[1])),None,zImageCL,fImageCL)
322 199 equemene
323 199 equemene
    CLLaunch.wait()
324 199 equemene
    elapsed = time.time()-start_time
325 199 equemene
    print("Elapsed %f: " % elapsed)
326 199 equemene
327 201 equemene
    cl.enqueue_copy(queue,zImage,zImageCL).wait()
328 201 equemene
    cl.enqueue_copy(queue,fImage,fImageCL).wait()
329 199 equemene
330 201 equemene
    print(zImage.max())
331 201 equemene
    print(fImage.max())
332 201 equemene
    zImageCL.release()
333 201 equemene
    fImageCL.release()
334 201 equemene
335 201 equemene
    ImageOutput(zImage,"TrouNoirZ")
336 201 equemene
    ImageOutput(fImage,"TrouNoirF")
337 199 equemene
    return(elapsed)
338 199 equemene
339 199 equemene
if __name__=='__main__':
340 199 equemene
341 199 equemene
    GpuStyle = 'OpenCL'
342 199 equemene
    Mass = 1.
343 199 equemene
    # Internal Radius 3 times de Schwarzschild Radius
344 199 equemene
    InternalRadius=6.*Mass
345 199 equemene
    #
346 199 equemene
    ExternalRadius=12.
347 199 equemene
    #
348 199 equemene
    ObserverDistance=100.
349 199 equemene
    # Angle with normal to disc 10 degrees
350 199 equemene
    Angle = numpy.pi/180.*(90.-10.)
351 199 equemene
    # Radiation of disc : BlackBody or Monochromatic
352 199 equemene
    BlackBody = True
353 199 equemene
    # Camera : Angular Camera or plate with the size of camera
354 199 equemene
    AngularCamera = True
355 199 equemene
    # Size of image
356 199 equemene
    Size=256
357 199 equemene
    # Variable Type
358 199 equemene
    VariableType='FP32'
359 199 equemene
    # ?
360 199 equemene
    q=-2
361 199 equemene
362 199 equemene
    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>'
363 199 equemene
364 199 equemene
    try:
365 199 equemene
        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="])
366 199 equemene
    except getopt.GetoptError:
367 199 equemene
        print(HowToUse % sys.argv[0])
368 199 equemene
        sys.exit(2)
369 199 equemene
370 199 equemene
    # List of Devices
371 199 equemene
    Devices=[]
372 199 equemene
    Alu={}
373 199 equemene
374 199 equemene
    for opt, arg in opts:
375 199 equemene
        if opt == '-h':
376 199 equemene
            print(HowToUse % sys.argv[0])
377 199 equemene
378 199 equemene
            print("\nInformations about devices detected under OpenCL API:")
379 199 equemene
            # For PyOpenCL import
380 199 equemene
            try:
381 199 equemene
                import pyopencl as cl
382 199 equemene
                Id=0
383 199 equemene
                for platform in cl.get_platforms():
384 199 equemene
                    for device in platform.get_devices():
385 199 equemene
                        #deviceType=cl.device_type.to_string(device.type)
386 199 equemene
                        deviceType="xPU"
387 199 equemene
                        print("Device #%i from %s of type %s : %s" % (Id,platform.vendor.lstrip(),deviceType,device.name.lstrip()))
388 199 equemene
                        Id=Id+1
389 199 equemene
390 199 equemene
            except:
391 199 equemene
                print("Your platform does not seem to support OpenCL")
392 199 equemene
393 199 equemene
            print("\nInformations about devices detected under CUDA API:")
394 199 equemene
                # For PyCUDA import
395 199 equemene
            try:
396 199 equemene
                import pycuda.driver as cuda
397 199 equemene
                cuda.init()
398 199 equemene
                for Id in range(cuda.Device.count()):
399 199 equemene
                    device=cuda.Device(Id)
400 199 equemene
                    print("Device #%i of type GPU : %s" % (Id,device.name()))
401 199 equemene
                print
402 199 equemene
            except:
403 199 equemene
                print("Your platform does not seem to support CUDA")
404 199 equemene
405 199 equemene
            sys.exit()
406 199 equemene
407 199 equemene
        elif opt in ("-d", "--device"):
408 199 equemene
#            Devices.append(int(arg))
409 199 equemene
            Device=int(arg)
410 199 equemene
        elif opt in ("-g", "--gpustyle"):
411 199 equemene
            GpuStyle = arg
412 199 equemene
        elif opt in ("-t", "--variabletype"):
413 199 equemene
            VariableType = arg
414 199 equemene
        elif opt in ("-s", "--size"):
415 199 equemene
            Size = int(arg)
416 199 equemene
        elif opt in ("-m", "--mass"):
417 199 equemene
            Mass = float(arg)
418 199 equemene
        elif opt in ("-i", "--internal"):
419 199 equemene
            InternalRadius = float(arg)
420 199 equemene
        elif opt in ("-e", "--external"):
421 199 equemene
            ExternalRadius = float(arg)
422 199 equemene
        elif opt in ("-o", "--observer"):
423 199 equemene
            ObserverDistance = float(arg)
424 199 equemene
        elif opt in ("-a", "--angle"):
425 199 equemene
            Angle = numpy.pi/180.*(90.-float(arg))
426 199 equemene
        elif opt in ("-b", "--blackbody"):
427 199 equemene
            BlackBody = True
428 199 equemene
        elif opt in ("-c", "--camera"):
429 199 equemene
            AngularCamera = True
430 199 equemene
431 199 equemene
    print("Device Identification selected : %s" % Device)
432 199 equemene
    print("GpuStyle used : %s" % GpuStyle)
433 199 equemene
    print("VariableType : %s" % VariableType)
434 199 equemene
    print("Size : %i" % Size)
435 199 equemene
    print("Mass : %f" % Mass)
436 199 equemene
    print("Internal Radius : %f" % InternalRadius)
437 199 equemene
    print("External Radius : %f" % ExternalRadius)
438 199 equemene
    print("Observer Distance : %f" % ObserverDistance)
439 199 equemene
    print("Angle with normal of (in radians) : %f" % Angle)
440 199 equemene
    print("Black Body Disc Emission (monochromatic instead) : %s" % BlackBody)
441 199 equemene
    print("Angular Camera (dimension of object instead) : %s" % AngularCamera)
442 199 equemene
443 199 equemene
    if GpuStyle=='CUDA':
444 199 equemene
        print("\nSelection of CUDA device")
445 199 equemene
        try:
446 199 equemene
            # For PyCUDA import
447 199 equemene
            import pycuda.driver as cuda
448 199 equemene
449 199 equemene
            cuda.init()
450 199 equemene
            for Id in range(cuda.Device.count()):
451 199 equemene
                device=cuda.Device(Id)
452 199 equemene
                print("Device #%i of type GPU : %s" % (Id,device.name()))
453 199 equemene
                if Id in Devices:
454 199 equemene
                    Alu[Id]='GPU'
455 199 equemene
456 199 equemene
        except ImportError:
457 199 equemene
            print("Platform does not seem to support CUDA")
458 199 equemene
459 199 equemene
    if GpuStyle=='OpenCL':
460 199 equemene
        print("\nSelection of OpenCL device")
461 199 equemene
        try:
462 199 equemene
            # For PyOpenCL import
463 199 equemene
            import pyopencl as cl
464 199 equemene
            Id=0
465 199 equemene
            for platform in cl.get_platforms():
466 199 equemene
                for device in platform.get_devices():
467 199 equemene
                    #deviceType=cl.device_type.to_string(device.type)
468 199 equemene
                    deviceType="xPU"
469 199 equemene
                    print("Device #%i from %s of type %s : %s" % (Id,platform.vendor.lstrip().rstrip(),deviceType,device.name.lstrip().rstrip()))
470 199 equemene
471 199 equemene
                    if Id in Devices:
472 199 equemene
                    # Set the Alu as detected Device Type
473 199 equemene
                        Alu[Id]=deviceType
474 199 equemene
                    Id=Id+1
475 199 equemene
        except ImportError:
476 199 equemene
            print("Platform does not seem to support OpenCL")
477 199 equemene
478 199 equemene
#    print(Devices,Alu)
479 199 equemene
480 199 equemene
#    MyImage=numpy.where(numpy.random.zeros(Size,Size)>0,1,-1).astype(numpy.float32)
481 201 equemene
    zImage=numpy.zeros((Size,Size),dtype=numpy.float32)
482 201 equemene
    fImage=numpy.zeros((Size,Size),dtype=numpy.float32)
483 199 equemene
484 201 equemene
    print(zImage)
485 199 equemene
486 201 equemene
    duration=BlackHole(zImage,fImage,Device)
487 199 equemene