Skip to content

Commit b5ab9fb

Browse files
committed
add working test suite for automated testing
1 parent cd61d37 commit b5ab9fb

File tree

7 files changed

+544
-19
lines changed

7 files changed

+544
-19
lines changed

test/Project.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[deps]
2+
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
3+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
4+
MicroscopePSFs = "de9ac726-48a4-48ab-84b0-1c03c7c18929"
5+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
6+
SMLMData = "5488f106-40b8-4660-84c5-84a168990d1b"
7+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

test/runtests.jl

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
using SMLMSim
22
using Test
3+
using SMLMData
4+
using Distributions
5+
using LinearAlgebra
6+
using MicroscopePSFs
7+
8+
# Include test files
9+
include("test_patterns.jl")
10+
include("test_molecules.jl")
11+
include("test_kinetics.jl")
12+
include("test_diffusion.jl")
13+
include("test_imaging_and_analysis.jl")
314

415
@testset "SMLMSim.jl" begin
5-
# Write your tests here.
16+
@testset "Patterns" begin
17+
test_patterns()
18+
end
619

7-
@testset "Interaction Diffusion" begin
8-
using MicroscopePSFs
20+
@testset "Molecules" begin
21+
test_molecules()
22+
end
923

10-
box_size = 1
11-
dt = 0.005
12-
density = 2
13-
state_history, args = SMLMSim.InteractionDiffusion.smoluchowski(;
14-
dt=dt, box_size=box_size, t_max=5.0, density=density, d_dimer=0.05)
15-
@test length(state_history.frames) == 1000
16-
17-
pixelsize = 0.1
18-
pixels = Int64(round(box_size / pixelsize))
19-
psf = MicroscopePSFs.Airy2D(1.3, 0.6, pixelsize)
20-
camera = SMLMSim.IdealCamera(xpixels=pixels, ypixels=pixels, pixelsize=pixelsize)
21-
dimer_history = SMLMSim.InteractionDiffusion.get_dimers(state_history)
22-
dimer_stack = SMLMSim.gen_image_stack(psf, dimer_history, camera;
23-
photons=1000.0, bg=5.0, poissonnoise=true, frame_integration=10)
24-
@test size(dimer_stack) == (pixels, pixels, 100)
24+
@testset "Kinetic Modeling" begin
25+
test_kinetics()
2526
end
2627

28+
@testset "Diffusion" begin
29+
test_diffusion()
30+
end
2731

28-
end
32+
@testset "Imaging & Analysis" begin
33+
test_imaging_and_analysis()
34+
end
35+
end

test/test_diffusion.jl

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using SMLMSim.InteractionDiffusion
2+
using Random
3+
# Import the initialize_system function explicitly
4+
using SMLMSim.InteractionDiffusion: initialize_system
5+
6+
function test_diffusion()
7+
@testset "SmoluchowskiParams" begin
8+
# Test default constructor
9+
params = SmoluchowskiParams()
10+
@test params.density == 1.0
11+
@test params.box_size == 10.0
12+
@test params.dt == 0.01
13+
@test params.boundary == "periodic"
14+
15+
# Test custom constructor with a few key parameters
16+
params = SmoluchowskiParams(
17+
density = 2.0,
18+
box_size = 20.0,
19+
ndims = 3,
20+
boundary = "reflecting"
21+
)
22+
23+
@test params.density == 2.0
24+
@test params.box_size == 20.0
25+
@test params.ndims == 3
26+
@test params.boundary == "reflecting"
27+
28+
# Test one invalid parameter case
29+
@test_throws ArgumentError SmoluchowskiParams(density = -1.0)
30+
end
31+
32+
@testset "Diffusion Simulation" begin
33+
# Create small system for quick tests
34+
params = SmoluchowskiParams(
35+
density = 1.0,
36+
box_size = 1.0,
37+
dt = 0.01,
38+
t_max = 0.05 # Just 5 frames
39+
)
40+
41+
# Test system initialization
42+
system = initialize_system(params)
43+
expected_molecules = round(Int, params.density * params.box_size^params.ndims)
44+
@test length(system.molecules) == expected_molecules
45+
46+
# Test basic simulation
47+
systems = simulate(params)
48+
@test length(systems) == round(Int, params.t_max / params.dt)
49+
50+
# Test dimer formation with parameters favoring dimers
51+
params_dimer = SmoluchowskiParams(
52+
density = 10.0, # High density
53+
box_size = 1.0, # Small box
54+
r_react = 0.1, # Large reaction radius
55+
k_off = 0.01, # Slow dissociation
56+
dt = 0.01,
57+
t_max = 0.1 # Short but likely sufficient for dimers
58+
)
59+
60+
systems_dimer = simulate(params_dimer)
61+
62+
# Check if dimers formed
63+
final_system = systems_dimer[end]
64+
n_dimers = count(m -> m.state == 2, final_system.molecules)
65+
66+
# Print rather than test - dimers might not form in all cases
67+
@info "Number of dimers formed: $n_dimers out of $(length(final_system.molecules)) molecules"
68+
end
69+
70+
@testset "Dimer Analysis" begin
71+
# Create a system with some dimers
72+
params = SmoluchowskiParams(box_size = 1.0, density = 5.0)
73+
system = initialize_system(params)
74+
75+
# Make some molecules into dimers
76+
n_molecules = length(system.molecules)
77+
n_dimers = min(2, div(n_molecules, 2))
78+
for i in 1:n_dimers
79+
mol1 = system.molecules[2*i-1]
80+
mol2 = system.molecules[2*i]
81+
mol1.state = 2
82+
mol2.state = 2
83+
mol1.link = mol2.id
84+
mol2.link = mol1.id
85+
end
86+
87+
# Test get_dimers
88+
dimer_system = get_dimers(system)
89+
@test length(dimer_system.molecules) == 2 * n_dimers
90+
@test all(m -> m.state == 2, dimer_system.molecules)
91+
92+
# Test analyze_dimer_fraction
93+
fractions = analyze_dimer_fraction([system])
94+
@test length(fractions) == 1
95+
expected_fraction = 2 * n_dimers / n_molecules
96+
@test fractions[1] expected_fraction
97+
end
98+
end

test/test_imaging_and_analysis.jl

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using SMLMSim.InteractionDiffusion
2+
using MicroscopePSFs
3+
using Random
4+
5+
function test_imaging_and_analysis()
6+
@testset "Image Generation" begin
7+
# Create a simple system with one molecule
8+
camera = IdealCamera(1:50, 1:50, 0.1) # 5μm x 5μm field with 100nm pixels
9+
emitter = Emitter2D{Float64}(2.5, 2.5, 1000.0) # Center of field
10+
molecule = DiffusingMolecule(emitter, 1, 1, nothing, false)
11+
12+
system = DiffusingMoleculeSystem(
13+
[molecule], camera, 5.0, 1, 1, Dict{String,Any}()
14+
)
15+
16+
# Create PSF and generate image
17+
psf = Gaussian2D(0.15)
18+
img = gen_image(psf, system, 1, photons=1000.0, bg=5.0, poisson_noise=false)
19+
20+
# Test basic image properties
21+
@test size(img) == (length(camera.pixel_edges_y)-1, length(camera.pixel_edges_x)-1)
22+
@test all(img .>= 5.0) # At least background everywhere
23+
24+
# Test image sequence generation
25+
# Create a minimal simulation
26+
params = SmoluchowskiParams(
27+
density = 1.0,
28+
box_size = 2.0,
29+
dt = 0.01,
30+
t_max = 0.03 # Just 3 frames
31+
)
32+
systems = simulate(params)
33+
34+
# Generate image sequence
35+
imgs = gen_image_sequence(psf, systems,
36+
photons=1000.0, bg=5.0,
37+
frame_integration=1, poisson_noise=false)
38+
39+
# Test basic sequence properties
40+
@test size(imgs, 3) == length(systems)
41+
42+
# Test frame integration
43+
imgs_integrated = gen_image_sequence(psf, systems,
44+
photons=1000.0, bg=5.0,
45+
frame_integration=3, poisson_noise=false)
46+
47+
@test size(imgs_integrated, 3) == 1 # Should have just one frame with integration=3
48+
end
49+
50+
@testset "Dimer Imaging" begin
51+
# Create a system with dimers
52+
params = SmoluchowskiParams(
53+
density = 5.0,
54+
box_size = 1.0,
55+
dt = 0.01,
56+
t_max = 0.01 # Just one frame
57+
)
58+
system = initialize_system(params)
59+
60+
# Make some molecules into dimers
61+
n_molecules = length(system.molecules)
62+
n_dimers = min(2, div(n_molecules, 2))
63+
for i in 1:n_dimers
64+
mol1 = system.molecules[2*i-1]
65+
mol2 = system.molecules[2*i]
66+
mol1.state = 2
67+
mol2.state = 2
68+
mol1.link = mol2.id
69+
mol2.link = mol1.id
70+
end
71+
72+
# Create a sequence with just this one system
73+
systems = [system]
74+
75+
# Create PSF and generate dimer images
76+
psf = Gaussian2D(0.15)
77+
dimer_images = gen_dimer_images(systems, psf,
78+
photons=1000.0, bg=5.0,
79+
frame_integration=1, poisson_noise=false)
80+
81+
# Test basic image properties
82+
@test size(dimer_images, 3) == 1
83+
end
84+
85+
@testset "Full Simulation Pipeline" begin
86+
# Test the complete workflow with minimal simulation
87+
# This is a crucial test as it ensures all components work together
88+
89+
# Create simulation parameters
90+
params = SmoluchowskiParams(
91+
density = 1.0,
92+
box_size = 1.0,
93+
dt = 0.01,
94+
t_max = 0.02 # Just 2 frames
95+
)
96+
97+
# Create PSF
98+
psf = Gaussian2D(0.15)
99+
100+
# Run simulation and imaging
101+
images, systems = simulate_and_image(params, psf,
102+
photons=1000.0, bg=5.0,
103+
frame_integration=1, poisson_noise=false)
104+
105+
# Test basic outputs
106+
@test isa(images, Array{Float64, 3})
107+
@test length(systems) == 2
108+
@test size(images, 3) == 2
109+
end
110+
111+
@testset "Core Interface" begin
112+
# Test the main simulate interfaces
113+
camera = IdealCamera(1:20, 1:20, 0.1)
114+
115+
# Basic interface
116+
smld_true, smld_model, smld_noisy = SMLMSim.simulate(
117+
ρ=1.0,
118+
camera=camera,
119+
nframes=5 # Minimal
120+
)
121+
122+
# Test basic outputs
123+
@test smld_true isa BasicSMLD
124+
@test smld_model isa BasicSMLD
125+
@test smld_noisy isa BasicSMLD
126+
127+
# With explicit pattern
128+
pattern = Nmer2D(n=4, d=0.1)
129+
smld_true, smld_model, smld_noisy = SMLMSim.simulate(
130+
pattern,
131+
ρ=1.0,
132+
camera=camera,
133+
nframes=5
134+
)
135+
136+
@test smld_true isa BasicSMLD
137+
end
138+
139+
# Skip visualization tests in normal test runs as they're slow and mostly check for errors
140+
if get(ENV, "RUN_VISUALIZATION_TESTS", "false") == "true"
141+
@testset "Visualization" begin
142+
# Create a small simulation
143+
params = SmoluchowskiParams(
144+
density = 2.0,
145+
box_size = 1.0,
146+
dt = 0.01,
147+
t_max = 0.03 # Just 3 frames
148+
)
149+
systems = simulate(params)
150+
151+
# Test with a temporary file (no assertion, just checking for errors)
152+
temp_file = "test_vis_$(rand(1:1000)).mp4"
153+
154+
try
155+
visualize_sequence(systems, filename=temp_file, framerate=10)
156+
finally
157+
if isfile(temp_file)
158+
rm(temp_file)
159+
end
160+
end
161+
end
162+
end
163+
end

0 commit comments

Comments
 (0)