2 # Copyright 2009 Daniel Cardenas All rights reserved.
3 # Sub atomic particles as standing electromagnetic waves.
4 # Strong and weak nuclear force are manifestations of electromagnetic forces.
12 # Force on other particles? (nah, just calulate it twice)
15 # Energy problem with this simulation:
16 # When parts are very close to each other the electric force is very strong. Approaching infinity as distance approaches zero.
17 # Simple simulation with discrete time quantum can't handle this problem.
18 # When electron is approaching proton its speed is increasing. When passing proton it has higher speed.
19 # Because of higher speed it is further away and therefore won't lose all of the energy gain.
20 # Lets call this digital energy gain.
22 # Simulation has error, energy gain, because wl.dt is not infinitely small.
23 # When electron approaches proton there are more samples taken as electron approaches proton then
24 # when leaving proton, because aproaching proton speed is slower and when leaving speed is higher.
25 # Gaining or Losing Energy: http://www.schlitt.net/xstar/n-body.pdf
26 # Simulated orbits spiral outwards: http://burtleburtle.net/bob/math/multistep.html
27 # http://www.amara.com/papers/nbody.html
28 # http://www.physicsforums.com/showpost.php?p=677453&postcount=5
30 # What are options for compensating for digital energy gain?
31 # 1. Only lose energy when in escape mode
32 # 2. Variable wl.dt, variable time quantum. Change the time quantum so it loses energy leaving close particle.
33 # 3. Lose energy after gained a lot? Track energy of the system. Problem how to calculate energy of system with infinite energy.
34 # 4. Figure out the path and velocity that the electron would really take and have. Difficult since electric fields are changing.
35 # Possible if use 3rd order form where acceleration is 2nd order when constant. 3rd order form involves jerk.
36 # Difficult when several protons and one electron involved.
37 # 5. Learn about skip method
38 # 6. Search for and study other methods on the internet
39 # 7. Collect data when it occurs and thus make smarter decision
40 # 8. Use special relativity. Didn't help.
41 # 9. Use integration algorithm for calculating velocity rather than dt method.
42 # Requires equation for velocity over the path
43 # 10. If particle is outside of the normal size of an atom then assume it is escaping due to energy gain.
44 # reset kinetic energy to zero.
48 # 1. x axis torquoise, greenish, blueish
50 # 3. electron redish, a bit of random color added to distinguish individual electrons
51 # 4. proton blueish, a bit of random color added to distinguish individual protons
52 # 5. direction green, equivalent to velocity
53 # 6. total force white
54 # 7. electric force red
55 # 8. magnetic force blue , Direction that external magnetic field is pushing us
56 # 9. magnetic moment yellow (.5,.5,0) Intrinsic magnetic field or spin as popular known.
61 # intrinsic_B_field_plus_qv - This is a vector using the right hand rule.
62 # It points in the direction of v in qv for example.
63 # The B field rotates around the direction that this vector points.
66 from visual
import * # See vpython.org for more info.
68 import random
# http://effbot.org/pyfaq/how-do-i-generate-random-numbers-in-python.htm
69 #import threading # Have computations on one thread and drawing on another
71 import sys
# for argv, flush
74 class simple_class
: # Used to hold constants for electron and proton and other global variables.
77 wl
= simple_class() # workload. Holds global variables related to our set of particles or system of particles
79 wl
.particle_count
= 2 # hydrogen
80 #wl.particle_count = 3 # Neutron and proton
81 #wl.particle_count = 4 # heavy hydrogen, Deuterium
82 #wl.particle_count = 8 # Helium, 2 neutrons
83 #wl.particle_count = 14 # lithum
84 wl
.size_adjust
= wl
.particle_count
/ 2 # Larger particles when there are more of them because they are further apart.
85 # See setup_globals(). Just eye candy improvement.
87 debug_sum_forces_on_one_particle
= 21
88 random
.seed(0) # Can comment out for real randomness.
89 c
= 299792458 # speed of light, http://en.wikipedia.org/wiki/Speed_of_light
90 c2
= c
**2 # Used for Lorentz factor http://en.wikipedia.org/wiki/Lorentz_factor
91 h_eVs
= 4.135667e-15 # http://en.wikipedia.org/wiki/Planck_constant
92 h_Js
= 6.62606896e-34 # http://en.wikipedia.org/wiki/Planck_constant
93 Ke
= 8.987551787e9
# Proportionality constant, called Coulomb's constant. http://en.wikipedia.org/wiki/Electric_force
94 u0
= 1.2566e-6 # Henry's per meter or Tesla*meters/Ampere. http://en.wikipedia.org/wiki/Magnetic_constant
95 coulomb
= 6.241509629e18
# http://en.wikipedia.org/wiki/Coulomb
96 size_of_hydrogen_nucleus
= 1.6e-15 # In meters. http://en.wikipedia.org/wiki/Atomic_nucleus
97 B_field_in_space
= 1.0e-11 # Teslas
98 earth_B_field
= vector(0,0,40.0e-06) # http://en.wikipedia.org/wiki/Earth%27s_magnetic_field#Field_characteristics. Arbitrarily assigned in the B field direction
99 background_magnetic_field
= earth_B_field
100 elementary_charge
= 1.602176487e-19 # coulombs
101 base_electric_pot_energy
= Ke
* ( elementary_charge
** 2 ) / size_of_hydrogen_nucleus
102 K_m
= u0
/(4*pi
) # magnetic constant. http://en.wikipedia.org/wiki/Biot%E2%80%93Savart_law
105 proton
= simple_class() # Just defines some constants
106 electron
= simple_class()
107 proton
.radius
= .875e-15 # http://en.wikipedia.org/wiki/Proton. Somewhat arbitrary. Doesn't effect experiment. Just for visual candy.
108 proton
.visual_radius
= proton
.radius
109 electron
.visual_radius
= proton
.visual_radius
* .5 # Arbitrary, just for visual candy
110 proton
.rest_mass_kg
= 1.672621636e-27 # kg
111 proton
.mass_MeV
= 938.272013
112 proton
.mass_eV
= proton
.mass_MeV
* 1e6
113 electron
.rest_mass_kg
= 9.10938215e-31 # http://en.wikipedia.org/wiki/Electron
114 electron
.mass_MeV
= 0.51099891 # http://en.wikipedia.org/wiki/Electron and http://en.wikipedia.org/wiki/Electronvolt
115 electron
.mass_eV
= electron
.mass_MeV
* 1e6
116 electron
.frequency
= ( 2 * electron
.mass_eV
) / h_eVs
# e = h*f , f = e /h, 2 because that is what is required from pair production.
117 proton
.frequency
= ( 2 * proton
.mass_eV
) / h_eVs
# e = h*f , f = e /h
118 electron
.wavelength
= h_Js
/ ( electron
.rest_mass_kg
* c
) # http://en.wikipedia.org/wiki/Compton_wavelength
119 electron
.period
= 1 / electron
.frequency
120 proton
.period
= 1 / proton
.frequency
121 print "\t electron frequency ", electron
.frequency
, " period ", electron
.period
, electron
.wavelength
122 print "\t proton frequency ", proton
.frequency
, " period ", proton
.period
123 proton
.charge
= elementary_charge
124 electron
.charge
= elementary_charge
* -1
125 electron
.magnetic_moment
= -928.476377e-26 # http://en.wikipedia.org/wiki/Electron_magnetic_dipole_moment
126 proton
.magnetic_moment
= 14.106067e-27 # http://en.wikipedia.org/wiki/Magnetic_moment#Elementary_particles
127 # Doesn't make sense that a proton would have a small magnetic moment.
128 # Joules / Teslas. Is that the unit of measure we need it in?
129 electron
.magnetic_moment
= elementary_charge
# Experimenting
130 proton
.magnetic_moment
= elementary_charge
# Experiment
132 el_pr_weight_diff
= proton
.rest_mass_kg
/ electron
.rest_mass_kg
# Used for arbitrary initial set up.
133 #print " el_pr_weight_diff %d" % el_pr_weight_diff
134 electron
.radius
= proton
.radius
/ el_pr_weight_diff
# Just a wild guess. Maybe the electron true radius is larger than that of the proton.
137 scene
.title
="Sub atomic particles as standing electromagnetic waves"
138 scene
.width
=800 # go ahead and change these to suit your preference.
143 axis_length
= size_of_hydrogen_nucleus
* 4 * wl
.size_adjust
144 y_axis_label
= label(pos
=(0,axis_length
,0), text
="Y", opacity
=.3, box
=0, line
=0)
145 y_axis
= arrow(pos
=(0,0,0), axis
=(0,size_of_hydrogen_nucleus
,0), length
=axis_length
, opacity
=0.7, color
=(.5,.5,0))
146 y_axis
.shaftwidth
= y_axis
.shaftwidth
/ 4
147 y_axis
. headwidth
= y_axis
. headwidth
/ 4
148 y_axis
. headlength
= y_axis
. headlength
/ 4
150 x_axis_label
= label(pos
=(axis_length
,0,0), text
="X", opacity
=.3, box
=0, line
=0)
151 x_axis
= y_axis
.__copy
__()
152 x_axis
.axis
= (size_of_hydrogen_nucleus
,0,0)
153 x_axis
.color
= (0,.5,0.5)
154 x_axis
.length
= axis_length
156 initial_velocity_max
= 3e4
# arbitrary
158 max_ptr_len
= size_of_hydrogen_nucleus
* wl
.size_adjust
159 min_ptr_len
= max_ptr_len
/ 2
161 #scene.show_rendertime = True
163 kb_input_label
= label(visible
=0)
165 def setup_workload() :
166 wl
.number_of_dt_per_proton_period
= 16
167 #wl.number_of_dt_per_proton_period = 32
168 #wl.number_of_dt_per_proton_period = 64
169 #wl.number_of_dt_per_proton_period = 128
170 wl
.desired_dt
= proton
.period
/ wl
.number_of_dt_per_proton_period
# wl.dt = time quantum or delta time.
171 wl
.dt
= wl
.desired_dt
# wl.dt = time quantum or delta time. Adjusts to smaller values when particles are close.
173 print "\t wl.dt %1.1e" % wl
.dt
174 wl
.last_dt_change
= wl
.dt
177 # If the electrical force is strong I want to have a smaller dt so that we can model orbits better
178 # Also have smaller digital energy gain issue.
179 #new_dt = large_dt / wl.largest_ele_force
180 # I want to lower dt when electrical force is greater than 50.
181 #new_dt = large_dt / 32
182 # large_dt = desired_dt * 32
183 wl
.large_dt
= wl
.desired_dt
* 32 # From running simulation I know that electron gets thrown when electrical force reaches this value.
184 wl
.pars
= [] # wl.pars = sub-atomic particles, a list of vpython sphere objects with added attributes.
186 wl
.main_loop_count
= 0 # Just a counter for number of iterations we've done.
187 wl
.curr_KE_system
= 0.0 # KE = Kinetic Energy
188 wl
.orig_KE_system
= 0.0 # KE = Kinetic Energy
189 wl
.prev_KE_system
= 0.0
190 wl
.part_with_most_energy
= 0;
191 wl
.play_mode
= True # if s == 's' or s == 'p' or s == ' ': #stop, pause or play
194 def print_unit_vector(string
, vec
) : # Vector should already be in normalized form
195 print "%s%2d" % (string
, int(vec
.x
*10)),
196 print "%2d" % int(vec
.y
*10),
197 print "%2d" % int(vec
.z
*10),
199 def find_perpendicular(vel
,to_proton_vec
):
200 # http://local.wasp.uwa.edu.au/~pbourke/geometry/disk/
203 # http://local.wasp.uwa.edu.au/~pbourke/geometry/disk/
204 # Step 1. Choose any point P randomly which doesn't lie on the line through P1 and P2
205 # Step 2. Calculate the vector R as the cross product between the vectors
206 # P - P1 and P2 - P1. This vector R is now perpendicular to P2 - P1.
207 # (If R is 0 then step 1 wasn't satisfied)
208 r
= cross( vel
, to_proton_vec
)
209 r_norm
= norm(r
) * -1
210 #print_unit_vector("vel", norm(vel)); print_unit_vector(" r", r_norm),
211 if r
.x
!= 0 or r
.y
!= 0 or r
.z
!= 0:
213 print "\t Cross product is not zero. Success."
215 print "\t Our points lie on the same line.",
216 print vel
, to_proton_vec
,
218 print "Can't find random points that are not on the same line."
220 random_vec
= vector(random
.random(),random
.random(),random
.random());
224 to_proton_vec
= random_vec
226 print "random vec ", random_vec
230 def setup_particles():
231 initial_spacing
= size_of_hydrogen_nucleus
* 16 * ( wl
.particle_count
/ 2 ) # arbitrary
234 num_particles_of_same_type
= int ( (wl
.particle_count
/ 2) + 0.5 )
235 for i
in range(0,wl
.particle_count
):
236 # For describing sub atomic particles particles we start with visual python sphere object then add to it.
237 wl
.pars
.append(sphere(radius
=electron
.visual_radius
)) # Specify a radius that gets reset so that we don't get flicker with autoscale.
238 part
= wl
.pars
[i
] # part = particle. Create a pointer to the sphere object which holds most of our data.
239 part
.index
= i
# Set one of the many variables in our particle object.
242 #part.is_proton = (i%2)==0;
243 part
.is_proton
= i
< ( (wl
.particle_count
+1) / 2 );
244 part
.is_electron
= not part
.is_proton
245 # For info on vector see: http://vpython.org/webdoc/visual/vector.html
246 spacing
= initial_spacing
247 need_random_loc_assigned
= True
248 if part
.is_electron
and i
>= 2 : # Put electron between protons.
249 need_random_loc_assigned
= False
250 #if part.is_electron and ((i+1)%4) == 0 : # Make a neutron. Put every other electron between previous protons.
251 #part.pos = mid_point(previous_proton, prev_prv_proton)
252 proton_index
= int((i
-1)/2)
253 p
= wl
.pars
[proton_index
]
254 np
= wl
.pars
[proton_index
+1] # np = next proton
257 np
= wl
.pars
[0] # put electron between first proton and last proton.
259 need_random_loc_assigned
= True
260 if not need_random_loc_assigned
:
261 part
.pos
= vector(p
.x
-((p
.x
-np
.x
)/2),p
.y
-((p
.y
-np
.y
)/2),p
.z
-((p
.z
-np
.z
)/2))
262 print "Putting electron in the middle of two protons"
263 if need_random_loc_assigned
:
265 spacing
= spacing
/ 2
266 part
.pos
= vector((random
.random()-.5)*spacing
, # Arbitrary values assigned
267 (random
.random()-.5)*spacing
,
268 (random
.random()-.5)*spacing
)
269 part
.opacity
= 0.3 # Arbitrary. Just chose what I think looks good.
270 #print i, 'is electron', part.is_electron
271 part
.velocity
= - norm(part
.pos
)
272 part
.vel_norm
= norm(part
.velocity
)
273 part
.vel_pointer
= arrow(pos
=part
.pos
, axis
=(1,0,0), length
=max_ptr_len
, color
=(0,1,0), opacity
=.2) # direction of velocity
274 if part
.is_electron
:
275 part
.ptype_name
= "electron"
276 part
.charge_avg
= electron
.charge
277 part
.frequency
= electron
.frequency
278 part
.rest_mass_kg
= electron
.rest_mass_kg
279 part
.period
= electron
.period
280 part
.radius
= electron
.visual_radius
* wl
.size_adjust
281 part
.color
= (1.0,random
.random()**2,random
.random()**2) # Redish color, ^2 the other colors makes them closer to zero
282 part
.EF_pointer
= arrow(pos
=part
.pos
, length
=max_ptr_len
, color
=(1,0,0), opacity
=.2, axis
=(1,0,0)) # Where is the electric force pushing us?
283 part
.MF_pointer
= arrow(pos
=part
.pos
, length
=max_ptr_len
, color
=(0,0,1), opacity
=.2, axis
=(1,0,0)) # Where is the magnetic force pushing us?
284 part
.tot_pointer
= arrow(pos
=part
.pos
, length
=max_ptr_len
, color
=(1,1,1), opacity
=.2, axis
=(1,0,0)) # Where is the total force pushing us?
285 part
.mag_moment_unit_vec
= vector(0,0,-1) # initial z direction is arbitrary
286 part
. avg_magnetic_moment
= electron
.magnetic_moment
;
287 part
.intrinsic_magnetic_moment
= part
.mag_moment_unit_vec
* part
.avg_magnetic_moment
; # http://en.wikipedia.org/wiki/Spin_%28physics%29#Magnetic_moments
288 part
.this_type_count
= electron_count
291 part
.ptype_name
= "proton "
292 part
.charge_avg
= proton
.charge
* 1
293 part
.frequency
= proton
.frequency
294 part
.rest_mass_kg
= proton
.rest_mass_kg
295 part
.period
= proton
.period
296 part
.radius
= proton
.visual_radius
* wl
.size_adjust
297 part
.color
= (random
.random()**2,random
.random()**2,1.0) # Blue-ish color, ^2 the other colors makes them closer to zero
298 part
.mag_moment_unit_vec
= vector(0,0,1) # initial z direction is arbitrary
299 part
. avg_magnetic_moment
= proton
.magnetic_moment
;
300 part
.intrinsic_magnetic_moment
= part
.mag_moment_unit_vec
* part
.avg_magnetic_moment
# http://en.wikipedia.org/wiki/Spin_%28physics%29#Magnetic_moments
301 part
.this_type_count
= proton_count
303 part
.previous_magnetic_moment
= vector(0,0,-1)
305 #part.type = part.ptype_name
306 #print "part.radius", part.radius
307 # magnetic Dipole moment pointer. http://en.wikipedia.org/wiki/Magnetic_dipole_moment
308 part
. mm_pointer
= arrow(pos
=part
.pos
, length
=part
.radius
*2, color
=(0.5,0.5,0.0), opacity
=.2, axis
=part
.mag_moment_unit_vec
) # What direction is the particle oriented to. Where is the magnetic moment vector pointing.
309 #part.mag_di_moment_arrow = arrow(pos=part.pos, axis=(0,1,0), length=part.radius*2, color=(1,1,0.25), opacity=.2) # Where is the total force pushing us?
310 part
.angular_velocity
= 0.0
312 if part
.this_type_count
== 0 :
313 #part.initial_wave_height_in_terms_of_dt = random.random() * part.period
314 part
.initial_wave_height_in_terms_of_dt
= 0
316 # handle pauli exclusion principle
317 # Create particles at different times in their cycles.
318 previous_part_of_same_type
= wl
.pars
[i
-1]
319 part
.initial_wave_height_in_terms_of_dt
= ( part
.period
/ num_particles_of_same_type
) + previous_part_of_same_type
.initial_wave_height_in_terms_of_dt
320 part
.lorentz_factor
= 1.0 # http://en.wikipedia.org/wiki/Lorentz_transformation
321 part
.rela_mass
= part
.rest_mass_kg
# Set relativistic mass
322 part
.mag_velocity
= mag(part
.velocity
)
323 part
.old_dist_apart
= 1.0 # Initialize to huge value.
324 print " ", part
.ptype_name
,
325 print "position ", part
.pos
326 print "\t velocity %1.1e" % mag(part
.velocity
), part
.velocity
327 print "\t wl.dt offset random ", part
.initial_wave_height_in_terms_of_dt
328 part
.trail
= curve(color
=part
.color
, radius
= part
.radius
/ 8, pos
=part
.pos
)
329 #part.trail.append(pos=part.pos,retain=50) # 50 = arbitrary
330 part
.old_vel
= vector(0,0,0)
331 part
.old_pos
= vector(0,0,0)
332 part
.old_f_unit_v
= vector(0,0,0)
333 part
.getting_further_apart
= False
335 part
.getting_closer
= False
336 part
.old_getting_closer
= False
337 part
.previous_force_was_3_digits
= False
338 part
.label
= label(pos
=part
.pos
,text
='%d' % part
.index
)
339 part
.moment_of_inertia
= ( 2.0 / 5.0 ) * part
.rest_mass_kg
* ( part
.radius
** 2 ) # http://en.wikipedia.org/wiki/List_of_moments_of_inertia
340 # I modeled it as a sphere but perhaps it is close to a disc.
341 print " part.moment_of_inertia", part
.moment_of_inertia
342 #calc_energy_of_system()
343 #wl.orig_total_energy = wl.total_energy
344 #wl.energy_limit = wl.orig_total_energy * 1.1
345 #print "\t total energy of system %5g" % wl.orig_total_energy
346 #wl.prev_total_energy = wl.orig_total_energy
347 #wl.energy_ratio = 1.0 # Energy ratio from original
350 def display_particle_labels() :
351 for part
in wl
.pars
:
352 part
.label
.visible
= True
353 part
.label
.pos
= part
.pos
354 wl
.display_particle_labels_bool
= True
355 num_loops_to_display_part_index
= 25 * wl
.particle_count
356 wl
.hide_number_label_count
= wl
.main_loop_count
+ num_loops_to_display_part_index
358 def hide_particle_labels() :
359 for part
in wl
.pars
:
360 part
.label
.visible
= False
361 kb_input_label
.visible
= 0
362 wl
.display_particle_labels_bool
= False
365 def calc_energy_of_system():
368 for part
in wl
.pars
:
369 part
.kinetic_energy
= .5 * part
.rest_mass_kg
* mag2(part
.velocity
); # mag2 = magnitude ^ 2
370 wl
.KE_system
+= part
.kinetic_energy
371 # Electric potential energy http://en.wikipedia.org/wiki/Electric_potential_energy
372 # Simplifying assumptions:
373 # 1. The system has zero net charge
374 # 2. The systems center of mass and center of charge is at the origin of the axis. (0,0,0)
375 # 3. If a particle is away from the center than potential energy is the amount of energy from current position to center, for single charge.
376 # Because charge at center is zero when all particles are there.
378 # gravitational potential energy = U = mgh
379 # For comparison purposes
381 mag_pos
= mag(part
.pos
)
383 part
.electric_energy
= 0
385 # Doesn't work. What happens when part is inside the base_electric_pot_energy? Value is negative.
386 part
.electric_energy
= base_electric_pot_energy
- ( Ke
* ( elementary_charge
** 2 ) / mag_pos
)
387 wl
.PE_system
+= part
.electric_energy
388 wl
.total_energy
= wl
.KE_system
+ wl
.PE_system
389 print " PE", wl
.PE_system
, ", KE", wl
.KE_system
, ", tot", wl
.total_energy
391 def update_particle_em_wave_heights(part
):
392 cycle
= ( wl
.total_time
+ part
.initial_wave_height_in_terms_of_dt
) * part
.frequency
* 2 * pi
393 part
.charge_cur
= ( part
.charge_avg
* sin(cycle
) ) + part
.charge_avg
# Theory is that it oscillates around the average
394 part
.B_field_mag
= ( part
.avg_magnetic_moment
* cos(cycle
) ) + part
.avg_magnetic_moment
395 part
.B_from_qv
= K_m
* part
.charge_cur
* part
.velocity
# http://en.wikipedia.org/wiki/Biot%E2%80%93Savart_law#Point_charge_at_constant_velocity
396 if mag2(part
.intrinsic_magnetic_moment
) == 0 :
397 if mag2(part
.previous_magnetic_moment
) == 0 :
398 part
.mag_moment_unit_vec
= vector(0,0,-1) # arbitrary
400 part
.mag_moment_unit_vec
= norm(part
.previous_magnetic_moment
)
402 part
.mag_moment_unit_vec
= norm(part
.intrinsic_magnetic_moment
)
403 part
. previous_magnetic_moment
= part
.intrinsic_magnetic_moment
# http://en.wikipedia.org/wiki/Spin_%28physics%29#Magnetic_moments
404 part
.intrinsic_magnetic_moment
= part
.mag_moment_unit_vec
* part
.B_field_mag
# Just using random direction for this case.
405 part
.intrinsic_B_field_plus_qv
= part
.intrinsic_magnetic_moment
+ part
.B_from_qv
406 if debug_verbosity
> 25 :
407 print " n ", part
.num
, part
.ptype_name
,
408 #print "b", part.B_field_mag, " uv", part.mag_moment_unit_vec,
409 print " qv ", part
.B_from_qv
,
410 print " intrinsic B field", part
.intrinsic_magnetic_moment
411 print " intrinsic_B_field_plus_qv", part
.intrinsic_B_field_plus_qv
413 #if (part.index != 0 and wl.main_loop_count&0x0f) or debug_sum_forces_on_one_particle > 25:
414 #if (wl.main_loop_count&0xff == 0) or debug_sum_forces_on_one_particle > 25:
415 if debug_sum_forces_on_one_particle
> 25:
416 percent_diff
= int((part
.charge_cur
/ part
.charge_avg
)*100)
417 print " %%%3d" % percent_diff
,
418 # print "\t charge_cur %+1.1e" % part.charge_cur, " delta %%%d" % percent_diff, " index ", part.index
420 # print "\t charge_cur %+5e" % part.charge_cur, " delta %%%5.3f" % (part.charge_cur / part.charge_avg), \
421 # " index ", part.index
423 # if part.index != 0 and debug_sum_forces_on_one_particle > 50:
424 # print "charge_cur %+5e" % part.charge_cur, " delta %5.3f" % (part.charge_cur / part.charge_avg), " index ", part.index
425 # print "charge_cur delta from part average ", (part.charge_avg - part.charge_cur), " index ", part.index
428 #################################################################################
429 # Might be documented at this web page:
430 # http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
431 # http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors
432 # There are just the first two web pages that came when searching on this topic
433 def angle_between_two_norm_vectors(n1
,n2
,v1
,v2
,caller
) :
434 dot_product
= dot(n1
,n2
)
435 #print " dot ", dot_product
436 if dot_product
> 1.0 or dot_product
< -1.0 :
438 if wl
.main_loop_count
> 0 :
439 #print " ref_pos ", ref_pos
440 #print " pos1 ", pos1
441 #print " pos2 ", pos2
445 print " dot ", dot_product
446 #print " zero angle "
448 # print "dot product", dot_product
449 result
= math
.acos(dot_product
)
450 #print " angle ", result
453 def angle_between_two_vectors(v1
,v2
,caller
) :
454 return angle_between_two_norm_vectors(norm(v1
),norm(v2
),v1
,v2
,caller
)
457 def angle_change_between_two_particles(pos1
,pos2
,ref_pos
) :
463 result
= angle_between_two_vectors(v1
,v2
,"Angle change")
466 def sum_forces_on_one_particle(part
):
467 # part = particle. A pointer to the sphere object which holds most of our data.
468 wl
.largest_ele_force
= 1e-15
469 part
.e_force_sum
= vector(0,0,0) # Sum of electric forces acting on the particle
470 part
.B_force_sum
= vector(0,0,0) # Sum of magnetic forces acting on the particle
471 part
.force_sum
= vector(0,0,0) # Sum of all forces acting on the particle
472 part
.closest_part
= part
473 part
.closest_dist
= 1 # 1 meter apart
475 #if part.is_electron :
476 if ( debug_sum_forces_on_one_particle
> 20 ):
477 print " #%d" % part
.index
,
478 for j
in range(wl
.particle_count
): # Calculate the force each particle exerts on this one
479 if ( part
.index
== j
):
480 continue # No need to calculate force that particle exerts on itself.
481 if ( debug_sum_forces_on_one_particle
> 60 ):
482 print "part.index %d, j %d" % (part
.index
, j
)
483 other_part
= wl
.pars
[j
]
484 dist_vec
= part
.pos
- other_part
.pos
# dist is a vector
485 mag2_dist
= mag2(dist_vec
) # mag2 = magnitude squared
486 part
.dist_apart
= mag (dist_vec
)
487 if part
.dist_apart
< part
.closest_dist
:
488 part
.closest_part
= other_part
# used to calculate B field direction
489 part
.closest_dist
= part
.dist_apart
491 if ( debug_sum_forces_on_one_particle
> 25 ):
492 print " dis a %1.0e" % part
.dist_apart
,
493 if ( debug_sum_forces_on_one_particle
> 35 ):
494 print " delta %1.0e" % (part
.dist_apart
-part
.old_dist_apart
),
495 # The below part is used to track when an electron is tossed by a proton.
496 # Tossed because of digitization simulation error.
497 # The digitization problem is corrected in implement_particle_calcs()
498 if part
.closest_part
== other_part
:
499 part
.getting_further_apart
= (part
.dist_apart
> part
.old_dist_apart
) # Don't know if these attributes are used.
500 part
.old_getting_closer
= part
.getting_closer
501 part
. getting_closer
= not part
.getting_further_apart
502 if part
.getting_closer
:
503 if part
.old_getting_closer
:
504 part
.getting_closer_count
+= 1
506 part
.getting_closer_count
= 1
508 # http://en.wikipedia.org/wiki/Electric_force
509 # positive force is repulsive, negative value is attraction
510 # For info on mag see: http://vpython.org/webdoc/visual/VisualIntro.html or http://vpython.org/webdoc/visual/vector.html
511 dist_unit_vector
= norm(dist_vec
)
512 e_force
= dist_unit_vector
* (Ke
* part
.charge_cur
* other_part
.charge_cur
/ mag2_dist
)
513 if ( debug_sum_forces_on_one_particle
> 20 ):
514 print "ele_force %3.0f " % mag(e_force
),
515 part
.e_force_sum
+= e_force
516 if mag(e_force
) > wl
.largest_ele_force
:
517 wl
.largest_ele_force
= mag(e_force
)
519 #################################################################
520 # Calculate the magnetic force due to the some of the B fields. #
521 #################################################################
523 # Want to sum all of the forces on the moving charge
524 # Force from a point charge: http://en.wikipedia.org/wiki/Biot%E2%80%93Savart_law#Point_charge_at_constant_velocity
525 # http://maxwell.ucdavis.edu/~electro/magnetic_field/pointcharge.html
527 # The B field of the other part relative to this one:
528 # Parts have two sources of magnetic field
529 # 1. Magnetic field created from moving charge
530 # 2. Magnetic field from standing EM wave. In this simulation also called intrinsic B field.
532 # What do the field lines look for the different magnetic fields?
533 # 1. Magnetic field do to a moving charge are circular similar to those from a current in a wire:
534 # http://en.wikipedia.org/wiki/File:Manoderecha.svg
535 # http://www.youtube.com/watch?v=eWaA9RiLsno
536 # http://web.mit.edu/jbelcher/www/java/part_biot/part_biot.html
537 # http://www.physics.sjsu.edu/becker/physics51/mag_field.htm
538 # The magnetic field created by the other part is circular
539 # so need to calculate what its field is at part location.
540 # Using the right hand rule with the direction of motion.
543 #B_force = K_m * cross(other_part.intrinsic_B_field_plus_qv,-dist_unit_vector/mag2_dist)
544 # Below is a form of the biot-savart law: http://en.wikipedia.org/wiki/Biot%E2%80%93Savart_law#Point_charge_at_constant_velocity
545 b_field_from_other_part_at_this_point_in_space
= K_m
* cross(
546 other_part
.intrinsic_B_field_plus_qv
, -dist_unit_vector
/mag2_dist
)
547 B_force
= cross(b_field_from_other_part_at_this_point_in_space
, part
.intrinsic_B_field_plus_qv
)
548 if ( debug_sum_forces_on_one_particle
> 25 ):
550 print "\t type", part
.ptype_name
, " dist apart", part
.dist_apart
551 print "\t intrinsic_B_field_plus_qv ", part
.intrinsic_B_field_plus_qv
, " other ", other_part
.intrinsic_B_field_plus_qv
552 #print "\t b_field_from_other_part_at_this_point_in_space %1.0e %1.0e %1.0e mag %1.1e" % (
553 # b_field_from_other_part_at_this_point_in_space.x,
554 # b_field_from_other_part_at_this_point_in_space.y,
555 # b_field_from_other_part_at_this_point_in_space.z,
556 # b_field_from_other_part_at_this_point_in_space.mag )
557 print "\t qv ", part
.B_from_qv
, " mag", mag(part
.B_from_qv
)
558 print "\t other_part.intrinsic_magnetic_moment", other_part
.intrinsic_magnetic_moment
559 print "\t B x%1.0e y%1.0e z%1.0e %g" % (B_force
.x
,B_force
.y
,B_force
.z
, mag(B_force
) )
560 part
.B_force_sum
+= B_force
562 part
.B_force_sum
+= background_magnetic_field
563 part
.force_sum
= part
.e_force_sum
+ part
.B_force_sum
564 part
.B_force_mag
= mag(part
.B_force_sum
)
565 part
.e_force_mag
= mag(part
.e_force_sum
)
566 part
.t_force_mag
= mag(part
.force_sum
)
567 # Calculate the torque.
568 # magnetic fields tend to align, so the torque and consequently the rotation will be to align in the same direction.
569 # The rotation will be from current location that magnetic moment vector is pointing to the magnetic moment vector of other particle
570 # The axis will be the cross product from old to new direction that the vector is pointing to.
571 # Our torque vectors direction is pointing in the direction of the axis of rotation.
572 # Torque http://en.wikipedia.org/wiki/Magnetic_moment#Effects_of_an_external_magnetic_field_on_a_magnetic_moment
573 part
.torque
= cross(part
.intrinsic_magnetic_moment
,part
.B_force_sum
)
574 part
.torque_mag
= mag ( part
.torque
)
575 #print "\t torque x%1.0e y%1.0e z%1.0e %g " % (part.torque.x,part.torque.y,part.torque.z, mag(part.torque))
577 if part
.is_electron
:
578 part
. EF_pointer
.axis
= norm(part
.e_force_sum
) * min_ptr_len
579 part
. MF_pointer
.axis
= norm(part
.B_force_sum
) * min_ptr_len
580 part
.tot_pointer
.axis
= norm(part
.force_sum
) * min_ptr_len
582 # Make length relative to strongest force
583 strongest_force
= part
.e_force_mag
584 if part
.B_force_mag
> strongest_force
:
585 strongest_force
= part
.B_force_mag
586 if part
.t_force_mag
> strongest_force
:
587 strongest_force
= part
.t_force_mag
588 if strongest_force
!= 0.0 :
589 part
. EF_pointer
.length
= min_ptr_len
+ (max_ptr_len
* ( part
.e_force_mag
/ strongest_force
) )
590 part
. MF_pointer
.length
= min_ptr_len
+ (max_ptr_len
* ( part
.B_force_mag
/ strongest_force
) )
591 part
.tot_pointer
.length
= min_ptr_len
+ (max_ptr_len
* ( part
.t_force_mag
/ strongest_force
) )
592 #if wl.main_loop_count > 10 :
593 # print "e%2.0f b%2.0f t%2.0f" % (part.e_force_mag, part.B_force_mag, part.t_force_mag),
594 if debug_sum_forces_on_one_particle
> 20 :
595 c_vel
= ( part
.mag_velocity
/ c
) * 100
596 #print "e %3.0f b %3.0f" % (part.e_force_mag, part.B_force_mag),
597 if part
.is_electron
:
598 print " v%3.0f" % (c_vel
),
600 print " v%1.0f" % (c_vel
),
601 if debug_sum_forces_on_one_particle
> 20 :
602 if part
.previous_force_was_3_digits
or part
.e_force_mag
>= 100.0:
603 if part
.e_force_mag
>= 100.0 :
604 part
.previous_force_was_3_digits
= True
605 part
.force_3_digits_iteration
= wl
.main_loop_count
606 elif (part
.force_3_digits_iteration
+ 50) < wl
.main_loop_count
:
607 part
.previous_force_was_3_digits
= False
608 print "e%3.0f b%3.0f t%3.0f" % (part
.e_force_mag
, part
.B_force_mag
, part
.t_force_mag
),
610 print "e%2.0f b%2.0f t%2.0f" % (part
.e_force_mag
, part
.B_force_mag
, part
.t_force_mag
),
613 if ( debug_sum_forces_on_one_particle
> 20 ):
614 percent_diff
= int((part
.charge_cur
/ part
.charge_avg
)*100)
615 print "%%%3d" % percent_diff
,
616 percent_diff
= int((part
.B_field_mag
/ part
.avg_magnetic_moment
)*100)
617 print "B%%%3d" % percent_diff
,
618 #print "d %1.1e " % part.dist_apart,
619 #print " e for %2.0f %1.0e, b for %2.0f %1.0e," % (part.e_force_mag, part.e_force_mag, part.B_force_mag, part.B_force_mag),
620 #print "e %1.0e b %1.0e," % (part.e_force_mag, part.B_force_mag),
621 #print " e for %3.0f, b for %3.0f " % (part.e_force_mag, part.B_force_mag), " tot ", part.force_sum
622 # print "\t part.e_force_mag %3g" % part.e_force_mag
623 #print "e_force_sum %e" % mag(part.e_force_sum), part.e_force_sum
624 if part
.e_force_sum
> 100 :
625 part
.was_very_close
= True
627 part
.was_very_close
= False
628 # end sum_forces_on_one_particle()
631 # If the electrical force is strong I want to have a smaller dt so that we can model orbits better
632 # Also have smaller digital energy gain issue.
633 new_dt
= wl
.large_dt
/ wl
.largest_ele_force
635 if (wl
.last_dt_change
/ new_dt
) > 1.2 :
636 print "\t lowering dt from %1.2e " % wl
.last_dt_change
, "to %1.2e" % new_dt
, "e force", int(wl
.largest_ele_force
)
637 wl
.last_dt_change
= new_dt
639 elif new_dt
> wl
.dt
and wl
.dt
< wl
.desired_dt
:
640 if new_dt
> wl
.desired_dt
:
641 new_dt
= wl
.desired_dt
642 print "\t Reached desired delta time (dt)"
643 if (wl
.last_dt_change
/ new_dt
) > 0.8 :
644 print "\t lowering dt from ", wl
.last_dt_change
, "to", new_dt
, "e force", wl
.largest_ele_force
645 wl
.last_dt_change
= new_dt
649 def calc_particle_acceleration(part
):
650 # Find the angle of the force on the current velocity.
651 # This is used for special relativity calcs. http://en.wikipedia.org/wiki/Special_relativity#Force
652 radian_angle
= angle_between_two_norm_vectors(part
.vel_norm
,part
.force_unit_v
,
653 part
.velocity
,part
.force_sum
,"calc accel")
654 #degrees = radian_angle * 57.2957795
655 #if part.is_electron :
656 # print "%3.0f" % degrees,
657 # force = gamma**3 * mass * acceleration_parallel + gamma * mass * acceleration_perendicular
658 # gamma = lorentz factor # http://en.wikipedia.org/wiki/Lorentz_factor
659 # http://en.wikipedia.org/wiki/Special_relativity#Force
660 # Need to divide the force into perpendicular and parallel parts.
661 # If force is completely parallel then force = gamma**3 * mass * accel
662 # If force is completely perpendicular then force = gamma * mass * accel
663 if radian_angle
== 0 :
664 part
.acceleration
= part
.force_sum
/ ( part
.lorentz_factor
**3 * part
.rest_mass_kg
)
666 r
= cross( part
.velocity
, part
.force_sum
)
667 perpen_to_velocity
= norm(cross(r
, part
.velocity
)) # This is perpendicular to velocity on the same place as the force and velocity.
668 perpen_force_fraction
= math
.fabs(sin(radian_angle
))**2 # If this is 90 degrees then answer is 1
669 parall_force_fraction
= math
.fabs(cos(radian_angle
))**2 # If force is parallel to velocity then result is 1
670 part
.perpen_force
= perpen_to_velocity
* perpen_force_fraction
* part
.t_force_mag
671 #if part.is_electron :
672 #print "%1.3f %1.3f" % ( parall_force_fraction, perpen_force_fraction ),
673 #print "ll %1.3f per %1.3f lorentz %g" % ( parall_force_fraction, perpen_force_fraction, part.lorentz_factor ),
674 part
.accel_parall
= ( part
.force_sum
* parall_force_fraction
) / ( part
.lorentz_factor
**3 * part
.rest_mass_kg
)
675 part
.accel_perpen
= part
.perpen_force
/ ( part
.lorentz_factor
* part
.rest_mass_kg
)
676 #part.acceleration = part.force_sum / ( part.lorentz_factor * part.rest_mass_kg )
677 #part.acceleration = part.force_sum / part.rest_mass_kg
678 part
.acceleration
= part
.accel_perpen
679 #if part.velocity < c or degrees > 90:
680 part
.acceleration
+= part
.accel_parall
681 # calc_particle_acceleration()
684 def calc_new_particle_position(part
):
686 part
.force_unit_v
= norm(part
.force_sum
)
687 calc_particle_acceleration(part
)
690 if ( debug_sum_forces_on_one_particle
> 50 ):
691 print "\t accelerat %e " % mag(part
.acceleration
), part
.acceleration
692 if ( debug_sum_forces_on_one_particle
> 60 ):
693 if ( part
.velocity
== vector(0,0,0) or part
.velocity
== 0 ):
694 print "\t old direction zero "
696 print "\t old direction ", part
.velocity
697 print "\t old direction ", norm(part
.velocity
) # norm = unit vector, http://vpython.org/webdoc/visual/vector.html
698 part
.new_velocity
= part
.velocity
+ (part
.acceleration
* wl
.dt
) # velocity = v0 + acceleration * wl.dt
699 if part
.index
!= 0 and debug_sum_forces_on_one_particle
> 60 :
700 print "new v", part
.new_velocity
, " old", part
.velocity
, " accel", part
.acceleration
701 part
.new_mag_vel
= mag (part
.new_velocity
)
702 part
.distance_traveled
= part
.new_velocity
* wl
.dt
# used to set new position
703 part
.mag_dist_traveled
= mag(part
.distance_traveled
)
704 if ( debug_sum_forces_on_one_particle
> 30 ):
706 print " v %1.1e " % mag(part
.new_velocity
),
708 if ( debug_sum_forces_on_one_particle
> 60 ):
709 print part
.new_velocity
,
710 if ( debug_sum_forces_on_one_particle
> 50 ):
711 print " dist trav ", part
.mag_dist_traveled
712 #print part.new_velocity
713 part
.new_pos
= part
.pos
+ part
.distance_traveled
714 if ( debug_sum_forces_on_one_particle
> 15 and wl
.main_loop_count
%64 == 0):
715 print "p %1.0e v%1.0e" % ( part
.new_pos
.mag
, part
.velocity
.mag
),
716 if part
.is_electron
:
717 if part
.new_velocity
> wl
.fastest_electron
:
718 wl
.fastest_electron
= part
720 if part
.new_velocity
> wl
.fastest_proton
:
721 wl
.fastest_proton
= part
724 # end of calc_new_particle_position()
727 # Remove rotate particle. Want to see curve with particles
728 # Have dt change while part is tossed
731 def rotate_particle(part
):
732 # Have torque. Want to spin the particle. How do i describe the current orientation?
733 # The orientation is described by the vector: magnetic moment.
735 # Something like angular moment + torque
736 # angular acceleration = torque / moment of inertia # http://en.wikipedia.org/wiki/Angular_acceleration
737 # Similar to acceleration = force / mass or f = m * a
738 # moment_of_inertia for sphere is: 2/5 m r^2 # http://en.wikipedia.org/wiki/List_of_moments_of_inertia
740 part
.angular_accel
= part
.torque_mag
/ part
.moment_of_inertia
741 # for linear motion: velocity = v0 + at
742 part
.angular_velocity
= part
.angular_velocity
+ part
.angular_accel
* wl
.dt
743 # for linear motion: location = x0 + v0*t + .5at^2
744 # v2 = rotate(v1, angle=theta, axis=(1,1,1)) http://vpython.org/contents/docs/visual/vector.html
745 if debug_verbosity
> 20 :
746 print " n ", part
.num
,
747 print " intrinsic_magnetic_moment", part
.intrinsic_magnetic_moment
,
748 print " angular_velocity", part
.angular_velocity
,
749 print " torque", part
.torque
,
750 # Minor documentation on rotate: http://vpython.org/webdoc/visual/vector.html
751 part
.intrinsic_magnetic_moment
= rotate(part
.intrinsic_magnetic_moment
, angle
=part
.angular_velocity
* wl
.dt
, axis
=part
.torque
)
752 part
.mag_moment_unit_vec
= rotate(part
.mag_moment_unit_vec
, angle
=part
.angular_velocity
* wl
.dt
, axis
=part
.torque
)
753 if debug_verbosity
> 20 :
754 print " mag_moment_unit_vec ", part
.mag_moment_unit_vec
,
755 print " axis", part
.mm_pointer
.axis
756 part
.mm_pointer
.axis
= part
.mag_moment_unit_vec
* part
.radius
*2;
760 def do_particle_calcs():
761 """Calculate the forces acting on each particle and update positions"""
762 #global wl.part_with_most_energy, wl.curr_KE_system, debug_sum_forces_on_one_particle
763 wl
.curr_KE_system
= 0.0
764 wl
.part_with_most_energy
= wl
.pars
[0] # initialize
765 wl
.fastest_proton
= wl
.pars
[0]
766 wl
.fastest_electron
= wl
.pars
[1]
767 #wl.part_with_highest_velocity = wl.pars[0]
768 for part
in wl
.pars
:
769 sum_forces_on_one_particle(part
)
771 for part
in wl
.pars
:
772 dt_changed
= calc_new_particle_position(part
)
775 rotate_particle(part
)
777 # end of do_particle_calcs()
780 def vector_copy(p1
,p2
): # copy by value instead of copy by reference
785 def implement_particle_calcs():
786 global debug_sum_forces_on_one_particle
787 highest_vel_part
= wl
.pars
[0]
788 for i
in range(wl
.particle_count
):
791 vector_copy(part
.old_f_unit_v
, part
.force_unit_v
)
792 vector_copy(part
.old_vel
, part
. velocity
)
793 part
.vel_norm
= norm(part
.new_velocity
)
794 # 10. If particle is outside of the normal size of an atom then assume it is escaping due to energy gain.
795 # reset kinetic energy to zero.
797 if part
.is_electron
:
798 #if part.pos.mag > 350e-12 : # Some atoms are 260e-15 in size. http://en.wikipedia.org/wiki/Atomic_radius
799 if part
.pos
.mag
> wl
.particle_count
*1e-12 : # Some atoms are 260e-15 in size. http://en.wikipedia.org/wiki/Atomic_radius
800 part
.new_pos
= 1e-13 * part
.vel_norm
802 elif part
.pos
.mag
> (wl
.particle_count
*1e-14) : # http://en.wikipedia.org/wiki/Atomic_nucleus
803 part
.new_pos
= 1e-15 * part
.vel_norm
806 print "\t escape " , part
.num
, " vel", part
.new_velocity
.mag
807 part
.new_velocity
= vector(0,0,0)
808 #debug_sum_forces_on_one_particle += 5
809 mag_velocity
= mag (part
.new_velocity
)
811 if part.getting_further_apart and part.mag_velocity > (c*(7/8)):
812 #if part.closest_dist < size_of_hydrogen_nucleus and part.e_force_mag > 150 : # If we do less than 10 then may have issue when electron orbits proton.
814 #part.has_been_tossed = True
816 print "\t slowing part", part.num, part.ptype_name, part.closest_part.num, part.closest_part.ptype_name,
817 if ( part.new_velocity.mag > c/2 ) :
818 part.new_velocity = part.vel_norm * c/2
819 part.mag_velocity = c/2
820 # slow down the proton too
821 if part.closest_part.velocity.mag > c/4 and part.closest_part.is_proton:
822 part.closest_part. velocity = part.closest_part.vel_norm * c/4
823 part.closest_part.new_velocity = part.closest_part.vel_norm * c/4
824 part.mag_velocity = c/4
826 mag_velocity
= mag (part
.new_velocity
)
827 vector_copy(part
.velocity
, part
.new_velocity
)
828 if part
.mag_velocity
> highest_vel_part
.mag_velocity
:
829 highest_vel_part
= part
830 # Handle special relativity
831 part
.vel2_div_c2
= part
.velocity
.mag2
/ c2
832 if part
.vel2_div_c2
< 1.0 :
833 divisor
= math
.sqrt(1.0 - part
.vel2_div_c2
) # http://en.wikipedia.org/wiki/Lorentz_factor
834 part
.lorentz_factor
= 1.0 / divisor
# http://en.wikipedia.org/wiki/Lorentz_transformation
835 #if part.is_electron :
836 #print "vel %2.0f, div %g, lorentz %g" % ( (part.mag_velocity/c)*100, divisor, part.lorentz_factor),
837 #print "vel %2.0f, div %g, lorentz %g" % ( (part.mag_velocity/c)*100, divisor, part.lorentz_factor),
839 print "Velocity matches c. :0(", part
.num
, part
.ptype_name
,
840 part
.velocity
= norm(part
.velocity
) * (c
-1)
842 part
.lorentz_factor
= 9e30
# Some random rediculuously large number
843 #part.lorentz_factor = 1 # Some random rediculuously large number
844 #print "highest vel part num %d" % highest_vel_part.num,
845 #part.old_dist_trav = part.distance_traveled
846 vector_copy(part
.old_pos
,part
. pos
)
847 vector_copy(part
. pos
,part
.new_pos
)
848 if part
.velocity
!= vector(0,0,0) :
849 #part.vel_pointer.axis = norm(part.velocity) * min_ptr_len
850 part
.vel_pointer
.axis
= norm(part
.velocity
)
851 part
.vel_pointer
.pos
= part
.pos
852 part
.vel_pointer
.length
= 2 * max_ptr_len
* ( part
.mag_velocity
/ c
)
853 if part
.vel_pointer
.length
< min_ptr_len
:
854 part
.vel_pointer
.length
= min_ptr_len
855 if part
.is_electron
:
856 part
. EF_pointer
.pos
= part
.pos
857 part
. MF_pointer
.pos
= part
.pos
858 part
.tot_pointer
.pos
= part
.pos
859 part
.mm_pointer
.pos
= part
.pos
# Magnetic moment
860 #part.mag_di_moment_arrow.pos = part.pos
861 #print " dist apart cur ", part.dist_apart, part.old_dist_apart
862 part
.old_dist_apart
= part
.dist_apart
864 # Set how long we want particle trails.
865 # Could make simulation run faster by having fewer joints in the trails.
866 if part
.mag_velocity
> (c
/2) :
868 elif part
.mag_velocity
> (c
/4) :
870 elif part
.mag_velocity
> (c
/8) :
872 elif part
.mag_velocity
> (c
/16) :
874 elif part
.mag_velocity
> (c
/32) :
878 if ( wl
.main_loop_count
% and_value
) == 0 :
879 my_retain
= 64 # arbitrary, what I think looks nice
880 if part
.is_electron
:
881 my_retain
= 512 / wl
.particle_count
# arbitrary
884 part
.trail
.append(pos
=part
.pos
,retain
=my_retain
)
885 #part.trail.append(pos=part.pos) # If using earlier version of vpython
886 #print "wl.pars[1].pos-old_pos", (wl.pars[1].pos-wl.pars[1].old_pos),
887 #print "high vel pos delta", pos_delta
888 # end implement_particle_calcs()
891 def particle_calcs():
895 dt_updated
= do_particle_calcs()
897 break # We didn't update our delta time (wl.dt) so we are done with do_particle_calcs.
898 implement_particle_calcs()
899 scene
.autoscale
= wl
.auto_zoom
900 wl
.prev_KE_system
= wl
.curr_KE_system
901 #if ( debug_sum_forces_on_one_particle > 20 ):
902 #if wl.main_loop_count%4 == 0 :
905 print "particles.py <num particles>"
906 print "\t a = toggle auto zoom"
907 print "\t n = show numbers"
908 print "\t <space bar> = toggle between pause and play mode"
912 opts
, args
= getopt
.getopt(sys
.argv
[1:], "ho:v", ["help", "output="]) # http://docs.python.org/library/getopt.html
913 except getopt
.GetoptError
, err
:
914 # print help information and exit:
915 print str(err
) # will print something like "option -a not recognized"
923 elif o
in ("-h", "--help"):
926 elif o
in ("-o", "--output"):
929 assert False, "unhandled option"
932 wl
.particle_count
= int(argv
[0])
935 display_particle_labels()
936 if ( wl
.particle_count
<= 2 ) :
937 hide_particle_labels()
939 if scene
.kb
.keys
: # did the user hit a key?
940 key
= scene
.kb
.getkey() # obtain keyboard information
941 #print "\ns%s\n", key
943 kb_input_label
.text
= key
# append new character
944 kb_input_label
.visible
= 1
945 if key
== 'q' or key
== 'e':
949 elif key
== 's' or key
== 'p' or key
== ' ': #stop, pause or play
950 wl
.play_mode
= not wl
.play_mode
952 kb_input_label
.visible
= 0
953 elif key
== 'n' or key
== 'N' :
954 if wl
.display_particle_labels_bool
:
955 hide_particle_labels()
957 display_particle_labels()
958 elif key
== 'a' or key
== 'A' :
959 wl
.auto_zoom
= not wl
.auto_zoom
961 kb_input_label
.visible
= 0
962 kb_input_label
.text
= '' # erase all the text
964 area_of_interest
= 50000000
965 #area_of_interest = 50
966 if wl
.main_loop_count
> area_of_interest
+ 118 :
968 elif wl
.main_loop_count
> area_of_interest
+ 100:
970 elif wl
.main_loop_count
> area_of_interest
+ 50:
972 elif wl
.main_loop_count
> area_of_interest
+ 25 :
974 elif wl
.main_loop_count
> area_of_interest
:
975 rate(50) # 10 = 1/10 of a second wait. http://vpython.org/webdoc/visual/rate.html
977 #rate(6500/(wl.main_loop_count+1)) # http://vpython.org/webdoc/visual/rate.html
978 if ( debug_sum_forces_on_one_particle
> 20 or
979 ( debug_sum_forces_on_one_particle
> 15 and wl
.main_loop_count
%64==0 )):
982 print "it %4d" % wl
.main_loop_count
,
983 for i
in range(wl
.particle_count
):
985 update_particle_em_wave_heights(part
) # Update the current magnitude of the e and m wave.
988 wl
.total_time
+= wl
.dt
989 wl
.main_loop_count
+= 1
990 #rate(1) # Remove this after debug
991 if wl
.display_particle_labels_bool
and wl
.main_loop_count
> wl
.hide_number_label_count
:
992 hide_particle_labels()
996 if __name__
== "__main__":
999 # This theory explains the following:
1000 # 1) All mass as standing EM waves
1001 # Electric charge as an oscillation of electric wave between 0 and 2e. Average is e.
1002 # There are no particles, just standing EM waves or from a different perspective: particles are standing EM waves.
1004 # 2) Physics spin as the amplitude of the magnetic wave
1005 # If you look close at the stern-gerlach experiment. If you get exact measurements for the particle distribution you will
1006 # see the result is sinusoidal distribution not a split.
1007 # This also explains other results from Japan that should the electrons flowing sinusoidally.
1008 # 3) Weak nuclear force
1009 # As electrical and magnetic forces and particles constantly in motion in the nucleus
1010 # Nucleus not a rigid body. Motion creates strong magnetic forces.
1011 # Explains beta decay.
1012 # 4) Why a neutron is not stable
1013 # Electron is hurling around the proton at relativistic speeds
1014 # Both particles oscillate between 0 and 2e charge.
1015 # When electron and proton are close to zero charge the two particles separate.
1016 # 5) Explain spin as intrinsic magnetic field
1017 # A changing electric field will give rise to an apposing magnetic field.
1019 # May help explain strong nuclear force:
1020 # No neutrons. Just electrons and protons.
1021 # Neutron is a proton and electron superimposed on each other.
1022 # a. Electron helps mask charge of nearby proton
1023 # When electron at 2e charge will cause protons to come closer together
1024 # but when electron at zero charge then protons will fly away
1025 # b. Magnetic fields forces particles into circular path
1026 # Stops them from flying directly away from each other.
1027 # c. Orbiting electrons spend time near the nucleus helping nucleus be stable
1028 # Can fly right thru center and possibly bump other electron out
1029 # d. Magnetic force from all particles can combine and attract.
1030 # Doesn't have to oppose like protons positive repelling each other.
1031 # Magnetic force from qv and intrinsic magnetic field
1032 # Magnetic force from qv high because electron buzzing around protons at nearly the speed of light.
1033 # Two protons traveling in the same direction will have a magnetic force that draws them together.
1034 # If speed is high enough then perhaps strong compared to electric repulsive force.
1035 # e. When measure size of the nucleus, perhaps what is being measured is a strong magnetic field.
1036 # Perhaps a protons are further apart then believed but still contribute to magnetic field of
1042 # Is split in Stern-Gerlach experiment due mostly to qv, intrinsic magnetic field, or both?
1047 1. Fix Only reduce velocity of electrons that have been tossed by a proton and vice versa.
1048 Bring it back much sooner?
1049 Quit the experiment if it has escape velocity?
1050 Calculate escape velocity?
1052 Enhance the program to?
1053 1. Specify opacity on command line and thru keyboard events.
1054 2. show number for particles
1055 3. Display info on a particular particle
1056 4. Specify what to log or not log anything
1057 5. Only show total force. Force is colored for electrical or magnetic force.
1058 6. Specify trail length or no trails
1059 7. Specify wl.dt as a multiple of proton frequency of 1/16.
1060 8. Other things that can be done to improve speed.
1062 0. Specify trail length. retain=
1063 a. Different algorithms to compensate for energy gain or no algo.
1064 b. Different algorithms for how the magnetic field lines up.
1068 1. http://en.wikipedia.org/wiki/Helium-6#Table
1069 Does it predect helium isotope decay?