Gridding
Daisho.jl implements a beam-aware radar gridding algorithm that accounts for Earth curvature, standard atmospheric refraction, and the radar beam pattern.
Grid Types
Several gridding modes are available:
| Mode | Function | Dimensions | Use Case |
|---|---|---|---|
| Volume | grid_radar_volume | 3D (X, Y, Z) | Full volumetric analysis |
| Lat/Lon Volume | grid_radar_latlon_volume | 3D (lon, lat, Z) | Geographic coordinate grids |
| RHI | grid_radar_rhi | 2D (R, Z) | Range-height cross sections |
| PPI | grid_radar_ppi | 2D (X, Y) | Plan position indicator |
| Composite | grid_radar_composite | 2D (X, Y) | Maximum value composite |
| Column | grid_radar_column | 1D (Z) | Vertical profile above radar |
Basic Usage
All grid geometry, field selection, interpolation, weighting, and CF metadata come from a DaishoParameters loaded from a TOML config (see Configuration files below). The drivers take the Volume, an output path, an index time, and the parameters:
Volume Gridding
p = DaishoParameters("mygrid.toml")
volume = read_cfradial("scan.nc")
Daisho.grid_radar_volume(volume, "output.nc", volume.time_coverage_start, p)PPI Gridding
Daisho.grid_radar_ppi(volume, "output_ppi.nc", volume.time_coverage_start, p)The [grid.*] sub-tables of the config select each product's geometry (grid_radar_volume uses [grid.volume], falling back to [grid.cartesian]; grid_radar_rhi uses [grid.rhi]; and so on).
Gridding Algorithm
The algorithm uses a BallTree spatial index for efficient nearest-neighbor queries:
- Build a BallTree of all radar gate locations in projected coordinates
- For each grid point, find nearby radar gates within the radius of influence
- Compute beam-pattern weights (Gaussian based on angular separation)
- Compute range weights
- Apply weighted interpolation (linear for dBZ, weighted average for velocity, etc.)
Key Parameters
power_threshold: The beam power level that defines the beam edge. The edge-referenced gate inclusion sets the beam half-angle tobeam_cutoff = ln(1/power_threshold) / beam_coef, so a lowerpower_thresholdmakes the beam wider (more of the exponential tail is counted as the beam). At the default0.5this is the half-power half-beamwidth. (The formerbeam_inflationknob is removed — per-range beam reach is now derived from the radar beamwidth and footprint; a leftoverbeam_inflationkey is accepted and ignored.)horizontal_roi_factor/vertical_roi_factor: Multipliers on the horizontal/vertical grid increment setting the grid-cell half-width/half-height for gate inclusion. Optional; default0.75each.range_guard_min/range_weight_max: Numerical guards on the near-radarrange_weightsingularity — a lower clamp (metres) on the slant-range divisor and an upper clamp on the resulting (unitless) weight. Optional; defaults1.0and10.0. These are weighting guards, not gate filters.range_minimum/range_maximum: Slant-range gate-inclusion bounds (metres). A gate is gridded only when its slant rangersatisfiesrange_minimum ≤ r ≤ range_maximum; out-of-range gates are excluded from every product (no coverage, no value), so a cell reachable only by excluded gates is left true-missing. Optional; defaults0.0/Inf(no filtering). Use them to homogenise a volume whose low sweep ranges farther than the others, or to cap a product at a higher-quality range.- Field roles (
define_detection/define_scanned): The gate-role moments are not gridding parameters — they are declared as field tags in[fields]. Tag the detection field (its presence proves a detectable echo; formerlyvalid_key, e.g.DBZ) withdefine_detection, and the scanned-indicator field (its presence proves the gate was scanned; formerlymissing_key, e.g.SQIorPID) withdefine_scanned. They are resolved at gridding time viafield_with_tag.
Configuration files
The high-level DaishoParameters struct bundles QC thresholds, gridding knobs, grid geometry (Cartesian / lat-lon / RHI / spectral), CF-1.12 metadata, and I/O fill values. It is loaded from a TOML file. To start a configuration, write the bundled template to a path you control and edit it for your deployment:
using Daisho
print_config("mygrid.toml") # write the template
# edit mygrid.toml: radar, grid geometry, [grid.metadata] CF attributes …
p = DaishoParameters("mygrid.toml") # strict loadDaishoParameters(path) is strict: every key documented in the template must be present in your file. There is no silent fallback to bundled defaults — a missing or mis-typed key raises an ArgumentError at load time, naming the offending section. This avoids subtle bugs where a forgotten or fat-fingered parameter would silently take a default value.
Coordinate Systems
Daisho uses Transverse Mercator projections (via CoordRefSystems.jl) centered on the radar location. The approximate inverse projection function converts projected coordinates back to lat/lon:
lat, lon = Daisho.appx_inverse_projection(ref_lat, ref_lon, [y_meters, x_meters])Output Format
Gridded data is written as CF-compliant NetCDF files with:
- Coordinate variables (X, Y, Z or lat, lon)
- Grid mapping metadata (Transverse Mercator)
- All gridded moments as 3D or 2D variables
- Time, starttime, stoptime
- Latitude/longitude grids for each horizontal point
Per-sweep gridding and accumulator-based combination
The Volume drivers above build a ScalarGridAccumulator internally, fold every sweep of the volume into it, and finalize once. The accumulator is also exposed as a first-class object so callers can grid one sweep at a time, persist intermediate state to JLD2, and combine sweeps from many files later. (To grid the scalar fields and the dual-Doppler wind in one pass, use build_accumulator — see the wind synthesis guide.) This is the natural workflow for airborne radars where each CfRadial file is one sweep along a flight track, and for multi-Doppler retrieval inputs where sweeps from different radars need to land on a common grid.
The flow uses three verbs:
grid_sweep_to_file— grid one sweep of a volume into a JLD2 accumulator file. Either create a fresh accumulator with agrid_specargument, or merge into an existing rolling file.combine_accumulator_files— merge many per-sweep accumulator files into one, provided they share a grid spec.finalize_accumulator_file— divide by weights, apply linear→dBZ conversion, and write a normalized NetCDF using the appropriatewrite_gridded_radar_*writer.
Example (one CfRadial file per sweep along a flight leg):
p = DaishoParameters("mygrid.toml")
first_volume = read_cfradial(first(p3_files))
grid_spec = build_grid_spec(:volume_3d, first_volume, p)
for file in p3_files
volume = read_cfradial(file)
threshold_qc!(volume.sweeps[1], p)
grid_sweep_to_file(volume, 1, "leg.accum.jld2", p;
grid_spec = grid_spec,
merge_into_existing = true)
end
finalize_accumulator_file("leg.accum.jld2", "leg_gridded.nc", p;
index_time = first_volume.time_coverage_start)Field-folds quantities
Radial velocity (VEL) and other folding quantities (anything where Field.metadata.field_folds == true) cannot be physically meaningfully merged across distinct look directions. The merge step (combine_accumulator_files and merge_accumulators!) refuses to combine field-folds fields across distinct sweeps and points the user at the wind-retrieval workflow, which reads the per-sweep accumulators directly.