GasLab Gas in a Box (Perspective Demo)
Model was written in NetLogo 5.0.4
•
Viewed 299 times
•
Downloaded 57 times
•
Run 0 times
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
Comments and Questions
Click to Run Model
globals [ tick-delta ;; how much we advance the tick counter this time through max-tick-delta ;; the largest tick-delta is allowed to be box-edge ;; distance of box edge from axes init-avg-speed init-avg-energy ;; initial averages avg-speed avg-energy ;; current averages fast medium slow ;; current counts percent-slow percent-medium percent-fast ;; percentage of current counts ] breed [ particles particle ] breed [ flashes flash ] flashes-own [birthday] particles-own [ speed mass energy ;; particle info last-collision ] to setup clear-all set-default-shape particles "circle" set-default-shape flashes "plane" set max-tick-delta 0.1073 ;; the box size is determined by the slider set box-edge (round (max-pxcor * box-size / 100)) make-box make-particles update-variables set init-avg-speed avg-speed set init-avg-energy avg-energy reset-ticks end to update-variables set medium count particles with [color = green] set slow count particles with [color = blue] set fast count particles with [color = red] set percent-medium (medium / ( count particles )) * 100 set percent-slow (slow / (count particles)) * 100 set percent-fast (fast / (count particles)) * 100 set avg-speed mean [speed] of particles set avg-energy mean [energy] of particles end to go ask particles [ bounce ] ask particles [ move ] ask particles [ if collide? [check-for-collision] ] ifelse trace? [ ask first sort particles [ pen-down ] ] [ ask first sort particles [ pen-up ] ] tick-advance tick-delta if floor ticks > floor (ticks - tick-delta) [ update-variables ] calculate-tick-delta ask flashes with [ticks - birthday > 0.4] [ die ] display end to calculate-tick-delta ;; tick-delta is calculated in such way that even the fastest ;; particle will jump at most 1 patch length when we advance the tick counter. ;; As particles jump (speed * tick-delta) at every clock tick, making ;; tick length the inverse of the speed of the fastest particle ;; (1/max speed) assures that. Having each particle advance at most ;; one patch-length is necessary for it not to "jump over" a wall ;; or another particle. ifelse any? particles with [speed > 0] [ set tick-delta min list (1 / (ceiling max [speed] of particles)) max-tick-delta ] [ set tick-delta max-tick-delta ] end to bounce ;; particle procedure ;; get the coordinates of the patch we'll be on if we go forward 1 let new-patch patch-ahead 1 let new-px [pxcor] of new-patch let new-py [pycor] of new-patch ;; if we're not about to hit a wall, we don't need to do any further checks if not shade-of? yellow [pcolor] of new-patch [ stop ] ;; if hitting left or right wall, reflect heading around x axis if (abs new-px = box-edge) [ set heading (- heading) ] ;; if hitting top or bottom wall, reflect heading around y axis if (abs new-py = box-edge) [ set heading (180 - heading)] ask patch new-px new-py [ sprout-flashes 1 [ set color pcolor - 2 set birthday ticks set heading 0 ] ] end to move ;; particle procedure if patch-ahead (speed * tick-delta) != patch-here [ set last-collision nobody ] jump (speed * tick-delta) end to check-for-collision ;; particle procedure ;; Here we impose a rule that collisions only take place when there ;; are exactly two particles per patch. We do this because when the ;; student introduces new particles from the side, we want them to ;; form a uniform wavefront. ;; ;; Why do we want a uniform wavefront? Because it is actually more ;; realistic. (And also because the curriculum uses the uniform ;; wavefront to help teach the relationship between particle collisions, ;; wall hits, and pressure.) ;; ;; Why is it realistic to assume a uniform wavefront? Because in reality, ;; whether a collision takes place would depend on the actual headings ;; of the particles, not merely on their proximity. Since the particles ;; in the wavefront have identical speeds and near-identical headings, ;; in reality they would not collide. So even though the two-particles ;; rule is not itself realistic, it produces a realistic result. Also, ;; unless the number of particles is extremely large, it is very rare ;; for three or more particles to land on the same patch (for example, ;; with 400 particles it happens less than 1% of the time). So imposing ;; this additional rule should have only a negligible effect on the ;; aggregate behavior of the system. ;; ;; Why does this rule produce a uniform wavefront? The particles all ;; start out on the same patch, which means that without the only-two ;; rule, they would all start colliding with each other immediately, ;; resulting in much random variation of speeds and headings. With ;; the only-two rule, they are prevented from colliding with each other ;; until they have spread out a lot. (And in fact, if you observe ;; the wavefront closely, you will see that it is not completely smooth, ;; because some collisions eventually do start occurring when it thins out while fanning.) if count other particles-here = 1 [ ;; the following conditions are imposed on collision candidates: ;; 1. they must have a lower who number than my own, because collision ;; code is asymmetrical: it must always happen from the point of view ;; of just one particle. ;; 2. they must not be the same particle that we last collided with on ;; this patch, so that we have a chance to leave the patch after we've ;; collided with someone. let candidate one-of other particles-here with [who < [who] of myself and myself != last-collision] ;; we also only collide if one of us has non-zero speed. It's useless ;; (and incorrect, actually) for two particles with zero speed to collide. if (candidate != nobody) and (speed > 0 or [speed] of candidate > 0) [ collide-with candidate set last-collision candidate ask candidate [ set last-collision myself ] ] ] end ;; implements a collision with another particle. ;; ;; THIS IS THE HEART OF THE PARTICLE SIMULATION, AND YOU ARE STRONGLY ADVISED ;; NOT TO CHANGE IT UNLESS YOU REALLY UNDERSTAND WHAT YOU'RE DOING! ;; ;; The two particles colliding are self and other-particle, and while the ;; collision is performed from the point of view of self, both particles are ;; modified to reflect its effects. This is somewhat complicated, so I'll ;; give a general outline here: ;; 1. Do initial setup, and determine the heading between particle centers ;; (call it theta). ;; 2. Convert the representation of the velocity of each particle from ;; speed/heading to a theta-based vector whose first component is the ;; particle's speed along theta, and whose second component is the speed ;; perpendicular to theta. ;; 3. Modify the velocity vectors to reflect the effects of the collision. ;; This involves: ;; a. computing the velocity of the center of mass of the whole system ;; along direction theta ;; b. updating the along-theta components of the two velocity vectors. ;; 4. Convert from the theta-based vector representation of velocity back to ;; the usual speed/heading representation for each particle. ;; 5. Perform final cleanup and update derived quantities. to collide-with [ other-particle ] ;; particle procedure ;;; PHASE 1: initial setup ;; for convenience, grab some quantities from other-particle let mass2 [mass] of other-particle let speed2 [speed] of other-particle let heading2 [heading] of other-particle ;; since particles are modeled as zero-size points, theta isn't meaningfully ;; defined. we can assign it randomly without affecting the model's outcome. let theta (random-float 360) ;;; PHASE 2: convert velocities to theta-based vector representation ;; now convert my velocity from speed/heading representation to components ;; along theta and perpendicular to theta let v1t (speed * cos (theta - heading)) let v1l (speed * sin (theta - heading)) ;; do the same for other-particle let v2t (speed2 * cos (theta - heading2)) let v2l (speed2 * sin (theta - heading2)) ;;; PHASE 3: manipulate vectors to implement collision ;; compute the velocity of the system's center of mass along theta let vcm (((mass * v1t) + (mass2 * v2t)) / (mass + mass2) ) ;; now compute the new velocity for each particle along direction theta. ;; velocity perpendicular to theta is unaffected by a collision along theta, ;; so the next two lines actually implement the collision itself, in the ;; sense that the effects of the collision are exactly the following changes ;; in particle velocity. set v1t (2 * vcm - v1t) set v2t (2 * vcm - v2t) ;;; PHASE 4: convert back to normal speed/heading ;; now convert my velocity vector into my new speed and heading set speed sqrt ((v1t ^ 2) + (v1l ^ 2)) set energy (0.5 * mass * speed ^ 2) ;; if the magnitude of the velocity vector is 0, atan is undefined. but ;; speed will be 0, so heading is irrelevant anyway. therefore, in that ;; case we'll just leave it unmodified. if v1l != 0 or v1t != 0 [ set heading (theta - (atan v1l v1t)) ] ;; and do the same for other-particle ask other-particle [ set speed sqrt ((v2t ^ 2) + (v2l ^ 2)) set energy (0.5 * mass * (speed ^ 2)) if v2l != 0 or v2t != 0 [ set heading (theta - (atan v2l v2t)) ] ] ;; PHASE 5: final updates ;; now recolor, since color is based on quantities that may have changed recolor ask other-particle [ recolor ] end to recolor ;; particle procedure ifelse speed < (0.5 * 10) [ set color blue ] [ ifelse speed > (1.5 * 10) [ set color red ] [ set color green ] ] end ;;; ;;; drawing procedures ;;; ;; draws the box to make-box ask patches with [ ((abs pxcor = box-edge) and (abs pycor <= box-edge)) or ((abs pycor = box-edge) and (abs pxcor <= box-edge)) ] [ set pcolor yellow ] end ;; creates initial particles to make-particles create-particles number-of-particles [ setup-particle random-position recolor ] calculate-tick-delta end to setup-particle ;; particle procedure set speed init-particle-speed set mass particle-mass set energy (0.5 * mass * speed * speed) set last-collision nobody end ;; place particle at random location inside the box. to random-position ;; particle procedure setxy ((1 - box-edge) + random-float ((2 * box-edge) - 2)) ((1 - box-edge) + random-float ((2 * box-edge) - 2)) end to-report last-n [n the-list] ifelse n >= length the-list [ report the-list ] [ report last-n n butfirst the-list ] end ; Copyright 1997 Uri Wilensky. ; See Info tab for full copyright and license.
There are 6 versions of this model.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
GasLab Gas in a Box (Perspective Demo).png | preview | Preview for 'GasLab Gas in a Box (Perspective Demo)' | over 11 years ago, by Uri Wilensky | Download |
This model does not have any ancestors.
This model does not have any descendants.