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