Skip to content

Commit 4e43018

Browse files
authored
Merge pull request #22 from JuliaSMLM/refactor-new-smlmdata-psfs
Refactor new smlmdata psfs
2 parents 781351c + 60d6093 commit 4e43018

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+7543
-2161
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
version:
13-
- '1.6'
13+
- '1.11'
1414
- 'nightly'
1515
os:
1616
- ubuntu-latest

CLAUDE.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SMLMSim.jl Development Guide
2+
3+
## Build, Test & Run Commands
4+
- Install dependencies: `julia --project -e "using Pkg; Pkg.instantiate()"`
5+
- Run all tests: `julia --project -e "using Pkg; Pkg.test()"`
6+
- Run specific test: `julia --project -e "using Pkg; Pkg.test(\"SMLMSim\", test_args=[\"Patterns\"])"`
7+
- Build docs: `julia --project=docs/ docs/make.jl`
8+
- Run benchmark: `julia --project=dev/ dev/benchmark.jl`
9+
10+
## Code Style Guidelines
11+
- Use physical units consistently (μm for space, seconds for time)
12+
- Follow Julia naming conventions: lowercase for functions, CamelCase for types
13+
- Organize imports: standard library first, then external packages
14+
- Place exports at module level, grouped by functionality
15+
- Type parameters should be explicit for functions with multiple dispatch
16+
- Error handling: use descriptive errors with parameter names and constraints
17+
- Documentation: include docstrings with examples and physical units
18+
- Re-export SMLMData types rather than redefining them
19+
- Follow existing patterns for defining new molecule or pattern types
20+
- Tests should use the `@test` macro with appropriate tolerances for floating-point comparisons
21+
22+
## Module Structure
23+
Functions should be organized in appropriate submodules: core, static, or diffusion.

Project.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
name = "SMLMSim"
22
uuid = "5a0a87e4-02d4-41f5-bf26-b8c94c784a04"
33
authors = ["klidke@unm.edu"]
4-
version = "0.2.1"
4+
version = "0.3.0"
55

66
[deps]
7-
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
87
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
9-
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
108
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
119
MicroscopePSFs = "de9ac726-48a4-48ab-84b0-1c03c7c18929"
10+
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1211
SMLMData = "5488f106-40b8-4660-84c5-84a168990d1b"
12+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1313

1414
[compat]
15-
CairoMakie = "0.10, 0.11"
1615
Distributions = "0.25"
17-
Images = "0.26"
18-
MicroscopePSFs = "0.3, 0.4"
19-
SMLMData = "0.1"
16+
Printf = "1.11.0"
17+
SMLMData = "0.2"
18+
Statistics = "1.11.1"
2019
julia = "1.6"
2120

2221
[extras]

README.md

Lines changed: 231 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,243 @@
55
[![Build Status](https://github.com/JuliaSMLM/SMLMSim.jl/workflows/CI/badge.svg)](https://github.com/JuliaSMLM/SMLMSim.jl/actions)
66
[![Coverage](https://codecov.io/gh/JuliaSMLM/SMLMSim.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaSMLM/SMLMSim.jl)
77

8-
Generate simulated SMLM coordinate data. Patterns, Cameras, Fluorophores, and SMLD data organization can be configured.
8+
## Overview
99

10-
Simulation parameters use physical units. Resulting `SMLMData.SMLD` structures are in units of pixels and frames.
10+
SMLMSim is a Julia package for simulating Single Molecule Localization Microscopy (SMLM) data with realistic physical properties. The package builds upon SMLMData, reexporting essential types and functions so you typically don't need to import SMLMData directly.
1111

12+
The package provides tools for:
1213

13-
The high level interface for simulating SMLM super-resolution coordinate data is the `SMLMSim.sim()` function.
14+
- Generating spatial patterns of fluorophores in 2D and 3D
15+
- Simulating fluorophore photophysics with stochastic kinetic models
16+
- Adding realistic localization uncertainty based on photon counts
17+
- Simulating diffusion and interactions between molecules
18+
- Generating microscope images with configurable PSFs
1419

20+
All simulations use physical units, with coordinates in microns and time in seconds. The resulting data is organized into `SMLMData.SMLD` structures compatible with the broader JuliaSMLM ecosystem.
21+
22+
## Installation
23+
24+
```julia
25+
using Pkg
26+
Pkg.add("SMLMSim")
1527
```
28+
29+
## Basic Usage
30+
31+
The high-level interface for simulating SMLM super-resolution coordinate data is the `simulate()` function with a `StaticSMLMParams` object.
32+
33+
```julia
1634
using SMLMSim
17-
using SMLMData
1835

19-
smld_true, smld_model, smld_noisy = SMLMSim.sim(;
20-
ρ=1.0,
21-
σ_PSF=0.13,
22-
minphotons=50,
23-
ndatasets=10,
24-
nframes=1000,
25-
framerate=50.0, # 1/s
26-
pattern=SMLMSim.Nmer2D(),
27-
molecule=SMLMSim.GenericFluor(; q=[0 50; 1e-2 0]), #1/s
28-
camera=SMLMSim.IdealCamera(; ypixels=256, xpixels=128, pixelsize=0.1) #pixelsize is microns
36+
# Basic simulation with default parameters
37+
camera = IdealCamera(1:128, 1:128, 0.1) # 128×128 pixels, 100nm pixels
38+
params = StaticSMLMParams() # Default parameters
39+
smld_true, smld_model, smld_noisy = simulate(
40+
params,
41+
camera=camera
42+
)
43+
```
44+
45+
This basic example creates a 2D simulation using default parameters:
46+
- 8-molecule circular patterns (Nmer2D with n=8, d=0.1μm)
47+
- 1 pattern per square micron (ρ=1.0)
48+
- PSF width of 130nm (σ_psf=0.13μm)
49+
- Two-state fluorophore kinetics with realistic blinking behavior
50+
- 1000 frames at 50 frames per second
51+
- Minimum photon threshold of 50 for detection
52+
53+
The function returns three SMLD objects with SMLM coordinates:
54+
- `smld_true`: Ground truth emitter positions (spatial coordinates only)
55+
- `smld_model`: Positions with simulated blinking kinetics (subset of true positions appearing in different frames)
56+
- `smld_noisy`: Positions with both blinking and localization uncertainty (realistic SMLM data with position errors)
57+
58+
For more control, you can customize the parameters:
59+
60+
```julia
61+
# More customized simulation
62+
params = StaticSMLMParams(
63+
ρ=1.0, # emitters per μm²
64+
σ_psf=0.13, # PSF width in μm (130nm)
65+
minphotons=50, # minimum photons for detection
66+
ndatasets=10, # number of independent datasets
67+
nframes=1000, # frames per dataset
68+
framerate=50.0 # frames per second
69+
)
70+
71+
smld_true, smld_model, smld_noisy = simulate(
72+
params,
73+
pattern=Nmer2D(n=6, d=0.2), # hexamer with 200nm diameter
74+
molecule=GenericFluor(; q=[0 50; 1e-2 0]), # rates in 1/s
75+
camera=IdealCamera(1:256, 1:128, 0.1) # 128×256 pixels, 100nm pixels
76+
)
77+
```
78+
79+
This customized example:
80+
- Creates hexagonal patterns (6 molecules in a 200nm circle)
81+
- Uses 10 independent datasets of 1000 frames each
82+
- Simulates fluorophores with specific on/off transition rates
83+
- Uses a rectangular camera field of view (128×256 pixels)
84+
85+
In both cases, the output SMLD objects contain emitter information (x, y coordinates, photon counts, frame numbers, etc.) that can be used for further analysis or visualization.
86+
87+
## Pattern Types
88+
89+
SMLMSim includes several built-in pattern types for positioning fluorophores:
90+
91+
### 2D Patterns
92+
93+
```julia
94+
# N molecules arranged in a circle
95+
nmer = Nmer2D(n=8, d=0.1) # 8 molecules in a 100nm diameter circle
96+
97+
# Linear pattern with random positions
98+
line = Line2D(λ=5.0, endpoints=[(-2.0, 0.0), (2.0, 0.0)]) # 5 molecules per μm along line
99+
```
100+
101+
### 3D Patterns
102+
103+
```julia
104+
# N molecules arranged in a circle at z=0
105+
nmer3d = Nmer3D(n=8, d=0.1) # 8 molecules in a 100nm diameter circle
106+
107+
# 3D line with random positions
108+
line3d = Line3D(λ=5.0, endpoints=[(-1.0, 0.0, -0.5), (1.0, 0.0, 0.5)])
109+
```
110+
111+
## Molecule Models
112+
113+
SMLMSim supports different fluorophore photophysical models:
114+
115+
```julia
116+
# Generic fluorophore with two-state kinetics
117+
fluor = GenericFluor(
118+
γ=10000.0, # photon emission rate in Hz
119+
q=[0 10; 1e-2 0] # transition rate matrix: state 1 ↔ state 2
29120
)
30121
```
122+
123+
## Diffusion and Interaction Simulation
124+
125+
The package includes tools for simulating diffusion and interactions between molecules:
126+
127+
```julia
128+
# Set up parameters for Smoluchowski diffusion simulation
129+
params = SmoluchowskiParams(
130+
density = 0.5, # molecules per μm²
131+
box_size = 10.0, # μm
132+
diff_monomer = 0.1, # μm²/s
133+
diff_dimer = 0.05, # μm²/s
134+
k_off = 0.2, # s⁻¹
135+
r_react = 0.01, # μm
136+
d_dimer = 0.05, # μm
137+
dt = 0.01, # s
138+
t_max = 10.0 # s
139+
)
140+
141+
# Run simulation
142+
systems = simulate(params)
143+
144+
# Visualize the simulation
145+
visualize_sequence(systems, filename="diffusion.mp4", framerate=round(Int64,1/params.dt))
146+
147+
# Generate microscope images
148+
psf = Gaussian2D(0.15) # 150nm PSF width
149+
images = gen_image_sequence(
150+
psf,
151+
systems,
152+
frame_integration=10
153+
)
154+
155+
# Extract only dimers
156+
dimer_systems = get_dimers(systems)
157+
dimer_images = gen_image_sequence(
158+
psf,
159+
dimer_systems,
160+
frame_integration=10
161+
)
162+
```
163+
164+
## Example Workflows
165+
166+
### 2D Simulation with Visualization
167+
168+
```julia
169+
using SMLMSim
170+
using CairoMakie
171+
172+
# Create camera with physical pixel size
173+
camera = IdealCamera(1:128, 1:256, 0.1) # 128×256 pixels, 100nm pixels
174+
175+
# Create simulation parameters
176+
params = StaticSMLMParams(
177+
ρ=1.0, # emitters per μm²
178+
σ_psf=0.13 # PSF width in μm
179+
)
180+
181+
# Run simulation
182+
smld_true, smld_model, smld_noisy = simulate(
183+
params,
184+
pattern=Nmer2D(n=6, d=0.2), # hexamer with 200nm diameter
185+
camera=camera
186+
)
187+
188+
# Extract coordinates from emitters
189+
x_noisy = [e.x for e in smld_noisy.emitters]
190+
y_noisy = [e.y for e in smld_noisy.emitters]
191+
photons = [e.photons for e in smld_noisy.emitters]
192+
193+
# Create figure and plot results
194+
fig = Figure(size=(800, 600))
195+
ax = Axis(fig[1, 1],
196+
title="Simulated SMLM Localizations",
197+
xlabel="x (μm)",
198+
ylabel="y (μm)",
199+
aspect=DataAspect(),
200+
yreversed=true # This makes (0,0) at top-left
201+
)
202+
203+
# Scatter plot with photon counts as color
204+
scatter!(ax, x_noisy, y_noisy,
205+
color=photons,
206+
colormap=:viridis,
207+
markersize=4,
208+
alpha=0.6
209+
)
210+
211+
Colorbar(fig[1, 2], colormap=:viridis, label="Photons")
212+
213+
# Show or save the figure
214+
display(fig)
215+
# save("smlm_simulation.png", fig)
216+
```
217+
218+
### 3D Simulation
219+
220+
```julia
221+
using SMLMSim
222+
223+
# Create camera with physical pixel size
224+
camera = IdealCamera(1:128, 1:256, 0.1) # 128×256 pixels, 100nm pixels
225+
226+
# Create 3D simulation parameters
227+
params = StaticSMLMParams(
228+
ρ=0.5, # emitters per μm²
229+
ndims=3, # 3D simulation
230+
zrange=[-2.0, 2.0] # 4μm axial range
231+
)
232+
233+
# Run simulation
234+
smld_true, smld_model, smld_noisy = simulate(
235+
params,
236+
pattern=Nmer3D(n=8, d=0.3), # 3D pattern
237+
camera=camera
238+
)
239+
```
240+
241+
## Contributors
242+
243+
- [JuliaSMLM Team](https://github.com/JuliaSMLM)
244+
245+
## License
246+
247+
This project is licensed under the MIT License - see the LICENSE file for details. The MIT License is a permissive license that allows for reuse with few restrictions. It permits use, modification, distribution, and private use while preserving copyright and license notices.

dev/Project.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
21
[deps]
3-
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
4-
ImageView = "86fae568-95e7-573e-a6b2-d8a6b900c9ef"
5-
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
2+
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
63
MicroscopePSFs = "de9ac726-48a4-48ab-84b0-1c03c7c18929"
74
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
85
SMLMSim = "5a0a87e4-02d4-41f5-bf26-b8c94c784a04"
6+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

dev/basic_sim_test.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using Pkg
2+
Pkg.activate("dev")
3+
4+
using Revise
5+
using SMLMSim
6+
using SMLMData
7+
using MicroscopePSFs
8+
using CairoMakie
9+
10+
# 2D Example
11+
camera = IdealCamera(1:512, 1:512, 0.1)
12+
pattern = SMLMSim.Nmer2D(n=6, d=0.2)
13+
params = StaticSMLMParams(ρ=1.0, nframes = 100)
14+
smld_true, smld_model, smld_noisy = simulate(
15+
params,
16+
pattern=pattern,
17+
camera=camera
18+
)
19+
20+
# generate images
21+
psf = AiryPSF(1.2, .555)
22+
psf_spline = SplinePSF(psf, -1:.1:1, -1:.1:1)
23+
img = gen_images(smld_model, psf_spline; dataset=1, support = 1.0)
24+
25+
image(img[:, :, 1])
26+
27+
28+
29+
30+
# 3D Example
31+
pattern3d = SMLMSim.Nmer3D(n=8, d=0.3)
32+
params3d = StaticSMLMParams(
33+
ρ=1.0,
34+
ndims=3,
35+
zrange=[-2.0, 2.0]
36+
)
37+
smld_true, smld_model, smld_noisy = simulate(
38+
params3d,
39+
pattern=pattern3d,
40+
camera=camera
41+
)
42+
43+
# Complex Pattern Example
44+
line3d = SMLMSim.Line3D(λ=5.0, endpoints=[(-1.0, 0.0, -0.5), (1.0, 0.0, 0.5)])
45+
params_line = StaticSMLMParams(
46+
ρ=0.5,
47+
σ_psf=0.15,
48+
ndims=3
49+
)
50+
smld_true, smld_model, smld_noisy = simulate(
51+
params_line,
52+
pattern=line3d,
53+
camera=camera
54+
)
55+

dev/benchmark.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ using BenchmarkTools
77
γ=10000.0
88
q=[0 10
99
1e-1 0]
10-
f=SMLMSim.GenericFluor(γ,q)
10+
f=SMLMSim.GenericFluor(photons=γ, k_off=10.0, k_on=0.1)
1111

1212
## Simulate intensity trace
1313

0 commit comments

Comments
 (0)