Netlogo : calling a procedure after opening a file - netlogo

Here-below is the code for opening a file, reading it and writing it into a list (inspired from another discussion) :
to setup
reset-timer
; first, we load the database file
; We check to make sure the file exists first
ifelse ( file-exists? "AT_data.txt" )
[
; We are saving the data into a list, so it only needs to be loaded once.
set AT-data []
file-open "AT_data.txt"
while [ not file-at-end? ]
[
; file-read gives variables stored in a double list
; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
set AT-data sentence AT-data (list (list file-read file-read file-read))
]
user-message "File loading complete!"
file-close
;; when adding this, the procedure is running endlessly, to be checked
;; ask patches [ assign-data ]
]
[ user-message "There is no AT_data.txt file in current directory!" ]
file-close-all
print timer
end
As I wrote as a comment, when I call the next procedure [assign-data], the procedure [assign-data] runs endlessly. I setup a timer in the [assign-data] procedure and I see that it is running over and over again. When I run [assign-data] on its own, it is working appropriatly, only once.
I tried with a stop after [assign-data] but it is not working.
There must be something that I did not get yet about the use of Netlogo, do you know what it is ?
Here is the code of the assign-dataprocedure (there are 2 choices, the second is running faster)
to assign-farmers1
reset-timer
ask patches with [seed = 1] [
set death last (first (filter [current-inner-list -> (item 0 current-inner-list = ID_farm)] AT-data))
set age item 1 (first (filter [current-inner-list -> (item 0 current-inner-list = ID_farm)] AT-data))
]
print timer
end
to assign-data2
reset-timer
ask patches with [seed = 1] [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID_farm = item 0 current-inner-list)
[ set age item 1 current-inner-list set death item 2 current-inner-list
stop]
[ set i i + 1 ]
]
]
print timer
end
-> that lead me to another question : how to stop a simulation from running endlessly ? I tried with stop in the command center but it is not working.
Thanks for you time.
HERE IS A REPRODUCIBLE EXAMPLE
(not sure if I should leave the beginning of the question)
AT_data.txt is a file made of 3 col where the first goes from 1 to 100, second and third are just random numbers.
globals [
AT-data
]
patches-own [
ID
AT1
AT2
seed
]
to setup
;; here I just create patches with different values that also appear in the list
ca
ask patches [ set seed random 10 set ID random 100
ifelse (seed = 4)
[ set pcolor orange] [set pcolor white]
]
end
to load
reset-timer
; first, we load the database file
; We check to make sure the file exists first
ifelse ( file-exists? "AT_data.txt" )
[
; We are saving the data into a list, so it only needs to be loaded once.
set AT-data []
file-open "AT_data.txt"
while [ not file-at-end? ]
[
; file-read gives variables stored in a double list
; Each iteration we append the next three-tuple to the current list: ID AT1 AT2
set AT-data sentence AT-data (list (list file-read file-read file-read))
]
user-message "File loading complete!"
file-close
;; when adding this, the procedure is running endlessly, to be checked
ask patches [ assign-data ]
stop
]
[ user-message "There is no AT_data.txt file in current directory!" ]
file-close-all
print timer
end
to assign-data
reset-timer
ask patches with [seed = 4] [
let i 1
while [i < length AT-data] [
let current-inner-list item i AT-data
ifelse (ID = item 0 current-inner-list)
[ set AT1 item 1 current-inner-list set AT2 item 2 current-inner-list
stop]
[ set i i + 1 ]
]
]
print timer
end

Are you sure the run is endless and not exponential? You ask patches to assign-data and in assign-data you use ask patches again. That means that every single patch is checking every single patch and letting the qualified patch go through the loop, which can take a while.

Related

How to access the first turtle of a code sequence in NetLogo 6.2?

I have the following doubts:
I have several individuals of 9 turtle codes.
The turtle codes are: R1M1 R2M1 R3M1 R1M2 R2M2 R3M2 R1M3 R2M3 R3M3. And I have 10 individuals of each code.
As the code is structured in a loop sequence and the order that the code exits in the result exported in .csv, I would like to ask the first individual of the first code (R1M1) to print the output header. But, I'm only getting it using one-of, and then the header often doesn't come out in the first line of the output. And I don't know how I can access the first turtle from the R1M1 code. Does anyone have any ideas?
What I thought of is calling turtle 0 which has the code R1M1. But, I still don't know how to do this in NetLogo.
OBS.: I tried to use only turtle 0, but in the other codes, too, there is turtle 0 and then the header appears.
Thanks in advance
let n count turtles with [ profiles-code = "R1M1" ]
if n > 0
[
ask one-of turtles with [ profiles-code = "R1M1" ]
[
prepare-header-output;; CALL A PROCEDURE
]
]
An example of how the header is coming out (has 3 individuals from each of the 9 codes)
I would use a flag / semaphore variable to indicate if a header is needed. You'll need to adapt the below if you have your turtles outputting the data, but hopefully this will get you pointed in the right direction- more details in comments:
globals [ need-headers? ]
turtles-own [ class ]
to setup
ca
random-seed 1
set need-headers? true
if file-exists? "test_output.csv" [ file-delete "test_output.csv" ]
crt 10 [
set class item random 5 "ABCDE"
]
reset-ticks
end
to go
if count turtles < 1 [ stop ]
ask turtles [
if random-float 1 < 0.25 [ die ]
]
; Toy output example
file-open "test_output.csv"
foreach range length "ABCDE" [ i ->
; Output headers if needed
if need-headers? [
file-print "turtle-type, count, ticks"
; Change the need-headers? to false so this step will only happen once
set need-headers? false
]
let ltr item i "ABCDE"
let n-type count turtles with [ class = ltr ]
file-print ( word ltr "," n-type "," ticks )
]
file-close
tick
end
Output here looks something like:
but if I don't change need-headers? to false, it looks like:

How to loop in NetLogo?

I have the following problem. I need to loop through the code. However, it doesn't work.
Contextualizing the problem: I have 3 files (in .asc) that represent data referring to 3 ages of the turtles (age 2, age 4 and age 8). I would like if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ] ; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ] and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]. The problem is that the loop is not working and gives various errors. Like:
Extension exception: ascii file ./L_8.asc not found or Can't find element 3 of the list [2 4 8], which is only of length 3 or go runs more than 3 simulations.
I was unable to attach the .ascii files here in the question. But if anyone can look at the code and identify the error I would be very grateful. I can't use BehaviouSpace to solve the situation, I need this loop in the code.
Thanks in advance!
extensions [ gis ]
globals [ num turtle-ages num-ages files random-seeds num-user repetitions ]
to setup
ca
set random-seeds 1
random-seed random-seeds
set num 0
set turtle-ages [ "2" "4" "8" ]
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-2
clear
random-seed random-seeds
set num-ages item num turtle-ages
setup-asc
setup-turtles
reset-ticks
end
to setup-turtles
ask n-of 5 patches [ sprout 1 ]
end
to clear
set files 0
clear-ticks
clear-turtles
end
to setup-asc
let number1 num-ages
set files gis:load-dataset ( word "./L_" number1 ".asc" ) ;; this loads a one raster file. There are 3 files in the folder with the names: (L_2.asc ; L_4.asc and L_8.asc
end
to go
move
tick
let n count turtles
if n = 0 or ticks = 10
[
set random-seeds random-seeds + 1
set repetitions 1
if random-seeds = repetitions + 1
[
set random-seeds 1
set num num + 1
;; if the user puts the value 1 in num-user, it would only do the simulation with only one file (L_2) that would represent [ "2" ]
;;; if the user puts the value 2 in num-user, he would do the simulation with the files (L_2 and L_4) that would represent [ "2" "4" ]
;;;; and finally, if the user puts the value 3 in num-use, it would simulate the files (L_2 , L_4 and L_8) that would represent [ "2" "4" "8" ]
set num-user 1 ;;
if num = num-user [ stop ]
]
setup-2
]
end
to move
ask turtles [
right random 360
fd 1
if ticks = 5 [ die ]
]
end
Whenever possible, I'd suggest paring down your code to a MRE to a) make sure that users here can run your code (without your files, for example, this is not really viable) and b) to see if reframing your question / goals in simpler terms would help get things working- at least that's what works for me!
I think that you might find foreach useful here as a way to loop through your desired simulations instead of manually tracking the number of iterations. For this example, assuming num-user is a numeric input widget on the interface, the setup below will determine which of the ages to process:
globals [ ages-to-run ]
to base-setup
ca
; Determine how many simulations to run, based on user input into
; 'num-user' numerical input widget on the interface
ifelse num-user < 1 or num-user > 3 [
print "Incorrect number of simulations indicated"
] [
let possible-sims [ "2" "4" "8" ]
set ages-to-run sublist possible-sims 0 num-user
]
reset-ticks
end
After running the above, the ages-to-run variable will contain ["2"], ["2" "4"], or ["2" "4" "8"]. Next, you can iterate over those desired ages to run your simulations (a little more detail in comments):
to run-simulations
if ages-to-run = 0 [
print "Simulation setup not complete"
]
foreach ages-to-run [
; This is the loop proper where each "age" is iterated.
; All of your simulation calls (manual variable resetting,
; etc) should all go within this loop.
current-age ->
print word "Running simulations for age: " current-age
let file-to-load ( word "./L_" current-age ".asc" )
print file-to-load
clear-turtles
ask n-of 5 patches [
sprout 1 [
pd
set color runresult current-age + 55
]
]
repeat 20 [
ask turtles [
rt random 60 - 30
fd 1
]
tick
]
print ( word "Simulations complete for age: " current-age "\n" )
]
end
Running that code above with 3 entered into num-user will run a simulation for each age (different colors indicate different runs):
So to run simulations proper, all your per-age code should go within that foreach loop indicated above- and be careful, as you were in your question, to not reset global variables.

Netlogo: How to make a turtle move towards an unique patch target?

I have turtles (patients), and they can only use only one bed each (white patch). Since patients are randomly generated in a waiting room (green patches), sometimes two or more of them get at the same distance and therefore they find the same patch as its target. I tried to add an attribute to the patch with the purpose of assigning that particular bed to a specific patient. The idea is something like this (please indulge on the ugly code, I'm learning :P):
globals [
waitxmax
waitxmin
waitymax
waitymin
box
]
breed [ patients patient ]
patients-own [ target ]
patches-own [ assigned ]
to setup-wait-room
set waitxmax -15
set waitxmin 15
set waitymax 11
set waitymin 15
ask patches with [
pxcor >= waitxmax and
pxcor <= waitxmin and
pycor >= waitymax and
pycor <= waitymin
] [ set pcolor green ]
end
to setup-beds
let cmy 7
let cmx 15
let dst 3
let nbox 7
ask patch cmx cmy [ set pcolor white ]
let i 1
while [ i < nbox ] [
ask patch (cmx - dst) cmy [ set pcolor white ]
set i i + 1
set cmx cmx - dst
]
ask patches with [ pcolor = white ] [ set assigned false ]
set box patches with [ pcolor = white ]
end
to setup-patients
create-patients start-patients [
set shape "person"
set target nobody
move-to one-of patches with [ pcolor = green ] ]
end
to setup [
clear-all
setup-wait-room
setup-beds
reset-ticks
]
to go
ask patients [ go-to-bed ]
tick
end
to go-to-bed
let _p box with [ self != [ patch-here ] of myself ]
if target = nobody [
set target min-one-of _p [ distance myself ]
ask target [ set assigned myself ]
]
;;; FIXME
if ([ assigned ] of target) != self [ show "not true" ]
if target != nobody [
face target
fd 1
]
end
When I print the two sides of the comparison below FIXME, from the command center I actually get the expected result. For example: both patient 0 and patient 1 have the same target (patch -3 7), but that patch is assigned to (patient 0). I would have expected that comparison to force patient 1 to get a new target since the bed doesn't have his name (I haven't written that code yet), but it always evaluates to true. This is more notorious as more patients I add over available beds (if no beds available, they should wait as soon as one gets free).
When inspecting trough the interface I also see that the patch -3 7 says (patient 0), so I don't know what's happening. Command center example:
observer> show [ assigned ] of patch -3 7
observer: (patient 0)
observer> if ([ assigned ] of patch -3 7) = [self] of patient 0 [ show "true" ]
observer: "true"
observer> if ([ assigned ] of patch -3 7) = [self] of patient 1 [ show "true" ]
;;;; SETUP AND GO
(patient 0): (patch -3 7)
(patient 0): (patient 0)
(patient 0): "true"
(patient 2): (patch 12 7)
(patient 2): (patient 2)
(patient 2): "true"
(patient 1): (patch -3 7)
(patient 1): (patient 1)
(patient 1): "true"
Maybe I'm just overthinking this and there are is a simpler way to assign a bed to a patient and vice versa?
There seems to be a chunk or two missing from your code above (I can't copy-paste and run it), so please have a look at the option below.
This version works by having a single place to store the 'claimed' beds- in the turtle variable. Since the turtle variables can be queried as a list using of, a bed-less turtle can check if there are any beds that are not already present in that list and, if so, claim one.
turtles-own [ owned-bed ]
to setup
ca
ask n-of 5 patches [
set pcolor green
]
crt 10 [
set owned-bed nobody
claim-unclaimed-bed
if owned-bed != nobody [
print word "I own the bed " owned-bed
]
]
reset-ticks
end
to claim-unclaimed-bed
; If I have no bed
if owned-bed = nobody [
; Pull the current owned beds for comparison
let all-owned-beds [owned-bed] of turtles
; Pull those beds that are green AND are not found in 'all-owned-beds'
let available-beds patches with [
pcolor = green and not member? self all-owned-beds
]
; If there are any beds available, claim one
ifelse any? available-beds [
set owned-bed one-of available-beds
] [
; If there are none available, print so
print "There are no available beds."
]
]
end
Edit: Forgot the actual question title- to actually move to their owned-bed (if they have one) in the example above, they simply face it and move how you like- for example:
to go
ask turtles with [ owned-bed != nobody ] [
ifelse distance owned-bed > 1 [
face owned-bed
fd 1
] [
move-to owned-bed
]
]
tick
end
Edit: added complexity
Ok, for an added element of severity, you will likely want to avoid using multiple with [ ... = x statements, and instead to use a primitive called min-one-of which returns the agent with the minimum value of some reporter. Then, you want to tell NetLogo to keep asking the next most severe and the next most severe, etc. One way to do this is with a while loop, which basically says "While this condition is met, continue evaluating the following code." Be careful with while loops- if you forget to write your code such that eventually the condition is no longer true, the while loop will just continue running until you will eventually Tools > Halt your model (or, as has happened to me with a large model, NetLogo crashes).
I've reworked the code (much of what was above is unchanged) to include such a while loop. Note as well that, since the model needs to check which beds are available multiple times, I've made that code into a to-report chunk to condense / simplify.
turtles-own [ owned-bed severity ]
to setup
ca
ask n-of 5 patches [
set pcolor green
]
crt 10 [
set owned-bed nobody
set severity random-float 10
]
let current-available-beds report-available-beds
while [any? current-available-beds] [
; From the turtles with no bed, ask the one with the lowest severity number to
; claim an unclaimed bed. Then, reset the current-available-beds
ask min-one-of ( turtles with [owned-bed = nobody] ) [ severity ] [
claim-unclaimed-bed
if owned-bed != nobody [
show ( word "I have a severity of " severity " so I am claiming the bed " owned-bed )
]
]
set current-available-beds report-available-beds
]
reset-ticks
end
to-report report-available-beds
let all-owned-beds [owned-bed] of turtles
report patches with [
pcolor = green and not member? self all-owned-beds
]
end
to claim-unclaimed-bed
; If I have no bed
if owned-bed = nobody [
let available-beds report-available-beds
; If there are any beds available, claim one
ifelse any? available-beds [
set owned-bed one-of available-beds
] [
; If there are none available, print so
print "There are no available beds."
]
]
end

How to create a table to know which turtles visited each patch in the world?

I would like to remove a doubt and have some help.
I have a closed world of 600X600 patches. Each patch spawns a turtle (using the sprout command). Each turtle makes a series of moves and returns a value for its home patch. I would like to have the following result: know which turtle was in each patch in the world and export this result in table form in .csv
I created a list for this. But, NetLogo is running for a while and then it closes and doesn't finish the model. And so I think if I create a table it should work. The question is: will creating a table solve the problem of the model not running? And if so, how can I create a table by generating an output from that table in .csv? But, I haven't found a NetLogo command that I can create a table to adjust my code to.
Any tip is very welcome. I thank the attention
globals [ edge-size output-turtle-visits ]
patches-own [ turtle-visits ]
to setup
ca
random-seed 1
set edge-size 599
set-patch-size 1.2
resize-world 0 edge-size 0 edge-size
let pcolors []
set pcolors [ 85 95 ]
ask patches [ sprout 1 ]
ask patches [
set turtle-visits n-values count turtles [0]
set pcolor item (random 2) pcolors
]
reset-ticks
end
to go
ask turtles [
rt random 360
fd 1
]
ask patches [
foreach [who] of turtles-here [ id ->
let current-num-visits item id turtle-visits
set turtle-visits replace-item id turtle-visits (current-num-visits + 1)
]
]
end
to output
file-open ( output-turtle-visits )
file-print ( word "id_turtle;my_xcor;my_ycor;turtle_visits" )
foreach sort patches
[
t ->
ask t
[
file-print ( word self " ; " xcor " ; " ycor " ; " turtle-visits )
]
]
file-print "" ;; blank line
file-close
end

How to separate values from a list using commas in netlogo?

Situation: I have a code that exports turtle coordinates according to the code below:
to path
file-open (word fileName ".csv")
file-print (word self xcor " " ycor)
file-close
end
The result is something like:
(turtle 1)[1 1 1 1 1 2] [4 4 4 2 1 5]
Question: How can I export this same list, but with its items separated by commas?
From [1 2 1 1 1] to [1,2,1,1,1], for example.
Thanks in advance
If you are trying to process this in R or something after the fact, I'd recommend potentially reporting in long format (ie, each line indicates a turtle, a tick [or similar], and the coordinates)- I find it simpler to process.
To answer your actual question- one way would be to manually collapse each list of coordinates into a string separated by commas. For example, see the toy model below.
Simple setup:
extensions [csv]
globals [ test ]
turtles-own [ xcor-list ycor-list ]
to setup
ca
crt 10 [
set xcor-list []
set ycor-list []
]
repeat 5 [
ask turtles [
rt random 90 - 45
fd 1
set xcor-list lput pxcor xcor-list
set ycor-list lput pycor ycor-list
]
]
reset-ticks
end
This reporter is what's actually doing the work of collapsing the list into a simple string for output:
to-report collapse-string-list [str-list]
report reduce word ( sentence map [ str -> word str ", " ] but-last str-list last str-list )
end
And this chunk pulls the desired turtle variables into a list of lists, calls the collapse-string-list reporter on them, then exports to a csv:
to output-coord-file
let all-turtles sort turtles
; Pull coordinates from each turtle
let who-coord-list map [
current-turtle ->
(list
[who] of current-turtle
collapse-string-list [xcor-list] of current-turtle
collapse-string-list [ycor-list] of current-turtle
)] all-turtles
; Add headers
set who-coord-list fput ["who" "x" "y"] who-coord-list
; Export
csv:to-file "toy.csv" (map [ row -> (map [i -> (word i)] row ) ] who-coord-list)
end
Output: