powered by NetLogo
view/download model file: Cornea_Patch_Formation.nlogo
This is a work-in-progress that seeks to understand how mosaic patches in mouse corneas arrange themselves into spirals. In part, it seeks to demonstrate the limitations of the current "stem-cell model", which argues that the pattern results from preferential placement of stem cells at the periphery, coupled to centripetal migration.
The yellow represents the parts of the mouse cornea that do not contain labeled clones, i.e., there are cells there but they are not visible. The white ring around the periphery is the limbus, a putative stem cell niche. The dark blue circles within the ring represent stem cells that serve as the sole provider of new "mosaic cells" (leaf shape, a representative cluster of ~16 cells) that ultimately migrate towards the center. Pacemaker cells have the same shape but they are red and have independent adjustable controllers. The cells move based on their ability to respond to a chemical that are secreted periodically by the population. Their rhythm can be entrained but only during a window when they are not secreting.
The rules were inspired by coupled-oscillator and Dictyostelium literature.
Cells are assigned an intrinsic energy variable (energy-level) that decreases with each tick according to the age-rate. Once that number reaches 0, the cell disappears/dies. Cells are replenished only through a constant stream of new daughters provided by stem cells.
The migration direction is initially recognized by mosaic cells through a patch value that is coupled to the chemical value secreted by both mosaics and pacemakers.
Mosaic cells move based on three parameters: sniff-angle, value-threshold and sniff-distance. Sniff-angle represents the angle the mosaic cell can sense a value. Value-threshold represents the amount necessary to respond. Sniff-distance is the number of patches ahead the mosaic cell can sense.
The primary difference between mosaics and pacemakers is that they have independent adjustable parameters for cycle and secretion length. Although there is no restriction in this model, pacemakers are generally believed to have a faster cycle.
NUMBER: sets the number of initial mosaic population
STEM-NUMBER: sets the number of initial stemcells population
SNIFF-ANGLE: sets the degree cone-angle with respect to current heading moving cells detect chemical. Also determines the angle the cell will turn after it determines the
highest concentration value.
SNIFF-DISTANCE: sets the point distance from current position cell can detect chemical
ENERGY-LEVEL: sets the initial amount of energy cells possess. This number is spread out over a range so that cells don't die all at once.
AGE-RATE: sets the rate at which cells lose energy.
DRAW-FRAME: draws a wire-frame for assigning positions
CLEAR-FRAME: clears drawings
PARALLELS: sets the number of parallel wires to be drawn
MERIDIANS: sets the number of meridian lines to be drawn
DRAW-SQUARE-FRAME: draws square vertical and horizontal tangents to parallel lines for estimating fractal dimension using a box counting method.
CHEMICAL-CONCENTRATION: sets the amount of chemical secreted with each tick
EVAP-RATE: sets the rate at which chemical is lost
SNIFF-THRESHOLD: sets the amount of chemical required to attract cell movement
FLASHES-TO-RESET: sets the minimum number of secreting neighboring cells required to reset the clock
CYCLE-LENGTH: sets the length of one period
FLASH-LENGTH: sets the duration during cycle in which cells are secreting, which is also the time in which they are refractory to resetting of their cycle.
COUNT-BOXES: reports the number of boxes that cover the periphery.
PACEMKR-RATIO: sets a proportional value with respect to the NUMBER slider to genereate pacemakers cells from the extant mosaic population.
PACEMAKER-LENGTH: sets the period of the pacemaker cell
PACEMAKER-FLASH: sets the duration a pacemaker is secreting
ON-OFF SHOW-CELLS?: gives choice as to whether you want the cells to be visible.
TOTAL-CELL-CLUSTERS: gives a report of how many cell clusters are present.
How do cells behave at the periphery?
How do cells behave near the center?
Try different values to synchronize flashes. How do combinations affect the turtles' movement, formation and shape of clumps?
Try to figure out a way to change the shape of the chemical concentration curve near the center. How does this affect the shape of cell clusters.
What effect does sniff-angle have?
What effect does lowering chemical concentration to 0 have?
Try adding some adhesion rules. What effect will this have?
How about changing the shape of the cornea (changing value)?
Ants use a similar idea of creatures that both drop chemical and follow the gradient of the chemical.
Synchrony and movement algorithms were borrowed from the Firefly model.
This model was developed at the MIT Media Lab using CM StarLogo. See Resnick, M. (1994) "Turtles, Termites and Traffic Jams: Explorations in Massively Parallel Microworlds." Cambridge, MA: MIT Press. Adapted to StarLogoT, 1997, as part of the Connected Mathematics Project. Adapted to NetLogo, 2000, as part of the Participatory Simulations Project.
To refer to this model in academic publications, please use: Wilensky, U. (1997). NetLogo Slime model. http://ccl.northwestern.edu/netlogo/models/Slime. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
In other publications, please use: Copyright 1997 Uri Wilensky. All rights reserved. See http://ccl.northwestern.edu/netlogo/models/Slime for terms of use.
Goodwin BC, Cohen MH. (1969). A phase-shift model for the spatial and temporal organization of developing systems. J Theor Biol. 25(1):49-107.
Dallon JC, Othmer HG. (1997). A discrete cell model with adaptive signalling for aggregation of Dictyostelium discoideum. Philos Trans R Soc Lond B Biol Sci. 352(1351):391-417.
Buck, John. (1988). Synchronous Rhythmic Flashing of Fireflies. The Quarterly Review of Biology, September 1988, 265 - 286.
breed [apex] breed [stemcells stemcell ] breed [mosaics mosaic ] breed [pacemakers pacemaker] patches-own [ chemical value ] globals [radius totals secreting] breed [ drawers drawer ] drawers-own [amount-to-move] breed [liners] ;breed [slougher] mosaics-own [ energy clock ;; each cell's clock threshold ;; the clock tick at which the cell stops secreting reset-level ;; the clock tick a cell will reset to when it is triggered by other secretions window ;; a cell can't reset its cycle if (clock <= window) ] pacemakers-own [clock threshold energy reset-level window ] to setup ca ;;to draw the cornea with mosaic cells on it... create-apex 1 [setxy 0 0 set color yellow ] ask apex [ ask n-of number patches in-radius 40 [sprout-mosaics 1 ] ] ask mosaics [ initialize-mosaic ] ;; Give some proportional value to cornea with respect to distance from center. ;; This is largely responsible for centripetal migration but I couldn't get the majority ;; of cells to move to the middle without it. ask patches [ let center distancexy 0 0 set value (scale-color yellow center 40 -20) * ( 1 / 20)] ;; color background of cornea (this region has cells that are not visible) ask patches [ let center distancexy 0 0 set pcolor scale-color yellow center 40 -10 ] ;; Generate stemcells at the limbus... set radius max-pxcor - 10 create-ordered-stemcells stem-number ask stemcells [ set color 88 fd radius set size 3 set shape "circle" ] ask n-of ( 0.4 * stem-number ) stemcells [set color 101 ] ;; Create a boundary so that cells don't fly off into space ask patches with [distancexy 0 0 > max-pxcor - 10] [ set pcolor grey] update-plots ask apex [die] system-dynamics-setup system-dynamics-do-plot end ;; Give some characters to mosaics... to initialize-mosaic set energy random 200 + energy-level let center distancexy 0 0 set color scale-color 101 center 50 -10 set size 3 set shape "leaf" ;; give them a timing property set clock random (round cycle-length) ;; and assign a boundary under which they can secrete chemical and over which ;; they are sensitive to clock resetting. (These are borrowed from "Firefly" model.) set threshold flash-length set reset-level threshold set window -1 end ;; ____________________________________________________________________________________________________________________________________ to go ask mosaics [move reset rechemical kill-crowd camouflage recolor-mosaics ] diffuse chemical 1 ;; To allow emergence of pacemakers from mosaics to represent the result of change in excitability ask (n-of (pacemkr-ratio * 100) mosaics ) [ if random 100 < 10 [ hatch 1 [ set breed pacemakers set color red initialize-pacemaker ]]] ask pacemakers [ move reset rechemical kill-crowd camouflage recolor ] check ;; Scale evaporation according to distance from center. This is a scaling due to ;; the fact that the view is curved and so there appears to be more cells at the periphery ;; when they should be equally dispersed. ask patches [ifelse distancexy 0 0 != 0 [set chemical chemical * evap-rate * (1 / sqrt distancexy 0 0)] [set chemical chemical * evap-rate ]] ;; evaporate chemical] ask patches [ set-boundaries] diffuse chemical 1 set totals count mosaics update-plots ;; Comment out "color-patches-by-chemical" for different view color-patches-by-chemical system-dynamics-go system-dynamics-do-plot tick end to initialize-pacemaker set shape "leaf" set size 3 set color red let center distancexy 0 0 set color scale-color red center 50 -10 move set clock random (round pacemaker-length) set energy random energy-level + 200 set threshold pacemaker-flash set reset-level threshold set window -1 end ; To show distributions of chemicals... to color-patches-by-chemical let max-chemical 2 ; max [chemical] of patches let min-chemical 0 ;min [chemical] of patches ask patch 0 0 [ ask patches in-radius radius [ set pcolor scale-color yellow chemical (min-chemical - 0.0001) (max-chemical + 0.0001) ] ] end to move ;; both mosaics and pacemakers do this... if value > 0.1 [ turn-toward-value ifelse ( distancexy 0 0 ) != 0 [fd ((1 / 3) * (1 / sqrt distancexy 0 0)) ] [fd 1]] if chemical > sniff-threshold ;; ignore pheromone unless there's enough here [ turn-toward-chemical ifelse ( distancexy 0 0 ) != 0 [fd ((1 / 3) * (1 / sqrt distancexy 0 0)) ] [fd 1 / 3]] if neighbors = grey [ facexy 0 0 rt random sniff-angle lt random sniff-angle fd ((1 / 3) * (1 / sqrt distancexy 0 0)) ] set energy energy - age-rate if energy <= 0 [ die ] if distancexy 0 0 > radius [ die ] end to reset ;; turtle procedure to allow resetting of clocks if (clock < threshold) [ set secreting 10 set chemical chemical + chemical-concentration * (1 / sqrt distancexy 0 0) ] if ( (clock > window) and (clock >= threshold) ) [ look ] if (clock >= threshold) [ set secreting 0 ] increment-clock end to look ; turtle procedure if count turtles in-radius 1 with [ secreting = 10 ] >= flashes-to-reset [ set clock reset-level ] end ;to slough ; let density = [count turtles in-radius 1] ; if density > 4 [ set breed slougher set color green ] ;end to camouflage ;; To see only the gradient... ifelse show-cells? [st] [ht] end to recolor let pale distancexy 0 0 set color scale-color red pale 50 -10 end to recolor-mosaics let center distancexy 0 0 set color scale-color 101 center 50 -10 end to increment-clock ; turtle procedure set clock (clock + 1) if clock = cycle-length [ set clock 0 ] end to set-boundaries if pcolor = grey [set chemical chemical * 0] end to-report crowding report count turtles in-radius 1 end to kill-crowd if crowding > 10 [ die ] end to rechemical if (clock < threshold) [ set chemical chemical + chemical-concentration * (1 / sqrt distancexy 0 0) ] end to check ask n-of 30 stemcells with [ color = 101 ] [ hatch-mosaics 1 [ initialize-mosaic let center distancexy 0 0 set color scale-color 101 center 50 -10 facexy 0 0 rt random 90 lt random 90 fd ((1 / 3) * (1 / sqrt distancexy 0 0)) ] ] diffuse chemical 1 end to turn-toward-chemical ;; turtle procedure ;; examine the patch ahead of you and two nearby patches; ;; turn in the direction of greatest chemical let ahead 0 let myright 0 let myleft 0 let sniffed-patch patch-ahead sniff-distance if sniffed-patch != nobody [ set ahead [chemical] of sniffed-patch ] set sniffed-patch patch-right-and-ahead sniff-angle sniff-distance if sniffed-patch != nobody [ set myright [chemical] of sniffed-patch ] set sniffed-patch patch-left-and-ahead sniff-angle sniff-distance if sniffed-patch != nobody [ set myleft [chemical] of sniffed-patch ] ifelse (myright >= ahead) and (myright >= myleft) [ rt sniff-angle ] [ if myleft >= ahead [ lt sniff-angle ] ] end to turn-toward-value ;; turtle procedure ;; examine the patch ahead of you and two nearby patches; ;; turn in the direction of greatest chemical let ahead 0 let myright 0 let myleft 0 let sniffed-patch patch-ahead 1 if sniffed-patch != nobody [ set ahead [value] of sniffed-patch ] set sniffed-patch patch-right-and-ahead sniff-angle sniff-distance if sniffed-patch != nobody [ set myright [value] of sniffed-patch ] set sniffed-patch patch-left-and-ahead sniff-angle sniff-distance if sniffed-patch != nobody [ set myleft [value] of sniffed-patch ] ifelse (myright >= ahead) and (myright >= myleft) [ rt sniff-angle / 2 ] [ if myleft >= ahead [ lt sniff-angle / 2 ] ] end to update-plots set-current-plot "total-cell-clusters" set-current-plot-pen "mosaics" plot count mosaics set-current-plot-pen "pacemakers" plot count pacemakers end to draw-frame let num-drawers parallels let polygon-num-sides 60 create-drawers num-drawers [ set heading 90 set color white ] let i 0 foreach sort drawers [ ask ? [ set ycor scale-it i ] set i i + 1 ] ask drawers [ pd ] ask drawers [ set amount-to-move 2 * distancexy 0 0 * (tan ((360 / polygon-num-sides) / 2)) ] ask drawers [ back amount-to-move / 2 ] ask drawers [ repeat polygon-num-sides [ fd amount-to-move rt 360 / polygon-num-sides ] ] create-ordered-liners meridians [fd 3] ask liners [pd set color white] ask liners [fd radius - 2] ask liners [die] ask drawers [ die ] end to draw-square-frame let num-drawers 2 * parallels create-drawers num-drawers [ set heading 90 set color white ] let i 0 - parallels foreach sort drawers [ ask ? [ set ycor scale-it i ] set i i + 1 ] ask drawers [ pd bk 100 fd 100 ] ask drawers [ set heading 0 ] set i 0 - parallels foreach sort drawers [ ask ? [ set xcor scale-it i ] set i i + 1 ] ask drawers [ pd bk 100 fd 100 ] ask drawers [die] end to-report scale-it [ i ] report radius * sin (90 * i / parallels) end to-report inverse-scale-it [ x ] report asin (x / radius) * parallels / 90 end to-report get-fractal-boxes-list let boxlist [] ask turtles [ if (distancexy 0 0 < radius - 0.5) [ let myposition (list (floor inverse-scale-it xcor) (floor inverse-scale-it ycor)) set boxlist fput myposition boxlist ; to check more points on the leaf (instead of just the center, as above), you can add more ; points to the boxlist, with offsets from the xcor and ycor set myposition (list (floor inverse-scale-it xcor) (floor inverse-scale-it (ycor + 0.5))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.5)) (floor inverse-scale-it (ycor + 0.5))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.5)) (floor inverse-scale-it (ycor + 0.5))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.5)) (floor inverse-scale-it (ycor - 0.5))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.5)) (floor inverse-scale-it (ycor - 0.5))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it xcor) (floor inverse-scale-it (ycor + 0.25))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.25)) (floor inverse-scale-it (ycor + 0.25))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.25)) (floor inverse-scale-it (ycor + 0.25))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.25)) (floor inverse-scale-it (ycor - 0.25))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.25)) (floor inverse-scale-it (ycor - 0.25))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it xcor) (floor inverse-scale-it (ycor + 0.1))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.1)) (floor inverse-scale-it (ycor + 0.1))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.1)) (floor inverse-scale-it (ycor + 0.1))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor + 0.1)) (floor inverse-scale-it (ycor - 0.1))) set boxlist fput myposition boxlist set myposition (list (floor inverse-scale-it (xcor - 0.1)) (floor inverse-scale-it (ycor - 0.1))) set boxlist fput myposition boxlist ] ] report (remove-duplicates boxlist) end to-report count-boxes let oldboxlist get-fractal-boxes-list let newboxlist [] foreach oldboxlist [ let myx first ? let myy last ? let neighborcount 0 foreach [ -1 0 1 ] [ let xchange ? foreach [ -1 0 1 ] [ let ychange ? if member? (list (myx + xchange) (myy + ychange)) oldboxlist [ set neighborcount neighborcount + 1 ] ] ] ;print (word ? " has " neighborcount " neighbors") if (neighborcount != 9) [ set newboxlist fput ? newboxlist ] ] report length newboxlist end to clear-frame clear-drawing end