Our simulation of ‘Imprimer la Lumière’ seeks to formalise and represent the dynamic interactions observed in the living experiments. The simulations learn from existing simulation methods, but develop a distinctive multi-agent approach. This allows us to simulate the development of the bacterial colonies and their interactions with their environment as they metabolise nutrition and oxygen. This approach places time at the centre of the simulation. In the simulation, time is abstracted as successive time steps and not represented as measured time. The simulation also abstracts the light performance of the bacteria. Vibrio fischeri’s signal sensitivity has been simulated [21], but does not allow for an understanding of the overall light performance. Capillary effect and surface tension have proved central in our investigations, but these physical phenomena, caused by forces on a molecular level, are too complex to simulate. This paper develops a simplified agent based system operating in voxel matrix correlating the growth rate with the key parameters observed in living experiments: topology, access to oxygen, nutrition level and humidity level.
Voxel simulation for living systems
The simulation is based on a voxel logic. Voxels, often referred to as 3D pixels, are a tool used for abstract spatial representation. Stripped down, they are numerical values arranged in a 3D grid [22]. They provide a simple and intuitive framework, easy to visualise in 3D, where complexity can be gradually added. Our simulation builds a voxelised representation of the host environment; the 3D printed form of the agar media, the integrated pools and the oxygen within the host environment (Fig. 3). As in the physical reference experiment, we start by inoculating everywhere.
The voxels’ position in space is implicit by their placement in the 3D array storing them. Each voxel has variables describing its physical state, including; humidity, nutrient level and oxygen which are calculated in respect to the physical properties; gravity, diffusion and evaporation that produce their interactions.
Each voxel has a number describing the bacteria count of the single voxel, which is a function of the physical state. The simulation operates through a principle of neighbourship. In ‘Imprimer la Lumière’, the voxels interact with each other through its cubic 26 neighbours. For each time step of the simulation the physical conditions and bacteria count of each voxel are updated by defined equations using their previous conditions and their neighbours’ conditions as input. This creates a method of simulating physical and bacterial states in the 3D model over time.
Implementing rules
In our multi agent system we have three agent definitions; medium, liquid broth and air. We chose humidity and nutrient level to be the physical variables describing the condition in each voxel. Since the liquid broth and the agar medium contain different amounts of nutrients and water, and since the bacteria act differently in the two mediums, we split them into two voxel types. The third voxel type, air voxels, are used to define which voxels are on the surface of the media. Bacteria can live in broth voxels and in the agar voxels which are on the surface of the geometry.
The number of bacteria in a medium or liquid broth voxel is set as a relative number between 0 and 1. As we observe a dimmer light in the liquid broth than on the medium, the maximum amount of bacteria is here set to 0.1 instead of 1, representing the stationary phase, where the rate of growth and death are equal [23]. To model propagation in the medium, the bacteria number will double at each time step, as long as there is humidity and nutrition in a voxel. This continues until the population reaches the maximum level. In liquid broth, this propagation doubling is further transferred to each neighbouring broth voxel. In the medium, the bacteria population must reach its maximum before transferring bacteria to neighbours. The bacteria count in each voxel affects and changes the available nutrition state as bacteria delete nutrition across their lifespans. The nutrition state is calculated as the previous amount of nutrient subtracted with the amount of bacteria.
Humidity is the most complicated state to calculate as it is fluid and subject to evaporation, diffusion and gravity. Gravity plays an important role as all our prototypes dry from the highest point and down. We calculate humidity as dependent on the saturation state of each voxel across the time steps. As humidity falls through the medium in time, it passes on humidity to its lower neighbour voxels as long as their state is not at full saturation. The combination of diffusion and gravity is particularly important for simulating the fluid behaviour of the broth. If two neighbouring broth voxels have different humidity levels, humidity will be transferred between them to even out the difference. The rate of evaporation is proportional to the voxels' exposure to air. When a broth voxel dries out it is replaced with an air-voxel and all the nutrients and bacteria are transferred to the voxel underneath.
A second humidity based rule mimics the capillary effect at the edges of the pool. Liquid broth voxels that have at least one horizontal medium voxel neighbour are set to have a lower evaporation rate and no diffusion rate. The voxel will still transfer humidity to lower voxels by gravity. This should ensure that the liquid voxels at the edges of the pools are one higher than the rest of the water surface.
Tuning
Since we are not working with exact physical values and forces, tuning the simulation to real world observations is essential. As the rules and parameters are interconnected, we cannot tune the parameters independently. The observations used for reference for tuning are based on the photographic registration images taken within the incubator (Fig. 4). Here, we can see that the bacterial colonies are largest and strongest 24 h after incubation as nutrition and oxygen levels have not yet been depleted. As these observations are taken from the top view, we have rendered the 3 dimensional voxel model from the same view.
Resolution
During the tuning of the simulation we found that the resolution of the model fundamentally impacts results. The resolution is important both for a recognisable representation of the geometry and the accuracy of the simulation. Running-time is a concern when deciding on the resolution. Since we are working with 3D arrays, the time complexity of the code is O(n^3), which means that doubling the resolution will slow down the runtime 8 times. On the other hand, a higher resolution is important to get realistic results, otherwise small geometrical details might be neglected. During our experiments we found that for our geometries, the resolution of the voxel framework should be high enough for every 3D-printed wall to be minimum 3 voxels thick so that the outer voxels representing the surface are not directly neighbouring the surface on the other side of the wall.
Our initial intention was to prototype and test at low resolution so as to tune and validate the model in respect to observed results, and then increase resolution for verification. This quickly proved ineffective as the system did not scale the same performances. Impediments for scaling were also found in the code basis of our simulations. Initial tests undertaken in the graphical programming environment Rhino/Grasshopper™ were replaced by a new infrastructure using Python with NumPy [24] for both calculation and visualisation. This allowed us to speed up the iterations through the 3D array drastically.
Our designs are informed by the smooth continuous lines that the 3D printing of medium performs best with. This base geometry is incompatible with the orthogonal logic of the voxels, creating a pixelated look. The incompatibility also gives practical issues. Neighbouring surface voxels on a curved wall can have drastically different exposure to air, (Fig. 5), and therefore change humidity level at different timerates. This is evident when looking at the simulation in perspective view where non-verified vertical lines of darkness become observable on an otherwise light surface. To mitigate this we implemented a diffusion rule set, but this complicates the tuning and slows down runtime.
Diffusion
In order to tune the interaction between the liquid pools and their drying, we use several small steps of gravity and diffusion with small coefficients. Diffusion enables us to even out humidity and its drying, but if it is not implemented and tuned correctly, it can give the opposite effect. When using larger coefficients, the system becomes chaotic (Fig. 6). Diffusion at 2% of the difference between the humidity in neighbouring cells has empirically proven to replicate results well. This coefficient has to be tuned with the number of diffusions per timestep. When there are too many diffusion sets in a row without other influences, it creates a chaotic behaviour of self-resonance. We observe similar behaviour when diffusion is applied in areas with low differences between neighbouring voxels. We find that these chaotic behaviours can be mitigated by adding a gravity-update between every diffusion state change.
To allow for a more intuitive understanding of the interactions between bacteria growth rate and light emission, we found that examining the state change of the humidity level in isolation (Fig. 7) allowed us to build an understanding of the growth environment. By validating the performance of the humidity level across the runtime of the model, we were able to save calculation time and consolide parts of the model before looking at the interaction between all parameters.
Representation
For the representation, we used Matplotlib in Python. The colour displayed for each voxel is given by the number of alive bacteria relative to the maximum alive bacteria. The colour cyan (rgb(0, 255, 255)) is used for the maximum light approximating the colour of the emitted light from the bioluminescent bacteria. The colour is set linearly, e.g. a voxel “half full” of bacteria is assigned the colour rgb(0, 127, 127).
A central challenge in the simulation is to represent the transparency of the voxels and the light they emit through neighbouring voxels. In the top view, this is solved by adding the value of light in the whole vertical column (projection). In 3D this calculation is more complex and we therefore settled on generating 3D-views without transparency. As the top view is used as the central validation data corresponding to our photographic recordings we are able to validate the model. However, we observe that the perspective views enable us a better understanding of the interactions in the model. Further research will investigate maximum intensity projection and volume rendering [25] as used in CT and astrophysical data enabling an implementation of an additive logic of light emission.
To increase the visual similarities with the reference photos we use blur and median filters to reduce the pixelated look (Fig. 8). Using libraries for image processing in python enables us to integrate this step as part of the simulation.