Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set min counts to fraction of median #100

Merged
merged 19 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: pfb-clean Workflow
name: pfb-imaging Workflow

on:
push:
Expand Down Expand Up @@ -31,7 +31,7 @@ jobs:
# - name: Pin setuptools
# run: python -m pip install setuptools==65.5

- name: Install pfb-clean
- name: Install pfb-imaging
run: python -m pip install .[testing]

- name: Run tests
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ RUN apt -y update && \


RUN python -m pip install -U pip setuptools wheel && \
python -m pip install -U pfb-clean@git+https://github.com/ratt-ru/pfb-clean@main && \
python -m pip install -U pfb-imaging@git+https://github.com/ratt-ru/pfb-imaging@main && \
python -m pip install numpy==1.22 && \
python -m pip cache purge
14 changes: 3 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pfb-clean
pfb-imaging
=========
Preconditioned forward-backward clean algorithm.
Radio interferometric imaging suite base on the pre-conditioned forward-backward algorithm.

Install the package by cloning and running

:code:`$ pip install -e pfb-clean/`
:code:`$ pip install -e pfb-imaging/`

Note casacore needs to be installed on the system for this to work.

Expand All @@ -19,14 +19,6 @@ no binary mode eg

:code:`$ pip install -e ducc`

You may also have to make numba aware of the tbb layer by doing

:code:`$ pip install tbb`

:code:`$ export LD_LIBRARY_PATH=/path/to/venv/lib`

see eg. https://github.com/ratt-ru/QuartiCal/issues/268

If you find any of this useful please cite (for now)

https://arxiv.org/abs/2101.08072
File renamed without changes.
File renamed without changes.
22 changes: 14 additions & 8 deletions pfb/parser/restore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,37 @@ inputs:
dtype: str
abbreviation: mname
default: MODEL
info: 'Name of model in mds'
info:
Name of model in dds
residual-name:
dtype: str
abbreviation: rname
default: RESIDUAL
info: 'Name of residual in dds'
info:
Name of residual in dds
nband:
dtype: int
required: true
abbreviation: nb
info: 'Number of imaging bands'
info:
Number of imaging bands
postfix:
dtype: str
default: 'main'
info: 'Can be used to specify a custom name for the image space data \
products'
info:
Can be used to specify a custom name for the image space data products
outputs:
dtype: str
default: mMrRiI
info: 'Output products. (m)odel, (r)esidual, (i)mage, (c)lean beam. \
Captitals correspond to cubes.'
info:
Output products (m)odel, (r)esidual, (i)mage, (c)lean beam, (d)irty,
(f)ft_residuals (amplitude and phase will be produced).
Use captitals to produce corresponding cubes.
overwrite:
dtype: bool
default: false
info: Allow overwrite of output xds
info:
Allow overwriting fits files

outputs:
{}
11 changes: 11 additions & 0 deletions pfb/parser/smoovie.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,17 @@ inputs:
The format to write movie out in.
gifs are usually better quality but can get quite large.
mp4 quality not currently great with streamjoy.
optimize:
dtype: bool
default: false
info:
To try and optimize the resulting gif.
Only possible if gifsicle is installed.
crf:
dtype: int
default: 12
info:
Constant rate factor for controlling mp4 output quality.

outputs:
{}
8 changes: 7 additions & 1 deletion pfb/parser/spotless.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,13 @@ inputs:
dtype: float
default: 0.5
info:
Lower the initail rmsfactor by this amount
Lower the initial rmsfactor by this amount
diverge-count:
dtype: int
default: 5
info:
Will terminate the algorithm if the rms increases this many times.
Set to > niter to disable this check.

outputs:
{}
12 changes: 6 additions & 6 deletions pfb/parser/uncabbedcabs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ pfb.degrid:
_include:
- (.)degrid.yaml

pfb.clean:
command: pfb.workers.clean.clean
pfb.klean:
command: pfb.workers.klean.klean
flavour: python
policies:
pass_missing_as_none: true

_include:
- (.)clean.yaml
- (.)klean.yaml

pfb.restore:
command: pfb.workers.restore.restore
Expand All @@ -52,14 +52,14 @@ pfb.fwdbwd:
_include:
- (.)fwdbwd.yaml

pfb.forward:
command: pfb.workers.forward.forward
pfb.fluxmop:
command: pfb.workers.fluxmop.fluxmop
flavour: python
policies:
pass_missing_as_none: true

_include:
- (.)forward.yaml
- (.)fluxmop.yaml

pfb.spotless:
command: pfb.workers.spotless.spotless
Expand Down
2 changes: 1 addition & 1 deletion pfb/utils/fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def set_wcs(cell_x, cell_y, nx, ny, radec, freq,

header = w.to_header()
header['RESTFRQ'] = fmean
header['ORIGIN'] = 'pfb-clean'
header['ORIGIN'] = 'pfb-imaging'
header['BTYPE'] = 'Intensity'
header['BUNIT'] = unit
header['SPECSYS'] = 'TOPOCENT'
Expand Down
84 changes: 77 additions & 7 deletions pfb/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,13 +503,14 @@ def _restore_corrs(vis, ncorr):
return model_vis


# model to fit
@jax.jit
def psf_errorsq(x, data, xy):
'''
Returns sum of square error for best fit Gaussian to data
'''
emaj, emin, pa = x
Smin = jnp.minimum(emaj, emin)
Smaj = jnp.maximum(emaj, emin)
# print(emaj, emin, pa)
A = jnp.array([[1. / Smin ** 2, 0],
[0, 1. / Smaj ** 2]])

Expand All @@ -519,7 +520,7 @@ def psf_errorsq(x, data, xy):
B = jnp.dot(jnp.dot(R.T, A), R)
Q = jnp.einsum('nb,bc,cn->n', xy.T, B, xy)
# GaussPar should corresponds to FWHM
fwhm_conv = 2 * jnp.sqrt(2 * np.log(2))
fwhm_conv = 2 * jnp.sqrt(2 * jnp.log(2))
model = jnp.exp(-fwhm_conv * Q)
res = data - model
return jnp.vdot(res, res)
Expand Down Expand Up @@ -660,7 +661,7 @@ def init_mask(mask, model, output_type, log):
return mask


def dds2cubes(dds, nband, apparent=False):
def dds2cubes(dds, nband, apparent=False, dual=True):
real_type = dds[0].DIRTY.dtype
complex_type = np.result_type(real_type, np.complex64)
nx, ny = dds[0].DIRTY.shape
Expand All @@ -686,7 +687,7 @@ def dds2cubes(dds, nband, apparent=False):
psfhat = None
mean_beam = [da.zeros((nx, ny), chunks=(-1, -1),
dtype=real_type) for _ in range(nband)]
if 'DUAL' in dds[0]:
if dual and 'DUAL' in dds[0]:
nbasis, nymax, nxmax = dds[0].DUAL.shape
dual = [da.zeros((nbasis, nymax, nxmax), chunks=(-1, -1, -1),
dtype=real_type) for _ in range(nband)]
Expand All @@ -707,7 +708,7 @@ def dds2cubes(dds, nband, apparent=False):
psfhat[b] += ds.PSFHAT.data
if 'MODEL' in ds:
model[b] = ds.MODEL.data
if 'DUAL' in ds:
if dual and 'DUAL' in ds:
dual[b] = ds.DUAL.data
mean_beam[b] += ds.BEAM.data * ds.WSUM.data[0]
wsums[b] += ds.WSUM.data[0]
Expand All @@ -720,7 +721,7 @@ def dds2cubes(dds, nband, apparent=False):
if 'PSF' in ds:
psf = da.stack(psf)/wsum
psfhat = da.stack(psfhat)/wsum
if 'DUAL' in ds:
if dual and 'DUAL' in ds:
dual = da.stack(dual)
for b in range(nband):
if wsums[b]:
Expand Down Expand Up @@ -1441,3 +1442,72 @@ def combine_columns(x, y, dc, dc1, dc2):
out=x,
casting='same_kind')
return x


# def fft_interp(image, cellxi, cellyi, nxo, nyo,
# cellxo, cellyo, shiftx, shifty):
# '''
# Use non-uniform fft to interpolate image in a flux conservative way

# image - input image
# cellxi - input x cell-size
# cellyi - input y cell-size
# nxo - number of x pixels in output
# nyo - number of y pixels in output
# cellxo - output x cell size
# cellyo - output y cell size
# shiftx - shift x coordinate by this amount
# shifty - shift y coordinate by this amount

# All sizes are assumed to be in radians.
# '''
# import matplotlib.pyplot as plt
# from scipy.fft import fftn, ifftn
# Fs = np.fft.fftshift
# iFs = np.fft.ifftshift
# # basic
# nx, ny = image.shape
# imhat = Fs(fftn(image))

# imabs = np.abs(imhat)
# imphase = np.angle(imhat) - 1.0
# # imphase = np.roll(imphase, nx//2, axis=0)
# imshift = ifftn(iFs(imabs*np.exp(1j*imphase))).real

# impad = np.pad(imhat, ((nx//2, nx//2), (ny//2, ny//2)), mode='constant')
# imo = ifftn(iFs(impad)).real

# print(np.sum(image) - np.sum(imo))

# plt.figure(1)
# plt.imshow(image/image.max(), vmin=0, vmax=1, interpolation=None)
# plt.colorbar()
# plt.figure(2)
# plt.imshow(imo/imo.max(), vmin=0, vmax=1, interpolation=None)
# plt.colorbar()
# plt.figure(3)
# plt.imshow(imshift/imshift.max() - image/image.max(), vmin=0, vmax=1, interpolation=None)
# plt.colorbar()

# plt.show()

# # coordinates on input grid
# nx, ny = image.shapeimhat
# x = np.arange(-(nx//2), nx//2) * cellxi
# y = np.arange(-(ny//2), ny//2) * cellyi
# xx, yy = np.meshgrid(x, y, indexing='ij')

# # frequencies on output grid
# celluo = 1/(nxo*cellxo)
# cellvo = 1/(nyo*cellyo)
# uo = np.arange(-(nxo//2), nxo//2) * celluo/nxo
# vo = np.arange(-(nyo//2), nyo//2) * cellvo/nyo

# uu, vv = np.meshgrid(uo, vo, indexing='ij')
# uv = np.vstack((uo, vo)).T


# res1 = finufft.nufft2d3(xx.ravel(), yy.ravel(), image.ravel(), uu.ravel(), vv.ravel())



6 changes: 4 additions & 2 deletions pfb/utils/stokes2vis.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def single_stokes(ds=None,
dc,
dc1,
dc2,
chunks=data.chunks)
chunks=data.chunks,
meta=np.empty((0,0,0), dtype=data.dtype))


nrow, nchan, ncorr = data.shape
Expand Down Expand Up @@ -90,7 +91,8 @@ def single_stokes(ds=None,
# weight = 1.0/sigma**2
weight = da.map_blocks(weight_from_sigma,
sigma,
chunks=sigma.chunks)
chunks=sigma.chunks,
meta=np.empty((0,0,0), dtype=sigma.dtype))
elif opts.weight_column is not None:
weight = getattr(ds, opts.weight_column).data
if opts.weight_column=='WEIGHT':
Expand Down
19 changes: 12 additions & 7 deletions pfb/utils/weighting.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,16 @@ def filter_extreme_counts(counts, nbox=16, nlevel=10):
counts, 'xy',
nbox, None,
nlevel, None,
dtype=counts.dtype)
dtype=counts.dtype,
meta=np.empty((0,0), dtype=float))



@njit(nogil=True, cache=True)
# @njit(nogil=True, cache=True)
def _filter_extreme_counts(counts, nbox=16, level=10.0):
'''
Replaces extreme counts by local mean computed i
Replaces extremely small counts by median to prevent
upweighting nearly empty cells
'''
# nx, ny = counts.shape
# I, J = np.where(counts>0)
Expand All @@ -203,10 +205,13 @@ def _filter_extreme_counts(counts, nbox=16, level=10.0):
# local_mean = np.mean(tmp[ix, iy])
# if counts[i,j] < local_mean/level:
# counts[i, j] = local_mean
# get the median ounts value
med = np.median(counts>0)
counts = np.where(counts > med/level, counts, med)

# get the median counts value
ix, iy = np.where(counts > 0)
cnts = counts[ix,iy]
med = np.median(cnts)
lowval = med/level
cnts = np.maximum(cnts, lowval)
counts[ix,iy] = cnts
return counts


Expand Down
Loading
Loading