Water Flowing Uphill NetLogo Model

Produced for the book series "Artificial Intelligence";

Author: W. J. Teahan; Publisher: Ventus Publishing Aps, Denmark.

powered by NetLogo

view/download model file: Water-Flowing-Uphill.nlogo

WHAT IS IT?

This model tries to visually simulate one possible solution to the problem of trying to get water to flow uphill. The solution is to use tanks or reservoirs at increasing heights, and have these fill up one after the other. A stop-valve (shown in blue at the end of the connecting pipes between reservoirs in the model) is used to prevent back filling of the reservoirs - once the water moves through the valve, it cannot flow backwards.

Various methods are tried to simulate how the "water" flows. All of these methods are failures, some of them producing strange effects that are impossible in the real world. The reader is encouraged to add his or her own methods which better approximate how water flows in real life.


WHAT IS ITS PURPOSE?

The purpose of the model is to draw an analogy between a seemingly impossible task (trying to get water to flow uphill) and what some people claim to also be impossible (creating Artificial Intelligence). For both of these tasks, we can try to find solutions that change the problem in some way, or we can try to change the physical properties of the universe (i.e. have it work in a virtual environment, but it would not work when transferred to a real environment), or we could create an illusion (i.e. it would look like the problem was solved, but like magic, it would just be trickery.)

A secondary purpose is to highlight the process of problem solving that humans are very good at. No computer program is capable of creating the variety of solutions that are shown in this model. For that matter, no computer programs are yet capable of understanding the problem itself.


HOW IT WORKS

The model implements various types of agents to try to simulate water flow - turtle agents, patch agents, agents that are boids (from Craig Reynolds work) with a cone of vision, and particle agents that simulate the velocity of each particle and takes into consideration viscosity, wind and gravity.

None of these solutions work i.e. they behave nothing like water does.


HOW TO USE IT

Press the setup-environment button in the Interface first to reset the simulation. Then choose one of the solutions using the solution chooser. See what happens when you press the go-simulation button.


THE INTERFACE

The model's Interface buttons are defined as follows:

- setup-simulation: This will reset the simulation back to the start state which is where all the reserviors have no water in them, and the tap is turned off.

- go-simulation: This turns on the tap, and agents that simulate water droplets start flowing downwards out of the tap into the first reservoir on the left.

The model's Interface sliders, switches and chooser are defined as follows:

1. For when the solution chooser is set to either "turtle agents 1" or "turtle agents 2":
- drops-per-tick: This is the number of drops that will emerge out of the tap every tick.
- size-of-drop: This is the size of each drop.
- shape-of-drop: This is the shape of each drop. Possible shapes are "drop", "circle", "square" and "hex".

2. For when the solution chooser is set to "boid agents 1":
- rate-of-random-turn: This controls how much the boid randomly turns each tick.
- radius-angle and radius-length: This defines the boids' cone of vision.
- boid-speed: This specifies how far the boids should move each tick.
- boid-bounce: This specifies how far the boids should bounce back when they hit the tank walls or the earth.

3. For when the solution chooser is set to "particle agents 1":
- max-particles: This specifies the maximum number of particles and can be used to control how many particles come out of the tap.
- initial-velocity-x and initial-velocity-y: This specifies the initial velocity of the particle in the x and y directions.
- initial-range-x: This provides some random variability in the velocity in the x direction.
- restitution-constant: This can be used to control how much bounce with floor damping occurs if the particle touches the tank floor.
- gravity-constant: This is used to scale the force of the gravity according to the particle's mass thereby simulating the effect of air resistance.
- viscosity-constant: This can be used to simulate the effect of viscosity.
- rate: This controls the rate of particle emission.
- step-size: The new location and speed of each particle is calculated by multiplying the forces by this number. The ticks also advance by this number.
- wind-velocity-x and wind-velocity-y: This specifies the velocity of the wind in the x and y directions.


THINGS TO NOTICE

When the chooser solution in the Interface is set to "turtle agents 1", the agents behave a bit like water, but do not spread out at the bottom. Why? How can their behaviour be changed to fix the problem?

When the chooser solution in the Interface is set to "turtle agents 1", the agents behave a bit like snow. Why? How can their behaviour be changed so that they behave more like water?

When the chooser solution in the Interface is set to "patch agents 1", the agents do not flow correctly on the right. Why? How can their behaviour be changed so that the right side of the reservoir fills up correctly and then flows via the connecting pipe to the next reservoir and so on?

When the chooser solution in the Interface is set to "patch agents 2", "patch agents 3", or "patch agents 4", the simulations are complete failures. Can any of these be salvaged in order to find a possible solution?

When the chooser solution in the Interface is set to "boid agents 1", the agents behave a bit like spray-painting in some configurations. Why? Also, like the "turtle agents 1" solution, they do not spread out at the bottom. Why? How can their behaviour be changed to fix the problem? How can their behaviour be changed so that they behave more like water?

When the chooser solution in the Interface is set to "particle agents 1", the agents tunnel through the surrounding earth. Why? How can their behaviour be changed so that they behave more like water?


THINGS TO TRY

Try out each of the solutions in turn to see what happens. Which one seems to be closest to what happens in real life?

Try changing the values of the sliders to see what effect they have on each solution (for turtle agents solutions 1 and 2, patch agents solution 1, boids agents solution 1 and particle agents solution 1).

When the solution variable is set to "particle agents 1", try sliding the "max-particles" slider back and forth. The effect of this is that the tap will seem to be temporarily turned on and off.


EXTENDING THE MODEL

Try devising your own solution that simulates water flow more accurately. Observe the process of problem solving that you apply in order to come up with your solution. Would it be possible to devise a computer program to replicate your behaviour?


CREDITS AND REFERENCES

This model was created by William John Teahan.

To refer to this model in publications, please use:

Water Flowing Uphill NetLogo model.
Teahan, W. J. (2010). Artificial Intelligence. Ventus Publishing Aps

The particle agents code used in this model was obtained from the Particle System Waterfall produced by Uri Wilensky. See the model for for a list of references and how to cite it.


PROCEDURES

; Water Flowing Uphill model.
;
; How not to make water go uphill.
; See if you can do better than me.
; 
; Copyright William John Teahan 2010. All Rights Reserved.

breed [taps tap]   ; the tap
breed [drops drop] ; water drops simulated as turtle agents
breed [particles particle] ; water drops simulated using particle agents

particles-own
[
  mass
  velocity-x             ; particle velocity in the x axis
  velocity-y             ; particle velocity in the y axis
  force-accumulator-x    ; force exerted in the x axis
  force-accumulator-y    ; force exerted in the y axis
]

globals
[
  colour-of-earth        ; colour used for earth around tanks
]

to setup-environment
  ca ;; clear everything

  ask patches
  [
    set pcolor white ;; make background full of white patches

    if (pxcor >= min-pxcor) and (pxcor <= 15 - max-pxcor) and
       (pycor >= max-pycor - 12) and (pycor <= max-pycor - 11)
      [ set pcolor black ] ; drawn pipe to tap

    ; draw earth below the tanks
    ; this will make the code easier as we can make stray drops
    ; 'disappear' into the earth by killing them off
    set colour-of-earth 38
    if (pycor < max-pxcor - 100 + 7) 
      [ set pcolor colour-of-earth ] 
    if (pxcor > 8 - max-pxcor + 90) and (pycor < max-pycor - 44)
      [ set pcolor colour-of-earth ] 
    if (pxcor > 8 - max-pxcor + 140) and (pycor < max-pycor - 24)
      [ set pcolor colour-of-earth ] 

  ]
    
  create-taps 1
  [ set shape "tap"
    setxy (19 - max-pxcor) (max-pycor - 10)
    set heading 0
    set color gray
    set size 10 ]

  setup-tank (8 - max-pxcor) (max-pycor - 100) 40 35
  setup-tank (8 - max-pxcor + 50) (max-pycor - 100 + 20) 40 35
  setup-tank (8 - max-pxcor + 100) (max-pycor - 100 + 40) 40 35
  
  setup-pipe (8 - max-pxcor + 40) (max-pycor - 100 + 30) 10 3
  setup-pipe (8 - max-pxcor + 90) (max-pycor - 100 + 50) 10 3
end

to setup-tank [xpos ypos xlen ylen]
; sets up a water tank

  ask patches
  [
    ; draw left side
    if (pxcor = xpos) and (pycor >= ypos) and (pycor <= ypos + ylen)
      [ set pcolor black ]
    ; draw bottom
    if (pxcor >= xpos) and (pxcor <= xpos + xlen) and (pycor = ypos)
      [ set pcolor black ]
    ; draw right side
    if (pxcor = xpos + xlen) and (pycor >= ypos) and (pycor <= ypos + ylen)
      [ set pcolor black ]

    ; drawn white inside tank
    if (pxcor >= xpos + 1) and (pxcor <= xpos + xlen - 1) and
       (pycor >= ypos + 1) and (pycor <= ypos + ylen)
      [ set pcolor white ]
  ]
end

to setup-pipe [xpos ypos xlen ylen]
; setups a pipe between tanks

  ask patches
  [
    ; draw top of pipe
    if (pxcor >= xpos) and (pxcor <= xpos + xlen) and (pycor = ypos)
      [ set pcolor gray ]
    ; draw bottom of pipe
    if (pxcor >= xpos) and (pxcor <= xpos + xlen) and (pycor = ypos + ylen)
      [ set pcolor gray ]
    ; clear left entrance of pipe, and pipe itself
    if (pxcor >= xpos) and (pxcor <= xpos + xlen - 1) and
       (pycor >= ypos + 1) and (pycor <= ypos + ylen - 1)
      [ set pcolor white ]
    ; draw a light blue coloured light over right exit of pipe to indicate
    ; a one-way valve
    if (pxcor = xpos + xlen) and (pycor >= ypos + 1) and (pycor <= ypos + ylen - 1)
      [ set pcolor cyan ]

  ]
end

to go-simulation
; runs the simulation creating a steady folow of water
; using different solutions
  if (solution = "turtle agents 1")   ; a bit like water, but doesn't spread out at bottom
    [ go-using-turtle-agents-1 ]
  if (solution = "turtle agents 2")   ; like snowflakes
    [ go-using-turtle-agents-2 ]
  if (solution = "turtle agents 3")   ; try you own solution here
    [ go-using-turtle-agents-3 ]
  if (solution = "patch agents 1")    ; like sand
    [ go-using-patch-agents-1 ]
  if (solution = "patch agents 2")    ; failed initial attempt that covers whole screen 
    [ go-using-patch-agents-2 ]
  if (solution = "patch agents 3")    ; failed second attempt that fills tank with diagonal steps
    [ go-using-patch-agents-3 ]
  if (solution = "patch agents 4")    ; failed third attempt that creates a rectangle of water
    [ go-using-patch-agents-4 ]
  if (solution = "patch agents 5")    ; try you own solution here
    [ go-using-patch-agents-5 ]
  if (solution = "boid agents 1")     ; like spray painting in some configurations
    [ go-using-boid-agents-1 ]
  if (solution = "boid agents 2")     ; try you own solution here
    [ go-using-boid-agents-2 ]
  if (solution = "particle agents 1") ; tunnels through the surrounding earth
    [ go-using-particle-agents-1 ]
  if (solution = "particle agents 2") ; try you own solution here
    [ go-using-particle-agents-2 ]
end

to create-new-drops
; creates the drops coming out of the tap each tick

  create-drops drops-per-tick ; create drops of water
  [ ; have the drops come out of the tap
    set color blue
    set shape shape-of-drop
    set size size-of-drop
    set heading 180 ; head down
    setxy (22 - max-pxcor) (max-pycor - 15)
    if (random 2 = 0) [ set xcor xcor + 1 ] ; half the drops come out of the right of the tap
  ]
end

to go-using-turtle-agents-1
; Solution 1 using turtle agents
; With this solution, the turtle agents flow down out of the tap OK,
; but they don't spread out to fill up the tank properly.

  create-new-drops
   
  ask drops
  [ turtles-flow ] ; make all the water drops flow
end

to-report turtles-all-clear? [xinc yinc]
; returns true if the location at dx = xinc, dy - yinc is all clear
; i.e. no tank wall or another water drop
  ifelse ([pcolor] of patch-at xinc yinc != white)
    [ report false ]
    [ report (count drops-at xinc yinc = 0) ]
end

to turtles-move-drop [xinc yinc]
; tries to move the drop in the direction dx=xinc, dy=yinc

  if not (turtles-all-clear? xinc yinc)
    [ stop ]
  setxy xcor + xinc ycor + yinc
end

to turtles-flow ;; turtle procedure
; makes the water drops flow downwards or sideways, but never up!

  ; try to move down first

  let white-patch one-of patches in-radius 1 with [pcolor = white]
  if (white-patch = nobody)
    [ stop ] ; can't move
  ifelse (count drops-at 0 -1 > drops-per-tick) ; too many water drops below me
      or ([pcolor] of patch-at 0 -1 = black) ; at edge of tank
    [ turtles-spread-out white-patch ]
    [ turtles-flow-down ]
end

to turtles-spread-out [white-patch];; turtle procedure
; makes the water drops spread out rather than fall down
; (when there are too many drops nearby)

  setxy [pxcor] of white-patch [pycor] of white-patch
end

to turtles-flow-down ;; turtle procedure
; makes the water drops flow downhill due to gravity

  set ycor ycor - 1 ; make movement downhill constant due to gravity
  let r random 20
  if (r = 0) and ([pcolor] of patch-at 1 0 != black)
    [ set xcor xcor + 1 ] ; make a few drops move to the right
  if (r = 1) and ([pcolor] of patch-at 1 0 != black)
    [ set xcor xcor - 1 ] ; make a few drops move to the left
end

to go-using-turtle-agents-2
; A different solution using turtle agents.
; The water drops behave more like snow flakes

  create-new-drops
   
  ask drops
  [ turtles-flow-1 ] ; make all the water drops flow
end

to turtles-flow-1
  let r random 20
  ifelse (r < 17)
    [ turtles-move-drop 0 -1 ] ; move downwards due to gravity
    [ ifelse (r < 18)
      [ turtles-move-drop -1 0 ] ; move left
      [ turtles-move-drop 1 0 ] ; move right
    ]
end

to go-using-turtle-agents-3
; Insert your own solution here.

  user-message "Not implemented yet!"
end

to go-using-patch-agents-1
; Solution 1 uses patch agents.
; With this solution, the patch agents end up behaving like sand.

  let tapx (19 - max-pxcor)
  let tapy (max-pycor - 10)
  let drawn false
  
  ask patches
  [ ; draw "water" at bottom of tap
    if (pxcor >= tapx + 3) and (pxcor <= tapx + 4) and (pycor = tapy - 5)
      [ set pcolor blue ]
  ]
 
  ask patches with [pcolor = blue]
  [
    set drawn false
    let r random 20
    ifelse (r > 1)
      [ set drawn patches-draw-drop? pxcor (pycor - 1) ] ; draw drop going down most of the time
      [ ifelse (r = 1)
        [ set drawn patches-draw-drop? (pxcor - 1) pycor ] ; draw drop left sometimes
        [ set drawn patches-draw-drop? (pxcor + 1) pycor ] ; draw drop right sometimes
      ]
    if (drawn)
      [ set pcolor white ] ; drop has moved on; reset patch to white
   ]
end

to-report patches-draw-drop? [xpos ypos]
; draw a drop at location xpos, ypos if patch there is white
; return true if the drop was drawn, false otherwise

  let drawn true

  if (xpos < min-pxcor) or (xpos > max-pxcor) or
     (ypos < min-pycor) or (ypos > max-pycor)
     [ report false ] ; outside environment - ignore
     
  ask patch xpos ypos
  [ ifelse (pcolor != white)
      [ set drawn false ]
      [ set pcolor blue ]
  ]
  
  report drawn
end

to-report patches-draw-drop-1? [xpos ypos]
; draw a drop at location xpos, ypos if patch there is not black
; return true if the drop was drawn, false otherwise

  let drawn true

  if (xpos < min-pxcor) or (xpos > max-pxcor) or
     (ypos < min-pycor) or (ypos > max-pycor)
     [ report false ] ; outside environment - ignore

  ask patch xpos ypos
  [ ifelse (pcolor = black)
      [ set drawn false ]
      [ set pcolor blue ]
  ]

  report drawn
end

to go-using-patch-agents-2
; Solution 2 using patch agents.
; This fails completely (run it to see why).

  let tapx (19 - max-pxcor)
  let tapy (max-pycor - 10)
  let drawn false
  let r 0

  ask patches
  [ ; draw "water" at bottom of tap
    if (pxcor >= tapx + 3) and (pxcor <= tapx + 4) and (pycor = tapy - 5)
      [ set pcolor blue ]
  ]
 
  ask patches with [pcolor = blue]
  [
    if not patches-draw-drop? pxcor (pycor - 1) ; check that down is free to move to
      [ set drawn false
        set r 0
        ifelse (r = 0)
          [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
          [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
        if not drawn
          [ ifelse (r = 0)
            [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
            [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
          ]
      ]
  ]
end

to-report patches-hit-surface? [xpos ypos]
; draw a drop at location adjacent to xpos, ypos if the blue patch
; at xpos, ypos is surrounded by a blue patch on the left/right and below it.

  let drawn false

  if ([pcolor] of patch (xpos + 1) ypos = white) ; space to right
    [ if ([pcolor] of patch xpos (ypos - 1) = blue) and
         ([pcolor] of patch (xpos + 1) (ypos - 1) = blue) and
         ([pcolor] of patch (xpos + 2) (ypos - 1) = blue)
        [ set drawn true
          ask patch (xpos + 1) ypos
          [ set pcolor blue ]
        ]
    ]  

  if ([pcolor] of patch (xpos - 1) ypos = white) ; space to left
    [ if ([pcolor] of patch xpos (ypos - 1) = blue) and
         ([pcolor] of patch (xpos - 1) (ypos - 1) = blue) and
         ([pcolor] of patch (xpos - 2) (ypos - 1) = blue)
        [ set drawn true
          ask patch (xpos - 1) ypos
          [ set pcolor blue ]
        ]
    ]  

  report drawn
end

to-report patches-hit-surface-1? [xpos ypos]
; draw a drop at location adjacent to xpos, ypos if the blue patch
; at xpos, ypos is surrounded by a blue patch on the left/right and below it.

  let drawn false

  if ([pcolor] of patch (xpos + 1) ypos = white) ; space to right
    [ if ([pcolor] of patch xpos (ypos - 1) = blue) and
         ([pcolor] of patch (xpos + 1) (ypos - 1) = blue)
        [ set drawn true
          ask patch (xpos + 1) ypos
          [ set pcolor blue ]
        ]
    ]  

  if ([pcolor] of patch (xpos - 1) ypos = white) ; space to left
    [ if ([pcolor] of patch xpos (ypos - 1) = blue) and
         ([pcolor] of patch (xpos - 1) (ypos - 1) = blue)
        [ set drawn true
          ask patch (xpos - 1) ypos
          [ set pcolor blue ]
        ]
    ]  

  report drawn
end

to go-using-patch-agents-3
; Solution 3 using patch agents.
; This also fails completely (run it to see why).

  let tapx (19 - max-pxcor)
  let tapy (max-pycor - 10)
  let drawn false
  let r 0

  ask patches
  [ ; draw "water" at bottom of tap
    if (pxcor >= tapx + 3) and (pxcor <= tapx + 4) and (pycor = tapy - 5)
      [ set pcolor blue ]
  ]
 
  ask patches with [pcolor = blue]
  [
    if not patches-hit-surface? pxcor pycor ; check hit surface to right and left
      [
        if not patches-draw-drop-1? pxcor (pycor - 1) ; check that down is free to move to
          [ set drawn false
            set r random 2
            ifelse (r = 0)
              [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
              [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
            if not drawn
              [ ifelse (r = 0)
                [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
                [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
              ]
          ]
      ]
  ]
end

to go-using-patch-agents-4
; Solution 4 using patch agents.
; This also fails completely (run it to see why).

  let tapx (19 - max-pxcor)
  let tapy (max-pycor - 10)
  let drawn false
  let r 0

  ask patches
  [ ; draw "water" at bottom of tap
    if (pxcor >= tapx + 3) and (pxcor <= tapx + 4) and (pycor = tapy - 5)
      [ set pcolor blue ]
  ]
 
  ask patches with [pcolor = blue]
  [
    if not patches-hit-surface-1? pxcor pycor ; check hit surface to right and left
      [
        if not patches-draw-drop-1? pxcor (pycor - 1) ; check that down is free to move to
          [ set drawn false
            set r random 2
            ifelse (r = 0)
              [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
              [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
            if not drawn
              [ ifelse (r = 0)
                [ set drawn patches-draw-drop? (pxcor + 1) pycor  ]; check right is free
                [ set drawn patches-draw-drop? (pxcor - 1) pycor  ]; check left is free
              ]
          ]
      ]
  ]
end

to go-using-patch-agents-5
; Insert your own solution here.

  user-message "Not implemented yet!"
end

to go-using-boid-agents-1
; Solution 1 using boid agents that use a cone of vision to sense the world (i.e. like Craig Reynold's boids).

  create-new-drops
  
  ask drops                              
  [
    rt random-float rate-of-random-turn 
    lt (rate-of-random-turn  / 2)                      
    fd random boid-speed 
    if count patches in-cone radius-length radius-angle with
        [pcolor = black or pcolor = colour-of-earth] > 0 ; checks patches in its vision
    [ bk boid-bounce / size-of-drop ] ; bounces back if hit tank wall or earth
  ]
end

to go-using-boid-agents-2
; Insert your own solution here.

  user-message "Not implemented yet!"
end

to go-using-particle-agents-1
; Solution 1 using particle agents.

  let tapx (22 - max-pxcor)
  let tapy (max-pycor - 15)

  create-new-particles tapx tapy
  compute-forces ; calculate the forces and add them to the accumulator
  apply-forces   ; calculate the new location and speed by multiplying the
                 ; forces by the step-size
  tick-advance step-size
  display
end

to go-using-particle-agents-2
; Insert your own solution here.

  user-message "Not implemented yet!"
end

to create-new-particles [init-x init-y]
  ;; using a Poisson distribution keeps the rate of particle emission
  ;; the same regardless of the step size
  let n random-poisson (rate * step-size)
  if n + count turtles > max-particles
    [ set n max-particles - count turtles ]
  ask patch init-x init-y
  [
    sprout-particles n
    [
      set color blue
      set shape shape-of-drop
      set size 1 + random-float 1
      set mass 5 * size ^ 2   ; mass proportional to square of size
      setxy init-x init-y
      set velocity-x initial-velocity-x
                     - random-float initial-range-x
                     + random-float initial-range-x
      set velocity-y initial-velocity-y
    ]
  ]
end

to compute-forces
  ask particles
  [
    ; clear the force-accumulator
    set force-accumulator-x 0
    set force-accumulator-y 0
    ; calculate the forces
    apply-gravity
    apply-wind
    apply-viscosity
  ]
end

to apply-gravity  ;; turtle procedure
  ; scale the force of the gravity according to the particle's mass; this
  ; simulates the effect of air resistance
  set force-accumulator-y force-accumulator-y - gravity-constant * mass
end

to apply-wind  ;; turtle procedure
  set force-accumulator-x force-accumulator-x + wind-constant-x
  set force-accumulator-y force-accumulator-y + wind-constant-y
end

to apply-viscosity  ;; turtle procedure
  set force-accumulator-x force-accumulator-x - viscosity-constant * velocity-x
  set force-accumulator-y force-accumulator-y - viscosity-constant * velocity-y
end

; calculates the position of the particle at each step but bounces if the particle
; reaches the edge
to apply-forces
  let this-patch nobody
  let these-colours lput colour-of-earth [black]
  
  ask particles
  [
    ; calculate the new velocity of the particle
    set velocity-x velocity-x + ( force-accumulator-x * step-size)
    set velocity-y velocity-y + ( force-accumulator-y * step-size)
    ; calculate the displacement of the particle
    let step-x velocity-x * step-size
    let step-y velocity-y * step-size
    let new-x xcor + step-x
    let new-y ycor + step-y
    set this-patch patch-at step-x step-y
    if (this-patch = nobody) or (member? ([pcolor] of this-patch) these-colours)
    [
      ; if the particle touches a wall or the ceiling, it dies
      if new-x > max-pxcor or new-x < min-pxcor or new-y > max-pycor
        [ die ]
      
      ; if the particle touches the tank floor, bounce with floor-damping
      set velocity-y (- velocity-y * restitution-coefficient)
      set step-y velocity-y * step-size
      set new-y ycor + step-y
    ]
    facexy new-x new-y
    setxy new-x new-y
  ]
end
;
; Copyright 2010 by William John Teahan.  All rights reserved.
;
; Permission to use, modify or redistribute this model is hereby granted,
; provided that both of the following requirements are followed:
; a) this copyright notice is included.
; b) this model will not be redistributed for profit without permission
;    from William John Teahan.
; Contact William John Teahan for appropriate licenses for redistribution for
; profit.
;
; To refer to this model in publications, please use:
;
; Teahan, W. J. (2010).  Water Flowing Uphill NetLogo model.
;   Artificial Intelligence. Ventus Publishing Aps.
;
; Copyright for Particle Agents code:
;
; Copyright 2007 Uri Wilensky. All rights reserved.
;
; Permission to use, modify or redistribute this model is hereby granted,
; provided that both of the following requirements are followed:
; a) this copyright notice is included.
; b) this model will not be redistributed for profit without permission
; from Uri Wilensky. Contact Uri Wilensky for appropriate licenses for redistribution for profit.
;
;