epwshiftr’s recommended workflow is now Create Future EPW Files, built around shift_*(), EsgStore, Downloader, and EpwMorpher.

The older data.table-oriented API is available from the legacy branch or epwshiftr v0.1.4. Those functions are no longer exported by the current package. The current package does, however, retain a belcher(profile = "legacy") compatibility profile for reproducing the earlier morphing calculations and eight EPW headers. This article separates numerical compatibility from API and file-layout compatibility while mapping old concepts to store-native concepts.

Concept Map

Legacy step Store-native replacement Why it changed
init_cmip6_index() shift_request() plus shift_datasets() / shift_collect() Search and file metadata are now query snapshots and result objects instead of one monolithic local index.
summary_database() EsgStore file catalog and storage_report() File identity, local paths, checksums, and artifacts live in a durable manifest.
match_coord() shift_site() and EsgStore$plan_region() Site metadata and extraction plans are explicit workflow objects.
extract_data() shift_extract() or EsgStore$extract() Extraction writes partitioned Parquet artifacts and records coverage.
morphing_epw() shift_morph() or EpwMorpher$run() Morphing factors and diagnostics are store-native and resumable.
future_epw() shift_epw() or EpwMorpher$write_epw() EPW outputs are registered with case metadata and artifact provenance.

Old Shape

A simplified legacy script looked like this:

index <- init_cmip6_index(...)
summary <- summary_database(...)
coord <- match_coord(epw, summary)
data <- extract_data(coord, years = 2060)
morphed <- morphing_epw(data, years = 2060)
future_epw(morphed)

That path assumed a local CMIP6 file index and passed large data objects between steps.

New High-Level Shape

The store-native path keeps durable state in the store and passes small stage objects between steps.

site <- shift_site(
    id = "SIN",
    lon = 103.98,
    lat = 1.37,
    label = "Singapore",
    epw = epw
)

request <- shift_request(
    project = "CMIP6",
    time = 2060L,
    filters = list(
        activity_id = "ScenarioMIP",
        source_id = "MPI-ESM1-2-LR",
        experiment_id = "ssp585",
        variant_label = "r1i1p1f1",
        frequency = "mon",
        variable_id = epw_morph_variables("recommended"),
        data_node = "esgf.ceda.ac.uk",
        table_id = "Amon"
    ),
    options = list(index_node = "https://esgf-data.dkrz.de")
)

epws <- request |>
    shift_collect(store = "~/cmip6-singapore-store") |>
    shift_extract(site = site, periods = epw_morph_periods(`2060s` = 2060L)) |>
    shift_morph(baseline = site, strict = TRUE) |>
    shift_epw()

Use shift_status(), shift_diagnostics(), shift_coverage(), shift_outputs(), and shift_data() to inspect stage state.

Reproduce Legacy Numerical Output with the Current API

Use the compatibility profile when a validation study needs the previous 35-column hourly result and header policies but can migrate to durable task and store objects:

run <- shift_future_epw(
    epw = epw,
    climate = shift_cmip6(
        model = "MPI-ESM1-2-LR",
        scenarios = "ssp585",
        member = "r1i1p1f1"
    ),
    periods = list(`2060s` = 2060L),
    method = belcher(
        profile = "legacy",
        reference = historical_reference(1995:2014)
    ),
    dir = "outputs/future-epw"
)

The legacy profile disables cyclic smoothing and snow-depth morphing, uses the historical HURS and radiation paths, and preserves ground temperatures, typical/extreme periods, and design conditions. It does not restore removed function names, legacy object classes, or legacy output-file naming.

New Lower-Level Shape

If your legacy script needed tight control over indexing, downloads, extraction, or morphing, split it into the lower-level engines instead of recreating the old global index.

query <- esg_query("https://esgf-data.dkrz.de")$
    activity_id("ScenarioMIP")$
    experiment_id("ssp585")$
    source_id("MPI-ESM1-2-LR")$
    variant_label("r1i1p1f1")$
    frequency("mon")$
    variable_id(epw_morph_variables("recommended"))$
    data_node("esgf.ceda.ac.uk")$
    params(table_id = "Amon")

datasets <- query$collect(type = "Dataset")
files <- datasets$collect(type = "File", fields = "*")$
    filter_time("2060-01-01", "2060-12-31", method = "drs")

store <- EsgStore$new("~/cmip6-singapore-store")
query_id <- store$add_files(files, label = "singapore-ssp585-2060")

plan <- store$plan_region(
    query_id = query_id,
    lon = 103.98,
    lat = 1.37,
    time = c("2060-01-01T00:00:00Z", "2060-12-31T23:59:59Z"),
    site_id = "SIN",
    variable_id = epw_morph_variables("recommended")
)

store$extract(plan_id = plan$plan_id, fallback = "auto")

morpher <- epw_morpher(store, epw = epw, site_id = "SIN")
morpher$workflow(
    plan_id = plan$plan_id,
    periods = epw_morph_periods(`2060s` = 2060L),
    strict = TRUE,
    dir = "outputs/future-epw"
)

See ESGF query results, ESG stores, and EpwMorpher for the details behind each layer.

Migration Checks

Before replacing a legacy script, make these choices explicit:

  • Use shift_request() filters that match the old scenario, source, variant, frequency, table, and variables.
  • Select belcher(profile = "legacy") when numerical/header compatibility is required; the default enhanced profile intentionally changes those results.
  • In new enhanced high-level workflows, prefer shift_cmip6(table = NULL) so atmospheric variables and optional snd can use their native CMIP tables.
  • Decide whether you need full NetCDF downloads. The new default reads OPeNDAP first; insert shift_download() only when you intentionally want local source files.
  • Use epw_morph_variables("recommended") for strict future EPW generation unless you are intentionally running a relaxed or experimental recipe.
  • Replace file-system scans with store validation and coverage checks.
  • Compare output EPW names and case grouping through shift_outputs() rather than relying on legacy directory conventions.

When to Keep the Legacy Branch

Keep using the legacy branch or epwshiftr v0.1.4 only when a project depends on removed function signatures, exact legacy object classes, old file naming, or a frozen software environment that cannot migrate. Exact Belcher numerical and EPW-header behavior alone no longer requires the old branch; use profile = "legacy" in the current API.

For new work, use the store-native API. It gives better diagnostics, durable metadata, resumable downloads, artifact tracking, and a clearer route from ESGF records to generated EPW files.