Skip to content

Metadata update #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jun 23, 2022
Merged

Metadata update #117

merged 17 commits into from
Jun 23, 2022

Conversation

ieivanov
Copy link
Contributor

@ieivanov ieivanov commented Jun 1, 2022

This PR updates the format of the metadata file saved by recorder. The main motivation was to add a field for logging LC voltages (and not just retardance), and to round float numbers before saving. In the process, I updated the structure of the metadata dictionary, adding the Calibration field (in addition to Summary, Notes, and Microscope parameters), changed some entries to more sensible naming (e.g. Calibration scheme instead of Acquired Using), and to more consistent capitalization (e.g. Extinction ratio instead of Extinction Ratio).

Saving LC voltage in the metadata file will be implemented in calibration_data_class_v2 branch, which will be tested and merged soon.

If we like this updated metadata file we should make sure to update recon pipelines that rely on it accordingly, keeping backward compatibility, if possible. @talonchandler, @Soorya19Pradeep, @mattersoflight let me know what you think.

Update:
Introduced MetadataReader class, which handles different versions of the calibration metadata we save. This class allows for backward compatibility and reconstructing data acquired with previous versions of the metadata format. Updated the repo to use the MetadataReader instead of loading the json file directly.

PR of the calibration_data_class_v2 branch will include logging of LC voltage in the calibration metadata (to 4 decimal places) and logging of the voltage interpolation method (e.g. interpolation vs Schoor fit)

@ieivanov
Copy link
Contributor Author

ieivanov commented Jun 1, 2022

The old format metadata looks like this

{
 "Summary": {
  "Timestamp": "2022-05-25 18:37:38.910646",
  "recOrder-napari version": "recOrder-napari 0.1.1.dev1+g148b9c3",
  "waveorder version": "waveorder 1.0.0b0",
  "Acquired Using": "5-State",
  "Swing (fraction)": 0.1,
  "Wavelength (nm)": 532,
  "BlackLevel": 144.91,
  "Extinction Ratio": 254.22,
  "ChNames": [
   "State0",
   "State1",
   "State2",
   "State3",
   "State4"
  ],
  "[LCA_Ext, LCB_Ext]": [
   0.30634075285030704,
   0.5834
  ],
  "[LCA_0, LCB_0]": [
   0.20634075285030704,
   0.5834
  ],
  "[LCA_45, LCB_45]": [
   0.3063,
   0.4952139933415637
  ],
  "[LCA_90, LCB_90]": [
   0.3984260299461079,
   0.5834
  ],
  "[LCA_135, LCB_135]": [
   0.3063,
   0.6532008989501689
  ],
  "Swing0": 0.1,
  "Swing45": 0.08818601607486636,
  "Swing90": 0.09208527709580083,
  "Swing135": 0.06980091084682555,
  "ROI Used (x, y, width, height)": [
   0,
   0,
   1232,
   1026
  ],
  "Instrument_Matrix": [
   [
    1.0,
    0.0,
    0.0,
    -1.0
   ],
   [
    1.0,
    0.5877852522924731,
    0.0,
    -0.8090169943749475
   ],
   [
    1.0,
    0.0,
    0.5877852522924731,
    -0.8090169943749475
   ],
   [
    1.0,
    -0.5877852522924731,
    0.0,
    -0.8090169943749475
   ],
   [
    1.0,
    0.0,
    -0.5877852522924731,
    -0.8090169943749475
   ]
  ]
 },
 "Notes": "",
 "Microscope Parameters": null
}

The new metadata format looks like this

{
 "Summary": {
  "Timestamp": "2022-05-31 20:14:30.027134",
  "recOrder-napari version": "recOrder-napari 0.1.1.dev1+g148b9c3",
  "waveorder version": "waveorder 1.0.0b0"
 },
 "Calibration": {
  "Calibration scheme": "5-State",
  "Swing (waves)": 0.1,
  "Wavelength (nm)": 532,
  "Black level": 119.73,
  "Extinction ratio": 237.08,
  "ROI (x, y, width, height)": [
   0,
   0,
   2448,
   2048
  ],
  "Channel names": [
   "State0",
   "State1",
   "State2",
   "State3",
   "State4"
  ],
  "LC retardance": {
   "LCA_ext": 0.30566,
   "LCB_ext": 0.5789,
   "LCA_0": 0.20566,
   "LCB_0": 0.5789,
   "LCA_45": 0.3057,
   "LCB_45": 0.48902,
   "LCA_90": 0.40126,
   "LCB_90": 0.5789,
   "LCA_135": 0.3057,
   "LCB_135": 0.64786
  },
  "LC voltage": {},
  "Swing_0": 0.1,
  "Swing_45": 0.09,
  "Swing_90": 0.096,
  "Swing_135": 0.069,
  "Instrument matrix": [
   [
    1.0,
    0.0,
    0.0,
    -1.0
   ],
   [
    1.0,
    0.58779,
    0.0,
    -0.80902
   ],
   [
    1.0,
    0.0,
    0.58779,
    -0.80902
   ],
   [
    1.0,
    -0.58779,
    0.0,
    -0.80902
   ],
   [
    1.0,
    0.0,
    -0.58779,
    -0.80902
   ]
  ]
 },
 "Notes": "",
 "Microscope parameters": null
}

@deprecated-napari-hub-preview-bot
Copy link

deprecated-napari-hub-preview-bot bot commented Jun 1, 2022

Preview page for your plugin is ready here:
https://preview.napari-hub.org/mehta-lab/recOrder/117
Updated: 2022-06-21T21:36:20.057965

@talonchandler
Copy link
Collaborator

Thanks @ieivanov! I think these are big improvements in clarity, and I really like the tightened getattr writers.

I have two questions:

1 - Since these files are the only record of the calibration, is rounding the right move here? You're keeping five digits of retardance and three digits of swing. My intuition says that that should be more than enough, but I don't have enough experience with the reconstructions to be sure without testing. Is there any chance that the fifth digit matters when you're on the steepest part of the voltage-retardance curve?

I know you're prioritizing readability here---maybe we should save all digits to file then round only during saving and loading?

2 - Can you update/remind me what you expect the advantages of voltage-space calibration will be? IIRC you're hoping to perform the optimization in voltage space (seems like a clear advantage to me) and avoid the interpolation errors by changing to a closed-form voltage-retardance mapping (again, seems like a clear advantage).

Do these changes necessitate saving in voltage space, though? Could we get away with saving in retardance space for simplicity+backwards compatibility reasons?

@ieivanov
Copy link
Contributor Author

ieivanov commented Jun 1, 2022

Thanks @talonchandler, these are good points

  • At the steepest point of the retardance vs voltage curve the slope is about -0.3 nm/mV, which roughly correspond to -5 x 10-4 waves / mV. I think the LC controllers would have accuracy on the order of 0.1 mV, so at best we can control the retardance in waves to 6 sig figs. I'll bump the rounding from 5 to 6 digits, 17 is a bit of an overkill here. The much better thing to do is to keep accurate record of the applied voltage.

  • Voltage-space calibration and saving the voltage applied to each LC are a bit unrelated. Here I'm creating space in the metadata file for a record of the voltage that is applied to each LC (to be filled in later since I have more convenient functions in the new branch), independent of the calibration method. That is the value that we actually know and can control, the LC retardance is a guess/interpolation that relies on the calibration curve. Makes sense?

@talonchandler
Copy link
Collaborator

Great! Thanks for the specs on the number of digits we can control...makes complete sense.

Thanks for the clarification on saving voltage. If I understand correctly, you're planning to always save the calibration result in both retardance and voltage space? Are you planning to save the voltage-retardance mapping as well (in the form the closed-form fit parameters you mentioned)?

These questions are low priority and not that relevant to this PR. Approving now...

metadata['Calibration'].update({
'Channel names': [f"State{i}" for i in range(5)],
'LC retardance': {f'LC{i}_{j}': np.around(getattr(self, f'lc{i.lower()}_{j}'), decimals=5)
for j in ['ext', '0', '45', '90', '135']
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor note: changing 'Ext' to 'ext' here will likely need to be updated in the calibration file reader as well. I'll add a commit shortly.

@ieivanov
Copy link
Contributor Author

@talonchandler I'm finished working on this PR and I think it's ready to be merged, but it's still failing some of the checks. Can you please help me troubleshoot it? I just ran it again, but I'm expecting it to fail.

@ieivanov
Copy link
Contributor Author

Since these files are the only record of the calibration, is rounding the right move here

I increased the retardance rounding to 6 decimal places. LC voltage will be rounded to 4 decimal places (0.1 mV) in upcoming PR.

If I understand correctly, you're planning to always save the calibration result in both retardance and voltage space?

Correct, we'll save both LC retardance and voltage, independent of the calibration method

Are you planning to save the voltage-retardance mapping as well (in the form the closed-form fit parameters you mentioned)?

I think it will be useful to have some record of how retardance was converted into voltage, I'll add that in the next PR.

Can reinstate when `numcodecs` releases 3.10 to PyPI.

Related issue: zarr-developers/numcodecs#308
@talonchandler
Copy link
Collaborator

Checks are passing now (dropped 3.10 checks for now...will reinstate when numcodecs pushes 3.10 to PyPI zarr-developers/numcodecs#308).

I fixed one typo, and checked that everything opens and is visible from my local machine. I haven't done any tests w/ hardware, but I think this is a WIP that doesn't affect anything beyond the calibration.

Ready to merge from my perspective!

@ieivanov
Copy link
Contributor Author

Thanks for looking into this! Merging...

@ieivanov ieivanov merged commit cc9caf5 into main Jun 23, 2022
@ieivanov ieivanov deleted the metadata_update branch June 23, 2022 01:20
@talonchandler talonchandler restored the metadata_update branch June 23, 2022 18:38
@talonchandler talonchandler deleted the metadata_update branch June 23, 2022 18:38
@ieivanov ieivanov restored the metadata_update branch June 30, 2022 00:56
talonchandler added a commit that referenced this pull request Mar 6, 2025
* New Stokes and Mueller module (#110)

* Initial fwd and inv w/ tests

* Add A-matrix and mueller-from-projection functions

* Debug AR_mueller

* Add convenience functions

* Make 4d transposes nd with moveaxis

* Add documentation

* Improve module docstring

* Change `KeyError` to `ValueError`

* Improved docs

* Remove unnecessary test

* Removed "float" from docs

* Revert "Removed "float" from docs"

This reverts commit d9dd7e3ac966a51359a0b331a14570657cdf2212.

* Use `assert_almost_equal`

* fixed couple of  typos

* `A` -> `I2S` & new `S2I`

* comprehensive renaming

* copy `s0` <-> `tra`

* `np.array(s0)` so that it always has `.copy()`

* Set default to "inverse"

---------

Co-authored-by: Shalin Mehta <[email protected]>

* PR docs (#111)

* Add .git-blame-ignore-revs (#109)

* Add #110 pr doc

* Phase 2D + 3D refactor (#117)

* black formatting

* move 2D-to-3D phase recon to phase.py

* convert gen_HZ_stack to ZYX

* keep existing gpu handling

* add 3D_to_3D phase OTF

* improve naming consistency in phase_2D_to_3D_OTF

* Add kwargs to recon params

* change axes for 2D recon preparation

* simplify 2D_to_3D recon with kwargs

* handle padding and simplify OTFs

* add 3D_to_3D recon with kwargs

* temporarily remove docs for rewriting

* first dependence on torch

* move gen_Hz_stack to torch

* convert 2d wotf to torch

* move gen_Greens_function_z to torch

* move important utils to torch

* phase3Dto3D complete overhaul

* refactor

* optics.py to torch

* high-level tests

* splitt phase.py into models

* clean up 3D script

* cleaning and notes

* phase2Dto3D placeholders

* clean tests

* use napari in tests

* better skipping

* reduce dependencies

* update tests

* maintiain PTI simulation's compatibility revised optics functions

* drop pdb

* Preserve birefringence recon

* fix transpose bug

* transpose bug

* phase2Dto3D.py example

* support padding

* empty model for planaraniso

* improved names

* broad renaming of phase2D_3D and phase3D_3D

* updated 2D phase and absorption recon

Return the 2D absorption along with phase. Viewing OTFs in napari is very nice. I changed the axis order to be able to compare phase and absorption OTFs at focal plane.

* display OTFs with Z-axis as a slider

* changes to 2D phase/absorption simulation

I suggest changing this example to be simulation and reconstruction of 2D specimens, thinner than the depth of field of the microscope.

* rename models to <object-type>_<object-thickness>_<data_shape>

* fix isotropic_thin_3d example, include absorption

* 2D -> 2d, 3D -> 3d

---------

Co-authored-by: Shalin Mehta <[email protected]>

* Prepare polarization algorithms for integration with `recOrder` (#118)

* black formatting

* move 2D-to-3D phase recon to phase.py

* convert gen_HZ_stack to ZYX

* keep existing gpu handling

* add 3D_to_3D phase OTF

* improve naming consistency in phase_2D_to_3D_OTF

* Add kwargs to recon params

* change axes for 2D recon preparation

* simplify 2D_to_3D recon with kwargs

* handle padding and simplify OTFs

* add 3D_to_3D recon with kwargs

* temporarily remove docs for rewriting

* first dependence on torch

* move gen_Hz_stack to torch

* convert 2d wotf to torch

* move gen_Greens_function_z to torch

* move important utils to torch

* phase3Dto3D complete overhaul

* refactor

* optics.py to torch

* high-level tests

* splitt phase.py into models

* clean up 3D script

* cleaning and notes

* phase2Dto3D placeholders

* clean tests

* use napari in tests

* better skipping

* reduce dependencies

* update tests

* maintiain PTI simulation's compatibility revised optics functions

* drop pdb

* Preserve birefringence recon

* fix transpose bug

* transpose bug

* phase2Dto3D.py example

* support padding

* empty model for planaraniso

* improved names

* broad renaming of phase2D_3D and phase3D_3D

* Rename variables in `stokes.py`.

* updated 2D phase and absorption recon

Return the 2D absorption along with phase. Viewing OTFs in napari is very nice. I changed the axis order to be able to compare phase and absorption OTFs at focal plane.

* display OTFs with Z-axis as a slider

* changes to 2D phase/absorption simulation

I suggest changing this example to be simulation and reconstruction of 2D specimens, thinner than the depth of field of the microscope.

* convert stokes to torch

* initial draft of planaraniso model

* rename models to <object-type>_<object-thickness>_<data_shape>

* fix isotropic_thin_3d example, include absorption

* 2D -> 2d, 3D -> 3d

* calculate background corrections with transfer function

* rearrange examples folder

* rearrange examples folder

* rearrange `isotropic` and `phase` examples

* add `inplane_anisotropic` model and example

* fix inplane tests

* fix maintenance scripts

* remove deprecated

* use `np.meshgrid` for consistency

* minor bug

* integration changes

---------

Co-authored-by: Shalin Mehta <[email protected]>

* Remove kwargs from reconstructions (#119)

* remove kwargs

* fix estimated background bug

* `illumination_wavelength` -> `wavelength_illumination` (#123)

* Remove duplicate test (#125)

remove duplicate test

* Add option for axial flip of `phase_thick_3d` transfer function (#124)

* `illumination_wavelength` -> `wavelength_illumination`

* add option for axial flip of transfer function

* test axial flip

---------

Co-authored-by: Ziwen Liu <[email protected]>

* Rename model from `anisotropic_thin` to `oriented_thick` (#127)

`anisotropic_thin` -> `oriented_thick`

* `isotropic_fluorescent_thick_3d` model (#128)

* typo

* model outline

* prototype transfer function

* 3d phantom + visualize transfer function

* refactor apply_transfer_function

* typo

* refactor padding (with gpt docs + tests)

* complete example

* test apply_inverse_transfer_function

* TV reconstructions raise NotImplementedError

* `pad_zyx` -> `pad_zyx_along_z`

* Simplify `data += 10`

* Update tests/test_util.py

Co-authored-by: Ziwen Liu <[email protected]>

---------

Co-authored-by: Ziwen Liu <[email protected]>

* Match parameters to simplify `recOrder`-`waveorder` interface (#131)

* add axial_flip to `isotropic_thin_3d`

* `illumination` -> `emission` for fluorescence

* simplify parameters for usage with recOrder

* fix test

* pin torch>=2.0.0

* `z_position_list` should accept a list

---------

Co-authored-by: Shalin Mehta <[email protected]>
Co-authored-by: Ziwen Liu <[email protected]>
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.

2 participants