Skip to content

Say how to measure a PSF in AGENTS.md - #69

Merged
HazenBabcock merged 1 commit into
ZhuangLab:masterfrom
HazenBabcock:agents-psf-fitting
Sep 9, 2026
Merged

HazenBabcock merged 1 commit into
ZhuangLab:masterfrom
HazenBabcock:agents-psf-fitting

Conversation

@HazenBabcock

Copy link
Copy Markdown
Member

Four of the six fitters need a PSF model before they will run, and AGENTS.md only had a two sentence stub about it. doc/source/analysis.rst already has the step by step for both measurement paths, so this is the layer above it: which tool produces which model, and the parts that are easy to get wrong.

The one that reframes the task is that there is no phase retrieval in this tree. make_pupil_fn.py and make_psf_from_pf.py build from Zernike coefficients you supply and never read bead data, so "measure the pupil function from my bead stack" is not something any tool here does. An agent can otherwise spend a long time looking for it.

The rest are traps, each checked against the tree rather than remembered:

  • aoi_size is a half width, so the default 12 gives a 24 pixel AOI.
  • The AOI border is assumed to be background and subtracted from every z plane, which is wrong in a crowded field or over a z range wide enough that the PSF is broader than the AOI.
  • z_range defaults differ between tools that look interchangeable: 0.6 um in measure_psf_beads.py, 0.75 um in the other two.
  • pixel_size is microns here and nanometres in the analysis XML, and both defaults are plausible.
  • make_pupil_fn.py takes no optics at all: wavelength, index and NA are module globals in simulator/psf.py.
  • geo_sim_pf defaults to True and silently halves the pixel size via GeometrySim.
  • pfZernikeRad returns the unnormalized radial polynomial, so a coefficient is not an rms wavefront error.
  • Geometry.aberration() does not go to 1 as depth goes to 0, so gating it on depth > 0 puts a step in anything you are optimizing.

No code changes; AGENTS.md only, 216 to 311 lines.

Four of the six fitters need a PSF model before they run, and the file only
had a two sentence stub about it. doc/source/analysis.rst already has the
step by step, so this is the layer above: which tool produces which model,
and the parts that are easy to get wrong.

The one that reframes the task is that there is no phase retrieval here.
make_pupil_fn.py and make_psf_from_pf.py build from Zernike coefficients you
supply and never read bead data, so "measure the pupil function from my bead
stack" is not a thing any tool does, and an agent can otherwise spend a long
time looking for it.

The rest are traps checked against the tree: aoi_size is a half width, the
AOI border is assumed to be background and is subtracted, z_range defaults
differ between tools that look interchangeable, pixel_size is microns here
and nanometres in the analysis XML, make_pupil_fn takes no optics at all,
geo_sim_pf silently halves the pixel size, pfZernikeRad is unnormalized so a
coefficient is not an rms wavefront error, and aberration() does not go to 1
as depth goes to 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@HazenBabcock
HazenBabcock merged commit 81f1b97 into ZhuangLab:master Sep 9, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant