Agent reproduction advanced

Author: Lukas Breitwieser
In the tutorials so far we used Cell::Divide to create new agents. In this demo we want to show how to define your own "process" that creates a new agent. Furthermore, we will explain the purpose of the functions Agent::Initialize and Agent::Update.

Assume that we want to create a new agent type Human which should be able to GiveBirth.

Let's start by setting up BioDynaMo notebooks.

Let's start by creating the ChildBirthEvent. In this example we do not need any attributes.

We continue by defining the class Human which derives from SphericalAgent.

The implementation of GiveBirth only requires two lines of code.

First, creating an instance of the event.
Second, invoking CreateNewAgents function which is defined in class Agent.

The first parameter of CreateNewAgents takes an event object, and the second a vector of agent prototypes. The size of this vector determines how many new agents will be created. In our case: one. If twins should be born we could change it to CreateNewAgents(event, {this, this});.

But why do we have to pass a list of agent pointers to the function?

The answer is simple: we have to tell CreateNewAgents which agent type it should create. In our use case we want to create another instance of class Human. Therefore, we pass the this pointer.

The only part missing is to tell BioDynaMo how to initialize the attributes of the new child. This decision is encapsulated in the Initialize function which we override from the base class. Don't forget to also call the implementation of the base class using Base::Initialize(event). Otherwise the intialization of the base class is skipped.

In our example we define that the child should be created next to the mother in 3D space.

This concludes all required building blocks. Let's try it out!

As expected the simulation consists of two "humans".

Let's take this one step further. Let's assume that class Human was provided in a library that we don't want to modify. However, we want to add two more attributes:

Let's create a new class called MyHuman which derives from Human and which adds these two attributes.

As in the example above, the Initialize method is used to set the attributes during new agent events. In this example, we have to set the mitochondrial dna of the child to the value from the mother. The following function definition does exactly that and prints out the value.

The only task left is to update the attributes of the mother. This is done by overriding the Update method. Again, do not forget to call the implementation of the base class for correctness. We increment the num_offsprings_ attribute by the number of newly created agents. Although we could just have incremented the attribute by one, the solution below is generic enough to handle e.g. twin births.

Let's create a new MyHuman, set its mitochondrial dna to 123 and output the current value of num_offsprings_, which we expect to be 0.

Now we can call GiveBirth again. We expect the output of two lines.

To real_t check, let's output the value of num_offsprings, which we expect to be 1