Create Agents#
Agents is a set of autonomous entities moving around and interacting with the environment during the simulation. Unlike Places, it is not a grid, but a big array of instances where some of them are “alive” while the others are “dead” (i.e.: still present in memory but will not participate in simulation). It is optional for a simulation and should always be associated with a Places instance. Each individual entity, called an Agent instance, should always reside on a Place instance.
Define Custom Agent Class#
Similar to Places, before instantiating an instance of Agents, we need to first define the behavior of each Agent instance in the simulation by defining a class inheriting from mass::Agent, which requires implementing the following methods:
The constructor. It always takes in a
mass::Indexrepresenting the flattened local index of this instance in the block, which should be passed to the base class constructor. Usually the body of the constructor should be empty since all the attributes are not created at this time. It should be decorated with__universal__.The
callMethod. This method is called when thecallAllmethod is invoked to thePlacesinstance. It is responsible for dispatching method invocation requests to the actual member method based on the givenmass::FunctionIdand the arguments asvoid*. Typical implementation of this method is using a bigswitchstatement on theFunctionId. It should be decorated with__device__.
For better identifying the custom methods and dispatch invocation requests in callMethod, it is recommended to use an enum as their identifier (the FunctionId).
#include <mass/Agent.h>
class MyAgent final : public mass::Agent {
public:
__universal__ explicit MyAgent(const mass::Index localIndex) : mass::Agent(localIndex) {}
enum Function {
FUNC1, FUNC2
};
__device__ void callMethod(const mass::FunctionId functionId, void*const args) {
switch (functionId) {
case FUNC1: func1(); break;
case FUNC2: func2(*static_cast<const int*>(args)); break;
default: break;
}
}
__device__ void func1() {}
__device__ void func2(const int arg) {}
};
Instantiate Agents Instance#
With the custom Agent class defined, we can create an instance of Agents using the defined MyAgent class. This is done using the mass::makeAgents function, which takes in the integer handle of the created Agents instance and a configuration instance of type mass::AgentsConfig. The integer handle can be any value as long as it is unique among all Agents instances in the same simulation. As for the AgentsConfig structure, it contains the following options.
Note that since an Agents should always be associated with a Places instance, we should always create the Places instance first before creating an Agents.
AgentsConfig::associatedPlacesHandle#
The integer handle of the Places instance that this Agents instance will be associated with. This is a required option since an Agents should always be associated with a Places instance. Typical ways to configure this option is first using the getHandle method on the Places instance the created Agents will be associated to, and then pass it to AgentsConfig::associatedPlacesHandle.
AgentsConfig::initialAgentsConfig#
The configuration for the initial set of alive Agents instances. This can be either a single integer or a span of mass::Index.
If a single integer $N$ is provided, it means that there will initially be $N$ alive
Agentinstances activated, which will be assigned to thePlaceinstances in a round-robin fashion. In other words, the firstAgentinstance is assigned to thePlaceinstance with flatten index 0, the secondAgentinstance is assigned to thePlaceinstance with flatten index 1, and so on, wrapping around when the lastPlaceinstance is reached.If a
spanofmass::Index$S$ is provided, it means that there will initially be $|S|$ aliveAgentinstances activated where the $i$-thAgentinstance will be assigned to thePlaceinstance with flatten index $S[i]$. In other words, the first agent instance assigned to thePlaceinstance with index $S[0]$, the second agent instance assigned to thePlaceinstance with index $S[1]$, and so on.
AgentsConfig::globalAgentSlotCount#
An integer value specifying the total number of slots for Agent instances. In other words, the maximum number of alive Agent instances that can be activated during the simulation. It should be larger than the number of initial alive agents configured in AgentsConfig::initialAgentsConfig