Netlogo: Can one access a turtle variable with a concatenated word? - variables

I have edited the code to focus on the issue:
globals [num_periods]
breed [observeds observe]
observeds-own [potential0 potential1 potential2 potential3 potential4 potential5 potential6 potential7 potential8 potential9
]
to setup
clear-all
reset-ticks
ask patches [set pcolor white]
create-observeds 1 [ setxy random-xcor random-ycor set shape "square" set color green
set potential0 random 0 set potential1 random 0 set potential2 random 0 set potential3 random 0 set potential4 random 0
set potential5 random 0 set potential6 random 0 set potential7 random 0 set potential8 random 0 set potential9 random 0
]
end
to go
ask observeds [
let test1 (word "potential" who) ;; this should output potential0 a variable
let test2 runreport [test1]
print test1 ;;prints potential0
ask observeds with [test2 = who][
move ]] ;; trying to move the turtle
end
to move
right random 360
fd 1
end
As there is only one agent it's who = 0. I have set all of the variables potentialx, x = [0,9], to zero. I have then 'created' the word 'potential0' by concatenating the work potential + who of the agent. Then I have asked all agents with potential0 to move and nothing happens.
Thanks,
Kevin

You will want to use runresult for this.
runresult takes whatever string it is applied to and treats it as a reporter rather than a string. If that string contains a number it returns a number. If it contains a variable name, it treats it as a variable.
So the following should solve your problem
ask observeds with [runresult test1 = who][
move
]

Use let test1 runresult (word ("potential" who) to form the string potential0. Subsequent commands will then recognise this as a reporter

Related

Netlogo variables as txt (csv) files

I am very new to Netlogo.
Linking a GIS file, I want to make a model simulating people's spending on food in reaction to the air pollution such as PM (particular matter). Of course, I also need to consider other variables such as air temperature, precipitation, and so forth. I have a panel data of food-consumption spending, air pollution and all other variables, collected by neighborhood.
My question is whether we can make a variable that changes by time, meaning when tick advances, the value of the variable changes. For example, agent may react to the air pollution in their neighborhood, and alter their food consumption behavior. I want to make a variable of "air pollution" for the neighborhood (patch) and that would change by time (following the data I collected). So somehow, I would like to link a text file of each variable and let net logo read it through when tick advances.
Is there any way to do that? Your advice would be very much appreciated.
I don't know how to link to a file and just pull one item. That sounds like accessing a database and I don't see or know of ( yet, just me ) a direct interface from netlogo to a database system.
Someone could write such a thing using Python, say, and use the interface to Python to pull the data you need. Or you could use the interface to R again with a little tweaking as certainly R has some very nice ways to read in CSV files and make them accessible on an item by item basis by the right clever statement in R.
Both of those would be fun to write. Anyone?
Lacking that, you COULD just read ALL of your data into NetLogo and populate , say, a list (indexed conceptually by tick) of lists ( of the 4 or 5 variables that change by tick ), then use a Netlogo statement to pull the right list indexed by tick ( plus or minus one, watch the zero versus one indexing. ) when you need it, and then parse that list to pull the variables out of it. That would certainly work.
I might write and post such a list of list solution this afternoon. Depends on the weather. Meanwhile, here's a related example I wrote once of reading in a CSV file and writing the variables to some patches-own variables, which is most of what you need.
I think this code works ( with a file to read of course. )
extensions [csv ]
globals [ XC YC ]
patches-own [
country
population
emissions_mass
vulnerability
jetfuel_civilian
climate_finance
]
to setup
clear-all
file-close
;; double the slashes so this works on a Windows computer
;; set-current-directory "C:\\Users\\wades\\Documents\\netlogo\\countries" ;
;; but simpler once just the let the user navigate to the file
;; file-open "countries.csv"
let mypath "???"
set-current-directory user-directory
file-open user-file
let headers file-read-line
print (word "There are the columns: " headers);
let headlist csv:from-row headers
let colcount length headlist
print (word "this many columns: " colcount)
let i 0
repeat colcount [
let determ item i headlist
print (word "column " i " is " determ)
set i ( i + 1 )
]
print "================================"
let nextline file-read-line
print ("skipping the second row of header info")
print nextline
print " "
while [ not file-at-end? ]
[
set nextline file-read-line
let mydata csv:from-row nextline
print "=============================================="
print (word "next incoming line to process is: " nextline )
print mydata;
set XC item 1 mydata
set YC item 2 mydata
print (word " data for patch (" XC ", " YC " )" )
let mytarget one-of patches with [ pxcor = XC and pycor = YC ]
ask mytarget
[
set country item 0 mydata
set population item 3 mydata
set emissions_mass item 4 mydata
set vulnerability item 5 mydata
set jetfuel_civilian item 6 mydata
set climate_finance item 7 mydata
set pcolor blue
set plabel country
]
print " that patch should now be blue"
]
file-close;
reset-ticks
end
to go
stop
tick
end
Here's sample code that reads time-series data from a csv file and puts it into a list-of-lists to pull later.
extensions [csv ]
globals [ list-of-lists ]
to setup
clear-all
reset-ticks
;; let max-rows-to-read 3 ;; for testing purposes
file-close
;; double the slashes so this works on a Windows computer
;; set-current-directory "C:\\Users\\wades\\Documents\\netlogo\\countries" ;
;; but simpler once just the let the user navigate to the file
;; file-open "countries.csv"
let mypath "???"
;; set-current-directory user-directory
file-open user-file
let headers file-read-line
print (word "There are the columns: " headers);
let headlist csv:from-row headers
let colcount length headlist
print (word "Found this many columns: " colcount)
let i 0
repeat colcount [
let determ item i headlist
print (word "column " i " is " determ)
set i ( i + 1 )
]
print "================================"
;; skip lines if you need to
; let nextline file-read-line
; print ("skipping the second row of header info")
; print nextline
; print " "
let rowcount 0
set list-of-lists [ ]
while [ not file-at-end? ]
[
set rowcount rowcount + 1
; if rowcount > max-rows-to-read [ print "list of lists: " show list-of-lists file-close stop]
let nextline file-read-line
let mydata csv:from-row nextline
print "=============================================="
print (word "next incoming line to process is: " nextline )
print mydata;
let onelist ( list
item 0 mydata
item 1 mydata
item 2 mydata )
set list-of-lists lput onelist list-of-lists
]
show list-of-lists
file-close;
end
to go
let indexer ticks ;; maybe you want this offset from ticks by some amount.
ifelse ( indexer < length list-of-lists )
[
let datalist item indexer list-of-lists
let time item 0 datalist
let temp item 1 datalist
let smog item 2 datalist
print (word "At tick " indexer " processing this list: " datalist )
print "yielding: "
print (word "At tick " indexer " time = " time " temp= " temp " and smog=" smog "\n")
]
[
print "All done. Have a nice day!"
]
tick
end

Netlogo Cyle using turtle_index

I am using a turtle_index code to create a cycle in Netlogo. The cycle works but it is only using one turtle at a time. Each turtle completes the cycle before the next turtle starts the cycle. I would like all turtles to involved in the cycle at the same time. Is there a faster way to make this happen than using:
to go
ask turtle 1 [cycle-forward]
wait 0.5
ask turtle 2 [cycle-forward]
wait 0.5
ask turtle 3[cycle-forward]
end
Okay from your comment I think I understand. One way to tackle this is to have turtles-own variables such that turtles know what step they have done and whether they have acted on the current tick. That way, they won't do a step out of turn. You can then break your cycle down into steps and use logical operators so that turtles don't take a step if they do not fulfill some criteria that you set. For example:
turtles-own [
step1?
step2?
step3?
acted?
]
to setup
ca
reset-ticks
crt 10 [
set step1? false
set step2? false
set step3? false
set acted? false
]
end
to go
ask turtles [
set acted? false
]
cycle
tick
end
to cycle
let step1t one-of turtles with [ step1? = false ]
if step1t != nobody [
ask step1t [
set step1? true
set acted? true
;;; example step 1
set color red
set heading 45
fd 3
]
]
let step2t one-of turtles with [step1? = true and step2? = false and acted? = false]
if step2t != nobody [
ask step2t [
set step2? true
set acted? true
;;; example step 2
set size 1.5
set heading 90
fd 3
]
]
let step3t one-of turtles with [step2? = true and step3? = false and acted? = false]
if step3t != nobody [
ask step3t [
set step3? true
set acted? true
;;; example step 3
set color color + 2
set heading 135
fd 3
]
]
end

Loop Through Array of Labels Using Temp Variable

I've got a 2D array of 100 labels in a 10x10 matrix (it's 2D because it represents some hardware out in the real world, if anyone cares). I want to loop through and check a conditional, and change the label background color if the conditional is false.
I've tried this ten different ways, but I keep getting an exception thrown because the temp variable I have created won't take an assignment to one of the label names.
'Table for correct switch module for corresponding actuator
Dim ActLabelLookup(,) As Label =
{{MTA91, MTA92, MTA93, MTA94, MTA95, MTA96, MTA97, MTA98, MTA99, MTA100},
{MTA81, MTA82, MTA83, MTA84, MTA85, MTA86, MTA87, MTA88, MTA89, MTA90},
{MTA71, MTA72, MTA73, MTA74, MTA75, MTA76, MTA77, MTA78, MTA79, MTA80},
{MTA61, MTA62, MTA63, MTA64, MTA65, MTA66, MTA67, MTA68, MTA69, MTA70},
{MTA51, MTA52, MTA53, MTA54, MTA55, MTA56, MTA57, MTA58, MTA59, MTA60},
{MTA41, MTA42, MTA43, MTA44, MTA45, MTA46, MTA47, MTA48, MTA49, MTA50},
{MTA31, MTA32, MTA33, MTA34, MTA35, MTA36, MTA37, MTA38, MTA39, MTA40},
{MTA21, MTA22, MTA23, MTA24, MTA25, MTA26, MTA27, MTA28, MTA29, MTA30},
{MTA11, MTA12, MTA13, MTA14, MTA15, MTA16, MTA17, MTA18, MTA19, MTA20},
{MTA1, MTA2, MTA3, MTA4, MTA5, MTA6, MTA7, MTA8, MTA9, MTA10}}
Private Sub UpdateActuatorStatus()
Dim X As Integer
Dim Y As Integer
Dim CurrAct As New Label
For X = 0 To (ActControl.MAX_X - 1)
For Y = 0 To (ActControl.MAX_Y - 1)
If TempFunctionalActuatorMatrix(X, Y) = False Then
CurrAct = ActLabelLookup(X, Y)
CurrAct.BackColor = Color.Firebrick
End If
Next
Next
End Sub
With this code, CurrAct is never getting set to anything. Anyone see what I'm doing wrong?
Your array isn't initialised (well, it is, but it is initialised with nothings as the labels are nothing as the form instance is created).
Try filling it before parsing (in Form Load or in UpdateActuatorStatus):
ActLabelLookup =
{{MTA91, MTA92, MTA93, MTA94, MTA95, MTA96, MTA97, MTA98, MTA99, MTA100},
{MTA81, MTA82, MTA83, MTA84, MTA85, MTA86, MTA87, MTA88, MTA89, MTA90},
{MTA71, MTA72, MTA73, MTA74, MTA75, MTA76, MTA77, MTA78, MTA79, MTA80},
{MTA61, MTA62, MTA63, MTA64, MTA65, MTA66, MTA67, MTA68, MTA69, MTA70},
{MTA51, MTA52, MTA53, MTA54, MTA55, MTA56, MTA57, MTA58, MTA59, MTA60},
{MTA41, MTA42, MTA43, MTA44, MTA45, MTA46, MTA47, MTA48, MTA49, MTA50},
{MTA31, MTA32, MTA33, MTA34, MTA35, MTA36, MTA37, MTA38, MTA39, MTA40},
{MTA21, MTA22, MTA23, MTA24, MTA25, MTA26, MTA27, MTA28, MTA29, MTA30},
{MTA11, MTA12, MTA13, MTA14, MTA15, MTA16, MTA17, MTA18, MTA19, MTA20},
{MTA1, MTA2, MTA3, MTA4, MTA5, MTA6, MTA7, MTA8, MTA9, MTA10}}
Change the member-level declaration of ActLabelLookup to just:
Dim ActLabelLookup(,) As Label
In the form's Load event handler add a line to initialize it:
ActLabelLookup(,) =
{{MTA91, MTA92, MTA93, MTA94, MTA95, MTA96, MTA97, MTA98, MTA99, MTA100},
{MTA81, MTA82, MTA83, MTA84, MTA85, MTA86, MTA87, MTA88, MTA89, MTA90},
{MTA71, MTA72, MTA73, MTA74, MTA75, MTA76, MTA77, MTA78, MTA79, MTA80},
{MTA61, MTA62, MTA63, MTA64, MTA65, MTA66, MTA67, MTA68, MTA69, MTA70},
{MTA51, MTA52, MTA53, MTA54, MTA55, MTA56, MTA57, MTA58, MTA59, MTA60},
{MTA41, MTA42, MTA43, MTA44, MTA45, MTA46, MTA47, MTA48, MTA49, MTA50},
{MTA31, MTA32, MTA33, MTA34, MTA35, MTA36, MTA37, MTA38, MTA39, MTA40},
{MTA21, MTA22, MTA23, MTA24, MTA25, MTA26, MTA27, MTA28, MTA29, MTA30},
{MTA11, MTA12, MTA13, MTA14, MTA15, MTA16, MTA17, MTA18, MTA19, MTA20},
{MTA1, MTA2, MTA3, MTA4, MTA5, MTA6, MTA7, MTA8, MTA9, MTA10}}

Defining Variables Prior to use in TCL

I'm brand new to TCL, and am trying to wrap my brain around all the usages of "", {}, and [] that it uses. Something I'm used to doing in other languages is defining my variables prior to use, at the beginning of the application. The below code works:
puts "Please enter an integer of choice to be added: "
flush stdout
gets stdin intAnswer
puts "Please enter a second integer of choice to be added: "
flush stdout
gets stdin intAnswerTwo
puts "Please enter a third integer of choice to be added: "
flush stdout
gets stdin intAnswerThree
puts "The total of the three integers is: [expr $intAnswer + $intAnswerTwo + $intAnswerThree]"
What I'm wanting to do is define the variables prior to use. As such:
set intAnswer 0
set intAnswerTwo 0
set intAnswerThree 0
set intTotal 0
This code, placed at the beginning, doesn't work with the rest of the code. What am I missing?
The code looks absolutely fine to me, though [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}] would be better (as it stops potential reinterpretation of the variables' contents, which would be both a safety and performance issue).
However, if you really want to have integers from the user, you need to validate their input. This is most easily done by writing a procedure to do the job so you can reuse it (i.e., you refactor the code to get a value so you can use a more sophisticated version and get it right once):
proc getIntFromUser {message} {
# Loop forever (until we [exit] or [return $response])
while true {
puts $message
flush stdout
set response [gets stdin]
# Important to check for EOF...
if {[eof stdin]} {
exit
}
# The validator (-strict is needed for ugly historical reasons)
if {[string is integer -strict $response]} {
return $response
}
# Not an integer, so moan about it
puts "\"$response\" is not an integer!"
}
}
Now you have that procedure, the rest of your code can become:
set intAnswer [getIntFromUser "Please enter an integer of choice to be added: "]
set intAnswerTwo [getIntFromUser "Please enter a second integer of choice to be added: "]
set intAnswerThree [getIntFromUser "Please enter a third integer of choice to be added: "]
puts "The total of the three integers is: [expr {$intAnswer + $intAnswerTwo + $intAnswerThree}]"
The art of writing good Tcl code (or good code in pretty much any other language) is knowing what are the good points to refactor. A good starting point is “if you do it twice or more, do it once and share”. It's doubly good if you can give the procedure a good name and clear interface, a clear indication that you've got it right. Indeed, you could also go for:
set total [expr {
[getIntFromUser "Please enter an integer of choice to be added: "] +
[getIntFromUser "Please enter a second integer of choice to be added: "] +
[getIntFromUser "Please enter a third integer of choice to be added: "]
}]
puts "The total of the three integers is: $total"
The results observed by the user will be identical.

Matlab instance variable not being saved, reverts to 0s

I am struggling to understand why my instance variables not being saved. Whenever I make a change to CurrentSettings, it does not appear next time I call another function. Basically it does not save and reverts to 0s after each function.
classdef laserControl
%LASERCONTROL This module is designed to control the laser unit.
% It can set the filter position, open and close the shutter and turn
% on/off the laser.
%
%%%%%%%%%%PORT LISTINGS%%%%%%%%%%%
%The set filter command is on port0
%The set shutter is in port1
%Laser 1 on port2
%Laser 2 on port3
%The filter digits are on ports 8-15 (the are on the second box)
properties%(GetAccess = 'public', SetAccess = 'private')
laserPorts; %The #'s of the output ports
currentSettings; %Current high/low settings
dio;
end
methods
%Constructor
%Opens the connection with the digital outputs
%Make sure to close the connection when finished
function Lobj = laserControl()
%Setup the laser
Lobj.laserPorts = [0:3 8:15];% 8:15
Lobj.currentSettings = zeros(1, length(Lobj.laserPorts));
%Make connection and reset values
Lobj.dio = digitalio('nidaq','Dev1');
addline(Lobj.dio, Lobj.laserPorts, 'out');
putvalue(Lobj.dio, Lobj.currentSettings);
end
%Closes the connection to the digital output
function obj = CloseConnection(obj)
putvalue(obj.dio, zeros(1, length(obj.currentSettings)));
delete(obj.dio);
clear obj.dio;
end
%Sets the position of the filter.
%positionValue - the integer amount for the position, cannot be
%larger than 150, as regulated by the box.
%The set filter command is on port0
%The filter digits are on ports 8-15 (the are on the second box)
function obj = SetFilterPosition(obj, positionValue)
if 0 <= positionValue && positionValue < 150
binaryDigit = de2bi(positionValue); %Convert it to binary form
%LaserOn OldSettings NewValue ExtraZeros
obj()
obj.currentSettings()
obj.currentSettings = [1 obj.currentSettings(1, 2:4) binaryDigit...
zeros(1, 8 - length(binaryDigit))];
putvalue(obj.dio, obj.currentSettings);
else
display('Error setting the filer: Value invalid');
end
end
end
Because your class does not inherit from handle, you've written a "value"-type class - in other words, when you make changes, you must capture the return value, like so:
myObj = SetFilterPosition( myObj, 7 );
For more on handle and value classes, see the doc