Reputation: 101
I have three models: Parent, Child1, Child2.
Child1 generates strings which must then be passed to Child2 for further processing. The strings are generated on the fly when Child1 is executing. Whenever a new string is generated it must be sent immediately to Child2. Sometimes 2 or more strings are generated at the same time (by different agents), and then those 2 or more strings must be sent at the same time (ie. within the same tick).
One solution is to skip the parent model and let Child1 become the Parent-model, which has then access to Child 2. However, that would complicate Child1 as it would then include all the required LevelSpace code. Furthermore the two children models must be useable on their own. The two models are used for educational purposes, and the students should not see the LevelSpace code. Hence the Parent model.
Another solution is to let the Parent model continuously poll the Child 1 model to ask for new strings. Not very pretty. Not very efficient.
So basically I'm looking for some shared memory and/or event functionality in LevelSpace :-)
By the way the strings represent DNA, RNA, etc. and we're illustrating transcription and translation of strings etc.
Any ideas?
Thanks, Palle
Upvotes: 4
Views: 167
Reputation: 12580
Jasper wrote a really nice solution, though it does rely on behavior that isn't supposed to work. Another way to do it is to have child1
collect the strings as it runs in a global variable. e.g.
Child 1 code:
globals [ strings ]
to go
set strings []
ask turtles [
set strings lput (word "hello from turtle " who) strings
]
tick
end
Then have child2
accept a list of strings in its go
method
Child 2 code:
to go [ strings ]
; do stuff with the strings
end
Then the parent passes the list between them:
Parent code:
to go
ls:ask child1 [ go ]
ls:let child1-strings [ strings ] ls:of child1
ls:ask child2 [ go child1-strings ]
tick
end
Upvotes: 3
Reputation: 2780
It is definitely not conventional NetLogo code, but the callback method seems like it works okay, at least for this simple example. You do need to complicate the child models a little bit to add the run callback
statement, but it could result in cleaner code overall than the polling method depending on the use case.
Parent model:
extensions [ ls ]
globals [ child1 child2 ]
to setup
ls:reset
(ls:create-models 1 "LS callback child.nlogo" [ [id] -> set child1 id ])
(ls:create-models 1 "LS callback child.nlogo" [ [id] -> set child2 id ])
ls:ask ls:models [
child-setup
]
; here we set the callback for the child models
; we could set the callback for just `child1` instead of all `ls:models`
ls:assign ls:models callback [ [id message] -> alert id message ]
ls:assign child1 id child1
ls:assign child2 id child2
end
to go
ls:ask ls:models [
child-go
]
end
; In this case our callback is simple, just taking the caller id
; and a message. We could add more parameters for it if we want to
to alert [id message]
show (word id ": " message)
; this is just to show that we can use the callback to update
; the state of one of the other models
if id = 0 [
ls:ask child2 [ set some-val (some-val + 1) ]
]
end
Child model:
globals [ id callback some-val ]
to child-setup
set some-val 0
; set the callback to an "empty" procedure so we don't have to check
; if it is set while we run the go method.
set callback [ [model-id message] -> ]
end
to child-go
if random 10 < 3 [
(run callback id (word "child alert: " some-val))
]
end
Sample output:
observer: "1: child alert: 0"
observer: "1: child alert: 0"
observer: "1: child alert: 0"
observer: "0: child alert: 0"
observer: "1: child alert: 1"
observer: "0: child alert: 0"
observer: "1: child alert: 2"
observer: "1: child alert: 2"
observer: "0: child alert: 0"
observer: "1: child alert: 3"
observer: "1: child alert: 3"
observer: "1: child alert: 3"
observer: "0: child alert: 0"
observer: "1: child alert: 4"
observer: "0: child alert: 0"
observer: "1: child alert: 5"
observer: "1: child alert: 5"
observer: "0: child alert: 0"
observer: "1: child alert: 6"
Every time the child1
model runs the callback, the alert
procedure increments the some-val
global in child2
.
Upvotes: 1