# Agent Operations

Unlike `Places`, the `Agents` are dynamic entities that can

* Be created dynamically (Spawning)
* Move to another `Place` instance (Migration)
* Be destroyed (Termination)

These operations are controlled with three corresponding APIs: `spawn`, `migrate` and `terminate`.


## Agent Spawning 

An `Agent` instance can spawn new instances on another `Place` instance using the `spawn` method provided in the `Agent` class. This function requires two arguments: 

* `numAgents`: The number of child `Agent` instances to spawn
* `place`: Pointer to the destination `Place` instance to spawn the child `Agent` instances on. 

The second argument can be obtained by first accessing the `Place` instance that the current `Agent` instance resides on, and then accessing the neighbors through the `getNeighborsPtr()` method. Normally, an `Agent` instance should only spawn children on the current `Place` instance or one of the direct neighbors. Though doing that on further neighbors is not prohibited, it is not recommended due to potential undefined behavior at the boundary of a block. 


## Agent Migration

An `Agent` instance can migrate to another `Place` instance using the `migrate` method provided in the `Agent` class. This function requires only one argument, which is the pointer to the destination `Place` instance. Similar to spawning, the argument can be obtained by first getting the current `Place` instance and then accessing the neighbors. 

The `migrate` method only requests the migration, but does not immediately handle the migration. In other words, after calling this method, the agent is still residing on the original `Place` instance. The actual migration process will be handled later after the method calling the `migrate` method returns. 

Note that migration destination can only be direct neighbors of the current `Place` instance that the `Agent` instance resides on. It cannot be the residing `Place` instance itself or instances further away. For the former, the migration will not take any effect, and for the latter, it may lead to undefined behavior at the boundary of a block. 

Due to current limitation in MASS CUDA, the `migrate` function does not guarantee to succeed. If it fails, there can be two cases: 

* The `Agent` instance stays at the original `Place` instance.
* The `Agent` instance becomes "detached", meaning that it's residing `Place` instance is `nullptr`. This situation happens only during cross-device migration where agent array on the destination `Place` instance is full. In this case, currently the only solution is to terminate it immediately. Future work can consider improving this.


## Agent Termination

An `Agent` instance can terminate itself using the `terminate` method provided in the `Agent` class. The method calling this API will not exit immediately after the call, but subsequent `callAll` will not be invoked on this instance. 


## Handling Agent Operations

All the three operations on `Agent` instances will not immediately take any effect on invoking them. Instead, users need to manually invoke the `manageAll` function on the `Agents` instance to actually handle these operations. A normal pattern is first requesting these operations during a `callAll` invocation, and then immediately call `manageAll` to make them take effect. 

```cpp
agents->callAll(MyAgent::Function::RequestSomeOperation);
agents->manageAll();
```