Skip to content

feat(data): DrivAerStar EnSight -> chunked Zarr preprocessing#238

Open
HennerM wants to merge 4 commits into
mainfrom
feat/drivaerstar-preprocessing
Open

feat(data): DrivAerStar EnSight -> chunked Zarr preprocessing#238
HennerM wants to merge 4 commits into
mainfrom
feat/drivaerstar-preprocessing

Conversation

@HennerM

@HennerM HennerM commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a preprocessing/conversion script for the DrivAerStar dataset — the DrivAerStar analogue of caeml/preprocessing.py, but writing directly into the chunked/sharded Zarr store (ZarrStoreWriter) introduced in #237 instead of per-field .pt files.

Stacked on feat/zarr-chunked-store (#237): the script imports noether.data.zarr_store and the preprocessing (scipy) extra, both of which live on that branch. Please merge #237 first.

What it does

  • Reads raw EnSight Gold cases (case_<T>/<id>/case/<T>_<id>.case + .geo + per-cell Pressure/Velocity/WallShearStress) from a local path or any fsspec URL (oci://emmi-drivaer-star, …; ocifs needs OCIFS_IAM_TYPE=api_key).
  • Surface/volume split matches Emmi-AI/proprioceptive's match_experiment_probes.py: volume = the domain block; surface = WallShearStress-bearing blocks that are not the domain and not wind-tunnel walls (Block.*), combined + surface-extracted, fields sampled at cell centres.
  • Stores surface_position/pressure/friction/normals and volume_position/pressure/velocity; keeps all volume cells (optional --subsample-factor).
  • Optional volume_sdf (distance-to-surface via scipy cKDTree, the same method caeml uses) behind --sdf, off by default — when disabled the FileMap drops the field so the writer doesn't expect it.
  • Crash isolation: each case is read/extracted in a child process, so a C-level crash in VTK's EnSight reader skips just that case (non-zero exit) instead of aborting the run. Cases convert concurrently (--workers); the manifest is saved at the end.

Why a child process / KD-tree SDF

  • Some DrivAerStar binaries crash vtkEnSightGoldBinaryReader at the C level (uncatchable from Python) — hence per-case subprocess extraction.
  • The exact VTK point-to-mesh distance was ~1092 s/case on ~10M points; scipy cKDTree gives the same nearest-surface distance in ~1.3 s, so the SDF (when enabled) uses the KD-tree.

Usage

OCIFS_IAM_TYPE=api_key uv run python -m noether.data.datasets.cfd.drivaerstar.preprocessing \
    --source oci://emmi-drivaer-star@frwnorq7ern2 \
    --output oci://emmi-drivaer-star@frwnorq7ern2/zarr_store \
    --case-types E --workers 16          # add --sdf to also store volume_sdf

Test plan

  • End-to-end on local case_E samples: 5/5 converted, full + subsampled reads via ZarrChunkReader, all fields finite and point-aligned, surface normals unit length, float16 range OK.
  • Default (no --sdf) run: store correctly omits volume_sdf and the reader returns only the present fields.
  • ruff + mypy clean.
  • OCI streaming smoke test (fsspec download path) — pending.
  • Full-dataset conversion.

HennerM and others added 4 commits June 3, 2026 21:45
…ding

Add a Zarr-v3-based data format and dataloader that subsamples by reading
random pre-shuffled chunks, so training at e.g. 16k of ~1M points only
transfers what it needs (byte-range reads against sharded arrays) instead
of loading full samples from per-field .pt files.

Format (src/noether/data/zarr_store/):
- writer/layout/manifest: one array per field, positions float32 / values
  float16 (per-field dtype overrides with float16 overflow guard),
  per-domain pre-shuffled points (seeded), shared chunk grid, configurable
  shard cap, consolidated metadata, chunk manifest (manifest.json).
- convert: generic CLI for any FileMap dataset; reads from a dataset root
  or any fsspec source (oci://, s3://, ...); ProcessPool-parallel;
  skips broken samples with a warning.
- reader: ZarrChunkReader samples random chunks per epoch; serial single
  oindex read or thread-parallel per-chunk reads to hide object-storage
  latency; field-selective reads.
- benchmark: equivalence and read-amplification validation vs .pt.

Datasets:
- ZarrAeroDataset(+Config): config-driven chunk subsampling
  (num_surface/volume_points), optional geometry_position emission for
  AB-UPT, per-sample read cache shared across getitem_* calls; local or
  fsspec store roots.
- ZarrShapeNetCarDataset and ZarrDrivAerNetDataset (splits/blacklists read
  from the store root via fsspec, category filtering).

Pipeline/integration:
- PointSampling and AnchorPointSampling skip (rename-only) when the
  requested count >= available points, so dataset-side subsampling makes
  them inert without config surgery.
- AeroCFDPipeline: geometry_position_from_dataset flag to consume the
  dataset-provided geometry draw.
- PropertySubsetWrapper now calls pre_getitem/post_getitem like
  Dataset.__getitem__.
- Recipe configs: shapenet/drivaernet zarr dataset configs and AB-UPT
  experiment files (incl. OCI-hosted DrivAerNet store).

Docs in docs/source/noether/efficient_zarr_store.rst; unit tests cover
round-trip, alignment, determinism, parallel reads, fsspec sources,
overflow guard and conversion error handling.
Two additions to the chunked Zarr store, both on top of the existing format.

Statistics:
- noether.data.zarr_store.statistics: stream a store (local or fsspec URL)
  in one pass and accumulate per-field running moments via RunningStats,
  yielding {field}_mean/std/min/max, logscale moments, and global
  raw_pos_min/raw_pos_max position bounds. CLI mirrors
  calculate_statistics.py but reads the store directly (no dataset class);
  --split-file restricts to listed ids (missing ids skipped with a warning),
  thread-parallel sample reads. Adds a public RunningStats.count property.

Optional obstore backend:
- stores.make_store() transparently uses the Rust-backed
  zarr.storage.ObjectStore for s3:// URLs when the optional `obstore`
  package is installed (credentials/region/endpoint from standard AWS_*
  env vars), falling back to FsspecStore otherwise or for non-S3 URLs.
  Benchmarked ~2x faster on the warm per-sample read path against OCI's
  S3-compatible endpoint; ~1.1-2.7x depending on concurrency/workload.
  Added as an opt-in extra: `uv sync --extra obstore`.

Docs and unit tests updated for both.
Add a preprocessing/conversion script for the DrivAerStar dataset, the
DrivAerStar analogue of caeml/preprocessing.py but writing directly into the
chunked/sharded Zarr store (ZarrStoreWriter) instead of per-field .pt files.

- Reads raw EnSight Gold cases (case_<T>/<id>/case/<T>_<id>.case) from a local
  path or any fsspec URL (oci://emmi-drivaer-star, ...).
- Surface/volume split matches Emmi-AI/proprioceptive's match_experiment_probes:
  volume = the `domain` block; surface = WallShearStress-bearing blocks that are
  not the domain and not wind-tunnel walls (Block.*), combined + surface-extracted,
  fields taken at cell centres.
- Stores surface position/pressure/friction/normals and volume
  position/pressure/velocity; keeps all volume cells (subsample optional).
- Optional volume_sdf (distance to surface via scipy cKDTree, the caeml method)
  behind --sdf, OFF by default; the FileMap drops the field when disabled so the
  writer does not expect it.
- Each case is read/extracted in a child process so a C-level crash in VTK's
  EnSight reader skips just that case (non-zero exit) instead of aborting the run;
  cases convert concurrently (--workers) and the manifest is saved at the end.

Validated end-to-end on local case_E samples: full + subsampled reads via
ZarrChunkReader, field alignment, unit-length normals, float16 range OK, and the
default (no-SDF) store correctly omits volume_sdf.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Coverage

Tests Skipped Failures Errors Time
1512 26 💤 0 ❌ 0 🔥 38.988s ⏱️

Base automatically changed from feat/zarr-chunked-store to main June 15, 2026 09:58
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