Overblog
Suivre ce blog Administration + Créer mon blog

Modèle probabiliste de propagation d'un épidémie : impact du confinement déconfinement

12 Mai 2020 , Rédigé par Hugues MEUNIER

Le confinement est une excellente mesure pour contrer une épidémie car il permet de limiter les contacts donc les contagions de l'épidémie.

Les simulations ci-dessous ont été générées avec un programme Python qui simule la propagation d'une épidémie via un algorithme de type "jeu de la vie". Les règles de ce "jeu" sont les suivantes :

- population initiale : 10 000 personnes

- cas infectés initiaux : 5 personnes

- taux de décès : 0,005

- durée de la simulation : 200 jours

- la durée d'infection est de 24 jours

- la maladie est létale entre le 10ème jours et le 24 ème

- l'immunité est acquise pour tous les jours restants après le 24ème d'infection.

- trois phases sont définies : la phase 1 de 40 jours qui correspond à la phase de contagion initiale, la phase 2 de confinement qui dure 57 jours et la phase de déconfinement qui dure jusqu'au 200ème jour.

 

1er cas: pas de confinement, une forte épidémie de 200 jours

Sur la simulation, on obtient environ 500 décès soit 5% de la population ce qui est très important (ramené à 67 millions cela ferait plus de 3 millions de décès. On obtient une courbe typique du modèle SIR en cloche mais au bout de 200 jours, nous ne sommes pas encore passés dans la partie décroissante et nous stagnons dans une partie plate.

2ème cas : confinement du 41ème jour à la fin de la simulation (200 jours)

La simulation comprend 2 phases :

- une phase initiale de propagation rapide pendant 40 jours

- et 160 jours de confinement pour ralentir la propagation avec un taux de contagion trois fois plus faible

Sur la simulation, on obtient environ 50 décès soit 0,5% de la population. On obtient une courbe typique du modèle SIR amorti et la propagation du virus s'éteint progressivement compte tenu du manque de contact.

3ème cas : phase initiale de propagation de 40 jours puis confinement de 57 jourspuis déconfinement du 98ème jour à la fin de la simulation (200 jours)

 

On obtiendrait donc un nombre de décès plus important que le cas précédent (2 à 3 fois plus de décès soit un taux de 1 à 1,5%). La dynamique est intéressante car on voit bien l'impact du confinement sur la courbe des cas infectés et le rebond (la "deuxième vague") dû au déconfinement au bout de 97 jours.

Conclusion:

Un confinement est une solution efficace de lutte contre les épidémies car il permet de faire baisser drastiquement le taux de contagion. Un modèle simple du type "jeu de la vie" permet de le démontrer. Un déconfinement entraîne toujours une augmentation du taux de contagion (car les contacts sont plus nombreux). Les modèles montrent que ce déconfinement entraîne une relance de l'épidémie du type de la "deuxième vague". 

Lire la suite

Installation et utilisation de Cryptomator sous Windows 10

5 Mai 2020 , Rédigé par Hugues MEUNIER

Créer un coffre-fort dans Onedrive (ou Dropbox ou autre chemin accessible depuis un poste W10)

 

Introduction

 

Cryptomator est un outil entièrement Opensource et gratuit qui permet de créer des coffres-forts sécurisés en local ou sur des dossiers Cloud. Il est disponible pour Windows 10, MACOS ou linux.

 

Installation

 

Télécharger le programme d’installation ici : www.cryptomator.org/downloads/

 

Valider les clauses de la licence.

 

Sélectionner l’emplacement de l’installation.

 

Sélectionner les composants à installer.

 

Attendre la fin de la copie…

 

Cliquer sur NEXT pour installer la librairie Dokan.

 

Sélectionner les composants à installer (laisser par défaut)

 

Cliquer sur « Install ».

 

Attendre la fin de la copie.

 

Cliquer 2 fois sur « Finish » pour fermer les boîtes de dialogue et ouvrir Cryptmator.

 

 

Ajouter un coffre dans OneDrive pour stocker vos documents sensibles

 

 

 

Le mot de passe (la clé) saisi devra être stockée dans un endroit sécurisé (Keepass ou autre).

 

Continuer en affichant  la clé de récupération et cliquer sur suivant. Pensez à stocker votre clé de récupération dans un autre coffre (Keepass ou Digiposte).

 

Déverrouiller le coffre

 

 

Affichage d’un lecteur D : dans l’explorateur qui contient les fichiers protégés. Vous pouvez l’utiliser comme n’importe quel dossier.

 

Cette vue est une vue logicielle affichée par l’outil Cryptomator. La vue physique dans Onedrive contient un ensemble de fichiers chiffrés et ne peut pas être exploitée sans avoir la clé ou la clé de secours.

 

 

 

Lire la suite

Jeu de la vie épidémique en Python

4 Mai 2020 , Rédigé par Hugues MEUNIER

Les algorithmes du type "jeu de la vie" sont utilisés depuis bien longtemps dans de nombreux domaines. Ils permettent également de simuler la propagation d'un virus dans une population donnée et ils offrent des effets visuels intéressants au niveau de la représentation graphique des résultats. Ils permettent de rendre compte de l'évolution d'un modèle SIR(M) probabilistes.

Le programme ci-dessous a été construit avec les hypothèses suivantes :

- l'immunité acquise ou initiale est permanente

- une personne infectée infecte ses "voisins" avec un taux de contagion probaContag

- la maladie est létale à partir du 8ème jour avec une probabilité de décès de probaDec

- les états possibles sont Sains, Infectés, Immunisés (Remis) ou Morts

Si j'exécute le programme avec les paramètres suivants :

- probaContag = 0.055

- probaDec = 0,005

- NbJours infection = 14

j'obtiens ce genre de simulation (la couleur représente l'état : blanc=sain, rouge=infecté, vert=immunisé, noir=décédé).

Simulation vidéo 1

et la dynamique du modèle est la suivante (l'échelle est logarithmique!) :

 

Cette simulation représente une épidémie très contagieuse; elle se propage très vite et la totalité de la population considérée devient soit immunisée ou soit décédée au bout de 120 jours.

 

Maintenant si j'exécute le programme avec les paramètres suivants :

- probaContag = 0.015

- probaDec = 0,005

- NbJours infection = 14

j'obtiens la simulation suivante:

Simulation vidéo 2

et la dynamique du modèle est la suivante (l'échelle est logarithmique!) :

Le programme python est le suivant :

#
# Simulation de la propagation d'une épidémie
# via un algorithme probabiliste du type jeu de la vie
# Hugues MEUNIER
# avril 2020
#

import numpy as np
from tkinter import Tk, Canvas, Button, RIGHT, LEFT
from random import random
import time
from matplotlib import pyplot as plt
from matplotlib.figure import Figure


# Par défaut le monde est créé en 2 dimensions et de taille NbL*NbC
NbL = 100  # hauteur du tableau
NbC = 100  # largeur du tableau
# NbJours est la durée de l'inefection avant d'être immunisé (l'immunité est supposée acquise)
NbJours = 14 #Nb de jours d'infection (incubation+ maladie) avant d'être remis
a = 7    # taille d'une cellule
NbBoucle = 200 #Nombre de jours pour la simulation

# Définitions des matrices de la simulation
cell = np.zeros((NbL,NbC),dtype=int)
etat = np.zeros((NbL,NbC),dtype=int)
NbGen = 0 # le jour courant

# Définition du dictionnaire des états possibles SAIN, MALADEx, IMMUN, DECES
# il y a x états MALADEx fonction du NbJours pendant lesquels la personne est infectée
state = {"SAIN":0}
bou = 1
# Boucle pour les NbJours d'infection
while bou <= NbJours:
    cle = 'MALADE'+str(bou)
    state[cle] = bou
    bou+=1
state["IMMUN"] = NbJours+1
state["DECES"] = NbJours+2

# Une couleur égale un état
CoulSain = "white"
CoulImmun = "green"
CoulMal = "red"
CoulDec = "black"

# Paramètre de la simulation
DensiteImmun = 0.0    # densité d'individus immunisés dans la population au temps zéro (vaccination ...)
ProbaContag = 0.015     # taux de contagion 0.055 signifie une probabilité de 5,5% de contaminer une personne à chaque contact
ProbaDec = 0.005        # taux de mortalité 0.005 signifie 0,5% de probabilité de décès par jour malade

#Initialisation des tableaux permettant de stocker les statistiques de l'épidémie
D = np.zeros(NbBoucle) # Tableau des personnes décédées
I = np.zeros(NbBoucle)# Tableau des personnes infectées ou malades
R = np.zeros(NbBoucle) #Tableau des personnes rétablies et immunisées
S = np.zeros(NbBoucle) # Tableau des personnes saines
t = np.linspace(0, NbBoucle, NbBoucle) # Tableau qui contient les jours

# Conditions initiales pour le démarrage de la simulation
D[0] = 0
I[0] = 0
R[0] = NbL*NbC*DensiteImmun
S[0] = NbL*NbC -D[0]-I[0]-R[0] 


# Fonction appelée à chaque itération (jour) pour calculer l'état du monde
def iterer(p, tau):
    appliquer_regles(p, tau)
    dessiner()

# Fonction d'initialisation
def initialiser_monde(p):
    # on répartit aléatoirement les personnes immunisées dans le monde
    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"]
                R[NbGen]+=1
    # 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)
    S[0] = NbL*NbC -D[0]-I[0]-R[0]
    canvas.itemconfig(canvas_txt_NbS, text="Nb sains: "+str(S[NbGen]))
    canvas.itemconfig(canvas_txt_NbI, text="Nb infectés: "+str(I[NbGen]))
    canvas.itemconfig(canvas_txt_NbR, text="Nb remis: "+str(R[NbGen]))
    canvas.itemconfig(canvas_txt_NbD, text="Nb décès: "+str(D[NbGen]))
    

# Fonction qui calcule l'état du monde à chaque itération en fonction des règles du jeu suivantes:
# Si un individu est infecté, il infecte tous ses voisins au sens de Von Neumann avec une probabilité égale au taux de contagion
# Si un individu est au NbJours de l'infection soit il décède avec la probabilité égale au taux de décès ou soit il est immunisé
# L'infection est létale uniquement à partir du 8eme jour de l'infection
def appliquer_regles(p,tau):
    global etat
    temp = etat.copy()  # sauvegarde de l'état courant
    for x in range(NbL):
        for y in range(NbC):
            if etat[x,y] >=1 and etat[x,y]<=NbJours:
                if etat[(x-1)%NbL,(y+1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[(x-1)%NbL,(y+1)%NbC] = state["MALADE1"]                                
                if etat[x,(y+1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[x,(y+1)%NbC] = state["MALADE1"] 
                if etat[(x+1)%NbL,(y+1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[(x+1)%NbL,(y+1)%NbC] = state["MALADE1"] 
                if etat[(x-1)%NbL,y] == state["SAIN"]:
                    if random() < p:
                        temp[(x-1)%NbL,y] = state["MALADE1"] 
                if etat[(x+1)%NbL,y] == state["SAIN"]:
                    if random() < p:
                        temp[(x+1)%NbL,y] = state["MALADE1"] 
                if etat[(x-1)%NbL,(y-1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[(x-1)%NbL,(y-1)%NbC] = state["MALADE1"] 
                if etat[x,(y-1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[x,(y-1)%NbC] = state["MALADE1"] 
                if etat[(x+1)%NbL,(y-1)%NbC] == state["SAIN"]:
                    if random() < p:
                        temp[(x+1)%NbL,(y-1)%NbC] = state["MALADE1"] 
                if etat[x,y] == NbJours:
                    if random() < tau:  
                        temp[x,y] = state["DECES"]
                    else:
                        temp[x,y] = state["IMMUN"]
                else:
                    if etat[x,y] >= 7:
                        if random() < tau:  
                            temp[x,y] = state["DECES"]
                        else:
                            temp[x,y] = etat[x,y]+1
                    else:
                        temp[x,y] = etat[x,y]+1            
                
    etat = temp.copy()  # maj de l'état courant


# Dessiner toutes les cellules
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["DECES"]:
                couleur = CoulDec
            if etat[x,y]>=1 and etat[x,y]<=NbJours:
                couleur = CoulMal
            canvas.itemconfig(cell[x][y], fill=couleur)
            
# Animation 
def pasapas():
    global NbGen
    i = 0
    while i < NbBoucle-1:
        NbGen += 1
        canvas.itemconfig(canvas_txt_NbJours, text="NbJours: "+str(NbGen))
        iterer(ProbaContag, ProbaDec)
        Compte()
        canvas.itemconfig(canvas_txt_NbS, text="Nb sains: "+str(S[NbGen]))
        canvas.itemconfig(canvas_txt_NbI, text="Nb infectés: "+str(I[NbGen]))
        canvas.itemconfig(canvas_txt_NbR, text="Nb remis: "+str(R[NbGen]))
        canvas.itemconfig(canvas_txt_NbD, text="Nb décès: "+str(D[NbGen]))
        if I[NbGen] == 0:
            print("Epidémie terminée!")
            Sortie()
            break
        #time.sleep(1)
        i+=1
        canvas.update()
    Sortie()

# Fonction de traitement du clic gauche de la souris
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["MALADE1"]
        I[0]+=1 #on ajoute une personne infectée à chaque clic gauche de la souris
        S[0] = NbL*NbC -D[0]-I[0]-R[0]
        canvas.itemconfig(cell[x][y], fill=CoulMal) #on dessine en rouge la cellule infectée
        canvas.itemconfig(canvas_txt_NbS, text="Nb sains: "+str(S[NbGen]))
        canvas.itemconfig(canvas_txt_NbI, text="Nb infectés: "+str(I[NbGen]))
        canvas.itemconfig(canvas_txt_NbR, text="Nb remis: "+str(R[NbGen]))
        canvas.itemconfig(canvas_txt_NbD, text="Nb décès: "+str(D[NbGen]))

# Fonction de comptage des polupations saines, infectées, décèdées et remises
def Compte():
    nbS = 0
    nbI = 0
    nbR = 0
    nbD = 0
    x=0
    y=0
    while x < NbL:
        while y < NbC:
            if etat[x,y] == state["IMMUN"]:
                nbR+=1
            if etat[x,y] == state["DECES"]:
                nbD+=1
            if etat[x,y] == state["SAIN"]:
                nbS+=1
            if etat[x,y]>=1 and etat[x,y]<=NbJours:
                nbI+=1
            y+=1
        y=0
        x+=1
    I[NbGen] = nbI
    R[NbGen] = nbR
    D[NbGen] = nbD
    S[NbGen] = nbS

# Fonction de sortie de la simulation avec affichage de la courbe d'évolution des populations S, I, R, D
def Sortie():
    fenetre.destroy()
    # Trace les courbes
    fig = plt.figure(facecolor='w')
    fig_size = plt.rcParams["figure.figsize"]
    print("Sortie...")
    fig_size[0] = 36
    fig_size[1] = 24
    plt.rcParams["figure.figsize"] = fig_size
    I2 = np.trim_zeros(I,trim = 'b')
    NbElem = np.size(I2)
    
    
    plt.title('Evolution de l\'épidémie')
    plt.plot(t[0:NbElem], S[0:NbElem], color='blue', label='Sains')
    plt.plot(t[0:NbElem], I[0:NbElem], color='red', label='Infectés')
    plt.plot(t[0:NbElem], R[0:NbElem], color='green', label='Remis')
    plt.plot(t[0:NbElem], D[0:NbElem], color='black', label='Décédés')
    #plt.plot(t, R, color='green', label='Remis')
    plt.xlabel('Nb de jours')
    plt.ylabel('Nb de personnes (log)')
    leg = plt.legend();
    plt.grid()
    plt.yscale('log')
    plt.show()
    # on ne profite pour sauver le graphe au format png
    fig.savefig("simul-ep.png", format='png', bbox_inches='tight')

# Définition de l'interface graphique
fenetre = Tk()
fenetre.title("Le jeu de la vie épidémique")
canvas = Canvas(fenetre, width=a*NbC+150, height=a*NbL+1, highlightthickness=0)
fenetre.wm_attributes("-topmost", True)
# Allocation de la fonction Infecter sur click gauche
canvas.bind("<Button-1>", Infecter)
canvas.pack()

# Définition des boutons de commande
bou1 = Button(fenetre,text='Sortie', width=8, command=Sortie)
bou1.pack(side=RIGHT)
bou2 = Button(fenetre, text='Go!', width=8, command=pasapas)
bou2.pack(side=LEFT)

#Définition des zones de texte pour afficher les compteurs pendant la simulation
canvas_txt_NbJours = canvas.create_text(NbC*a+20,20, anchor="nw")
canvas.itemconfig(canvas_txt_NbJours, text="NbJours: "+str(NbGen))
canvas_txt_NbS = canvas.create_text(NbC*a+20,40, anchor="nw")
canvas.itemconfig(canvas_txt_NbS, text="Nb sains: "+str(S[NbGen]))
canvas_txt_NbI = canvas.create_text(NbC*a+20,60, anchor="nw")
canvas.itemconfig(canvas_txt_NbI, text="Nb infectés: "+str(I[NbGen]))
canvas_txt_NbR = canvas.create_text(NbC*a+20,80, anchor="nw")
canvas.itemconfig(canvas_txt_NbR, text="Nb remis: "+str(R[NbGen]))
canvas_txt_NbD = canvas.create_text(NbC*a+20,100, anchor="nw")
canvas.itemconfig(canvas_txt_NbD, text="Nb décès: "+str(D[NbGen]))

# lancement de l'automate
initialiser_monde(DensiteImmun)
fenetre.mainloop()

Lire la suite