extensions [ matrix csv] globals [ relatedness-matrix patch-choice-list next-gen gene-number pTs pTns pNT ;;proportion of selective, non-selective and non-teaching alleles in population number-of-new-alleles background-alleles available-matrix-numbers current-sim gens initial-pTs initial-pTns initial-pNT initial-nTsTeachers initial-nTnsTeachers pTs-list pTns-list pNT-list nTsTeachers nTnsTeachers dataset ;;interface variables number-of-iterations turtle-number number-of-subgroups number-of-options number-of-food-patch-types asocial-learning-probability social-learning-probability selective-teaching non-selective-teaching seeded? initial-selective-freq initial-non-selective-freq initial-non-teaching-freq dominant second-dominant recessive number-of-generations generation-time stop-at-generation kin-follow-preference only-follow-parent-offspring following-radius following-probability deciding-time feeding-time food-patch-distribution food-patch-radius food-patch-bias food-patch-cover ] turtles-own [ last-turn subgroup matrix-number generation energy my-learned-actions current-action teaching-alleles teaching-phenotype following? exploring? deciding? time-deciding feeding? time-feeding know-location? ] directed-link-breed [follow-links follow-link] directed-link-breed [parent-offspring-links parent-offspring-link] undirected-link-breed [sibling-links sibling-link] patches-own [ food-patch? correct-feeding-action ] to restart clear-all set current-sim 1 set gens ["end generation"] set initial-pTs ["initial pTs"] set initial-pTns ["initial pTns"] set initial-pNT ["initial-pNT"] set initial-nTsTeachers ["initial selective teacher count"] set initial-nTnsTeachers ["initial non-selective teacher count"] set pTs-list ["end pTs"] set pTns-list ["end pTns"] set pNT-list ["end pNT"] set nTsTeachers ["end selective teacher count"] set nTnsTeachers ["end non-selective teacher count"] set dataset [] setup-interface-variables setup end to setup-interface-variables set number-of-iterations 1000 set turtle-number 60 set number-of-subgroups 1 set number-of-options 10 set number-of-food-patch-types 10 set asocial-learning-probability 0.5 set social-learning-probability 0.5 set selective-teaching 0.2 set non-selective-teaching 0 set seeded? "unseeded" ;;can be "unseeded", ""seeded with one informed individual" or "seeded with one informed per subgroup" set initial-selective-freq 0.15 set initial-non-selective-freq 0 set initial-non-teaching-freq 0.85 set dominant "Ts" ;;dominant, second-dominant and recessive can be set to "Ts" (selective-teaching), "Tns" (non-selective teaching) or "NT" (non-teaching) set second-dominant "Tns" set recessive "NT" set number-of-generations 2 set generation-time 2000 set stop-at-generation 100 set kin-follow-preference 0 set only-follow-parent-offspring? true ;;true or false set following-radius 10 set following-probability 0.5 set deciding-time 2 set feeding-time 10 set food-patch-distribution "scattered" ;;can be either "scattered" or "clustered" set food-patch-radius 5 ;;only has an effect with a "clustered" food patch distribution set food-patch-bias 0 ;;percentage - only has an effect with a "clustered" food patch distribution set food-patch-cover 6 ;;percentage - only has an effect with a "scattered" food patch distribution end to setup clear-ticks clear-turtles clear-patches clear-drawing clear-all-plots clear-output ;;all except clear globals reset-ticks ;;reset all globals apart from the pTs list etc set next-gen 0 set gene-number 0 set number-of-new-alleles 0 set background-alleles [] set relatedness-matrix matrix:make-identity turtle-number set pTs initial-selective-freq set pTns initial-non-selective-freq set pNT initial-non-teaching-freq set available-matrix-numbers n-values turtle-number [ ?1 -> ?1 ] ;; lists 0, 1, 2, 3 .... n setup-patches setup-food-patches setup-turtles ask sibling-links [hide-link] ask parent-offspring-links [hide-link] calculate-gene-frequencies set initial-pTs lput pTs initial-pTs set initial-pTns lput pTns initial-pTns set initial-pNT lput pNT initial-pNT set initial-nTsTeachers lput count turtles with [teaching-phenotype = "Ts"] initial-nTsTeachers set initial-nTnsTeachers lput count turtles with [teaching-phenotype = "Tns"] initial-nTnsTeachers end to setup-patches clear-patches ask patches [set pcolor green + 3 set food-patch? false set correct-feeding-action "n/a" ] end to setup-food-patches ;;;set up food patch distribution - clustered or scattered;;; set patch-choice-list [] while [length patch-choice-list < number-of-food-patch-types][ set patch-choice-list n-values number-of-food-patch-types [random number-of-options + 1] ;;ensures it starts at 1 and not 0, as non-food patches will have 0 set patch-choice-list remove-duplicates patch-choice-list] ; show patch-choice-list if food-patch-distribution = "clustered" [ let distance-from-edge food-patch-radius + 1 ask patches with [pycor = (max-pycor - distance-from-edge) and pxcor = (min-pxcor + distance-from-edge)][ set food-patch? true set pcolor brown + 1 ask patches in-radius food-patch-radius [ set food-patch? true set correct-feeding-action one-of patch-choice-list set pcolor brown + 1]] ] if food-patch-distribution = "scattered" [ let food-patch-number ((count patches / 100) * food-patch-cover) ask n-of food-patch-number patches [ set food-patch? true set correct-feeding-action one-of patch-choice-list set pcolor brown + 1] ] end to setup-turtles let subgroup-list n-values number-of-subgroups [ ?1 -> ?1 + 1 ] ;;;;; lists 1, 2, 3, 4, etc etc let number-per-subgroup turtle-number / number-of-subgroups let generation-list n-values number-of-generations [ ?1 -> ?1 + 1 ] set generation-list but-first generation-list ;gen 1 made seperately let number-per-generation turtle-number / number-of-generations let number-per-generation-per-subgroup number-per-generation / number-of-subgroups foreach subgroup-list [ ?1 -> ask patch 10 0 [ sprout number-per-generation-per-subgroup [ set color red set last-turn "right" set exploring? false set deciding? false set feeding? false set my-learned-actions [] set current-action "" set following? false set teaching-alleles [] set teaching-phenotype "" set know-location? false set subgroup ?1 set generation 1 set energy 0 let my-matrix-number min available-matrix-numbers set matrix-number my-matrix-number set available-matrix-numbers remove my-matrix-number available-matrix-numbers ]] ask turtles with [subgroup = ?1][ create-sibling-links-with other turtles with [subgroup = ?1] let siblings [who] of sibling-link-neighbors let my-matrix-number [matrix-number] of self foreach siblings [ ??1 -> let current-matrix-number [matrix-number] of turtle ??1 matrix:set relatedness-matrix my-matrix-number current-matrix-number 0.25 matrix:set relatedness-matrix current-matrix-number my-matrix-number 0.25 ] ] ] repeat round (initial-selective-freq * count turtles) [ ask one-of turtles with [length teaching-alleles < 2][ set teaching-alleles lput "Ts" teaching-alleles]] repeat round (initial-non-selective-freq * count turtles) [ ask one-of turtles with [length teaching-alleles < 2][ set teaching-alleles lput "Tns" teaching-alleles]] ask turtles with [length teaching-alleles < 2][ while [length teaching-alleles < 2][ set teaching-alleles lput "NT" teaching-alleles]] ;;;;calculate initial turtle's alleles from initial allele frequencies;;;; set number-of-new-alleles (count turtles * 2) calculate-background-alleles ask turtles [ set-alleles-from-background] set number-of-new-alleles (turtle-number - count turtles) calculate-background-alleles foreach subgroup-list [ ?1 -> let current-subgroup ?1 foreach generation-list [ ??1 -> let current-generation ??1 set next-gen ??1 let these-turtles [who] of turtles with [subgroup = current-subgroup and generation = current-generation - 1] foreach these-turtles [ ???1 -> ask turtle ???1 [spawn] ] ;;;Control code: Ensures population = turtle-number even if it doesn't divide equally between subgroups or generations;;; while [count turtles with [subgroup = current-subgroup and generation = current-generation] <= (number-per-generation-per-subgroup - 1)] ;;;minus 1 because it will run the code one more time before stopping [ ask one-of turtles with [subgroup = current-subgroup and generation = (current-generation - 1)] [spawn] ] ] while [count turtles with [subgroup = current-subgroup] <= number-per-subgroup - 1][ ask one-of turtles with [subgroup = current-subgroup and generation < number-of-generations][ spawn]] ] while [count turtles < turtle-number] [ ask one-of turtles with [generation < number-of-generations][ spawn] ] set next-gen max [generation] of turtles + 1 ask sibling-links [hide-link] ask parent-offspring-links [hide-link] ask turtles [ calculate-phenotype ] ;;seeding - one individual becomes knowledged of ALL possible food patch options - i.e. can instantly feed anywhere. if seeded? = "seeded with one informed individual" [ ask one-of turtles [ set my-learned-actions patch-choice-list]] if seeded? = "seeded with one informed per subgroup" [ foreach subgroup-list [ ?1 -> ask one-of turtles with [subgroup = ?1] [ set my-learned-actions patch-choice-list] ]] ask parent-offspring-links [hide-link] ask sibling-links [hide-link] end to spawn ;turtle procedure let mothers-other-children out-parent-offspring-link-neighbors hatch 1 [ create-parent-offspring-link-from myself if any? mothers-other-children [create-sibling-links-with mothers-other-children] set teaching-alleles [] set teaching-phenotype "n/a" set generation next-gen set exploring? false set deciding? false set feeding? false set my-learned-actions [] set current-action "" set following? false set teaching-alleles [] set teaching-phenotype "n/a" set know-location? false set energy 0 let my-matrix-number min available-matrix-numbers set matrix-number my-matrix-number set available-matrix-numbers remove my-matrix-number available-matrix-numbers ;;;;; genetics ;;;;; set teaching-alleles lput (one-of [teaching-alleles] of myself) teaching-alleles ;;first allele = one of mother's (myself = the turtle doing the spawning) set-alleles-from-background ;; second allele, from the background frequencies update-relatedness-matrix calculate-phenotype ] end to setup-relatedness-matrix ;;;slightly different for the beginning set relatedness-matrix matrix:make-identity count turtles end to update-relatedness-matrix let my-matrix-number [matrix-number] of self let mother [matrix-number] of one-of in-parent-offspring-link-neighbors let all-turtles [matrix-number] of other turtles let my-relatedness-list n-values turtle-number [0] set my-relatedness-list replace-item my-matrix-number my-relatedness-list 1 if any? in-parent-offspring-link-neighbors [ set my-relatedness-list replace-item mother my-relatedness-list 0.5 foreach all-turtles [ ?1 -> let current-turtle ?1 if ?1 != mother [ let turtle-relatedness-to-parent matrix:get relatedness-matrix mother current-turtle let relatedness-to-me (0.5 * turtle-relatedness-to-parent) set my-relatedness-list replace-item current-turtle my-relatedness-list relatedness-to-me ] ] matrix:set-row relatedness-matrix my-matrix-number my-relatedness-list matrix:set-column relatedness-matrix my-matrix-number my-relatedness-list ] end to calculate-background-alleles ;;;observer procedure let background-allele-number number-of-new-alleles ;;;i.e. one for each newly-spawned turtle set background-alleles [] repeat (round (pTs * background-allele-number)) [set background-alleles lput "Ts" background-alleles] repeat (round (pTns * background-allele-number)) [set background-alleles lput "Tns" background-alleles] repeat (round (pNT * background-allele-number)) [set background-alleles lput "NT" background-alleles] while [length background-alleles < background-allele-number] [ set background-alleles lput one-of [teaching-alleles] of one-of turtles background-alleles] ;;; creates list of male alleles with set frequencies ;;; if numbers don't divide equally and there ends up not being enough, adds a random allele to the list until there is enough to distribute between new turtles end to set-alleles-from-background ;;turtle procedure while [length teaching-alleles < 2] [ let selected-allele one-of background-alleles let allele-position position selected-allele background-alleles set teaching-alleles lput selected-allele teaching-alleles set background-alleles remove-item allele-position background-alleles ] ;;takes one allele from paternal background population, adds to new turtle, removes from background population record. end to calculate-phenotype ifelse member? dominant teaching-alleles [set teaching-phenotype dominant] [ifelse member? second-dominant teaching-alleles [set teaching-phenotype second-dominant] [set teaching-phenotype recessive]] if teaching-phenotype = "Tns" [ set shape "non-selective-teacher"] if teaching-phenotype = "Ts" [ set shape "selective-teacher"] if teaching-phenotype = "NT" [ set shape "default"] end to calculate-gene-frequencies set gene-number ( turtle-number * 2 ) let nTs (( count turtles with [item 0 teaching-alleles = "Ts"]) + (count turtles with [item 1 teaching-alleles = "Ts"])) let nTn (( count turtles with [item 0 teaching-alleles = "Tns"]) + (count turtles with [item 1 teaching-alleles = "Tns"])) let nNT (( count turtles with [item 0 teaching-alleles = "NT"]) + (count turtles with [item 1 teaching-alleles = "NT"])) set pTs (nTs / gene-number) set pTns (nTn / gene-number) set pNT (nNT / gene-number) end to go tick ;;When a generation is up, oldest generation dies, youngest generation produces the next, based on energy values;; if remainder ticks generation-time = 0 [ let min-gen min [generation] of turtles let max-gen max [generation] of turtles ;; only work out breeders if someone has managed to gain energy, otherwise skip this and wait until another generation has passed if sum [energy] of turtles with [generation = max [generation] of turtles] > 0 and length remove-duplicates [energy] of turtles with [generation = min-gen + 1]> 1[ ask turtles with [generation = min-gen] [ set available-matrix-numbers lput [matrix-number] of self available-matrix-numbers die]] set number-of-new-alleles (turtle-number - count turtles) set background-alleles [] let breeding-turtles turtles with [generation = min-gen + 1] let breeders [who] of turtles with [generation = min-gen + 1] let current-breeding-turtles [] if sum [energy] of turtles with [generation = max [generation] of turtles] > 0 and length remove-duplicates [energy] of turtles with [generation = min-gen + 1] > 1[ while [length current-breeding-turtles < number-of-new-alleles][ let breeders-sublist breeders ;;reset let sum-Ej 0 let looping? true foreach breeders [ ?1 -> if count turtles < turtle-number and looping? [ let Ei [energy] of turtle ?1 set sum-Ej Ei set breeders-sublist butfirst breeders-sublist foreach breeders-sublist [ ??1 -> let Ej [energy] of turtle ??1 set sum-Ej sum-Ej + Ej ] if sum-Ej > 0 [ ;;stops the error of dividing by 0 if turtle hasn't had a chance to gain any energy if random 100 < (Ei / sum-Ej) * 100 [set current-breeding-turtles lput ?1 current-breeding-turtles set looping? false ]] ] ]]] foreach current-breeding-turtles [ ?1 -> set background-alleles lput item 0 [teaching-alleles] of turtle ?1 background-alleles set background-alleles lput item 1 [teaching-alleles] of turtle ?1 background-alleles ] ;creates paternal allele frequencies based on 'successful' maternal breeders ;if one maternal breeder produces 2 offspring based on energy values, its alleles are added 2 times, etc. foreach current-breeding-turtles [ ?1 -> ask turtle ?1 [spawn] ] set next-gen max [generation] of turtles + 1 calculate-gene-frequencies ask parent-offspring-links [hide-link] ask sibling-links [hide-link] ] ;;;;turtle actions;;;; follow-procedure move-turtles food-patch-actions ;;;;;RESET AND STOP PROCEDURES;;;;; ;sets up the next iteration when the last gen is reached or one allele reaches fixation ;stops the simulation when at the end of the last iteration if any? turtles with [generation = stop-at-generation or pTs = 1 or pNT = 1 or pTns = 1] [ set gens lput max [generation] of turtles gens set pTs-list lput pTs pTs-list set pTns-list lput pTns pTns-list set pNT-list lput pNT pNT-list set nTsTeachers lput count turtles with [teaching-phenotype = "Ts"] nTsTeachers set nTnsTeachers lput count turtles with [teaching-phenotype = "Tns"] nTnsTeachers ifelse current-sim < number-of-iterations [ set current-sim current-sim + 1 setup] ;;else [if current-sim >= number-of-iterations[ set dataset (list gens initial-pTs pTs-list initial-pTns pTns-list initial-pNT pNT-list initial-nTsTeachers nTsTeachers initial-nTnsTeachers nTnsTeachers) let file-name "" ;;file name set to include changed variables to avoid overwriting of files ;;change file names as appropriate if only-follow-parent-offspring? = false [ set file-name (word "Ts-" selective-teaching "-Kf-" kin-follow-preference "-SOC-" social-learning-probability "-ASOC-" asocial-learning-probability ".csv") ] if only-follow-parent-offspring? = true [ set file-name (word "Ts-" selective-teaching "-Only-0.5-follow--SOC-" social-learning-probability "-ASOC-" asocial-learning-probability ".csv") ] ; csv:to-file (word "C:/PathName/" file-name) dataset ;;;Insert own pathway here stop ]]] end to move-turtles ask turtles [ if not feeding? and not deciding? [ ;;; stop on patch if feeding / deciding ;;;;turn at edge of world;;;; if xcor >= max-pxcor or xcor <= min-pxcor [ set heading heading + 45 ] if ycor >= max-pycor or ycor <= min-pycor [ set heading heading + 45 ] ;;;;move around world - when not following;;;; if not food-patch? [ if know-location? = true [ ;;will only be true if food patch is clustered and turtle has visited it before if random 100 < food-patch-bias [ let food-heading towards min-one-of patches with [food-patch?] [distance myself] let heading-difference subtract-headings food-heading heading let bias-proportion (food-patch-bias / 100) set heading heading + ((heading-difference / 10) * (bias-proportion)) ;; heading-difference = difference between turtle's current heading and if it was facing nearest food patch ]]] if not following? [ ifelse not exploring? ;;normal movement;; [ifelse last-turn = "right" ;;based on last turn, to give momentum of movement [ifelse random 100 > 25 [rt random 10 fd 0.5 set last-turn "right" ] [lt random 10 fd 0.5 set last-turn "left" ] ] [ifelse random 100 > 25 [lt random 10 fd 0.5 set last-turn "left" ] [rt random 10 fd 0.5 set last-turn "right" ] ]] ;;foraging movement - moves slower when exploring on large clustered food patch [ifelse random 100 < 50 [rt random 10 fd 0.2] [lt random 10 fd 0.2] ] ] ;;;;following procedure;;;; if any? out-follow-link-neighbors [ let leaders out-follow-link-neighbors if following? = true and not any? leaders in-radius 0.5[ ;;tells a follower to follow its outgoing link, as long as it isn't feeding etc set heading towards one-of leaders fd 0.5] ]] ] end to food-patch-actions ask turtles [ if food-patch-distribution = "clustered" [ if food-patch? = true and not deciding? and not feeding? [ set exploring? true if know-location? != true and food-patch-bias > 0[ set know-location? true ; set color red - 3.5 ] ;;learn location of food patch if you've found it once ]] if food-patch-distribution = "scattered" [ let current-patch list pxcor pycor if food-patch? = true and not feeding? [ set deciding? true]] ;;explore the large food patch if clustered, if scattered just eat from this patch ] ;;;;decide after exploratory phase;;;; ask turtles [ if exploring? = true [ ifelse following? = true and any? out-follow-link-neighbors [if member? (one-of out-follow-link-neighbors) (other turtles-here) [ set deciding? true set exploring? false ;decide when you reach patch your leader is on ]] [if random 10 < 4 [ set deciding? true set exploring? false ]] ]] ;;;DECIDING;;; ask turtles [ if deciding? = true [ ifelse time-deciding >= deciding-time [ make-choice set time-deciding 0] [set time-deciding time-deciding + 1] ]] ;;;;FEEDING;;; ask turtles [ if feeding? = true [ ;;;i.e. if "make-choice" said it should feed;;; ifelse time-feeding >= feeding-time [ feed set time-feeding 0] [set time-feeding time-feeding + 1] ]] end to follow-procedure ;;;;decide to FOLLOW at a given probability;;; ask turtles [ if random 100 > 90 [ ;;change following status at a given probability set following? false ask my-out-follow-links [die] ;;reset if random 100 < following-probability * 100 [set following? true] if following? = true[ let my-matrix-number [matrix-number] of self let potential-leaders other turtles in-radius following-radius with [following? = false] let potential-leader-numbers [matrix-number] of potential-leaders let leader-sublist potential-leader-numbers ifelse any? potential-leaders [ if not any? my-out-follow-links[ ;;;;;;; prevents a turtle creating >1 link and following >1 turtles at same time foreach potential-leader-numbers [ ?1 -> if not any? my-out-follow-links[ let first-turtle ?1 let relatedness-i matrix:get relatedness-matrix ?1 my-matrix-number let wi 0 if only-follow-parent-offspring? = false [ set wi 1 + (2 * kin-follow-preference * relatedness-i) ] if only-follow-parent-offspring? = true [ if relatedness-i = 0.5 [ set wi 2]] let sum-wj wi ;;;i.e. adding first turtles weighting to start with set leader-sublist but-first leader-sublist foreach leader-sublist[ ??1 -> let relatedness-j matrix:get relatedness-matrix ??1 my-matrix-number let wj 0 if only-follow-parent-offspring? = false [ set wj 1 + (2 * kin-follow-preference * relatedness-j)] if only-follow-parent-offspring? = true [ if relatedness-j = 0.5 [ set wj 2]] set sum-wj sum-wj + wj ] ifelse sum-wj > 0 [if random 100 < (wi / sum-wj) * 100 [ create-follow-link-to one-of turtles with [matrix-number = ?1] ask follow-links [hide-link] ]] ;else [set following? false] ] ]]] ;else (no potential leaders - i.e. no turtles nearby) [set following? false] ] ] ] end ;;;~~feeding and learning related~~;;; to make-choice ;;turtle procedure ;;;social learning if informed turtles, asocial if not if food-patch? = true [ ifelse not member? correct-feeding-action my-learned-actions [ ;; i.e. if not informed about this action let informed-feeders other turtles-here with [current-action = correct-feeding-action and feeding? = true] ; same patch or given radius? let my-subgroup [subgroup] of self let my-matrix-number [matrix-number] of self let same-subgroup-feeders informed-feeders with [subgroup = my-subgroup] let other-subgroup-feeders informed-feeders with [subgroup != my-subgroup] let my-phenotype [teaching-phenotype] of self ifelse any? informed-feeders [ let informed-feeder-numbers [who] of informed-feeders let s social-learning-probability let Tns non-selective-teaching let Ts selective-teaching let prob-learning 0 foreach informed-feeder-numbers [ ?1 -> let current-matrix [matrix-number] of turtle ?1 let relatedness matrix:get relatedness-matrix my-matrix-number current-matrix if current-action != correct-feeding-action [ let current-turtle turtle ?1 let current-matrix-number [matrix-number] of current-turtle let r matrix:get relatedness-matrix current-matrix-number my-matrix-number if [teaching-phenotype] of current-turtle = "NT" [ set prob-learning s ] if [teaching-phenotype] of current-turtle = "Tns" [ set prob-learning (s + (( 1 - s ) * Tns )) ] if [teaching-phenotype] of current-turtle = "Ts" [ set prob-learning (s + (( 1 - s ) * 2 * Ts * r )) ] if random 100 < prob-learning * 100 [ set current-action [current-action] of current-turtle ]] ] if current-action != correct-feeding-action [ if random 100 < (asocial-learning-probability * 100) [ set current-action random number-of-options + 1 ] ] ] [if random 100 < (asocial-learning-probability * 100) [ set current-action random number-of-options + 1 ]] ;; if no informed feeders here, try to learn asocially ;;;;;;;; + 1 to fit in with the food patch options, which start at 1 and not 0 ifelse current-action = correct-feeding-action [set feeding? true set deciding? false set my-learned-actions lput current-action my-learned-actions ;;;adds this action to its repetoire if it allowed the turtle to feed ] [set deciding? false set feeding? false set current-action ""] ] ;;all within uninformed bracket ;;;else (already learned this action) [ set current-action correct-feeding-action set feeding? true set deciding? false ] ] if not food-patch? [ set deciding? false set feeding? false set current-action ""] ;;prevents choices still being made if turtle has moved off food patch (e.g. if it starts returninf home) end to feed ;;; turtle procedure set energy energy + 10 set deciding? false set feeding? false end