Build: #3 was successful

Job: ManyLinux 2.28 was successful

Stages & jobs

  1. Default Stage

  2. Test

Code commits

Casa6

  • Josh Marvil

    Josh Marvil 6cf1ede958f01d0f3ed691911c29f0f5c2778eb7

    CAS-14874: derive briggsbwtaper fracBW from output cube

  • Josh Marvil

    Josh Marvil d27fff1705e9d9b7af956665dcd0a23eb5d5e692

    CAS-14874: Make the Briggs cube weight density partition-invariant
    The per-channel imaging-weight density that briggsbwtaper/perchanweightdensity
    relies on is local to a channel: f2/d2[chan] are derived from that channel's
    gridded-weight plane only.  The quality of that plane nevertheless depended on
    *how many* channels this process happens to own, which made the weights - and
    therefore the PSF and flux scale - vary with the number of MPI processes:

    - estimateSwingChanPad() scaled its extra margin by the sub-cube channel count
      (extrapad = max(min(4, imNChan/10), 1)), so different sub-cubes got different
      guard margins.
    - estimateSwingChanPad() returned 0 for a homogeneous frame, i.e. no guard
      margin at all, even though the FT machine still interpolates visibility
      frequencies across neighbouring channel planes (edge truncation).
    - init() padded its density template by a fixed +4/+2 channels while
      fillImgWeightCol() used the data-derived swingpad, so the two passes could
      disagree on the geometry.
    - the default pad for the multi-field/multi-MS path was a bare 4.
    - the scratch weight table key was (nrows, freqbeg, freqend, rmode, robust,
      interp).  All ranks chdir to the same working directory, so ranks that
      produced the same key shared one IMAGING_WEIGHT_* table and raced on it
      (reuse-if-nonzero-row-count, else delete-and-recreate) while it was being
      filled and consumed through readWeightColumn().  The reuse checks in
      initImgWeightCol()/init() keyed on (nx, ny, first-channel frequency) only and
      could hand back a density built for a different sub-cube.
    - initializeFTMachine() rebuilt grids_p[index] from the new template on every
      call but sized f2_p/d2_p only on the first one, so a template that grew
      between calls left f2_p/d2_p shorter than the grid and made
      f2_p[index][pos(3)] read past the end of the vector.

    Fix, in this file only:

    - introduce minWgtDensityEdgePad = 4 (channels per edge) and use it everywhere
      the guard margin was previously derived from the local channel count;
    - return that floor instead of 0 when no frame swing is present;
    - align init()'s template padding and the multi-field default with it;
    - fold a spectral geometry token (nchan, channel reference pixel, first
      channel frequency) into the scratch table name, and require it in the
      initImgWeightCol() early return;
    - pin the init() reuse on the cached density extent (f2_p) matching the
      requested template channel count;
    - grow f2_p/d2_p (and zero them) in initializeFTMachine() when the template
      channel count exceeds the cached allocation, and bounds-check the channel
      index in both weightUniform() and getWeightUniform() so a stale allocation
      yields a zero weight instead of an out-of-bounds read.

    Because the density itself is per-channel-local, making the geometry
    rule partition-independent is enough to make parallel results agree with serial
    for a single input MS, and it removes the shared-table race entirely.  No
    interface, XML or Python change.

    Known remaining partition dependence (follow-up, needs the full-cube channel
    count to be plumbed into this file):

    - the inOneGo threshold in initImgWeightCol() still compares the swing pad
      against templateimage.shape()[3]/10, so multi-MS inputs can still choose a
      different processing path on a small sub-cube than serial does;
    - estimateSwingChanPad() still derives freqbeg/freqend (and so the swing
      estimate itself) from the local template rather than the full selection, so
      the swing term remains weakly dependent on the sub-cube range;
    - the scratch table stays in the shared working directory (a per-rank workdir
      is not knowable here), so cross-run reuse of a same-tag, same-row-count table
      remains possible, as before.

    Validation: two standalone harnesses compile the changed logic against stubbed
    casacore types - the first asserts geometry-key/cache-key behaviour (reuse only
    for identical token/extent/nx/ny/freq) and the pad floor values, the second a
    faithful Block<Vector<Float>> model asserts the grow-then-zero path and that a
    stale shorter f2_p is rejected rather than read out of bounds.  Brace/paren
    balance preserved (110->112 braces, 794->849 parens, both sides equal).  A full
    casatools build plus serial-vs-parallel tests are still required before merge.