NetLogo: Issues when restricting number of users charging at a certain patch - netlogo

I am working on a project to model the impact of charging electric cars on the grid and modeling/simulating the driving and charging habits of the car users. I'm getting an issue in my code that unable to resolve yet.
Each location has a limited number of charging ports. For example, WORK has a total of 2 TERMINALS, so only 2 adopters can charge there simultaneously (first-come-first-serve basis). What I want to do is when 2 adopters arrive at WORK, they start charging (if required, i.e. "charging-status" = true). Any additional adopters wait until a port is available there. The adopters who finish charging should vacate the charging port for those in the wait-list, even if they don't leave.
Here's part of my effort (code) that I did:
to go
...
charge-car ; sets the charging-status based on state-of-charge.
ask adopters
[
if charging? and not marked?
[
ifelse remaining-ports != 0
[
set remaining-ports max list (remaining-ports - 1) 0
set marked? true
]
[set occupied? true]
]
if marked? and not charging?
[
set remaining-ports min list (remaining-ports + 1) terminals
set marked? false
set occupied? false
]
]
ask adopters with [charging? and marked?]
[
set color green
let battery0 battery
let charging-speed0 charging-speed
let battery1 max list 0 ( battery + charging-speed0 )
set battery min list battery1 battery-capacity
let charged min list ( battery - battery0 ) charging-speed0
set charge-demand charge-demand + charged
set soc battery / battery-capacity
set range-left battery / discharge-patch
]
tick
end
Now, the issue is this: there are multiple location on the map with charging ports. This code gives different results at some locations, even though it is the same algorithm for all locations and agents. For example, if both ports are occupied at certain locations, the "occupied?" will be true for some locations and not all of the ones with all ports engaged. I mean to say, this is showing quite a random response.
Can anyone please help me with this? Is there another way to do what I want to do? Also, please let me know if you need more info to understand my situation.
Thank you!
Edit:
This is my code for to go
to go
...
ask adopters
[
if patch-here = current-loc ; choose next target only when reached at a destination (current location)
[
choose-target
set nearest-station min-one-of patches with [location = "charging-station"][distance myself]
] ; choose target based on start time and current location
; go to target only when NOT at the arbitrary target location
if target != [0 0]
[
let dist-to-targ distance-between current-loc target
let dist-to-station distance-between current-loc nearest-station
ifelse dist-to-targ > range-left and dist-to-station < range-left
[go-to-station nearest-station]
[go-to-target]
]
if charging = "Charge Car Now"
[charge-car]
...
]
where, charge-car is
to charge-car
if patch-here = current-loc and charging-point
[
ifelse soc < 1
[
if charge-power = 1
[
set charging-speed 1 / 12
set charging-status true
]
if charge-power = 2
[
set charging-speed 6.6 / 12
set charging-status true
]
]
[
set charging-status false
set color blue
]
]
end
and go-to-target is
to go-to-target
ifelse patch-here != target
[
; move towards destination and use fuel
face target
; set marked? false
set color blue
ifelse distance target <= speed
[set speed1 0.3 * distance target] ; decrease speed as target gets nearer
[set speed1 speed]
forward speed1
set moving? true
set charging-status false
if marked?
[
set rem-term min list (rem-term + 1) terminals
type patch-here type "Updated ports" print rem-term
set marked? false
set occupied? false
]
]
[
move-to target
if target != [0 0]
[set dist-trav distance-between current-loc target]
set current-loc target
set moving? false
set dwell dwell-acq day-ind time-ind position [location] of target places ; calculate dwell time based on arrival time at target
ifelse dwell < 0
[
set dwell 288 - (ticks mod 288) ; spend rest of the time till 24:00 at that location
set dwell-flag 1
]
[set dwell-flag 0]
if current-loc = target
[
set arrival-time (ticks mod 288)
set start-time (dwell + arrival-time) mod 288
set target [0 0]
set battery battery - (discharge-patch * dist-trav) ; discharge based on distance traveled per tick
set soc battery / battery-capacity
set range-left battery / discharge-patch
if battery < 0
[set battery 0]
if soc < 0
[set soc 0]
]
]
end
where, rem-term is same as remaining-ports and charging-status is same as charging?.
I tried adding the same code in the go-to-target function, since charging-status changes there first, but that didn't show any change in the results I'm getting.

I can't see anything obviously wrong with your code. This sort of thing usually happens because you have multiple ask turtles blocks, and you work out the intention in the first block but don't do the behaviour until the second block. In your case, I can see you updating the ports count in the first block, so that doesn't directly apply.
However, I wonder if you're doing something similar with your if statements, that turtles are going through different blocks than you expect and the relevant code is missing from the extract that you pulled out. The easiest way to diagnose this type of problem is with print statements. See below for one possibility.
ask adopters
[ if charging? and not marked?
[ ifelse remaining-ports > 0
[ type patch-here print remaining-ports
set remaining-ports remaining-ports - 1
set marked? true
type patch-here type "Updated ports" print remaining-ports
]
[ set occupied? true ]
]
if marked? and not charging?
[ set remaining-ports min list (remaining-ports + 1) terminals
set marked? false
set occupied? false
]
]
Note that I also changed your code for testing/updating number of remaining ports for clarity.
On your question about lists, there is no problem adding a turtle to a list (eg set queue lput self queue) but if you want more detail than that, please ask a separate question. I strongly recommend that you do not make any attempt to introduce queues for your ports until you have the existing code working properly.

Related

To do a netlogo model with several patch layers (think floors of a building) do I need to go to Netlogo 3D?

I have a netlogo application in mind which involves multiple non interacting layers. Think floors of a building. Would I need to go to netlogo 3D or is there a suggested way to handle in regular netlogo?
This was an interesting enough question that I decided to make a simple sample.
The method I use is to have a global variable to track the number-of-floors we'll have in our building, as well as the active-floor that we are currently working with. Then all our agents, walls and workers, have a floor-num that tracks which they are on. We have a set-active-floor procedure that handles switching our currently active floor that we want to see and work with, making the patches a certain color (active-color) if they have a wall agent present and swapping which workers are hidden?. In this way, most of the magic happens in the setup-floor and set-active-floor procedures, and the real work of our model in go can be pretty typical NetLogo code asking the active-workers to do whatever we want.
While the model is running you can call set-active-floor n to any value 0 to 4 to change the current workers and walls. I also included a show-all procedure that'll un-hide all the walls and workers and let you see where they are at; you'll need to run that with the model stopped.
globals [colors active-color number-of-floors active-floor]
turtles-own [floor-num]
breed [walls wall]
breed [workers worker]
to setup
clear-all
set colors (list red blue green orange violet)
set number-of-floors 5
foreach (range 0 number-of-floors) setup-floor
reset-ticks
set-active-floor 0
end
to setup-floor [num]
set active-floor num
set active-color (item num colors)
ask patches [ set pcolor black ]
; make some random walls
create-walls (count patches * 0.2) [
set floor-num num
set hidden? true
set size 0.5
setxy random-pxcor random-pycor
set pcolor active-color
]
; only one wall per patch
ask patches [
let patch-walls floor-walls-here
let wall-count count patch-walls
if (wall-count > 1) [
ask n-of (wall-count - 1) patch-walls [ die ]
]
]
; make some workes
create-workers 10 [
set floor-num num
set hidden? true
set shape "person"
set color active-color - 2
move-to one-of patches with [pcolor != active-color]
]
end
to go
; this only "runs" the active floor, but you could run all of them
; using the same `foreach (range 0 number-of-floors) ...` code as
; in the `setup` procedure.
set-active-floor active-floor
ask active-workers [
; this code can be about the same as you'd write in a normal model...
move-to one-of patches with [pcolor != active-color]
]
tick
end
to set-active-floor [num]
set active-floor num
set active-color (item num colors)
; after the `pcolor` is set, we can use that to determine if a wall
; exists or not for an `active-worker`, we don't have to check the
; floor number at all while we do our work.
ask walls [ set hidden? true ]
ask patches [
set pcolor ifelse-value no-walls-here [ black ] [ active-color ]
]
ask workers [
set hidden? floor-num != active-floor
]
end
to-report active-workers
report workers with [floor-num = active-floor]
end
to-report floor-walls-here
report walls-here with [floor-num = active-floor]
end
to-report no-walls-here
report (count floor-walls-here = 0)
end
to show-all
foreach (range 0 number-of-floors) [ num ->
ask patches [
set pcolor ifelse-value any? walls-here [ red - 3 ] [ black ]
]
ask turtles with [floor-num = num] [
set color item num colors
set hidden? false
]
]
end
Finally, if things got much more complicated than this, I would probably choose to move to NetLogo 3D instead.

NetLogo: link an agent to another, ask things to the agent and other things to the linked agent

I'm working on extending NetLogo Robotic Factory with a mechanism where there can be only one robot per machine and where the machine takes several ticks to perform the task.
To model this, I'm creating a link between the robot and the machine. And there can only be one link per machine.
It is the first time I'm using NetLogo. So I'm not used to switching contexts. I'm trying to find out how I can give orders to both the robot and the machine when they are linked.
to move
ask robots [
if waiting = 0 [
if can-move? 1 [forward 1 face destination]
set energy energy - 1
]
if waiting > 0 [
set waiting waiting - 1
]
]
end
to set-robots-destination
ask robots [
(ifelse
; ---------------
; Step1: forges
; ---------------
[ breed ] of destination = forges [
ifelse any? forges-here [
if [count links] of one-of forges-here = 0 [
create-link-with one-of forges-here
set color of one-of forges-here red
set waiting 5
if waiting = 0 [
set costs costs + 1
set destination one-of forges
set [color] of one-of materials-here blue
ask my-links [ die ]
]
]
]
[ move ]
]
...
As you can see, repeating one-of forge there create several issues. First of all the syntax to change its color is incorrect. Then, it is unclear if the color will actually turn blue by the end or if the robot will already have left.
I would prefer to find a way to switch context with the linked forge and give it orders directly. Is this possible?

SEIS Disease Model Help in NetLogo - infected individuals do not become susceptible again?

I'm developing a simple NetLogo disease model that has 4 compartments:
S - susceptible individuals
E - Exposed individuals
I - Infected individuals
S - Recovered individuals that become susceptible again (i.e. there is no immunity).
My simulation starts off with 1 individual who is initially infected with the rest being susceptible.
This is the code I have so far:
turtles-own [
disease?
latent?
susceptible?
latent-period-time
infectious-period-time
]
to setup
clear-all
create-turtles num-agents [ setxy random-xcor random-ycor
set shape "wolf"
set size 2
become-susceptible
]
ask n-of infected-agents turtles [become-infected]
reset-ticks
end
to go
move
spread
tick
end
to move
ask turtles [
right random 50
left random 50
fd 1 ]
end
to spread
ask turtles [
ifelse disease? [] [
if any? other turtles-here with [ disease? ]
[ become-latent
set latent-period-time 0 ]
]]
ask turtles [
if latent-period-time = latent-period ;latent-period is a slider variable set to 30
[
become-infected
set infectious-period-time 0]
]
ask turtles [
if infectious-period-time = infectious-period ;infectious-period is a slider variable set to 100
[
become-susceptible]
]
ask turtles [
if latent?
[ set latent-period-time latent-period-time + 1 ]
if disease?
[set infectious-period-time infectious-period-time + 1] ]
end
to become-susceptible
set disease? false
set latent? false
set susceptible? true
set color orange
end
to become-latent
set latent? true
set disease? false
set susceptible? false
set color gray
end
to become-infected
set latent? false
set disease? true
set susceptible? false
set color blue
end
For some reason only the initial infected individual seems to go back to the susceptible pool, while any other newly infected individuals do not go back to the susceptible pool. The initially infected individual is also unable to get infected again after going back to the susceptible pool even though it encounters infected individuals.
I'm not sure how to fix this problem.
Thanks!
Your problem is that you never reset the value of latent-period-time and infectious-period-time back to 0. There are two ways to fix this:
Put the set to 0 into the same code that changes all the state flags and colours
Scrap the tracking and incrementing entirely and use a variable that records when the turtle gets to the state - assume it's called 'state-start-time' then you would simply have set state-start-time ticks and then do a subtraction for your test of duration.

How to make a turtle go one step at a time to another turtle?

I am trying to write a program which simulates drones picking up packets and delivering them to certain platforms. Once the packets have been delivered, they die. Right now, if a "single step" is performed, the drones move immediately from a packet location to a platform and again to a packet location. However, I'd like the drones to move in actual steps, such that I can include proper waiting times of packets and get a better view of how long it takes to deliver one package.
I have tried to implement "fd 1" in multiple locations (for example immediately in the "to go" function, but also separately in "to fly" or both in "to fly-empty" and "fly-loaded". If I implement the "fd 1" in any of these locations, the drones still jump in (for me seeming to be) random jump sizes and the system stops functioning, as it does not actually pick up any packages. It would be great if someone could help me with this!! Thanks in advance.
enter code here
breed [platforms platform]
breed [packets packet ]
breed [drones drone ]
drones-own [charge
mypacket
status
consumption
target
dropoff
capacity
transportedpackets
]
packets-own [destination
waitingtime
pickups
mydrone
lastdrone
]
globals [delivered
faults
nrdrones
deliverydrones
colorize
pickedup
destinationlist
dronewithpackets]
to setup
ca
clear-all-plots
setup-globals
setup-platforms
setup-drones
setup-packets
reset-ticks
end
to setup-globals
set delivered 0
set faults 0
set deliverydrones (list)
set destinationlist(list)
set colorize color?
end
to setup-platforms
create-platforms 1 [setxy -15 6 set color green set shape "circle" set label "Platform 0"]
create-platforms 1 [setxy -2 10 set color green set shape "circle" set label "Platform 1"]
create-platforms 1 [setxy 18 -7 set color green set shape "circle" set label "Platform 2"]
create-platforms 1 [setxy 9 -2 set color green set shape "circle" set label "Platform 3"]
end
to setup-drones
create-drones 3 [
setxy 0 0
set color red
set mypacket nobody
set status "ready"
set charge MaxCharge
set label who
set transportedpackets (list)
]
end
to setup-packets
create-packets 10 [
setxy 10 10
set color yellow
set shape "circle"
set size .5
set destination platform 1
set waitingtime 0
set pickups 0
set mydrone nobody
]
create-packets 4 [
setxy -10 -10
set color yellow
set shape "circle"
set size .5
set destination platform 3
set waitingtime 0
set pickups 0
set mydrone nobody
]
create-packets 10 [
setxy 9 -2
set color yellow
set shape "circle"
set size .5
set destination platform 1
set waitingtime 0
set pickups 0
set mydrone nobody
]
create-packets 10 [
setxy -2 -10
set color yellow
set shape "circle"
set size .5
set destination platform 0
set waitingtime 0
set pickups 0
set mydrone nobody
]
end
to go
ask drones with [status = "flying" ] [fly ]
ask drones with [status = "charging" ] [recharge ]
ask drones with [status = "ready" ] [pickup ]
ask packets with [mydrone = nobody ] [countwaitingtime ]
ask drones with [status = "waiting for new packets"] [packetstopickup ]
end
to fly
set charge charge - consumption
;print (word "Drone " who "has this much charge left: " charge)
if charge < 0 [if capacity != 0 [ask packets with [mydrone = dronewithpackets] [die] die]]
ifelse mypacket = nobody [fly-empty] [fly-loaded]
end
to fly-loaded
ask packets with [mydrone = dronewithpackets]
[print (word "Thanks drone" dronewithpackets " for dropping me, packet number " who " of at platform " position max destinationlist destinationlist) die]
move-to dropoff
if distance dropoff = 0
[land]
end
to fly-empty
ifelse any? packets with [mydrone = nobody]
[set target one-of packets with [mydrone = nobody]
move-to target
if distance target = 0
[pickup]]
[set status "waiting for new packets"
print "No more packets to transport at the moment"]
end
to land
set delivered delivered + capacity
set status "charging"
end
to pickup
ifelse any? packets-here with [mydrone = nobody]
[ set destinationlist (list)
set destinationlist lput (count packets-here with [destination = platform 0 and mydrone = nobody]) destinationlist
set destinationlist lput (count packets-here with [destination = platform 1 and mydrone = nobody]) destinationlist
set destinationlist lput (count packets-here with [destination = platform 2 and mydrone = nobody]) destinationlist
set destinationlist lput (count packets-here with [destination = platform 3 and mydrone = nobody]) destinationlist
;print destinationlist
;print (word "Platform " position max destinationlist destinationlist "is my next destination")
ifelse max destinationlist >= 5 [set capacity 4][set capacity max destinationlist]
set dronewithpackets who
ask n-of capacity packets-here with [destination = platform (position max destinationlist destinationlist) and mydrone = nobody] [
set mydrone dronewithpackets
print (word "I am packet " who "and I am transported by drone " mydrone "to platform " position max destinationlist destinationlist)
;print (word "I have been waiting to be pickedup for " waitingtime )
]
set dropoff platform (position max destinationlist destinationlist)
set mypacket capacity
set consumption capacity
set pickedup pickedup + capacity
;print (word "I picked up " capacity " packet(s)")
set transportedpackets lput capacity transportedpackets
;print (word "I am drone " who " and I have transported " sum transportedpackets " packets today" )
set status "flying"
]
[set mypacket nobody set consumption 1]
set status "flying"
end
to recharge
set charge charge + RechargePower
if charge > MaxCharge [set status "ready" ]
end
to countwaitingtime
set waitingtime waitingtime + 1
end
to packetstopickup
ifelse any? packets with [mydrone = nobody]
[pickup] [fly-empty]
end
Replace all your move-to with something like:
face dropoff
forward 1
The face tells the turtle to change heading to go in the direction towards where it is trying to get to. This will move it forwards one unit distance each iteration through the go procedure.
You should consider adding time to your model by adding tick at the end of the go procedure, which advances the internal counter. You use time implicitly by, for example, increasing the waitingtime counter, but you don't actually have time progressing.
Once you have both tick and forward then the turtles will move 1 unit each tick and everything that happens simultaneously can occur during one tick. If you have a go button, that button instructs the model to run the go procedure once and you can edit the button to check 'forever' so that it keeps on calling the go procedure.
The code below should do it. The ifelse statement in the while loop incorporates JenB comment, that the target is never reached with a step size of one, while the distance is lower than one.
Please check the ifelse below: if the distance is lower than one, the drone moves to the target. In case the distance is greater, it moves a step towards the target, waits 0.1 seconds (to show discrete steps) and the while loop is executed again until the drone reaches the target.
breed [targets target]
breed [drones drons]
to setup
ca
create-targets 5 [
set shape "circle"
set color white
setxy random-xcor random-ycor
]
create-drones 1 [
set color red
]
end
to go
ask one-of drones [
;; assuming you have multiple targets to choose from
;; if there is just one target, remove the line below
let temp-target one-of targets
face temp-target
while [distance temp-target != 0] [
ifelse distance temp-target < 1
[ move-to temp-target ]
[ wait 0.1 fd 1 ]
]
show "target reached"
]
end

Q: Need help to disseminate a crisis in a network

I have created a network of agents where each agent has a GDP value and a GDP growth rate. The agents are interconnected with undirected links.
I have made a countdown that every 200 ticks randomly assign a 'shock status' to 10 agents. When an agent is under shock it gets the value 'in-crisis? = true' and consequentially its GDP growth rate changes.
However, I want to add a second trigger. I want agents with the 'in-crisis? = false' to check their link-neighbors and see if any of them have 'in-crisis? = true'. If they are linked to an agent whose in-crisis is true, then they should check if their own GDP is smaller than half of the GDP of the linked state that has 'in-crisis? = true'. If it is smaller, then the agent will set his own 'in-crisis?' as true.
to shock
if ticks mod 200 = 0 [ ;; This is the countdown
spread-crisis
ask n-of 10 turtles [
become-in-crisis]
]
end
to spread-crisis ;;;;;;;;;;;;;;;; This is the second trigger. I need help here!
ask turtles with [in-crisis? = false]
[ if any? link-neighbors with [in-crisis? = true] [
if any? link-neighbors with [gdp > my-gdp] [
become-in-crisis ] ]]
end
to-report my-gdp
report (gdp * 2)
end
to become-in-crisis
set in-crisis? true
let random-years-of-shock 20 + random 100
set shock-tick random-years-of-shock
end
If you have time, please help me to adjust the spread-crisis procedure!
Thank you
Change my-gdp to [my-gdp] of myself.
to spread-crisis
ask turtles with [not in-crisis?] [
if any? link-neighbors with [in-crisis? and gdp > [my-gdp] of myself] [
become-in-crisis
]
]
end