-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add start of description about collaboration
- Loading branch information
Showing
7 changed files
with
238 additions
and
2 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
# How to Collaborate | ||
Often in science, we're not the only people who are working on a project. | ||
If we are working with others, it is worth learning about effective ways to use Git, allowing for asynchronous collaboration and minimizing the risk of **merge conflicts**. | ||
Fortunately for us, much of this revolves around the **branching** concept outlined in [the previous chapter](branching-strategies.qmd). | ||
|
||
## Feature Branches | ||
|
||
The main principal is that every new feature/change, where that is a bug fix or new model, has its own branch. | ||
Ideally, each one will will only be a small change, but sometimes this gets away from us and results in 500 lines changes. | ||
|
||
### Why GitHub Issues | ||
|
||
GitHub has a couple of useful features that make this easy to work with, as well as track progress in your todo list of features. | ||
The first key concept is the liberal use of **GitHub issues**. | ||
For every feature I want to add, I create an **issue** (I promise this is going somewhere). | ||
Each issue should be small enough that is only does one thing and is easy to understand and review (though it will likely be comprised of multiple **commits**). | ||
|
||
For example, say I have just added my final size calculation code and I realize that I want update my model to be an SEIR model instead of an SIR model. | ||
I could just make a new branch and be done with it, but creating an **issue** allows us to track which **commits** are involved in the change. | ||
It also allows us to outline a number of changes we wish to make over the next short while and link them, making it easier to remember what we wanted to do when we come back to a project, as well as who was working on the changes. | ||
|
||
### Creating an Issue | ||
|
||
To create an issue, simply navigate to your project in GitHub, click on the Issues tab, and then on the "New Issue" button. | ||
|
||
![Creating an issue](./figs/Collaboration_GitHub-issue-01.png) | ||
|
||
From here, add a short and descriptive title, explanation, and assign the issue to someone (if you're the only person in the project, this obviously isn't necessary). | ||
You may also find it useful to add a label to the issue to distinguish it from other issues later on (e.g., use the default "enhancement" label for new features and "bug" for bugs). | ||
|
||
::: {.callout-tip} | ||
You can also create a GitHub issue from directly within GitKraken if you are signed into your GitHub account. | ||
::: | ||
|
||
Once you have created the issue, you will see an option on the right side that suggests you "Create a branch", under the "Development" heading. | ||
You can use this, or you can open up GitKraken and do the same thing there as GitKraken will take care of connecting the new local branch to your GitHub repository, so that's what we'll do. | ||
Opening up your repository, you will see in the sidebar a heading "GitHub Issues". | ||
Clicking on that will reveal your issues, and upon selecting the correct one you will see an option to create a feature branch. | ||
|
||
![Creating an issue branch in GitKraken](./figs/Collaboration_issue-branch.png) | ||
|
||
Going through the next steps, you can name your branch whatever you like (though I tend to leave the default suggestion as they're not hanging around for long), and which branch you want to use for the base. | ||
If you're following the short-lived branch strategy, your base should probably be the **main** branch, an no others should be around for long enough that extra features can be branches off of them. | ||
Once you have your new **local** branch created, you should push it so there is a copy on your **remote** repository. | ||
At this point, you're ready to update your code. | ||
|
||
Below is code that updates the simulation files (*simulation.R* and *simulation.py*). | ||
|
||
|
||
<details> | ||
<summary> | ||
R Code | ||
</summary> | ||
<p> | ||
|
||
```r | ||
library(deSolve) | ||
library(tidyverse) | ||
library(rootSolve) | ||
|
||
theme_set(theme_minimal()) | ||
|
||
sirmod <- function(t, y, parms) { | ||
# Pull state variables from y vector | ||
S <- y[1] | ||
E <- y[2] | ||
I <- y[3] | ||
R <- y[4] | ||
|
||
# Pull parameter values from parms vector | ||
beta <- parms["beta"] | ||
sigma <- parms["sigma"] | ||
mu <- parms["mu"] | ||
gamma <- parms["gamma"] | ||
N <- parms["N"] | ||
|
||
# Define equations | ||
dS <- mu * (N - S) - beta * S * I / N | ||
dE <- beta * S * I / N - sigma * E | ||
dI <- sigma * E - (mu + gamma) * I | ||
dR <- gamma * I - mu * R | ||
res <- c(dS, dE, dI, dR) | ||
|
||
# Return list of gradients | ||
list(res) | ||
} | ||
|
||
|
||
times <- seq(0, 26, by = 1 / 10) | ||
parms <- c(mu = 0, N = 1, beta = 2, sigma = 1, gamma = 1 / 2) | ||
start <- c(S = 0.999, E = 0.0, I = 0.001, R = 0) | ||
|
||
out <- ode(y = start, times = times, func = sirmod, parms = parms) | ||
out_df <- as_tibble(out) %>% | ||
pivot_longer(cols = -time, names_to = "state", values_to = "number") %>% | ||
mutate( | ||
time = as.numeric(time), | ||
number = as.numeric(number), | ||
state = factor(state, levels = c("S", "E", "I", "R")), | ||
number = round(number, 6) | ||
) | ||
|
||
ggplot(out_df, aes(x = time, y = number, color = state)) + | ||
geom_line(linewidth = 2) + | ||
labs(x = "Time", y = "Number", color = "State") | ||
|
||
|
||
# Candidate values for R0 and beta | ||
R0 <- seq(0.1, 5, length = 50) | ||
betas <- R0 * 1 / 2 | ||
|
||
# Calculate proportion infected for each value of R0 | ||
# map2_dfr is a {purrr} function that applies a function to two vectors i.e., it is a vectorized version of a for loop, and returns a data frame | ||
final_size_df <- map2_dfr( | ||
.x = betas, | ||
.y = R0, | ||
.f = function(.x, .y) { | ||
equil <- runsteady( | ||
y = c(S = 1 - 1E-5, E = 0.0, I = 1E-5, R = 0), | ||
times = c(0, 1E5), | ||
func = sirmod, | ||
parms = c(mu = 0, N = 1, beta = .x, sigma = 1, gamma = 1 / 2) | ||
) | ||
|
||
tibble( | ||
R0 = .y, | ||
final_size = equil$y["R"] | ||
) | ||
} | ||
) | ||
|
||
ggplot(final_size_df, aes(x = R0, y = final_size)) + | ||
geom_line(linewidth = 2) + | ||
labs(x = "R0", y = "Final size") | ||
|
||
``` | ||
|
||
</p> | ||
</details> | ||
|
||
<details> | ||
<summary>Python Code</summary> | ||
<p> | ||
|
||
```python | ||
# %% | ||
import numpy as np | ||
import pandas as pd | ||
from scipy.integrate import solve_ivp | ||
from plotnine import * | ||
|
||
|
||
# %% | ||
def sirmod(t, y, beta, mu, sigma, gamma, N): | ||
# Unpack states | ||
S, E, I, R = y | ||
|
||
# Define equations | ||
dS = mu * (N - S) - beta * S * I / N | ||
dE = beta * S * I / N - sigma * E | ||
dI = sigma * E - (mu + gamma) * I | ||
dR = gamma * I - mu * R | ||
|
||
# Return list of gradients | ||
return dS, dE, dI, dR | ||
|
||
|
||
# %% | ||
tmin = 0 | ||
tmax = 26 | ||
tstep = 1 / 10 | ||
times = np.arange(tmin, tmax, tstep) | ||
|
||
beta = 2 | ||
mu = 0 | ||
sigma = 1 | ||
gamma = 1 / 2 | ||
N = 1 | ||
parms = (beta, mu, sigma, gamma, N) | ||
|
||
S0 = 0.999 | ||
E0 = 0 | ||
I0 = 0.001 | ||
R0 = 0 | ||
start = (S0, E0, I0, R0) | ||
|
||
# %% | ||
out = solve_ivp(sirmod, [tmin, tmax], np.array(start), args=parms, t_eval=times) | ||
|
||
# %% | ||
out_df = ( | ||
pd.DataFrame(out.y).transpose().rename(columns={0: "S", 1: "E", 2: "I", 3: "R"}) | ||
) | ||
out_df["time"] = out.t | ||
out_df = out_df.melt(id_vars="time", value_vars=["S", "E", "I", "R"]).rename( | ||
columns={"variable": "state", "value": "number"} | ||
) | ||
|
||
# %% | ||
theme_set(theme_minimal()) | ||
|
||
( | ||
ggplot(out_df, aes(x="time", y="number", color="state")) | ||
+ geom_line(size=2) | ||
+ labs(x="Time", y="Number", color="State") | ||
) | ||
|
||
# %% | ||
# Candidate values for R0 and beta | ||
R0 = np.linspace(0.1, 5, 50) | ||
betas = R0 * 1 / 2 | ||
|
||
# %% | ||
solve_ivp(sirmod, [tmin, 1e5], start, args=parms).y[2, -1] | ||
|
||
# %% | ||
final_size_df = pd.DataFrame({"R0": R0, "final_size": np.zeros(len(R0))}) | ||
|
||
for index, beta in enumerate(betas): | ||
p = (beta, mu, sigma, gamma, N) | ||
final_size_df.final_size[index] = solve_ivp(sirmod, [tmin, 1e5], start, args=p).y[ | ||
2, -1 | ||
] | ||
|
||
# %% | ||
( | ||
ggplot(final_size_df, aes(x="R0", y="final_size")) | ||
+ geom_line(size=2) | ||
+ labs(x="R0", y="Final size") | ||
) | ||
``` | ||
|
||
</p> | ||
</details> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.