Post-Production Workflow Guide

This guide explains how to write and run a pycWB post-production workflow. Post-production starts after search jobs have produced catalog and progress Parquet files. A workflow YAML then selects analysis subsets, matches simulation triggers to injection truth, trains or applies ranking models, builds FAR products, computes simulation efficiency, and writes report artifacts.

The main command is:

pycwb post-process path/to/postprocess_workflow.yaml

To inspect the dependency graph without running any action:

pycwb post-process path/to/postprocess_workflow.yaml --diagram-only

The user-facing template examples/postproduction/standard_analysis_10pct_workflow.yaml is a good starting point for a complete background, simulation, FAR, efficiency, and HTML-report workflow.

What The Workflow Consumes

A complete post-production workflow usually consumes these files:

Artifact

Typical path

Purpose

Background catalog

BKG/.../catalog/catalog.parquet

Trigger rows used for training, FAR holdout, and zero-lag scoring.

Background progress

BKG/.../catalog/progress.parquet

Job/livetime rows used for train/FAR splits and reports.

Simulation trigger catalog

SIM/.../catalog/catalog.parquet

Recovered simulation triggers.

Simulation progress

SIM/.../catalog/progress.parquet

Job metadata for selecting a simulation training subset.

Simulation summary

SIM/.../catalog/simulations.parquet

One row per injected signal, generated before post-production.

XGBoost config

XGB/.../xgb_config.py

Feature and ranking-statistic configuration.

Public alerts

public_alerts.txt

Optional known-event candidates for the background report.

For simulation studies, build simulations.parquet before running the workflow:

pycwb simulation-summary user_parameters.yaml \
  --work-dir /path/to/sim/run \
  --output /path/to/sim/run/catalog/simulations.parquet

You can also run matching as a standalone command, but complete workflows should prefer the explicit postprocess.matching.match_simulations action:

pycwb match-simulations catalog.parquet simulations.parquet \
  --how right --output matched_right.parquet

YAML Structure

A workflow has three top-level sections:

vars

User-editable values and reusable paths. Put run names, chunks, split fractions, output locations, and input file paths here.

runtime

Execution settings owned by the workflow runner, especially the temporary directory and cleanup policy.

steps

Ordered actions. Each step declares an id, human-readable name, action path, inputs, optional args, and outputs.

Minimal shape:

vars:
  work_dir: .
  paths:
    bkg_catalog: BKG/run/catalog/catalog.parquet

runtime:
  tmp_dir: ${work_dir}/tmp/postprod
  cleanup_tmp: never

steps:
  - id: example_step
    name: Example Step
    action: postprocess.selection.trigger_selection
    inputs:
      catalog_file: ${paths.bkg_catalog}
      progress_file: BKG/run/catalog/progress.parquet
    args:
      returns: [jobs, triggers, livetime]
    outputs:
      triggers_file: tmp://selected.parquet

Variables, References, And Temporary Files

Use ${...} to expand values from vars. Dotted paths are supported:

vars:
  work_dir: .
  chunks:
    train_bkg_1: K20
    train_bkg_2: K22
    target: K21
    tag: k20_k22_k21
  train_fraction_label: 10pct
  run:
    output_name: O4_${chunks.target}_run1
    analysis_slug: bkg_${chunks.tag}_${train_fraction_label}
  paths:
    output_dir: public/${run.output_name}
    model_file: ${paths.output_dir}/models/${run.analysis_slug}_xgb_model_blf.ubj

Use @step.path to read values returned by earlier steps:

catalog_file: "@k21_bkg_split.far.triggers_file"
livetime: "@k21_bkg_split.far.livetime.seconds"

Use tmp:// for intermediate files. The workflow runner resolves those paths under runtime.tmp_dir:

runtime:
  tmp_dir: ${work_dir}/tmp/${run.analysis_slug}

outputs:
  output_file: tmp://bkg_far_scored.parquet

Cleanup policies are:

never

Keep temporary files. This is best while developing or debugging.

on_success

Remove runtime.tmp_dir after a successful workflow.

always

Remove runtime.tmp_dir even if a later step fails.

Changing Chunks Or Fractions

For a chunk-swap workflow, keep the paths derived from a small set of values:

train_fraction_label: 10pct

chunks:
  train_bkg_1: K20
  train_bkg_2: K22
  target: K21
  tag: k20_k22_k21

run:
  output_name: O4_${chunks.target}_run1
  analysis_slug: bkg_${chunks.tag}_${train_fraction_label}

To use K23 instead of K22, update:

chunks:
  train_bkg_1: K20
  train_bkg_2: K23
  target: K21
  tag: k20_k23_k21

The derived catalog paths, temporary directory, model name, FAR JSON, plots, and report paths will update together.

If you change the training fraction, update all three values together:

k21_train_fraction: 0.3
k21_far_fraction: 0.7
train_fraction_label: 30pct

Action Reference

postprocess.selection.trigger_selection

Selects or splits trigger catalogs by jobs or intervals. Use it for BKG train/FAR splits, SIM training fractions, and full SIM evaluation selections.

postprocess.matching.match_simulations

Matches a trigger catalog to simulations.parquet. Use how: outer before SIM training filters and how: right for efficiency curves.

postprocess.selection.filter_real_simulation

Keeps recovered simulation triggers and optionally removes vetoed or across-segment injections.

postprocess.train_xgboost.train_xgboost

Trains the XGBoost ranking model from BKG and SIM catalog lists.

postprocess.evaluate.evaluate_far_rho

Scores the FAR holdout and writes the FAR-vs-ranking lookup.

postprocess.evaluate.score_catalog

Scores a catalog, commonly the target zero-lag background.

postprocess.evaluate.evaluate_efficiency

Scores simulation evaluation triggers and writes a scored catalog.

postprocess.plot_efficiency.compute_efficiency_vs_hrss_by_waveform

Builds waveform-level efficiency curves using a matched simulation table.

postprocess.report.standard_background_report

Writes the standard background plots, fake-open-box outputs, and zero-lag report products.

postprocess.evaluate.score_mdc_catalog

Scores MDC detections against a background IFAR threshold.

postprocess.report_builder.postproduction_report

Aggregates workflow artifacts into the final HTML and JSON report.

Validation And Debugging

Start with a diagram-only dry run:

pycwb post-process postprocess_workflow.yaml --diagram-only

Useful checks before a full run:

  • All ${...} variables resolve to the intended files.

  • Every @step.path reference points to an earlier step.

  • runtime.tmp_dir is unique for this analysis.

  • how: outer is used for SIM training matching.

  • how: right is used for SIM evaluation matching.

  • BKG selections use exclude_zero_lag: true.

  • SIM selections use exclude_zero_lag: false.

  • Report paths point to the same files produced by earlier steps.

Common failure modes:

Missing simulations.parquet

Run pycwb simulation-summary for the simulation production, then rerun post-production.

duckdb import error

Install the catalog matching dependency in the active environment.

Reference resolution error

Check that the producing step has an id and that the referenced key is returned by that action.

Unexpected train/FAR overlap

Use split.by: interval_livetime and make sure the input catalog carries job shift metadata.

Temporary file missing

Keep cleanup_tmp: never while debugging so intermediate parquet files remain inspectable.

Outputs To Expect

A complete workflow typically produces:

  • trained model under ${paths.output_dir}/models/;

  • XGBoost training settings and training output logs;

  • FAR JSON lookup table;

  • scored FAR and zero-lag background catalogs;

  • scored simulation evaluation catalog;

  • waveform efficiency plot and fit-parameter CSV;

  • background report plots;

  • optional MDC detection CSV;

  • final index.html and report_data.json.

Keep the workflow YAML with the report output. It records the exact inputs, fractions, seeds, matching modes, and artifact paths used for the analysis.