briggsbwtaper Weighting and Parallel Cube Imaging¶
Background¶
The briggsbwtaper weighting scheme (CAS-13021) applies a UV-distance-dependent
taper whose strength is controlled by the fractional bandwidth of the full
cube:
fracBW = 2 * (maxFreq - minFreq) / (maxFreq + minFreq)
The taper factor applied to each visibility in BriggsCubeWeightor is:
nCellsBW = fracBW * sqrt(uscale*u² + vscale*v²)
uvDistFactor = nCellsBW + 0.5 (clamped for short baselines)
imweight /= gwt * f2 / uvDistFactor + d2
Why It Fails in Parallel Cube Mode¶
In pclean’s parallel cube mode, each Dask worker images an independent sub-cube
of 1–N channels (cube_chunksize). This breaks briggsbwtaper because:
fracBWcollapses to zero. Withcube_chunksize=1, each worker’s sub-cube has a single channel, somaxFreq == minFreq→fracBW = 0.0. The C++ code inBriggsCubeWeightorthrows:AipsError: BriggsCubeWeightor fractional bandwith is not a valid value, 0.0.
Even with multi-channel chunks, each worker computes
fracBWfrom its own sub-cube, not the full bandwidth. The resulting taper would be physically incorrect.
What briggsbwtaper Actually Needs¶
The algorithm has two independent components:
Component |
Scope |
Parallelizable? |
|---|---|---|
Per-channel Briggs weight density grid ( |
Single channel |
Yes — |
|
Full cube bandwidth |
No — requires knowledge of all channels |
Since per-channel density grids are already independent, the only cross-channel
quantity is the fracBW scalar. If this value were pre-computed from the full
cube parameters and passed to each worker, the results would be identical to
serial tclean.
C++ Code Path¶
SynthesisImagerVi2::weight() already accepts fracBW as a parameter
(default 0.0). When fracBW != 0.0, it skips auto-computation and uses the
passed value directly:
// SynthesisImagerVi2.cc line 879
if (rmode == "bwtaper") {
if (fracBW == 0.0) {
// auto-compute from sub-cube spectral axis — FAILS for 1-chan
minFreq = SpectralImageUtil::worldFreq(itsMaxCoordSys, 0.0);
maxFreq = SpectralImageUtil::worldFreq(itsMaxCoordSys, itsMaxShape(3)-1);
fracBW = 2 * (maxFreq - minFreq) / (maxFreq + minFreq);
}
// if fracBW was already nonzero, used as-is ✓
}
The fracBW value propagates through:
SynthesisImagerVi2::weight()
→ fillWeightRecord() stores fracBW in Record
→ BriggsCubeWeightor reads fracBW_p
→ used in weightUniform() / getWeightUniform() taper formula
Fix: Exposing fracBW Through the Python Binding (Option A — Implemented)¶
The Python setweighting binding originally did not expose the fracBW
parameter. This has been fixed with three coordinated changes:
1. casatools XML binding (synthesisimager.xml)¶
Added <param name="fracbw" type="double"> to the setweighting method
definition, with a default of 0.0 (preserving backward compatibility — existing
callers that omit it get the auto-compute behavior).
2. casatools C++ wrapper (synthesisimager_cmpt.cc)¶
Added const double fracbw to the setweighting() function signature and
passed it as the 13th argument to itsImager->weight():
itsImager->weight(type, rmode, cnoise, robust, cfov, npixels,
multifield, usecubebriggs, filtertype, bmaj, bmin, bpa, fracbw);
3. pclean params.py¶
Added
fracbw=0.0to_DEFAULT_WEIGHT.When
weighting="briggsbwtaper", pre-computesfracBWfrom the full cube’sstart,width, andnchanparameters:
fracBW = 2.0 * (maxFreq - minFreq) / (maxFreq + minFreq)
This value is stored in weightpars["fracbw"] and passed through to each Dask
worker via si.setweighting(**params.weightpars). Since the binding now accepts
fracbw, the C++ layer receives the correct full-cube fractional bandwidth
and skips the broken auto-computation.
Note: Requires rebuilding casatools with the modified XML/C++ files.
Fallback Workaround¶
Use weighting='briggs' with perchanweightdensity=True (the default):
pclean(
...,
weighting="briggs", # not "briggsbwtaper"
robust=0.5,
perchanweightdensity=True,
parallel=True,
cube_chunksize=1,
)
This computes per-channel Briggs weights independently and is compatible with per-channel parallelization.
tclean Reference Constraints¶
tclean itself also restricts briggsbwtaper:
Requires
perchanweightdensity=TrueRequires
specmode='cube'(not'mfs'or'cont')Requires
npixels=0
See task_tclean.py lines 218–236 in casa6.