Skip to content

Commit 28faf62

Browse files
committed
v2.0.0 documentation cleanup
1 parent ec11a86 commit 28faf62

6 files changed

Lines changed: 29 additions & 71 deletions

File tree

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55

66
# EarthSHAB
77

8-
> ⚠️ **v2.0 forecast schema change.** GFS and ERA5 forecasts now share a single
9-
> canonical netCDF format read by one `Forecast` class. Archived v1 forecasts
10-
> are rejected on load and must be converted once with the `migrate_v1` CLI.
11-
> See the **[v2 migration guide](docs/source/migration-v2.md)** (and the
12-
> [canonical schema](docs/source/forecast-schema-v2.md)) before upgrading.
8+
> ⚠️ **v2.0.0 introduces a new unified NetCDF forecast schema.** Archived v1 forecasts
9+
> can be converted with the `migrate_v1` CLI.
10+
> For more information, see the **[v2 migration guide](docs/source/migration-v2.md)** (and the
11+
> [canonical NetCDF schema](docs/source/forecast-schema-v2.md)).
1312
1413
Solar high altitude balloons (SHAB) are a simple and lightweight option for aerial exploration and meteorological data collection both terrestrially and on other planets. By using a
1514
lightweight material that absorbs visual light and emits low levels of thermal radiation, solar balloons behave similarly to hot air balloons, but are capable of ascending to much higher altitudes. Unlike hot air balloons, which use a heat source to raise the temperature of the internal air, solar balloons generate heat by absorbing solar radiation, providing a free source of lift and eliminating the need for a lighter than air gas or carrying fuel.

docs/source/API/wind_interpolation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Wind Interpolation Methods
33
===========================
44

5-
EarthSHAB's unified :class:`Forecast` reader (which serves both GFS and ERA5
5+
EarthSHAB's unified :class:`Forecast` reader (which serves both GFS and ERA5 netcdf
66
files) exposes three different methods for interpolating wind from the discrete
77
pressure levels of a forecast to the balloon's continuous altitude during
88
simulation. The active method is selected from a single config field:

docs/source/forecast-schema-v2.md

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Canonical Forecast Schema (v2)
1+
# Canonical NetCDF Forecast Schema v2
22

33
EarthSHAB v2.0 standardizes on a single netCDF forecast format: what the
44
**Copernicus Climate Data Store (CDS) API returns post-September 2024** for
@@ -10,11 +10,15 @@ Adopting the CDS post-September-2024 layout as canonical means current ERA5
1010
downloads load with no conversion, and GFS is the only source that needs a
1111
converter (`saveNETCDF.py` for live forecasts, `saveNETCDF_archive.py` for
1212
historical cycles from the AWS GFS archive — both emit identical v2 output).
13+
14+
For converting between older/alternate forecast layouts (e.g. pre-September-2024
15+
ERA5 or other variable/dimension naming), see the
16+
[ERA5-Utils toolkit](https://github.com/tkschuler/ERA5-Utils).
1317
:::
1418

1519
Reference files (the bundled SHAB14-V flight):
1620
`src/EarthSHAB/forecasts/SHAB14V_ERA5_20220822_20220823.nc` (ERA5) and
17-
`src/EarthSHAB/forecasts/gfs_0p25_20220822_12.nc` (GFS, migrated to canonical).
21+
`src/EarthSHAB/forecasts/gfs_0p25_20220822_12.nc` (GFS, migrated from v1 to v2 canonical format).
1822

1923
---
2024

@@ -34,7 +38,7 @@ lacking `Conventions == "CF-1.7"` AND containing the old GFS variables
3438
migration message (see [migration-v2.md](migration-v2.md)).
3539
:::
3640

37-
### Source provenance
41+
### Automatic Netcdf Forecast Sourcing
3842

3943
`Forecast.source` (the field used for plot labels and evaluation grouping) is
4044
resolved from `institution`:
@@ -51,7 +55,7 @@ value. Files migrated before this convention was introduced carry an empty
5155

5256
### Storage convention
5357

54-
**Every v2 file is a tight bounding-box subset.** No full-world arrays with
58+
**Every v2 file is a bounded subset.** No full-world arrays with
5559
mask-based subsetting; the shape of `u/v/z/t` IS the data extent. Missing
5660
samples inside the subset (e.g., at high pressure levels above the model top)
5761
are represented as `_FillValue` / NaN and resolved by the reader's
@@ -93,11 +97,6 @@ Dimension ORDER on data vars: `(valid_time, pressure_level, latitude, longitude)
9397
| dtype | `int64` |
9498
| stored order | strictly ascending |
9599

96-
:::{note}
97-
**No `has_year_zero` quirk.** Using `proleptic_gregorian` with epoch seconds
98-
round-trips cleanly to stdlib `datetime`; no 2-day calendar offset.
99-
:::
100-
101100
### 3.2 `pressure_level` (1D, dim `pressure_level`)
102101

103102
| Attribute | Value |
@@ -139,7 +138,7 @@ Real CDS files publish 37 standard pressure levels: `[1000, 975, 950, 925, 900,
139138
| convention | **`-180` to `180`** (NOT `0` to `360`) |
140139

141140
:::{note}
142-
GFS downloads natively use 0-360; `saveNETCDF.py` must convert to -180..180 before writing.
141+
GFS downloads natively use 0-360; `saveNETCDF.py` must convert to -180-180 before writing.
143142
:::
144143

145144
---
@@ -154,8 +153,6 @@ reader treats them as informational only.
154153
| `number` | scalar (int64) | Ensemble member ID; always `0` for our single-realization use case |
155154
| `expver` | `(valid_time,)` string | ECMWF experiment version (`"0001"` for operational ERA5) |
156155

157-
The reader MUST NOT depend on these being present. The GFS converter is NOT required to emit them.
158-
159156
---
160157

161158
## 5. Data variables
@@ -178,27 +175,18 @@ Four required data variables. All have:
178175
the `/g` conversion when interpolating against an altitude query.
179176
:::
180177

181-
GRIB attribute pass-throughs (`GRIB_paramId`, `GRIB_centre`, …) are TOLERATED but not required. The GFS converter need not emit them.
182-
183178
---
184179

185180
## 6. Index axis summary
186181

187182
For a query at `(t_query, alt_query_m, lat_query, lon_query)` the reader:
188183

189184
1. finds nearest indices: `valid_time` (ascending), `latitude` (descending),
190-
`longitude` (ascending; query in -180..180);
185+
`longitude` (ascending; query in -180-180);
191186
2. builds the altitude column `z[t_idx, :, lat_idx, lon_idx] / g`;
192187
3. interpolates `u`, `v` over altitude (per `wind_interpolation`), then over
193188
`valid_time` between the two enclosing time steps.
194189

195-
:::{note}
196-
Because `pressure_level` is descending hPa, level index 0 is the *lowest*
197-
altitude — the column is already ascending in altitude, so no reversal is
198-
needed. (The legacy `ERA5.py` applied an unnecessary `[::-1]`; that quirk was
199-
removed when the readers collapsed into `Forecast`.)
200-
:::
201-
202190
---
203191

204192
## 7. Differences from v1 ("processed" ERA5 format the legacy ERA5.py expected)
@@ -214,8 +202,6 @@ removed when the readers collapsed into `Forecast`.)
214202
| `t` (temperature) | optional | required |
215203
| CF Conventions attr | absent or older | `CF-1.7` |
216204

217-
The Forecast class auto-detects v1 vs v2 and refuses v1 with a clear migration message (see [migration-v2.md](migration-v2.md)).
218-
219205
---
220206

221207
## 8. Differences from v1 GFS format (saveNETCDF.py output)
@@ -231,30 +217,15 @@ The Forecast class auto-detects v1 vs v2 and refuses v1 with a clear migration m
231217
| Level (`lev`) order | descending hPa | same (`pressure_level` descending hPa) |
232218
| `Conventions` attr | absent | `CF-1.7` |
233219

234-
`saveNETCDF.py` (live) and `saveNETCDF_archive.py` (historical, AWS archive) both do all the conversion at download time; pre-v2 archived files are migrated by the `migrate_v1` CLI.
220+
`saveNETCDF.py` (current) and `saveNETCDF_archive.py` (historical, AWS archive) both do all the conversion at download time; pre-v2 archived files are migrated by the `migrate_v1` CLI.
235221

236222
:::{seealso}
237223
[migration-v2.md](migration-v2.md) — detecting v1 files, the converter, and rollback.
238224
:::
239225

240226
---
241227

242-
## 9. Validation
243-
244-
The canonical Forecast class validates on `__init__` and raises `ForecastFormatError` with a specific message if any of these fail:
245-
246-
1. Required dimensions (`valid_time`, `pressure_level`, `latitude`, `longitude`) all present with `len >= 1`.
247-
2. Required data variables (`u`, `v`, `z`, `t`) all present with `dtype == float32` and correct dim ordering.
248-
3. `pressure_level` strictly descending; `valid_time` strictly ascending; `latitude` strictly descending; `longitude` strictly ascending.
249-
4. `valid_time.units` parseable as a CF time unit; `valid_time.calendar` set.
250-
5. `Conventions == "CF-1.7"` (warn if missing or different value but still attempt to load — interop with future CF revisions).
251-
6. `longitude` values all within `[-180, 180]`.
252-
253-
A separate `migrate_v1` script handles detection of the two v1 formats (by variable-name signature) and produces a canonical file in-place with the original backed up to `<name>.v1.nc`.
254-
255-
---
256-
257-
## 10. Reference
228+
## 9. Reference
258229

259230
The canonical example files are the bundled SHAB14-V v2 forecasts:
260231

@@ -269,7 +240,4 @@ Inspect either directly with:
269240
import netCDF4
270241
ds = netCDF4.Dataset('src/EarthSHAB/forecasts/SHAB14V_ERA5_20220822_20220823.nc')
271242
print(ds)
272-
```
273-
274-
When in doubt about an edge case not covered above, the reference files'
275-
behavior is authoritative.
243+
```

docs/source/migration-v2.md

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Files in the older v1 formats are **rejected on load** with
99
original is preserved as a `.v1.nc` sibling for rollback.
1010
:::
1111

12-
## TL;DR
12+
## Quick Migration of Forcast Directory
1313

1414
```bash
1515
python -m EarthSHAB.forecast_processing.migrate_v1 src/EarthSHAB/forecasts/
@@ -73,14 +73,6 @@ time encoding transparently, and both layouts need the same axis fixes.
7373
All canonical files are written with `Conventions = "CF-1.7"`, float32 data,
7474
and the dimension order `(valid_time, pressure_level, latitude, longitude)`.
7575

76-
## Why no auto-conversion in the reader
77-
78-
:::{note}
79-
Silent on-load conversion would mutate user data without an audit trail, hide
80-
the cost of the change, and make it impossible to reproduce a prior run. The
81-
reader fails loudly with the exact CLI to run; the converter writes a `.v1.nc`
82-
backup so the original is always recoverable.
83-
:::
8476

8577
## CLI reference
8678

src/EarthSHAB/Forecast.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
"""Forecast reader for the v2 canonical schema.
1+
"""Forecast reader for the v2 canonical netcdf forecast schema.
22
3-
Single class for both GFS- and ERA5-sourced files. Source-specific quirks
4-
were eliminated in the v2 refactor; this module replaces both ERA5.py and GFS.py.
3+
Single class for both GFS- and ERA5-sourced netcdf files.
4+
This module replaces both ERA5.py and GFS.py.
55
66
Standard v2 file format::
77
@@ -13,19 +13,18 @@
1313
global: Conventions = 'CF-1.7'
1414
institution = 'NOAA/NCEP (GFS)' or 'ECMWF (ERA5)'
1515
16-
Every file is a tight bounding-box subset — no full-world arrays with
17-
mask-based subsetting. The reader slices the entire stored array.
16+
Every netcdf file is a bounded forecast subset (no full-world arrays with
17+
mask-based subsetting), although full world forecasts can still be downloaded
18+
by applying full world lat/lon bounds.The reader slices the entire stored array.
1819
19-
Source provenance (self.source) is read from the ``institution`` global
20+
Forecast type is read from the ``institution`` global
2021
attribute. When that attribute is missing or empty (the case for older
2122
already-migrated files), the reader falls back to filename pattern::
2223
2324
- basename containing 'gfs' (case-insensitive) -> 'GFS'
2425
- basename containing 'era5' -> 'ERA5'
2526
- otherwise -> 'unknown'
2627
27-
Contributing authors: Craig Motell and Michael Rodriguez of NIWC Pacific
28-
Edited and integrated: Tristan Schuler
2928
"""
3029
import math
3130
import sys

src/EarthSHAB/windmap.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
2-
This is file generates a 3d windrose plot for a particular coordinate and timestamp.
3-
The polar plot displays information on wind speed and direction at
4-
various altitudes in a visual format
2+
This plotting file generates 3d windrose plots (Hodographs) for a particular
3+
coordinate and timestamp. The polar plot displays information on wind speed
4+
and direction at various altitudes in a visual format
55
66
"""
77

0 commit comments

Comments
 (0)