Travel Time

This example demonstrates how to record and analyze outcomes from a cellular potts simulation.

Here we will track the mean displacement of cell centers with and without active migration. From this data, we can calculate mean square displacement as a function of lag time.

\[ msd(\tau) = <\Delta r(\tau)^2> = <(r(t+\tau) - r(t))^2>\]

Here r(t) represents the current position of the cell and the brackets indicate an average over time. If a cell is moving randomly, this function will be linear. Cells with directional motion will deflect the curve upward. Let's see if we can replicate these theoretic results.

Create a model containing a cell with and without directional motion.

using CellularPotts, Plots
using Random, Statistics

#Set a random seed for reproducibility
Random.seed!(314);

#Models have same space and cell initializations
space = CellSpace(100,100)

#Center the moving cell to avoid edges and put stationary cell off into a corner
positions =

#Cells will have same volume
initialCellState = CellState(
    [:StationaryCell, :MovingCell],
    [200, 200],
    [1,1];
    positions = [(20,20),(50,50)])

#Add a migration penalty to one cell encourage cell movement
penalties = [
    AdhesionPenalty([0 30 30;
                    30 0 30
                    30 30 0]),
    VolumePenalty([30, 30]),
    PerimeterPenalty([0, 10]),
    MigrationPenalty(40, [0, 40], size(space)) # 0 means no migration
    ]

#Generate the model
cpm = CellPotts(space, initialCellState, penalties)

#Record model iterations
cpm.recordHistory = true

#Simulate the model
for _ in 1:1000
    ModelStep!(cpm)
end

Calculate Average Cell Position

Given a CellSpace and a cell ID, calculate the cell's center.

function meanPosition(space, n)

    totalPixels = 0
    avePos = zeros(2) #x and y positions

    #Loop over all points in space
    for i in axes(space,1)
        for j in axes(space,2)
            #Save positions that match cell ID
            if space[i,j] == n
                avePos[1] += i
                avePos[2] += j
                totalPixels += 1
            end
        end
    end

    return avePos ./ totalPixels
end


#Plot trajectories
p1 = plotcpm(cpm)

trajectoryRandom = zeros(2,cpm.step.counter)
trajectoryDirected = zeros(2,cpm.step.counter)

for i in 1:cpm.step.counter
    trajectoryRandom[:,i] .= meanPosition(cpm(i).nodeIDs, 1)
    trajectoryDirected[:,i] .= meanPosition(cpm(i).nodeIDs, 2)
end

plot!(p1, trajectoryRandom[1,:], trajectoryRandom[2,:])
plot!(p1, trajectoryDirected[1,:], trajectoryDirected[2,:])

Plot Mean Squared Displacement

MeanSqDis(cpm, τ, id) = mean([sum(abs2, meanPosition(cpm(i+τ).nodeIDs, id) - meanPosition(cpm(i).nodeIDs, id)) for i in 1:τ:cpm.step.counter-τ])
MeanSqDis (generic function with 1 method)

Here we choose a lag time of 50 steps (arbitrary)

scatter([MeanSqDis(cpm, τ, 1) for τ in 1:50],
    labels = "Random")

scatter!([MeanSqDis(cpm, τ, 2) for τ in 1:50],
    title = "Random vs Directed Motion",
    xlabel = "Lag Time",
    ylabel = "Mean Squared Displacement",
    framestyle = :box,
    labels = "Directed")

Here we see that, as a function of lag time, mean squared displacement for random motion does produce a linear relationship whereas directed motion is deflected upward.


This page was generated using Literate.jl.