Skip to content

Commit 7718012

Browse files
kalidkeclaude
andcommitted
Update documentation for (result, info) tuple return pattern
- Update README.md with new tuple returns for simulate() and gen_images() - Update api_overview.md with SimInfo and ImageInfo documentation - Update docs/src/index.md quick start examples - Update docs/src/static/overview.md and examples.md - Update docs/src/diffusion/overview.md and examples.md - Update docs/src/images.md with ImageInfo return type All functions now return (result, info) tuples: - simulate() returns (smld_noisy, SimInfo) where info contains smld_true, smld_model - gen_images() returns (images, ImageInfo) with timing and statistics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 506ce59 commit 7718012

File tree

8 files changed

+158
-124
lines changed

8 files changed

+158
-124
lines changed

README.md

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,20 @@ camera = IdealCamera(128, 128, 0.1) # 128×128 pixels, 100nm pixels
3838
params = StaticSMLMParams(density=1.0, σ_psf=0.13) # Density 1/μm², PSF 130nm
3939

4040
# Run simulation for an 8-molecule ring pattern
41-
smld_true, smld_model, smld_noisy = simulate(
41+
smld_noisy, info = simulate(
4242
params; # Use semicolon to separate positional and keyword arguments
4343
pattern=Nmer2D(n=8, d=0.1), # 100nm diameter ring
4444
camera=camera
4545
)
4646

47+
# Access ground truth and kinetic model from info
48+
smld_true = info.smld_true
49+
smld_model = info.smld_model
50+
4751
# smld_noisy contains realistic SMLM coordinates
4852
println("Generated $(length(smld_noisy.emitters)) localizations.")
4953
```
50-
*Output:* `smld_true` (ground truth), `smld_model` (kinetics), `smld_noisy` (kinetics + noise).
54+
*Output:* `smld_noisy` (primary result with noise), `info` (SimInfo with `smld_true`, `smld_model`, timing).
5155

5256
### Diffusion & Interaction Simulation
5357

@@ -69,9 +73,9 @@ params = DiffusionSMLMParams(
6973
)
7074

7175
# Run diffusion simulation
72-
smld = simulate(params) # Returns a BasicSMLD object with all emitters
76+
smld, info = simulate(params) # Returns (BasicSMLD, SimInfo) tuple
7377

74-
println("Simulated diffusion for $(params.t_max) seconds.")
78+
println("Simulated diffusion for $(params.t_max) seconds in $(info.elapsed_ns / 1e6)ms.")
7579
# 'smld' can be used for analysis or image generation
7680
```
7781

@@ -111,12 +115,12 @@ using MicroscopePSFs # Needed for PSF types
111115
# Note: Frame timing is controlled by DiffusionSMLMParams (camera_framerate, camera_exposure)
112116
# Multiple simulation timesteps are automatically integrated during simulate()
113117
psf = GaussianPSF(0.15) # 150nm PSF width
114-
images = gen_images(smld, psf;
118+
images, img_info = gen_images(smld, psf;
115119
support=1.0, # PSF support radius in μm (faster than default Inf)
116120
poisson_noise=true # Add shot noise
117121
)
118122

119-
println("Generated $(size(images,3)) camera images.")
123+
println("Generated $(img_info.frames_generated) camera images with $(img_info.n_photons_total) total photons.")
120124
```
121125

122126
### sCMOS Camera with Realistic Noise
@@ -132,7 +136,7 @@ camera_scmos = SCMOSCamera(128, 128, 0.1, 1.6)
132136

133137
# Run static simulation with sCMOS camera
134138
params = StaticSMLMParams(density=1.0, σ_psf=0.13)
135-
smld_true, smld_model, smld_noisy = simulate(
139+
smld_noisy, info = simulate(
136140
params,
137141
pattern=Nmer2D(n=8, d=0.1),
138142
camera=camera_scmos
@@ -141,11 +145,11 @@ smld_true, smld_model, smld_noisy = simulate(
141145
# Generate images with full sCMOS noise model
142146
# (quantum efficiency, Poisson, read noise, gain, offset)
143147
psf = GaussianPSF(0.15)
144-
images_scmos = gen_images(smld_noisy, psf, bg=10.0, camera_noise=true)
148+
images_scmos, img_info = gen_images(smld_noisy, psf, bg=10.0, camera_noise=true)
145149

146150
# For diffusion simulations
147151
diff_params = DiffusionSMLMParams(density=0.5, box_size=10.0)
148-
smld_diff = simulate(diff_params; camera=camera_scmos, override_count=10)
152+
smld_diff, diff_info = simulate(diff_params; camera=camera_scmos, override_count=10)
149153
```
150154

151155
The sCMOS noise model applies:
@@ -165,7 +169,7 @@ using MicroscopePSFs
165169
# --- Simulation Setup ---
166170
camera = IdealCamera(128, 128, 0.1) # 128×128 pixels, 100nm pixels
167171
params = StaticSMLMParams(density=1.0, σ_psf=0.13)
168-
smld_true, smld_model, smld_noisy = simulate(
172+
smld_noisy, info = simulate(
169173
params,
170174
pattern=Nmer2D(n=6, d=0.2), # Hexamer
171175
camera=camera
@@ -209,17 +213,17 @@ params = DiffusionSMLMParams(
209213
t_max = 0.5, # 0.5 second total
210214
camera_framerate = 100.0 # 100 fps
211215
)
212-
smld = simulate(params; camera=camera_scmos, photons=200.0)
216+
smld, sim_info = simulate(params; camera=camera_scmos, photons=200.0)
213217

214218
# Generate images with full sCMOS noise model
215219
# (quantum efficiency, Poisson, read noise, gain, offset)
216220
psf = GaussianPSF(0.13) # 130nm PSF
217-
images_scmos = gen_images(smld, psf, bg=10.0, camera_noise=true)
221+
images_scmos, img_info = gen_images(smld, psf, bg=10.0, camera_noise=true)
218222

219223
# For comparison: same data with ideal camera (Poisson noise only)
220224
camera_ideal = IdealCamera(64, 64, 0.1)
221225
smld_ideal = BasicSMLD(smld.emitters, camera_ideal, smld.n_frames, smld.n_datasets)
222-
images_ideal = gen_images(smld_ideal, psf, bg=10.0, poisson_noise=true)
226+
images_ideal, _ = gen_images(smld_ideal, psf, bg=10.0, poisson_noise=true)
223227

224228
# Compare statistics
225229
println("sCMOS: mean=$(round(mean(images_scmos), digits=1)) ADU, std=$(round(std(images_scmos), digits=1))")

api_overview.md

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -218,30 +218,36 @@ camera_scmos = SCMOSCamera(
218218

219219
#### simulate
220220

221-
The main simulation function with multiple methods for different simulation types.
221+
The main simulation function with multiple methods for different simulation types. All simulation functions return a `(result, info)` tuple.
222222

223223
```julia
224224
# Static SMLM simulation
225225
# First create simulation parameters
226226
params = StaticSMLMParams()
227227

228-
# Then run simulation
229-
smld_true, smld_model, smld_noisy = simulate(
228+
# Then run simulation - returns (smld_noisy, SimInfo) tuple
229+
smld_noisy, info = simulate(
230230
params;
231231
pattern=Nmer2D(),
232232
molecule=GenericFluor(),
233233
camera=IdealCamera(128, 128, 0.1)
234234
)
235235

236+
# Access ground truth and kinetic model from info
237+
smld_true = info.smld_true # Ground truth positions
238+
smld_model = info.smld_model # Positions with blinking kinetics
239+
# info also contains: elapsed_ns, backend, device_id, n_frames, n_emitters, n_localizations
240+
236241
# Diffusion simulation
237242
# First create simulation parameters
238243
params_diff = DiffusionSMLMParams()
239244

240-
# Then run simulation
241-
smld = simulate(
245+
# Then run simulation - returns (smld, SimInfo) tuple
246+
smld, info = simulate(
242247
params_diff;
243248
photons=1000.0
244249
)
250+
# info contains: elapsed_ns, backend, device_id, n_frames
245251
```
246252

247253
#### kinetic_model
@@ -289,10 +295,10 @@ smld_noisy_3d = apply_noise(smld_model_3d, [0.13, 0.13, 0.39]) # [x, y, z] widt
289295

290296
#### gen_images
291297

292-
Generate camera images from SMLD data using the specified PSF model.
298+
Generate camera images from SMLD data using the specified PSF model. Returns a `(images, ImageInfo)` tuple.
293299

294300
```julia
295-
images = gen_images(
301+
images, img_info = gen_images(
296302
smld::SMLD,
297303
psf::AbstractPSF;
298304
dataset::Int=1, # Dataset number to use from SMLD
@@ -307,6 +313,8 @@ images = gen_images(
307313
# - For IdealCamera: ignored (use poisson_noise instead)
308314
)
309315

316+
# ImageInfo contains: elapsed_ns, backend, device_id, frames_generated, n_photons_total, output_size
317+
310318
# The support parameter controls PSF computation region:
311319
# 1. Inf (default): Compute PSF over entire image (most accurate but slowest)
312320
support=Inf
@@ -321,18 +329,18 @@ support=(4.0, 6.0, 4.0, 6.0) # Only compute PSF within this region
321329
# Example: sCMOS camera with realistic noise
322330
camera_scmos = SCMOSCamera(128, 128, 0.1, 1.6)
323331
smld = BasicSMLD(emitters, camera_scmos, n_frames, n_datasets)
324-
images_scmos = gen_images(smld, psf, bg=10.0, camera_noise=true)
332+
images_scmos, img_info = gen_images(smld, psf, bg=10.0, camera_noise=true)
325333
# Applies: QE → Poisson → read noise → gain → offset
326334

327335
# Example: IdealCamera with Poisson noise only
328336
camera_ideal = IdealCamera(128, 128, 0.1)
329337
smld = BasicSMLD(emitters, camera_ideal, n_frames, n_datasets)
330-
images_poisson = gen_images(smld, psf, bg=10.0, poisson_noise=true)
338+
images_poisson, img_info = gen_images(smld, psf, bg=10.0, poisson_noise=true)
331339
```
332340

333341
#### gen_image
334342

335-
Generate a single frame camera image.
343+
Generate a single frame camera image. Returns a `(image, ImageInfo)` tuple.
336344

337345
```julia
338346
# Example of generating a single frame image
@@ -342,9 +350,9 @@ smld = ... # Your SMLD data
342350
psf = GaussianPSF(0.15) # PSF model with 150nm width
343351
frame_number = 10 # The frame you want to generate
344352

345-
# Generate image for a specific frame
346-
single_frame = gen_image(
347-
smld, # SMLD data
353+
# Generate image for a specific frame - returns (image, ImageInfo) tuple
354+
single_frame, img_info = gen_image(
355+
smld, # SMLD data
348356
psf, # PSF model
349357
frame_number; # Frame to generate
350358
support=1.0, # Same keyword arguments as gen_images
@@ -387,7 +395,7 @@ state_history = track_state_changes(smld)
387395

388396
# First, run a simulation
389397
params = StaticSMLMParams()
390-
smld_true, smld_model, smld_noisy = simulate(params)
398+
smld_noisy, info = simulate(params)
391399

392400
# Specify a track ID to extract
393401
track_id = 1 # ID of the track to extract
@@ -441,7 +449,7 @@ x, y, z = uniform3D(density, pattern3d, field_x, field_y, zrange=[-2.0, 2.0])
441449
1. Define simulation parameters
442450
2. Create a pattern (or use default)
443451
3. Define a fluorophore model (or use default)
444-
4. Run simulation to get true positions, kinetic model, and noisy localizations
452+
4. Run simulation to get noisy localizations and info (containing ground truth)
445453
5. Generate microscope images or analyze the data
446454

447455
```julia
@@ -458,16 +466,17 @@ pattern = Nmer2D(n=6, d=0.2) # hexamer with 200nm diameter
458466
# 3. Define fluorophore model
459467
fluor = GenericFluor(photons=1e5, k_off=50.0, k_on=1e-2)
460468

461-
# 4. Run simulation
462-
smld_true, smld_model, smld_noisy = simulate(
469+
# 4. Run simulation - returns (smld_noisy, SimInfo) tuple
470+
smld_noisy, info = simulate(
463471
params;
464472
pattern=pattern,
465473
molecule=fluor
466474
)
475+
# Access ground truth from info: info.smld_true, info.smld_model
467476

468477
# 5. Create microscope images with efficient PSF support
469478
psf = GaussianPSF(0.15) # 150nm PSF width
470-
images = gen_images(smld_model, psf;
479+
images, img_info = gen_images(info.smld_model, psf;
471480
support=1.0, # 1.0 μm radius around each emitter
472481
poisson_noise=true # Add realistic photon counting noise
473482
)
@@ -491,8 +500,8 @@ params = DiffusionSMLMParams(
491500
t_max = 10.0 # s
492501
)
493502

494-
# 2. Run simulation
495-
smld = simulate(params)
503+
# 2. Run simulation - returns (smld, SimInfo) tuple
504+
smld, sim_info = simulate(params)
496505

497506
# 3. Analyze the results
498507
dimer_smld = get_dimers(smld)
@@ -505,7 +514,7 @@ camera_scmos = SCMOSCamera(n_pixels, n_pixels, 0.1, 1.6)
505514
smld_cam = BasicSMLD(smld.emitters, camera_scmos, smld.n_frames, 1)
506515

507516
psf = GaussianPSF(0.15) # 150nm PSF width
508-
images = gen_images(smld_cam, psf;
517+
images, img_info = gen_images(smld_cam, psf;
509518
support=1.0, # 1.0 μm PSF support radius (faster)
510519
bg=5.0, # Background photons per pixel
511520
camera_noise=true # Full sCMOS noise model (QE, Poisson, read noise, gain, offset)
@@ -522,27 +531,32 @@ using MicroscopePSFs
522531

523532
# Define a camera and simulation parameters
524533
camera = IdealCamera(128, 128, 0.1) # 128×128 pixels, 100nm pixels
525-
params = StaticSMLMParams(density=1.0, σ_psf=0.13, nframes=1000)
534+
params = StaticSMLMParams(density=1.0, σ_psf=0.13, nframes=1000)
526535

527-
# Run simulation for an 8-molecule ring pattern
528-
smld_true, smld_model, smld_noisy = simulate(
536+
# Run simulation for an 8-molecule ring pattern - returns (smld_noisy, SimInfo) tuple
537+
smld_noisy, info = simulate(
529538
params;
530539
pattern=Nmer2D(n=8, d=0.1), # 100nm diameter ring
531540
molecule=GenericFluor(1e5, [-10.0 10.0; 0.5 -0.5]), # γ=100,000, k_off=10, k_on=0.5
532541
camera=camera
533542
)
534543

544+
# Access ground truth and kinetic model from info
545+
smld_true = info.smld_true
546+
smld_model = info.smld_model
547+
535548
# Create a PSF model
536549
psf = GaussianPSF(0.15) # 150nm PSF width
537550

538-
# Generate microscope images with finite PSF support
539-
images = gen_images(smld_model, psf;
551+
# Generate microscope images with finite PSF support - returns (images, ImageInfo) tuple
552+
images, img_info = gen_images(smld_model, psf;
540553
support=1.0, # 1.0 μm PSF support radius (faster than Inf)
541554
bg=5.0, # 5 background photons per pixel
542555
poisson_noise=true # Add realistic photon counting noise
543556
)
544557

545558
println("Generated $(length(smld_noisy.emitters)) localizations and $(size(images,3)) images.")
559+
println("Image generation took $(img_info.elapsed_ns / 1e6) ms.")
546560
```
547561

548562
### Diffusion with Dimer Analysis
@@ -562,22 +576,23 @@ params = DiffusionSMLMParams(
562576
boundary = "reflecting" # Use reflecting boundaries
563577
)
564578

565-
# Run diffusion simulation
566-
smld = simulate(params)
579+
# Run diffusion simulation - returns (smld, SimInfo) tuple
580+
smld, sim_info = simulate(params)
567581

568582
# Analyze dimer formation
569583
frames, dimer_fraction = analyze_dimer_fraction(smld)
570584
avg_lifetime = analyze_dimer_lifetime(smld)
571585

572-
# Generate microscope images with finite PSF support
586+
# Generate microscope images with finite PSF support - returns (images, ImageInfo) tuple
573587
psf = GaussianPSF(0.15) # 150nm PSF width
574-
images = gen_images(smld, psf;
588+
images, img_info = gen_images(smld, psf;
575589
support=1.0, # 1.0 μm PSF support radius (faster)
576590
bg=2.0, # Background photons per pixel
577591
poisson_noise=true # Add realistic photon counting noise
578592
)
579593

580594
println("Simulation complete with $(length(smld.emitters)) emitters")
595+
println("Simulation took $(sim_info.elapsed_ns / 1e6) ms")
581596
println("Average dimer fraction: $(mean(dimer_fraction))")
582597
println("Average dimer lifetime: $(avg_lifetime) seconds")
583598
```
@@ -638,12 +653,13 @@ params = StaticSMLMParams(
638653
# Create custom pattern
639654
double_ring = DoubleRing3D(n=6, d1=0.15, d2=0.3, z1=-0.3, z2=0.3)
640655

641-
# Run simulation
642-
smld_true, smld_model, smld_noisy = simulate(
656+
# Run simulation - returns (smld_noisy, SimInfo) tuple
657+
smld_noisy, info = simulate(
643658
params;
644659
pattern=double_ring,
645660
camera=camera
646661
)
662+
smld_model = info.smld_model
647663

648664
# Generate images with a 3D astigmatic PSF and finite support
649665
# Create a PSF with astigmatism using Zernike coefficients
@@ -658,12 +674,13 @@ x_range = y_range = -1.0:xy_sampling:1.0
658674
z_range = -1.0:z_sampling:1.0
659675
psf_spline = SplinePSF(psf_scalar, x_range, y_range, z_range)
660676

661-
# Generate images using the spline PSF with finite support
662-
images = gen_images(smld_model, psf_spline;
677+
# Generate images using the spline PSF with finite support - returns (images, ImageInfo) tuple
678+
images, img_info = gen_images(smld_model, psf_spline;
663679
support=0.5, # 0.5 μm PSF support radius for performance
664680
bg=5.0, # Background photons per pixel
665681
poisson_noise=true # Add realistic photon counting noise
666682
)
667683

668684
println("Generated $(length(smld_noisy.emitters)) localizations in 3D")
685+
println("Generated $(img_info.frames_generated) frames with $(img_info.n_photons_total) total photons")
669686
```

0 commit comments

Comments
 (0)