This note is the current implementation summary for the CURC-specific workflow code in this repository. It is intended to replace the prior session-by-session narrative with a compact description of what exists now.
Archived historical notes live in notes_curc_archive.md.
- Load Miniforge before using
mamba:module load miniforge
- Use the
spipy14environment for repo commands. - Interactive shell pattern:
module load miniforgemamba activate spipy14
- One-off command pattern:
module load miniforge && mamba run -n spipy14 <command>
- Python rule on this server:
- do not run bare
python3for this repo - run Python through
spipy14, e.g.module load miniforge && mamba run -n spipy14 python <...>
- do not run bare
Build/import checks:
- Build extension in-place:
module load miniforge && mamba run -n spipy14 python setup.py build_ext --inplace
- Verify imports:
module load miniforge && mamba run -n spipy14 python -c "import spires; print('imports_ok')"
If build fails, verify required packages in spipy14:
swiggxxgccnlopt
- The active CURC orchestration code lives in
workflows/curc/. - The main user-facing entrypoints live in
scripts/. - The exploratory notebook is
examples/12_curc_sensor_workflow_planning.ipynb. - The current step planner and runtime are specialized to
sensor="viirs"andplatforms=("snpp",).
workflows/curc/config.py
CurcWorkflowConfigdefines scratch paths, source root, sensor/platform/tile/year selection, dry-run behavior, retry policy, inversion options, and Slurm settings.canonicalized()normalizes sensor and platform names through the SpiPy registry.SlurmProfilecarries submission-time resource settings:accountqostimememcpus_per_taskoutput_dirextra_args
workflows/curc/paths.py
- Staged reflectance:
<scratch_root>/input/<sensor>/<platform>/reflectance/<tile>/<water_year>/ - Ancillary root:
<scratch_root>/input/<sensor>/<platform>/ancillary/<tile>/ - Annual R0 root:
<scratch_root>/input/<sensor>/<platform>/ancillary/r0/<tile>/<r0_year>/ - Annual R0 dataset:
<scratch_root>/input/<sensor>/<platform>/ancillary/r0/<tile>/<r0_year>/<platform>_r0_<tile>_<r0_year>.nc - Raw inversion outputs:
<scratch_root>/output/<sensor>/<platform>/<tile>/raw/wy<water_year>/ - Run-group logs:
<scratch_root>/logs/<run_group_id>/ - Tile-local detailed logs:
<scratch_root>/logs/<run_group_id>/<tile>/detailed_logs/
build_run_group_id() creates IDs like:
- full water year:
<timestamp>_viirs_snpp_wy2023_full - single date:
<timestamp>_viirs_snpp_wy2023_2023-03-16_single_date - subset:
<timestamp>_viirs_snpp_wy2023_<start>_<end>_date_subset
workflows/curc/planner.py
plan_viirs_snpp_workflow_steps()produces four explicit step plans:stage_reflectancestage_ancillarybuild_r0run_inversion
- Reflectance discovery uses
discover_viirs_snpp_reflectance_files(). - Water-year inversion scenes come from the requested water year or from explicit
target_dates. build_r0uses summer scenes from the resolvedr0_year.- If
r0_yearis not supplied, the default comes fromdefault_r0_year_for_water_year(). - Tests currently assert the intended rule that water year
Nuses the previous summer forR0.
plan_viirs_snpp_inversion_array() converts the run_inversion portion into a SlurmArrayPlan.
- One logical task is created per acquisition date.
- Each task stores:
task_indexdate- discovered source paths
- output root
- detailed log path
r0_yearretry_count
- The array plan also carries:
- concurrency limit
- retry limit
- inversion mask/grouping options
- full
SlurmProfile
workflows/curc/execution.py
stage_reflectance- preview mode renders
rsync -av --ignore-existing ... - execute mode runs those
rsynccommands directly
- preview mode renders
stage_ancillary- creates the expected ancillary, R0, and output directories
- preview lists expected static files such as
canopy_fractionandglacier_ice_fraction
build_r0- calls
spires.sensors.viirs.r0.build_r0_from_sources(...) - writes the annual dataset with the current CURC naming convention
- calls
run_inversion- does not execute directly here
- must go through the manifest-backed Slurm array path
workflows/curc/task_manifest.py
write_inversion_array_manifest()persists aSlurmArrayPlanas JSON.- The manifest stores:
- job metadata
- run-group and tile log directories
- retry limit
- inversion options
- Slurm profile
- per-date tasks
workflows/curc/slurm.py
render_array_submission_payload_from_manifest()reconstructs a compact submission payload from a manifest.render_sbatch_command_for_array_payload()builds the actualsbatchcommand.- Slurm profile flags are rendered first; CLI
--sbatch-argvalues append after them as one-off overrides. - Slurm stdout defaults to the manifest directory unless
slurm_profile.output_diris set.
workflows/curc/runtime.py
build_viirs_snpp_inversion_runtime_context()resolves one manifest task into concrete runtime paths.- It infers
scratch_rootfrom the output path stored in the manifest task. - It resolves:
- staged reflectance path(s)
- ancillary root
- annual R0 path
- platform LUT path
- output dataset path
- task log path
- The default output dataset name is:
<platform>_raw_output_<tile>_<YYYYMMDD>.nc
Important current runtime assumptions:
- The executor currently expects exactly one staged reflectance file per acquisition date.
- Missing reflectance, R0, or LUT inputs are classified before execution.
OSError-style filesystem failures are treated as retryable.- The runtime reads inversion options from the manifest unless explicitly overridden at execution time:
apply_valid_inversion_maskuse_groupinggrouping_method
execute_viirs_snpp_inversion_task() is the main manifest-backed runtime entrypoint.
- Dry-run mode resolves and validates context without running the inversion.
- Execute mode calls
spires.sensors.viirs.workflow.run_viirs_inversion(...). - Structured task logs include Slurm metadata when present.
- Per-job log files use
run_inversion_<date>_job<SLURM_JOB_ID>.logwhen a Slurm job ID exists.
workflows/curc/status.py
scan_inversion_array_status()inspects one manifest family and classifies each logical date task.- Status is derived from:
- output dataset validity
- latest structured runtime summary log
- retry counters stored in the manifest
- Current failure codes include:
missing_staged_reflectancemissing_r0missing_lutmissing_runtime_inputinvalid_runtime_inputfilesystem_errorpython_exceptionslurm_or_external_failure
Retry behavior:
max_auto_retry_countis stored in the manifest and defaults to3.write_retry_manifest()creates a new manifest containing failed tasks only.- Retry tasks are renumbered from zero and get
retry_count + 1. should_auto_retry()returnsTrueonly when at least one failed task is still eligible.
Summary artifacts:
- Tile-level summaries:
run_inversion_<tile>_wy<water_year>_summary.csvrun_inversion_<tile>_wy<water_year>_summary.txt
- Run-group summaries:
run_inversion_wy<water_year>_summary.csvrun_inversion_wy<water_year>_summary.txt
write_terminal_summary_artifacts()writes tile summaries when a tile is terminal and run-group summaries once every tile in the run group is terminal.
Current entrypoints:
scripts/run_curc_workflow_step.py- preview or execute
stage_reflectance,stage_ancillary, orbuild_r0
- preview or execute
scripts/run_curc_inversion_array_task.py- resolve or execute one manifest-backed inversion task
scripts/submit_curc_inversion_array.py- preview or submit an initial array from an existing manifest
scripts/scan_curc_inversion_array.py- scan status, write summaries, optionally emit a retry manifest
scripts/auto_retry_curc_inversion_array.py- scan status, create the next retry manifest, optionally submit it
scripts/submit_curc_sensor_workflow.py- renders older deterministic job-manifest payloads from
build_job_manifest()
- renders older deterministic job-manifest payloads from
Relevant tests currently cover:
- planner behavior:
tests/test_curc_planner.py - Slurm profile persistence and sbatch rendering:
tests/test_curc_slurm_profile.py - runtime log naming and log path helpers:
tests/test_curc_runtime_logging.py - attempt-history summaries and run-group summaries:
tests/test_curc_status_reporting.py
- CURC planning/runtime are presently VIIRS SNPP-specific.
run_inversionis array-first; there is no direct non-Slurm step executor for it.- Runtime currently assumes one reflectance file per date task.
- The newer CURC implementation of record is the
workflows/curc/stack, not the historical notes or notebook-only logic.