Agent Operations

Host agent operations are performed on a single agent state, via HostAgentAPI, the state can be omitted if agents exist within the default state.

FLAMEGPU_HOST_FUNCTION(example_agent_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Retrieve the host agent tools for agent wolf in the hungry state
    flamegpu::HostAgentAPI hungry_wolf = FLAMEGPU->agent("wolf", "hungry");
}

Variable Reductions

Various reduction operators are provided, to allow specific agent variables to be reduced across the population.

HostAgentAPI Reduction Methods

Method

Arguments

Description

sum()

variable

Returns the sum of the specified agent variable.

meanStandardDeviation()

variable

Returns a pair of doubles, the first item being the mean, and the second the standard deviation of the specified agent variable.

min()

variable

Returns the minimum value of the specified agent variable.

max()

variable

Returns the maximum value of the specified agent variable.

count()

variable, value

Returns the number of agents with the specified value of the specified agent variable.

histogramEven()

variable, histogramBins, lowerBound, upperBound

Returns a histogram of the specified agent variable, with evenly spaced bins in the inclusive-exclusive range [lowerBounds, upperBound)

As with most variable operations, these require the variable type to be specified as a template argument (appended to the method name in Python).

The C++ interface optionally allows the output type for sum and histogramEven to be specified as a second template argument too.

// Define an host function called reduce_hostfn
FLAMEGPU_HOST_FUNCTION(reduce_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Reduce for the min, max of the sheep agent's health variable
    float min_health = sheep.min<float>("health");
    float max_health = sheep.max<float>("health");
    // Reduce for the sum of the sheep agent's health variable with the output type double
    double sum_health = sheep.sum<float, double>("health");
    // Count the number of sheep with a health variable equal to 0
    unsigned int empty_health = sheep.count<float>("health", 0.0f);
    // Create a histogram of sheep health
    std::vector<unsigned int> health_hist = sheep.histogramEven<float>("health", 5, 0.0f, 100.001f);
    // Fetch the mean and standard deviation of sheep health
    std::pair<double, double> mean_sd = sheep.meanStandardDeviation<float>("health");
    double mean_health = mean_sd.first;
    double standard_dev_health = mean_sd.second;
}

The C++ API also has access to custom reduction and transform-reduction operations:

// Define a bespoke reduction operator sum
FLAMEGPU_CUSTOM_REDUCTION(sum, a, b) {
    return a + b;
}
// Define a bespoke reduction operator
FLAMEGPU_CUSTOM_TRANSFORM(is_even, a) {
    return static_cast<int>(a)%2 == 0 ? a : 0;
}

// Define an host function called customreduce_hostfn
FLAMEGPU_HOST_FUNCTION(customreduce_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Reduce for the sum of the sheep agent's health variable, the input value is 0
    double sum_health = sheep.reduce<float>("health", sum, 0.0f);
    // Reduce for the sum of the sheep agent's health variable's that are even, the input value is 0
    double sum_even_health = sheep.transformReduce<float, double>("health", is_even, sum, 0.0f);
}

Sorting Agents

Agent populations can also be sorted according to a variable, the C++ API can additionally sort according to two variables.

Note

FLAME GPU 2 may automatically sort agent populations that are outputting spatial messages, as this can significantly improve performance when reading messages.

FLAMEGPU_HOST_FUNCTION(reduce_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Sort the sheep population according to their health variable
    sheep.sort<float>("health", HostAgentAPI::ASC);
    // Sort the sheep population according to their awake variables, those with equal awake variables are sub-sorted by health
    sheep.sort<int, float>("awake", HostAgentAPI::DESC, "health", HostAgentAPI::ASC);
}

Agent Creation

Note

These agents are not created until after the layer has completed execution, so they will not affect reductions or sorts carried out in the same host function.

It’s also possible to create new agents with the HostAgentAPI, this is the preferred method of host agent creation as it performs a single host-device memory copy.

newAgent() returns an instance of HostNewAgentAPI, this can be used like other objects to set and get a new agent’s variables via setVariable() and getVariable(). Additionally, getID() can be used to retrieve the ID which will be assigned to the new agent.

FLAMEGPU_HOST_FUNCTION(CreateNewSheep) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");

    // Create 10 new 'sheep' agents
    for (int i = 0; i < 10; ++i) {
        flamegpu::HostNewAgentAPI new_sheep = sheep.newAgent();
        new_sheep.setVariable<int>("awake", 1);
        new_sheep.setVariable<float>("health", 100.0f - i);
        new_sheep.setVariable<int, 3>("genes", {12, 2, 45});
    }
}

Direct Agent Access

For raw access to agent data, DeviceAgentVector can be used. This has an interface similar to AgentVector (and hence std::vector), however automatically synchronises data movement between host and device. This should only be used in limited circumstances as copying memory between host and device has high latency (although the implementation attempts to minimise unnecessary data transfers).

FLAMEGPU_HOST_FUNCTION(deviceagentvector_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Get DeviceAgentVector to the sheep population
    flamegpu::DeviceAgentVector sheep_vector = sheep.getPopulationData();
    // Set all sheep's health back to 100
    for(auto s : sheep_vector)
        s.setVariable<float>("health", 100.0f);
}

DeviceAgentVector can also be used to create and remove agents. However, this level of interaction with agent populations is discouraged and is likely to impact performance if used regularly (e.g. as a step or host-layer function). The host agent creation method demonstrated above should be used where possible.

FLAMEGPU_HOST_FUNCTION(deviceagentvector_hostfn) {
    // Retrieve the host agent tools for agent sheep in the default state
    flamegpu::HostAgentAPI sheep = FLAMEGPU->agent("sheep");
    // Remove the first agent
    av.erase(0);
    // Add a default initialised agent to the end of the vector
    av.push_back();
    // Initialise the new agent's non-default variables
    av.back().setVariable<float>("health", 50.0f);
    av.back().setVariable<int, 3>("genes", {12, 2, 45});
}

Additionally, syncChanges() can be called, to explicitly push any changes back to device. Allowing changes to impact agent reductions.

Miscellaneous Methods

These other methods are also available within HostAgentAPI for use within host functions:

Method

Return

Description

count()

unsigned int

Returns the number of agents within the selected agent (state) population. Not to be confused with the count() reduction method, this version takes no arguments.