Step 4. Add networks

1. Create cities

The model you created so far is a great Westeros start, but it is missing some key elements. Some of those are cities and road that connect them. Adding the cities and roads will allow you to analyse the importance of certain cities or houses, based on their location and their connections to other locations.

In the GIS data you downloaded, you will find a vector file that contains the position of major cities, castles, and establishments. The vector file contains a lot of different buildings, but you will filter out ruins and buildings called "others."

The first step will be to create a new breed of agents for cities, and give them their own set of variables.

breed [ humans human ]   ; add humans as a breed (plural first, then singular)

breed [ cities city ]   ; add cities as a breed

 

turtles-own [ energy ]    ; both wolves and sheep have energy

wolves-own [ domesticated? ]   ; To know if the wolf is domesticated

 

cities-own [

  city-name   ; the name of the city or castle

  city-size   ; size of the city (taken from the shapefile)

  centrality   ; will take the centrality measure of the city when we create networks with roads

]

breed [ humans human ]  

breed [ cities city ]

 

turtles-own [ energy ] 

wolves-own [ domesticated? ] 

 

cities-own [

  city-name 

  city-size

  centrality

]

2. Import cities from vector file

Now, you need to actually create those cities and place them on the landscape. The location of each city is already embedded in the Westeros_locations.shp vector file as a point, so you should create a new procedure that imports that file and asks the patches that intersect with a GIS point to sprout a new city, but ignore the points that are ruins or 'others'.

**Important: Here, we will change the location of the GIS files to follow common procedures in modeling. To do that, place your model into a folder called 'code' and your GIS data into a folder called 'data'. Both your 'code' and 'data' folders should be in the same folder. You will have to update the path to all the GIS files you imported to reflect this. To do so, simply add "../data/" before the path you already have. This tells NetLogo to look into the data folder.

The cities should record their name as well as size from the vector file. They should also take on the color of the house to which they are assigned.

The procedure created here uses a foreach loop, which might be new to you. Here, the loop iterates through each entries in the dataset (each point in the vector). The x is an anonymous variable that takes on the identify of each of the entries iterated through.

This code also uses the property-value primitive, which takes on the value of the variable identified and does so for each entry x.

To set the cities to look like castles, import the 'House' shape from this model, where we modified things a little. Overwrite the default shape.

Cities.png

to setup-world

  ; Set up a virtual world using GIS raster base maps

  let basemap gis:load-dataset "../data/Land_raster.asc"  ; Loads the GIS data to temp variable basemap

to setup-world

  

  let basemap gis:load-dataset "../data/Land_raster.asc"  

to setup-wall   ; observer procedure

  ; load the vector dataset of the wall into the temporary variable wall-basemal

  let wall-basemap gis:load-dataset "../data/Wall.shp"

to setup-wall   

  

  let wall-basemap gis:load-dataset "../data/Wall.shp"

to setup-houses   ; observer procedure

  ; load the vector dataset of houses  to the temporary houses-basemap variable

  let houses-basemap gis:load-dataset "../data/W_political_revised.shp"

to setup-houses   

  

  let houses-basemap gis:load-dataset "../data/W_political_revised.shp"

to setup-cities   ; observer procedure

  ; load the vector dataset of cities to the temporary variable

  let cities-basemap gis:load-dataset "../data/Westeros_locations.shp"

  ; ask all patches that intersect with a vector point to create a city

  ; foreach means that the code within brackets runs for each entry in the vector file (each point)

  foreach gis:feature-list-of cities-basemap [

    x -> let city-type gis:property-value x "TYPE"   ; for each entry (x), city-type becomes the "TYPE" of each x 

    if city-type != "Ruin" or city-type != "Other" [   ; filters out entries that are ruins or others

      ask patches gis:intersecting x [   ; if the entry is valid (not ruin or others), this asks patches...

        sprout-cities 1 [   ; ... intersecting its location to create one city

          if land? = false [   ; asks houses in water to move to the closest land patch

            move-to min-one-of patches with [ land? = true ][ distance myself ]

          ]

          set shape "house"     ; the city will have a house shape

          set color house-color   ; sets the color to the house-color of the patch where it stands

          set city-name gis:property-value x "NAME"   ; assigns the "NAME" from the file to the city-name variable

          set city-size gis:property-value x "SIZE"   ; assign the "SIZE" value from the file to the city-size variable

          set size city-size + 2   ; set the city size based on the "real" data

        ]

      ]

    ]

  ]

 

end

to setup-cities  

  

  let cities-basemap gis:load-dataset "../data/Westeros_locations.shp"

  

  

  foreach gis:feature-list-of cities-basemap [

    x -> let city-type gis:property-value x "TYPE"   

    if city-type != "Ruin" or city-type != "Other" [   

      ask patches gis:intersecting x [  

        sprout-cities 1 [   

          if land? = false [   

            move-to min-one-of patches with [ land? = true ][ distance myself ]

          ]

          set shape "house"    

          set color house-color   

          set city-name gis:property-value x "NAME" 

          set city-size gis:property-value x "SIZE" 

          set size city-size + 2 

        ]

      ]

    ]

  ]

 

end

to setup

  clear-all

 

  setup-world   ; call the setup-world procedure to import GIS data

  setup-wall   ; call the setup-wall procedure to import the Wall vector

  setup-houses   ; call the setup-houses procedure to identify the kingdom in which each patch falls

  setup-cities   ; call the setup-cities procedure to create cites

to setup

  clear-all

 

  setup-world   

  setup-wall  

  setup-houses  

  setup-cities 

3. Add roads

Now, let's use the major roads to connect some of the major cities. The GIS dataset you downloaded earlier already contains a vector file of lines that represent Westeros major roads. You will import this file and tell every patch intersecting with those lines to become a road.

But first, you need to add a road? variable to patches, so that they take on a different color if they are part of a road.

Then, create a new procedure that imports the GIS data and identifies which patches are roads. Do not forget to call that new procedure in setup. Road patches are then set to black and do not have resources.

patches-own [

  countdown   ; used to trigger grass regrowth

  land?  ; boolean that identifies is a cell is land

  wall?  ; boolean that identifies if the cell overlaps the wall (and thus is part of the wall)

  house   ; identifies which house owns the cell

  house-color  ; to show the extent of each house's territory

  road?  ; identify if the patch is part of a road

]

patches-own [

  countdown   

  land?  

  wall?

  house 

  house-color 

  road? 

]

to setup-roads   ; observer procedure

  ; load the vector dataset of roads to the roads-basemap temporary variable

  let roads-basemap gis:load-dataset "../data/Westeros_roads.shp"

  ; identify the patches that intersect with the roads and ask them to become roads.

  ask patches gis:intersecting roads-basemap [

    set road? true 

  ]

  

end

to setup-roads 

  

  let roads-basemap gis:load-dataset "../data/Westeros_roads.shp"

  

  ask patches gis:intersecting roads-basemap [

    set road? true 

  ]

  

end

to setup

  clear-all

 

  setup-world   ; call the setup-world procedure to import GIS data

  setup-wall   ; call the setup-wall procedure to import the Wall vector

  setup-houses   ; call the setup-houses procedure to identify the kingdom in which each patch falls

  setup-cities   ; call the setup-cities procedure to create cites

  setup-roads   ; call the setup-road procedure to create roads

 

  set land-patches patches with [ land? = true ]  ; Creates a patchset that comprises only land patches

 

  ask land-patches [   ; ask only land patches to do what's between the square brackets

    ifelse road? = true [

      set pcolor black ; roads are black and do not have resources

    ][

      set pcolor one-of [ green brown ]   ; each patch chooses a color between the two

      ifelse pcolor = green   ; if they chose green...

        [ set countdown grass-regrowth-time ]   ; they need to set their countdown for when they'll get eaten

        [ set countdown random grass-regrowth-time ]   ; initialize grass regrowth clocks randomly for brown patches

    ]

  ]

 

to setup

  clear-all

 

  setup-world 

  setup-wall 

  setup-houses 

  setup-cities 

  setup-roads 

 

  set land-patches patches with [ land? = true ]  

 

  ask land-patches [  

    ifelse road? = true [

      set pcolor black

    ][

      set pcolor one-of [ green brown ]   

      ifelse pcolor = green  

        [ set countdown grass-regrowth-time ]   

        [ set countdown random grass-regrowth-time ]  

    ]

  ]

 

3. Create a network of connected cities

You have now imported all the GIS data you need for this model, so hopefully, this gave you some practice with importing different types of GIS data into a NetLogo model.

 

Now, let's use the data we have to see which cities are well connected through main roads and which ones are not, and maybe infer the power each of them has in the game of thrones.

While you did create roads, there is no easy way to use them to connect cities, so you will need to manually create links between cities that are connected by roads. In NetLogo, links are types of turtles represented as lines with a start and an end point. Size influences their width. Links can be undirected (movement is assumed from both directions) or directed (movement is assumed to occur only from one direction. While roads should created undirected movement, you will still practice making a directed network to see how the directionality affects the network.

Behind the scenes, we have identified the list of cities to connect and their respective city-name to simplify the coding. You will use these city-names when making the networks. As this piece of code is quite long, it may be easier to simply copy and paste it in your model, but try to read through it and see that you understand what it does. In particular, make sure you see the difference between the creation of directed and undirected links.

Roads.png

to setup-undirected-network   ; observer procedure

  ; Hardcoding those temp variables so that they can be called below (shorter code below)

  let castle-black one-of cities with [ city-name = "Castle Black" ]

  let winterfell one-of cities with [ city-name = "Winterfell" ]

  let moat-cailin one-of cities with [ city-name = "Moat Cailin" ]

  let crossroad-inn one-of cities with [ city-name = "Crossroads Inn" ]

  let lannisport one-of cities with [ city-name = "Lannisport" ]

  let eyrie one-of cities with [ city-name = "The Eyrie" ]

  let kings-landing one-of cities with [ city-name = "King's Landing" ]

  let maidenpool one-of cities with [ city-name = "Maidenpool" ]

  let highgarden one-of cities with [ city-name = "Highgarden" ]

  let storms-end one-of cities with [ city-name = "Storm's End" ]

  let oldtown one-of cities with [ city-name = "Oldtown" ]

  ; These roads are an oversimplification of the roads in Westeros and focus on cities connected by the big roads only

  ask castle-black [ create-link-with winterfell ]  ; Road between Castle Black and Winterfell

  ask winterfell [ create-link-with moat-cailin ]  ; Road between Winterfell and Moat Cailin

  ask moat-cailin [ create-link-with crossroad-inn ]  ; Road between Moat Cailin to the Inn at the crossroads

  ask lannisport [ create-link-with highgarden ]  ; Road between Lannisport and Highgarden

  ask highgarden [ create-link-with oldtown ]  ; Road between Highgarden and Old Town

  ask crossroad-inn [ 

    create-link-with lannisport  ; Road between the inn and Lannisport

    create-link-with eyrie  ; Road between the inn and the Eyrie

    create-link-with kings-landing  ; Road between the inn and King's Landing

  ]

  ask kings-landing [

    create-link-with maidenpool  ; Road between King's Landing and Maidenpool

    create-link-with lannisport  ; Road between King's Landing and Lannisport

    create-link-with highgarden  ; Road between King's Landing and Highgarden

    create-link-with storms-end  ; Road between King's Landing and Storm's End

  ]

 

end

 

to setup-directed-network   ; observer procedure

  ; Hardcoding those temp variables so that they can be called below (shorter code below)

  let castle-black one-of cities with [ city-name = "Castle Black" ]

  let winterfell one-of cities with [ city-name = "Winterfell" ]

  let moat-cailin one-of cities with [ city-name = "Moat Cailin" ]

  let crossroad-inn one-of cities with [ city-name = "Crossroads Inn" ]

  let lannisport one-of cities with [ city-name = "Lannisport" ]

  let eyrie one-of cities with [ city-name = "The Eyrie" ]

  let kings-landing one-of cities with [ city-name = "King's Landing" ]

  let maidenpool one-of cities with [ city-name = "Maidenpool" ]

  let highgarden one-of cities with [ city-name = "Highgarden" ]

  let storms-end one-of cities with [ city-name = "Storm's End" ]

  let oldtown one-of cities with [ city-name = "Oldtown" ]

  ; These roads are an oversimplification of the roads in Westeros and focus on cities connected by the big roads only.

  ; For directed networks, the direction of the links is arbitrary and does not follow any ASOIAF data

  ask castle-black [ create-link-from winterfell ] ; Road to Castle Black from Winterfell (Brothers can't go back home)

  ask winterfell

  [ create-link-from moat-cailin

    create-link-to moat-cailin ]  ; Bidirectional road between Winterfell and Moat Cailin

  ask moat-cailin [ create-link-to crossroad-inn ]  ; Road from Moat Cailin to the Inn at the crossroads

  ask crossroad-inn

  [ create-link-to lannisport  ; Road from the inn to Lannisport

    create-link-from eyrie  ; Road to the inn from the Eyrie

    create-link-from kings-landing ]  ; Road to the inn from King's Landing

  ask kings-landing

  [ create-link-from maidenpool  ; Road to King's Landing from Maidenpool

    create-link-from lannisport  ; Road to King's Landing from Lannisport

    create-link-from highgarden  ; Road to King's Landing from Highgarden

    create-link-from storms-end ]  ; Road to King's Landing from Storm's End (all roads lead to King's Landing)

  ask lannisport [ create-link-to highgarden ]  ; Road from Lannisport to Highgarden

  ask highgarden [ create-link-from oldtown ]  ; Road to Highgarden from Oldtown

 

end

to setup-undirected-network   

  

  let castle-black one-of cities with [ city-name = "Castle Black" ]

  let winterfell one-of cities with [ city-name = "Winterfell" ]

  let moat-cailin one-of cities with [ city-name = "Moat Cailin" ]

  let crossroad-inn one-of cities with [ city-name = "Crossroads Inn" ]

  let lannisport one-of cities with [ city-name = "Lannisport" ]

  let eyrie one-of cities with [ city-name = "The Eyrie" ]

  let kings-landing one-of cities with [ city-name = "King's Landing" ]

  let maidenpool one-of cities with [ city-name = "Maidenpool" ]

  let highgarden one-of cities with [ city-name = "Highgarden" ]

  let storms-end one-of cities with [ city-name = "Storm's End" ]

  let oldtown one-of cities with [ city-name = "Oldtown" ]

  

  ask castle-black [ create-link-with winterfell ]  

  ask winterfell [ create-link-with moat-cailin ]  

  ask moat-cailin [ create-link-with crossroad-inn ]  

  ask lannisport [ create-link-with highgarden ]  

  ask highgarden [ create-link-with oldtown ] 

  ask crossroad-inn [ 

    create-link-with lannisport  

    create-link-with eyrie  

    create-link-with kings-landing  

  ]

  ask kings-landing [

    create-link-with maidenpool  

    create-link-with lannisport  

    create-link-with highgarden  

    create-link-with storms-end  

  ]

 

end

 

to setup-directed-network   

 

  let castle-black one-of cities with [ city-name = "Castle Black" ]

  let winterfell one-of cities with [ city-name = "Winterfell" ]

  let moat-cailin one-of cities with [ city-name = "Moat Cailin" ]

  let crossroad-inn one-of cities with [ city-name = "Crossroads Inn" ]

  let lannisport one-of cities with [ city-name = "Lannisport" ]

  let eyrie one-of cities with [ city-name = "The Eyrie" ]

  let kings-landing one-of cities with [ city-name = "King's Landing" ]

  let maidenpool one-of cities with [ city-name = "Maidenpool" ]

  let highgarden one-of cities with [ city-name = "Highgarden" ]

  let storms-end one-of cities with [ city-name = "Storm's End" ]

  let oldtown one-of cities with [ city-name = "Oldtown" ]

  

  

  ask castle-black [ create-link-from winterfell ] 

  ask winterfell

  [ create-link-from moat-cailin

    create-link-to moat-cailin ]  

  ask moat-cailin [ create-link-to crossroad-inn ]  

  ask crossroad-inn

  [ create-link-to lannisport  

    create-link-from eyrie  

    create-link-from kings-landing ]  

  ask kings-landing

  [ create-link-from maidenpool  

    create-link-from lannisport  

    create-link-from highgarden  

    create-link-from storms-end ]  

  ask lannisport [ create-link-to highgarden ]  

  ask highgarden [ create-link-from oldtown ]  

 

end

LinkChooser.png

4. Create a chooser for the two scenarios

After writing those two long procedures, you need to call them, but before doing that, let's create a chooser on the Interface that will allow the user to choose if they want directed or undirected networks.

On the Interface, right-click where you want this new chooser and select 'Chooser'. Name the chooser 'link-type' and write the two possibilities in the main window. Make sure to have both options between quotes. 

Then, update the setup procedure to call the appropriate procedure, based on the chooser.

  setup-world   ; call the setup-world procedure to import GIS data

  setup-wall   ; call the setup-wall procedure to import the Wall vector

  setup-houses   ; call the setup-houses procedure to identify the kingdom in which each patch falls

  setup-cities   ; call the setup-cities procedure to create cites

  setup-roads   ; call the setup-road procedure to create roads

  

  ifelse link-type = "undirected" [  ; check which link type is chosen in the Interface

    setup-undirected-network  ; create the undirected network

  ][

    setup-directed-network  ; create the directed network

  ]

 

  ask links [ ; for visibility, links should be white and narrow

    set thickness 0.2

    set color white 

  ]

  setup-world 

  setup-wall 

  setup-houses 

  setup-cities 

  setup-roads 

  

  ifelse link-type = "undirected" [

    setup-undirected-network

  ][

    setup-directed-network

  ]

 

  ask links [ 

    set thickness 0.2

    set color white 

  ]

5. Use the nw extension to analyze the network

To compute some network analyses, you will need to use the nw extension. Simply add it to the extension brackets. 

Then, you will be able to calculate different centrality measures of all the connected cities. The nw extension allows computing degree, betweenness, closeness, and eigenvector centrality, as well as the clustering coefficient (and other network-related stuff). Here, you will focus on the centrality measures to see which city is best connected (and thus may have the most power?).

First, create a chooser to determine which centrality measure the model will calculate.

Then, create a procedure that takes the chooser's value and computes the correct centrality measure. In the next step, you will create a button to call the procedure.

CentralityChooser.png

extensions [ gis nw ]     ; activates the gis and nw extensions

extensions [ gis nw ]    

;;; CITIES PROCEDURE ;;;

 

to calculate-centrality [ centrality-type-chosen ]

  

  set label ""  ; resets the label to blank

  if any? my-links [  ; the code below will be done only by cities that have links

    ifelse centrality-type = "degree" [  ; for degree centrality...               

      set centrality count my-in-links   ; cities sum the number of links that go towards them

      set size centrality * 2  ; cities change their size based on the centrality measured for visibility

    ][

      ifelse centrality-type = "betweenness" [

        set centrality nw:betweenness-centrality  ; this calculates betweenness centrality

        set size centrality 

      ][

        ifelse centrality-type = "eigenvector" [

          set centrality nw:eigenvector-centrality  ; this calculates eigenvector centrality

        ][ 

          set centrality nw:closeness-centrality  ; calculates closeness centrality

        ]

        set size centrality * 10  ; for visibility

      ]

    ]

    set label precision centrality 2  ; set the label to the centrality measure, up to 2 decimals (precision n 2)

  ]

  

end

;;; CITIES PROCEDURE ;;;

 

to calculate-centrality [ centrality-type-chosen ]

  

  set label ""  

  if any? my-links [ 

    ifelse centrality-type = "degree" [ 

      set centrality count my-in-links  

      set size centrality * 2  

    ][

      ifelse centrality-type = "betweenness" [

        set centrality nw:betweenness-centrality  

        set size centrality 

      ][

        ifelse centrality-type = "eigenvector" [

          set centrality nw:eigenvector-centrality 

        ][ 

          set centrality nw:closeness-centrality  

        ]

        set size centrality * 10  

      ]

    ]

    set label precision centrality 2  

  ]

  

end

ButtonCentrality.png

6. Create a button to calculate centrality

Here, instead of having the main code call the new procedure, you will create a button that can call it again and again. We choose to set it this way so that, after setting up the networks, the user can change the type of network centrality measure to compute and simply recalculate over and over without having to setup everything again.

To achieve this result, create a button on the Interface and write the following piece of code in the Commands box.

When the button is created, press setup to get a new World, and press the compute centrality button. Which city is the biggest? Now, change the centrality-type and press the compute centrality button again. Do you see a change? Is the biggest city still the same?

You can even change the type of network (undirected vs. directed), and compute centrality, but if you do that, you have to press setup again, as those links are created through the setup procedure.

7. The Inn at the crossroads wins?

While exploring the different centrality measures computed from the networks, you may notice that the Inn at the Crossroads often has high centrality values, sometimes even higher than King's Landing, even if the latter has more roads connecting to other cities. Why is that?

 

Betweenness centrality calculates how many inter-node links (here, inter-city roads) pass through each node (here, a city). As all southern cities have to go through the Inn to get to Winterfell and Castle Black, it has a very high betweenness centrality measure. This is actually not very surprising, and explains (in a very simplified way) why it has such a prominent place in the story. Right, M. Martin?

In all seriousness, congratulations on adding roads and creating networks in your ABM.

 

If you want to see the finished model for this step, download it here.

In the next step, you will create conflict between houses, using the famous prisoner's dilemma problem. See you there!

Final.png