Codes to count particles in boxes and calculate statistics of these the fluctuating counts
If you use this code please cite our paper available on ArXiv (https://arxiv.org/abs/2311.00647), and soon on Phys. Rev. X.
[1] Mackay, E. K., Marbach, S., Sprinkle, B., & Thorneywork, A. L. (2023). The Countoscope: Measuring Self and Collective Dynamics without Trajectories. arXiv preprint arXiv:2311.00647.
and we will come up shortly with a Zenodo release for the code which you can cite as well
To install, clone this directory into your site-packages directory (eg cd ~/.local/lib/python3.10/site-packages && git clone https://github.com/Countoscope/countoscope_PRX/ countoscope
)
or simply download the codes
- example_runcounting.py * example code to run the counting algorithm and plot relevant curves
- test_data/example_dataset.txt * example data set simulated from Brownian motion of non-interacting particles
- Box_Count_Stats.py * source codes to count particles in boxes and calculate statistics
- Numba_Box_Count_stats.py * same as above but with just-in-time-compilation. Sometimes numba is not compatible with some machines.
- LICENSE * licence agreement
- Old_Codes/ * old codes directory
To use
import countoscope as countoscope
results = countoscope.calculate_nmsd(data=f"data.dat", window_size_x=217.6, window_size_y=174, box_sizes=Box_Ls, sep_sizes=sep)
See the full example in example_runcounting.py
(which also includes plotting)
The parameters to calculate_nmsd
are:
data
. Either:data
should be a string, the address of a text file containing rows of x, y, t values, whitespace separated.- or
data
should be provided as a 2D array wheredata[i, 0:2]
is[x, y, t]
- the
t
values should be the index of the frame. They can be 0-based or 1-based (or any other), and can be supplied as floats or integers.
window_size_x
andwindow_size_y
optional, the dimensions of the viewing window. If not supplied, the maximum x and y coordinate over all frames and particles will be used instead.- it is assumed that the particles lie in
0 <= x <= window_size_x
and0 <= y <= window_size_y
. Viewing windows not cornered at the origin are not currently supported.
- it is assumed that the particles lie in
- The box sizes are specified as:
- if only
box_sizes
is provided, the boxes will be square, width and height of boxi
equal tobox_sizes[i]
. - if
box_sizes_x
andbox_sizes_y
are provided, boxi
will be of shapebox_sizes_x[i]
*box_sizes_y[i]
. - however, if you want one of the width or height to be constant, you can just pass a single value to one of
box_sizes_x
orbox_sizes_y
and then all boxes will have the same width or height.
- if only
sep_sizes
should be an array of the same size asbox_sizes
/box_sizes_x
/box_sizes_y
- if any elements of
sep_sizes
are negative, the boxes will overlap. This causes the library to use a different algorithm to count the particles which is substantially slower. You should be careful when choosing the overlaps; if the overlap is a rational fraction of the box size then some boxes' edges will touch, leaving the counts correlated.
- if any elements of
The return object:
Property | Shape | Description |
---|---|---|
results.N2_mean |
len(box_sizes) * Nframes | number displacement fluctuations (N(t) - N(0))^2 mean value |
results.N2_std |
len(box_sizes) * Nframes | number displacement fluctuations (N(t) - N(0))^2 mean value |
results.N_mean |
len(box_sizes) | mean particles per box, averaged over all boxes |
results.N_mean_std |
len(box_sizes) | standard deviation of (mean particles per box in time) over all boxes |
results.N_var |
len(box_sizes) | variance of all counts |
results.N_var_sem_ub |
len(box_sizes) | |
results.N_var_sem_lb |
len(box_sizes) | |
results.N_var_mod |
len(box_sizes) | variance of number of particles in box over time, averaged over all boxes |
results.N_var_mod_std |
len(box_sizes) | standard deviation of (variance of number of particles in box over time) over all boxes |
results.num_boxes |
len(box_sizes) | number of boxes used for each box size |
results.counts |
len(box_sizes) * max_boxes_y * max_boxes_x * num_timesteps | the raw counts in each box |
results.box_coords |
len(box_sizes) * max_boxes_y * max_boxes_x * 2 | the (x, y) positions of the lower-left corner of each box |
numpy, scipy, and numba. By default, numba will run using as many threads as you have cores on your machine. Use NUMBA_NUM_THREADS=16 python ....
to limit numba to a certain number of threads if you don't want it to use all your cores. If tqdm
is installed, we will use it for nice progress bars.
If you get an annoying C error like Segmentation fault
, try running with NUMBA_DISABLE_JIT=1 python myscript.py
to disable numba compilation (it will take much longer), and see if you get any pure Python errors