Feat: Add stitching multiple ome zarr files together#84
Draft
jimmyjam100 wants to merge 39 commits into
Draft
Conversation
jimmyjam100
marked this pull request as draft
April 27, 2026 15:29
added 22 commits
April 27, 2026 11:59
jimmyjam100
marked this pull request as ready for review
April 28, 2026 17:38
jimmyjam100
marked this pull request as draft
April 30, 2026 13:09
added 9 commits
April 30, 2026 09:48
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.
Added the ability for a user to stitch a bunch of ome zarr files together into a larger ome zarr. This PR largerly modifies and generalizes code that was used for spool.py
Also allows for the reading of zarr files from dandi
makes writing to zarr more dask friendly
I swear this PR is not that large its just poetry.lock needed to be rewritten but its auto generated so does not need to be reviewed
NOTES FOR AFTER SITE VISIT:
During the process of getting mode code running in time for the site visit I learned several things and ran into several difficulties. This is a log of all the problems I ran into, how I solved them, and how I would solve them differently if I take up this code again and am not under time crunch. The strict deadline from the site visit caused me to come to not super rational solutions to all of my code as you will soon see.
Most notably is that it seems when a zarr-python object is loaded into memory it stays in memory until the object is removed via garbage collection. This lead me to the solution of having two different objects for shapes and data so that garbage collection can easily delete the object containing data. This is far from an elegant solution, but it worked and did not have the time for constant revisions. If I were to redo this I would probably find a way to just load the data of the objects used to calculate shape, then manually remove all pointers to that object once it was done writing
After testing multiple different methods of skew correction it seems like using a wrapper worked the quickest. Like above this is far from the most elegant solution but I tested several ideas including just using dask_image.ndinterp.map_coordinates and dask_image.ndinterp.affine_transform with no wrapper. This wrapper works by mimicking the functionality of a dask array but also applying deskewing to it on the fly. This includes modifying the shape of the object. I actually like this solution. Having a wrapper that can edit the shape of an object is super convenient for down the line calculations. The major downside is it does take a whole object to do what could be done with a couple lines of code so it is messy.
I also ran into issues getting everything to run within 12 hours and ended up adding parameters to split runs along the x axis and combine them afterwards. This also had the benefit of loading only small parts of chunks into memory at a time when writing to a zarr file which was good because a single chunk would sometimes exceed the 128 GB memory limit for mit_normal. However after coming up with a checkpoint system and using mit_preemptable I think this addition is not needed. mit_preemptable would make it so I could use 512 GB of memory and the checkpoint system would mean I don't have to worry about time constraints. One possible upside of this method is that it allows for stitching multiple different sections in parallel across nodes which might be faster than how dask would do it (Have not tested). In the future I will probably just remove this feature to remove feature clutter especially because I think it does not work well with sharding.
I was also running into issues generating pyramids for very large ome zarrs because of OOM errors. My solution of only generating a pyramid one chunk at a time makes sense but the implementation is sloppy. Especially because in order to get it to work quickly I had to implement it in zarr-python as opposed to the parent zarr class.
In order to run this on the MIT cluster I would run the following scripts.
First I would preprocess stripe correction using
Then I would generate vertical slices using a script that resembles
Then I would copy them all into one ome.zarr using a script like
Then I would expand the pyramid with the following script