;==================== begin random-walk.nls ====================================
; random-walk - random walk for individuals.  Respects non-wrapping
; world boundaries.
;
; By Rik Blok, 2013 <http://www.zoology.ubc.ca/~rikblok/wiki/doku.php>
;
; This is free and unencumbered software released into the public domain.
;
; Anyone is free to copy, modify, publish, use, compile, sell, or
; distribute this software, either in source code form or as a compiled
; binary, for any purpose, commercial or non-commercial, and by any
; means.
;
; Provides:
;  
;   random-walk
;     All specified agents perform a random walk.
;   random-walk-in-bounds
;     As random-walk but bounded.
;   random-walk-in-cone
;     As random-walk but heading has persistence.
;   random-walk-in-cone-bounds
;     As random-walk-cone but bounded.
;   random-walk-jump-size
;     Reports the step size given diffusion constant and time step.
;   random-walk-time-patch 
;     Reports typical time to cross one patch given diffusion constant.
;   random-walk-time-world
;     Reports typical time to cross world given diffusion constant.
;   random-walk-cone-from-per-patch
;     Reports cone-angle per step in random walk from angle per patch.
;   random-walk-cone-from-per-tick
;     Reports cone-angle per step in random walk from angle per tick.
;
; Usage:
;
;   set _time-step_  random-walk-time-patch  _diffusion-constant_
;   print  random-walk-time-world  _diffusion-constant_
;   random-walk  _agents_  random-walk-jump-size  _diffusion-constant_  _time-step_
;
; Example:
;
;   ; assume well-mixed-switch, diffusion-const-slider and error-tolerance are already set
;   globals [ dt ]
;   to go
;     ; choose timestep so it's rare for an individual to cross patch per step
;     set dt error-tolerance * random-walk-time-patch diffusion-const-slider
;     ifelse (well-mixed-switch?) [
;       ; turtles are well-mixed, can move anywhere
;       random-walk turtles 0
;     ][
;       ; move random direction, variance proportional to diffusion-const-slider * dt
;       random-walk turtles random-walk-jump-size diffusion-const-slider dt
;   end
;
; Known limitations:
;
;   2013-08-18 - cone code untested
; 
; Revisions:
;
;   2013-08-18 - renamed from diffuse-individual.nls to random-walk.nls
;              - added random-walk-in-bounds procedure
;              - added random-walk-jump-size reporter
;              - changed random-walk procedures: now take a single jump-size parameter
;                instead of diffusion-constant & time step
;              - added random-walk-in-cone and random-walk-in-cone-bounds procedures
;              - added random-walk-cone-from-per-tick and
;                random-walk-cone-from-per-patch reporters
;   2013-08-16 - added random-walk-time-patch & random-walk-time-world reporters
;   2013-08-02 - initial release by Rik Blok
;-------------------------------------------------------------------------------


to random-walk
; All _rw-agents_ perform a random walk with steps of size _rw-jump-size_.
; Parameters:
[ rw-agents    ; agents to do random walk
  rw-jump-size ; jump size.  0 for well-mixed.
]
  random-walk-in-cone-bounds rw-agents rw-jump-size 360 task [ true ]
end


to random-walk-in-bounds
[ rw-agents        ; agents to do random walk
  rw-jump-size     ; jump size.  0 for well-mixed.
  rw-is-in-bounds? ; task.  Reports true if destination patch is in bounds.
]
  random-walk-in-cone-bounds rw-agents rw-jump-size 360 rw-is-in-bounds?
end


to random-walk-in-cone
[ rw-agents        ; agents to do random walk
  rw-jump-size     ; jump size.  0 for well-mixed.
  rw-cone-angle    ; angle of cone agents can turn. 0 to 360.
]
  random-walk-in-cone-bounds rw-agents rw-jump-size rw-cone-angle task [ true ]
end


to random-walk-in-cone-bounds
[ rw-agents        ; agents to do random walk
  rw-jump-size     ; jump size.  0 for well-mixed.
  rw-cone-angle    ; angle of cone agents can turn. 0 to 360.
  rw-is-in-bounds? ; task.  Reports true if destination patch is in bounds.
]
  if-else (rw-jump-size = 0)
  [ ; well-mixed, anybody could be anywhere
    ask rw-agents 
    [ let newx random-xcor
      let newy random-ycor
      ; if new coordinates are in bounds
      if [runresult rw-is-in-bounds?] of patch newx newy 
      [ setxy newx newy ; move current individual to new coordinates 
      ]
    ]
  ]
  [ ; not well-mixed, do random walk
    ; see http://en.wikipedia.org/wiki/Random_walk#Relation_to_Wiener_process
    ask rw-agents 
    [ right ( random-float rw-cone-angle ) - rw-cone-angle / 2 
      ; error trap
      let jump-patch patch-ahead rw-jump-size
      if jump-patch = nobody [ stop ]
      ; if new coordinates are in bounds
      if [runresult rw-is-in-bounds?] of jump-patch 
      [ jump rw-jump-size ; move current individual to new coordinates
      ]
    ]
  ]
end


to-report random-walk-time-patch
; Reports typical time to cross one patch.  Assumes 2 dimensions, no boundaries.
; Parameters:
[ rw-diff-const ; diffusion constant
]
  if-else (rw-diff-const = 0)
  [ ; well-mixed, takes no time to cross space
    report 0
  ]
  [ ; not well-mixed, take diffusion length to be patch length (unity) & assume 2D
    ; from: diffusion-length = sqrt ( 2 * dimensions * random-walk-time * diff-const )
    report 1 / ( 4 * rw-diff-const )
  ]
end


to-report random-walk-time-world
; Reports typical time to cross world.  Assumes 2 dimensions, no boundaries.
; Parameters:
[ rw-diff-const ; diffusion constant
]
  if-else (rw-diff-const = 0)
  [ ; well-mixed, takes no time to cross space
    report 0
  ]
  [ ; not well-mixed, take diffusion length to be sqrt of whole area & assume 2D
    ; from: diffusion-length = sqrt ( 2 * dimensions * random-walk-time * diff-const )
    report world-width * world-height / ( 4 * rw-diff-const )
  ]
end


to-report random-walk-jump-size
; Reports the jump size for a random walk with specified diffusion constant and 
; time step.  Assumes 2 dimensions, no boundaries.
; Parameters:
[ rw-diff-const  ; diffusion constant
  rw-dt          ; time step
]
  report sqrt ( 4 * rw-diff-const * rw-dt )
end


to-report random-walk-cone-from-per-patch
; Reports cone-angle per step in random walk from angle per patch.
; Parameters:
[ rw-angle-per-patch ; cone angle per patch
  rw-diff-const      ; diffusion constant
  rw-dt              ; time step
]
  report random-walk-cone-from-per-tick 
    ( rw-angle-per-patch / random-walk-time-patch rw-diff-const ) 
    rw-dt
end
  
to-report random-walk-cone-from-per-tick
; Reports cone-angle per step in random walk from angle per tick.
; Assumes heading performs random walk in 1 dimension with 
; steps-per-tick = 1 / (time step).  Then 
; angle-per-tick = sqrt ( steps per tick ) * angle-per-step so
; angle-per-step = angle-per-tick * sqrt ( time step ).
; Parameters:
[ rw-angle-per-tick  ; cone angle per tick
  rw-dt              ; time step
]
  report rw-angle-per-tick * sqrt rw-dt
end
  
;==================== end random-walk.nls ======================================