netlogo: how to group properties patches own - gis

I was wondering in what way you can group variables that patches-own to loop over them? I am using NetLogo 5.3.1.
Specifically I am doing this:
patches-own[some-variable other-variables]
to setup
gis:apply-coverage dataset-1 "some-variable" some-variable
;this line above for 1000 other-variables
end
and I would like to do it like this:
globals [group-variables]
patches-own [some-variable other-variables]
to setup
set group-variables (list some-variable other-variables)
foreach group-variables[
gis:apply-coverage dataset-1 "?" ?
]
end
But this seems to be impossible: setup is now turtle/patch only. I also got the message that gis:apply-coverage is expecting something, but got anything instead.
What other way can I use to group these variables somehow, without slowing the program down?
I have looked at lists, arrays and tables but the problem is the gis:apply-coverage demands a patch variable. This excludes arrays and tables. Lists would need to be defined in a patch context, but the gis:apply-coverage needs to be called in an observer context. The read-from-string variable does not support reading a variable and making a string of everything and then calling run on it does not improve execution speed.

I think the main problem is that you use the ? variable as a string ("?"). This cannot work, because it does not refer to the current foreach loop variable.
Maybe there are better solutions, but I got it to work by using the run primitive, which allows to create a command from a combination of strings and variables.
Here is a short example, using the countries dataset from the GIS code examples:
extensions[gis]
globals [group-vars shp]
patches-own [CNTRY_NAME POP_CNTRY]
to load-multiple-vars-from-shp
ca
; Load Data
set shp gis:load-dataset "C:/Program Files/NetLogo 5.3.1/app/models/Code Examples/GIS/data/countries.shp"
; Print properties
print gis:property-names shp
; Select two properties to write to patch-variable
set group-vars (list "CNTRY_NAME" "POP_CNTRY")
; Loop over group-vars
foreach group-vars
[
; Apply coverage of current variable
run (word "gis:apply-coverage shp \"" ? "\"" ?)
]
; Visualize patch variables to check if everything is working
ask patches
[
set plabel substring (word CNTRY_NAME) 0 1
set pcolor POP_CNTRY
]
end

Related

initialize turtles from the same patch for two different scenario runs

I want to run my NetLogo model to see how the change in landscape scenario 'baseline' and 'future' affects agents' annual travel distance. I have initialized agents on a random patch within their residential postcode boundary.
To be able to compare changes in travel, I should have them initialized from the same patch for both scenarios. I have been trying using random-seed but can't get it to work. I want to run the model for 100 different initial patches but maintain the same patch for each baseline and future scenario in a single run (ideally that is two runs, one with baseline scenario and one future scenario.
When I use random-seed in setup, it initializes agents from different patches for each scenario.
I tried setting a global variable random-seed-turtles and tried 2 runs in behaviour space with two different seeds.
[ "random-seed-turtles" 1 2 ]
[ "landscape-scenario" "baseline" "future"]
It creates turtles from the same patch for each run for baseline but differs for future scenario.
Is there a way to code so that I can have a different initial patch for turtles for each of the 100 runs but same origin for individual runs.
e.g.
run1
baseline my_home = patch 113 224
future my_home = patch 113 224
Also, does the place where you insert the random-seed command matter?
The patch value (landscape availability) changes every tick, reading from a raster prepared for that timestep. Landscape_scenario is a chooser on the interface with the values for 'baseline' and 'future' each reading a different set of rasters. Does this interfere random-seed?
NOTE: The answer below assumes that your situation is such that you want the baseline and the future scenarios to be run as part of a single model iteration.
Also, I propose two (very similar) approaches. The one you'll prefer will depend on your specific situation and needs, that we don't know since you didn't share the structure of your model.
You have to create a turtles-own variable where each turtle will directly store its starting patch.
Then, when you close your baseline scenario and prepare your future scenario, you will have to manually delete all the variables that you want to delete except that variable where turtles stored their starting patch (so, for example, you shouldn't use clear-all or clear-turtles in that passage, because such commands would also clear the turtles-own variable that you want to keep).
To show the approach with an example, see the code below:
globals [
; Put here your gobal variables.
]
patches-own [
; Put here your patches' variables.
]
turtles-own [
my-start
my-value ; I only included this to show that you have to manually clear the turtles' variables EXCEPT from 'my-start'.
]
to setup
clear-all
reset-ticks
; Do here what you need to do to prepare the baseline scenario.
create-turtles 20 [
setxy random-xcor random-ycor
set my-value random 10
set my-start patch-here
]
end
to go
run-model
clear-baseline-scenario
prepare-future-scenario
run-model
end
to run-model
; Put here all the things you need to have to run your model,
; including a stop condition (and ticks, if you want them).
end
to clear-baseline-scenario
clear-globals
clear-patches
reset-ticks
; Now, you also have to manually clear all your turtles' variables EXCEPT
; from 'my-start':
ask turtles [
set my-value 0
]
end
to prepare-future-scenario
; Do here what you need to do to prepare the future scenario,
; and also tell your agents to go to their starting patch:
ask turtles [
move-to my-start
]
end
There is another approach which basically is just the same solution but applied to patches instead of turtles.
In this case, you will have a patches-own variable that signals if a patch is or isn't a starting patch (for example by taking 1/0 value, or TRUE/FALSE if you prefer).
Then, when going from the baseline scenario to the future scenario, you will clear all the things you need to clear except from that patches-own variable (i.e. without using clear-all or clear-patches in that passage, because such commands would also clear the patches-own variable that you want to keep).
This approach is doable if you are not interested in having exactly the same turtle starting on that same patch, but you are happy to have any turtle starting on any of the starting patches.
So it will be something like:
globals [
; Put here your gobal variables.
]
patches-own [
slope ; I only included this to show that you have to manually clear the patches' variables EXCEPT from 'starting-patch?'.
starting-patch?
]
turtles-own [
; Put here your turtles' variables.
]
to setup
clear-all
reset-ticks
; Do here what you need to do to prepare the baseline scenario.
create-turtles 20 [
setxy random-xcor random-ycor
set starting-patch? TRUE
]
ask patches [
set slope random 5
if (starting-patch? = 0) [
set starting-patch? FALSE
]
]
end
to go
run-model
clear-baseline-scenario
prepare-future-scenario
run-model
end
to run-model
; Put here all the things you need to have to run your model,
; including a stop condition (and ticks, if you want them).
end
to clear-baseline-scenario
clear-globals
clear-turtles
reset-ticks
; Now, you also have to manually clear all your patches' variables that you
; want to clear EXCEPT from 'my-start':
ask patches [
set slope 0
]
end
to prepare-future-scenario
; Do here what you need to do to prepare the future scenario,
; and also tell your agents to go to an empty starting patch:
create-turtles 20 [
move-to one-of patches with [(starting-patch?) AND (not any? turtles-here)]
]
end

How to add many selections to one variable in tcl

after doing some other things in my script I end up with a series of variables set in tcl ($sel1, $sel2, $sel3, ...) and I need to add them to the following line:
set all [::TopoTools::selections2mol "$box $sel1 $sel2 $sel3 $sel4"]
Now, if I only had four this would be fine by hand, but in the final version I will have hundreds which is untenable to do by hand. I'm sure the answer is some kind of loop, but I've been giving it some thought now and I can't quite figure it out. If I had, say, $sel1, $sel2, all the way to a given number, how would I add them to that line in the format shown at any amount that I want, with the $box at the beginning as shown? Thanks very much for your help.
It may or may not be relevant, but I define the variables in a loop as follows:
set sel$i [atomselect $id all]
I'm not familiar with the software you are using, but it should be possible to fix this without too much hassle.
If you put this inside the loop instead:
set sell$i [atomselect $id all]
append valueStr " " [set sell$i]
(or perhaps this, even if it is little C:)
append valueStr " " [set sell$i [atomselect $id all]]
you will get the string that " $sel1 $sel2 $sel3 $sel4" is substituted into (remember to put $box in as well).
With Tcl 8.5 or later, you can do
dict set values $i [atomselect $id all]
inside the loop, which gives you a dictionary structure containing all values, and then create the sequence of values with:
set all [::Topotools::selections2mol [concat $box [dict values $values]]]
Depending on the output and input formats of atomselect and selections2mol, the latter might not actually work without a little fine-tuning, but it should be worth a try.
In the latter case, you aren't getting the variables, but each value is available as
dict get $values $i
You can do this with an array also:
set values($i) [atomselect $id all]
but then you need to sort the keys before collecting the values, like this
set valueStr [list $box]
foreach key [lsort -integer [array names values]] {
append valueStr " " $values($key)
}
Documentation:
append,
array,
concat,
dict,
foreach,
list,
lsort,
set

TCL output with space

I have 5 different variable coming from different if and loop statements, when I use "put" to take output into text file all characters and digits are altogether like this : alphaclass112098voip. where
variables: name = alpha
category = class1
number = 12098
service = voip
I want output in file as like this with spaces on same line.
Alpha class1 12098 voip
Beta class1 12093 DHCP SIP
Also at certain point I want to through delimiters for future purposes.
The easiest way to deal with this is to construct a Tcl list that represents the record. You can do this piecemeal with lappend, or all at once with list. Or mix them.
foreach name $names category $categories number $numbers service $services {
set record [list $name $category]
lappend record $number
lappend record $service
puts $record
}
This shows the record for each line in a format that Tcl finds easy to parse (you'll see what I mean if you have a name with a space in it). To use a delimiter to separate the values instead, the join command is very useful:
puts [join $record $delimiter]
The default delimiter is space, but try a : instead to see how it works.
If you're generating a CSV file, do use the csv package in Tcllib. It handles the tricky edge-cases (e.g., embedded commas) for you.

Printing multiple variables in tcl

I have to print multiple variables in a single puts like this
puts "$n1_$n2_$n3_$n4"
where n1 , n2 , n3 , n4 are 4 variables.
It wont print and will show error n1_ : no such variable
Expected output should be something like this (example)
01_abc_21_akdd
Variable names in Tcl can be any string in Tcl, there are no restrictions but if you want to use special characters (those not in the range of a-z, 0-9 and _, and letters in different languages depending on the platform and locale), you have to either brace the expression names or use other workarounds (like with the answer of Hoodiecrow).
What this means is that if you have a variable named abc.d, and if you use $abc.d, the Tcl engine will try to find the variable $abc because . is not a 'normal' character.
But if you have a variable named abc and use $abcd, or $abc_d, then the engine will start looking for the variables abcd or abc_d and not abc.
Because of this, you will have to use braces between the variable name for example:
${n1}
The reason why putting a backslash works is that \ is not a 'normal' character and after reading the above, it should be a little more obvious how things worked.
There are a few things that yet can go in variable names which don't need bracing and still mean something, except that something is 'special':
::: This is usually used for scoping purposes. For instance if you have a global variable named my_var, you can also use $::my_var to refer to it. Here :: tells Tcl that my_var is a global variable. Note that if there are more than two : in a row they will not add up:
% set ::y 5
5
% set ::::y
5
% set :::y
5
:: is usually used to define the namespace the variable is in. For example, $mine::var is a variable called var in the namespace with a name of mine.
(): These are used for arrays. $arr(key) is a variable with two parts: the array name arr and the key name key. Note: you can have an array named and a key named because...
% set () abc
abc
% puts $()
abc
% array get ""
{} abc
There might be some more, but those are the basics you could look out for.
Two other ways:
puts "${n1}_${n2}_${n3}_${n4}"
puts [format "%s_%s_%s_%s" $n1 $n2 $n3 $n4]
Documentation: format
(Note: the 'Hoodiecrow' mentioned in Jerry's answer is me, I used that nick earlier.)

tcl: how to use the value of a variable to create a new variable

here is an example of what I'm trying to do.
set t SNS
set ${t}_top [commands that return value]
Want to get the info stored at ${t}_top
puts “${t}_top”
 SNS_top (really want the data stored there?)
Thought it was : ${{$t}_top} , maybe that was perl but {} inside the {} do not work.
One of the really interesting things about Tcl is that you can create variable names dynamically, as you are doing in the question you posted. However, this makes it tricky to write and makes your code harder than necessary to understand.
Instead of trying to figure out how to do the equivalent of ${{$t}_top}, it's arguably better to avoid the problem altogether. You can do that by using an associative array.
For example, instead of this:
set t SNS
set ${t}_top [commands that return value]
...
puts [set ${t}_top]
Do this:
set t SNS
set top($t) [commands that return value]
...
puts $top($t)
Most people agree that the latter example is much more readable.
try
puts [set ${t}_top]
Each line of code in Tcl is run through the substitution phase (in which variables, commands, etc are substituted) only once... generally. As such, something like
set var1 1
set var2 var1
set var3 $$var2
won't wind up with var3 equaling 1, since the substitutor will replace "$$var2" with "the value of the variable named '$var2' (literally)" and stop.
What you need it to either go about things another way or to force another round of substitution. The other way is generally to avoid needing a second round of substitution (as shown by Jackson):
set var3 [set $var2]
Here, the $var2 is replaced, during substitution, by "var1"... then [set var1] returns 1... then var3 gets set to the value of "1"... and you're good.
The syntax
puts [expr $${t}_top]
works as well, and avoids using the 'set' operation so a syntax error shouldn't overwrite your data.