2

A social network of agents of different ages is set up in NetLogo similarly to the following, which results in a circle of agents connected by links. The overall purpose of these links is to represent contact between those links. The model simulates the spread of infection through the network. Agents begin as susceptible, with the possibility of becoming infected if they come into contact with an infectious link neighbour. I want to model for example the isolation or quarantine of an infected individual. i.e. their links to others would be deactivated completely or at least the majority of their links would be deactivated. Ideally I'd press a button on the observer interface to deactivate the links of infected agents. I'd also like to be able to model the closure of a school for instance whereby the majority of toddlers and children and their connections between each other would be deactivated, stopping the ability of infection between children. Their links to adults should probably remain open if fewer of them, though it may be better to just focus on links between one breed at a time for now.

breed [ toddlers toddler ]
breed [ children child ]
breed [ adults adult ]
breed [ over45s over45 ]

globals
[
  num-nodes
  num-infected
  num-susceptible  
  prob-infection-toddler
  prob-infection-child
  prob-infection-adult
  prob-infection-over45
  force-of-infection 
]

turtles-own
[
  temp-infected?    ;; temporary infected state
  infected?         ;; true if agent has been infected
  susceptible?
  num-infected-neighbors
]

links-own
[
 closed? 
]


to setup
  clear-all
  create-toddlers 20
  create-children 20
  create-adults 20
  create-over45s 20
  create-network
  reset-ticks
  layout-circle (sort turtles) max-pxcor - 8
  ask turtles
  [
     facexy 0 0
     if who mod 2 = 0 [fd 4]
  ]
  ask turtles
    [set susceptible? true]

  ask one-of turtles
  [
    set infected? true
    set susceptible? false
    set color red
  ]
  display
end

to create-network

  let connexions (list
    (list toddlers toddlers 5)
    (list toddlers children 2)
    (list toddlers adults 2)
    (list toddlers over45s 1)
    (list children toddlers 3)
    (list children children 8)
    (list children adults 5)
    (list children over45s 1)
    (list adults toddlers 1)
    (list adults children 3)
    (list adults adults 6)
    (list adults over45s 3)
    (list over45s toddlers 1)
    (list over45s children 1)
    (list over45s adults 5)
    (list over45s over45s 5)
  )

  foreach connexions [
    let source-breed item 0 ?
    let target-breed item 1 ?
    let num-connexions item 2 ?
    let reverse-num-connexions item 2 first filter [
      item 0 ? = target-breed and item 1 ? = source-breed
    ] connexions
    ask source-breed [
      repeat num-connexions [
        let possible-targets other target-breed with [
          (not member? myself link-neighbors) and
          (count link-neighbors with [ breed = source-breed ] < reverse-num-connexions)
        ]
        let target one-of possible-targets
        if target != nobody [ create-link-with target ]
      ]
    ]
  ]

  ask links [set closed? false]
end

to spread
  ;;; there is one of these for each age group as they have different probabilities for infection
  ask toddlers with [ susceptible? = true ]
    [

   ;;tried changing to something like this but this is the line that throws up an error  
   ask my-links with [closed? = false][
       set num-infected-neighbors count (link-neighbors with [infected? = true])
   ]
   ;;should only include active links
   set force-of-infection (prob-infection-toddler) ^ num-infected-neighbors ;;paraphrased equation but num-infected-neigbours is important

   if ( random-float 1 <= force-of-infection)  ;; infect with probability p
     [

            set temp-infected? true
            set susceptible? false

     ]
 ]
   ask turtles with [temp-infected? = true]
    [
      set infected? true
      set temp-infected? false
    ]
end

to isolate-infected
   ;;for all infected individuals deactivate their links
end


to close-schools
   ask toddlers 
   [
     ask my-links [set closed? true]
   ]

end

to close-offices
   ;; e.g cut the number of links between adults and so on
end

As you can see there are two problems here, one being the deactivation (ideally they could be turned on again once school closures are over or once an infected individual recovers for example) of links based on what state the end nodes are in or the breed that they are.

And the second problem of counting the number of infected link-neighbours without including the links which are deactivated. Hiding a link does not stop it from existing it just becomes invisible and thus doesn't stop the contact. I've also considered simply changing the color of the deactivated links to for example black. Is there a way in which I can rewrite the counting of infected neighbors to count only links that aren't black or hidden for example set num-infected-neighbors count (link-neighbors with [infected? = true]...and link hidden? = false.... or link-color "!=" black? )

I feel the second problem is probably the easier of the two but I may be mistaken. I've hit too many brick walls at this stage and my head is fried on the matter. Any help would really be greatly appreciated. Thanks for your time reading this already, I realise it was a bit of a rant :) Thanks again to Nicolas Payette for his help previously

EDIT: Added links-own boolean for closed?

Tried to alter the section which counts the number of infected neighbours on open links but I get the error this code can't be run by a link error while link 14 15 running SET called by procedure SPREAD called by Button 'Spread'

Also added in a function in "to close-schools" which gives a very basic closure of all toddlers links by setting closed? to true

Edit: Would this be a possible solution here

set num-infected-neighbors 0
   ask my-links with [closed? = false][
      ask other-end [if (infected?) [set num-infected-neighbors num-infected-neighbors + 1 ]]
   ]
   set force-of-infection 1 - (1 - prob-infection-adult) ^ num-infected-neighbors

Edit: num-infected-neighbors should be a turtles-own variable as far as I can tell, but when I put a watch on a turtle and run the simulation, the num-infected-neighbors that a turtle has seems to consistently surpass the actual number of link-neighbors that the turtle has. It is also just wrong. I can't see why though....

Edit:

let infectnum 0
  set num-infected-neighbors 0
   ask my-links with [closed? = false][
      ask other-end [if (infected?) [set infectnum infectnum + 1 ]]
       ;;set num-infected-neighbors count (link-neighbors with [infected? = true])
   ]
   set num-infected-neighbors infectnum

doesn't seem to be working properly either...

Edit: For future reference problem was solved by -

set num-infected-neighbors length filter [[infected?] of ?]
                        [other-end] of my-links with [not closed?]

First a list is formed of the link-neighbors on not-closed links, then that is filtered to give just the infected ones. num-infected-neighbors is the length of that list

Steve
  • 43
  • 1
  • 7

1 Answers1

2

First some general advice: It would be better to give a minimum working example (MWE), i.e. one that's stripped down to the bare minimum to show the problem. This code has too much detail, so people are less likely to answer. Also, sometimes once you strip it down, you'll figure out the answer. This code doesn't work, either: The definitions for the global variables are missing.

You might want to take a look at "Virus on a Network" in the Models Library that comes with NetLogo. It does similar things, but using a more "NetLogoey" coding style.

You can test links for their color. i.e. you could use the fact that a link is the "deactivated" color to test whether it should be counted, or followed. A better idea would be to give the links a variable using links-own, and test that. But here is some example code (modified from a procedure in "Virus on a Network") that uses color for this purpose:

to spread-virus
  ask turtles with [infected?]
    [ ask my-links with [color != red]
      [ask other-end
        [ if (not resistant?) and (random-float 100 < virus-spread-chance)
            [ become-infected ] ] ] ]
end

The trick is that rather than looking directly at link-neighbors, I ask each turtle for its my-links, then test their colors. Then for each link that passes the test, I ask it for its other-end, i.e. the turtle that is not the turtle that found the link via my-links. Then the virus is transmitted to that turtle--but only if the link had not been disabled. (I think this code works right--seems to. But you should test it thoroughly if you do something like this.) Counting disabled or non-disabled links using my-links should be even easier. For isolate-infected you can do something like ask turtles with [infected?] [ask my-links [set color/deactivated/etc. ]]. Haven't tested that.

For the new error in the edited version in response to my answer, I think the problem might be this code:

ask my-links with [closed? = false][
  set num-infected-neighbors count (link-neighbors with [infected? = true])
]

This asks some links to run the procedure link-neighbors, but that procedure is only designed to be run by turtles. (In NetLogo, certain procedures are only to be designed to be run "by an agent", e.g. within braces after ask .... However, some of these procedures only work in turtle agents, and others only work in link agents.) You probably should use other-end, which is a procedure designed to be run by a link. (It's kind of a funny procedure, though, because it's only designed to be run by a link when the ask command that's asking the link to run other-end, was an ask invoked by a turtle. So other-end only works if you've got something like ask turtle 1 [ask mylinks [ ... other-end ...]].)

(It is possible to reference an agent inside another agent that the first agent asked. For one level of this, you can use myself. For additional levels of asks, you can define variables at the outer levels and then reference them in the inner levels.)

Mars
  • 8,689
  • 2
  • 42
  • 70
  • Thanks for your inout, believe it or not this is much less code than my actual implementation. I tried to strip it down but didn't want to leave out valuable information at the same time. I mistakenly left out global variables. – Steve Aug 22 '13 at 10:29
  • With regards to the spread, the formula I've been using requires me to count the number of infectious neighbours which the turtle has. I've edited my code to show something I've tried but it gives me an error saying "this code can't be run by a link error while link 11 12 running SET called by procedure SPREAD called by Button 'Spread'" – Steve Aug 22 '13 at 10:47
  • 1
    About simplifying, I understand. It's hard to figure out what might be important to the question. Given the question, I don't think you need all of the different breeds, though. – Mars Aug 22 '13 at 15:31
  • Yeah it might have been a bit much, sorry 'bout that. That is indeed the problem code. I figured that it couldn't be run Any ideas of a way around this problem. Getting the sum of infected link nighbours on links that aren't closed? Edit: I just saw your last edit now, I'm not quite sure what you mean – Steve Aug 22 '13 at 16:00
  • 1
    Let me know whether the additional clarification I just added helps. Also look again at what I did in the first bit of example code that I posted. You might want to compare it with the original definition of `spread-virus` in "Virus on a Network" in the Models Library. Do you understand what I did with `my-links` and `other-end`? If not, that's OK, but help me understand what's not clear. Don't worry about my parenthetical remark about `myself` at this point. It was just extra information. – Mars Aug 22 '13 at 16:32
  • Doesn't run without adding something like `ask turtles [set infected? false]` to setup, but other than that looks OK to me. Oh, wait. When you `ask` `other-end`, the `num-infected-neighbors` variable is the `other-end`'s, but that's not the one you're trying to increment. This is where that stuff about `myself` might be relevant, but the quickest edit I see would be to define a local variable with value 0 in the `ask toddlers` block. Then increment that variable the `ask other-end` block. Then after the `ask my-links` block, `set num-infected-neighbors` to the value of the local variable. – Mars Aug 23 '13 at 00:51
  • I'm not sure I see how this is any different? Actually I see what you mean about it being the wrong turtle, but won't it result in the same number. I wish there was a way to just say `ask my-links with [closed? = false][set num-infected neighbors count (link-neighbors with infected?)]` I realise this isn't possible, but I'd feel a little more confident in it. How would I fix it using `myself`? Added an edit to post, is this what you meant? – Steve Aug 23 '13 at 10:31
  • That doesn't seem to be giving me accurate enough numbers. Is there any way around using the `count` function within the `ask my-links with [closed? = false]` to get the actual number – Steve Aug 23 '13 at 10:48
  • Perhaps something like this `ask my-links with [closed? = false][ ask myself [ set num-infected-neighbors count (link-neighbors with [infected? = true])] ]`? – Steve Aug 23 '13 at 15:33
  • re 3 comments back: Yes, the edit is what I had in mind. I see your point that it might seem like the old procedure should give the right result--except that in the old way of doing things, weren't you resetting the count back to 0 repeatedly?. I think the new edit should work. Maybe I'm wrong, but it could be that you have to resort to old-fashioned debugging :-) which I'm sure you're already doing. There may be some kind of debugging facility for NetLogo, but I usually just insert print statements. It could help to reduce the number of turtles, etc., of course. – Mars Aug 24 '13 at 14:02
  • As to other methods, well, this is at the boundary of my NetLogo knowledge, so I'd just have to experiment and read the docs. You could cook up a simple example and ask about alternative methods in a new SO question post. There are some real NetLogo experts who visit here sometimes, but I wouldn't expect anyone to read through this whole conversation to answer a question. – Mars Aug 24 '13 at 14:07
  • (Re `myself`: if you `ask` one agent, then in the associate code block, you can refer to that turtle as `self`. If that code `asks` another agent, in that `ask`'s code block, `myself` refers to the first turtle you `ask`'ed. Not sure what `myself` refers to if you go into a third `ask` block.) – Mars Aug 24 '13 at 14:07
  • Very nice answer. (How about a vote up, though? Don't mark my answer as the answer, of course.) – Mars Aug 27 '13 at 17:28
  • It won't allow me to vote unfortunately as its a new account and I need 15 reputation to do so. Sorry, but thanks again for all the help – Steve Aug 27 '13 at 21:29