I'm working on an epidemic model. In this model, there are 2 types of susceptible states, S1 and S2. At the start of the model, I want there to be agents in S1 state as well as S2 state.
For example, I have total 1000 agents at first, and I want there to be 200 in S1 and 800 in S2.
I tried to set S1 as the start state and create a message transition from S1 to S2, then coded in main as:
for(int i = 0; i < 1000*0.8; i++)
send("s1 to s2", people.random());
But it will cause repeat message to the same agent, thus there won't be 800 in S2 state. Also I think it's not a good design.
You need some code to do selection-without-replacement so you don't choose the same agent multiple times. There's nothing built-in to AnyLogic to do this for you, so you'd want code something like the below (assuming your agents are of type Person).
// Create selection list with all Person agents in
List<Person> selectionList = new ArrayList<Person>();
for (Person p : people) {
selectionList.add(p);
}
// Select one 800 times (removing them from our selection list as we go)
for (int i = 0; i < 800; i++) {
int randomIndex = uniform_discr(0, selectionList.size() - 1);
send ("s1 to s2", selectionList.get(randomIndex));
selectionList.remove(randomIndex);
}
The crucial thing to remember (and something that many AnyLogic modellers don't understand) is that messages to statecharts are processed asynchronously (in hidden timeout 0 events which you can see on the Events View at runtime) however you send them (e.g., whether you use send, receive or the statechart's fireEvent function --- these just affect the number of such intermediate events and whether the "On message received" action of the Connections element is triggered or not).
Thus an agent will never have changed state in a block of code which sends messages to them. (It will only do so after this block of code --- and the current event it is triggered from --- completes.)
P.S. As per your comment to Emile's (incorrect) answer, the other way to do this is via dynamic events so that each message is sent after previous ones have been processed. But then you have to be very careful that you get the at-the-same-sim-time event ordering correct (loads of subtle detail here) and you'd still have to do the filtering in Emile's answer which is very wasteful; much easier to do it the more conceptually correct way where you whittle down the set of agents you're sampling from as you go.
I am trying to make a model to simulate the contagion of covid in public spaces using a mix between SEIR and pedestrian models.
In another question I asked to use a static population. They suggested that before deleting the agent a copy be saved in a list and after the first X agents have been generated I want the next agent generated by the pedSource to be one of the list.
Currently what I do is take a random agent from the list and if it is infected I send a message to the new agent so that it goes into the infected state. But by doing that I am resetting the timeout to recover every time an agent enters the zone that I am modeling.
this is the code that currently runs in the pedSource on exit:
if (personasEnCasa.size()+personasEnSuper.size() > poblacionMaxima){
Persona p = randomFrom(personasEnCasa);
if (p.statechart.getState() == Persona.Infeccioso){
send("Contagiado", ped);
};
personasEnCasa.remove(p);
};
personasEnSuper is my population of Persona, personasEnCasa is my list of agents outside the zone and and poblacionMaxima is the maximum number of agents in the lista and the population
I would like to be able to copy the current statechart of the agent in the list to the agent that generates my pedSource. Or use something similar to a pedSource.inject () but inserting an agent from the list instead of a new one. But I did not know how to do it.
is there any way to do this?
your ped already exists and you don't need to copy it you can just move it to the flow like this, with pedWait being any pedestrian block that you want, so instead of send("Contagiado", ped); you would do enter.take(ped);
but if you insist in using the send, then you can use branches on your statechart to define where this ped goes:
you will need in this case before the send, use ped.infectious=true; and the condition in the branch would be infectious==true to move to the infectious state.
As a side note, instead of p.statechart.getState() == Persona.Infeccioso you should use p.statechart.getState().equals(Persona.Infeccioso)
use == only with primitives such as boolean, int and double, otherwise you are susceptible to errors that are very difficult to discover
I'd like to return and capture a list of the path elements and nodes that an agent will travel if given a moveTo() command. From this list, I can see if the agent will pass through certain nodes where the agent will behave differently (slow down, pause for 1 minute, etc.). I can then cycle through moveTo() commands for each node and change the parameters based on the node it's going through.
I'd love to give some sample code, but I'm not sure where to begin to get the list. TIA
You can use this function to get the shortest route from source to target:
RouteData rd = RouteData findShortestPath(ILocation source, ILocation target, Node[] nodesToAvoid, Path[] pathsToAvoid);
You can access the elements of rd by calling rd.getMovements().get(index).getNetworkElement(). This will return an object which could be an instance of a path, or a node, or a rectangular node etc.
For more details you can look here: AnyLogic Help - TransporterControl
Given the following code if I use the first method in the if branch to obtain a MIDIDestination the code works correctly, and MIDI data is sent. If I use the second method from the else branch, no data is sent.
var client = MIDIClientRef()
var port = MIDIPortRef()
var dest = MIDIEndpointRef()
MIDIClientCreate("jveditor" as CFString, nil, nil, &client)
MIDIOutputPortCreate(client, "output" as CFString, &port)
if false {
dest = MIDIGetDestination(1)
} else {
var device = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(device, 0)
dest = MIDIEntityGetDestination(entity, 0)
}
var name: Unmanaged<CFString>?
MIDIObjectGetStringProperty(dest, kMIDIPropertyDisplayName, &name)
print(name?.takeUnretainedValue() as! String)
var gmOn : [UInt8] = [ 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 ]
var pktlist = MIDIPacketList()
var current = MIDIPacketListInit(&pktlist)
current = MIDIPacketListAdd(&pktlist, MemoryLayout<MIDIPacketList>.stride, current, 0, gmOn.count, &gmOn)
MIDISend(port, dest, &pktlist)
In both cases the printed device name is correct, and the status of every call is noErr.
I have noticed that if I ask for the kMIDIManufacturerName property that I get different results - specifically using the first method I get Generic, from the USB MIDI interface to which the MIDI device is connected, and with the second method I get the value of Roland configured via the Audio MIDI Setup app.
The reason I want to use the second method is specifically so that I can filter out devices that don't have the desired manufacturer name, but as above I can't then get working output.
Can anyone explain the difference between these two methods, and why the latter doesn't work, and ideally offer a suggestion as to how I can work around that?
It sounds like you want to find only the MIDI destination endpoints to talk to a certain manufacturer's devices. Unfortunately that isn't really possible, since there is no protocol for discovering what MIDI devices exist, what their attributes are, and how they are connected to the computer.
(Remember that MIDI is primitive 1980s technology. It doesn't even require bidirectional communication. There are perfectly valid MIDI setups with MIDI devices that you can send data to, but can never receive data from, and vice versa.)
The computer knows what MIDI interfaces are connected to it (for instance, a USB-MIDI interface). CoreMIDI calls these "Devices". You can find out how many there are, how many ports each has, etc. But there is no way to find out anything about the physical MIDI devices like keyboards and synthesizers that are connected to them.
"External devices" are an attempt to get around the discovery problem. They are the things that appear in Audio MIDI Setup when you press the "Add Device" button. That's all!
Ideally your users would create an external device for each physical MIDI device in their setup, enter all the attributes of each one, and set up all the connections in a way that perfectly mirrors their physical MIDI cables.
Unfortunately, in reality:
There may not be any external devices. There is not much benefit to creating them in Audio MIDI Setup, and it's a lot of boring data entry, so most people don't bother.
If there are external devices, you can't trust any of the information that the users added. The manufacturer might not be right, or might be spelled wrong, for instance.
It's pretty unfriendly to force your users to set things up in Audio MIDI Setup before they can use your software. Therefore, no apps do that... and therefore nobody sets anything up in Audio MIDI Setup. It's a chicken-and-egg problem.
Even if there are external devices, your users might want to send MIDI to other endpoints (like virtual endpoints created by other apps) that are not apparently connected to external devices. You should let them do what they want.
The documentation for MIDIGetDevice() makes a good suggestion:
If a client iterates through the devices and entities in the system, it will not ever visit any virtual sources and destinations created by other clients. Also, a device iteration will return devices which are "offline" (were present in the past but are not currently present), while iterations through the system's sources and destinations will not include the endpoints of offline devices.
Thus clients should usually use MIDIGetNumberOfSources, MIDIGetSource, MIDIGetNumberOfDestinations and MIDIGetDestination, rather iterating through devices and entities to locate endpoints.
In other words: use MIDIGetNumberOfDestinations and MIDIGetDestination to get the possible destinations, then let your users pick one of them. That's all.
If you really want to do more:
Given a destination endpoint, you can use MIDIEndpointGetEntity and MIDIEndpointGetDevice to get to the MIDI interface.
Given any MIDI object, you can find its connections to other objects. Use MIDIObjectGetDataProperty to get the value of property kMIDIPropertyConnectionUniqueID, which is an array of the unique IDs of connected objects. Then use MIDIObjectFindByUniqueID to get to the object. The outObjectType will tell you what kind of object it is.
But that's pretty awkward, and you're not guaranteed to find any useful information.
Based on a hint from Kurt Revis's answer, I've found the solution.
The destination that I needed to find is associated with the source of the external device, with the connection between them found using the kMIDIPropertyConnectionUniqueID property of that source.
Replacing the code in the if / else branch in the question with the code below works:
var external = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(external, 0)
var src = MIDIEntityGetSource(entity, 0)
var connID : Int32 = 0
var dest = MIDIObjectRef()
var type = MIDIObjectType.other
MIDIObjectGetIntegerProperty(src, kMIDIPropertyConnectionUniqueID, &connID)
MIDIObjectFindByUniqueID(connID, &dest, &type)
A property dump suggests that the connection Unique ID property is really a data property (perhaps containing multiple IDs) but the resulting CFData appears to be in big-endian format so reading it as an integer property instead seems to work fine.
for the same socket, I want to register two events: one is EPOLLIN and another is EPOLLOUT|EPOLLET.
so for input, I want it to be level trigger and for output I want it to be edge trigger.
ev.data.fd=fd;
ev.events=EPOLLIN;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
ev.events=EPOLLOUT|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
is it possible or not? are there any problems? thanks!
Here's from epoll(7) Questions and answers section:
Q1 What happens if you register the same file descriptor on an epoll instance twice?
A1 You will probably get EEXIST. However, it is possible to add a duplicate (dup(2), dup2(2), fcntl(2) F_DUPFD) descriptor to the same epoll instance. This can be a useful technique for filtering events, if the duplicate file descriptors are registered with different events masks.