vignettes/articles/esgf-troubleshooting.Rmd
esgf-troubleshooting.RmdThis article collects the checks that are most useful when a future EPW workflow returns empty results, cannot open remote data, downloads slowly, or produces incomplete coverage.
For high-level workflows, inspect the stage first. Stage diagnostics are meant to point to the layer that needs attention.
shift_status(epws)
shift_diagnostics(epws)
shift_ids(epws)Use shift_ids() only for deeper inspection. Ordinary
scripts should rely on the stage helpers first.
An index node answers search requests. A data node hosts files and service URLs. Confusing the two is a common source of empty results.
query <- esg_query("https://esgf-data.dkrz.de")
query$list_fields()
query$list_shards()
query$list_values(c("activity_id", "experiment_id", "table_id"))shards controls distributed search indexes.
data_node is a search facet that restricts where the
matching files are hosted.
If a query is unexpectedly empty:
data_node temporarily to see whether files exist
elsewhere;activity_id, experiment_id,
source_id, variant_label,
frequency, table_id, and
variable_id;Dataset records are parent records. File records identify NetCDF files. Aggregation records are optional and may be absent.
datasets <- shift_datasets(request)
datasets$count()
files <- datasets$collect(type = "File", fields = "*", all = TRUE, limit = NULL)
files$count()
aggregations <- datasets$collect(type = "Aggregation", fields = "*", all = TRUE, limit = NULL)
aggregations$count()If Aggregation records are empty, continue with File records. The robust store workflow does not require Aggregation records.
ESGF datetime search parameters and file coverage are not the same thing. For CMIP-style files, prefer collecting Dataset/File records and then filtering file coverage.
files_2060 <- files$filter_time(
"2060-01-01T00:00:00Z",
"2060-12-31T23:59:59Z",
method = "drs"
)Use method = "drs" for lightweight filename parsing. Use
method = "opendap" only when you need to inspect remote
time axes and can tolerate live network reads.
The default extraction path is OPeNDAP-first. Full NetCDF downloads are optional unless you need offline work, repeated extraction, or fallback from unreliable remote access.
file_table <- shift_files(files_stage)$to_data_table(fields = c(
"filename", "variable_id", "data_node", "url_opendap", "url_download"
))
file_table[, .(
filename,
variable_id,
opendap = !is.na(url_opendap) & nzchar(url_opendap),
http = !is.na(url_download) & nzchar(url_download)
)]When OPeNDAP fails, try:
fallback = "auto";shift_download() before
shift_extract() if repeated local reads are preferred;url_opendap;Downloader state is persistent. Inspect sessions, tasks, jobs, and events before re-running a large download.
downloader <- shift_store(files_stage)$downloader()
downloader$sessions()
downloader$tasks(session_id = session_id)
downloader$events(session_id = session_id)
downloader$data_nodes(service = "HTTPServer")For failed or interrupted tasks:
downloader$retry(session_id = session_id)
downloader$resume(session_id = session_id)
downloader$verify(session_id = session_id)If using the CLI:
Use store validation when local files, manifest records, or download layout look inconsistent.
store <- shift_store(epws)
store$storage_report(detail = TRUE)
validation <- store$validate_files(
query_id = shift_ids(epws)$query_id,
checksum = FALSE,
layout = TRUE
)
validation$summary
validation$actionsRepair and cleanup methods are preview-first. Execute only after reviewing actions.
store$repair_files(validation$actions, dry_run = TRUE)
store$cleanup_downloads(scope = "tmp", older_than = 7 * 24 * 3600, dry_run = TRUE)Coverage must be complete before strict morphing can write future EPWs.
coverage <- shift_coverage(extracted)
coverage[, .(site_id, variable_id, complete, status, output_rows, output_file_count)]If coverage is incomplete:
epw_morph_variables("recommended");shift_extract() after fixing file selection or
access;Enhanced Belcher recipes can combine atmospheric variables from
Amon with snow depth (snd, metres) from
LImon. Keep both table and grid automatic for the first
resolution attempt:
recipe <- epw_morph_recipe("belcher")
epw_morph_variables(recipe)
epw_morph_variables(recipe, include_optional = TRUE)
climate <- shift_cmip6(
"BCC-CSM2-MR", "ssp585",
table = NULL,
grid = NULL
)
print(climate)The plan receipt reports tables auto by variable. After
resolution, progress, watch, and verbose receipts show the authoritative
partitions, for example Amon=gn · LImon=gr. A single
grid_label in a case table is only the primary
compatibility summary; use the partition result when diagnosing
multi-table selection.
Common causes of avoidable resolution failures are:
table = "Amon" forces every variable, including
snd, into Amon;grid = "gn" can reject an otherwise complete case when
its LImon data exists only on gr;"table": {"snd": "LImon"}, not
"table": "LImon", for an override;snd exists but the matching historical reference
does not, or vice versa.With snow_depth = "auto", the last case is
informational: snow morphing is disabled and the EPW is still produced.
Use snow_depth = "required" to make missing
future/reference snd block resolution, or
"off" to avoid querying it altogether.
required_snow <- belcher(
reference = historical_reference(1995:2014),
options = list(snow_depth = "required")
)
no_snow <- belcher(options = list(snow_depth = "off"))If automatic mapping is correct but a particular catalog needs a pin,
override only that variable with table = c(snd = "LImon").
Normal and verbose prints preserve the distinction between an automatic
mapping, a named override, and a scalar table forced across all
variables.
Strict morphing blocks on missing recipe variables, missing baseline EPW fields, or incomplete monthly summaries.
morphed <- shift_morph(extracted, baseline = epw, strict = FALSE)
shift_diagnostics(morphed)Use the lower-level EpwMorpher article when you need to
inspect climate summaries, baseline summaries, factors, and morphing
plan diagnostics directly.
shift_status() and
shift_diagnostics().filter_time(method = "drs").shift_coverage() before strict morphing.snd is available on both sides
of the comparison.