phd-thesis-en/partie-otb.tex

2230 lines
117 KiB
TeX
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\chapter{Travelling Bacteria}\label{chap:partie-otb}
\minitoc
\begin{figure}[h]
\centerline{%
\includegraphics[width=19cm]{figures/otb2-display}}
\caption{Fenêtre de rendu du logiciel \tb{} lors d'une simulation comportant
un grand nombre de bactéries. Les cadres jaunes indiquent l'espace
actuellement occupé par les bactéries et leur support}
\label{fig:otb2-display}
\end{figure}
\clearpage
\section*{Préliminaires}
Voici quelques notations utilisées dans ce chapitre:
\begin{itemize}
\item $(G,+)$ est le groupe engendré par l'ensemble $G$ et la loi $+ : G \times
G \rightarrow G$.
\item $\langle G \rangle$ est le groupe libre engendré par l'ensemble des
générateurs $G$.
\item $\mathbb{N}_+$ est l'ensemble des entiers naturels privé de $0$.
\item $\lfloor x \rfloor = \text{max} \{ m \in \mathbb{Z} \,|\, m \leq x \}$ est
la fonction partie entière de $x \in \mathbb{R}$.
\item $\orr{u}$ est un vecteur,
\item $\|\orr{u}\|$ est la norme euclidienne du vecteur $\orr{u}$,
\item $k \cdot\orr{u}$ est le produit scalaire entre un scalaire $k$ et un
vecteur \orr{u},
\item $\orr{u}\cdot\orr{v}$ est le produit scalaire entre deux vecteurs \orr{u}
et \orr{v},
\item $\orr{u}\wedge\orr{v}$ est le produit vectoriel entre deux vecteurs
\orr{u} et \orr{v}.
\item $\left[ x \right]^{x_{\mathit{max}}}_{x_{\mathit{min}}}
= \left\{ \begin{array}{ll}
x_{\mathit{max}} & \text{si}\; x > \mathit{max}\\
x_{\mathit{min}} & \text{si}\; x < \mathit{min}\\
x & \text{sinon}
\end{array}
\right.$ est la fonction \emph{clamp}.
\end{itemize}
\section{Simuler la morphogenèse des populations}
En tant que science expérimentale, la recherche en biologie cellulaire et
moléculaire nécessite d'important moyens matériels afin de tester \emph{in
vivo} les hypothèses formulées par les chercheurs. Notamment, la préparation
et l'exécution d'une expérience est…
\begin{itemize}
\item consommatrice en temps. Il faut parfois attendre que les cultures d'un
organisme particulier atteignent l'état désiré\footnote{cf. le projet
\synbiotic};
\item consommatrice en ressources. Maintenir les conditions de pression,
d'humidité, de température, d'acidité, d'oxygénation, etc. nécessite du
matériel onéreux;
\end{itemize}
D'un côté, de par les moyens engagés, il est difficile d'envisager de tester des
hypothèses très prospectives ou bien de se faire une idée du résultat probable
d'une expérience quand beaucoup d'entités interagissent. D'un autre, un plan
d'expérience comprend idéalement un nombre minimum nécessaire d'expérimentations
pour valider ou infirmer une hypothèse du modèle, ce nombre pouvant néanmoins
rester élevé au regard des moyens à disposition. La simulation informatique
permet, à partir d'un modèle donné, de confirmer ou de rejeter rapidement une
hypothèse, ce qui peut aider à choisir quelles expérimentations effectuer. Dans
ce cas c'est un outil d'aide à la décision. Si la simulation est suffisamment
précise, comme dans la cas de la simulation de la motilité de quelques bactéries
\Ecoli{} \cite{bray_chemotactic_2007}, elle pourrait même se substituer en
partie à l'expérimentation \emph{in vivo}; on parlera dans ce cas
d'expérimentation \emph{in silico}.
Nous nous intéressons au problème de la \emph{morphogénèse} c'est à dire à
l'ensemble des lois qui déterminent les étapes de la forme, de la structure des
tissus, des organes et des organismes. Les organismes multicellulaires sont le
fruit d'un grand nombre de divisions cellulaires successives et qui donnent lieu
à l'apparition d'une forme et de fonctionnalités caractéristiques et
reproductibles. Comprendre la morphogénèse est un enjeu fondamental pour la
biologie synthétique (voir à ce propos la section~\ref{sec:synbiotic}).
Pour répondre à ce problème et dans le cadre du projet \synbiotic, nous avons
développé \tb{}, un simulateur des interactions d'une population de bactéries
\ecoli{} au cours de sa croissance. \tb{} permet de suivre une cellule ou une
sous partie de cette population au cours du temps de manière similaire aux
conditions expérimentales et ainsi de tester des hypothèses à l'échelle de la
population dans le domaine de la biologie synthétique.
\subsection{Propriétés attendues}
Dans le but de fournir aux biologistes le moyen d'expérimenter \emph{in silico}
la validité d'un modèle concernant l'évolution d'une population de bactéries
\ecoli{}, nous avons dressé une liste de propriétés nécessaires.
\begin{description}
\item[Sorties] Le simulateur permet de recueillir des résultats qualitatifs via
un affichage graphique, reprenant la métaphore de la boîte de Petri qui
permettra d'identifier la forme de la population en croissance. Il est
possible de marquer une sous-partie de la population pour la suivre plus
facilement. Le simulateur permet de recueillir des résultats quantitatifs, tel
que le nombre et la position des bactéries dans un fichier texte pour
traitement ultérieur, par exemple pour la reconnaissance automatique de forme,
ou des calculs statistiques;
\item[Entrées] Les conditions initiales de la simulation sont décrites par un
fichier de configuration dans un langage dédié; au delà des conditions
initiales de l'expérience, il permettra au moins de fixer quelques paramètres
du rendu graphique ou textuel, comme la couleur de représentation des
morphogènes et des bactéries, et de sélectionner quelles informations
quantitatives seront écrites pendant la simulation;
\item[Précision] Le simulateur reprend aussi fidèlement que possible les
connaissances actuelles sur l'aspect mécanique (croissance et collision des
bactéries) et sur l'aspect chimique (réaction et diffusion de morphogènes).
Une étape de calibrage sera donc nécessaire par rapport à des comptes rendus
d'expériences \emph{in vivo};
\item[Efficacité] Le simulateur est suffisamment efficace pour être utilisable
sans matériel spécifique; par exemple, passer d'une bactérie à une population
de l'ordre de $10^4$ bactéries, soit un temps réel d'environ de
\SI{4}{\hour}\SI{30}{\minute}, nécessitera un temps de simulation
correspondant de l'ordre de l'heure sur un ordinateur portable contemporain,
moins encore sur une machine spécialisée;
\item[Autonomie] Les résultats sont accessibles sans la nécessité de faire
fonctionner le simulateur sur une grille de calcul, un tel matériel ne servira
qu'à réduire le temps de simulation afin d'effectuer un plan d'expérience plus
rapidement;
\item[Scalabilité] Malgré les points précédents, \tb{} passe à l'échelle et peut
s'adapter à une machine de calcul dédiée ou à une grille de calcul distribuée;
plusieurs instances du simulateur peuvent être lancées de manière concurrente;
\item[Adaptabilité] Il est possible d'ajouter à \tb{} de nouvelles
fonctionnalités avec peu d'effort: l'architecture du simulateur est modulaire
et vient avec une documentation claire;
\item[Stabilité] Comme une simulation complexe peut prendre plusieurs heures, il
est important que le simulateur ne produise pas d'erreur en cours de
fonctionnement, autrement dit \tb{} est stable; d'une part le langage utilisé
apportera des garanties de part des vérifications du système de type, d'autre
part des tests fonctionnels permettront de valider le fonctionnement correct
de chaque partie du simulateur;
\item[Ouverture] Le simulateur est un programme informatique ouvert, son code
source peut-être téléchargé en ligne, compilé, amélioré et redistribué,
modifié ou non;
\end{description}
\subsection{\ocaml} % Adaptabilité, stabilité
Pour répondre aux critères \emph{d'adaptabilité} et de \emph{stabilité},
nous avons choisi d'implémenter \otb avec le langage \ocaml, un langage de
programmation fonctionnel, statiquement typé, modulaire et interfaçable avec
le langage C. \ocaml est à la fois un projet académique avec de solides
bases théoriques, notamment utilisé comme langage d'implémentation de
l'assistant de preuve Coq\footnote{cf. la page «à propos» du projet Coq
\url{https://coq.inria.fr/about-coq}}, et aussi un langage industriel ayant à
son actif de belles réussites comme l'analyseur statique \textsc{Astrée} en
usage chez Airbus.
\paragraph{Langage de programmation fonctionnel}
La programmation fonctionnelle est issue du $\lambda$-calcul, un modèle de
calcul mathématique reposant sur des variables, des applications et des
abstractions regroupées sous le nom de \emph{$\lambda$-termes}.
Dans le modèle du $\lambda$-calcul, la règle centrale pour le calcul des
$\lambda$-termes est la \emph{substitution} dont les deux principaux
représentants sont l'$\alpha$-conversion et la $\beta$-réduction. Le calcul de
nouveaux $\lambda$-termes s'effectue par un système de réécriture. C'est ce
modèle de calcul qui a donné lieu au paradigme de la programmation
fonctionnelle. Par extension, les langages de programmation fonctionnelle purs
ont la particularité de considérer la programmation d'un algorithme comme une
composition de fonctions s'appelant les unes les autres plutôt que comme une
suite d'instructions qui agissent par effet de bord, c'est-à-dire en modifiant
l'état de la mémoire. Ils se dissocient de la vision de la machine à état comme
support de programmation en adoptant un style plus mathématique dans leur
écriture, proche de la réécriture des $\lambda$-termes. \ocaml dispose ainsi
\begin{itemize}
\item de structures de contrôle comme le filtrage par motif,
\item de clôtures, qui sont des définitions de fonction accompagnées de leur
environnement lexical, analogues des $\lambda$-termes et
\item permet de définir des fonctions d'ordre supérieur, c'est-à-dire aux
fonctions pouvant avoir des fonctions en argument et pouvant retourner des
fonctions comme résultat.
\end{itemize}
Un paradigme de programmation influe sur la syntaxe et la sémantique du langage,
et comme \ocaml est un langage multiparadigme, empruntant aux paradigmes
de la programmation fonctionnelle, de la programmation impérative et de la
programmation orientée objet, il hérite de leurs aspects. \ocaml dispose d'un
ramasse-miette efficace qui gère la désallocation de la mémoire quand celle-ci
n'est plus utilisée sans l'intervention de l'utilisateur. Ceci fait de \ocaml
un langage de programmation de haut niveau. Comme nous le présentons ci-après,
\ocaml est de plus un langage fonctionnel fortement et statiquement typé.
\paragraph{Typage fort et typage statique}
Les types ont d'abord été introduit en logique combinatoire et dans le
$\lambda$-calcul dans les années 1930. Ils ont depuis eu un fort impact en
informatique: ils sont utilisés comme une abstraction d'un programme et
permettent d'en vérifier certaines propriétés, comme par exemple garantir que le
résultat d'une fonction appartient à un ensemble d'éléments connus. Dans le
langage C, un langage bas niveau proche de l'expression d'un processeur, les
types décrivent la taille de la représentation machine et les règles de
conversion d'une valeur du langage. En \ocaml, les types sont plutôt utilisés
pour modéliser les données du programme. \ocaml permet de déclarer des types
algébriques récursifs permettant par exemple de décrire la structure de listes
\begin{OCAMLcode}
type 'a list =
Nil
| Cons of 'a * 'a list
\end{OCAMLcode}
ou d'arbres binaires
\begin{OCAMLcode}
type 'a tree =
Leaf of 'a
| Node of 'a tree * 'a tree
\end{OCAMLcode}
\ocaml présente un typage fort. On distingue un typage fort d'un typage faible
par la manière dont s'effectue la transformation d'un type en un autre: plus
elle est explicite plus c'est un typage fort, moins elle explicite moins c'est
un typage faible. Autrement dit, plus un langage est fortement typé, plus il est
difficile de transformer un type en un autre. Dans le langage C, un opérateur
appelé \emph{cast} permet aisément de transformer presque n'importe quel type en
un autre. En \ocaml, cette transformation n'est pas possible dans le cadre de
fonctionnement normal du langage, donc \ocaml est plus fortement typé que C et
le système de type d'\ocaml est par conséquent plus riche. Le code source d'un
programme \ocaml est typé statiquement, c'est à dire que toutes les
annotations de type sont connues avant la compilation. À l'opposé, dans le cas
d'un typage dynamique, certaines informations de type peuvent ne pas être
connues avant la compilation, peuvent rester après la compilation et peuvent
évoluer durant l'exécution du programme.
\ocaml utilise un typage statique et fort et les annotations de type sont
utilisées à la compilation pour permettre au compilateur de détecter les erreurs
de types avant l'exécution du programme, ce qui apporte quelques garanties
concernant le comportement. Par exemple, les types nous permettent d'apporter
des informations supplémentaires que le compilateur peut prendre en compte.
Déclarer les types
\begin{OCAMLcode}
type nom = Nom of string
type prenom = Prenom of string
\end{OCAMLcode}
permet au compilateur de distinguer deux chaînes de caractères identiques, mais
dont le sens est différent, ce qui est représenté par deux types différents.
\paragraph{Modularité native}
Lors de la rédaction d'un programme, il est vite nécessaire de «compartimenter»
le code source, d'abord parce que certaines fonctionnalité sont génériques et
peuvent être utilisées plusieurs fois dans des contextes différents, mais aussi
pour des raisons de relecture et de segmentation de l'espace de noms. La
\emph{modularité} consiste à rassembler les fonctionnalités d'un programme dans
des modules \emph{indépendants} et \emph{interchangeables}. En \ocaml, la
modularité est une caractéristique native du langage dans la gestion du code
source et repose sur trois constructions syntaxiques: les \emph{structures}, les
\emph{interfaces} et les \emph{modules}. Les structures contiennent
l'implémentation des modules, les interfaces décrivent les valeurs qui en sont
accessibles — les valeurs dont l'implémentation n'est pas exposée sont des
valeurs abstraites, et celles qui n'apparaissent pas du tout dans
l'implémentation du module sont inaccessibles. Un module peut avoir plusieurs
interfaces — du moment qu'elles sont toutes compatibles avec les types de
l'implémentation — et plusieurs modules peuvent vérifier une même interface.
Enfin, \ocaml dispose de modules paramétriques nommés \emph{foncteurs} qui
sont des structures paramétrées par d'autres structures.
% http://caml.inria.fr/pub/docs/manual-ocaml/intfc.html
\paragraph{Interface avec le langage C}
Un aspect important pour les besoins du cahier des charges (voir
\ref{ss:req-parallel}) est de pouvoir communiquer avec des objets compilés C via
une interface dédiée, typiquement des bibliothèques écrites et compilés dans ce
langage. \ocaml propose une interface claire avec des bibliothèques
logicielles écrites en C, permettant d'empaqueter des valeurs dans des types
\ocaml conservant les avantages d'un typage fort, de dépaqueter des valeurs
typées de \ocaml vers un type C arbitraire et surtout de profiter de la
gestion automatique de la mémoire par le ramasse-miette de \ocaml.
\subsection{Calcul parallèle} % Efficacité et Autonomie
\label{ss:req-parallel}
Notre simulateur calcule l'évolution d'un grand nombre d'objet de même nature
simultanément. Pour répondre aux critères \emph{d'efficacité} et
\emph{d'autonomie} nous avons le choix d'utiliser un GPU, le processeur dédié
des cartes graphiques, ou bien d'utiliser un cluster: une grappe de serveurs
interconnectés sur le réseau local. En prenant le nombre d'opérations en virgule
flottante par seconde, notée \si{FLOPS}, comme référence de la vitesse d'un
ordinateur, utiliser le parallélisme embarqué dans les GPU semble être la bonne
manière d'atteindre des vitesses de calcul élevées. Nous nous appuyons sur le
fait que plus de la moitié des 500 supercalculateurs les plus rapides au monde
sont construit sur NVidia
Kepler\footnote{\url{https://www.top500.org/statistics/list/}}, un GPU. Les GPU
grand public sont accessibles en terme de prix, leur consommation est
suffisamment faible pour fonctionner sur batterie dans un PC portable et les
plus puissants atteignent les \SI{10000}{\giga FLOPS}\footnote{%
\url{https://www.nvidia.com/en-us/geforce/products/10series/titan-x-pascal}\\
Par exemple, la carte graphique NVidia Titan X possède \num{3584} cœurs
de calculs, cadencés à \SI{1417}{\mega\hertz} pour un prix avoisinant les
\num{1200} euros}.Enfin,
le parallélisme des GPU semble être plus efficace énergétiquement par rapport
aux CPU en comparant leur \si{\giga FLOPS} par Watt~\cite{dong_step_2014}.
%parallélisme SIMD OpenCL
\paragraph{SIMD}
La taxinomie de Flynn~\cite{flynn_computer_1972} classifie différentes
architectures d'ordinateur et comporte quatre catégories selon le type
d'organisation du flux de données et du flux d'instructions. Le modèle de
programmation le plus répandu repose sur l'architecture de Von Neumann, ce qui
correspond à la catégorie \emph{Single Instruction Single Data} (SISD). Les
ordinateurs de cette catégorie n'exploitent aucun parallélisme et sont purement
séquentiels, tant au niveau des instructions qu'au niveau de la mémoire. Ce
modèle de programmation ne correspond pas à la réalité des processeurs
contemporains qui exploitent le parallélisme des données (plusieurs banques de
mémoire RAM) ou d'instructions grâce à plusieurs processeurs à plusieurs cœurs.
À l'extrême opposé de la classification se trouvent les architectures
\emph{Multiple Instruction on Multiple Data} (MIMD), puis les architectures
\emph{Multiple Instructions on Single Data} (MISD). Dans le cas des MISD, des
problèmes de concurrence à la lectureécriture apparaissent et il est d'usage
d'avoir recours à des barrières de synchronisation, des sémaphores ou des Mutex.
SPMD, \emph{Single Program on Multiple Data}, est la technique la plus courante
pour utiliser le parallélisme des ordinateurs multiprocesseurs contemporain, où
chaque processeur exécute un programme distinct et possède sa propre mémoire, en
plus de partager une mémoire globale, la RAM. Finalement, dans les ordinateurs
contemporains, il existe, en complément d'un CPU et d'une mémoire partagée, des
cartes de calcul dédiées, comme des cartes graphiques, spécialisées dans le
calcul vectoriel, capable d'effectuer des opérations rapides sur des grandes
matrices. L'architecture d'une carte graphique, munie d'un GPU et d'une mémoire
RAM entre dans la catégorie \emph{Single Instruction on Multiple Data} (SIMD).
Ces processeurs sont spécialisés dans le traitement en parallèle d'un grand
nombre de données. Depuis la taxinomie de Flynn, d'autres types de Nous avons
choisi de tirer parti du parallélisme disponible sur l'ordinateur où est exécuté
\tb{}, qu'il provienne de plusieurs CPU ou d'une carte graphique.
\paragraph{\opencl}
Afin d'accéder aux périphériques présent sur la plateforme de simulation et de
les programmer, nous utilisons \opencl (Open Computing Language), un framework
pour l'écriture de programmes s'exécutant sur des plateformes hétérogènes:
microprocesseurs (CPU), processeurs graphique (GPU), processeurs de signal
numérique (DSP), réseau de portes programmables in situ (FPGA) ou autre carte
accélératrice. \opencl spécifie un langage de programmation, inspiré de C99,
pour la programmation de ces périphériques ainsi que des interfaces de
programmation (API) pour le contrôle de la plateforme et l'exécution des
programmes sur les périphériques. \opencl fournit une interface standard pour
la programmation parallèle utilisant le parallélisme de tâche et le parallélisme
de données. Il existe d'autres framework pour la programmation des GPU, comme
CUDA\footnote{\url{http://www.nvidia.com/object/cuda_home_new.html}}, cependant
l'avantage de \opencl est qu'il est le seul langage pour le GPGPU (General
Purpose computing on Graphics Processing Unit) à ne pas être restreint à une
seule plateforme. En effet, il fonctionne sur une large gamme de matériel et, au
contraire de CUDA, ne se limite pas à un seul constructeur, ni à un seul type de
périphérique. \opencl est un standard ouvert maintenu par Khronos
Group\footnote{\url{https://www.khronos.org/about}}, un consortium technologique
à but non lucratif. De nombreux constructeurs fournissent une implémentation
officielle, comme AMD, Intel et Nvidia les principaux constructeurs de CPU et de
cartes graphiques grand public.
\paragraph{\opengl} % Sorties
Pour répondre au point «Sortie», nous avons choisi d'utiliser \opengl (Open
Graphics Library), une API multiplateforme, multilangage utilisée pour
programmer un GPU spécifiquement pour un rendu graphique. Dans le modèle de
programmation de \opengl, un ensemble de vecteurs dans l'espace en trois
dimensions sont successivement transformés pour obtenir une projection en deux
dimension rastérisée. Le programmeur écrit des programme de traitement, des
shader, qui viennent se brancher à différents points de la chaîne de traitement
graphique. À l'inverse de \opencl, \opengl est optimisé pour le calcul vectoriel
et n'est pas approprié pour effectuer des calculs généraux sur les GPU. Cette
bibliothèque logicielle nous permet de proposer une ou plusieurs fenêtre
de rendu en temps réel pour présenter des informations qualitatives sur la
progression d'une simulation.
\subsection{Modélisation d'une cellule}
\begin{figure}[t]
\centering
\includegraphics[height=6cm]{figures/EscherichiaColi}\hfill
\includegraphics[page=1,height=6cm]{figures/bacteria}
\caption{Une image d'une microscopie électronique à balayage d'une culture de
\ecoli\ (à gauche) et une représentation simplifiée en deux dimensions d'une
bactérie \ecoli\ (à droite)}
\label{fig:ecoli}
\end{figure}
\Ecoli\ est une bactérie bacillaire, c'est à dire en forme de bâtonnet, du genre
\emph{Escherichia}. C'est une bactérie vivant habituellement dans l'intestin des
animaux à sang chaud, dont elle constitue 0,1\% de la flore intestinale.
Découverte en 1885 par Theodor Escherich et étudiée intensivement depuis 60 ans,
c'est un organisme très utilisé dans le domaine de l'ingénierie biologique et de
la microbiologie industrielle, notamment pour sa disponibilité et sa facilité de
culture. La souche K-12, adaptée à l'étude en laboratoire, est également un des
premiers organisme dont le génome a été séquencé \cite{blattner_complete_1997}.
Elle est à l'origine du domaine de la biotechnologie en étant choisie comme
premier organisme génétiquement modifié contenant de l'ADN recombiné, c'est à
dire de l'ADN dont la séquence des nucléotides à été altérée pour modifier
l'expression des gènes de la bactérie. Elle est ensuite utilisée comme hôte pour
la production de protéines hétérologues (provenant d'un autre organisme),
notamment pour la production industrielle d'insuline humaine
\cite{goeddel_expression_1979} mais aussi de vaccins. \ecoli{} est utilisée en
bioremédiation pour la neutralisation de déchets toxique ou la dépollution des
sites contaminés et pour la production d'enzymes. Les efforts de recherche se
concentrent actuellement sur la synthèse par \ecoli{} de protéines plus
complexes comprenant par exemple des ponts bisulfure ou nécessitant une
modification post-traductionnelle pour être stables ou bien juste
fonctionnelles~\cite{han_escherichia_2006}.
\begin{table}[hb]
\centering
\begin{tabular}{llll}
\hline
\textbf{Paramètre} & \textbf{Symbole} & \textbf{Valeur} & \textbf{Unité}\\
\hline
Longueur & $L = 2 (l+r)$ & \num{2.5+-0.6} & \si{\micro\meter} \\
Largeur ou Diamètre & $d = 2r$ & \num{0.88+-0.09} & \si{\micro\meter} \\
Volume & $V$ & \num{1.4} & \si{\femto\liter} \\
Vitesse rectiligne & $v$ & \num{29+-6} & \si{\micro\meter\per\second} \\
Temps de génération & $G$ & 20 — 30 & \si{\minute} \\
\hline
\end{tabular}
\caption{Quelques ordres de grandeur associés aux bactéries \Ecoli{}
\cite{bremer_modulation_1996,darnton_torque_2007}%
\cite{britanica_online_encyclopedia_bacteria_2016}}
\label{tab:ecoli-odg}
\end{table}
\paragraph{La chimiotaxie de \Ecoli}
Comme la plupart des bactéries bacillaires, \ecoli{} possède une ciliature
péritriche: elle est assortie de longs flagelles elliptiques, quatre en moyenne,
recouvrant sa surface qui sont utilisés comme moteur de son déplacement. Ces
flagelles sont fixés à leur base à un moteur rotatif réversible entraîné par un
flux de protons et tournent sur eux-mêmes à une fréquence de l'ordre de
\SI{100}{\hertz}. Suivant le sens de leur rotation, sens direct (CCW pour
Counter ClockWise) et sens indirect (CW pour ClockWise), ils sont à l'origine de
deux modes de déplacement:
\begin{itemize}
\item le mode «run», les moteurs tournent dans le sens direct et les flagelles
se regroupent pour propulser la bactérie dans une direction rectiligne. Il
dure en moyenne \SI{1}{\second};
\item le mode «tumble», au moins un des moteurs tourne dans le sens indirect.
Les flagelles se désolidarisent ce qui a pour effet moyen de faire tourner la
bactérie sur elle-même dans le sens horaire \cite{diluzio_escherichia_2005}.
Ce mode dure en moyenne \SI{0,1}{\second}.
\end{itemize}
Ces deux modes de déplacement alternent successivement et, en fonction de
l'environnement de la bactérie, les amènent à migrer vers des environnements
favorables, riches en nutriments et à fuir les environnements toxiques et
délétères \cite{berg_chemotaxis_1972}.
Ce phénomène s'appelle la \emph{chimiotaxie}. Il résulte de la transmission
de signaux extracellulaires, détectés par les récepteurs de la membrane, aux
moteurs des flagelles qui contrôlent le comportement de la cellule.
D'un point de vue macroscopique, \ecoli{} effectue une marche aléatoire
biaisée vers une direction particulière. Elle détecte la variation
\emph{dans le temps} de la concentration d'un chimioeffecteur. Ainsi, lorsque
la bactérie se dirige vers un milieu plus favorable, les réorientations par
tumble deviennent plus rares et la bactérie peut remonter le gradient de la
concentration d'une molécule qui se diffuse dans l'environnement. Entre deux
run, \ecoli{} peut complètement changer de direction, avec un angle allant
jusqu'à 180°, le plus souvent entre 0° et 90° \cite{turner_real-time_2000}.
D'un point de vue microscopique, \ecoli{} peut détecter différents acides
aminés, sucres et dipeptides ainsi que l'acidité, la température et l'état
d'oxydoréduction.
Les récepteurs principaux, comme ceux de l'aspartate (Tar)
et de la sérine (Tsr), sont très nombreux et sont aux nombre de quelques
milliers par cellule. Les récepteurs secondaires, comme ceux spécifiques aux
dipeptides (Tap), ribose et galactose (Trg), et au potentiel d'oxydoréduction
(Aer), sont bien moins nombreux avec seulement une centaine de copies par
cellule. Ces récepteurs se regroupent en amas, ce qui induit des dynamiques
complexes dans la détection de chimioeffecteurs \cite{sourjik_receptor_2004},
impliquant soit une plus grande sensibilité ou au contraire une plus grande
diversité de détection.
Dans le réseau de régulation génétique, parmi les voies de signalisation
de la cellule, la voie de réponse chimiotaxique consiste donc en un ensemble
de protéines réceptrices transmembranaires sus-citées et les produits de six
gènes chimiotaxiques: CheR, CheB, CheW, CheA, CheY et CheZ. L'information sur
la liaison de ligants bénéfiques ou nocifs aux récepteurs est transportée
jusqu'au moteur des flagelles ce qui leur permet de changer le sens de rotation
du moteur. Il existe plusieurs modèles stochastiques capables de simuler
en détail la cascade d'évènements entre la liaison d'un chimioeffecteur
à un récepteur jusqu'au biais des moteurs \cite{shimizu_spatially_2003,
mello_quantitative_2003}.
\paragraph{Modèle de croissance}
\ecoli\ suit un modèle de croissance linéaire
\cite{zaritsky_growth_1982,kubitschek_cell_1990} par élongation et bien que son
diamètre décroisse avec l'élongation, cette variation reste négligeable quand
$L$ est suffisamment grande \cite{trueba_changes_1980,skarstad_cell_1983}. Nous
considérerons donc que seule sa longueur $L$ (voir \textsc{Fig.}~\ref{tab:ecoli-odg})
varie lors de la croissance d'une bactérie. Comme toutes les cellules
procaryotes, \ecoli{} se reproduit par scissiparité. Ce cycle de division
implique:
\begin{enumerate}
\item La réplication de la molécule d'ADN circulaire au sein de la cellule;
\item La migration après duplication des deux brins d'ADN à chacun des pôles de
la cellule;
\item La croissance de la cellule pour laisser la place à un matériel génétique
plus volumineux;
\item Le plan équatorial de la cellule se resserre et fini par scinder la
membrane en deux, de sorte que chaque nouvelle cellule fille ait le même
matériel génétique.
\end{enumerate}
L'équation \ref{eq:generation-time} présente le calcul du temps de génération
pour une population de bactéries dont la croissance s'effectue par division
binaire, où $t$ est le temps en minutes, $n$ est le nombre de générations, $B$
est le nombre de bactéries au début de la période de temps mesurée et $b$ est le
nombre de bactéries à la fin de la période de temps mesurée. Cela permet aux
biologistes de retrouver le temps moyen d'un cycle cellulaire pour la population
observée.
\begin{equation}
\displaystyle
G = \frac{t}{n} = \frac{t}{3,3 \times ln (b / B)}
\label{eq:generation-time}
\end{equation}
\paragraph{Vieillissement et mort cellulaire}
Il semble que les bactéries se scindant en deux bactéries filles en tout point
identiques atteignent une sorte d'immortalité, au moins fonctionnelle. Néanmoins
quand elle n'est pas tuée par des antibiotiques, par manque de nutriments ou par
le système immunitaire d'organisme multicellulaires, même dans des conditions
idéales \ecoli{} vieillit~\cite{stewart_aging_2005}. Ce vieillissement résulte
d'une asymétrie entre les parois membranaires des pôles de la cellule. En effet,
un de ces pôle est celui de la cellule mère, alors que le second provient du
plan équatorial de scission de la cellule mère et a été fraîchement créé. En
partant d'une unique cellule mère, à chaque génération deux cellules possèdent
les parois membranaires des pôles de la cellule mère susmentionnée. Avec les
générations, le matériel cellulaire diffusant peu et ayant une longue demi-vie
s'accumule dans ces «vieux» pôles. Les cellules aux pôles plus âgés produisent
moins de cellules filles et ont une probabilité de décès spontané plus élevée.
On peut ainsi donner un âge à chaque pôle prenant en compte le nombre de
divisions qu'il a subit. Cela permet d'attribuer un âge à chaque cellule, qui
est définit comme l'âge du pôle le plus âgé. En conséquence, \otb inclus un
modèle de vieillissement des bactéries pouvant causer le décès spontané (nommé
apoptose) d'une cellule si sa lignée dépasse une certaine valeur, paramétrable
en début de simulation.
\subsection{Organisation logicielle du simulateur}
Pour décrire l'organisation logicielle du simulateur, il nous faut parler des
architectures de \opencl et de \opengl avant de présenter l'architecture de
\otb afin de comprendre comment ces différents composants communiquent pour
simuler l'évolution d'une population de bactéries.
\subsubsection{Architecture \opencl}\label{sec:archi-cl}
Nous présentons ici une version simplifiée de l'architecture de \opencl%
\footnote{\url{http://www.khronos.org/registry/cl/specs/opencl-1.1.pdf}}. Un
programme \opencl est construit en deux parties: le programme hôte et les
\emph{kernel}. Le programme hôte s'exécute normalement sur CPU. Dans notre cas,
c'est la partie du simulateur gérée par \ocaml. Les kernels sont des fonctions
écrites en C99 destinées à être exécutées sur les périphériques gérés par
\opencl, comme une carte graphique. Le modèle d'exécution d'\opencl définit
comment ces kernels sont instanciés sur les différentes unités de calcul
disponibles.
Lorsque l'hôte soumet un kernel à exécuter à \opencl, un espace d'indices est
définit et, pour chaque indice de cet espace, une instance du kernel est
exécutée. Cette instance est appelée un \emph{work-item}. Les work-items sont
regroupés en \emph{work-group}, une division par blocs de l'espace d'indices.
Les work-items ont accès à quatre types de mémoire: la mémoire globale, la
mémoire constante, la mémoire locale et la mémoire privée. Chacune de ces
mémoires est manipulable soit par l'hôte, soit par un work-item, soit par les
deux. Par exemple, la mémoire privée est réservée à un work-item, la mémoire
local est accessible à tous les work-items du même work-group, les mémoires
constantes et globales sont accessibles à l'hôte comme aux work-items.
L'hôte peut également demander des transferts de données entre sa mémoire
principale, la RAM, et les mémoires du device, dans les deux sens, afin de
fournir des données initiales aux work-items et de récupérer leur travail.
\subsubsection{Architecture \opengl}
Le framework \opengl définit une architecture client-serveur: le client
fonctionnant sur l'hôte, côté CPU, et le serveur s'exécutant sur la carte
graphique, côté GPU. La pièce maîtresse du serveur est le \emph{rendering
pipeline} (chaîne de traitement du rendu), une succession de tâches permettant
de transformer par étapes un ensemble de vertex, définis dans un espace en trois
dimensions, en un tableau de pixels en deux dimensions.
\begin{figure}[ht]
\centering
\includegraphics[width=\textwidth]{figures/openGLPipeline}
\caption{Vue de haut niveau de la chaîne de traitement de \opengl. Les
shaders en gras peuvent être définis par l'utilisateur, les shaders en
pointillé sont optionnels. }
\label{fig:openGLPipeline}
\end{figure}
Ces étapes peuvent peuvent pour certaines être programmées à l'aide d'un langage
appelé \emph{GLSL} (OpenGL Shading Language), une variante de C, et sont
appelées des \emph{shaders} (voir \textsc{Fig.}~\ref{fig:openGLPipeline}). Voici une
description succinte des shaders programmable utilisés dans \otb, avec leurs
entrées, leurs sorties et une description de leur rôle:
\begin{description}
\item{\bfseries Vertex Shader}
\begin{itemize}
\item Entrée: un vertex;
\item Sortie: un vertex;
\item Description: ce shader modifie un vertex, par exemple ses attributs de
position {vec4 gl_Position} ou de taille de point {float gl_PointSize}.
\end{itemize}
\item{\bfseries Geometry Shader}
\begin{itemize}
\item Entrée: un vertex, une ligne, des triangles;
\item Sortie: zéro, un ou plusieurs vertex, ligne ou triangles;
\item Description: ce shader permet d'effectuer des calculs géométriques sur
les primitives qui lui sont données, soit pour modifier leur attributs, soit
pour générer de nouveaux points, de nouvelles lignes ou de nouveaux
triangles. Par exemple, dans \otb, ce shader est utilisé pour construire les
vertex nécessaire à la représentation d'une bactérie, à partir de trois
vertex donnés en entrée.
\end{itemize}
\item{\bfseries Fragment Shader}
\begin{itemize}
\item Entrée: un fragment;
\item Sortie: une couleur;
\item Description: ce shader permet d'attribuer une couleur à un pixel sur
l'écran à partir des informations calculées par le shader de Rasterization.
C'est ici par exemple que la représentation de chaque bactérie obtient ses
couleurs.
\end{itemize}
\end{description}
\subsubsection{Architecture de \otb}
% Extracted with:
% $ $grep ^module * 2> /dev/null | sed -e 's/^.*\.ml.\?://' | sort -u | copy
L'architecture de \tb{} est organisée en modules \ocaml. L'usage de modules a
été une méthode intuitive pour rapidement prototyper le fonctionnement du
simulateur. Les modules de \tb{} peuvent être découpés en deux catégories: les
modules haut niveau, utilisés dans la programmation de la logique du simulateur
et les modules bas niveau utilisés pour fournir des outils concrets aux modules
de haut niveau, comme par exemple communiquer avec les périphériques
d'entrée/sortie via des binding vers des bibliothèques externes. Les modules
sont écrits avec \ocaml, mais l'accès à \opengl et \opencl ne peut se faire
que via le langage C, ainsi les modules de bas niveau \texttt{Viewer} et
\texttt{OpenCL} sont en partie dédiés à la traduction entre l'interface C et
\ocaml.
\begin{figure}[ht]
\centering
\includegraphics[width=\textwidth]{figures/otbModules}
\caption{Organisation des dépendances entre les modules de \tb{}. Les modules
de bas niveau sont organisés sur le rang inférieur, les modules de haut
niveau sont sur le rang supérieur.}
\label{fig:tbModules}
\end{figure}
\paragraph{Entrée} Le point d'entrée par défaut du programme, à savoir la
fonction d'entrée dans le programme, se trouve dans le module \texttt{Main}. Ce
dernier fait appel aux autres modules pour construire une simulation et
l'exécuter.
\paragraph{Modules de haut niveau}
Les modules de haut niveau regroupent les définitions des fonctions dédié au
travail des modèles: d'une bactérie et d'une population de bactéries, d'un
environnement de morphogènes, d'une zone délimitant les bords physiques de
l'environnement de simulation et enfin de l'assemblage des trois modèles
précédents. Comme indiqué par les flèches de la \textsc{Fig.}~\ref{fig:tbModules}, un
module de haut dépend d'un ou plusieurs modules bas niveau. Le module
\texttt{Bacterium} décrit le modèle d'une bactérie ainsi que l'automate
cellulaire support d'une population de bactéries. Sa fonction la plus notable,
\texttt{Bacterium.run}, prépare et lance le calcul d'un pas de simulation d'une
population de bactéries sur le GPU. Le module \texttt{Morphogen}, assez
symétrique au module \texttt{Bacterium}, décrit l'automate cellulaire modélisant
la réaction-diffusion des morphogènes. Sa fonction principale,
\texttt{Morphogen.run} initialise et lance le calcul d'un pas de simulation
d'une grille de morphogènes sur le GPU. Ces deux modules font appel à quatre
autres modules de bas niveau qui sont décrits dans le paragraphe suivant.
\texttt{Zone} est un module de haut niveau modélisant une boîte de Petri de
taille dynamique en fonction de la répartition des individus qu'elle contient.
Ses bords sont représentées par un cadre jaune dans la
\textsc{Fig.}~\ref{fig:otb2-display}. Finalement, le module \texttt{Coupling} décrit le
modèle complet obtenu par l'interaction entre les bactéries et leur
environnement. C'est ce modèle qui permet aux bactéries de déposer des
morphogènes dans leur environnement et de consommer les morphogènes qui y sont
présent.
\begin{figure}[h]
\centering
\includegraphics[width=\textwidth]{otb-multi-view}%
\caption[Présentation des zones dynamiques]{Trois vues d'une même simulation
avec \num{1174} bactéries présentant, à gauche, une vue globale montrant
les zones dynamiques (délimitées en rouge, la zone intérieure est celle
des bactérie, la zone extérieure est celle des morphogènes). À droite sont
présentés des vues agrandies de la simulation mettant en évidence, en
haut, le comportement physique des bactéries et, en bas, la diffusion des
morphogènes.}
\label{fig:tbModules}
\end{figure}
\paragraph{Modules de bas niveau}
Le module \texttt{Packfile} regroupe les fonctions de sérialisation nécessaire à
la sauvegarde dans un fichier de l'état d'une simulation. Le module
\texttt{BoundingBox} contient les types et les fonctions permettant de définir
et d'effectuer des calculs courants sur des boîtes encadrantes, une
représentation rectangulaire d'une zone géométrique.
Les modules \texttt{OpenCL} et \texttt{Viewer} sont des modules permettant
d'accéder à des bibliothèques externes. En effet, \tb{} communique avec la
carte graphique \emph{via} le langage et framework \opencl pour les calculs
généraux. Dans un premier temps, nous avons fait appel à un module \ocaml,
appelé SPOC~\cite{bourgoin_spoc:_2012}, fournissant un binding \opencl et une
gestion automatique de la mémoire de la carte graphique. Au delà d'une simple
interface entre \ocaml et \opencl, SPOC abstrait la programmation GPGPU et donne
un accès transparent à d'autres framework. Cependant, SPOC posant des problèmes
de stabilité et possédant bien plus de fonctionnalités que nous avions besoin,
nous avons finalement écrit notre propre interface bas niveau pour \opencl, car
nous souhaitons manipuler explicitement le transfert entre l'hôte et la carte.
Cette interface a pour intérêt d'être simple, stable et de donner une grande
latitude au développeur \ocaml quant à la gestion de la mémoire entre l'hôte et
la carte graphique. Ce binding est contenu dans le module \texttt{OpenCL}. \tb{}
communique aussi avec la carte graphique \emph{via} \opengl. De la même manière,
il existe plusieurs bindings \opengl pour \ocaml. Toutefois, nous n'utilisons
qu'un faible sous-ensemble des fonctions de l'\api{} d'\opengl et nous avons
écrit notre propre interface bas niveau, minimale et spécifique à l'utilisation
de \tb{}. \texttt{Viewer} contient le binding vers \opengl, glew et glfw, trois
bibliothèques utilisées dans la création de l'interface graphique du simulateur.
\subsection{Le langage \sbgp{}}
Pour répondre au point «Entrée» du cahier des charges, nous avons développé
notre propre langage afin de faciliter le paramétrage d'une
simulation \cite{pascalie_developmental_2016} avec \tb{}. \sbgp{} (Synthetic
Biology Genetic Programming) est un langage déclaratif décrivant les options de
configuration d'une simulation \otb. Un fichier de configuration de la
simulation écrit avec \sbgp{} donne une représentation abstraite du génome de la
bactérie sous la forme d'une machine à états finis et inclus des informations
supplémentaires pour paramétrer la simulation, comme les couleurs de rendu.
\paragraph{Syntaxe}
Un fichier \sbgp{} est formaté en JSON~\cite{bray_javascript_2014}. Un génome
\sbgp{} est un objet JSON contenant les blocs suivants:
\begin{itemize}
\item \texttt{signals}: la liste des signaux en usage dans la simulation,
chaque signal est définit par un triplet: nom du signal, coefficient de
diffusion et coefficient de dégradation;
\item \texttt{reactions}: la liste des réactions, si elles existent. Chaque
réaction est définit par un triplet: $(r,p,\tau)$$r$ est une liste des
réactants, $p$ une liste des produits et $\tau$ le taux de réaction;
\item \texttt{type}: la liste des types identifiés par une étiquette unique;
\item \texttt{behavior}: le comportement, un objet donnant pour chaque type la
liste des actions à exécuter à chaque pas de temps;
\item \texttt{transition}: une matrice de taille
$card(\text{\texttt{type}}) \times card(\text{\texttt{type}})$
qui représente la table de transition d'état entre chaque types. La matrice
donne l'identifiant de la transition si il existe.
\item \texttt{cond\_transition}: la transition conditionnelle identifiée par
son étiquette; chaque étiquette dans la table de transition d'état doit
être défini dans ce bloc
\end{itemize}
Le type de chaque bloc est le suivant:
\begin{SBGPcode}
{
"signals" : [[Sid_i, Deg_rate_i, Diff_rate_i], [...]],
"reactions" : [[[Pid_i, Pid_j], [Rid_i], Rate_i], [...]],
"type" : [T0, ..., Tn],
"behavior" : {T0 : [{InstructionID : [Pid_1, ..., Pid_n]}]}
"transition" : [type x type] of Condition_name,
"cond_transition" : [{Condition_name_i : ConditionID}, ..., {...}]
}
\end{SBGPcode}
\paragraph{Déclaration des signaux}
Les signaux sont déclarés dans une liste. Chaque signal est un triplet contenant
le nom du signal sous forme de chaîne de caractères, et les coefficients de
diffusion et de dégradation sous forme de nombres réels.
\begin{SBGPcode}
"signals" : [
["alpha", 0.05, 0.01],
["beta", 1.5, 1]
]
\end{SBGPcode}
\paragraph{Déclaration des réactions}
Les réactions sont déclarés dans une liste. Chaque réaction consiste en un
triplet: la liste des réactants, la liste des produits et la constante cinétique
de la réaction. Par exemple, le bloc \sbgp{} suivant est utilisé pour décrire la
réaction $2\alpha + \beta \xrightarrow{0.15} \gamma$:
\begin{SBGPcode}
"reactions" : [
[
["alpha", "alpha", "beta"],
["gamma"],
0.15
]
]
\end{SBGPcode}
\paragraph{Déclaration des types}
Les types de bactéries légaux sont déclarés dans une liste d'identifiants. Le
bloc suivant donne la liste des types impliqués dans le génome:
\begin{SBGPcode}
"type" : [
"QUIESCENT",
"LEADER",
"FLESH",
"SKIN",
"DEAD"
]
\end{SBGPcode}
\paragraph{Déclaration du comportement}
Les comportements spécifiques aux types sont déclarés dans une liste
associative; une liste d'instructions est donnée pour chaque étiquette
déclaré dans le bloc type. Par exemple, le code suivant donne le comportement
d'une bactérie de type \texttt{LEADER}:
\begin{SBGPcode}
"behavior" : {
"LEADER" : [ { "EmitSignal" : ["alpha", "150"] },
{ "StopDivide" : [] },
{ "Accumulate" : ["lambda","1"] }
]
}
\end{SBGPcode}
Une instruction est décrite conformément à la structure suivante:
\begin{SBGPcode}
{ "InstructionID" : ["param1", ... ,"paramN"] }
\end{SBGPcode}
La valeur du champ \texttt{InstructionID} doit être pris parmi l'ensemble des
instructions \sbgp{} suivantes:
\begin{itemize}
\item \texttt{EmitSignal(s,q)}: dépose une quantité |q| du morphogène |s| à
la position courante de la bactérie dans l'environnement;
\item \texttt{AbsorbSignal(s,q)}: consomme une quantité |q| du morphogène
|s| à la position courante de la bactérie dans l'environnement;
\item \texttt{Differentiate(A)}: force un changement de type de la bactérie vers
le type |A| (il doit exister dans la liste des types);
\item \texttt{Die()}: détruit la bactérie. Elle est en pratique marquée comme
inactive et réinitialisée;
\item \texttt{Freeze()}: place le marqueur |immobile| sur une bactérie. Dans cet
état une bactérie est immobile et ne croît pas;
\item \texttt{Unfreeze()}: retire le marqueur |immobile|;
\item \texttt{Divide(r)}: définit le taux de croissance de la bactérie à la
valeur particulière |r|;
\item \texttt{StopDivide()}: définit le taux de croissance de la bactérie comme
nul, l'empêchant ainsi de se diviser;
\item \texttt{Accumulate(p,q)}: incrémente le compteur de morphogènes |p| avec
la valeur |q|;
\item \texttt{Deplete(p,q)}: décrémente le compteur de morphogènes |p| avec la
valeur |q|.
\end{itemize}
\paragraph{Déclaration des transitions}
Le bloc transition est une matrice encodant le graphe de différentiation du
génome. La taille de la matrice dépend du nombre de types. Lorsque qu'une
transition existe entre deux types, une étiquette est définie dans la case de la
matrice correspondante, sinon, le mot-clé \texttt{NA} est spécifié. Le code
\sbgp{} suivant présente le graphe de différenciation d'un cœur homéostatique à
deux couches: la population croît autour d'une bactérie mère en formant deux
anneaux concentriques constitués d'une quantité invariante de bactéries.
\begin{SBGPcode}
"transition" : [
["NA","CL","C1" ,"C2" ,"NA" ,"NA" ],
["NA","NA","NA" ,"NA" ,"NA" ,"NA" ],
["NA","NA","NA" ,"C12","NA" ,"NA" ],
["NA","NA","C21","NA" ,"C23","NA" ],
["NA","NA","NA" ,"NA" ,"NA" ,"C3D"],
["NA","NA","NA" ,"NA" ,"NA" ,"NA" ]
],
\end{SBGPcode}
\paragraph{Déclaration des conditions de transition}
Une condition est une expression booléenne renvoyant |true| ou |false|. La
valeur du champ \texttt{ConditionID} doit être prise parmi l'ensemble des
instructions \sbgp{} suivantes:
\begin{itemize}
\item \texttt{AND(Cid1,Cid2)}, \texttt{OR(Cid1,Cid2)}: {AND} et {OR} sont les
opérations classiques de la logique booléenne;
\item \texttt{EqThreshold(s,q)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est égale à |q|;
\item \texttt{LessThreshold(s,q)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est inférieure à |q|;
\item \texttt{GreaterThreshold(s,q)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est supérieure à |q|;
\item \texttt{LessEqThreshold(s,q)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est inférieure ou égale à |q|;
\item \texttt{GreaterEqThreshold(s,q)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est supérieure ou égale à |q|;
\item \texttt{BetweenThreshold(s,q1,q2)}: ce prédicat n'est vérifié que si la
concentration du morphogène |s| est comprise strictement entre |q1| et
|q2|;
\item \texttt{InternalProtEqCond(p,q)}: ce prédicat n'est vérifié que si le
compteur de morphogènes |p| est égal à la valeur |q|;
\item \texttt{InternalProtLessCond(p,q)}: ce prédicat n'est vérifié que si le
compteur de morphogènes |p| est inférieur strictement à la valeur |q|;
\item \texttt{InternalProtGreatCond(p,q)}: ce prédicat n'est vérifié que si le
compteur de morphogènes |p| est supérieur strictement à la valeur |q|;
\item \texttt{InternalProtLessEqCond(p,q)}: ce prédicat n'est vérifié que si le
compteur de morphogènes |p| est inférieur ou égal à la valeur |q|;
\item \texttt{InternalProtGreatEqCond(p,q)}: ce prédicat n'est vérifié que si le
compteur de morphogènes |p| est supérieur ou égal à la valeur |q|;
\item \texttt{MidPlane(a,b,t)}: ce prédicat n'est vérifié que si la valeur de la
concentration du morphogène |a| moins la concentration du morphogène |b|
est comprise entre |-t| et |t|.
\end{itemize}
\section{Propagation Parallèle à la Margolus}\label{sec:ppm}
Nous avons présenté l'architecture de haut niveau de \otb, ainsi que son langage
de configuration, cette section présente l'algorithme de Propagation Parallèle à
la Margolus (\ppm). Cette algorithme forme le socle théorique que nous
implémentons dans les kernels \opencl. Nous commençons par un rappel sur les
automates cellulaires, les automates à blocs, puis nous présentons l'algorithme
de bounding-box dynamique et enfin \ppm.
\subsection{Automates cellulaires et voisinage de Margolus}
% Voir peut-être aussi CML (https://en.wikipedia.org/wiki/Coupled_map_lattice)
Notre travail se situe dans le contexte des automates cellulaires. Un automate
cellulaire est un modèle de calcul discret, introduit par John Von Neumann et
Stanislaw Ulam dans les années 1960~\cite{neumann_theory_1966}. C'est un modèle
de calcul Turing complet qui a d'abord été objet de recherche académique sur les
processus d'auto réplication, ensuite popularisé par le «Game of Life» de John
Conway\footnote{lors de sa publication dans les pages du Scientific American en
octobre 1970} où il est devenu un modèle pour les processus biologiques. Les
automates cellulaires sont un outil des paradigmes de programmation non
conventionnels, d'un côté permettant de formaliser les processus biologiques
observés, et de l'autre de les modéliser et de les simuler.
\begin{mpo-definition}[Configuration]
Soit $\oQ$ un ensemble d'états, $G$ un groupe, $c_{\oQ} : G \rightarrow \oQ$ est
une \emph{configuration} et $C_{\oQ} := \{ c \,|\, c:G \rightarrow \oQ \}$ est
\emph{l'ensemble de toutes les configurations} $c_{\oQ}$. Quand le contexte lève
tout ambigüité, on pourra omettre l'indice $\oQ$.
\end{mpo-definition}
\begin{mpo-definition}[Automate cellulaire]\label{def:ca}
Un automate cellulaire est un tuple $\oA = (M, \oQ, N, f)$ dont:
\begin{itemize}
\item $(M,+)$ est un groupe abélien libre appelé \emph{maillage des cellules};
\item $\oQ$ est \emph{l'ensemble des états}, aussi parfois appelé alphabet,
\item $N \in M^k$, $k \in \mathbb{N}$ est \emph{l'indice de
voisinage}, dont les éléments sont uniques deux à deux et $N =
(n_1,n_2,\ldots,n_k)$;
\item $f: \oQ^k \rightarrow \oQ$ est la \emph{fonction de transition locale}
\end{itemize}
$f$ induit une fonction de transition globale $F$, $\forall c \in C_{\oQ}$ et $m
\in M$:
\[ F(c)(m) := f(c(m+n_1),c(m+n_2),\ldots,c(m+n_k)) \]
\end{mpo-definition}
La mise à jour d'une configuration se fait de manière locale, par l'application
de $f$ sur chaque cellule en fonction du voisinage, et \emph{synchrone} avec
des pas de temps discrets. Dans le cas d'un voisinage classique ou de Von
Neumann, à gauche dans la \textsc{Fig.}~\ref{fig:voisinage-2D}, les voisins directs
sont pris en compte pour le calcul du nouvel état de chaque cellule. Du point de
vue de \mgs{}, un automate cellulaire est constitué d'un ensemble $C$ de
collections topologiques et d'une transformation $T$ jouant le rôle de la
fonction de transition globale de l'automate. Quelques restrictions s'appliquent
sur chaque $c_i \in C$ et $T$: $c_i$ doit être une collection newtonienne de
type \gbf{} et $T$ doit utiliser la stratégie de réécriture
\texttt{maximal-parallel}, afin que la mise à jour soit synchrone.
\begin{figure}[ht]
\centering
\includegraphics[page=1,width=.3\textwidth]{figures/ca-neighborhood-2D}
\includegraphics[page=2,width=.3\textwidth]{figures/ca-neighborhood-2D}
\includegraphics[page=3,width=.3\textwidth]{figures/ca-neighborhood-2D}
\caption{Trois exemples de voisinages sur un grille carrée en 2D, à gauche un
voisinage de Von Neumann, au centre un voisinage hexagonal et à droite un
voisinage de Moore.}
\label{fig:voisinage-2D}
\end{figure}
En tant que modèle de calcul, un automate cellulaire fonctionne de manière
fortement parallèle: la même fonction est appliquée sur chaque cellule de la
grille, ou autrement dit le même algorithme est appliqué à de multiples données
ce qui est la définition d'une architecture SIMD. On pourrait donc tirer parti
d'une architecture fortement parallèle pour implémenter un automate cellulaire.
Néanmoins, la dépendance entre les données par la relation de voisinage entre
les cellules pose encore problème. Une solution classique revient à utiliser une
mémoire intermédiaire (un buffer) depuis lequel on va lire les données et écrire
les résultat dans un second buffer, cassant ainsi la dépendance en écriture sur
les cellules concernées. Cependant, il reste une \emph{dépendance en lecture}
sur les cellules voisines causant des collisions de lecture et pouvant encore
porter atteinte à l'efficacité d'une implémentation parallèle. Pour résoudre ces
problèmes, nous nous sommes tournés vers le voisinage de Margolus et de manière
plus générale, le modèle de calcul des automates à blocs.
S'intéressant au développement d'ordinateurs simulant des systèmes physiques,
Toffoli et Margolus introduisent
dans~\cite{toffoli_cellular_1987,margolus_physics-like_1984} les automates
cellulaire à blocs (\emph{block cellular automata}), ou automate à partitions
(\emph{partitioning automata}), pour modéliser le comportement dynamique de
l'écoulement d'un fluide en respectant le principe de \emph{réversibilité} des
lois physiques. En thermodynamique, durant un processus réversible l'entropie
n'augmente pas et le système est en état d'équilibre thermodynamique. On appelle
\emph{automate cellulaire réversible} les automates cellulaire dont on retrouve
la configuration d'origine en «inversant» la flèche du temps. Un automate
cellulaire dont chaque cellule est mise à jour en inversant sa valeur précédente
et en ignorant son voisinage est trivialement réversible. Cependant, au delà
d'une dimension, la réversibilité d'un automate cellulaire est
indécidable~\cite{kari_reversibility_1994}. L'automate gaz sur réseau (lattice
gas automaton)~\cite{hardy_time_1973}, la règle
«Tron»~\cite{toffoli_cellular_1987}, l'ordinateur à boules de billard
(billiard-ball computer)~\cite{fredkin_conservative_1982} sont des exemples
d'automates cellulaires réversibles. Toffoli et Margolus montrent également que
la classe des automates à partitions est équivalente à celles des automates
cellulaires, et que ces deux modèles peuvent se simuler l'un l'autre.
\begin{mpo-definition}[Automate cellulaire à blocs] Un automate cellulaire à
blocs, aussi appelé automate à partitions, est un tuple
$B=(M,\oQ,p,\text{\em shift},f)$ avec:
\begin{itemize}
% Lattice (order) != Lattice (groups) | Treilli != Réseau
\item $(M,+)$ le maillage des cellules. C'est le groupe abélien \emph{libre}
engendré par l'ensemble fini $A = \{g_1,...,g_n\}$;
\item $\oQ$ un ensemble d'états;
\item $p : M \rightarrow M$ la fonction de pavage qui pour $\{c_1,...,c_n\}
\subset \mathbb{Z}^n$ et $\{k_1,...,k_n\} \subset \mathbb{N}_{+}^n$ associe à
chaque point de $M$ un \emph{bloc}:
\[
p(\sum\limits_{i=1}^{n}{c_i\ g_i})
= \sum\limits_{i=1}^{n}{\left\lfloor \frac{c_i}{k_i} \right\rfloor g_i}
\]
La fonction inverse $p^{-1}(m) = \{ m \in M\, |\, p(m) \in M \}$ permet
d'obtenir l'ensemble des éléments du bloc indicé par $m$.
\item $\text{\em shift}$ est la liste d'éléments $(m_1,...,m_n)$ de $M$ .
\item $f : Q^k \rightarrow Q^k$ est la fonction de transition locale, avec $k
= \prod_{i=1}^{n}{k_i}$.
\end{itemize}
La fonction de transition locale $f$ induit une fonction de transition
globale, dont la définition est décrite par l'algorithme
\begin{algorithm}
\ForAll {$s \in \text{shift}$}
{ \ForAll {$m \in M$} {
$M \gets f (c_1 (T^s \beta(m)))$ \;
}
}
\end{algorithm}
en posant:
\begin{itemize}
\item $T^s$ l'opérateur de décalage sur les groupes Abéliens, $T^s f(g) =
f(g+s)$ en prenant un groupe Abélien $G$, $g \in G$ et $f : G \rightarrow
G$;
\item $\beta(m) = (p^{-1} \circ p) (m)$ l'ensemble des éléments appartenant au
bloc de la cellule $m$ et
\item $c_1(B) : M \rightarrow Q^k $ la configuration d'un ensemble de cellules
\emph{indexées par leur élément correspondant} dans le groupe. Nous
n'expliciterons pas la version formelle ici pour ne pas alourdir la
définition inutilement.
\end{itemize}
\end{mpo-definition}
Nous avons choisi d'utiliser la structure de groupe abélien libre pour
représenter un maillage de cellule. C'est également le point de vue utilisé dans
la définition des \gbf{} à la différence que nous nous restreignons aux groupes
libres, afin de pouvoir définir un pavage naturel. De ce point du vue, il
semblerait qu'un automate cellulaire à bloc ne puisse pas avoir de maillage
hexagonal, avec la présentation de groupe $H = \langle a,b,c \:|\: a + b = c
\rangle$, car ce n'est pas un groupe libre. Néanmoins, nous pourrons considérer
qu'un maillage hexagonal est un maillage carré, de présentation $H = \langle a,b
\rangle$ sur lequel le voisinage entre cellules est spécifique comme présenté
sur la \textsc{Fig.}~\ref{fig:voisinage-2D} au centre. Par conséquent, c'est la
fonction de transition locale qui déterminera quel voisinage est utilisé.
La fonction $\lfloor x/k \rfloor$ se comporte « naturellement » autour de $0$:
chaque image par cette fonction possède exactement $k$ préimages. Cette
caractéristique permet, par exemple, de partitionner $\mathbb{Z}$ en
sous-ensembles de cardinalité $k$, d'où son usage dans la définition de $p$.
Pour la définition de la fonction de pavage, nous avons choisi une approche
similaire à la définition d'une partition de l'espace passant par les
$\mathbb{Z}$-modules comme introduit dans~\cite{michel_representations_1996} à
la section VI.1.1. Notre approche correspond mieux à l'idée intuitive d'une
sous division de l'espace: à chaque cellule du maillage on fait correspondre une
cellule du même maillage, ce qui expose immédiatement la structure et la
régularité du pavage.
Le voisinage de Margolus est la règle de partitionnement du maillage d'un
automate à blocs en une grille composée de blocs de $2$ cellules (ou en carrés
de $2\times 2$ cellules en deux dimensions, en cubes de $2\times 2\times 2$
cellules en trois dimension, …) avec un décalage d'une «case» dans toutes les
directions. C'est donc un cas particulier d'automate cellulaire à blocs, avec
les restrictions suivantes (en reprenant le contexte de la définition des
automates à blocs):
\begin{itemize}
\item $p : M \rightarrow M$ la fonction de pavage qui pour $\{c_1,...,c_n\}
\subset \mathbb{Z}^n$ associe à chaque point de $M$ un bloc de côté 2:
\[
p(\sum\limits_{i=1}^{n}{c_i\ g_i})
= \sum\limits_{i=1}^{n}{\left\lfloor \frac{c_i}{2} \right\rfloor g_i}
\] et
\item shift est l'élément $\sum\limits_{i=1}^{n}{1\ g_i} \in M$.
\end{itemize}
\begin{figure}[ht]
\centering
\includegraphics[page=1,width=.4\textwidth]{figures/ca-neighborhood}
\hspace{1cm}
\includegraphics[page=2,width=.4\textwidth]{figures/ca-neighborhood}
\caption{Voisinage classique (à gauche) d'un automate cellulaire à une
dimension et voisinage de Margolus (à droite). Pour le voisinage classique,
chaque ligne correspond à un pas dans la simulation de l'automate, de haut
en bas. Pour le voisinage de Margolus, un seul pas de simulation est
présenté, la ligne du milieu est présentée afin de montrer la correspondance
entre les deux automates.}
\label{fig:ac-nh}
\end{figure}
\subsection{Bounding box et activité}\label{sec:boundingbox}
Dans OTB, l'environnement dans lequel évoluent les bactéries n'a pas \emph{a
priori} de taille fixe et subit une expansion ou une contraction en fonction
de l'espace occupé par les bactéries, ou par leur support. Nous appelons
\emph{bounding box} la boîte englobante dont l'intérieur forme l'environnement
dans lequel évoluent les bactéries, ou leur support. Cette bounding box a une
taille rectangulaire libre. La bounding box est construite \emph{a posteriori}:
elle est déterminée par la taille de la grille d'automate qu'elle représente. De
cette manière, il est possible d'accéder rapidement à la taille d'une population
de bactéries et d'effectuer des calculs de collision entre bounding box et des
opérations de séparation et de fusion. Ces opérations, bien que planifiées, ne
sont que partiellement implémentées à l'heure de l'écriture de ce mémoire.
\begin{figure}[ht]
\centering
\includegraphics[page=1,width=.8\textwidth]{figures/bb-activity}
\caption{Grille d'un automate cellulaire, ses indicateurs vertical et
horizontal et sa Bounding Box (en gras)}
\label{fig:bb-activity}
\end{figure}
Nous utilisons une mesure d'activité spatiale pour déterminer s'il est
nécessaire d'agrandir ou de diminuer la taille de l'environnement. Chaque
cellule de l'automate contenant une bactérie est considérée comme active. Si une
cellule active se trouve à une distance inférieure à $d_c$ d'un des bords, alors
l'environnement est agrandi. À l'inverse, si la distance la cellule active la
plus proche d'un bord à ce bord est supérieure à $d_f$ alors, l'environnement
est rétréci.
En pratique, une bounding box est définie par un triplet $(p,w,h)$$p=(x,y)$
est un point dans le plan représentant le coin inférieur gauche de la boîte, $w$
est sa largeur et $h$ est sa hauteur (Fig.~\ref{fig:bb-activity}). Nous mesurons
l'occupation pour chaque ligne et chaque colonne avec deux tableaux appelés
\emph{indicateur}: un pour l'occupation horizontale, l'autre pour l'occupation
verticale. Ces deux tableaux sont suffisant pour déterminer s'il est nécessaire
d'agrandir ou de rétrécir l'environnement. L'algorithme suivant est utilisé par
\otb pour déterminer une nouvelle bounding box optimale, $w,h$ sont la largeur
et la hauteur respectives de la bounding box de départ, $c_w,c_h$ sont les
tableaux indicateurs sur la largeur et la hauteur respectivement.
La première partie de cet algorithme détermine la position de coupe par rapport à
chacun des quatre bords nord, sud, est et ouest de la bounding box. Il suffit
pour cela de déterminer la position du premier élément non nul pour chaque
extrémité de chaque indicateur, ce qui nous fournit le quadruplet $(\text{posN},
\text{posS}, \text{posE}, \text{posW})$ de positions de coupe au nord, au sud à
l'est et à l'ouest respectivement.
La seconde partie de cet algorithme détermine la nouvelle dimension de la
bounding box, en prenant en compte les deux marges notée $d_c$ et $d_f$ et en
fonction des positions de coupe déterminées auparavant. La fonction
\texttt{CropBoundingBox()} est chargée de la mise en œuvre du découpage de
l'ancienne bounding box et en retourne une nouvelle en fonction du quadruplet
$(\text{n}, \text{s}, \text{e}, \text{w})$ indiquant les corrections de marge à
chacune des extrémité. Par exemple, $\text{n}=2$ agrandi de 2 unités la taille
de la bounding box au nord, alors que $\text{e}=-4$ rétrécie de 4 unités la
taille de la bounding box à l'est. Cette fonction est implémenté dans le module
de bas niveau |BoundingBox|.
\begin{algorithm}[H]
\SetKwInOut{Input}{input}\SetKwInOut{Output}{output}
\SetKwData{PosN}{posN}\SetKwData{PosS}{posS}
\SetKwData{PosE}{posE}\SetKwData{PosW}{posW}
\SetKwData{OldBB}{oldBB}
\SetKwFunction{CBB}{cropBoundingBox}
\Input{Bounding box actuelle \OldBB et \PosN, \PosS, \PosE, \PosW}%
\Output{Une nouvelle bounding box ajustée}
\eIf(\tcp*[f]{Marge nord}){$\PosN < d_c$}{
$n \gets d_c - \PosN$\;
}{
\If{$\PosN > d_f$} {
$n \gets d_c - \PosN$\;}
\Else{
$n \gets 0$\;
}
}
\tcp{Exactement la même opération pour sud, est et ouest}
\Return{\CBB{\OldBB, $n$, $s$, $e$, $w$}}
\caption{Création d'un nouvelle bounding box aux \emph{bonnes} dimensions}
\end{algorithm}
\subsection{Propagation Parallèle à la Margolus}
L'algorithme \ppm est inspiré du voisinage de Margolus, à droite dans la
\textsc{Fig.}~\ref{fig:ac-nh}, en deux dimensions et l'utilise comme structure de
données. Il effectue la simulation d'un automate cellulaire à blocs sur une
machine parallèle d'architecture SIMD, nous l'avons implémenté sous forme d'un
kernel \opencl. Pour faciliter sa lisibilité, en voici une description un peu
plus haut niveau que notre implémentation.
\paragraph{Cellule}%
Chaque cellule est constituée de quatre emplacements: son propre état et l'état
de trois de ses voisines comme présenté dans la \textsc{Fig.}~\ref{fig:margolus-grid}.
Ces quatre emplacements seront notés dans l'algorithme suivant par abus
de la notation classique de tableau, avec les indices spéciaux 1, 2, 3 et
4. Ainsi, $m[a1]$ désigne le premier emplacement de la cellule $A$. La
\textsc{Fig.}~\ref{fig:margolus-grid} (a) donne une représentation visuelle de la
position des cellules et de leurs emplacements en accord avec l'algorithme.
\begin{figure}[ht]
\centering
\includegraphics[page=1,width=.24\textwidth]{figures/margolus}\hfill%
\includegraphics[page=2,width=.24\textwidth]{figures/margolus}\hfill%
\includegraphics[page=3,width=.24\textwidth]{figures/margolus}\hfill%
\includegraphics[page=4,width=.24\textwidth]{figures/margolus}
\hspace{.11\textwidth}(a)\hfill(b)\hfill(c)\hfill(d)\hspace{.11\textwidth}
\caption[Quatre configuration successives d'un automate cellulaire en deux
dimensions.]{\textit{Général.} Quatre configurations successives d'un
automate cellulaire en deux dimensions dont les cellules sont en gris.%
\textit{\hspace{1em}(a).} Les coordonnées utilisées dans l'algorithme pour
une cellule de Margolus.%
\textit{\hspace{1em}(b).} Les cellules A,B,C et D font partie d'une cellule
du voisinage de Margolus (en noir, en gras).%
\textit{\hspace{1em}(c).} Chacune des cellules stocke quatre états: la copie
de l'état de trois de ses voisines et le sien (en blanc sur fond noir).
Le positionnement de ces états est présenté par rapport au voisinage de
Margolus courant.%
\textit{\hspace{1em}(d).} Après une étape de calcul, les états de A, B, C
et D sont mis à jour en A', B', C' et D' et le voisinage de Margolus est
décalé.}
\label{fig:margolus-grid}
\end{figure}
\paragraph{Algorithme}%
\ppm prend en entrée un tableau de cellules |cellSpace[w][h]| en deux
dimensions de largeur |w| et de hauteur |h| et un indicateur |shift|
déterminant le décalage du voisinage. La fonction d'évolution locale
|evol(c,n1,n2,n3,n4,n5,n6,n7,n8)| prend en argument l'état courant |c| ainsi
que l'état des 8 cellules voisines |n1,...,n8|.
La fonction de mise à jour est appelée en parallèle sur \emph{le même tableau}
de cellules et doit donc être paramétrée pour indiquer sur quelle cellule elle
travaille: c'est le rôle des deux variables spéciales $gc_x$ et $gc_y$ indiquant
la position globale en abscisse et en ordonnée du bloc courant. C'est donc la
coordonnée d'une cellule du voisinage de Margolus qui est fournie. Ces deux
variables sont les paramètres propres à un work-item \opencl, qui permet à
chaque instance du kernel d'avoir un comportement différent.
\begin{algorithm}
\SetKwInOut{Input}{input}\SetKwInOut{Output}{output}
\SetKwData{CellSpace}{cellSpace}\SetKwData{Shift}{shift}
\SetKwData{Slot}{.slot}\SetKwData{Evol}{evol}
\Input{Une configuration \CellSpace d'un automate cellulaire en deux
dimension, un indice de décalage \Shift valant 0 ou 1 et les coordonnées
globales $(gc_x,gc_y)$ du bloc actuel}%
\Output{Aucune (le changement est effectué par effet de bord)}
$p_x \gets 2 * gc_x + \texttt{shift}$ \tcp*{Coordonnées de la cellule}
$p_y \gets 2 * gc_y + \texttt{shift}$\;
$i_x \gets p_x + 1$\;
$i_y \gets p_y + 1$\;
Nouveau tableau local de 2×2 cellules: $m[2][2]$\;
$m[0][1] \gets \texttt{cellSpace}[N*iy+px]$\;
$m[1][1] \gets \texttt{cellSpace}[N*iy+ix]$\;
$m[0][0] \gets \texttt{cellSpace}[N*py+px]$\;
$m[1][0] \gets \texttt{cellSpace}[N*py+ix]$\;
Nouvelle cellule locale: $n$\;
$n[1] \gets \Evol(m[a3],$\tcp*[f]{Cellule courante $A$}\\
$\qquad m[a1],m[a2],m[b1],m[b4],m[c1],m[d2],m[d1],m[a4])$
\;
$n[2] \gets \Evol(m[b4],$\tcp*[f]{Cellule courante $B$}\\
$\qquad m[a2],m[b1],m[b2],m[b3],m[c2],m[c1],m[d2],m[a3])$
\;
$n[3] \gets \Evol(m[c1],$\tcp*[f]{Cellule courante $C$}\\
$\qquad m[a3],m[b4],m[b3],m[c2],m[c3],m[c4],m[d3],m[d2])$
\;
$n[4] \gets \Evol(m[d2],$\tcp*[f]{Cellule courante $D$}\\
$\qquad m[a4],m[a3],m[b4],m[c1],m[c4],m[d3],m[d4],m[d1])$
\;
$\CellSpace[N*iy+px] \gets n$\;
$\CellSpace[N*iy+ix] \gets n$\;
$\CellSpace[N*py+px] \gets n$\;
$\CellSpace[N*py+ix] \gets n$\;
\caption{\ppm}
\end{algorithm}
La cellule localement créée $n$ est au cœur du fonctionnement de \ppm.
Il pourrait paraître en premier lieu étrange qu'elle soit recopiée à
l'identique dans les quatre cellules de |cellSpace| constituant l'unique
cellule de Margolus en cours de mise à jour. Néanmoins, en s'aidant de la
\textsc{Fig.}~\ref{fig:margolus-grid} et en prenant en compte que le prochain
décalage de la grille de Margolus se fait sur une cellule en diagonale, une
symétrie apparaît.
La création d'un tableau local $m$ de $2 \times 2$ est en revanche moins
importante, cependant elle reste utile pour deux raisons: elle améliore sa
lisibilité de l'algorithme et l'utilisation de variables locales en général nous
permet de limiter le nombre d'accès à la mémoire globale en faisant un usage
plus intensif de la mémoire privée (voir le paragraphe Architecture \opencl
page~\pageref{sec:archi-cl}).
L'algorithme \ppm travaille sur un bloc et, dans le voisinage de Margolus,
chaque bloc est indépendant, ainsi il n'y a pas de problème de concurrence ni à
l'accès au données ni à l'écriture. Chaque cellule embarque un quart de son
voisinage et comme un bloc est constitué de quatre cellules, ce bloc contient
toutes les informations nécessaires pour effectuer une mise à jour localement.
Ainsi, alors que les algorithmes usuels de simulation d'automates cellulaires
utilisent deux copies de la configuration actuelle pour éviter les collisions de
lecture, \ppm n'en a pas besoin.
% #IloveFloatBarrier
\FloatBarrier
\section{Implémentation de \tb{}}\label{sec:implementation}
Dans cette section nous décrivons les trois modèles (appelés moteurs) qui
gouvernent le fonctionnement du simulateur: le moteur chimique, le moteur
physique et le moteur de décision.
\subsection{Moteur chimique: réaction et diffusion}
Dans cette section nous présentons la fonction de transition de l'automate
cellulaire en charge de la simulation chimique du milieu dans lequel évolueront
les bactéries. Ce milieu a comme propriété de diffuser plusieurs morphogènes et
de les faire réagir. L'équation de réaction-diffusion est un modèle mathématique
qui permet, entre autres, de modéliser l'évolution de la concentration dans
le temps et dans l'espace d'espèces chimiques diffusant et réagissant entre
elles. Il a notamment été utilisée par A. Turing~\cite{turing_chemical_1952}
a qui nous empruntons le terme de \emph{morphogène} pour décrire une espèce
chimique dans notre automate. Exprimée pour un seul morphogène dans une
dimension d'espace, l'équation de réaction-diffusion est appelé l'équation de
Kolmogorov-Petrovsky-Piskounov (KPP)~\cite{kolmogorov_etude_1937}.
Nous partirons d'une version généralisée de l'équation KPP en deux dimensions
d'espace, avec un nombre $n \in \mathbb{R}_+$ de morphogènes:
\begin{equation}
\frac{\partial\orr\varphi}{\partial t} =
\orr{\text{X}}(\orr\varphi) +
\orr{\text{D}}^{\text{T}} \cdot \left( \frac{\partial^2\orr\varphi}{\partial x^2} +
\frac{\partial^2\orr\varphi}{\partial y^2} \right)
\label{eq:reaction-diffusion-2D}
\end{equation}
L'équation~\ref{eq:reaction-diffusion-2D} donne la variation des concentrations
de plusieurs espèces chimiques, ou morphogènes, dénotée $\orr\varphi =
(\varphi_1,\ldots,\varphi_n)$, au cours du temps et dans un espace à deux
dimensions où $\orr{\text{D}}^{\text{T}} = (\text{D}_1,\ldots,\text{D}_n)$ sont
les coefficients de diffusion et $\orr{\text{X}}^{\text{T}} =
(\text{X}_2,\ldots,\text{X}_n)$ est un champ de vecteur décrivant la cinétique
locale du système, autrement dit les réactions entre morphogènes.
\paragraph{Discrétisation}
Lors d'une simulation numérique, le temps et l'espace sont discrétisés et il
existe différentes méthodes pour approcher par des méthodes discrètes la
solution de l'équation~\ref{eq:reaction-diffusion-2D}. L'implémentation actuelle
du simulateur utilise la méthode d'Euler, la méthode d'intégration numérique la
plus simple:
\begin{align}\label{eq:num-int}
\displaystyle
\varphi^{t + \Delta t}_{k,i,j} &= \Delta t\,\text{X}_1(\varphi^t_{1,i,j}, \ldots, \varphi^t_{k,i,j})
+ \frac{\text{D}_k\Delta t}{(\Delta x)^2}
(\varphi^t_{k,i-1,j} + \varphi^t_{k,i+1,j} + \varphi^t_{k,i,j-1} + \varphi^t_{k,i,j+1}
- 4\varphi^t_{k,i,j})
\end{align}
où les indices $(i,j)$ dénotent la position sur une grille carrée en 2D.
Dans~\cite{dilao_validation_1998}, les auteurs fournissent une classe
de méthodes pour l'intégration numérique d'équations de diffusion et de
réaction-diffusion approchant la solution exacte de l'équation de diffusion
continue. En l'absence d'une validation plus poussée de notre outil, nous ne
pouvons pas encore nous prononcer sur l'impact de l'erreur introduite par la
discrétisation sur automate. Cependant, d'un point de vue qualitatif, le moteur
chimique s'est suffisamment bien comporté pour les quelques tests que nous avons
menés. En choisissant un $\Delta t$ suffisamment petit, en l'occurrence $\Delta
t = \num{0.01}$, nous avons pu reproduire des réactions chimiques classiques,
dont une réaction BZ (voir section~\ref{sec:bz}).
\paragraph{Fonction de transition}
\newcommand{\RTable}{\ensuremath{\mathit{RTable}}}
\newcommand{\RRate}{\ensuremath{\mathit{RRate}}}
Chaque cellule de l'automate a pour état la concentration de chacun des $n$
morphogènes de la simulation:
\[
(conc_1,conc_2,\ldots,conc_n)
\]
Une table des réactions $\RTable[i][j]$ est définie comme un tableau en deux
dimensions avec selon $i$ les $n$ morphogènes et selon $j$ les $r$ réactions.
Une liste des taux de réaction $\RRate[j]$ donne le coefficient de vitesse pour
la réaction $j$. Ces deux valeurs sont définies avant la simulation et sont donc
accessibles à la fonction de transition locale du moteur chimique. Par exemple,
dans le cas d'une simulation à trois morphogènes $a,b,c$ où deux réactions $r,s$
sont possibles
\[
\RTable = \left[
\begin{array}{rrr}
-1 & -2 & 2 \\
0 & 2 & -1
\end{array} \right]
\qquad
\RRate = (\alpha, \beta)
\]
désigne les réactions
\[
a + 2b \xrightarrow{\alpha} 2c
\qquad\text{et}\qquad
c \xrightarrow{\beta} 2b
\]
\begin{algorithm}
\SetKwData{Evol}{evol}
\SetKw{KwFrom}{from}
\SetKw{And}{and}
\SetKwData{NBPC}{$\mathit{nbpc}$}
\SetKwProg{Fn}{Fonction}{ as}
\Fn{\Evol(c: cell, $n_1$: cell, $\ldots$, $n_8$: cell): cell}{
\For(\tcp*[f]{Diffusion de chacun des morphogènes}){$i$ \KwFrom $0$ \KwTo
$n-1$}{%
$ c'[i] \gets c[i] + \Delta t * D[i] * \frac{1}{(\Delta x)^2} * ( n_2[i] +
n_4[i] + n_6[i] + n_8[i] - 4 c[i] )$\;%
\For(\tcp*[f]{Résultat des réactions entre morphogènes}){$j$ \KwFrom $0$
\KwTo $r-1$}{ $c'[i] \gets c'[i] + \Delta t * \RTable[i][j] * \RRate[j]$\;
} } \Return{$c'$}\; }
\caption{Fonction de transition locale du moteur chimique}
\end{algorithm}
Dans le cas de la diffusion sans réaction, la diffusion sur
automate à bloc à voisinage de Margolus a été traité dans la
littérature~\cite{medvedev_multi-particle_2010} et montre que le processus
de diffusion est exactement simulé par un automate cellulaire booléen
bloc synchrone sur voisinage de Margolus.
\subsection{Moteur physique: collisions}
Dans cette section, nous présentons la construction de la fonction de transition
de l'automate cellulaire en charge de la simulation physique des bactéries. Le
moteur physique représente certains aspects de la mécanique du solide, notamment
les translations sur le plan, la rotation et la collision entre objets. Nous
utilisons un modèle de mécanique newtonien avec des simplifications spécifiques
à l'échelle à laquelle les bactéries évoluent. Le modèle suivant est décrit dans
un plan vectoriel en deux dimensions.
\paragraph{Modèle physique au repos}
Une bactérie est modélisée par une masse $m$, un centre de masse $p =
(p_x,p_y)$, une longueur $l$ et un rayon $r$ donnant son épaisseur (voir
Fig.~\ref{fig:ecoli} droite). Son orientation est représentée de manière
équivalente, soit par un angle $t$, soit par un vecteur directeur $d =
(d_x,d_y)$ en prenant $d_x = \mathit{cos}(t)$ et $d_y = \mathit{sin}(t)$. La
longueur totale d'une bactérie est notée $L$ et sa surface $S$.
Nous ajoutons deux points $f=(f_x,f_y)$ et $b=(b_x,b_y)$ représentant respectivement l'avant et
l'arrière de la bactérie
\begin{align*}
f_x &= p_x + l \times \mathit{cos}(t) & b_x &= p_x - l \times \mathit{cos}(t)\\
f_y &= p_y + l \times \mathit{sin}(t) & b_y &= p_y - l \times \mathit{sin}(t)
\end{align*}
%
% Forces
Du point de vue cinétique, une bactérie possède une vitesse de déplacement de
norme $v_b$ colinéaire à $\orr{d}$ et une vitesse de rotation de norme
$\omega_b$ autour de $p$. Elle a également un taux de croissance $g$ faisant
varier sa masse, sa longueur et sa largeur.
La quantité de mouvement, aussi appelé moment linéaire, d'une bactérie est
$\orr{p} = m \orr{v}_b$ et son moment angulaire, aussi appelé moment cinétique,
autour de son centre d'inertie est $\orr{L} = I \orr{\omega}_b$ où le moment
d'inertie $I$ est similaire au moment d'inertie d'une tige de densité de masse
uniforme, tournant autour de son centre de masse, de la même longueur que la
bactérie, à savoir:
\[
I = \displaystyle\frac{1}{12} \times m(2r+2l)^2 =
\displaystyle\frac{1}{6} \times m(r+l)^2
\]
Du point de vue dynamique, nous considérons que les bactéries évoluent dans un
milieu dont la viscosité est très élevée. Au centre de masse de chaque bactérie
s'applique la somme des forces extérieures d'accélération linéaire $F$ et
accélération angulaire $T$ transmises lors de collisions avec d'autres objets.
% Calcul d'une collision (schéma)
\begin{figure}[ht]
\centering
\includegraphics[page=2,width=.49\textwidth]{figures/collision}\hfill
\includegraphics[page=3,width=.49\textwidth]{figures/collision}
\caption{La détection d'une collision a lieu lorsque l'un des pôles d'une
bactérie est proche du corps d'une autre bactérie (à gauche). Quelques
vecteurs utilisés dans le calcul de l'impulsion (à droite)}
\label{fig:collision}
\end{figure}
% Qu'est-ce-qu'une collision
\paragraph{Collision entre deux bactéries}
En général, déterminer si deux objets sont en collision, c'est à dire déterminer
si l'intersection des deux objets est non vide, n'est pas trivial, et ce pour
deux raisons: les objets ont une forme potentiellement complexe et il peut
y avoir un grand nombre d'objets. Pour les ceux qui ont une forme complexe,
un objet de forme proche et plus simple, comme un disque ou un rectangle,
appelé \emph{bounding box}\footnote{différent de la bounding box que nous avons
présenté avant, celle-ci est autour d'une unique bactérie, notre bounding
box est autour d'une population de bactérie. Leurs fonctions sont toutefois
similaires.} est utilisée pour faciliter le calcul d'intersection. Dans le cas
où un grand nombre d'objet peuvent entrer en collision, l'espace est divisé en
petites sections afin que le test de collision n'ait lieu que pour un faible
nombre d'objets.
% Collision de deux bactéries
Commençons par déterminer la fonction de collision pour deux bactéries. Cette
fonction prend en entrée deux bactéries et retourne vrai s'il y a collision,
avec la distance de collision la plus courte, les vecteurs de collision, les
positions des collisions, ou faux s'il n'y a pas collision. Chaque bactérie est
déterminée par un quadruplet comprenant le vecteur position du centre de masse,
le vecteur directeur (unitaire), la longueur et le rayon respectivement $b_1 =
(\orr{p_1},\orr{d_1},l_1,r_1)$ et $b_2 = (\orr{p_2},\orr{d_2},l_2,r_2)$. À
partir de ces informations, nous pouvons obtenir les coordonnées des extrémités
\begin{align*}
\orr{f_1} &= \orr{p_1} + l_1 \cdot \orr{d_1} & \orr{f_2} &= \orr{p_2} + l_2 \cdot \orr{d_2}\\
\orr{b_1} &= \orr{p_1} - l_1 \cdot \orr{d_1} & \orr{b_2} &= \orr{p_2} - l_2 \cdot \orr{d_2}
\end{align*}
Le critère de collision est simple. Grâce à la forme de la bactérie, il nous
faut juste vérifier qu'aucun point du segment $[f_1,b_1]$ n'est à une distance
inférieure ou égale à $d_{\mathrm{min}} = r_1+r_2$ d'un point du segment
$[f_2,b_2]$. Aussi, nous commencerons par construire les projections
orthogonales restreintes à un segment des pôles $\orr{f}^j_i, \orr{b}^j_i$ d'une
bactérie $i$ sur le corps d'une bactérie $j$.
\begin{align*}
\orr{f}^2_1 &= \orr{p_2} +
\big[ \orr{d_2} + (\orr{f_1} - \orr{p_2}) \big]^{l_2}_{-l_2}
\cdot{} \orr{d_2} &
\orr{f}^1_2 &= \orr{p_1} +
\big[ \orr{d_1} + (\orr{f_2} - \orr{p_1}) \big]^{l_1}_{-l_1}
\cdot{} \orr{d_1} \\
\orr{b}^2_1 &= \orr{p_2} +
\big[ \orr{d_2} + (\orr{b_1} - \orr{p_2}) \big]^{l_2}_{-l_2}
\cdot{} \orr{d_2} &
\orr{b}^1_2 &= \orr{p_1} +
\big[ \orr{d_1} + (\orr{b_2} - \orr{p_1}) \big]^{l_1}_{-l_1}
\cdot{} \orr{d_1}
\end{align*}
Restreindre la projection a un segment reflète le fait qu'une bactérie a une
longueur \emph{limitée}. Si on omet cette restriction, on obtient les
projections de la \textsc{Fig.}~\ref{fig:collision}, où la distance la plus courte
n'est pas nécessairement indicatrice d'une collision. Il nous reste à obtenir
les 4 vecteurs de collisions
\begin{align*}
\orr{n}_{f_{12}} &= \orr{f}^2_1 - \orr{f}_1 & \orr{n}_{f_{21}} &= \orr{f}^1_2 - \orr{f}_2 \\
\orr{n}_{b_{12}} &= \orr{b}^2_1 - \orr{b}_1 & \orr{n}_{b_{21}} &= \orr{b}^1_2 - \orr{b}_2
\end{align*}
dont les normes nous donnent bien la distance entre les corps des bactéries. Si
$\| \orr{n}_{f_{12}} \| \le d_{\mathrm{min}}$ ou $\| \orr{n}_{b_{12}} \| \le
d_{\mathrm{min}}$ ou $\| \orr{n}_{f_{21}} \| \le d_{\mathrm{min}}$ ou $\|
\orr{n}_{b_{21}} \| \le d_{\mathrm{min}}$, alors il existe au moins une collision
entre les deux bactéries. Le point d'impact se trouve sur le segment entre
le pôle de la première bactérie et son projeté sur le corps de la seconde.
Supposons que la collision ait lieu lorsque les corps des deux bactéries sont au
contact, alors les points de collisions peuvent être les suivants
\begin{align*}
\orr{c}_{f_{12}} &= \displaystyle\frac{r_1 \cdot\orr{f}_1 + r_2 \cdot\orr{f}^2_1}{r_1 + r_2} & \orr{c}_{f_{21}} &= \displaystyle\frac{r_2 \cdot\orr{f}_2 + r_1 \cdot\orr{f}^1_2}{r_1 + r_2} \\
\orr{c}_{b_{12}} &= \displaystyle\frac{r_1 \cdot\orr{b}_1 + r_2 \cdot\orr{b}^2_1}{r_1 + r_2} & \orr{c}_{b_{21}} &= \displaystyle\frac{r_2 \cdot\orr{b}_2 + r_1 \cdot\orr{b}^1_2}{r_1 + r_2}
\end{align*}
\paragraph{Modèle physique post-collision}
Pour calculer le résultat des échanges de forces lors d'un impact entre une
bactérie $i$ et une bactérie $j$, il est nécessaire de déterminer le type
d'impact que nous souhaitons représenter. Dans le cas d'un impact parfaitement
élastique, toute l'énergie transmise à la bactérie est restituée et l'énergie
cinétique du système est conservée. Dans le cas d'un impact inélastique, une
partie de l'énergie est dissipée et seule une partie de l'énergie totale est
restituée. En une dimension, les vitesses post-collision de deux objets $a$ et
$b$ sont données par les deux équations suivantes
\[
v_a = \displaystyle\frac{Cr\ m_b (u_b - u_a) + m_a u_a + m_b u_b}{m_a + m_b}
\qquad
v_b = \displaystyle\frac{Cr\ m_a (u_a - u_b) + m_a u_a + m_b u_b}{m_a + m_b}
\]
\begin{itemize}
\item $Cr \in [0,1]$ est le \emph{coefficient de restitution}, $0$ pour une
collision parfaitement inélastique et $1$ pour une collision parfaitement
élastique;
\item $u_a, u_b$ sont les vitesses avant collision des objets $a, b$
respectivement;
\item $m_a, m_b$ sont les masses des objets $a, b$ respectivement.
\end{itemize}
Dans le cas d'une collision en 2D, nous pourrions appliquer ces deux équations
sur chacune des deux composantes des vecteurs vitesse, mais il nous manquerait
les informations sur le moment angulaire de chaque bactérie. Nous utilisons un
modèle un peu différent, ajusté à la collision de corps en 2D dont voici la
description.
\noindent
Les vecteurs vitesse \emph{au point de collision} pré-collision sont
\[
\orr{v}_{ac1} = \orr{v}_1 + \orr{\omega}_1 \wedge \orr{r}_1
\qquad
\orr{v}_{ac2} = \orr{v}_2 + \orr{\omega}_2 \wedge \orr{r}_2
\]
Notre objectif est de trouver les nouvelles valeurs $\orr{v}'_i$ et
$\orr{\omega}'_i$ des deux bactéries après la collision. Écrivons d'abord les
vecteurs vitesse au point de collision post-collision
\[
\orr{v}_{pc1} = \orr{v}'_1 + \orr{\omega}'_1 \wedge \orr{r}_1
\qquad
\orr{v}_{pc2} = \orr{v}'_2 + \orr{\omega}'_2 \wedge \orr{r}_2
\]
Les vitesses relatives au point d'impact $\orr{v}_{ac12}, \orr{v}_{pc12}$
pré-collision et post-collision respectivement sont données par
\[
\orr{v}_{ac12} = \orr{v}_{ac1} - \orr{v}_{ac2}
\qquad
\orr{v}_{pc12} = \orr{v}_{pc1} - \orr{v}_{pc2}
\]
Dans notre modèle, nous faisons l'hypothèse que la vitesse à laquelle les deux
bactéries se séparent est proportionnelle à la vitesse à laquelle les deux
bactéries se rapprochent.
\begin{equation*}
\orr{v}_{pc12} \cdot{} \orr{n} = -\mathit{Cr}\ \orr{v}_{ac12} \cdot{} \orr{n}
\end{equation*}
Nous retrouvons ici le coefficient de restitution $\mathit{Cr} \in [0,1]$ et
\orr{n} est le \emph{vecteur normal unitaire} ($\|\orr{n}\| = 1$) au point de
collision pointant vers l'extérieur de la seconde bactérie.
La collision en elle-même est modélisée par une \emph{impulsion}. Pour une
bactérie quelconque, rencontrer un obstacle équivaut à se voir appliquer une
force au point de collision, dont la durée d'application est suffisamment courte
pour qu'elle soit considérée \emph{constante}. Cette application s'effectue
\emph{sans frottements} ce qui implique qu'elle soit dirigée selon \orr{n}, la
normale de collision. Une impulsion $\orr{J} = j \cdot \orr{n}$ est
l'intégration de cette force sur $\Delta_t = t' - t$ le temps d'application
\[
\orr{J} = \int^{t'}_t \orr{F} dt
\]
Comme d'après la seconde loi de Newton, une force est la dérivée temporelle
d'une quantité de mouvement et que l'on suppose $\Delta_t$ suffisamment court
pour que \orr{F} ne varie pas, une impulsion est une variation entre les
quantités de mouvement entre les temps $t$ et $t'$ et a donc la dimension d'une
quantité de mouvement. La collision modifie les vitesses des deux bactéries
selon \orr{n} avec l'intensité $j$. En divisant le tout par la masse, on
retrouve la dimension d'une vitesse. L'impulsion s'applique selon \orr{n} pour
la première bactérie et selon $-\orr{n}$ pour la seconde.
\begin{equation*}
\orr{v}'_{1} = \orr{v}_{ac1} + j \orr{n} / m_1
\qquad
\orr{v}'_{2} = \orr{v}_{ac2} - j \orr{n} / m_2
\end{equation*}
Les vitesses angulaires sont aussi modifiées de manière symétrique en prenant en
compte la distance au centre de rotation des bactéries — si cette distance est
nulle, la vitesse angulaire est nulle — et en divisant cette fois
par le moment d'inertie de chacune des bactéries
\begin{equation*}
\orr{\omega}'_{1} = \orr{\omega}_{ac1} + (\orr{r}_1 \wedge j \orr{n}) / I_1
\qquad
\orr{\omega}'_{2} = \orr{\omega}_{ac2} - (\orr{r}_2 \wedge j \orr{n}) / I_2
\end{equation*}
\noindent
Après résolution des équations précédentes pour $j$, on obtient
\begin{equation*}
j = \displaystyle\frac{-(1 + Cr)\ \orr{v}_{ac12} \cdot{} \orr{n}} { 1/m_1 +
1/m_2 + (\orr{r}_1 \wedge \orr{n})^2 / I_1 + (\orr{r}_2 \wedge \orr{n})^2
/ I_2}
\end{equation*}
et il est possible de déterminer le quadruplet $(\orr{v}'_1, \orr{\omega}'_1,
\orr{v}'_2, \orr{\omega}'_2)$ post-collision. Plus généralement, l'impulsion
résultant d'une collision entre une bactérie $a$ et une bactérie $b$ se notera
$j_{ab}$.
Dans le cas de plusieurs collisions simultanées de la bactérie $1$ avec les
bactéries $(2,\ldots,N)$, dans la mesure ou chaque bactérie est indépendante,
les vitesses linéaires et angulaires post-collision de la bactérie $1$ sont
\begin{equation*}
\orr{v}'_1 = \orr{v}_{ac1} + \sum^N_{k=2} \frac{j_{1k}\orr{n}}{m_1}
\qquad
\orr{\omega}'_1 = \orr{\omega}_{ac1} + \sum^N_{k=2} \frac{\orr{r}_1 \wedge j_{1k}\orr{n}}{I_1}
\end{equation*}
l'impulsion étant le seul terme dépendant de la collision, il est différent pour
chacune des collisions.
% Les places sont limitées
\paragraph{Fonction de transition locale}
La méthode naïve pour détecter les collisions entre un nombre arbitraire de
bactéries est d'effectuer un test de collision pour chaque paire de bactéries,
c'est à dire $\binom{n}{2}$ combinaisons, ce qui n'est pas atteignable pour une
population de l'ordre de \num{E4} individus avec les contraintes que nous nous
sommes fixées. Pour résoudre ce problème, nous utiliserons le fait que, comme
nous effectuons une simulation physique, nous partons du principe que tout ce
qui cause un changement d'état du système a un \emph{effet local} et se
\emph{propage} de proche en proche. C'est bien le chemin que nous avons emprunté
en choisissant les automates cellulaires comme support de la simulation. Nous
devons déterminer comment effectuer notre recherche de collision localement pour
qu'elle soit correcte à l'échelle de la population. Nous allons donc restreindre
la recherche de collision à un petit groupe de bactéries, contenu dans une
cellule de l'automate. Le nombre de bactéries par cellule $\mathit{nbpc}$ dépend
de plusieurs paramètres:
\begin{itemize}
\item l'aire minimum d'une bactérie $S_{\mathit{min}}$ (dépendant de
$l_{\mathit{min}}$ et $r_{\mathit{min}}$);
\item l'aire d'une cellule $C_p$ de diffusion du moteur physique.
\end{itemize}
Nous donnons une dimension physique concrète aux cellules car nous allons devoir
superposer les deux automates cellulaires des moteurs physique et chimiques pour
savoir où les bactéries déposent et consomment des morphogènes. De plus, nous
gardons un rapport entier entre les aires des cellules $C_p$ du moteur physique
et $C_c$ du moteur chimique afin que les deux grilles soient toujours alignées.
\[
\mathit{nbpc} = \left\lfloor
\displaystyle\frac{C_p}{S_{\mathit{min}}}
\right\rfloor
\qquad \text{et} \qquad
C_p = n_r \times C_c
\]
Le rapport entre $C_p$ et $C_c$, noté $n_r$, est un entier.
L'espace ainsi segmenté en cellules est une \emph{configuration}. Afin que notre
automate cellulaire soit complet, il nous reste à spécifier la fonction de
transition locale à utiliser pour mettre à jour cette configuration.
\begin{algorithm}
\SetKwData{Evol}{evol}
\SetKwData{GCol}{getCollisions}
\SetKwData{UpBact}{updateBacteria}
\SetKw{KwFrom}{from}
\SetKw{And}{and}
\SetKwData{NBPC}{$\mathit{nbpc}$}
\SetKwProg{Fn}{Fonction}{ as}
\Fn{\Evol(c: cell, $n_1$: cell, $\ldots$, $n_8$: cell): cell}{
\For{$i$ \KwFrom $0$ \KwTo $\NBPC - 1$}{
\tcp{Calcul de collision}
$v \gets 0$,
$\omega \gets 0$\;
\ForAll{$c_n \in \{c,n_1,\ldots,n_8\}$}{
\For{$j$ \KwFrom $0$ \KwTo $\NBPC - 1$}{
\If{$c[i] \ne c_n[j]$ \And $\GCol (c[i],c_n[j],\orr{c},\orr{n},\orr{j})$}{
$v \gets v + \frac{\orr{j}}{c[i].m}$,
$\omega \gets \omega + \frac{(\orr{c} - c[i].\orr{p}) \wedge \orr{j}}{c[i].I}$\;
}
}
}
\tcp{Mise à jour de position}
$\UpBact (v,\omega)$\;
}
\Return{$c'$}\;
}
\caption{Fonction de transition locale du moteur physique}
\end{algorithm}
La fonction |getCollisions| effectue les calculs de collision présentés
ci-dessus et retourne |true| si une collision est détectée et |false| sinon.
Les variables \orr{c}, \orr{n} et \orr{j} sont passées par adresse et sont
définies seulement dans le cas d'un collision.
\FloatBarrier
\subsection{Moteur de décision: bactéries et morphogènes réunis}
La coordination entre moteur chimique et moteur physique est le dernier problème
à résoudre. En effet, pour être complet, les deux parties du simulateur doivent
communiquer:
\begin{itemize}
\item les bactéries peuvent \emph{lire} des valeurs des concentrations en
morphogène \emph{à leur position} et
\item les bactéries peuvent \emph{consommer} ou \emph{déposer} des
morphogènes à leur position.
\end{itemize}
Lire, consommer et déposer des morphogène implique que la fonction d'évolution
des bactéries doit avoir connaissance de la configuration de l'automate chimique
et doit pouvoir la modifier. Il n'est pas souhaitable que les bactéries écrivent
directement dans les cellules de la configuration de l'automate chimique car ces
valeurs dépendent du temps et sont intégrées numériquement. Une meilleure
solution est de faire déposer par les bactéries une contribution $\epsilon$ qui
sera ajoutée lors de l'intégration numérique pendant la mise à jour de
l'automate chimique. Nous reprenons l'équation \ref{eq:num-int} auquel nous
ajoutons un nouveau terme:
\begin{align*}
\displaystyle
\varphi^{t + \Delta t}_{k,i,j} &= \Delta t\,\text{X}_1(\varphi^t_{1,i,j}, \ldots, \varphi^t_{k,i,j})
+ \frac{\text{D}_k\Delta t}{(\Delta x)^2}
(\varphi^t_{k,i-1,j} + \varphi^t_{k,i+1,j} + \varphi^t_{k,i,j-1} + \varphi^t_{k,i,j+1}
- 4\varphi^t_{k,i,j}) + \Delta t\,\epsilon_{\varphi_k,i,j}
\end{align*}
Ensuite, les deux configurations des automates physique et chimique doivent se
superposer dans l'espace afin de lier la position d'une bactérie à la
concentration en morphogènes à cette position. À la position du centre d'une
bactérie $(p_x,p_y)$ correspond une cellule de la configuration de l'automate
cellulaire du moteur chimique
\begin{equation*}
\left(\frac{p_x}{\Delta x},\frac{p_y}{\Delta x}\right)
\end{equation*}
$\Delta x$ est la taille du côté d'une cellule de cet automate et à condition
qu'à la position $(0,0)$ corresponde la cellule de coordonnées $(0,0)$.
La contrainte suivante concerne la taille des configurations. Nous avons indiqué
dans la section~\ref{sec:boundingbox} que les dimensions des configurations
variaient en fonction de leur contenu. Comme une bactérie doit toujours pouvoir
lire, écrire ou consommer des morphogènes, cela implique que la partie de
l'espace $S_c$ couvert par la configuration du moteur chimique doit inclure la
partie de l'espace $S_p$ couvert par la configuration du moteur physique, soit
$S_p \subset S_c$.
Finalement, lorsque les bactéries ont accès aux concentrations de morphogènes,
elles peuvent s'en servir pour modifier leur comportement ce qui est l'objet du
moteur de décision. Chaque bactérie a un état prédéfini en début de simulation
qui regroupe les différents variables normales et booléennes (dont la valeur par
défaut est donnée entre parenthèses) suivants
\begin{itemize}
\item Division (vrai): si vrai, la bactérie croît et se divise quand sa masse a
doublé;
\item Décès (faux): si vrai, la bactérie décide d'entrer en apoptose et
disparaît de la simulation;
\item TumbleRun (vrai): si vrai, la bactérie tourne sur elle-même, sinon la
bactérie se déplace selon une trajectoire rectiligne uniforme vers l'avant;
\item Production/Consommation du morphogène $\varphi_i$: la bactérie dépose une
certaine quantité de morphogènes à sa position dans l'environnement. Cette
quantité est déterminée par le modélisateur en début de simulation.
\end{itemize}
Les transitions entre les états sont également donnés en début de simulation
dans un fichier de description de simulation \sbgp.
Le fonctionnement du moteur de décision est donné par la fonction de transition
décrite dans l'algorithme~\ref{algo:decision}. Cette dernière est appelée sur
chaque cellule de la configuration de l'automate du moteur physique directement,
sans passer par \ppm car il n'y a pas conflit en lecture ou en écriture et
peut être parallélisée naïvement. Cette fonction a de plus à sa disposition
la configuration de l'automate du moteur chimique $\mathit{H}$ ainsi qu'une
configuration $\mathit{E}$ des contributions aux concentrations des morphogènes
de la même taille que $\mathit{H}$. Nous considérerons une simulation où il y
a $N$ morphogènes. Dans l'algorithme~\ref{algo:decision}, toutes les valeurs
précédées de |init| sont issues de l'initialisation de la simulation.
\begin{algorithm}
\SetKwData{Evol}{evol}
\SetKw{KwFrom}{from}\SetKw{KwIn}{in}\SetKw{And}{and}\SetKw{KwBreak}{break}
\SetKwData{NBPC}{$\mathit{nbpc}$}
\SetKwProg{Fn}{Fonction}{ as}
\Fn{\Evol(c: cell, H: configuration, E: configuration): cell}{
\For{$i$ \KwFrom $0$ \KwTo $\NBPC - 1$}{
\tcp{Indice de la cellule de $H$ correspondant à la bactérie courante}
$j \gets projection(H,(c[i].px,c[i].py))$\;
\tcp{Mise à jour de la bactérie pour chaque morphogène}
\For{$k$ \KwFrom $0$ \KwTo $N - 1$}{
E[i][k] <- E[i][k] + |init.behavior.(c[i].type).EmitSignal[k].value|
}
\tcp{Transition vers un nouveau type}
\For{$t$ \KwIn |init.transisition.(c[i].type)|}{
\If{|init.cond_transition.t|}{
$c[i].type \gets t$\;
\KwBreak\;
}
}
}
\Return{$c'$}\;
}
\caption{\label{algo:decision}Fonction de transition locale du moteur de
décision}
\end{algorithm}
\noindent
En prenant en compte toutes les contraintes précédentes, l'exécution d'un pas de
simulation s'effectue de la façon suivante:
\begin{enumerate}
\item un pas du moteur physique,
\item un pas du moteur chimique,
\item redimensionnement des configurations et
\item un pas du moteur de décision.
\end{enumerate}
\FloatBarrier
\section{Mise en œuvre}\label{sec:mise-en-oeuvre}
Dans cette section nous présentons trois exemples de simulation avec \otb. Pour
chacun de ces exemple nous fournissons le rendu de l'interface graphique et
le fichier SBGP qui l'a engendré. Ces trois exemples mettent en évidence le
fonctionnement de chacun des moteurs (chimique, physique et de décision).
% Chimique BZ
\subsection{Une réaction de Belooussov-Jabotinski}
\label{sec:bz}
\newcommand{\gfp}{\ensuremath{\mathit{bleu}}}%
\newcommand{\rfp}{\ensuremath{\mathit{vert}}}%
Les réactions de Belooussov-Jabotinski (BZ) sont une classe de réactions
chimiques dans laquelle les concentrations de plusieurs réactants oscillent
périodiquement jusqu'à épuisement de l'un d'entre eux. Leur importance réside
dans le fait que l'état d'équilibre n'est pas atteint immédiatement mais après
une série d'oscillations pouvant prendre plusieurs minutes. Quand elle est
effectuée dans une boîte de Petri, il est possible d'observer des vagues de
réactions.
Dans le cas de notre moteur chimique, nous pouvons facilement spécifier les
réactions et les couleurs associés à chacun des morphogènes. Nous construisons
donc cette réaction avec le minimum de réactifs et de réactions nécessaires,
soit deux réactifs \gfp{} et \rfp{} et les trois réactions suivantes:
\begin{align*}
\gfp + \rfp &\xrightarrow{0.05} 2 \rfp\\
\gfp &\xrightarrow{0.05} 2 \gfp\\
\rfp &\xrightarrow{0.05} .\\
\end{align*}
\noindent
La configuration de la simulation décrite en \sbgp{} est la suivante
\begin{SBGPcode}
{
"signals" : [ ["bleu", 0.0, 1.0], ["vert", 0.0, 1.0] ],
"reactions" : [ [["bleu","vert"], ["vert","vert"], 0.05],
[["bleu"], ["bleu","bleu"], 0.05],
[["vert"], [], 0.05] ],
"type" : [],
"behavior" : {},
"transition" : [],
"cond_transition" : []
}
\end{SBGPcode}
où les quatre derniers champs sont vides car il n'y a pas de bactéries à
simuler. Durant la simulation, il est possible d'observer une alternance entre
les concentrations des deux morphogènes (en vert et en bleu) au cours du temps.
Comme les morphogènes diffusent, ne s'évaporent pas et que l'environnement
est ouvert, les concentrations locales baissent et il devient de plus en
plus difficile de distinguer les deux morphogènes au centre. Par contre, des
vagues de concentrations alternant bleu puis vert se forment à la périphérie
conformément aux réactions BZ effectuées en boîte de Petri.
% Réaction BZ
\begin{figure}[ht]
\centering
\includegraphics[width=.245\textwidth]{figures/BZ-reaction1}
\includegraphics[width=.245\textwidth]{figures/BZ-reaction2}
\includegraphics[width=.245\textwidth]{figures/BZ-reaction3}
\includegraphics[width=.245\textwidth]{figures/BZ-reaction4}
\caption{Quatre états d'une simulation de réaction BZ ordonnés en fonction du
temps de gauche à droite. Il est possible de noter l'alternance entre le
vert et le bleu au cours du temps}
\label{fig:reaction-BZ}
\end{figure}
\subsection{Sectorisation d'une population de \ecoli{}}
Pour la validation du moteur physique, nous avons reproduit une expérience de la
littérature~\cite{hallatschek_genetic_2007}. Dans cet article, les auteurs
étudient la ségrégation génomique à la frontière entre deux populations de
bactéries en croissance.
\paragraph{Protocole expérimental} Les auteurs utilisent deux souches de
bactéries \Ecoli{} de génotypes exactement identique, à l'exception d'une unique
mutation du même gène promoteur induisant
\begin{itemize}
\item la première souche à produire une protéine fluorescente cyan (CFP) et
\item la seconde souche à produire une protéine fluorescente jaune (YFP).
\end{itemize}
On répartit de façon homogène ces deux souches pour obtenir des cultures de
différentes proportions. Une gouttelette de cette culture est posée au centre
d'une gélose pour dénombrement dans un milieu contenant un médium de croissance
enrichi afin d'obtenir une croissance rapide des deux populations. Comme les
bactéries utilisées sont immobiles, le développement de la population s'effectue
aux bords. Dans le cas d'un mélange équilibré contenant 50\% de chaque souche,
il est possible d'observer des secteurs monochromes dans la zone d'expansion de
la population.
D'après les auteurs de~\cite{hallatschek_genetic_2007}, la
\textsc{Fig.}~\ref{fig:sectorisation} à gauche: « […] is a visible manifestation of
random genetic drift acting at the leading edge of a range expansion ». La
dérive génétique (genetic drift) est l'évolution d'une population ou d'une
espèce causée par des phénomènes aléatoires, impossible à prévoir. Du point de
vue génétique, c'est la modification de la fréquence d'un allèle, ou d'un
génotype, au sein d'une population, indépendamment des mutations, de la
sélection naturelle et des migrations.
\paragraph{Simulation avec \otb} Dans notre simulation de cette expérience, nous
avons utilisé deux états différents ayant le même comportement pour les deux
souches de bactéries afin de pouvoir colorer les deux sous populations a
posteriori. Voici le protocole que nous avons suivi:
\begin{enumerate}
\item nous avons initialement laissé croître une population initiale issue d'une
unique bactérie jusqu'à \num{1054} individus, pour obtenir une goutte de
l'ordre du dixième de millimètre;
\item nous avons marqué chaque individu par l'état $A$ avec une probabilité de
50\%, les autres ont été marqué par l'état $B$;
\item Nous avons repris la croissance de cette population jusqu'à atteindre une
population de \num{271958} individus (voir Fig.~\ref{fig:sectorisation}) après
vingt minutes de calcul sur un serveur muni d'une carte de calcul
Tesla\footnote{NVidia Tesla est une carte de calcul dédié munie de plusieurs
GPU};
\item nous avons fait émettre aux individus de type $A$ un morphogène de couleur
verte et aux individus type $B$ un morphogène de couleur rouge, afin de
pouvoir observer qualitativement la répartition des bactéries.
\end{enumerate}
Bien qu'idéalement il nous faudrait une population de l'ordre de \num{E6}
individus pour être dans les mêmes conditions que le protocole expérimental,
nous avons obtenu un résultat qualitativement très proche des photos présentées
dans l'article original. Étonnamment, nos bactéries rudimentaires, par les seules
contraintes mécaniques du moteur physique, se répartissent en secteurs lors de
la croissance de la population.
% Sectorisation
\begin{figure}[ht]
\centering
\includegraphics[height=.4\textwidth]{figures/sectors-original}\hspace{1cm}
\includegraphics[height=.4\textwidth]{figures/sectors}
\caption[Deux population de bactéries \ecoli{} croissant librement:
comparaison avec un résultat de la littérature.] {Deux population de
bactéries \ecoli{} croissant librement dans un milieu riche en nutriment.
La figure de droite est issue de la fenêtre de rendu du simulateur \otb.
La figure de gauche est issue de~\cite{hallatschek_genetic_2007} pour
comparaison}
\label{fig:sectorisation}
\end{figure}
\FloatBarrier
% Ensemble Cercles concentriques
\subsection{Une population stable ?}
Les bactéries croissent, se divisent et entrent en apoptose. Nous avons tenté
dans cette simulation d'obtenir une population stable ou au moins croissant
linéairement. Intuitivement, l'idée que avons suivie est de faire en sorte que
les bactéries croissent en cercles concentriques autour de la bactérie mère
initiale. Cette dernière dépose un morphogène, appelé «Vert» dans le modèle,
et se divise en deux bactéries: une nouvelle bactérie mère et une bactérie
fille qui change d'état immédiatement. Cette nouvelle bactérie fille dépose
un morphogène «Rouge» dans l'environnement. L'ensemble des bactéries filles
forme alors un premier anneau autour de la bactérie mère. Si ces dernières ne
perçoivent pas un taux de morphogène «Vert» suffisamment grand, signifiant
qu'elles sont trop éloignées, alors elles changent à nouveau d'état.
Voici le comportement que nous avons spécifié en SBGP:
\begin{SBGPcode}
{
"signals" : [ ["Vert", 0.01, 2.5],
["Rouge", 0.001, 1.5],
["Bleu", 0.001, 1.5] ],
"reactions" : [],
"type" : [ "LEADER",
"CDAUGHTER",
"FDAUGHTER",
"DEAD" ],
"behavior" : {
"LEADER" : [ { "Divide" : [] },
{ "Tumble" : [] },
{ "EmitSignal" : [ "Vert", 50 ] } ],
"CDAUGHTER" : [ { "Divide" : 0.005 },
{ "Tumble" : [] },
{ "EmitSignal" : [ "Rouge", 50 ] } ],
"FDAUGHTER" : [ { "Divide" : 0.005 },
{ "Tumble" : [] },
{ "EmitSignal" : [ "Bleu", 50 ] } ],
"DEAD" : [ { "Die" : [] } ]
},
"transition" : [
["NA","NA","NA","NA"],
["CD","NA","NA","NA"],
["NA","CF","NA","NA"],
["NA","NA","CA","NA"]
],
"cond_transition" : [
{"CD" : "IsDaughter()"},
{"CF" : "LessThreshold(Vert,0.1)"},
{"CA" : "And(LessThreshold(Rouge,0.1),LessThreshold(Bleu,10.0))"}
]
}
\end{SBGPcode}
\noindent
Les bactéries peuvent être de quatre types:
\begin{enumerate}
\item |LEADER| est la première bactérie de la simulation. Elle dépose le
morphogène vert dans l'environnement;
\item |CDAUGHTER| sont les bactéries filles directes de la bactérie de type
|LEADER|. Elles déposent le morphogène |Rouge| dans l'environnement;
\item |FDAUGHTER| sont les bactéries filles qui sont assez éloignées de la
bactérie de type |LEADER| d'après la concentration en morphogène |Vert|.
Elles déposent le morphogène |Bleu| dans l'environnement;
\item |DEAD| sont les bactéries filles qui se sont trop éloignées de la
bactérie de type |LEADER| et qui meurent quand les concentrations en
morphogènes |Vert| et |Bleu| sont trop faibles.
\end{enumerate}
\begin{figure}[ht]
\centering
\includegraphics{figures/stablePopulation}
\caption{Graphique de la simulation « Une population stable? » présentant le
nombre de bactérie en fonction du temps de simulation. Après une phase de
croissance linéaire, la population se stabilise autour de \num{6000}
individus}
\label{graph:stablePopulation}
\end{figure}
\begin{figure}[ht]
\centering
\includegraphics[width=.45\textwidth]{figures/ftl01}\hspace{1em}
\includegraphics[width=.45\textwidth]{figures/ftl02}\vspace{1em}
\includegraphics[width=.45\textwidth]{figures/ftl03}\hspace{1em}
\includegraphics[width=.45\textwidth]{figures/ftl05}
\caption[Différentes étapes de la simulation «Une population
stable?».]{Différentes étapes de la simulation « Une population stable? ».
La bactérie mère (en haut à gauche) se divise une première fois et sa fille
change d'état (en haut à droite). Après un certain nombre de divisions,
une des bactérie est suffisamment éloignée de la bactérie mère et change
d'état (en bas à gauche). Plus tard dans la simulation, les bactéries «
bleues » trop éloignées de la bactérie mère meurent à la périphérie.}
\label{fig:stablePopulation}
\end{figure}
\FloatBarrier
\section{Conclusion et perspectives}
Cette courte section vise à rappeler les principaux résultats obtenus suite à
nos travaux sur le simulateur de bactéries \otb ainsi que nos futures pistes de
travail sur le sujet.
\subsection{Conclusion}
% Résumé des épisodes précédents
Dans ce chapitre nous présentons \otb, un simulateur d'une population de
bactéries \Ecoli{}. Nous débutons ce chapitre en présentant nos motivations
pour le développement d'\otb ainsi que les choix techniques que nous avons
fait: l'utilisation de \ocaml, de \opencl et \opengl. Nous avons ainsi décidé
de tirer partie du parallélisme présent dans les ordinateurs grand public,
ce qui nous a amené à développer \ppm, un algorithme inspiré des travaux des
chapitres précédents (section~\ref{sec:ppm}). \ppm est conçu de sorte que le
contexte nécessaire à l'exécution de chaque kernel lui soit immédiatement
disponible. Ainsi le travail de chaque kernel est effectué de manière autonome
et en parallèle sans accès concurrent à la mémoire. \ppm est utilisé à la fois
pour l'exécution du moteur chimique et pour l'exécution du moteur physique. Ces
deux moteurs étant indépendants, la conception de \otb repose sur un dernier
moteur de décision permettant aux bactéries et à leur support de communiquer par
le couplage des moteurs chimique et physique. Ces trois moteurs sont présentés
dans la section~\ref{sec:implementation}. Nous clôturons le chapitre par
trois simulations permettant de rendre compte du fonctionnement du simulateur
(section~\ref{sec:mise-en-oeuvre}), montrant le fonctionnement des moteurs
chimique, physique et de décision.
% Résultats importants
\noindent
De nos travaux sur \otb nous tirons deux résultats:
\begin{itemize}
\item un résultat théorique: l'algorithme \ppm est générique et peut-être
adapté à d'autres outils travaillant sur les automates cellulaires;
\item un résultat pratique: le simulateur \otb est un exécutable utilisable
librement sur différentes plateformes, principalement pour l'étude de la
morphogénèse dans les populations de \ecoli. Il est modulaire et extensible
et pourrait donc aisément être adapté à d'autres types de population.
\end{itemize}
\subsection{Perspectives}
Nos travaux futurs s'articulent autour des grands axes suivants, dont
l'objectif principal est la pérennisation d'\otb comme outil de simulation:
\begin{description}
\item[Calibration]
Nous projetons de comparer les résultats de simulation avec des résultats
d'expériences \emph{in vivo} connus afin d'étalonner au mieux les moteurs
physique et chimique. Si cela s'avère nécessaire, nous changerons
l'algorithme d'intégration numérique pour une version plus précise, au prix
de la performance. Nous envisageons d'implémenter bien plus d'exemples de
modèles qu'actuellement. Nous considérons dans ce but l'établissement d'une
collaboration avec des scientifiques des sciences du vivant s'intéressant
à la morphogénèse ou plus largement aux dynamiques d'une population de
bactéries.
\item[Performance]
La performance actuelle du simulateur \otb provient principalement d'une
planification en amont de sa conception. Il est encore possible d'améliorer
la vitesse d'exécution du simulateur. Pour cela, il sera nécessaire
d'effectuer des mesures quantitatives afin d'identifier les parties du
programme les plus coûteuses en temps de calcul et les optimiser au mieux,
par rapport à l'environnement dans lequel le simulateur est utilisé et
en fonction des ressources en espace disponible sur le périphérique de
calcul. Il pourra ensuite être envisageable de comparer les performances de
\otb par rapport à d'autres simulateurs de population de bactéries comme
\gro~\cite{jang_specification_2012}.
\item[Interface de sortie]
L'interface utilisateur de \otb est à ce jour rudimentaire. Pour qu'un plus
grand nombre d'utilisateurs puissent utiliser le simulateur au quotidien
il est impératif de lui ajouter quelques fonctionnalités: un meilleur
contrôle à la souris, l'ajout d'obstacles et de flux dans l'environnement
afin de tester l'influence de contraintes mécaniques sur une population
en croissance ou encore présenter plusieurs vues en simultané de la même
population. Il est envisageable d'ajouter d'autres modes de sortie, comme
des mesures quantitatives agrégées sous forme de graphes en fonction du
temps de la simulation comme, par exemple, l'orientation moyenne des
bactéries, leur nombre, leur taille moyenne, leur volume moyen, etc.
\item[Interface d'entrée]
La description d'une simulation par un fichier \sbgp{} peut encore être
améliorée. Il est d'abord nécessaire d'optimiser le contenu de ce fichier
en fonction des informations réellement nécessaire à une simulation \otb
ce qui sera possible une fois le point «Calibration» effectué et après
discussion avec les futurs utilisateurs d'\otb. Il est aussi envisageable
de contrôler \otb à partir d'un programme externe, par exemple une
interface graphique regroupant les interfaces d'entrée et de sortie pour un
usage plus intuitif.
\item[Formes de bactérie]
De part sa conception, \otb est modulaire et extensible. Une piste
de travail futur est l'exploration de la simulation d'autre formes de
bactéries du genre bacillus (comme \ecoli), diplobacillus (des couples de
bâtonnets), streptobacillus (des chaînes de bacillus), coccus (des sphères),
coccobacillus (des ovales), etc. Changer de forme de bactérie implique de
mettre à jour l'algorithme de collision qui a été développé spécifiquement
pour les bactéries bacillaires. Ces développements se feront également en
lien avec le point «Calibration» en fonction des besoins.
\item[Grille hexagonale]
Une propriété des grilles hexagonales est que toutes les cellules ont un
bord en commun et leur centres sont équidistants (ce qui n'est pas le cas
sur une grille carrée, les centres des cellules en diagonale sont plus
éloignés). Nous souhaitons explorer le fonctionnement de \ppm sur ce support
afin de déterminer s'il est possible d'obtenir une diminution des erreurs
de la méthode d'intégration actuelle du moteur chimique et du calcul de
collision du moteur physique.
\item[\mgs]
Dans le point «Interface d'entrée» nous avons indiqué qu'il était
envisageable qu'un programme externe serve d'interface de contrôle pour
\otb. \mgs est un bon candidat pour cette tâche. En effet, nous pouvons
considérer que \otb définit une collection topologique dont les éléments
sont les bactéries. Cette collection est paramétrée par les réactions
entre les morphogènes. Chaque élément de cette collection a pour valeur
la spécification d'un réseau de régulation génétique sous la forme d'un
automate avec nombre fini d'états.
\end{description}