Skip to content

compresses raw forcing netcdf files, cuts file size in about half - #132

Closed
quinnylee wants to merge 14 commits into
CIROH-UA:mainfrom
quinnylee:compression-tests
Closed

compresses raw forcing netcdf files, cuts file size in about half#132
quinnylee wants to merge 14 commits into
CIROH-UA:mainfrom
quinnylee:compression-tests

Conversation

@quinnylee

Copy link
Copy Markdown
Contributor

see issue #107 and discussion there for more details

Compression level was set to 1 because according to tests, higher compression levels provided negligible benefits to file size

@JoshCu

JoshCu commented Jun 30, 2025

Copy link
Copy Markdown
Member

What do you think about only enabling this if the files are larger than say 5 or 10gb? This new Nan interpolation step goes from taking 2s on a 217mb file to taking ~30s once it's compressed to 51mb.

For smaller files I'd rather things be faster but for larger datasets things the compression is far more valuable. The nan interpolation step rewrites the netcdf without overwriting it so it needs 2x the files size available to work.

@quinnylee

Copy link
Copy Markdown
Contributor Author

Interesting, I hadn't noticed such a dramatic difference in performance. Maybe I got lucky and only tested compression on time periods and catchments where there were no nans...

I'll write something to enable compression if files are larger than 5 gb.

@JoshCu

JoshCu commented Jul 1, 2025

Copy link
Copy Markdown
Member

the machine I'm testing on is unusual, lots of very slow cores, so if something is serial it takes an eternity for me. Which is exactly what was happening. The problem was with the interpolation step, it opens the database after its been downloaded with no dask chunking so all the operations were running serially. I'm updating that which should alleviate this issue

quinnylee and others added 12 commits July 2, 2025 14:35
* delayed hf download until subset step

* asks about output directory only when data being preprocessed, i.e. not when --help is run
* displays warning prompt when user attempts to overwrite an existing subset gpkg

* map app prompts before potential overwrite

* clean up old code

* speed up upstream cat fetching

---------

Co-authored-by: Josh Cunningham <jcunningham8@ua.edu>
* lumped in graph pickle file download with hf download

* Update modules/data_sources/source_validation.py

---------

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>
* Update documentation

Added funding notice
Reorganized/cleaned up sections
Updated installation and run information to reflect our strong organizational preference for running via uvx
Acknowledged and explained the default realization (this would benefit from a once-over from someone with a stronger hydrology background)

* Add CIROH logo for funding notice

* Suggestion: "output" -> "download"

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* Batch-apply suggestions

Additional fixes to follow.

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* Suggestion follow-ups

---------

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>
* estimates t-route ram usage and makes parquet files accordingly

* removed print statements

* Update modules/data_sources/ngen-routing-template.yaml

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* Update modules/data_processing/create_realization.py

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* Update modules/data_processing/create_realization.py

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* Update modules/data_processing/create_realization.py

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>

* fixed nts max_loop_size mixup

* fix template parsing error

* change max loop size to custom value based on machine

---------

Co-authored-by: Josh Cunningham <josh.cu@gmail.com>
* update lstm config to new version

* renamed em to lstm

* Enable full lstm ensemble

* fix ngiab run cpu count
@JoshCu

JoshCu commented Sep 4, 2025

Copy link
Copy Markdown
Member

I've messed with this a bunch more and even without interpolation I don't think we can compress the data to netcdf without slowing things down way too much. With the aorc data the save time for each chunk goes from 3ms to 300-400ms and the download speed drops to ~13mbs from ~500.

I've been trying out saving to zarr and that does seem to work and is actually faster than uncompressed netcdf saving too (the download part, I haven't tested out the forcing processing yet)

modifying the client calls in dask_utils.py to this speeds things up client = Client(threads_per_worker=1)

after the download things still break, but this is what I've got so far

def save_dataset(
    ds_to_save: xr.Dataset,
    target_path: Path,
    engine: Literal["netcdf4", "scipy", "h5netcdf"] = "h5netcdf",
):
    """
    Helper function to compute and save an xarray.Dataset (specifically, the raw
    forcing data) to a NetCDF file.
    Uses a temporary file and rename for atomicity.
    """
    x_len = ds_to_save.sizes["x"]
    y_len = ds_to_save.sizes["y"]
    time_len = ds_to_save.sizes["time"]

    encoding = {}
    compressor = Blosc(cname="zstd", clevel=3, shuffle=2)
    for var in list(ds_to_save.keys()):
        encoding[var] = {
            "compressor": compressor,  # higher compression levels provide negligible benefits to file size
        }
    for name, var in ds_to_save.data_vars.items():
        chunks = {"time": 144, "x": x_len, "y": y_len}
        ds_to_save[name] = var.chunk(chunks)

    if not target_path.parent.exists():
        target_path.parent.mkdir(parents=True, exist_ok=True)

    temp_file_path = target_path.with_name(target_path.name + ".saving.nc")
    if temp_file_path.exists():
        try:
            temp_file_path.unlink()
        except IsADirectoryError:
            shutil.rmtree(temp_file_path)

    client = Client.current()
    future: Future = client.compute(
        ds_to_save.to_zarr(
            store=temp_file_path,
            mode="w",
            compute=False,
            write_empty_chunks=False,
            encoding=encoding,
        )
    )  # type: ignore
    logger.debug(
        f"NetCDF write task submitted to Dask. Waiting for completion to {temp_file_path}..."
    )
    logger.info("For more detailed progress, see the Dask dashboard http://localhost:8787/status")
    progress(future)
    future.result()
    os.rename(str(temp_file_path), str(target_path))
    logger.info(f"Successfully saved data to: {target_path}")

@JoshCu

JoshCu commented Nov 11, 2025

Copy link
Copy Markdown
Member

I think I'm going to close this because proceeding with zarr seems to improve compression as well as the performance #173

@JoshCu JoshCu closed this Nov 11, 2025
@quinnylee
quinnylee deleted the compression-tests branch February 24, 2026 16:49
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.

3 participants