Modélisation de la propagation d'une épidémie par AC

L'objectif de la modélisation

Dans la page consacrée à la modélisation et la simulation, nous avons abordé l'exemple de la propagation d'une épidémie sous l'angle des effectifs de population (le modèle SIR). Dans la présente page, nous allons partir d'un autre point de vue.
Nous allons nous demander comment une épidémie se propage spatialement sur un territoire fermé, à partir d'un petit nombre, paramétrable, de foyers d'infections. Cela nous donnerons l'occasion d'utiliser un outil formidable de modélisation et de simulation : les automates cellulaires, que nous avons déjà rencontrés ici.

Le modèle

L'univers modélisé

Considérons un territoire fermé dans lequel se répartit une population d'individus elle aussi fermée, c'est à dire à effectif constant. J'applique sur ce territoire une grille carrée, qui le décompose en une multitude de cellules, occupées par un individu (ou un groupe d'individus, peu importe).
Comme dans la réalité, la population initiale sera saine. Et parmi les personnes saines, une proportion donnée de la population sera immunisée contre la maladie, naturellement ou par vaccination.

Les règles du modèle

Les règles du fonctionnement du modèle sont très simples, et même simplistes !
Au début de la simulation, un ou quelques individus infectés sont positionnés sur la grille parmi les individus sains. Il n'est pas possible d'infecter un individu immunisé.
Un individu infecté contamine son voisinage, par contact ou voie aérienne. Un voisin sain devient infecté avec une probabilité paramétrée qui correspond à la contagiosité de la maladie. Un voisin immunisé n'est pas contaminé et ne transmet pas la maladie (la notion de porteur sain n'existe pas dans mon modèle). Le voisinage s'entend au sens de Moore, c'est à dire qu'un individu a 8 voisins.
Le calcul de la situation de la population (sain, immunisé, malade) est effectué à chaque génération. Le déroulement des générations se fait pas à pas, ce qui permet d'observer la propagation de l'épidémie sur le territoire.

La modélisation basée sur un automate cellulaire

Le principe

Il s'agit de construire un modèle du comportement de notre système dynamique, la propagation spatiale de l'épidémie, sur la base des mécanismes d'un automate cellulaire (AC). Rappelons-les brièvement:

La modélisation par AC est particulièrement pertinente pour l'étude des systèmes dynamiques discrets, ce qui est notre cas dans l'exemple choisi.

Le script Python

Le script complet est disponible dans ACPropagationEpidemie.py. Je ne signale ci-dessous que les parties intéressantes du script.

La contruction de la grille initiale

Elle est assurée par la fonction initialiser_monde(), qui possède un paramètre p, qui est la densité d'individus immunisés dans la population.

def initialiser_monde(p):   

# répartition aléatoire sur la grille d'état des individus immunisés

etat[0:NbL,0:NbC] = state["SAIN"]

for x in range(NbL):

for y in range(NbC):

if random() < p: 

etat[x,y] = state["IMMUN"]

# création de la grille d'affichage

for x in range(NbL):

for y in range(NbC):

if etat[x,y]==state["SAIN"]:       

coul = CoulSain

if etat[x,y]==state["IMMUN"]:    

coul = CoulImmun   

cell[x,y] = canvas.create_rectangle((x*a, y*a,(x+1)*a,(y+1)*a), outline="gray", fill=coul)

Deux matrices de mêmes dimensions sont utilisées : la matrice etat, qui contient l'état SAIN, IMMUN ou MALADE de chaque cellule/individu; et la matrice cell qui permet de gérer l'affichage de l'automate dans la fenêtre TkInter.

La sélection des individus malades

La fonction Infecter permet de déclarer MALADE un individu sain, qui apparaitra sur la grille dans la couleur représentative des individus malades (rouge dans mon code). Notez qu'il n'est pas possible d'infecter un individu immunisé.

def  Infecter(event):

x, y = event.x//a, event.y//a

# on ne peut pas infecter un individu immunisé

if etat[x,y] != state["IMMUN"]: 

etat[x,y] = state["MALADE"]    

canvas.itemconfig(cell[x][y],fill=CoulMal)

L'instruction suivante permet d'indiquer à TkInter que le clic du bouton gauche dela souris doit provoquer l'appel de la fonction Infecter. Pour infecter un individu sain, l'utilisateur le place sur la grille avec le pointeur de la souris et clique sur le bouton gauche.

canvas.bind("<Button-1>",Infecter)

L'application des règles du modèle

La fonction appliquer_regles est le coeur du script puisque c'est elle qui parcourt, à chaque génération, toutes les cellules de la grille et leur applique les règles d'évolution du modèle. Le paramètre p est la contagiosité, la probabilité d'être infecté au contact de son voisin malade.
Le voisinage appliqué est un voisinage de Moore. La topologie de la grille est torique, c'est à dire que les bords haut et bas et gauche et droit sont collés.
La règle appliquée est simple : si l'individu présent dans la cellule traitée est malade, alors si ses voisins sont sains, ils sont infectés avec une propabilité p.

def appliquer_regles(p):

global etat

temp = etat.copy()  # sauvegarde de l'état courant

for x in range(NbL):

for y in range(NbC):

if etat[x,y] == state["MALADE"]: 

if etat[(x-1)%NbL,(y+1)%NbC] == state["SAIN"]:

if random() < p:

temp[(x-1)%NbL,(y+1)%NbC] = state["MALADE"] 

if etat[x,(y+1)%NbC] == state["SAIN"]:   

if random() < p:

temp[x,(y+1)%NbC] = state["MALADE"]

if etat[(x+1)%NbL,(y+1)%NbC] == state["SAIN"]: 

if random() < p:   

temp[(x+1)%NbL,(y+1)%NbC] = state["MALADE"]

if etat[(x-1)%NbL,y] == state["SAIN"]:  

if random() < p:       

temp[(x-1)%NbL,y] = state["MALADE"]

if etat[(x+1)%NbL,y] == state["SAIN"]:      

if random() < p:     

temp[(x+1)%NbL,y] = state["MALADE"]

if etat[(x-1)%NbL,(y-1)%NbC] == state["SAIN"]    

if random() < p: 

temp[(x-1)%NbL,(y-1)%NbC] = state["MALADE"]

if etat[x,(y-1)%NbC] == state["SAIN"]:     

if random() < p:

temp[x,(y-1)%NbC] = state["MALADE"]

if etat[(x+1)%NbL,(y-1)%NbC] == state["SAIN"]: 

if random() < p:        

temp[(x+1)%NbL,(y-1)%NbC] = state["MALADE"]

etat = temp.copy()  # maj de l'état courant

Une remarque : en début de fonction, je sauvegarde la matrice etat courante et je travaille dans une copie temporaire pour que les changements d'état de chaque cellule ne se propagent pas au cours de la même génération. En fin de fonction, je recopie la matrice temporaire dans la matrice etat. Attention à bien faire une copie et pas une simple affection, qui ne copierait pas le contenu, mais seulement le pointeur de la matrice.

La représentation graphique

Rien de bien remarquable dans cette fonction : elle parcourt la matrice etat et affiche la cellule correspondante de la grille cell en fonction de l'état consigné dans etat.

def dessiner():

for x in range(NbL):    

for y in range(NbC):      

if etat[x,y]==state["SAIN"]:   

couleur = CoulSain 

if etat[x,y]==state["IMMUN"]:     

couleur = CoulImmun

if etat[x,y]==state["MALADE"]:       

couleur = CoulMal      

canvas.itemconfig(cell[x,y], fill=couleur)

Simulation

Les paramètres de la simulation

Le modèle proposé, qui est simpliste, propose deux paramètres de variation:

La population totale est toujours de 1 600 individus (grille de 40x40). Les individus immunisés sont répartis aléatoirement sur la grille.

Des exemples de simulation

Faible densité d'individus immunisés, faible contagiosité

Fixons la densité d'immunisation à 0.2 et la contagiosité à 0.1. Plaçons un individu infecté au milieu d'un cluster d'individus sains.

Au bout de 10 générations (le numéro de la génération courante est inscrit sur votre console Python), j'obtiens :

Propagation I=0.2 C=0.1 G=10

Au bout de 50 générations, presque toute la population saine est infectée :

Propagation I=0.2 C=0.1 G=50
Forte densité d'individus immunisés, faible contagiosité

Fixons la densité d'immunisation à 0.8 et la contagiosité à 0.1. Plaçons 2 individus infectés au milieu d'un cluster d'individus sains.

Au bout de 10 générations (le numéro de la génération courante est inscrit sur votre console Python), l'épidémie est pratiquement stoppée :

Propagation I=0.8 C=0.1 G=10

Au bout de 50 générations, l'épidémie n'a pas évolué, la vaccination est efficace :

Propagation I=0.8 C=0.1 G=50

Faible densité d'individus immunisés, forte contagiosité

Fixons la densité d'immunisation à 0.2 et la contagiosité à 0.5. Plaçons un individu infecté au milieu d'un cluster d'individus sains.

Au bout de 10 générations, l'épidémie a déjà touché le tiers de la population saine :

Propagation I=0.2 C=0.5 G=10

Toute la population est contaminée moins de 30 générations :

Propagation I=0.2 C=0.5 G=29

Autres simulations

Je vous suggère de modifier un peu le code pour enregistrer pour chaque génération l'effectif de la population contaminée. Puis de tracer la courbe correspondante. Vous trouverez une forme qui vous rappellera sans doute des souvenirs si vous retournez sur la page consacrée à la percolation.

Vous pouvez aussi enrichir le modèle en instituant des règles sur la mort des individus contaminés (avec une probabilité de létalité) et aussi sur la guérison (avec une probabilité de guérison spontanée).

Le script Python

Le script Python ACPropagationEpidemie.py étudié dans cette page est disponible dans le package ACEpidemie.zip.


Contenu et design par Dominique Lefebvre - www.tangenteX.com février 2017   Licence Creative Commons    Contact : PhysiqueX ou

Cette œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Pas de Modification 3.0 France.