asimov-pycbc ============= ``asimov-pycbc`` is a plugin for `Asimov `_ 0.7+ that integrates `PyCBC Inference `_ parameter estimation. Once installed, the plugin is discovered automatically via Asimov's entry-point registry -- no extra configuration is required. **What it does** * Renders a ``pycbc_inference`` config file from a production's meta-data (waveform, data, sampler, likelihood), using this plugin's bundled :attr:`config_template ` -- or picks up a hand-written ``.ini`` already committed to the event repository. * Submits ``pycbc_inference`` to an HTCondor or Slurm scheduler via Asimov's scheduler-agnostic API. * Once the run completes, advertises its samples (via ``collect_assets()``) for any downstream production that declares a ``needs:`` dependency on it -- for example a `asimov-pesummary `_ post-processing production. This plugin does not submit that job itself; see *Post-processing* below. * Resubmits a failed or evicted job so it resumes from ``pycbc_inference``'s own checkpoint, rather than restarting from scratch. Installation ------------ PyCBC Inference itself must be installed separately (e.g. via conda-forge) -- this plugin shells out to the ``pycbc_inference`` executable rather than importing ``pycbc``, so it isn't pulled in as a Python dependency: .. code-block:: bash conda install -c conda-forge pycbc "dynesty<2" pip install asimov-pycbc From source: .. code-block:: bash conda install -c conda-forge pycbc "dynesty<2" git clone https://github.com/etive-io/asimov-pycbc.git cd asimov-pycbc pip install -e ".[docs,test]" .. note:: ``dynesty<2`` is required: PyCBC's ``dynesty`` sampler backend (``pycbc.inference.sampler.dynesty``) imports ``dynesty.nestedsamplers``, a module removed in ``dynesty`` 2.0. This isn't PyCBC-Inference-specific -- pin it if you plan to use the ``dynesty`` sampler at all. Tutorial: from a fresh project to posterior samples ---------------------------------------------------- This walks through a complete, runnable example -- an event with simulated (``--fake-strain``) noise, so no real strain data or datafind access is required. It's the same configuration this plugin's own end-to-end test (``.github/workflows/e2e.yml``) runs for real. Swap in real ``data`` metadata (see *Data* below) for an actual analysis. 1. Create a project and point Asimov at your PyCBC environment: .. code-block:: bash asimov init "Tutorial Project" cd "Tutorial Project" asimov configuration update pipelines/environment "$CONDA_PREFIX" 2. Apply an event: .. code-block:: yaml # event.yaml kind: event name: GW150914 interferometers: - H1 event time: 1126259462.4 waveform: approximant: IMRPhenomD reference frequency: 30 minimum frequency: H1: 30 .. code-block:: bash asimov apply -f event.yaml ``waveform`` lives here, at the event level, rather than being repeated on each production: it's real signal metadata shared by everything analysing this event, and Asimov inherits event-level meta into every production for it automatically (before that production's own blueprint keys are merged on top) -- so both productions below pick it up with nothing further needed. 3. Apply a ``pycbc`` production. This one uses simulated noise, so it needs no upstream data-retrieval step: .. code-block:: yaml # pycbc-production.yaml kind: analysis name: pycbc-test pipeline: pycbc status: ready likelihood: sample rate: 2048 minimum frequency: H1: 30 data: fake strain: aLIGOZeroDetHighPower fake strain seed: 1234 sampler: sampler: dynesty sampler kwargs: nlive: 50 dlogz: 5.0 scheduler: accounting group: ligo.dev.o4.cbc.pe.pycbc .. code-block:: bash asimov apply -f pycbc-production.yaml -e GW150914 asimov manage build submit ``manage build`` renders ``pycbc-test.ini`` from this plugin's bundled :attr:`config_template ` (unless one already exists in the event repository), and ``submit`` submits it. 4. Wait for it to finish (a few seconds to a few minutes, depending on sampler settings), checking status with: .. code-block:: bash asimov monitor Once finished, the posterior samples live at ``working/GW150914/pycbc-test/pycbc-test.hdf``. 5. Chain a PESummary post-processing step onto it as its own production, with a ``needs:`` dependency on ``pycbc-test``: .. code-block:: yaml # pesummary-production.yaml kind: analysis name: pycbc-test-pesummary pipeline: pesummary status: ready needs: - pycbc-test postprocessing: pesummary: multiprocess: 2 .. code-block:: bash asimov apply -f pesummary-production.yaml -e GW150914 asimov manage build submit You can apply this at any point, even before ``pycbc-test`` has finished -- Asimov's own dependency resolution won't actually build and submit ``pycbc-test-pesummary`` until ``pycbc-test`` reaches ``finished``, at which point PESummary picks up its samples through ``pycbc-test``'s ``collect_assets()`` (via ``production._previous_assets()``), with no glue code of any kind needed from this plugin. Keep running ``asimov monitor`` to drive both productions through to completion; PESummary's output pages land under Asimov's configured webroot. ``summarypages`` (from the real ``pesummary`` package) needs to be able to ``import pycbc`` to read ``pycbc_inference``'s native HDF5 format, so install ``asimov-pesummary`` into the *same* environment as ``pycbc`` itself -- if it's installed anywhere ``pycbc`` isn't importable, reading the samples will fail with ``Unable to find a posterior samples table``. .. note:: An earlier version of this plugin submitted the PESummary job automatically from ``after_completion()``, by looking up the ``pesummary`` pipeline via Asimov's entry-point registry. That approach is no longer used: this plugin's ``after_completion()`` now only marks the production ``finished`` -- post-processing is always expressed as an explicit, dependency-linked production, as above. Data ---- Strain data is read from a production's ``data`` meta-data, using the same conventions as the sibling GW pipeline plugins (``asimov-lalinference``, ``asimov-bayeswave``) and `asimov-gwdata `_: .. code-block:: yaml data: channels: H1: H1:DCS-CALIB_STRAIN_CLEAN_C01 L1: L1:DCS-CALIB_STRAIN_CLEAN_C01 frame types: H1: H1_HOFT_C01 L1: L1_HOFT_C01 or, with a pre-built LAL-format cache instead of a datafind lookup: .. code-block:: yaml data: cache files: H1: /path/to/H1.cache L1: /path/to/L1.cache Because these are the same ``data.*`` keys ``asimov-gwdata`` writes, a ``pycbc`` production listed after a ``gwdata`` production in the same event (or made to ``needs:`` it) picks up real frame data automatically -- ``data-retrieval -> pycbc -> pesummary`` is expressed entirely through Asimov's own dependency mechanism, with no extra glue code. Status messages ~~~~~~~~~~~~~~~~ ``wait`` The pipeline will ignore the production. ``ready`` Asimov will attempt to submit the job to the scheduler. ``running`` Applied after the job is submitted to the cluster. ``stuck`` Applied when the job is held or an error is detected in the pipeline's execution. ``finished`` Applied when normal termination of the pipeline is detected (a real, readable posterior HDF5 file exists). This is a terminal state as far as this plugin is concerned -- see *Post-processing* below for what (if anything) happens next. Post-processing ---------------- This plugin does not run any post-processing itself, and ``after_completion()`` does nothing beyond marking the production ``finished``. Instead, post-processing (PESummary or otherwise) is expressed as its own, separate production with a ``needs:`` dependency on the ``pycbc`` production -- see step 5 of the tutorial above. Asimov's own dependency resolution is what actually builds and submits that production once this one finishes; this plugin only needs to make its samples available via ``collect_assets()``, which it always does regardless of whether anything ever consumes them. .. toctree:: :maxdepth: 2 :caption: Reference api