Guest User

see http://bit.ly/SZfe3U

a guest
Jul 28th, 2012
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.54 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. #
  4. # Honors project for PHYS 4700 - Electricity & Magnetism
  5. # Shad Sterling <[email protected]>
  6. #
  7. # Green particles have negative charge, Red particles have positive charge
  8. # Blue arrows represent velocity, Yellow arrows represent acceleration
  9. # Grey grid arrows are scaled electric field vectors
  10. #
  11. # Add particles by clicking on empty space (new particles will alternate charge)
  12. # Move particles by drag & drop (next new particle will have opposite charge as moved particle)
  13. # Remove particles by clicking without dragging (next new particle will have same charge)
  14. # Advance motion by clicking on any motion arrow (velocity or acceleration)
  15. # Continuously advance motion by dragging on a motion arrow and holding button down
  16. #
  17.  
  18.  
  19. from __future__ import division
  20. from visual import *
  21. import random
  22. import os
  23. import inspect
  24. import pprint
  25. import gc
  26. import time
  27.  
  28.  
  29. grid_span = 25    #number of field vectors across field width & height
  30. vec_width = 0.1   #width of grid vector arrows
  31. vec_scale = 1     #proportional length of vector arrows
  32. vec_limit = 0.5   #don't draw vectors more than this factor of the display width
  33. vec_halo = 0.9    #don't draw vectors within in this factor of a charge radius
  34. move_width = 0.6  #proportion of charge radius used for velocity & acceleration arrow widths
  35. move_scale = 3    #proportional length of velocity & acceleration arrows
  36. move_limit = 1    #distance for calculating force must be at most this proportion of radius
  37. rebound = 0.1     #velocity reflected from boundary
  38. step_time = 0.5   #simulation time per frame
  39.  
  40.  
  41. def electron( pos ):
  42.     e = sphere()
  43.     e.pos = pos
  44.     e.radius = .5 #arbitrary?
  45.     e.charge = -1 # 1e = -1.602176565(35) * 10**(-19) C
  46.     e.mass = 1 # 9.10938291(40) * 10**(-31) kg
  47.     e.color = (0,.9,0)
  48.     e.removable = true
  49.     e.vel = arrow( pos = e.pos, shaftwidth = e.radius*move_width, fixedwidth = true,
  50.                    axis = vector( 0, 0, 0 ), color = (0,.2,1), stepper = true )
  51.     e.accel = arrow( pos = e.pos, shaftwidth = e.radius*move_width, fixedwidth = true,
  52.                      axis = vector( 0, 0, 0 ), color = color.yellow, stepper = true )
  53.     return e
  54.  
  55. def positron( pos ):
  56.     e = sphere()
  57.     e.pos = pos
  58.     e.radius = .5 #arbitrary?
  59.     e.charge = 1 # 1e = -1.602176565(35) * 10**(-19) C
  60.     e.mass = 1 # 9.10938291(40) * 10**(-31) kg
  61.     e.color = (1,.1,.1)
  62.     e.removable = true
  63.     e.vel = arrow( pos = e.pos, shaftwidth = e.radius*move_width, fixedwidth = true,
  64.                    axis = vector( 0, 0, 0 ), color = (.2,0,1), stepper = true )
  65.     e.accel = arrow( pos = e.pos, shaftwidth = e.radius*move_width, fixedwidth = true,
  66.                      axis = vector( 0, 0, 0 ), color = color.yellow, stepper = true )
  67.     return e
  68.  
  69. def move( obj, pos ):
  70.     obj.pos = pos
  71.     obj.vel.pos = pos
  72.     obj.accel.pos = pos
  73.     return None
  74.  
  75. def hide( obj ):
  76.     obj.visible = false
  77.     obj.vel.visible = false
  78.     obj.accel.visible = false
  79.  
  80. def reveal( obj ):
  81.     obj.visible = true
  82.     obj.vel.visible = true
  83.     obj.accel.visible = true
  84.  
  85. def dim( obj ):
  86.     obj.opacity = 0.75
  87.     obj.vel.opacity = 0.75
  88.     obj.accel.opacity = 0.75
  89.  
  90. def bright( obj ):
  91.     obj.opacity = 1
  92.     obj.vel.opacity = 1
  93.     obj.accel.opacity = 1
  94.  
  95. def getvel( obj ):
  96.     newvel = vector(obj.vel.axis)
  97.     newvel.mag = (newvel.mag-obj.radius)/move_scale
  98.     return newvel
  99.  
  100. def setvel( obj, newvel ):
  101.     obj.vel.axis = vector( newvel )
  102.     obj.vel.axis.mag = obj.vel.axis.mag*move_scale+obj.radius
  103.     return obj.vel.axis
  104.  
  105. def getaccel( obj ):
  106.     newaccel = vector(obj.accel.axis)
  107.     newaccel.mag = (newaccel.mag-obj.radius)/move_scale
  108.     return newaccel
  109.  
  110. def setaccel( obj, newaccel ):
  111.     obj.accel.axis = vector( newaccel )
  112.     obj.accel.axis.mag = obj.accel.axis.mag*move_scale+obj.radius
  113.     return obj.accel.axis
  114.  
  115. def getarrow( objects, gridarrow ):
  116.     axis = vector( 0, 0, 0 )
  117.     for obj in objects:
  118.         if hasattr( obj, "charge" ):
  119.             r = gridarrow.pos - obj.pos #from arrow to obj
  120.             if r.mag < obj.radius*vec_halo:
  121.                 axis = vector( 0, 0, 0 )
  122.                 break
  123.             axis += r * obj.charge / (r.mag**3)
  124.     axis.mag = 0.5 + sqrt(axis.mag)*vec_scale
  125.     if axis.mag < gridarrow.shaftwidth or axis.mag > vec_limit*scene.range:
  126.         axis = vector( 0, 0, 0 )
  127.     return axis
  128.  
  129. def getforce( objects, object ):
  130.     force = vector( 0, 0, 0 )
  131.     for obj in objects:
  132.         if obj is not object and hasattr( obj, "charge" ):
  133.             r = object.pos - obj.pos
  134.             r.mag = max( r.mag, object.radius * move_limit )
  135.             force += r * object.charge * obj.charge / (r.mag**3)
  136.     return force
  137.  
  138. def repos( obj, pos=None ):
  139.     i = 0
  140.     r = false
  141.     if None == pos:
  142.         p = vector( obj.pos )
  143.     else:
  144.         p = pos
  145.     v = getvel( obj )
  146.     t = vector( p )
  147.     while i < 2:
  148.         if abs(p[i]) > scene.range[i]:
  149.             p[i] = sign(p[i]) * scene.range[i]
  150.             v[i] = -rebound * v[i]
  151.             r = true
  152.         i = i + 1
  153.     move( obj, p )
  154.     setvel( obj, v )
  155.     return r
  156.  
  157. def capacitor( count, length, width, pos, angle ):
  158.     c = cos( angle )
  159.     s = sin( angle )
  160.     count = count - 1
  161.     next = vector( length*s/count, length*c/count, 0 )
  162.     gap = vector( width*c/2, -width*s/2, 0 )
  163.     pos = vector(pos) - count*next/2
  164.     while( 0 <= count ):
  165.         electron( pos-gap )
  166.         positron( pos+gap )
  167.         pos = pos + next
  168.         count = count - 1
  169.     return None
  170.  
  171. def setup( scene, size, spacing=1 ): #range is width of field arrow area
  172.     half = ceil(abs(size/2))
  173.     scene.autoscale = false
  174.     scene.autocenter = false
  175.     scene.range = half
  176.     for obj in scene.objects:
  177.         if hasattr( obj, "gridarrow" ):
  178.             obj.visible = false
  179.     for y in xrange( int(floor(-half)), int(ceil(half)), spacing ):
  180.         for x in xrange( int(floor(-half)), int(ceil(half)), spacing ):
  181.             a = arrow( pos = ( x, y, 0 ), shaftwidth = vec_width, fixedwidth = true,
  182.                        color = color.gray(0.7) )
  183.             a.gridarrow = true
  184.             a.axis = getarrow( scene.objects, a )
  185.     return None
  186.  
  187. def refresh( objects ):
  188.     for obj in objects:
  189.         if hasattr( obj, "gridarrow" ):
  190.             obj.axis = getarrow( objects, obj )
  191.         if hasattr( obj, "accel" ) and 0 != obj.charge:
  192.             setaccel( obj, getforce( objects, obj ) / obj.mass )
  193.     return None
  194.  
  195. def update( objects ):
  196.     for obj in objects:
  197.         if hasattr( obj, "accel" ) and 0 != obj.accel.axis.mag:
  198.             #repos moves within bounds, handles rebound velocity; accel is updated by refresh()
  199.             repos( obj, obj.pos + getvel(obj)*step_time )
  200.             setvel( obj, getvel(obj)+getaccel(obj)*step_time )
  201.     return None
  202.  
  203. setup( scene, grid_span )
  204. capacitor( ceil(grid_span/3), grid_span*2/3, grid_span/2, (0,0,0), 2*math.pi*random.random() )
  205. #rotate described by http://www.vpython.org/webdoc/visual/vector.html
  206. setvel( positron( (0,0,0) ),
  207.         rotate( (grid_span/6/move_scale,0,0), 2*math.pi*random.random(), (0,0,1) ) )
  208. negative = true
  209. target = None
  210. event = None
  211. step = false
  212. changed = true
  213. run = false
  214.  
  215. ticksum = 0
  216. tickcount = 0
  217. tickwait = 0.5
  218.  
  219. while true:
  220.     if changed:
  221.         #tickstart = time.time()
  222.         if step:
  223.             update( scene.objects )
  224.         refresh( scene.objects )
  225.         gc.collect()
  226.         changed = false
  227.         #time.sleep( tickwait )
  228.         #tickend = time.time()
  229.         #ticktime = tickend - tickstart #tick time, including sync wait
  230.         #tickcount = tickcount + 1
  231.         #ticksum = ticksum + ticktime
  232.         #tickrate = tickcount/ticksum # ticks per second
  233.         #tickwait = ticksum/tickcount/2 # half of the average tick time
  234.         #print "tick", tickcount, ticktime, ticksum, 1/tickrate, tickwait, tickrate
  235.         #visual.rate( tickrate ) #why doesn't this affect drawing?
  236.         #print "refresh complete"
  237.     #else:
  238.         #print "refresh skipped"
  239.     if 0 == scene.mouse.events and ( run or None != target ) and None != event and event.drag:
  240.         #print "dragging"
  241.         newpos = vector( scene.mouse.pos[0], scene.mouse.pos[1], 0 )
  242.     else:
  243.         #print "awaiting event..."
  244.         event = scene.mouse.getevent()
  245.         newpos = vector( event.pos[0], event.pos[1], 0 )
  246.     if event.press:
  247.         if None != event.pick:
  248.             if hasattr( event.pick, "removable" ):
  249.                 target = event.pick
  250.                 startpos = vector(target.pos)
  251.                 changed = false
  252.                 #print "press:  targeted", startpos
  253.                 ##TODO: return to start if focus leaves while pressed
  254.             elif hasattr( event.pick, "stepper" ):
  255.                 #print "press:  stepping"
  256.                 #update( scene.objects )
  257.                 step = true
  258.                 changed = true
  259.                 run = true
  260.         elif None != target:
  261.                 #print "press:  replace at", newpos, "from", startpos
  262.                 move( target, newpos )
  263.                 reveal( target )
  264.                 negative = target.charge > 0
  265.                 changed = true
  266.         else:
  267.             if negative:
  268.                 #print "press:  electron at", newpos
  269.                 target = electron( newpos )
  270.                 startpos = vector(target.pos)
  271.                 negative = false
  272.                 changed = true
  273.             else:
  274.                 #print "press:  positron at", newpos
  275.                 target = positron( newpos )
  276.                 startpos = vector(target.pos)
  277.                 negative = true
  278.                 changed = true
  279.     elif event.drag:
  280.         if None != target and target.pos != newpos:
  281.             #print "drag:  dragged to", newpos, "via", target.pos, "from", startpos
  282.             move( target, newpos )
  283.             dim( target )
  284.             changed = true
  285.             drag = true
  286.         elif run:
  287.             #print "drag:  continue stepping"
  288.             #update( scene.objects )
  289.             step = true
  290.             changed = true
  291.         else:
  292.             #print "drag:  no object targeted"
  293.             changed = false
  294.     elif event.release:
  295.         if None != target:
  296.             if target.pos == startpos:
  297.                 #print "release: removed from", startpos
  298.                 hide( target )
  299.                 changed = true
  300.             else:
  301.                 #print "release: dropped at", newpos, "from", startpos
  302.                 move( target, newpos )
  303.                 bright( target )
  304.                 negative = target.charge > 0
  305.                 target = None
  306.                 startpos = None
  307.                 changed = true
  308.         elif run:
  309.             #print "release:  end stepping"
  310.             run = false
  311.         else:
  312.             #print "release:  nothing in progress"
  313.             changed = false
  314.     else:
  315.         print "Unknown Event!", pprint.pprint( inspect.getmembers( event ) )
  316.         changed = false
  317.  
  318. os._exit(0)
Add Comment
Please, Sign In to add comment