Commit a6e1eb4f authored by Martin Reinecke's avatar Martin Reinecke
Browse files

Merge branch 'wsclean_adjustments' into 'master'

Wsclean adjustments

See merge request !28
parents 38f63ce9 eb9f681c
......@@ -152,27 +152,6 @@ template<typename T, size_t ndim> const_mav<T, ndim> nullmav()
shp.fill(0);
return const_mav<T, ndim>(nullptr, shp);
}
template<typename T, size_t ndim> class tmpStorage
{
private:
vector<T> d;
mav<T,ndim> mav_;
static size_t prod(const array<size_t,ndim> &shp)
{
size_t res=1;
for (auto v: shp) res*=v;
return res;
}
public:
tmpStorage(const array<size_t,ndim> &shp)
: d(prod(shp)), mav_(d.data(), shp) {}
mav<T,ndim> &getMav() { return mav_; }
const_mav<T,ndim> getCmav() { return cmav(mav_); }
void fill(const T & val)
{ std::fill(d.begin(), d.end(), val); }
};
//
// basic utilities
......@@ -239,6 +218,28 @@ template<size_t ndim> void checkShape
template<typename T> inline T fmod1 (T v)
{ return v-floor(v); }
template<typename T, size_t ndim> class tmpStorage
{
private:
vector<T> d;
mav<T,ndim> mav_;
static size_t prod(const array<size_t,ndim> &shp)
{
size_t res=1;
for (auto v: shp) res*=v;
return res;
}
public:
tmpStorage(const array<size_t,ndim> &shp)
: d(prod(shp)), mav_(d.data(), shp) {}
mav<T,ndim> &getMav() { return mav_; }
const_mav<T,ndim> getCmav() { return cmav(mav_); }
void fill(const T & val)
{ std::fill(d.begin(), d.end(), val); }
};
//
// Utilities for Gauss-Legendre quadrature
//
......@@ -254,8 +255,8 @@ void legendre_prep(int n, vector<double> &x, vector<double> &w, size_t nthreads)
x.resize(m);
w.resize(m);
double t0 = 1 - (1-1./n) / (8.*n*n);
double t1 = 1./(4.*n+2.);
const double t0 = 1 - (1-1./n) / (8.*n*n);
const double t1 = 1./(4.*n+2.);
#pragma omp parallel num_threads(nthreads)
{
......@@ -381,14 +382,17 @@ class ES_Kernel
size_t supp;
public:
ES_Kernel(size_t supp_, size_t nthreads)
: beta(get_beta(supp_)*supp_), p(int(1.5*supp_+2)), supp(supp_)
ES_Kernel(size_t supp_, double ofactor, size_t nthreads)
: beta(get_beta(supp_,ofactor)*supp_), p(int(1.5*supp_+2)), supp(supp_)
{
legendre_prep(2*p,x,wgt,nthreads);
psi=x;
for (auto &v:psi)
v=operator()(v);
}
ES_Kernel(size_t supp_, size_t nthreads)
: ES_Kernel(supp_, 2., nthreads){}
double operator()(double v) const { return exp(beta*(sqrt(1.-v*v)-1.)); }
/* Compute correction factors for the ES gridding kernel
This implementation follows eqs. (3.8) to (3.10) of Barnett et al. 2018 */
......@@ -399,33 +403,59 @@ class ES_Kernel
tmp += wgt[i]*psi[i]*cos(pi*supp*v*x[i]);
return 1./(supp*tmp);
}
static double get_beta(size_t supp)
static double get_beta(size_t supp, double ofactor=2)
{
static const vector<double> opt_beta {-1, 0.14, 1.70, 2.08, 2.205, 2.26,
2.29, 2.307, 2.316, 2.3265, 2.3324, 2.282, 2.294, 2.304, 2.3138, 2.317};
myassert(supp<opt_beta.size(), "bad support size");
return opt_beta[supp];
myassert((supp>=2) && (supp<=15), "unsupported support size");
if (ofactor>=2)
{
static const vector<double> opt_beta {-1, 0.14, 1.70, 2.08, 2.205, 2.26,
2.29, 2.307, 2.316, 2.3265, 2.3324, 2.282, 2.294, 2.304, 2.3138, 2.317};
myassert(supp<opt_beta.size(), "bad support size");
return opt_beta[supp];
}
if (ofactor>=1.2)
{
// empirical, but pretty accurate approximation
static const array<double,16> betacorr{0,0,-0.51,-0.21,-0.1,-0.05,-0.025,-0.0125,0,0,0,0,0,0,0,0};
auto x0 = 1./(2*ofactor);
auto bcstrength=1.+(x0-0.25)*2.5;
return 2.32+bcstrength*betacorr[supp]+(0.25-x0)*3.1;
}
myfail("oversampling factor is too small");
}
static size_t get_supp(double epsilon)
static size_t get_supp(double epsilon, double ofactor=2)
{
static const vector<double> maxmaperr { 1e8, 0.19, 2.98e-3, 5.98e-5,
1.11e-6, 2.01e-8, 3.55e-10, 5.31e-12, 8.81e-14, 1.34e-15, 2.17e-17,
2.12e-19, 2.88e-21, 3.92e-23, 8.21e-25, 7.13e-27 };
double epssq = epsilon*epsilon;
if (ofactor>=2)
{
static const vector<double> maxmaperr { 1e8, 0.19, 2.98e-3, 5.98e-5,
1.11e-6, 2.01e-8, 3.55e-10, 5.31e-12, 8.81e-14, 1.34e-15, 2.17e-17,
2.12e-19, 2.88e-21, 3.92e-23, 8.21e-25, 7.13e-27 };
for (size_t i=1; i<maxmaperr.size(); ++i)
if (epssq>maxmaperr[i]) return i;
myfail("requested epsilon too small - minimum is 1e-13");
for (size_t i=1; i<maxmaperr.size(); ++i)
if (epssq>maxmaperr[i]) return i;
myfail("requested epsilon too small - minimum is 1e-13");
}
if (ofactor>=1.2)
{
for (size_t w=2; w<16; ++w)
{
auto estimate = 12*exp(-2.*w*ofactor); // empirical, not very good approximation
if (epssq>estimate) return w;
}
myfail("requested epsilon too small");
}
myfail("oversampling factor is too small");
}
};
/* Compute correction factors for the ES gridding kernel
This implementation follows eqs. (3.8) to (3.10) of Barnett et al. 2018 */
vector<double> correction_factors(size_t n, size_t nval, size_t supp,
vector<double> correction_factors(size_t n, double ofactor, size_t nval, size_t supp,
size_t nthreads)
{
ES_Kernel kernel(supp, nthreads);
ES_Kernel kernel(supp, ofactor, nthreads);
vector<double> res(nval);
double xn = 1./n;
#pragma omp parallel for schedule(static) num_threads(nthreads)
......@@ -467,7 +497,7 @@ class Baselines
public:
template<typename T> Baselines(const const_mav<T,2> &coord_,
const const_mav<T,1> &freq)
const const_mav<T,1> &freq, bool negate_v=false)
{
constexpr double speedOfLight = 299792458.;
myassert(coord_.shape(1)==3, "dimension mismatch");
......@@ -488,8 +518,12 @@ class Baselines
f_over_c[i] = freq(i)/speedOfLight;
}
coord.resize(nrows);
for (size_t i=0; i<coord.size(); ++i)
coord[i] = UVW(coord_(i,0), coord_(i,1), coord_(i,2));
if (negate_v)
for (size_t i=0; i<coord.size(); ++i)
coord[i] = UVW(coord_(i,0), -coord_(i,1), coord_(i,2));
else
for (size_t i=0; i<coord.size(); ++i)
coord[i] = UVW(coord_(i,0), coord_(i,1), coord_(i,2));
}
RowChan getRowChan(idx_t index) const
......@@ -550,56 +584,68 @@ class Baselines
class GridderConfig
{
protected:
size_t nx_dirty, ny_dirty;
double eps, psx, psy;
size_t supp, nsafe, nu, nv;
size_t nx_dirty, ny_dirty, nu, nv;
double ofactor, eps, psx, psy;
size_t supp, nsafe;
double beta;
vector<double> cfu, cfv;
size_t nthreads;
double ushift, vshift;
int maxiu0, maxiv0;
complex<double> wscreen(double x, double y, double w, bool adjoint) const
complex<double> wscreen(double x, double y, double w, bool adjoint,
bool divide_by_n) const
{
constexpr double pi = 3.141592653589793238462643383279502884197;
double tmp = 1-x-y;
if (tmp<0) return 0.;
double nm1 = (-x-y)/(sqrt(tmp)+1); // more accurate form of sqrt(1-x-y)
double n = nm1+1., xn = 1./n;
if (tmp<=0) return divide_by_n ? 0. : 1.; // no phase factor beyond the horizon
double nm1 = (-x-y)/(sqrt(tmp)+1); // more accurate form of sqrt(1-x-y)-1
double phase = 2*pi*w*nm1;
if (adjoint) phase *= -1;
double xn = divide_by_n ? 1./(nm1+1) : 1;
return complex<double>(cos(phase)*xn, sin(phase)*xn);
}
public:
GridderConfig(size_t nxdirty, size_t nydirty, double epsilon,
double pixsize_x, double pixsize_y, size_t nthreads_)
: nx_dirty(nxdirty), ny_dirty(nydirty), eps(epsilon),
GridderConfig(size_t nxdirty, size_t nydirty, size_t nu_, size_t nv_,
double epsilon, double pixsize_x, double pixsize_y, size_t nthreads_)
: nx_dirty(nxdirty), ny_dirty(nydirty), nu(nu_), nv(nv_),
ofactor(min(double(nu)/nxdirty, double(nv)/nydirty)),
eps(epsilon),
psx(pixsize_x), psy(pixsize_y),
supp(ES_Kernel::get_supp(epsilon)), nsafe((supp+1)/2),
nu(max(2*nsafe,2*nx_dirty)), nv(max(2*nsafe,2*ny_dirty)),
beta(ES_Kernel::get_beta(supp)*supp),
supp(ES_Kernel::get_supp(epsilon, ofactor)), nsafe((supp+1)/2),
beta(ES_Kernel::get_beta(supp, ofactor)*supp),
cfu(nx_dirty), cfv(ny_dirty), nthreads(nthreads_),
ushift(supp*(-0.5)+1+nu), vshift(supp*(-0.5)+1+nv),
maxiu0((nu+nsafe)-supp), maxiv0((nv+nsafe)-supp)
{
myassert(nu>=2*nsafe, "nu too small");
myassert(nv>=2*nsafe, "nv too small");
myassert((nx_dirty&1)==0, "nx_dirty must be even");
myassert((ny_dirty&1)==0, "ny_dirty must be even");
myassert((nu&1)==0, "nu must be even");
myassert((nv&1)==0, "nv must be even");
myassert(epsilon>0, "epsilon must be positive");
myassert(pixsize_x>0, "pixsize_x must be positive");
myassert(pixsize_y>0, "pixsize_y must be positive");
myassert(ofactor>=1.2, "oversampling factor smaller than 1.2");
auto tmp = correction_factors(nu, nx_dirty/2+1, supp, nthreads);
auto tmp = correction_factors(nu, ofactor, nx_dirty/2+1, supp, nthreads);
cfu[nx_dirty/2]=tmp[0];
cfu[0]=tmp[nx_dirty/2];
for (size_t i=1; i<nx_dirty/2; ++i)
cfu[nx_dirty/2-i] = cfu[nx_dirty/2+i] = tmp[i];
tmp = correction_factors(nv, ny_dirty/2+1, supp, nthreads);
tmp = correction_factors(nv, ofactor, ny_dirty/2+1, supp, nthreads);
cfv[ny_dirty/2]=tmp[0];
cfv[0]=tmp[ny_dirty/2];
for (size_t i=1; i<ny_dirty/2; ++i)
cfv[ny_dirty/2-i] = cfv[ny_dirty/2+i] = tmp[i];
}
GridderConfig(size_t nxdirty, size_t nydirty,
double epsilon, double pixsize_x, double pixsize_y, size_t nthreads_)
: GridderConfig(nxdirty, nydirty, max<size_t>(30,2*nxdirty),
max<size_t>(30,2*nydirty), epsilon, pixsize_x,
pixsize_y, nthreads_) {}
size_t Nxdirty() const { return nx_dirty; }
size_t Nydirty() const { return ny_dirty; }
double Epsilon() const { return eps; }
......@@ -611,6 +657,7 @@ class GridderConfig
size_t Nsafe() const { return nsafe; }
double Beta() const { return beta; }
size_t Nthreads() const { return nthreads; }
double Ofactor() const{ return ofactor; }
template<typename T> void apply_taper(const mav<const T,2> &img, mav<T,2> &img2, bool divide) const
{
......@@ -716,31 +763,69 @@ class GridderConfig
}
template<typename T> void apply_wscreen(const const_mav<complex<T>,2> &dirty,
mav<complex<T>,2> &dirty2, double w, bool adjoint) const
mav<complex<T>,2> &dirty2, double w, bool adjoint, bool divide_by_n) const
{
checkShape(dirty.shape(), {nx_dirty, ny_dirty});
checkShape(dirty2.shape(), {nx_dirty, ny_dirty});
double x0 = -0.5*nx_dirty*psx,
y0 = -0.5*ny_dirty*psy;
#pragma omp parallel for num_threads(nthreads) schedule(static)
for (size_t i=0; i<=nx_dirty/2; ++i)
#if 0
if ((nx_dirty==ny_dirty) && (psx==psy)) // extra symmetry
{
double p0 = -0.5*nx_dirty*psx;
#pragma omp parallel for num_threads(nthreads) schedule(dynamic,10)
for (size_t i=0; i<=nx_dirty/2; ++i)
{
double fx = p0+i*psx;
fx *= fx;
for (size_t j=0; j<=i; ++j)
{
double fy = p0+j*psy;
auto ws = complex<T>(wscreen(fx, fy*fy, w, adjoint, divide_by_n));
dirty2(i,j) = dirty(i,j)*ws; // lower left
if (j!=i) dirty2(j,i) = dirty(j,i)*ws; // lower left
size_t i2 = nx_dirty-i, j2 = ny_dirty-j;
if ((i>0)&&(i<i2))
{
dirty2(i2,j) = dirty(i2,j)*ws; // lower right
if (i!=j) dirty2(j,i2) = dirty(j,i2)*ws; // lower right
if ((j>0)&&(j<j2))
{
dirty2(i2,j2) = dirty(i2,j2)*ws; // upper right
if (i!=j) dirty2(j2,i2) = dirty(j2,i2)*ws; // upper right
}
}
if ((j>0)&&(j<j2))
{
dirty2(i,j2) = dirty(i,j2)*ws; // upper left
if (i!=j) dirty2(j2,i) = dirty(j2,i)*ws; // upper left
}
}
}
}
else
#endif
{
double fx = x0+i*psx;
fx *= fx;
for (size_t j=0; j<=ny_dirty/2; ++j)
double x0 = -0.5*nx_dirty*psx,
y0 = -0.5*ny_dirty*psy;
#pragma omp parallel for num_threads(nthreads) schedule(static)
for (size_t i=0; i<=nx_dirty/2; ++i)
{
double fy = y0+j*psy;
auto ws = complex<T>(wscreen(fx, fy*fy, w, adjoint));
dirty2(i,j) = dirty(i,j)*ws; // lower left
size_t i2 = nx_dirty-i, j2 = ny_dirty-j;
if ((i>0)&&(i<i2))
double fx = x0+i*psx;
fx *= fx;
for (size_t j=0; j<=ny_dirty/2; ++j)
{
dirty2(i2,j) = dirty(i2,j)*ws; // lower right
double fy = y0+j*psy;
auto ws = complex<T>(wscreen(fx, fy*fy, w, adjoint, divide_by_n));
dirty2(i,j) = dirty(i,j)*ws; // lower left
size_t i2 = nx_dirty-i, j2 = ny_dirty-j;
if ((i>0)&&(i<i2))
{
dirty2(i2,j) = dirty(i2,j)*ws; // lower right
if ((j>0)&&(j<j2))
dirty2(i2,j2) = dirty(i2,j2)*ws; // upper right
}
if ((j>0)&&(j<j2))
dirty2(i2,j2) = dirty(i2,j2)*ws; // upper right
dirty2(i,j2) = dirty(i,j2)*ws; // upper left
}
if ((j>0)&&(j<j2))
dirty2(i,j2) = dirty(i,j2)*ws; // upper left
}
}
}
......@@ -803,8 +888,6 @@ template<typename T, typename T2=complex<T>> class Helper
{
if (bu0<-nsafe) return; // nothing written into buffer yet
#pragma omp critical (gridder_writing_to_grid)
{
int idxu = (bu0+nu)%nu;
int idxv0 = (bv0+nv)%nv;
for (int iu=0; iu<su; ++iu)
......@@ -819,7 +902,6 @@ template<typename T, typename T2=complex<T>> class Helper
locks[idxu].unlock();
if (++idxu>=nu) idxu=0;
}
}
}
void load()
......@@ -1279,8 +1361,13 @@ template<typename T> void apply_wcorr(const GridderConfig &gconf,
double tmp = 1.-fx-fy;
if (tmp>=0)
{
auto nm1 = (-fx-fy)/(sqrt(1.-fx-fy)+1.); // accurate form of sqrt(1-x-y)
fct = T((nm1<=-1) ? 0. : kernel.corfac(nm1*dw));
auto nm1 = (-fx-fy)/(sqrt(tmp)+1.); // accurate form of sqrt(1-x-y)-1
fct = T(kernel.corfac(nm1*dw));
}
else // beyond the horizon, don't really know what to do here
{
double nm1 = sqrt(-tmp)-1;
fct = T(kernel.corfac(nm1*dw));
}
size_t i2 = nx_dirty-i, j2 = ny_dirty-j;
dirty(i,j)*=fct;
......@@ -1367,9 +1454,12 @@ template<typename Serv> class WgridHelper
if (verbosity>0) cout << "Using single-threaded mode" << endl;
#endif
if (verbosity>0) cout << "W range: " << wmin << " to " << wmax << endl;
double x0 = -0.5*gconf.Nxdirty()*gconf.Pixsize_x(),
y0 = -0.5*gconf.Nydirty()*gconf.Pixsize_y();
double nmin = sqrt(max(1.-x0*x0-y0*y0,0.))-1.;
if (x0*x0+y0*y0>1.)
nmin = -sqrt(abs(1.-x0*x0-y0*y0))-1.;
dw = 0.25/abs(nmin);
nplanes = size_t((wmax-wmin)/dw+2);
dw = (1.+1e-13)*(wmax-wmin)/(nplanes-1);
......@@ -1382,6 +1472,15 @@ template<typename Serv> class WgridHelper
if (verbosity>0) cout << "nplanes: " << nplanes << endl;
minplane.resize(nplanes);
#if 0
// extra short, but potentially inefficient version:
for (size_t ipart=0; ipart<nvis; ++ipart)
{
int plane0 = max(0,int(1+(abs(srv.getCoord(ipart).w)-(0.5*supp*dw)-wmin)/dw));
minplane[plane0].push_back(idx_t(ipart));
}
#else
// full fledged, overdesigned OpenMP version
vector<size_t> tcnt(max<int>(nthreads, my_max_threads())*nplanes,0);
#pragma omp parallel num_threads(nthreads)
{
......@@ -1417,6 +1516,7 @@ template<typename Serv> class WgridHelper
minplane[plane0][myofs[plane0]++]=idx_t(ipart);
}
}
#endif
}
typename Serv::Tsub getSubserv() const
......@@ -1459,14 +1559,14 @@ template<typename T, typename Serv> void x2dirty(
grid.fill(0);
x2grid_c(gconf, hlp.getSubserv(), grid, hlp.W(), dw);
gconf.grid2dirty_c_overwrite(grid, tdirty);
gconf.apply_wscreen(cmav(tdirty), tdirty, hlp.W(), true);
gconf.apply_wscreen(cmav(tdirty), tdirty, hlp.W(), true, true);
#pragma omp parallel for num_threads(nthreads)
for (size_t i=0; i<gconf.Nxdirty(); ++i)
for (size_t j=0; j<gconf.Nydirty(); ++j)
dirty(i,j) += tdirty(i,j).real();
}
// correct for w gridding
apply_wcorr(gconf, dirty, ES_Kernel(gconf.Supp(), nthreads), dw);
apply_wcorr(gconf, dirty, ES_Kernel(gconf.Supp(), gconf.Ofactor(), nthreads), dw);
}
else
{
......@@ -1511,7 +1611,7 @@ template<typename T, typename Serv> void dirty2x(
for (size_t j=0; j<ny_dirty; ++j)
tdirty(i,j) = dirty(i,j);
// correct for w gridding
apply_wcorr(gconf, tdirty, ES_Kernel(gconf.Supp(), nthreads), dw);
apply_wcorr(gconf, tdirty, ES_Kernel(gconf.Supp(), gconf.Ofactor(), nthreads), dw);
tmpStorage<complex<T>,2> grid_({gconf.Nu(),gconf.Nv()});
auto grid=grid_.getMav();
tmpStorage<complex<T>,2> tdirty2_({nx_dirty, ny_dirty});
......@@ -1524,7 +1624,7 @@ template<typename T, typename Serv> void dirty2x(
for (size_t i=0; i<nx_dirty; ++i)
for (size_t j=0; j<ny_dirty; ++j)
tdirty2(i,j) = tdirty(i,j);
gconf.apply_wscreen(cmav(tdirty2), tdirty2, hlp.W(), false);
gconf.apply_wscreen(cmav(tdirty2), tdirty2, hlp.W(), false, true);
gconf.dirty2grid_c(cmav(tdirty2), grid);
grid2x_c(gconf, cmav(grid), hlp.getSubserv(), hlp.W(), dw);
......@@ -1619,7 +1719,7 @@ void fillIdx(const Baselines &baselines,
size_t lo, hi;
calc_share(nthr, id, nrow, lo, hi);
vector<idx_t> &lacc(acc[id]);
lacc.resize(nbu*nbv+1, 0);
lacc.assign(nbu*nbv+1, 0);
for (idx_t irow=lo, idx=lo*(chend-chbegin); irow<hi; ++irow)
for (int ichan=chbegin; ichan<chend; ++ichan, ++idx)
......@@ -1666,13 +1766,16 @@ void fillIdx(const Baselines &baselines,
}
template<typename T> vector<idx_t> getWgtIndices(const Baselines &baselines,
const GridderConfig &gconf, const const_mav<T,2> &wgt)
const GridderConfig &gconf, const const_mav<T,2> &wgt,
const const_mav<complex<T>,2> &ms)
{
size_t nrow=baselines.Nrows(),
nchan=baselines.Nchannels(),
nsafe=gconf.Nsafe();
bool have_wgt=wgt.size()!=0;
if (have_wgt) checkShape(wgt.shape(),{nrow,nchan});
bool have_ms=ms.size()!=0;
if (have_ms) checkShape(ms.shape(), {nrow,nchan});
constexpr int side=1<<logsquare;
size_t nbu = (gconf.Nu()+1+side-1) >> logsquare,
nbv = (gconf.Nv()+1+side-1) >> logsquare;
......@@ -1690,10 +1793,11 @@ template<typename T> vector<idx_t> getWgtIndices(const Baselines &baselines,
size_t lo, hi;
calc_share(nthr, id, nrow, lo, hi);
vector<idx_t> &lacc(acc[id]);
lacc.resize(nbu*nbv+1, 0);
lacc.assign(nbu*nbv+1, 0);
for (idx_t irow=lo, idx=lo*nchan; irow<hi; ++irow)
for (idx_t ichan=0; ichan<nchan; ++ichan, ++idx)
if ((!have_wgt) || (wgt(irow,ichan)!=0))
if (((!have_ms ) || (norm(ms (irow,ichan))!=0)) &&
((!have_wgt) || (wgt(irow,ichan)!=0)))
{
auto uvw = baselines.effectiveCoord(RowChan{irow,idx_t(ichan)});
if (uvw.w<0) uvw.Flip();
......@@ -1732,30 +1836,51 @@ template<typename T> vector<idx_t> getWgtIndices(const Baselines &baselines,
return res;
}
template<typename T> void ms2dirty_general(const const_mav<double,2> &uvw,
const const_mav<double,1> &freq, const const_mav<complex<T>,2> &ms,
const const_mav<T,2> &wgt, double pixsize_x, double pixsize_y, size_t nu, size_t nv, double epsilon,
bool do_wstacking, size_t nthreads, const mav<T,2> &dirty, size_t verbosity,
bool negate_v=false)
{
Baselines baselines(uvw, freq, negate_v);
GridderConfig gconf(dirty.shape(0), dirty.shape(1), nu, nv, epsilon, pixsize_x, pixsize_y, nthreads);
auto idx = getWgtIndices(baselines, gconf, wgt, ms);
auto idx2 = const_mav<idx_t,1>(idx.data(),{idx.size()});
x2dirty(gconf, makeMsServ(baselines,idx2,ms,wgt), dirty, do_wstacking, verbosity);
}
template<typename T> void ms2dirty(const const_mav<double,2> &uvw,
const const_mav<double,1> &freq, const const_mav<complex<T>,2> &ms,
const const_mav<T,2> &wgt, double pixsize_x, double pixsize_y, double epsilon,
bool do_wstacking, size_t nthreads, const mav<T,2> &dirty, size_t verbosity)
{
Baselines baselines(uvw, freq);
GridderConfig gconf(dirty.shape(0), dirty.shape(1), epsilon, pixsize_x, pixsize_y, nthreads);
auto idx = getWgtIndices(baselines, gconf, wgt);
auto idx2 = const_mav<idx_t,1>(idx.data(),{idx.size()});
x2dirty(gconf, makeMsServ(baselines,idx2,ms,wgt), dirty, do_wstacking, verbosity);
ms2dirty_general(uvw, freq, ms, wgt, pixsize_x, pixsize_y,
2*dirty.shape(0), 2*dirty.shape(1), epsilon, do_wstacking, nthreads,
dirty, verbosity);
}
template<typename T> void dirty2ms(const const_mav<double,2> &uvw,
template<typename T> void dirty2ms_general(const const_mav<double,2> &uvw,
const const_mav<double,1> &freq, const const_mav<T,2> &dirty,
const const_mav<T,2> &wgt, double pixsize_x, double pixsize_y, double epsilon,
bool do_wstacking, size_t nthreads, const mav<complex<T>,2> &ms, size_t verbosity)
const const_mav<T,2> &wgt, double pixsize_x, double pixsize_y, size_t nu, size_t nv,double epsilon,
bool do_wstacking, size_t nthreads, const mav<complex<T>,2> &ms,
size_t verbosity, bool negate_v=false)
{
Baselines baselines(uvw, freq);
GridderConfig gconf(dirty.shape(0), dirty.shape(1), epsilon, pixsize_x, pixsize_y, nthreads);
auto idx = getWgtIndices(baselines, gconf, wgt);
Baselines baselines(uvw, freq, negate_v);
GridderConfig gconf(dirty.shape(0), dirty.shape(1), nu, nv, epsilon, pixsize_x, pixsize_y, nthreads);
const_mav<complex<T>,2> null_ms(nullptr, {0,0});
auto idx = getWgtIndices(baselines, gconf, wgt, null_ms);
auto idx2 = const_mav<idx_t,1>(idx.data(),{idx.size()});
ms.fill(0);
dirty2x(gconf, dirty, makeMsServ(baselines,idx2,ms,wgt), do_wstacking, verbosity);
}
template<typename T> void dirty2ms(const const_mav<double,2> &uvw,
const const_mav<double,1> &freq, const const_mav<T,2> &dirty,
const const_mav<T,2> &wgt, double pixsize_x, double pixsize_y, double epsilon,
bool do_wstacking, size_t nthreads, const mav<complex<T>,2> &ms, size_t verbosity)
{
dirty2ms_general(uvw, freq, dirty, wgt, pixsize_x, pixsize_y,
2*dirty.shape(0), 2*dirty.shape(1), epsilon, do_wstacking, nthreads, ms,
verbosity);
}
} // namespace detail
......
......@@ -284,6 +284,8 @@ w : float
the w value to use
adjoint: bool
if True, apply the complex conjugate of the w screen
divide_by_n: bool, default=True
if True, divide ny n.
Returns
=======
......@@ -314,9 +316,13 @@ class PyGridderConfig: public GridderConfig
{
public:
using GridderConfig::GridderConfig;
PyGridderConfig(size_t nxdirty, size_t nydirty, size_t nu_, size_t nv_,
double epsilon, double pixsize_x, double pixsize_y, size_t nthreads_)
: GridderConfig(nxdirty, nydirty, nu_, nv_, epsilon, pixsize_x, pixsize_y, nthreads_) {}
PyGridderConfig(size_t nxdirty, size_t nydirty, double epsilon,
double pixsize_x, double pixsize_y, size_t nthreads)
: GridderConfig(nxdirty, nydirty, epsilon, pixsize_x, pixsize_y, nthreads) {}
double pixsize_x, double pixsize_y, size_t nthreads_)
: GridderConfig(nxdirty, nydirty, epsilon, pixsize_x, pixsize_y, nthreads_) {}
template<typename T> pyarr<T> apply_taper2(const pyarr<T> &img, bool divide) const
{
......@@ -416,23 +422,25 @@ class PyGridderConfig: public GridderConfig
myfail("type matching failed: 'dirty' has neither type 'c8' nor 'c16'");