Skip to content

Commit

Permalink
update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mastrof committed Dec 28, 2023
1 parent 4fb582a commit 9976ae7
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 167 deletions.
4 changes: 2 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ end

pages = [
"Home" => "index.md",
"Tutorial" => ["firststeps.md", "randomwalks.md", "chemotaxis.md"],
"Validation" => "validation.md",
"Introduction" => ["firststeps.md", "randomwalks.md", "chemotaxis.md"],
"Examples" => [
[namify(section) => [joinpath.("examples", section, readdir(outdir[section]))...]
for section in sections]...
],
"Validation" => "validation.md",
"API" => "api.md"
]

Expand Down
56 changes: 56 additions & 0 deletions docs/src/examples/Chemotaxis/celani_gauss2D.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
```@meta
EditURL = "../../../../examples/Chemotaxis/celani_gauss2D.jl"
```

# Noisy chemotaxis towards Gaussian source

In this example we set up a static Gaussian source and observe the chemotactic behavior
of the `Celani` model, in the presence of sensing noise (via the `chemotactic_precision`).
Playing with the `chemotactic_precision`, it can be seen that the clustering of bacteria
at the source becomes stronger with decreasing noise (decreasing chemotactic precision).

````@example celani_gauss2D
using MicrobeAgents
using Plots
function concentration_field(pos, model)
C = model.C
σ = model.σ
p₀ = model.p₀
concentration_field(pos, p₀, C, σ)
end
concentration_field(pos, p₀, C, σ) = C * exp(-sum(abs2.(pos.-p₀))/(2*σ^2))
timestep = 0.1 # s
extent = ntuple(_ -> 1000.0, 2) # μm
space = ContinuousSpace(extent; periodic=false)
p₀ = extent./2 # μm
C = 1.0 # μM
σ = 100.0 # μm
properties = Dict(
:concentration_field => concentration_field,
:C => C,
:σ => σ,
:p₀ => p₀,
)
model = StandardABM(Celani{2}, space, timestep; properties)
foreach(_ -> add_agent!(model; chemotactic_precision=6.0), 1:300)
nsteps = 5000
adata = [position]
adf, = run!(model, nsteps; adata)
traj = vectorize_adf_measurement(adf, :position)
xmesh = range(0, first(spacesize(model)); length=100)
ymesh = range(0, last(spacesize(model)); length=100)
c = [concentration_field(p, p₀, C, σ) for p in Iterators.product(xmesh, ymesh)]
heatmap(xmesh, ymesh, c', cbar=false, ratio=1, c=:bone, axis=false)
x = getindex.(traj,1)[end-100:4:end, :]
y = getindex.(traj,2)[end-100:4:end, :]
a = axes(x,1) ./ size(x,1)
plot!(x, y,
lab=false, lims=(0,1000), lw=1, alpha=a
)
````

146 changes: 146 additions & 0 deletions docs/src/examples/Chemotaxis/response_functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
```@meta
EditURL = "../../../../examples/Chemotaxis/response_functions.jl"
```

# Response function (Xie)

In this example we will probe the response function implemented
in the `Xie` model of chemotaxis.
The impulse response function is the "output" of the bacterial chemotaxis
pathway when presented with an input signal`.

To do this, we will emulate another classical laboratory assay, where the
bacterium is tethered to a wall, and it is exposed to a temporal change
in the concentration of a chemoattractant.
The response to the stimulus can be measured by observing modulations
in the instantaneous tumbling rate.
For each of the implemented microbe types, MicrobeAgents provides a
`tumblebias` function which returns the instantaneous bias
in the tumbling rate, evaluated from the internal state of the microbe.
Monitoring the time evolution of the tumble bias under teporal stimuli
then allows us to access the response function of the microbe.

In the `Xie` model, chemotaxis is implemented by direct samplings of the
`concentration_field`, thus we don't need to explicitly define neither
a `concentration_gradient` nor a `concentration_time_derivative`.
We will represent our temporal stimuli in the form of square waves which
instantaneously switch from a baseline value `C₀` to a peak value `C₁+C₀`
homogeneously over space.
The excitation will occur at a time `t₁` and go back to baseline levels
at a time `t₂`.

````@example response_functions
using MicrobeAgents
using Plots
θ(a,b) = a>b ? 1.0 : 0.0 # heaviside theta function
function concentration_field(pos, model)
C₀ = model.C₀
C₁ = model.C₁
t₁ = model.t₁
t₂ = model.t₂
dt = model.timestep
t = abmtime(model) * dt
# notice the time dependence!
concentration_field(t, C₀, C₁, t₁, t₂)
end
concentration_field(t,C₀,C₁,t₁,t₂) = C₀+C₁*θ(t,t₁)*(1-θ(t,t₂))
space = ContinuousSpace(ntuple(_ -> 500.0, 3)) # μm
C₀ = 0.01 # μM
C₁ = 5.0-C₀ # μM
T = 60.0 # s
t₁ = 20.0 # s
t₂ = 40.0 # s
properties = Dict(
:concentration_field => concentration_field,
:C₀ => C₀,
:C₁ => C₁,
:t₁ => t₁,
:t₂ => t₂,
)
dt = 0.1 # s
model = StandardABM(Xie{3}, space, dt; properties)
````

A peculiarity of the `Xie` model is that the chemotactic properties of the
microbe differ between the forward and backward motile states, so we can
probe the response function in both the forward and backward motile state
by initializing two distinct microbes in the two states.
To keep the microbes in these motile states for the entire experiment duration,
we suppress their tumbles, and (just for total consistency with experiments)
we also set their speed to 0.

````@example response_functions
add_agent!(model; turn_rate_forward=0,
motility=RunReverseFlick(motile_state=MotileState(Forward), speed=[0])
)
add_agent!(model; turn_rate_backward=0,
motility=RunReverseFlick(motile_state=MotileState(Backward), speed=[0])
)
````

In addition to the `tumblebias`, we will also monitor two other quantities
`state_m` and `state_z` which are internal variables of the `Xie` model
which represent the methylation and dephosphorylation processes which
together control the chemotactic response of the bacterium.

````@example response_functions
nsteps = round(Int, T/dt)
#state(a::Xie) = max(tumblebias(a)*a.state, 0)
adata = [tumblebias, :state_m, :state_z]
adf, = run!(model, nsteps; adata)
S = vectorize_adf_measurement(adf, :tumblebias)
m = (vectorize_adf_measurement(adf, :state_m))[:,1] # take only fw
z = (vectorize_adf_measurement(adf, :state_z))[:,1] # take only fw
````

We first look at the response function in the forward and backward
motile state: when the concentration increases we have a sharp negative
response (the tumble bias decreases), then the bacterium adapts to the new
concentration level, and when it drops back to the basal level we observe
a sharp positive response (the tumble bisa increases) before adapting
again to the new concentration level.

````@example response_functions
_green = palette(:default)[3]
plot()
x = (0:dt:T) .- t₁
plot!(
x, S,
lw=1.5, lab=["Forward" "Backward"]
)
plot!(ylims=(-0.1,4.5), ylab="Response", xlab="time (s)")
plot!(twinx(),
x, t -> concentration_field(t.+t₁,C₀,C₁,t₁,t₂),
ls=:dash, lw=1.5, lc=_green, lab=false,
tickfontcolor=_green,
ylab="C (μM)", guidefontcolor=_green
)
````

By analysing the methylation and dephosphorylation processes, we can
understand how the chemotactic response arises.
First, when the concentration increases, both `m` and `z` increase and converge
to a new steady-state value, but since they respond on different timescales,
the response (defined by the difference between these two quantities), shows
a sharp decrease followed by a slower relaxation.
The same occurs for the negative stimulus.

````@example response_functions
x = (0:dt:T) .- t₁
τ_m = model[1].adaptation_time_m
τ_z = model[1].adaptation_time_z
M = m ./ τ_m
Z = z ./ τ_z
R = M .- Z
plot(
x, [M Z R],
lw=2,
lab=["m/τ_m" "z/τ_z" "m/τ_m - z/τ_z"],
xlab="time (s)"
)
````

46 changes: 0 additions & 46 deletions docs/src/examples/Chemotaxis/xie_2D.md

This file was deleted.

Loading

0 comments on commit 9976ae7

Please sign in to comment.