Prepare caches locally, over SSH and on Slurm#
The dataset TOML is the complete recipe for cache population. It defines the observations, source readers, cache directory and worker settings. No metric definitions or analysis script are required. The cache contains reduced source arrays; metrics, reductions, selections and weights are chosen later.
QUALITY and calibration deliberately remain uncached: they are fast to read. Populate the expensive PS and horizon-filtered variance sources, then compute their metrics alongside freshly read QUALITY/calibration values in the notebook.
Define the recipe once#
[blocks]
pspipe_config = "ps/l3.toml"
[sources.quality]
path = "results/{night}_{field}_{level}_{sw}/aoquality/{night}_{field}_{stage}.qs"
stage = "l3"
[sources.ps]
pspipe_config = "ps/l3.toml"
fmhz = [60.5, 72.5]
umin = 15
umax = 40
stokes = ["I", "V", "dt_V"]
ps_config = {ft_method = "nudft"}
[sources.variance]
pspipe_config = "ps/l3.toml"
fmhz = [60.5, 72.5]
umin = 15
umax = 40
stokes = ["I", "V", "dt_V"]
horizon_factor = 1.0
[cache]
dir = "cosmic_metrics_cache"
sources = ["ps", "variance"]
batch_size = 4
require = true
[worker]
nodes = "slurm"
max_concurrent = 8
slurm_nodes = 1
max_time = 3600
slurm_options = "--clusters=astro_thin -p def --account=fmertens --qos=astro_thin_def_long --exclude=node0168 --mem=0"
[worker.resources]
cache = {cpus = 1, mem = "4GB"}
This is an NT04 example: adapt paths, cluster, account and QoS to your site.
The complete dataset example
is also in the repository.
Paths are resolved relative to the dataset TOML. Keep frequency coverage, Stokes
products, UV cuts and filtering in the source sections; the population command
never infers them from metrics. For example, several 1 MHz variance metrics can
share the spectrum produced by the broad-band variance source above.
[cache].sources selects source aliases, not metric names. Omit it to populate
all readers declaring cache=True. Selecting an uncached reader is an error.
batch_size limits blocks per worker task, within one source and observing night;
each block is nevertheless persisted immediately. require=true controls later
metric computation, not cache preparation.
Populate and check#
cosmic-metrics cache populate dataset.toml --dry-run
cosmic-metrics cache populate dataset.toml
cosmic-metrics cache status dataset.toml
# Rebuild selected entries, including ones that are already valid.
cosmic-metrics cache populate dataset.toml --force
The dry run reports valid, missing, stale and corrupt entries plus the planned
execution and pending batch count. It loads no source arrays, writes nothing and
submits no jobs. status checks every expected current entry and exits nonzero
when some are unavailable. Unlike cache.inspect(), it includes absent files.
Valid entries are skipped without rewriting their files. If every selected entry
is valid, population returns without starting local workers or submitting a Slurm
job. Use --force to rebuild all selected entries, locally or on Slurm;
--force --dry-run previews the work without changing files or submitting jobs.
In Python, use dataset.cache.populate(force=True). A failed forced rebuild
retains the previous entry until a successful load can replace it atomically.
Older or invalid entries are recomputed using the same dependency checks and atomic writes as normal dataset computation. Previous cache formats without the current metadata must be rebuilt; they are not migrated by guessing their source configuration. Changing metric definitions does not change the raw cache. Changing a source configuration selects a different namespace.
Execution settings#
Population uses libpipe.worker.get_worker_pool(), following nenucal’s execution
pattern. [worker].nodes is a libpipe host specification:
|
Execution |
|---|---|
|
Local worker processes; no Slurm installation required |
|
Workers on SSH hosts |
|
Slurm tasks; libpipe manages the allocation and job steps |
Before execution, the command records the TOML hash, source identities, block
bounds, cache path, effective worker settings and package implementation in a
manifest under cache/runs/<run>/. All backends run the same source/block tasks
and produce the same reports.
As with nenucal, the command runs in the foreground until all tasks finish. Keep
the terminal open or use a persistent session such as tmux. With nodes="slurm",
slurm_nodes requests an allocation through libpipe. Inside an existing Slurm
allocation, steps use that allocation without creating a nested one or requesting
cross-cluster database access from compute nodes. Slurm 20.11+ is needed for exact
job steps.
Command-line settings override the corresponding TOML values for that run:
cosmic-metrics cache populate dataset.toml --hosts localhost --max-concurrent 4
cosmic-metrics cache populate dataset.toml --hosts 'node[01-04]' --env-file workers.sh
cosmic-metrics cache populate dataset.toml --hosts slurm --slurm-nodes 4
cosmic-metrics cache populate dataset.toml --hosts slurm --slurm-options='-p def --mem=0'
--slurm-nodes overrides [worker].slurm_nodes without editing the TOML or
replacing the configured Slurm account, partition or other options. The dry run
reports the requested node count. --slurm-options accepts raw Slurm flags;
libpipe settings such as slurm_nodes=4 do not belong in that string. Inside an
existing Slurm allocation, the command reuses that allocation regardless of the
requested node count.
Workers use the same Python executable as the submitting command, retaining its
virtual-environment path. Optional worker.env_file is sourced before every task.
All source/configuration paths, the Python environment and the cache directory must
be accessible from the allocated nodes. Worker replay verifies the configuration,
implementation, source identities and cache path before reading data, and reuses
the submission’s block list without rediscovering observations.
max_concurrent sets libpipe’s task concurrency per host. For managed Slurm
allocations, libpipe sizes its worker pool for the allocated nodes and schedules
steps according to available CPUs; worker.resources.cache supplies each step’s
CPUs and memory. Start with one CPU per task and measure memory/throughput before
increasing concurrency. BLAS is limited to one thread per population worker,
avoiding nested process/thread oversubscription. max_time is in seconds and
limits tasks and Slurm allocations; an explicit time in slurm_options takes
precedence for Slurm. Source data must not change during the run.
Compute nodes may have no internet access. If populating an ionosphere source, download the required IONEX maps beforehand into the configured shared directory.
Progress, failures and resuming#
Each task logs completed block IDs with valid/written/missing/error status and
elapsed time. Libpipe displays progress and reports CPU time and peak memory for
local and Slurm workers. The run folder contains per-task logs/JSON results,
manifest.json and a combined report.json. Missing inputs and worker failures produce
a nonzero final job exit status; partial results remain available.
To resume, run the same populate command again. It schedules only entries that are not valid; each worker checks again before loading. Successfully written blocks survive interrupted steps. If the TOML or package changes while a job is queued, that run fails validation: submit a fresh run with the intended settings. Logs and manifests are preserved when clearing managed cache entries.
Use the cache in a notebook#
import cosmic_metrics as cm
from cosmic_metrics import metrics as m
dataset = cm.Dataset.from_toml('dataset.toml')
rfi = m.BandVarianceRatio((67, 68))
quality = m.StdOverDStd('XX')
table = dataset.compute_metrics([rfi, quality])
table.plot(rfi.name)
By default, compute_metrics() prints the absolute cache directory and a summary
for each requested source alias, aggregated across nights and metrics:
Cache directory: /data/nt04/cosmic_metrics_cache
...
variance: 317 blocks loaded from cache; 0 blocks loaded from source
quality: 0 blocks loaded from cache; 317 blocks loaded from source (uncached source)
Counts describe actual reads: newly computed entries count as source loads on
that call, then as cache loads on later calls. Missing blocks are reported as
unavailable. verbose=False silences both progress and cache summaries.
With [cache].require=true, computation checks required entries before loading
any source. Missing, stale or corrupt PS/variance entries raise
CacheMissError instead of starting expensive calculations.
QUALITY and calibration still read directly. A late cache miss also raises; it
cannot silently fall back to loading cubes. Override explicitly with
compute_metrics(..., require_cache=False) when local recomputation is intended.
For direct Python preparation, dataset.cache.populate() uses the same raw-cache
implementation locally. It returns one report row per source/block and needs no
metrics. The CLI adds TOML-driven worker scheduling around this operation.