\documentclass{article} \usepackage{pythonhighlight} \usepackage[english]{babel} % Set page size and margins % Replace `letterpaper' with`a4paper' for UK/EU standard size \usepackage[letterpaper,top=2cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry} % Useful packages \usepackage{amsmath} \usepackage{graphicx} \usepackage[colorlinks=true, allcolors=blue]{hyperref} \title{FCP Epidemic Simulator} \author{Finn Grimmett, Max Latz, Nor Atira Abd Shakor, Otis Lee, Antoine Blackwell} \begin{document} \maketitle \tableofcontents \section{Introduction} \par This project has a simulation that shows how epidemic occurs in the community and a GUI where it can take inputs from user and use it for the simulation. There is also a GUI where the user can choose to see any of the data visualization of COVID-19 in the UK. \par This epidemic simulator helps visualize the spreading of the virus among people and estimates the severity of this infectious disease. User can also compare the simulation results with the real data concerning this epidemic. \section{Running the code} \href{https://github.com/fgrimmett/fcp2021/blob/main/README.md}{README.md} provides the best overview of running the code. Please refer to this. A when using Simulation A note that all data will be deposited in csv files in the file the code is in, to save these rename the files. \section{Project Classes} \subsection{Simulation Class} \subsubsection{Overview} \href{https://github.com/fgrimmett/fcp2021/blob/main/simulation.py}{The first simulation} (this class is also located in the \href{https://github.com/fgrimmett/fcp2021/blob/main/Project_Classes.py}{Project\_Classes}) is a numpy array based model that draws upon a set of arrays to use the factor of age to predetermine whether an individual will: be symptomatic; be hospitalised or die. These outcomes are saved in the arrays: will\_die (line 161), will\_hospital (line 162) and will\_symptomatic (line 163) and the progression through these states is controlled by three more arrays that act as timers, changing state to the next state or recovery when it reaches zero. This model assumes asymptomatic cases to occur 3 days before symptoms and is fixed to last 3 days. Whilst, this is an oversimplification, it encapsulates asymptomatic cases (where the individual progresses to recovered) along with the scenario of symptomatic cases transmitting before symptoms start. This allows the potential of seeing the effect of raw quarantine of those showing symptoms through reducing this rate and the degree of issue caused by asymptomatic cases. \par The above described process is shown in Figure 1. \par The interaction module works by obtaining the values of symptomatic and asymptomatic cases and producing an interaction matrix that represents where this shows the coordinates of the origin and the source. \begin{figure} \centering \includegraphics[width=0.9\textwidth]{Flowchart1.png} \caption{\label{simulation}Flowchart of 'daily operations' of simulator.} \end{figure} \subsubsection{Features} There is a written lockdown feature however the degree of control of transmission variables (range and amount of interactions) demonstrated in the \href{https://github.com/fgrimmett/fcp2021/blob/main/UK2020simulation.py}{simulation} means that this function is for ease of use and much greater control can be applied in this way. \par Additionally death/hospitalisation/symptomatic rates can be changed for age which allows for factors such as vaccination to be considered by reducing the death rate of those in the age groups being vaccinated. A key advantage of this model is its ability to handle large samples, although the transmission process does significantly reduce speed at large values. The UK simulation referenced above uses a sample of 64 million, which whilst slow does produce comparable results. Additionally it is possible \subsubsection{Further Potential / Conclusion} The shielding function described in the Overview would greatly improve the capability of this model, at the expense of significant speed. This would allow the age arrays potential to be used as well as allowing for the vaccination consideration to include transmission as well as deaths ,showing the true effect and the lack of time to produce this is unfortunate. The transmission function is also a sticking point in terms of operation as this is the slowest process and a method to reduce the time this consumes is desirable, although its speed is of little concern below 1 million. \subsection{Animation} \subsubsection{Overview} The Animation class combines two animations to be displayed on the Axis defined in a Figure. The \_\_init\_\_ method calls the GridAnimation and LineAnimation class, to synchronise them to the same changes. Indeed, the simulation.day\_run() function (which moves the simulation by one day in time, making all the changes accordingly) is called in the update method. Thus applying the same changes to all the animations defined. The methods show() and save() use FuncAnimation (method from Matplotlib.animation) to animate everything on the screen. This class works in conjunction with the Simulation class. The object created from the Animation class takes a Simulation class object as a parameter. This allows the animation object to call variables from the Simulation class. The main features of this class stayed the same in the `Project\_Classes` as the `simulator.py` script shared. The end result of the animation is shown in Figure 2. \begin{figure} \centering \includegraphics[width=0.9\textwidth]{animation.png} \caption{\label{animation}Animation of the simulation} \end{figure} \subsubsection{Features} \subsubsection{GridAnimation}\label{gridanimation} The GridAnimation class will produce an RGB (Red-Green-Blue) matrix using the get\_rgb\_matrix method. It is built by applying a color to all the status in the matrix, and showing it with matplotlib's imshow method. Axis points are set to modify the RGB matrix at every day in the simulation. This is then animated as explained above. All the people's status in the matrix are therefore updated according to the interactions methods in the Simulation class. Research were carried out on the FuncAnimation method. A script was written to understand it outside a class first, then it was adapted to work within one. \begin{python} # Libraries to import import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation # This is only a test to experiment the Animation Class from Testing_Simulation import Simulation simulation = Simulation(100, 2, 2, 0.7, 5, 0.6, 3, 100) # Setting up the Figure and axes for the animation to display fig, ax = plt.subplots() # Introducing Covid asymptomatic and symptomatic cases simulation.init_array() # Producing a rgb matrix out of the array state rgb_matrix = simulation.get_rgb_matrix() # print(rgb_matrix) # Setting up an image to show the different days of the simulation image = ax.imshow(rgb_matrix) # Setting up axis points to allow the animate function to modify those points ax.set_xticks([]) ax.set_yticks([]) def animate(i): # Argument 'i' is number of frame we will be working with simulation.day_run() rgb_matrix = simulation.get_rgb_matrix() image.set_array(rgb_matrix) # This method draws the first day/frame of the simulation on the figure and axes return [image] # Passing it all to FuncAnimation animation = FuncAnimation(fig, animate, frames=range(100), blit=True, interval=200) plt.show() \end{python} The main changes are: \begin{itemize} \item New dictionaries to adapt RGB matrix colours to new statuses. \item Adapting the methods in the Simulation class to constantly return the same matrix \item Adding the get\_rgb\_matrix() \end{itemize} \subsubsection{LineAnimation} This class is called with the GridAnimation class by the Animation class. It displays a plot of the number of people in each status as a function of the days the simulation has been running for. The data is plotted at the same time as the GridAnimation changes the people's status (or colours) in the matrix. It was more complex to adapt the code to Finn's Simulation class with the LineAnimation. This class uses a dictionary to store all the lines that will be animated on the screen. In Oscar Benjamin's script, the line\_mpl variable (storing the lines to be plotted) use the keys from the Statuses dictionary with their related colours as values. The data from each status (i.e., number of infected, number of recovered, etc...) are calculated using the get\_percent\_status() method and are appended to the y data of their corresponding lines from the line\_mpl dictionary. This is done with the following code: \begin{python} percents = self.simulation.get_percentage_status() for status, percent in percents.items(): self.ydata[status].append(percent) self.line_mpl[status].set_data(self.xdata, self.ydata[status]) \end{python} This is where a conflict occurs. In Finn's script, the data is calculated and stored with the statistics() method. It was originally made to create Excel files to construct graphs with the GUI (see section \ref{gui}). To overcome this problem, new dictionaries were created with key names similar to the one in the statistics() method in the Simulation class. Thus, the legend in the LineAnimation axes is built with .csv files' name. Furthermore, the statistics() method does not calculate percentage but actual numbers. Thus, the lines plotted have different scales (the simCumulative.csv line will always have the highest y values). To ensure all the plots can be displayed, the y-axis limit is set to 'simulation.size**2' (i.e., the total number of people in the matrix). The x-axis, on the other hand is simply defined by the argparser argument size (see section \ref{commandline}) \subsubsection{Function evolution\_simulation} This function uses the plot\_simulation function from the simulator.py script as a template. It shows the evolution in time of the virus spreading by capturing 'moments' of the simulation at different intervals. Major changes are made throughout the function to adapt it to the day\_run() method and improve it, to offer the user more control over the final aspect of the figure. Those changes include: \begin{itemize} \item Allowing the user to choose the number of image of the simulation displayed on the figure (number of images per row (height) and column (width) \item Introducing an if statement to prevent the user from selecting less days than the number of images to be displayed on the figure. Images are selected at equal intervals in the time domain (days) of the simulation, however if it lasts less than the number of images, some days will be repeated. \item The way the simulation updates itself when days pass. The 'days' variable is a list of N days spaced at equal intervals from each other from Day 0 to Day F (with F = simulation.days equivalent of the last day of the simulation). A for loop is used to update the simulation by the number of days in the simulation. The number of iteration of the for loop is implemented using the range() function. To prevent the simulation from repeating updates, a previous day variable: prev\_day is defined. It starts at 0 and then takes the value of the previous day. This is used in the range function in the for loop, as shown below; \begin{python} for update in range(prev_day, day): # Making sure the simulation is updated by # the number of actual days and not by the number of elements in the days list # (Which is obviously less) or by the number of days in each element in the days # list (which this time is obviously more) simulation.day_run() \end{python} \end{itemize} \section{Folder test\_infection\_simulation} This part of the project features an animation/simulation consisting of 2 files, person.py and simulate\_people.py. It attempts to simulate COVID-19 in a small neighbourhood. The first script person.py gives the "person" object some attributes, both intrinsic properties and COVID-19 related properties. This can include the velocity of the person, or whether the person is infectious, which is stored in the \_\_init\_\_() function. The second script imports the object and visualizes it on a Matplotlib box plot and animated graph subplot. The \_\_init\_\_() function of this script stores all global constants with respect to the environment, such as the infection rate, death rate and recovery time. \par 3 main functions are responsible for the entire simulation. The instantiate() function helps to determine the initial number of contagious people, and the initial percentage of population in quarantine. These are passed down into a global list: self.people, The graphics() function calls the previous function and plots initial conditions on the two graphs. It returns the size of the population along with every attribute that belongs to each person in the population. At last, these parameters are passed into the update() function, where the global constants are updated for the upcoming frame. In this function, 2 mechanisms were implemented to make the animation more realistic: \begin{itemize} \item Infection radius: People travelling around infectious people have a certain percentage chance of getting infected. \item Re-infection: If people don't quarantine after recovering, they have a certain chance of getting re-infected. \end{itemize} \begin{figure} \centering \includegraphics[width=0.8\textwidth]{animation_subplot_covid.jpg} \caption{\label{infection_simulation}Output figure of simulate\_people.py} \end{figure} \section{Graphical User Interface (GUI)}\label{gui} \subsection{Overview} There are two parts in the \href{https://github.com/fgrimmett/fcp2021/blob/main/GUI.py}{GUI.py}: simulation and real data graphing. User can choose any values for the simulation's input and run the simulation by themselves. User can also see the graphs for UK's COVID-19 data in video form and image form. This could give some insight to the user about the what could happen and what really happened regarding this epidemic. \subsection{Simulation GUI} \subsubsection{Page 1} \begin{flushleft} The first page of the GUI is one of the primary sources of information for the simulations. The GUI consists of 8 variables that can be custom selected or edited to create a near-infinite amount of possible simulations. The workflow of the GUI is shown in Figure 4 and the window for the simulation GUI is shown in Figure 5. \end{flushleft} \begin{figure} \centering \includegraphics[width=0.98\textwidth]{Flowchart2.png} \caption{\label{simulation GUI}Flowchart of 'daily operations' of the simulation GUI} \end{figure} \begin{figure} \centering \includegraphics[width=0.6\textwidth]{firstpageGUI.png} \caption{\label{operation GUI 1}Flowchart of 'daily operations' of the simulation GUI} \end{figure} \textbf{Sliders:}\par \begin{flushleft} The sliders allow the user to change the input value within a set range, this control is to prevent extreme cases that may cause crashes, I have set reasonable values going higher than *most* realistic cases however they can be edited to be larger if such case occurs.\par The “size of experiment” Slider is referring to how many people are in the total simulation, this variable is capped at 2500 to prevent the code from becoming too slow or crashing.\par “Chances of symptoms” refers to the ratio of how many people will have and not have symptoms out of those who have the virus.\par Additionally, The “\% starting ill” is referring to the number of people who will be ill at the beginning of the simulation\par The “Social Interaction of Asym” and “Social Interaction of Sym” sliders changes the amount of interaction. They refer to the interaction of those who are symptomatic and those who are not.\par Similarly, the “Travel Distance of Asym” and “Travel Distance of Sym” refer to the distance the virus will travel.\par Finally, the “Days Of Experiment” refers to the number of days the experiment will be simulated for, I decided 1000 days was ideal for this as it was large while still being controllable, alternative inputs for this value were also made.\par Changes have since been made to move the changing of values from the "save" function to the slider itself, this means the slider will now represent the value to be used within the simulation. This change has been made to make the program quicker.\par \end{flushleft} \textbf{Text Entry:}\par \begin{flushleft} The text entry box labels “Custom Days Of Experiment” allows for a custom input for the “Days Of Experiment” variable, there is no limit to how high the number can be. It can be left blank if you wish to use the slider. This is thanks to exception handling (“Try:” / “Except:”) for which if invalid input is used such as letter, symbol, decimals or left blank it refers back to the slider’s value and sets it to the global variable value. The text box has priority over the slider, so no button to select it is needed.\par \end{flushleft} \textbf{Button:}\par \begin{flushleft} The first button is a large “Simulate” button, this starts the function “Save” when clicked. The save function creates a list of global variables for each of the values that will be outputted, it then uses the “get” function to collect the value from the sliders. It then defines the “Days” variable as global and tries to define it using the Text input, if this fails or causes an issue it redefines itself using the Sliders value.\par \end{flushleft} \subsubsection{Change Page Function} \begin{flushleft} The Change GUI page is controlled by two buttons, the one on the first page labels “See: UK’s COVID-19 data” and on the second page “Back”. When pressed they call the “Changepage” function.\par The change page function works by checking the current page, deleting it, setting the variable to the other page, then calling the latter page function which will recreate a new page, this is done seamlessly so that it appears to change, however, it’s actually deleting the whole page and creating a new one.\par \end{flushleft} \subsection{Real Data Graphing} The program starts when the user clicked the 'See: UKs COVID-19 data' button in the GUI. The workflow of the GUI is shown in Figure 5.\par \begin{figure} \centering \includegraphics[width=0.9\textwidth]{Flowchart3.png} \caption{\label{real data GUI}Flowchart of 'daily operations' of real data GUI.} \end{figure} The animated graph can only be saved for one version of the graphs only. Each time the user clicked the 'Play' button, the video will be saved. User can also save the still image of the graph by clicking the save button on the window.\par The window for the real data GUI is as shown in Figure 6.\par \begin{figure} \centering \includegraphics[width=0.5\textwidth]{secondPageGUI.png} \caption{\label{window GUI 2}Window for the graphs} \end{figure} Panda module was used to read the content of the \href{https://github.com/fgrimmett/fcp2021/blob/main/UK_full_covid_data_may.csv}{csv file} and variables were created to easily access the data. The x and y variables for the plot were written inside a separate function so that it will be easier to plot the graphs. Besides that, the still image of the graph was embedded on a separate window from the second page of the GUI as shown in Figure 7.\par \begin{figure} \centering \includegraphics[width=0.98\textwidth]{graphWindow.png} \caption{\label{content GUI 2}Window for the graph's image} \end{figure} \subsection{Further Potential/Conclusions} More features could be added to the GUI such as a save button for the animation of the simulation and a button for the user to see the grid plot for every few days and the things that can be done through the terminal that can't be done using the current GUI window. Besides that, a subtext for the graph was deleted since the window shrunk when the graph button was clicked due to a yet unidentified reason.\par \section{Command Line} The 'fcp.py' script comprises of a main function. This function is used to represent the first model of this project. It uses the ArgumentParser class and creates an object from it inside the main function. This allows the user to modify the simulation object from the terminal, without having to edit the actual script. Different arguments can be changed (please refer to \href{https://github.com/fgrimmett/fcp2021/blob/main/README.md#135-command-line}{README.Command Line}). The arguments selected are parsed to if statements, to control the user's output display. \end{document}