Project: Step 4.3
Bacteria with group movements

Disclaimer: the automatically generated English translation is provided only for convenience and it may contain wording flaws. The original French document must be taken as reference!

Objectives: Introduce a new type of bacteria that moves in groups.

The target used to compile and run this part is groupMotilityTest. You must uncomment it when the time comes in the CMakeLists.txt. Note that Ctrl-F allows you to search within the QtCreator editor (to find where groupMotilityTest is located, for example).

The new type of bacteria to be coded at this stage is characterized primarily by a specific mode of movement (in groups): the bacterium closest to nutrient sources will exert an attractive force on the others. This is therefore an example where the force governing movement is not the zero vector!

You are asked here to:

  1. Model a new type of bacteria and its membership in a group (BacteriaGroup) of bacteria of the same type.
  2. Ensure that their movement is governed by a force representing the attraction exerted by the best-positioned bacterium.

Bacteria moving in groups will be represented using a generic class GroupMotilityBacterium. Each of them will belong to a group (BacteriaGroup).

There may be several groups in a culture dish. The difference between one group and another will be based on:

  1. The force exerted by the bacterium closest to the nutrients on the others.
  2. The color of these bacteria.
Each GroupMotilityBacterium will be associated only with its BacteriaGroup.

Let’s start by modeling the concept of a group more precisely.

Create an empty shell for the GroupMotilityBacterium class.

Group

A BacteriaGroup will simply be characterized by:

A BacteriaGroup will be a simulable object whose update method is responsible for updating the “ leader ” bacterium at each simulation step. A BacteriaGroup is not drawable as such.

[Question Q4.11]: A culture dish will now also contain BacteriaGroups that it must evolve. Given that we want to have a Laboratory::addSwarm method that adds a BacteriaGroup (empty of bacteria) to each culture dish and can be called as follows:

getEnv().addSwarm(id)); // id is the string identifying the group
What changes do you make and to which class(es) to integrate this?

Answer this question in your REPONSES file and implement these changes.

The features that can reasonably be expected for the BacteriaGroup are:

  1. Methods for adding or removing a specific GroupMotilityBacterium* from the group.
  2. A method returning the position of the "leader" bacterium.
  3. A "getter" returning the starting color of the bacteria in the BacteriaGroup, via the configuration file (value associated with ["swarms"][mId]["color"] for the BacteriaGroup with identifier mId).
  4. And of course the update method mentioned above.

Feel free to add other methods if necessary.

The GroupMotilityBacterium class

Let’s now complete the GroupMotilityBacterium class outlined earlier. A GroupMotilityBacterium is a Bacterium (it has all the generic characteristics of bacteria). For simplicity, we assume that it knows the BacteriaGroup to which it belongs.

If we start from this assumption, there will be a circular dependency between the classes GroupMotilityBacterium and BacteriaGroup. To break this dependency, you can predefine GroupMotilityBacterium in BacteriaGroup.hpp.

[Question Q4.12]: A GroupMotilityBacterium must have a force governing its movement, just like single bacteria. What relationships do you establish to model this force?

Answer this question in your REPONSES file and implement the empty shell of the GroupMotilityBacterium class by setting up these inheritance relationships.

A GroupMotilityBacterium divides like a Bacterium, but must produce a GroupMotilityBacterium (belonging to the same group as the original bacterium).

Finally, to simplify matters, GroupMotilityBacteriums have no mutable characteristics other than their color.

[Question Q4.13] Given the above, which methods already present in the bacteria class hierarchy must you redefine in GroupMotilityBacterium?

Answer this question in your REPONSES file.

Drawing

A GroupMotilityBacterium will be drawn as a Bacterium. If it is the " leader ", also ensure that in "debug" mode (the isDebugOn function in Application.hpp), a red ring is drawn around it (see the videos below).

You have already drawn rings in CultureDish, for example.

Construction/Destruction

The constructor of a GroupMotilityBacterium will take as parameters its position and a pointer to the BacteriaGroup to which it belongs.

The values needed for initialization can, of course, be found in the configuration file (under ["group motility"] ).

The constructor will be responsible for adding the bacterium to its BacteriaGroup.

We will create the GroupMotilityBacterium by pressing the numeric keys on the keyboard (1, 2 or 3). Pressing the 1 key, for example, will create a bacterium belonging to the BacteriaGroup with the identifier 1. These groups are created at the start of the simulation. Open the test file GraphicalTests/GroupMotilityTest and examine the methods onSimulationStart and onEvent to understand how this all works. There are therefore always 3 groups in the box, but they will remain empty until bacteria are placed in them using the appropriate keys. Be careful, however: your code must be designed in a general way, that is, without assuming that only identifiers 1, 2 or 3 will always exist.

[Question Q4.14] If you examine the onEvent method in the previous program example, you will see that placing a GroupMotilityBacterium requires calling getEnv().addBacteriumToSwarm(id, const Vec2d& position);. The purpose of this method is to add a GroupMotilityBacterium to the current swarm by integrating it into the group with identifier id of that swarm. What do you need to add to your code and where to implement this functionality ?

[Question Q4.15] A GroupMotilityBacterium is therefore added to the box like all the others (it is part of the box’s collection of bacteria). Do you think the BacteriaGroup destructor should do anything?

[Question Q4.16] When a GroupMotilityBacterium dies, it should no longer be counted in its BacteriaGroup. What do you need to add to your code and where to ensure this constraint is met?

Answer these questions in your REPONSES file, justifying your choices.

Drawing on what you've done so far for the other bacteria and taking into account the description above, implement all the features of the BacteriaGroup except for the one related to movement (the move method).

Test 15: Bacteria with Group Behavior

To test this section, you can use the provided test GraphicalTests/GroupMotilityTest.cpp, which can be run using the target groupMotilityTest (which you will have taken care to uncomment in the file CMakeLists.txt).

This test allows you to create bacteria with group behavior using the keys from '1' to '3'.

When the first nutrient source appears, create a bacterium—using the '1' key, for example—by placing it on the nutrient source. This bacterium should immediately appear as the “ leader ” and begin feeding.

Create other bacteria from the same BacteriaGroup (using the same key) on other nutrient sources. You should also be able to observe changes in “ leadership ” depending on the proximity of nutrient sources, as well as phenomena such as division and color mutation.

← Here, the 1 key is used first (green bacteria), followed by the 2 key. The change in "leadership" based on proximity to nutrients should be visible. Color changes can be observed following cell division (facilitated by the prior creation of abundant nutrients).

Group movement

The move method will be coded similarly to what you did in MonotrichousBacterium.

The differences will lie in the following two points:

  1. The force will no longer be the zero vector but the vector coeff_force_swarm * (position_leader - position) where position is the position of the bacterium, position_leader is the position of the " leader " of its group, and coeff_force_swarm is a leader attraction coefficient specific to each BacteriaGroup (value linked to ["swarms"][idBacteriaGroup]["force factor"] in the configuration file).
  2. If the bacterium is the " leader ", once its position has been updated, it will randomly choose a new direction: from among 20 randomly selected options, it will take the one with the best score.
  3. For easily observable group behavior, it is recommended to maintain a constant speed (getAppConfig()["group motility"])["speed"]["initial"].toDouble()). The velocity vector will then simply be this constant speed multiplied by the direction vector.

Test 16: Grouped Movement

To test this part, you can use the same test as before.

This test allows you to create bacteria with group behavior using the keys '1' to '3'.

Delay the generation of nutrients by adjusting the parameter ["generator"] ["nutrient delay"], then:

  1. When the first nutrient source appears, create a bacterium—using the '1' key, for example—and position it near the nutrient source. This bacterium should immediately appear as the “ leader ” and head toward the source.
  2. Then create other bacteria from the same BacteriaGroup (using the same key). They should follow the “ leader ”.

You should also be able to observe changes in “leadership” depending on proximity to nutrient sources, as well as all other expected behaviors (disappearance, division, color change, etc.)

← Here, the 1 key is used first (green bacteria), followed by the 2 key. The simulation is slowed down, with relatively few nutrients, to allow for better observation of the movement dynamics. Under faster conditions with more nutrients, divisions should be observable, as in the previous video.

Final Tweaks

You recently learned that destructors must be virtual when used polymorphically.

Review the existing destructors in your code in light of this advice (if you don’t see the point of this, ask us questions ;-))


Back to the project description (Part 4)