heatwave3 1.2.0 (2026-06-04)
Breaking changes
-
name-stem output replaces explicit output paths.ts2clm3(),detect_event3(), anddetect3()now take a singlenameargument (a path stem) and derive their output filenames from it:-
ts2clm3()writespaste0(name, "_clim.nc"). -
detect_event3()writespaste0(name, "_events.nc"). - the per-day products use
"_events_daily.nc"and"_protoevents.nc". The oldfile_out/file_out_clim/file_out_eventarguments are removed.detect_event3()’sclim_filenow defaults topaste0(name, "_clim.nc").
-
-
return_dfandsave_fileare removed. The compute functions always write their native NetCDF and (invisibly) return the path(s) written. To read a product into R or export it to CSV/RDS/Parquet, usehw3_export()(below).
New features
-
Per-day output, controlled by paths/flags rather than extra return modes.
-
detect_event3(daily = "also")writes a per-day companion NetCDF beside the event table;daily = "only"writes just the per-day file (no event table);daily = "none"(default) writes only the event table. The per-day product holdstemp,seas,thresh,intensity(temp - seas),event,event_no, and the daily Hobday (2018)category(0 = none, 1 = I Moderate … 4 = IV Extreme). -
protoEvent = TRUEwrites the per-day proto-event series (paste0(name, "_protoevents.nc")) instead of the event table, mirroringheatwaveR::detect_event(protoEvents = TRUE):temp,seas,thresh,threshCriterion,durationCriterion,event,event_no. Both are gridded[lon, lat, time]files with adays since 1970-01-01time axis. Verified againstheatwaveR::detect_event(protoEvents = TRUE): identical event counts and proto flags pixel-by-pixel.
-
-
hw3_export()is now a read/export hub for every product. It auto-detects the product (climatology, events, daily, proto-events) via the C++ reader and either returns a longdata.frame(whole, or the firstnrows for a quick look) or writes a flat companion file (.csv/.rds/.parquet). It replaces the oldreturn_df/save_filepathways. -
category_daily3()builds the per-pixel daily marine-heatwave (or cold-spell) category series for a date window straight from an SST file, a climatology, and an events file, entirely via the C++ readers. It reads only the requested SST time-window (a hyperslab) and re-runs no detection: event membership is read from the events file, so events that began before the window are still recognised (re-detecting on a short window would silently drop them). It returns the full daily grid with the same columns as thedetect_event3(daily = "also")product (lon, lat, t, temp, seas, thresh, intensity, event, event_no, category), withcategoryset on event-member exceedance days andNAelsewhere. This is a NetCDF-native replacement for the Marine Heatwave Tracker’s tidync-basedload_sub_cat_clim()(about 240x faster per longitude in testing), with anice_threshargument for the cold-spell sea-ice category; the Tracker’s event-day subset issubset(x, !is.na(category)).sst_filemay be a single multi-time file or a directory / vector of daily files (one time step each, e.g. daily-global OSTIA/GHRSST).
Bug fixes
-
In-process multithreading no longer depends on OpenMP/
libomp. The parallel loops (climatology and event detection) now use C++std::thread. On macOS, adlopen-edlibompcould fail to allocate its per-worker thread-local storage in a process carrying a large native footprint – terra / raster / sf with their GDAL stack, conda toolchains, or the Positron/arkkernel that embeds R – and segfault in__kmp_suspendthe moment a multithreaded run started.std::threaduses pthreads and has no such dependency, son_threads > 1is now reliable in any session and front-end. Results are unchanged (verified pixel-by-pixel). The package no longer detects or links an OpenMP runtime;configurereportsParallelism: C++ std::thread. -
Noon-stamped daily products are no longer dated a day forward. CF time parsing rounded each timestamp to the nearest day, so daily files stamped at 12:00:00 (OSTIA, GHRSST, MUR, and similar) were assigned to the next calendar day. Times are now mapped to the calendar day that contains them (floor), matching
heatwaveR’sas.Date()truncation. Midnight-stamped data (for example OISST) is unaffected. Climatologies, events, and daily categories derived from noon-stamped inputs should be regenerated. -
Streaming subset extraction in
hw3_export().vars,lon_range,lat_range,time_range, andnselect a subset that is read straight from the NetCDF as a hyperslab: for the gridded products only the requested lon/lat/time window and the chosen variables are pulled from disk, so memory and I/O scale with the subset rather than the file.time_rangetakes dates for daily/proto-event products (and overlap-filters the events table);lon_range/lat_rangefilter the events table by per-event coordinate.
Internal
-
hw3_read_subset()(C++) performs the hyperslab read behindhw3_export()’s subset path. -
Post-computation console summary.
ts2clm3()anddetect_event3()print the head, tail, and summary statistics of each product written, with a pointer tohw3_export(). Suppress withquiet = TRUE. -
hw3_read_daily_nc()andhw3_file_meta()read a per-day NetCDF and a product’s lightweight metadata (type, dimensions, row count) respectively.
heatwave3 1.1.4 (2026-06-03)
Documentation
- Rebuilt pkgdown site The public facing documentation website for heatwave3 was re-compiled. The new vignettes have been added, as well as links to other resources and a light/dark theme switch.
Bug fixes
-
The package now builds on Linux with libstdc++. The
#include <pthread.h>insrc/hw3_omp.hsat insidenamespace hw3, so pthread’s symbols (pthread_create,pthread_join, and the rest) were declared ashw3::pthread_*rather than at global scope. Whenhw3_omp.hwas the first translation unit to pull in<pthread.h>(for instance viaclimatology.cppahead of Rcpp), libstdc++’s threading shim<gthr-default.h>could not resolve::pthread_createand the build failed on Linux/g++. macOS/libc++ masked the fault by including<pthread.h>globally and early. The guarded#includenow sits at global scope; the fork-handler functions remain inside the namespace.
Internal
CI action versions updated.
actions/upload-artifact@v3is fully retired and hard-failed thetest-coveragejob;actions/checkout@v3was on the same deprecation path. Both are now pinned to@v4across theR-CMD-checkandtest-coverageworkflows. Ther-lib/actions@v2pins are unchanged, sincev2is the current maintained major.Generated
src/Makevarsis now git-ignored. Theconfigurescript writessrc/Makevarswith machine-specific absolute paths at build time; only thesrc/Makevars.inandsrc/Makevars.wintemplates are tracked.
heatwave3 1.1.3 (2026-06-02)
New features
ts2clm3(return_df = TRUE)now returns the computed climatology as a long data frame withlon,lat,doy,seas, andthresh, while still writing the primary NetCDF output.Companion exports now use
save_fileonly.ts2clm3()anddetect_event3()now infer the requested companion export format from the extension ofsave_file. Supported extensions are.csv,.rds, and.parquet. Ifsave_file = NULL, no companion file is written.detect_event3()now implements griddedthreshClim2. Users may supply a secondary logical criterion as a NetCDF file, vector of files, or directory of daily files. Non-zero, non-missing values are treated asTRUE, and the secondary pass usesminDuration2andmaxGap2with the same event logic asheatwaveR::detect_event().CSV and Parquet companion exports are chunked.
hw3_export()now streams CSV rows and writes Parquet row groups using a configurablechunk_size, reducing peak memory pressure for large gridded outputs.
Bug fixes
OpenMP now works on macOS. Multithreading had been silently disabled (the package ran single-threaded regardless of
n_threads) by three faults in theconfigureOpenMP probe: the run-test checked the input vector instead of the.C()return value and so always “failed”; an undefinedSHLIB_CXX17FLAGSspliced anERROR:string into the compile flags; and the probe did not match the package’s own scheduling. The parallel loops now useschedule(static, 1)rather thanschedule(dynamic)(same round-robin load balance, but needing only symbols present in every libomp;schedule(dynamic)requires__kmpc_dispatch_deinit, which R’s bundled libomp lacks, and that causeddlopenfailures such assymbol not found ... ___kmpc_dispatch_deinit). On macOS the build now links R’s own libomp, so the whole R process shares a single OpenMP runtime instead of dragging in a second, conflicting copy. A new vignette, Parallel performance, documents OpenMP versus R-side (parallel) scaling and per-platform setup.detect_event3(return_df = TRUE)now matches saved event CSV output. The returned data frame now includes the full event-variable set written to the event NetCDF and companion CSV, includingpixel_index, threshold-relative intensity metrics, and absolute intensity metrics. Category and season labels are returned as character values so that CSV reads andreturn_dfoutput compare cleanly.detect3()now passes through the current base-function options. Companion output paths can be supplied separately for climatology and event outputs, anddetrendis passed through tots2clm3().detect3()now passes through secondary event-detection options.threshClim2,threshClim2_var_name,minDuration2, andmaxGap2are passed through todetect_event3().NetCDF time calendars and temperature units are handled more defensibly. Non-Gregorian CF calendars now fail with an explicit error instead of being silently interpreted as Gregorian, and climatology/event NetCDF outputs now preserve the input temperature units instead of hard-coding
degC.Multi-file input handling is fail-fast by default. Unreadable files and mismatched grids now stop multi-file reads unless
skip_bad_files = TRUEis supplied explicitly.Event categories now use the unrounded peak intensity internally. Category labels and progress values are still written with the requested rounding, but category boundaries are no longer affected by rounded
intensity_maxvalues.category3()is now documented and validated as a convenience wrapper. Inline categories fromdetect_event3(category = TRUE)can be read without a climatology file; uncategorised event files now requireclim_filewith a clear error.detect_blob3()now validates fragile arguments. Unsupported connectivity, invalid return components, invalid ranking variables, singleton grids, and grid mismatches now fail with explicit errors.
heatwave3 1.1.2 (2026-06-02)
Bug fixes
-
detect_event3()no longer glues events across calendar gaps in the input SST stack. When the input had missing days (e.g. unavailable OSTIA files), the run-length-encoding indetect_pixel_events()walked array indices rather than calendar dates. An event that had above-threshold days on both sides of a missing-data window was joined into one event whose reporteddate_end − date_start + 1was larger thanduration(calendar-span > index-count). The fix expands the per-pixel series to a dense daily array up front (mirroring whatts2clm3()has always done incompute_pixel_clim), filling missing dates withNA.proto_event()then breaks runs at the gap exactly asheatwaveR::detect_event()does viamake_whole(). Verified by pixel-by-pixel agreement with heatwaveR (1705 / 1705 events on a Cape Town OSTIA region match exactly: same count, same date_start / peak / end, same duration, intensities to rounding precision) and by a synthetic 30-day-gap reproducer.Internal API change:
EventResultgains three integer fields (jd_start,jd_peak,jd_end) holding the absolute Julian Day of the start, peak, and end of each event.index_*fields are now indices into the dense (gap-filled) array rather than the sparse input. Downstream code that useshw3_read_event_nc()/category3()/block_average3()is unaffected: the NetCDF event-file layout and the R-facing return values are unchanged.
heatwave3 1.1.1 (2026-05-28)
Bug fixes
ts2clm3()now validates that the parent directory offile_outexists before running the climatology computation. Previously, an invalid path (e.g. a typo such asdev/test/clim.ncwhen onlydev/tests/exists) caused libnetcdf to fail at the write step with a misleadingPermission denied, after the full per-pixel climatology had already been computed. The new check fires immediately with a clearOutput directory does not exist: ...message.hw3_export()now correctly handles climatology files whose grid has a singleton longitude or latitude dimension. Previouslyncdf4::ncvar_get()dropped the singleton dimension by default, causingseas[, j, i]to fail with incorrect number of dimensions. The variable is now read withcollapse_degen = FALSE.hw3_export()now writes Hobday et al. (2018) category and season values as human-readable labels ("I Moderate","II Strong", …,"Summer","Fall", …) when exporting an event file, matching the labels returned bycategory3(). Previously the raw integer codes (1–4) were written, making the exported CSV / RDA / Parquet hard to use directly.
heatwave3 1.1.0 (2026-05-27)
OpenMP thread management overhaul
Adopts data.table-style OpenMP patterns for safer, more portable parallelism.
New features
getHW3threads()/setHW3threads()— package-level thread management. Defaults to 50% of available cores (polite). Overridable via theR_HEATWAVE3_NUM_THREADSenvironment variable. The per-functionn_threadsparameter still takes precedence when set.Auto-detect OpenMP on macOS — the
configurescript now performs a compile-link-run test (following data.table’s approach) that probes five OpenMP variants in order: user flags,-fopenmp, Apple Clang-Xclang -fopenmp -lomp, Homebrew libomp (ARM64 and Intel). Each test compiles a small program withschedule(dynamic)and runs a parallel reduction in R, catching runtime symbol conflicts that compile-only tests miss. Falls back to single-threaded gracefully.Fork safety — a
pthread_atforkhandler (registered at package load via.onLoad) drops to 1 thread before fork and restores afterward, preventing deadlocks when heatwave3 is used insideparallel::mclapply().
Internal improvements
Never calls
omp_set_num_threads()— all parallel regions now use#pragma omp parallel for num_threads(nt)with a private thread count, eliminating the global side effect that changed thread counts for other OpenMP-using packages in the R session.src/hw3_omp.hcompatibility header — provides stub macros (omp_get_thread_num(),omp_get_max_threads(), etc.) when_OPENMPis not defined, eliminating#ifdef _OPENMPguards from source files.Thread throttling — at least 100 iterations per thread to avoid OpenMP overhead on small grids.
heatwave3 1.0.0 (2026-05-27)
Major: C++ reimplementation
This release is a ground-up rewrite of heatwave3. All core algorithms (climatology, event detection, categorisation, block averages) are now implemented in C++17 with OpenMP parallelism and direct libnetcdf I/O. The previous R/heatwaveR-based implementation is fully replaced.
New features
Inline category computation —
detect_event3(category = TRUE)computes Hobday et al. (2018) severity categories (I Moderate through IV Extreme) during event detection, writing them directly to the event NetCDF. This eliminates the separatecategory3()call and the second read of the climatology file.Cold-spell categories — category computation now uses
|seas - thresh|as the category width, correctly handling both heatwaves (thresh > seas) and cold-spells (thresh < seas). Previously,category3()returned all NAs for cold-spell events.hemisphereparameter — replaces the crypticS = TRUEboolean withhemisphere = "south"(or"north"). Used for season naming in category output. Backward-compatible: theSparameter is still accepted incategory3().return_dfparameter —detect_event3(return_df = TRUE)returns the event table as a tidydata.framedirectly, avoiding the write-then-read round-trip for interactive use.Progress reporting — climatology and event detection now emit progress updates (percentage complete) from the C++ OpenMP loops, visible in the R console during long-running jobs.
hw3_read_metric_summary()— new C++ function that reads a single metric from the event NetCDF and aggregates per pixel in C++, for efficient spatial plotting without reading the full event table into R.detect3()as primary entry point — now acceptscategory,hemisphere, andreturn_dfparameters, making it the single function needed for a complete analysis pipeline.
Eliminated ncdf4 dependency
- All four R functions that previously used the ncdf4 package (
category3,block_average3,plot_metric3,event_line3) now use the package’s own C++ NetCDF reader. This eliminates a class of segfaults caused by symbol collisions when ncdf4 and heatwave3 both linked against libnetcdf in the same R session.
Performance
-
category3()andblock_average3()are now pure C++. On a 5.6M-event Benguela dataset,category3()completes in ~3 seconds (previously ~15 minutes in R with ncdf4). -
plot_metric3()aggregation is now C++-backed viahw3_read_metric_summary().
Other improvements
- Event NetCDF files now contain
category,p_moderate–p_extreme,season, andhemispherevariables when produced withcategory = TRUE. -
read_event_netcdf()gracefully handles older event files that lack category fields. - Cleaned up ggplot2 code in
event_line3()andplot_metric3(): properexpression()axis labels, composable plot objects, no hard-coded colours.
Breaking changes
-
category3(S = TRUE)is deprecated in favour ofcategory3(hemisphere = "south"). TheSparameter is still accepted but will be removed in a future release. - Event NetCDF files produced with
category = TRUEcontain additional variables. This does not break reading by older code, which simply ignores unknown variables.
heatwave3 0.0.4 (2024-06-13)
-
detect3()catches NA pixels before calculating climatologies
heatwave3 0.0.3 (2024-01-22)
-
detect3()now converts hourly data to daily before running detection code - It also checks for pixels with missing data and handles them accordingly
heatwave3 0.0.2 (2023-12-05)
- Pushing codecov up towards 100%
- Changed
heatwaveRdependence to development version
heatwave3 0.0.1 (2023-08-27)
- Package now checks and builds correctly
- Added example dataset as CSV for now
heatwave3 0.0.0.9006 (2023-08-20)
- Added if gates at the start of
detect3()to catch common errors
heatwave3 0.0.0.9004 (2023-07-30)
-
detect3()now returns the full event metric output.
