#load various variable definitions that are the same for each app source('startup_script.R') sapply(files_to_source, source) #source some helper files defined in the files_to_source variable currentrmdfile = knitr::current_input() #get current file name appsettings = get_settings(currentrmdfile,appdocdir,packagename) #get settings for current app
This app allows exploration of a virus infection model that includes several components of the immune response. Read about the model in The Model tab. Then, work through the tasks described in the What To Do tab.
This model consists of several compartments that capture some of the basic dynamics of virus and immune response during an infection. In this model, we track the following entities, by assigning each to a compartment:
In addition to specifying the compartments of a model, we need to specify the dynamics determining the changes for each compartment. Broadly speaking, there are processes that increase the numbers in a given compartment/stage, and processes that lead to a reduction. Those processes are sometimes called in-flows and out-flows.
For our system, we specify the following processes/flows:
The diagram illustrating this compartmental model is shown in the figure.
knitr::include_graphics(path = paste0("../media/",appsettings$modelfigname))
Implementing this model as a continuous-time, deterministic model leads to the following set of ordinary differential equations.
\begin{align} \dot U &= n - d_U U - bUV \ \dot I &= bUV - d_I I - k_T T I \ \dot V &= \frac{pI}{1+s_F F} - d_V V - b UV - k_A AV \ \dot F &= p_F - d_F F + \frac{V}{V+ h_V}g_F(F_{max}-F) \ \dot T &= F V g_T + r_T T \ \dot B &= \frac{F V}{F V + h_F} g_B B \ \dot A &= r_A B - d_A A - k_A A V \end{align}
The innate response is modeled in a rather abstract sense. We could think of it as some form of cumulative effect of all innate response components, or alternatively a single dominant innate response component, e.g., interferon. If one knows more about a specific system and has enough data, one can of course model the innate response in more detail (e.g., with additional compartments). For the sake of simplicity, we only look at a single compartment.
We are ignoring the death of T-cells and B-cells in this model. As such, it is only applicable to systems where we want to study the dynamics during the growth/expansion phase of the adaptive response and not further. This is valid for most acute infections, but would not be a suitable model for something like HIV or other chronic viral infections.
The initial condition for the innate response is set to its steady state value in the absence of a pathogen, p~F~/d~F~. This is hard-coded; if you wanted to change this, you will have to edit the underlying simulation code.
While this model and these processes make some biological sense, there are many other possible alternatives one could formulate the detailed processes going on. Based on what you know about the system you want to model, you might have good information about some of the components and for other parts you will have to make reasonable assumptions. Another app deals specifically with this issue of having different ways to formulate a model and how that can sometimes impact results. For this app, reasonable terms were chosen with a focus on showcasing a variety of different ways certain immune response processes are often implemented.
The tasks below are described in a way that assumes everything is in units of days (rate parameters, therefore, have units of inverse days). If any quantity is not given in those units, you need to convert it first (e.g. if it says a week, you need to convert it to 7 days).
#this is the running counter for the records which starts at 1 rc=1 #empty object, will hold all outcomes alloutcomes = NULL ######################### # Task 1 ######################### tid = 1 tasktext = "Start with 10^5^ uninfected cells, no infected cells, 10 virus particles, and no initial B-cells, T-cells, or antibodies. Note that the initial condition for the innate response is set to its steady state value in the absence of a pathogen, *p~F~*/*d~F~*. This is hard-coded; if you wanted to change this, you will have to edit the underlying simulation code. Set birth and death rate of uninfected cells to 0. Assume that infected cells have a life-span of 1 day, and virus has a life-span of 6 hours. Also, assume that the virus production by an infected cell is 100 virions per day and that the rate at which new cells become infected is 10^-5^. Turn off all immune response components for now by setting production rate and growth rate of the innate response to 0. (The death rate needs to be non-zero, otherwise you get an error message because of the way the steady state is computed.) \nBy looking at the equations, convince yourself that if you have no T- or B-cells and no baseline production and extra induction of the innate response (*p~F~*=*g~F~*=0), all immune response quantities will be and remain at 0, no matter what you set the remaining parameters to. \nRun your model for 30 days, start at 0 and set the time step for which solutions are returned to 0.01. \nIf you run the simulation with the settings above, you should get a single acute infection with a peak number of infected cells of around 70217. Confirm that the immune response quantities were zero throughout." nrec = 1 # number of items to record out_records = c("Day at which the viral load peaks") out_types = rep("Integer",nrec) out_notes = rep("Report the integer",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task ######################### # Task 2 ######################### tid = tid + 1 tasktext = "Now we'll slowly add immune response components. We start with the innate response. \nSet innate response production rate to 100, removal rate to 1. Leave innate growth rate at 0. Set T-cell induction rate to 0. Set the suppression of virus production by innate response parameter to 10^-12^ (almost 0). Leave everything else as before. \nBy looking at the equations, convince yourself that while there will now be an innate response, it does not affect the infection dynamics. Also convince yourself that there will still be no B-cells and T-cells. \nRun the simulation to confirm/test. You should find the innate at a steady level of 100, and an infection that is as before, with again a peak of around 70217 infected cells." nrec = 1 # number of items to record out_records = c("Day at which the number of infected cells peaks") out_types = rep("Integer",nrec) out_notes = rep("Report the integer",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task ######################### # Task 3 ######################### tid = tid + 1 tasktext = "Allow the innate response to impact virus production by increasing *s~F~* to 0.01. Contemplate what you expect to see, then check with the simulation. \nNow, allow the innate response to also grow in the presence of the virus by setting innate response growth to 1. Contemplate what you expect to see, check with the simulation. \nExplore the innate response by trying different values for all innate response related parameters (i.e. *p~F~*, *d~F~*, *g~F~*, *s~F~*, *h~V~* and *F~max~* ) \nIf you are somewhat familiar with a specific virus and know how the kinetics of (some component of) the innate response should look, try to find parameter values that give you something that might be a reasonable approximation to the real system for all variables (uninfected cells, infected cells, virus, innate response)." nrec = 2 # number of items to record out_records = c("Day at which viral load peaks with *s~F~* = 0.01 and *g~F~* = 0", "Day at which viral load peaks with *s~F~* = 0.01 and *g~F~* = 1") out_types = rep("Integer",nrec) out_notes = rep("Report the integer",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task ######################### # Task 4 ######################### tid = tid + 1 tasktext = "Now instead of having the innate response reduce virus production, let's consider its effect on T-cell activation. \nSet everything as in task 2. Then, set T-cell induction rate to 0.1 and T-cell growth rate to 0.5. Set T-cell killing rate close to 0 (e.g. 10^-20^). Contemplate what you'd expect to see; run the simulation to confirm. \nYou should see the same size acute infection as before, namely with around 70217 infected cells at the peak. You will also see T-cells growing. \nNow, allow T-cells to kill infected cells by increasing the killing rate. First, formulate your expectation, then test with the simulation. As killing rate increases, you should see a steeper decline of infected cells and virus toward the end of the infection. The peak will also be somewhat affected. \nPlay around with the parameters that directly govern T-cell kinetics and impact (*r~T~*, *g~T~*, *k~T~*), as well as any parameters that indirectly impact T-cells through changing the innate response strength (i.e. everything you explored in the previous task)." nrec = 1 # number of items to record out_records = c("TRUE or FALSE: It is possible to prevent any cells from being infected by setting the T-cell killing rate arbitrarily high.") out_types = rep("Logical",nrec) out_notes = rep("Report TRUE or FALSE",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task ######################### # Task 5 ######################### tid = tid + 1 tasktext = "Let's now explore B-cell/antibody response. Set everything as in task 2, B-cell growth rate to 0.5 and saturation constant to 10^2^. Assume B-cells produce antibodies at a rate of 100 per day, and antibodies live an average of 1 day. Assume virus removal by antibodies is negligible, i.e. set it to 10^-20^. Run the simulation. Why don't you see any increasing numbers of B-cells and antibodies? *Hint: Look at the equations and the initial conditions.* \nRemedy the previous problem by setting the initial number of B-cells to 1. You should now see both B-cells and antibodies grow. If you run the simulation for 20 days, you should have around 4048 B-cells at the end of the simulation. The maximum number of infected cells is as before. I'm sure it's clear why: while the B-cells and antibodies are there now, they don't *do* anything just yet. \nAllow the antibodies to impact virus by slowly increasing the virus removal rate, *k~A~*. You will see an interesting pattern for the antibodies with a pronounced dip. Try to understand why that happens." nrec = 2 # number of items to record out_records = c("Number of B-cells after 20 days with *k~A~* = 0.1", "Peak number of infected cells with *k~A~* = 0.1") out_types = rep("Rounded_Integer",nrec) out_notes = rep("Report the rounded integer",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task ######################### # Task 6 ######################### tid = tid + 1 tasktext = "So far, we have only had a single immune response component at a time act on the virus or infected cells. Now, it's time to look at 'everything'. This is a free and open exploration. Turn on any and all immune response components you like, play around with any other parameters, and see what happens. You might notice that the model, while still in some sense fairly small and simple, is nevertheless already fairly complex, with lots of 'knobs to turn' and parameters to adjust and things going on. This is a challenge when building models: smaller models are less realistic but easier to build and study. Larger models are potentially more realistic but harder to build, harder to study, and if you want to apply the model to a specific pathogen, you will need to find values for all the model parameters somewhere in the literature. That's often tricky." nrec = 1 # number of items to record out_records = c("Nothing") out_types = rep("None",nrec) out_notes = rep("",nrec) outcomes = data.frame( TaskID = rep(tid,nrec), TaskText = rep(tasktext,nrec), RecordID = paste0('T',tid,'R',(1:nrec)), Record = out_records, Type = out_types, Note = out_notes) alloutcomes = rbind(alloutcomes,outcomes) rc = rc + nrec #increment record counter by number of outcomes to record for this task
#save the fully filled task table to a tsv file alloutcomes$QuizID = paste0(packagename,"_",appsettings$appid) alloutcomes$AppTitle = appsettings$apptitle alloutcomes$AppID = appsettings$appid #remove a few variables from the data frame savedoutcomes <- dplyr::select(alloutcomes,QuizID,AppID,AppTitle,TaskID,TaskText,RecordID,Record,Type,Note) write.table(savedoutcomes, paste0(appsettings$appid,"_tasktable.tsv"), append = FALSE, sep = "\t", row.names = F, col.names = TRUE)
# Take all the text stored in the table and print the tasks and items to record write_tasktext(alloutcomes)
This app (and all others) are structured such that the Shiny part (the graphical interface you see and the server-side function that goes with it) calls an underlying R script (or several) which runs the simulation for the model of interest and returns the results.
For this app, the underlying function running the simulation is called r appsettings$simfunction
. You can call them directly, without going through the shiny app. Use the help()
command for more information on how to use the functions directly. If you go that route, you need to use the results returned from this function and produce useful output (such as a plot) yourself.
You can also download all simulator functions and modify them for your own purposes. Of course to modify these functions, you'll need to do some coding.
For examples on using the simulators directly and how to modify them, read the package vignette by typing vignette('DSAIRM')
into the R console. An example of a model similar to the above applied to influenza, see e.g. [@handel10].
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.