Add Chromatix thin-phase sample core - #70
Open
efe-bastug wants to merge 1 commit into
Open
Conversation
efe-bastug
force-pushed
the
brightfield-thin-sample
branch
from
August 27, 2026 20:23
8482a4b to
72604d1
Compare
efe-bastug
force-pushed
the
brightfield-thin-sample
branch
from
August 30, 2026 22:29
72604d1 to
12570f7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds the physical specimen input and the vector-field sample interaction as package code. It stops at the field immediately after the sample: the returned object is a Chromatix
VectorField, not a brightfield image.Two new files, no existing file touched:
SyMBac/brightfield.pytests/test_brightfield.pyWhat each function does
scene_to_thickness_um(opl_scene, *, pix_mic_conv_um, resize_amount)Converts a SyMBac scene into projected sample thickness in micrometres:
Despite its legacy name,
OPL_sceneholds projected geometric thickness measured in supersampled simulation pixels, not an optical path length, so this is a pure change of units and no refractive-index contrast enters it. The scene must be two-dimensional, finite and non-negative, and both scale factors must be positive and finite. The shape is preserved, a newfloat64array is returned, and the input is not modified. This function is pure NumPy and needs neither JAX nor Chromatix.apply_thin_phase_sample(field, thickness_um, *, refractive_index_difference)Applies that thickness map to one monochromatic Chromatix
VectorFieldas a thin, isotropic, non-absorbing (pure-phase) sample:The vacuum wavelength is read from the field itself, so there is no second wavelength argument that could disagree with the field it is applied to. The transmittance
exp(1j * phase_rad)has unit modulus everywhere, and the same real phase reaches all three components, so intensity, power and polarization are unchanged. The function requires the field and the thickness map to share a spatial shape, requires a finite (possibly negative) refractive-index difference, and returns a newVectorFieldwith the same spatial shape and the same[z, y, x]component order.JAX and Chromatix are imported inside the call rather than at module import time, because this project installs them only for Python 3.12. Nothing in the module executes on import, and neither function plots, prints, writes files nor normalizes anything.
Units
opl_scenepix_mic_conv_umresize_amountthickness_umrefractive_index_differencephase_radChromatix function used
chromatix.functional.phase_change, called asThe phase is already calculated for the single field wavelength, so the spectral-modulation choice is made explicit instead of relying on the default.
cf.thin_sampleis not used: in pinned Chromatix 0.6.0 it is documented for scalar fields, whereas this production path stays vectorial. In pinned 0.6.0phase_changebroadcasts the 2D phase to(y, x, 1)and returnsfield * exp(1j * phase), so one real phase reaches all three components. The production code never multiplies the field byexp(i * phase)by hand; that independent calculation exists only in the test.Tests
tests/test_brightfield.pyskips cleanly when JAX or Chromatix are unavailable, viapytest.importorskipat module level, and runs in the Python 3.12 Pixi environment. It covers:pix_mic_conv_um / resize_amountmicrometres per supersampled pixel, with shape preserved and neither axis transposed;draw_scene_from_segmentspassing through both functions;input_field * exp(i * phase_rad)calculation;VectorField.intensityandField.powerpreserved by the pure-phase sample;[z, y, x]component dimension, finite values and input immutability, for both the field and the thickness array;Two further tests check that the phase follows the wavelength stored in the field (0.405, 0.532 and 0.660 µm) and that a negative refractive-index difference produces a negative phase without changing the intensity.
Test commands and results
The full suite was 63 passed with the same single warning before this branch, so the 28 new tests are additive and nothing existing changed. The warning is the pre-existing CPU-fallback notice from
SyMBac/renderer.py:55(no GPU backend on this machine).git diff --checkandgit diff --cached --checkare both clean.AI assistance
An AI coding assistant was used to draft
SyMBac/brightfield.pyandtests/test_brightfield.py.Not part of this PR
Propagation away from the sample, an objective, pupil or camera relay, defocus, partial coherence, multiple wavelengths, two-state unpolarized illumination, detector sampling, photons or noise, a scalar production mode,
Rendererintegration, figures, notebooks or example images, and performance optimization. PR #68 is untouched.