@@ -298,7 +298,7 @@ def frac_coord(npixel, kernel_oversampling, p):
298298 :param kernel_oversampling: Fractional values to round to
299299 :param p: Coordinate in range [-.5,.5[
300300 """
301- assert numpy .array (p >= - 0.5 ).all () and numpy .array (p < 0.5 ).all (), "uv overflows grid uv= %s" % str (p )
301+ assert numpy .array (p >= - 0.5 ).all () and numpy .array (p < 0.5 ).all (), "Cellsize is too large: uv overflows grid uv= %s" % str (p )
302302 x = npixel // 2 + p * npixel
303303 flx = numpy .floor (x + 0.5 / kernel_oversampling )
304304 fracx = numpy .around ((x - flx ) * kernel_oversampling )
@@ -318,48 +318,69 @@ def frac_coords(shape, kernel_oversampling, xycoords):
318318 return x , xf , y , yf
319319
320320
321- def fixed_kernel_degrid (kernel , vshape , uvgrid , uv , frequency , polarisation , uvscale , vpolmap = lambda pol : pol ,
322- vchanmap = lambda frequency : 0 ):
321+ def fixed_kernel_degrid (kernels , vshape , uvgrid , vuvwmap , vfrequencymap , vpolarisationmap ):
323322 """Convolutional degridding with frequency and polarisation independent
324323
325324 Takes into account fractional `uv` coordinate values where the GCF
326325 is oversampled
327326
328- :param kernel: Oversampled convolution kernel
327+ :param kernel: list of oversampled convolution kernel
329328 :param vshape: Shape of visibility
330329 :param uvgrid: The uv plane to de-grid from
331- :param uv: fractional uv coordinates in range[-0.5,0.5[
332- :param uvscale: scaling for each channel
330+ :param uvw: fractional uvw coordinates in range[-0.5,0.5[
331+ :param vuvwmap: function to map uvw to grid fractions
332+ :param vfrequencymap: function to map frequency to image channels
333+ :param vpolarisationwmap: function to map polarisation to image polarisation
333334 :returns: Array of visibilities.
334335 """
335- kernel_oversampling , _ , gh , gw = kernel .shape
336+ kernels = numpy .conjugate (list (kernels ))
337+ kernel_oversampling , _ , gh , gw = kernels [0 ].shape
336338 assert gh % 2 == 0 , "Convolution kernel must have even number of pixels"
337339 assert gw % 2 == 0 , "Convolution kernel must have even number of pixels"
338340 inchan , inpol , ny , nx = uvgrid .shape
339- nvis , vnchan , vnpol = vshape
340- assert vnpol == inpol , "Number of polarizations must be the same"
341+ nvis = vshape [0 ]
341342 vis = numpy .zeros ([nvis ], dtype = 'complex' )
342343 wt = numpy .zeros ([nvis ])
343-
344- ichan = vchanmap ( frequency )
345- ipol = vpolmap ( polarisation )
346- # Calculate grid point and fractional part for scaled u and v
347- y , yf = frac_coord (uvgrid . shape [ 2 ] , kernel_oversampling , uvscale [ 1 ] * uv [..., 1 ])
348- x , xf = frac_coord ( uvgrid . shape [ 3 ], kernel_oversampling , uvscale [ 0 ] * uv [..., 0 ])
344+
345+ # uvw -> fraction of grid ampping
346+ # uvw -> fraction of grid mapping
347+ y , yf = frac_coord ( ny , kernel_oversampling , vuvwmap [:, 1 ])
348+ x , xf = frac_coord (nx , kernel_oversampling , vuvwmap [:, 0 ])
349+
349350 # Now calculate slices for the footprint of each sample
350351 slicey = []
351352 slicex = []
352353 for xx in x :
353354 slicex .append (slice ((xx - gw // 2 ), (xx + (gw + 1 ) // 2 )))
354355 for yy in y :
355356 slicey .append (slice ((yy - gh // 2 ), (yy + (gh + 1 ) // 2 )))
356- coords = slicex , xf , slicey , yf
357+
357358 # Now we can degrid the points and accumulate weight as well
358- vis [...] = [
359- numpy .sum (uvgrid [ichan , ipol , sly , slx ] * kernel [yf , xf , :, :])
360- for slx , xf , sly , yf in zip (* coords )
361- ]
362- wt [...] = [numpy .sum (kernel [yf , xf , :, :].real ) for x , xf , y , yf in zip (* coords )]
359+ if len (kernels ) > 1 :
360+
361+ coords = list (vfrequencymap ), list (vpolarisationmap ), slicex , xf , slicey , yf
362+ vis [...] = [
363+ numpy .sum (uvgrid [ic , ip , sly , slx ] * kernel [yf , xf , :, :])
364+ for kernel , ic , ip , slx , xf , sly , yf in zip (kernels , * coords )
365+ ]
366+
367+ wt [...] = [
368+ numpy .sum (kernel [yf , xf , :, :].real )
369+ for kernel , ic , ip , slx , xf , sly , yf in zip (kernels , * coords )
370+ ]
371+ else :
372+ kernel = kernels [0 ]
373+
374+ coords = list (vfrequencymap ), list (vpolarisationmap ), slicex , xf , slicey , yf
375+ vis [...] = [
376+ numpy .sum (uvgrid [ic , ip , sly , slx ] * kernel [yf , xf , :, :])
377+ for ic , ip , slx , xf , sly , yf in zip (* coords )
378+ ]
379+ wt [...] = [
380+ numpy .sum (kernel [yf , xf , :, :].real )
381+ for ic , ip , slx , xf , sly , yf in zip (* coords )
382+ ]
383+
363384 vis [numpy .where (wt > 0 )] = vis [numpy .where (wt > 0 )] / wt [numpy .where (wt > 0 )]
364385 vis [numpy .where (wt < 0 )] = 0.0
365386 return numpy .array (vis )
@@ -381,7 +402,7 @@ def gridder(uvgrid, vis, xs, ys, kernel=numpy.ones((1,1)), kernel_ixs=None):
381402 """
382403
383404 if kernel_ixs is None :
384- kernel_ixs = numpy .zeroes ((len (vis ),0 ))
405+ kernel_ixs = numpy .zeros ((len (vis ),0 ))
385406 else :
386407 kernel_ixs = numpy .array (kernel_ixs )
387408 if len (kernel_ixs .shape ) == 1 :
@@ -392,134 +413,107 @@ def gridder(uvgrid, vis, xs, ys, kernel=numpy.ones((1,1)), kernel_ixs=None):
392413 uvgrid [y :y + gh , x :x + gw ] += kernel [tuple (kern_ix )] * v
393414
394415
395- def fixed_kernel_grid (kernel , uvgrid , uv , frequency , polarisation , uvscale , vis , visweights ,
396- vpolmap = lambda pol : pol , vchanmap = lambda frequency : 0 ):
416+ def fixed_kernel_grid (kernels , uvgrid , vis , visweights , vuvwmap , vfrequencymap ,
417+ vpolarisationmap ):
397418 """Grid after convolving with frequency and polarisation independent gcf
398419
399420 Takes into account fractional `uv` coordinate values where the GCF
400421 is oversampled
401422
402- :param kernel: Oversampled convolution kernel
423+ :param kernel: List of versampled convolution kernels
403424 :param uvgrid: Grid to add to
404- :param uv: UVW positions
405- :param uvscale: Scaling for each axis (u,v) for each channel
425+ :param uvw: UVW positions
406426 :param vis: CompressedVisibility values
407427 :param vis: CompressedVisibility weights
428+ :param vuvwmap: map uvw to grid fractions
429+ :param vfrequencymap: map frequency to image channels
430+ :param vpolarisationwmap: map polarisation to image polarisation
408431 :returns: uv grid[nchan, npol, ny, nx], sumwt[nchan, npol]
409432 """
410433
411- kernel_oversampling , _ , gh , gw = kernel .shape
434+ kernels = list (kernels )
435+ kernel_oversampling , _ , gh , gw = kernels [0 ].shape
412436 assert gh % 2 == 0 , "Convolution kernel must have even number of pixels"
413437 assert gw % 2 == 0 , "Convolution kernel must have even number of pixels"
414438 inchan , inpol , ny , nx = uvgrid .shape
415- nvis , vnchan , vnpol = vis .shape
416- assert vnpol == inpol , "Number of polarizations must be the same"
417- wtgrid = numpy .zeros (uvgrid .shape , dtype = 'float' )
439+
440+ # Construct output grids (in uv space)
418441 sumwt = numpy .zeros ([inchan , inpol ])
419- ichan = vchanmap (frequency )
420- ipol = vpolmap (polarisation )
421- y , yf = frac_coord (ny , kernel_oversampling , uvscale [1 ] * uv [..., 1 ])
422- x , xf = frac_coord (nx , kernel_oversampling , uvscale [0 ] * uv [..., 0 ])
442+
443+ # uvw -> fraction of grid mapping
444+ # vuvwmap is a list of generators, one per axis so we need to
445+ # select a generator and then instantiate it by making it into
446+ # a list, and finally use the values. This defers filling out
447+ # the arrays until they are needed.
448+ y , yf = frac_coord (ny , kernel_oversampling , vuvwmap [:,1 ])
449+ x , xf = frac_coord (nx , kernel_oversampling , vuvwmap [:,0 ])
450+
451+ # Construct all the slices that we will need: trade off memory to
452+ # simplify loop
423453 slicey = []
424454 slicex = []
425455 for xx in x :
426456 slicex .append (slice ((xx - gw // 2 ), (xx + (gw + 1 ) // 2 )))
427457 for yy in y :
428458 slicey .append (slice ((yy - gh // 2 ), (yy + (gh + 1 ) // 2 )))
429- coords = slicex , xf , slicey , yf
459+
460+ # Now we can loop over all rows
430461 wts = visweights [...]
431462 viswt = vis [...] * visweights [...]
432- coords = ichan , ipol , slicex , xf , slicey , yf
433- for v , vwt , ic , ip , slx , xf , sly , yf in zip (viswt , wts , * coords ):
434- uvgrid [ic , ip , sly , slx ] += kernel [yf , xf , :, :] * v
435- wtgrid [ic , ip , sly , slx ] += kernel [yf , xf , :, :].real * vwt
436- sumwt [ichan , ipol ] += numpy .sum (wtgrid [ichan , ipol , ...])
437-
438- return uvgrid , sumwt
439-
463+ # There are two cases:row independent and row dependent kernel. We try to make these as
464+ # similar as possible
465+ if len (kernels ) > 1 :
466+
467+ coords = list (vfrequencymap ), list (vpolarisationmap ), slicex , xf , slicey , yf
468+ for v , vwt , kernel , ic , ip , slx , xf , sly , yf in zip (viswt , wts , kernels , * coords ):
469+ uvgrid [ic , ip , sly , slx ] += kernel [yf , xf , :, :] * v
470+ sumwt [ic , ip ] += numpy .sum (kernel [yf , xf , :, :].real * vwt )
471+ else :
472+ kernel = kernels [0 ]
440473
441- def box_grid (kernel , uvgrid , uv , frequency , polarisation , uvscale , vis , visweights , vpolmap = lambda pol : pol ,
442- vchanmap = lambda chan : chan ):
443- """Grid with a box function
474+ coords = list (vfrequencymap ), list (vpolarisationmap ), slicex , xf , slicey , yf
475+ for v , vwt , ic , ip , slx , xf , sly , yf in zip (viswt , wts , * coords ):
476+ uvgrid [ic , ip , sly , slx ] += kernel [yf , xf , :, :] * v
477+ sumwt [ic , ip ] += numpy .sum (kernel [yf , xf , :, :].real * vwt )
444478
445- Takes into account fractional `uv` coordinate values where the GCF
446- is oversampled
447-
448- :param kernel: Oversampled convolution kernel
449- :param uvgrid: Grid to add to
450- :param uv: UVW positions
451- :param uvscale: Scaling for each axis (u,v) for each channel
452- :param vis: CompressedVisibility values
453- :param vis: CompressedVisibility weights
454- :param chanmap: function to map visibility channels to image channels
455- """
456-
457- inchan , inpol , ny , nx = uvgrid .shape
458- nvis , vnchan , vnpol = vis .shape
459- assert vnpol == inpol , "Number of polarizations must be the same"
460- wtgrid = numpy .zeros (uvgrid .shape , dtype = 'float' )
461- sumwt = numpy .zeros ([inchan , inpol ])
462- ichan = vchanmap (frequency )
463- ipol = vpolmap (polarisation )
464- y , _ = frac_coord (ny , 1 , uvscale [1 ] * uv [..., 1 ])
465- x , _ = frac_coord (nx , 1 , uvscale [0 ] * uv [..., 0 ])
466- coords = frequency , polarisation , x , y
467- wts = visweights [...]
468- viswt = vis [...] * visweights [...]
469- for v , vwt , ic , ip , x , y in zip (viswt , wts , * coords ):
470- uvgrid [ic , ip , y , x ] += v
471- wtgrid [ic , ip , y , x ] += vwt
472- sumwt = numpy .sum (wtgrid , axis = (2 ,3 ))
473-
474479 return uvgrid , sumwt
475480
476481
477- def weight_gridding (shape , uv , uvscale , visweights , weighting = 'uniform' ,
478- vpolmap = lambda pol : pol , vchanmap = lambda chan : chan ):
482+ def weight_gridding (shape , visweights , vuvwmap , vfrequencymap , vpolarisationmap , weighting = 'uniform' ):
479483 """Reweight data using one of a number of algorithms
480484
481485 Takes into account fractional `uv` coordinate values where the GCF
482486 is oversampled
483487
484488 :param shape:
485- :param uv: UVW positions
486- :param uvscale: Scaling for each axis (u,v) for each channel
489+ :param uvw: UVW positions
487490 :param vis: CompressedVisibility values
488- :param visweights: CompressedVisibility weights
489- :param weighting: Weighting algorithm (natural|uniform) (uniform)
490- :param vpolmap = lambda pol: pol, vchanmap: function to map visibility channels to image channels
491+ :param vis: CompressedVisibility weights
492+ :param vuvwmap: map uvw to grid fractions
493+ :param vfrequencymap: map frequency to image channels
494+ :param vpolarisationwmap: map polarisation to image polarisation
495+ :returns: visweights, density, desnitygrid
491496 """
492- densitygrid = numpy .zeros (shape )
497+ wtgrid = numpy .zeros (shape )
493498 density = numpy .zeros_like (visweights )
494499 if weighting == 'uniform' :
495500 log .info ("weight_gridding: Performing uniform weighting" )
496501 inchan , inpol , ny , nx = shape
497- nvis , vnchan , vnpol = visweights .shape
498- # Add all visibility points to a float grid
499- for vchan in range (vnchan ):
500- ichan = vpolmap = lambda pol : pol , vchanmap (vchan )
501- y , _ = frac_coord (ny , 1 , uvscale [1 ] * uv [..., 1 ])
502- x , _ = frac_coord (nx , 1 , uvscale [0 ] * uv [..., 0 ])
503- coords = x , y
504- for pol in range (vnpol ):
505- wts = visweights [..., vchan , pol ]
506- for wt , x , y , in zip (wts , * coords ):
507- densitygrid [ichan , pol , y , x ] += wt
508- # for i in range(visweights[..., chan, pol].shape[0]):
509- # densitygrid[chan, pol, y[i], x[i]] += wts[i]
510-
502+
503+ # uvw -> fraction of grid mapping
504+ # uvw -> fraction of grid mapping
505+ y , yf = frac_coord (ny , 1.0 , vuvwmap [:, 1 ])
506+ x , xf = frac_coord (nx , 1.0 , vuvwmap [:, 0 ])
507+ wts = visweights [...]
508+ coords = list (vfrequencymap ), list (vpolarisationmap ), x , y
509+ for vwt , ic , ip , x , y in zip (wts , * coords ):
510+ wtgrid [ic , ip , y , x ] += vwt
511+
511512 # Normalise each visibility weight to sum to one in a grid cell
512513 newvisweights = numpy .zeros_like (visweights )
513- for vchan in range (vnchan ):
514- ichan = vpolmap = lambda pol : pol , vchanmap (vchan )
515- coords = frac_coord (shape [3 ], 1 , uvscale [1 ] * uv [..., 1 ]), \
516- frac_coord (shape [2 ], 1 , uvscale [0 ] * uv [..., 0 ])
517- for pol in range (vnpol ):
518- wts = visweights [..., vchan , pol ]
519- for wt , x , y in zip (wts , * coords ):
520- density [..., vchan , pol ] += densitygrid [ichan , pol , y , x ]
521- newvisweights [..., vchan , pol ][densitygrid [ichan , pol , y , x ] > 0.0 ] = \
522- wt / densitygrid [ichan , pol , y , x ][densitygrid [ichan , pol , y , x ] > 0.0 ]
523- return newvisweights , density , densitygrid
514+ for wt , ic , ip , x , y in zip (wts , * coords ):
515+ density [...] += wtgrid [ic , ip , y , x ]
516+ newvisweights [...] = wt / wtgrid [ic , ip , y , x ][wtgrid [ic , ip , y , x ] > 0.0 ]
517+ return newvisweights , density , wtgrid
524518 else :
525- return visweights , density , densitygrid
519+ return visweights , density , wtgrid
0 commit comments