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

merge

parents 3502ad2f d02f825f
...@@ -619,6 +619,8 @@ class GridderConfig ...@@ -619,6 +619,8 @@ class GridderConfig
if (i2>=nu) i2-=nu; if (i2>=nu) i2-=nu;
size_t j2 = nv-ny_dirty/2+j; size_t j2 = nv-ny_dirty/2+j;
if (j2>=nv) j2-=nv; if (j2>=nv) j2-=nv;
// FIXME: for some reason g++ warns about double-to-float conversion
// here, even though there is an explicit cast...
dirty(i,j) = tmav(i2,j2)*T(cfu[i]*cfv[j]); dirty(i,j) = tmav(i2,j2)*T(cfu[i]*cfv[j]);
} }
} }
...@@ -656,6 +658,8 @@ class GridderConfig ...@@ -656,6 +658,8 @@ class GridderConfig
if (i2>=nu) i2-=nu; if (i2>=nu) i2-=nu;
size_t j2 = nv-ny_dirty/2+j; size_t j2 = nv-ny_dirty/2+j;
if (j2>=nv) j2-=nv; if (j2>=nv) j2-=nv;
// FIXME: for some reason g++ warns about double-to-float conversion
// here, even though there is an explicit cast...
grid(i2,j2) = dirty(i,j)*T(cfu[i]*cfv[j]); grid(i2,j2) = dirty(i,j)*T(cfu[i]*cfv[j]);
} }
} }
...@@ -676,7 +680,7 @@ class GridderConfig ...@@ -676,7 +680,7 @@ class GridderConfig
grid.data(), grid.data(), T(1), nthreads); grid.data(), grid.data(), T(1), nthreads);
} }
template<typename T>void getpix(T u_in, T v_in, T &u, T &v, int &iu0, int &iv0) const void getpix(double u_in, double v_in, double &u, double &v, int &iu0, int &iv0) const
{ {
u=fmod1(u_in*psx)*nu, u=fmod1(u_in*psx)*nu,
iu0 = int(u-supp*0.5 + 1 + nu) - nu; iu0 = int(u-supp*0.5 + 1 + nu) - nu;
...@@ -759,7 +763,7 @@ template<typename T, typename T2=complex<T>> class Helper ...@@ -759,7 +763,7 @@ template<typename T, typename T2=complex<T>> class Helper
vector<T2> rbuf, wbuf; vector<T2> rbuf, wbuf;
bool do_w_gridding; bool do_w_gridding;
T w0, xdw; double w0, xdw;
size_t nexp; size_t nexp;
size_t nvecs; size_t nvecs;
vector<Lock> &locks; vector<Lock> &locks;
...@@ -809,9 +813,9 @@ template<typename T, typename T2=complex<T>> class Helper ...@@ -809,9 +813,9 @@ template<typename T, typename T2=complex<T>> class Helper
T kernel[64] ALIGNED(64); T kernel[64] ALIGNED(64);
Helper(const GridderConfig &gconf_, const T2 *grid_r_, T2 *grid_w_, Helper(const GridderConfig &gconf_, const T2 *grid_r_, T2 *grid_w_,
vector<Lock> &locks_, T w0_=-1, T dw_=-1) vector<Lock> &locks_, double w0_=-1, double dw_=-1)
: gconf(gconf_), nu(gconf.Nu()), nv(gconf.Nv()), nsafe(gconf.Nsafe()), : gconf(gconf_), nu(gconf.Nu()), nv(gconf.Nv()), nsafe(gconf.Nsafe()),
supp(gconf.Supp()), beta(gconf.Beta()), grid_r(grid_r_), supp(gconf.Supp()), beta(T(gconf.Beta())), grid_r(grid_r_),
grid_w(grid_w_), su(2*nsafe+(1<<logsquare)), sv(2*nsafe+(1<<logsquare)), grid_w(grid_w_), su(2*nsafe+(1<<logsquare)), sv(2*nsafe+(1<<logsquare)),
bu0(-1000000), bv0(-1000000), bu0(-1000000), bv0(-1000000),
rbuf(su*sv*(grid_r!=nullptr),T(0)), rbuf(su*sv*(grid_r!=nullptr),T(0)),
...@@ -829,18 +833,18 @@ template<typename T, typename T2=complex<T>> class Helper ...@@ -829,18 +833,18 @@ template<typename T, typename T2=complex<T>> class Helper
T Wfac() const { return kernel[2*supp]; } T Wfac() const { return kernel[2*supp]; }
void prep(const UVW &in) void prep(const UVW &in)
{ {
T u, v; double u, v;
gconf.getpix<T>(in.u, in.v, u, v, iu0, iv0); gconf.getpix(in.u, in.v, u, v, iu0, iv0);
T xsupp=T(2)/supp; double xsupp=2./supp;
auto x0 = xsupp*(iu0-u); double x0 = xsupp*(iu0-u);
auto y0 = xsupp*(iv0-v); double y0 = xsupp*(iv0-v);
for (int i=0; i<supp; ++i) for (int i=0; i<supp; ++i)
{ {
kernel[i ] = x0+i*xsupp; kernel[i ] = T(x0+i*xsupp);
kernel[i+supp] = y0+i*xsupp; kernel[i+supp] = T(y0+i*xsupp);
} }
if (do_w_gridding) if (do_w_gridding)
kernel[2*supp] = min(T(1), xdw*xsupp*abs(w0-T(in.w))); kernel[2*supp] = min(T(1), T(xdw*xsupp*abs(w0-in.w)));
for (size_t i=nexp; i<nvecs; ++i) for (size_t i=nexp; i<nvecs; ++i)
kernel[i]=0; kernel[i]=0;
for (size_t i=0; i<nvecs; ++i) for (size_t i=0; i<nvecs; ++i)
...@@ -857,6 +861,28 @@ template<typename T, typename T2=complex<T>> class Helper ...@@ -857,6 +861,28 @@ template<typename T, typename T2=complex<T>> class Helper
} }
}; };
template<class T, class Serv> class SubServ
{
private:
const Serv &srv;
const_mav<uint32_t,1> subidx;
public:
SubServ(const Serv &orig, const const_mav<uint32_t,1> &subidx_)
: srv(orig), subidx(subidx_){}
size_t Nvis() const { return subidx.size(); }
const Baselines &getBaselines() const { return srv.getBaselines(); }
UVW getCoord(size_t i) const
{ return srv.getCoord(subidx[i]); }
complex<T> getVis(size_t i) const
{ return srv.getVis(subidx[i]); }
uint32_t getIdx(size_t i) const { return srv.getIdx(subidx[i]); }
void setVis (size_t i, const complex<T> &v) const
{ srv.setVis(subidx[i], v); }
void addVis (size_t i, const complex<T> &v) const
{ srv.addVis(subidx[i], v); }
};
template<class T, class T2> class VisServ template<class T, class T2> class VisServ
{ {
private: private:
...@@ -876,9 +902,8 @@ template<class T, class T2> class VisServ ...@@ -876,9 +902,8 @@ template<class T, class T2> class VisServ
checkShape(idx.shape(), {nvis}); checkShape(idx.shape(), {nvis});
if (have_wgt) checkShape(wgt.shape(), {nvis}); if (have_wgt) checkShape(wgt.shape(), {nvis});
} }
VisServ(const VisServ &orig, const const_mav<uint32_t,1> &/*newidx*/) SubServ<T, VisServ> getSubserv(const const_mav<uint32_t,1> &subidx) const
: baselines(orig.baselines), idx(orig.idx), vis(orig.vis), wgt(orig.wgt) { return SubServ<T, VisServ>(*this, subidx); }
{ myfail("must not happen"); }
size_t Nvis() const { return nvis; } size_t Nvis() const { return nvis; }
const Baselines &getBaselines() const { return baselines; } const Baselines &getBaselines() const { return baselines; }
UVW getCoord(size_t i) const UVW getCoord(size_t i) const
...@@ -890,7 +915,6 @@ template<class T, class T2> class VisServ ...@@ -890,7 +915,6 @@ template<class T, class T2> class VisServ
{ vis(i) = have_wgt ? v*wgt(i) : v; } { vis(i) = have_wgt ? v*wgt(i) : v; }
void addVis (size_t i, const complex<T> &v) const void addVis (size_t i, const complex<T> &v) const
{ vis(i) += have_wgt ? v*wgt(i) : v; } { vis(i) += have_wgt ? v*wgt(i) : v; }
bool isMsServ() const { return false; }
}; };
template<class T, class T2> VisServ<T, T2> makeVisServ template<class T, class T2> VisServ<T, T2> makeVisServ
(const Baselines &baselines, (const Baselines &baselines,
...@@ -916,8 +940,8 @@ template<class T, class T2> class MsServ ...@@ -916,8 +940,8 @@ template<class T, class T2> class MsServ
checkShape(ms.shape(), {baselines.Nrows(), baselines.Nchannels()}); checkShape(ms.shape(), {baselines.Nrows(), baselines.Nchannels()});
if (have_wgt) checkShape(wgt.shape(), ms.shape()); if (have_wgt) checkShape(wgt.shape(), ms.shape());
} }
MsServ(const MsServ &orig, const const_mav<uint32_t,1> &newidx) SubServ<T, MsServ> getSubserv(const const_mav<uint32_t,1> &subidx) const
: MsServ(orig.baselines, newidx, orig.ms, orig.wgt) {} { return SubServ<T, MsServ>(*this, subidx); }
size_t Nvis() const { return nvis; } size_t Nvis() const { return nvis; }
const Baselines &getBaselines() const { return baselines; } const Baselines &getBaselines() const { return baselines; }
UVW getCoord(size_t i) const UVW getCoord(size_t i) const
...@@ -939,7 +963,6 @@ template<class T, class T2> class MsServ ...@@ -939,7 +963,6 @@ template<class T, class T2> class MsServ
auto rc = baselines.getRowChan(idx(i)); auto rc = baselines.getRowChan(idx(i));
ms(rc.row, rc.chan) += have_wgt ? v*wgt(rc.row, rc.chan) : v; ms(rc.row, rc.chan) += have_wgt ? v*wgt(rc.row, rc.chan) : v;
} }
bool isMsServ() const { return true; }
}; };
template<class T, class T2> MsServ<T, T2> makeMsServ template<class T, class T2> MsServ<T, T2> makeMsServ
(const Baselines &baselines, (const Baselines &baselines,
...@@ -1215,12 +1238,12 @@ template<typename T> void apply_wcorr(const GridderConfig &gconf, ...@@ -1215,12 +1238,12 @@ template<typename T> void apply_wcorr(const GridderConfig &gconf,
{ {
double fy = y0+j*psy; double fy = y0+j*psy;
fy*=fy; fy*=fy;
double fct = 0; T fct = 0;
double tmp = 1.-fx-fy; double tmp = 1.-fx-fy;
if (tmp>=0) if (tmp>=0)
{ {
auto nm1 = (-fx-fy)/(sqrt(1.-fx-fy)+1.); // accurate form of sqrt(1-x-y) auto nm1 = (-fx-fy)/(sqrt(1.-fx-fy)+1.); // accurate form of sqrt(1-x-y)
fct = (nm1<=-1) ? 0. : kernel.corfac(nm1*dw); fct = T((nm1<=-1) ? 0. : kernel.corfac(nm1*dw));
} }
size_t i2 = nx_dirty-i, j2 = ny_dirty-j; size_t i2 = nx_dirty-i, j2 = ny_dirty-j;
dirty(i,j)*=fct; dirty(i,j)*=fct;
...@@ -1315,9 +1338,7 @@ template<typename T, typename Serv> void x2dirty( ...@@ -1315,9 +1338,7 @@ template<typename T, typename Serv> void x2dirty(
wstack_common(gconf, srv, wmin, dw, nplanes, nvis_plane, minplane, verbosity); wstack_common(gconf, srv, wmin, dw, nplanes, nvis_plane, minplane, verbosity);
dirty.fill(0); dirty.fill(0);
vector<complex<T>> vis_loc_; vector<uint32_t> subidx;
vector<uint32_t> idx_loc_;
vector<uint32_t> mapper;
tmpStorage<complex<T>,2> grid_({gconf.Nu(),gconf.Nv()}); tmpStorage<complex<T>,2> grid_({gconf.Nu(),gconf.Nv()});
auto grid=grid_.getMav(); auto grid=grid_.getMav();
tmpStorage<complex<T>,2> tdirty_(dirty.shape()); tmpStorage<complex<T>,2> tdirty_(dirty.shape());
...@@ -1331,38 +1352,15 @@ template<typename T, typename Serv> void x2dirty( ...@@ -1331,38 +1352,15 @@ template<typename T, typename Serv> void x2dirty(
double wcur = wmin+iw*dw; double wcur = wmin+iw*dw;
size_t cnt=0; size_t cnt=0;
mapper.resize(nvis_plane[iw]); subidx.resize(nvis_plane[iw]);
const auto &bla(minplane[iw/supp]); const auto &bla(minplane[iw/supp]);
for (size_t i=0; i<bla.size(); ++i) for (size_t i=0; i<bla.size(); ++i)
if ((int(iw)>=bla[i].minplane) && (int(iw)<bla[i].minplane+int(supp))) if ((int(iw)>=bla[i].minplane) && (int(iw)<bla[i].minplane+int(supp)))
mapper[cnt++] = bla[i].idx; subidx[cnt++] = bla[i].idx;
idx_loc_.resize(nvis_plane[iw]); auto subidx2 = const_mav<uint32_t, 1>(subidx.data(), {subidx.size()});
if (srv.isMsServ()) auto subsrv = srv.getSubserv(subidx2);
{ grid.fill(0);
#pragma omp parallel for num_threads(nthreads) x2grid_c(gconf, subsrv, grid, wcur, dw);
for (size_t i=0; i<nvis_plane[iw]; ++i)
idx_loc_[i] = srv.getIdx(mapper[i]);
grid.fill(0);
auto idx_loc = const_mav<uint32_t, 1>(idx_loc_.data(), {idx_loc_.size()});
Serv newsrv(srv, idx_loc);
x2grid_c(gconf, newsrv, grid, wcur, dw);
}
else
{
vis_loc_.resize(nvis_plane[iw]);
#pragma omp parallel for num_threads(nthreads)
for (size_t i=0; i<nvis_plane[iw]; ++i)
{
auto ipart = mapper[i];
vis_loc_[i] = srv.getVis(ipart);
idx_loc_[i] = srv.getIdx(ipart);
}
grid.fill(0);
auto vis_loc = const_mav<complex<T>,1>(vis_loc_.data(), {nvis_plane[iw]});
auto idx_loc = const_mav<uint32_t,1>(idx_loc_.data(), {nvis_plane[iw]});
vis2grid_c(srv.getBaselines(), gconf, idx_loc, vis_loc, grid,
nullmav<T,1>(), wcur, dw);
}
gconf.grid2dirty_c(cmav(grid), tdirty); gconf.grid2dirty_c(cmav(grid), tdirty);
gconf.apply_wscreen(cmav(tdirty), tdirty, wcur, true); gconf.apply_wscreen(cmav(tdirty), tdirty, wcur, true);
#pragma omp parallel for num_threads(nthreads) #pragma omp parallel for num_threads(nthreads)
...@@ -1424,9 +1422,7 @@ template<typename T, typename Serv> void dirty2x( ...@@ -1424,9 +1422,7 @@ template<typename T, typename Serv> void dirty2x(
// correct for w gridding // correct for w gridding
apply_wcorr(gconf, tdirty, ES_Kernel_with_correction(supp, nthreads), dw); apply_wcorr(gconf, tdirty, ES_Kernel_with_correction(supp, nthreads), dw);
vector<complex<T>> vis_loc_; vector<uint32_t> subidx;
vector<uint32_t> idx_loc_;
vector<uint32_t> mapper;
tmpStorage<complex<T>,2> grid_({gconf.Nu(),gconf.Nv()}); tmpStorage<complex<T>,2> grid_({gconf.Nu(),gconf.Nv()});
auto grid=grid_.getMav(); auto grid=grid_.getMav();
tmpStorage<complex<T>,2> tdirty2_({nx_dirty,ny_dirty}); tmpStorage<complex<T>,2> tdirty2_({nx_dirty,ny_dirty});
...@@ -1446,37 +1442,15 @@ template<typename T, typename Serv> void dirty2x( ...@@ -1446,37 +1442,15 @@ template<typename T, typename Serv> void dirty2x(
gconf.apply_wscreen(cmav(tdirty2), tdirty2, wcur, false); gconf.apply_wscreen(cmav(tdirty2), tdirty2, wcur, false);
gconf.dirty2grid_c(cmav(tdirty2), grid); gconf.dirty2grid_c(cmav(tdirty2), grid);
subidx.resize(nvis_plane[iw]);
size_t cnt=0; size_t cnt=0;
mapper.resize(nvis_plane[iw]);
const auto &bla(minplane[iw/supp]); const auto &bla(minplane[iw/supp]);
for (size_t i=0; i<bla.size(); ++i) for (size_t i=0; i<bla.size(); ++i)
if ((int(iw)>=bla[i].minplane) && (int(iw)<bla[i].minplane+int(supp))) if ((int(iw)>=bla[i].minplane) && (int(iw)<bla[i].minplane+int(supp)))
mapper[cnt++] = bla[i].idx; subidx[cnt++] = bla[i].idx;
idx_loc_.resize(nvis_plane[iw]); auto subidx2 = const_mav<uint32_t, 1>(subidx.data(), {subidx.size()});
if (srv.isMsServ()) auto subsrv = srv.getSubserv(subidx2);
{ grid2x_c(gconf, cmav(grid), subsrv, wcur, dw);
#pragma omp parallel for num_threads(nthreads)
for (size_t i=0; i<nvis_plane[iw]; ++i)
idx_loc_[i] = srv.getIdx(mapper[i]);
auto idx_loc = const_mav<uint32_t, 1>(idx_loc_.data(), {idx_loc_.size()});
Serv newsrv(srv, idx_loc);
grid2x_c(gconf, cmav(grid), newsrv, wcur, dw);
}
else
{
vis_loc_.resize(nvis_plane[iw]);
auto vis_loc = mav<complex<T>,1>(vis_loc_.data(), {nvis_plane[iw]});
vis_loc.fill(0);
auto idx_loc = mav<uint32_t,1>(idx_loc_.data(), {nvis_plane[iw]});
#pragma omp parallel for num_threads(nthreads)
for (size_t i=0; i<nvis_plane[iw]; ++i)
idx_loc[i] = srv.getIdx(mapper[i]);
grid2vis_c(srv.getBaselines(), gconf, cmav(idx_loc), cmav(grid), vis_loc,
nullmav<T,1>(), wcur, dw);
#pragma omp parallel for num_threads(nthreads)
for (size_t i=0; i<nvis_plane[iw]; ++i)
srv.addVis(mapper[i], vis_loc[i]);
}
} }
} }
else else
......
...@@ -138,9 +138,9 @@ Class storing UVW coordinates and channel information. ...@@ -138,9 +138,9 @@ Class storing UVW coordinates and channel information.
Parameters Parameters
========== ==========
coord: np.array((nrows, 3), dtype=np.float) coord: np.array((nrows, 3), dtype=np.float64)
u, v and w coordinates for each row u, v and w coordinates for each row
freq: np.array((nchannels,), dtype=np.float) freq: np.array((nchannels,), dtype=np.float64)
frequency for each individual channel (in Hz) frequency for each individual channel (in Hz)
)"""; )""";
class PyBaselines: public Baselines class PyBaselines: public Baselines
...@@ -305,6 +305,8 @@ pixsize_x: float ...@@ -305,6 +305,8 @@ pixsize_x: float
Pixel size in x direction (radians) Pixel size in x direction (radians)
pixsize_y: float pixsize_y: float
Pixel size in y direction (radians) Pixel size in y direction (radians)
nthreads: int
the number of threads to use for all calculations involving this object.
)"""; )""";
class PyGridderConfig: public GridderConfig class PyGridderConfig: public GridderConfig
{ {
...@@ -714,6 +716,35 @@ template<typename T> pyarr<T> vis2dirty2(const PyBaselines &baselines, ...@@ -714,6 +716,35 @@ template<typename T> pyarr<T> vis2dirty2(const PyBaselines &baselines,
} }
return dirty; return dirty;
} }
constexpr auto vis2dirty_DS = R"""(
Converts an array of visibilities to a dirty image.
Parameters
==========
baselines: Baselines
the Baselines object
gconf: GridderConf
the GridderConf object to be used
(used to optimize the ordering of the indices)
idx: np.array((nvis,), dtype=np.uint32)
the indices for the provided visibilities
vis: np.array(nvis,), dtype=np.complex64 or np.complex128)
The input visibilities
Its data type determines the precision in which the calculation is carried
out.
wgt: np.array((nvis,), dtype=float with same precision as `vis`, optional
If present, visibilities are multiplied by the corresponding entries.
do_wstacking: bool
if True, the full improved w-stacking algorithm is carried out, otherwise
the w values are assumed to be zero.
Returns
=======
np.array((nxdirty, nydirty), dtype=float of same precision as `vis`.)
The dirty image
)""";
py::array Pyvis2dirty(const PyBaselines &baselines, py::array Pyvis2dirty(const PyBaselines &baselines,
const PyGridderConfig &gconf, const py::array &idx, const PyGridderConfig &gconf, const py::array &idx,
const py::array &vis, const py::object &wgt, bool do_wstacking) const py::array &vis, const py::object &wgt, bool do_wstacking)
...@@ -745,6 +776,34 @@ template<typename T> pyarr<complex<T>> dirty2vis2(const PyBaselines &baselines, ...@@ -745,6 +776,34 @@ template<typename T> pyarr<complex<T>> dirty2vis2(const PyBaselines &baselines,
} }
return vis; return vis;
} }
constexpr auto dirty2vis_DS = R"""(
Converts a dirty image into a 1D array of visibilities.
Parameters
==========
baselines: Baselines
the Baselines object
gconf: GridderConf
the GridderConf object to be used
(used to optimize the ordering of the indices)
idx: np.array((nvis,), dtype=np.uint32)
the indices for the visibilities to be computed
dirty: np.array((nxdirty, nydirty), dtype=np.float32 or np.float64)
dirty image
Its data type determines the precision in which the calculation is carried
out.
wgt: np.array((nvis,), same dtype as `dirty`, optional
If present, visibilities are multiplied by the corresponding entries.
do_wstacking: bool
if True, the full improved w-stacking algorithm is carried out, otherwise
the w values are assumed to be zero.
Returns
=======
np.array((nvis,), dtype=complex of same precision as `dirty`.)
The visibility data
)""";
py::array Pydirty2vis(const PyBaselines &baselines, py::array Pydirty2vis(const PyBaselines &baselines,
const PyGridderConfig &gconf, const py::array &idx, const py::array &dirty, const PyGridderConfig &gconf, const py::array &idx, const py::array &dirty,
const py::object &wgt, bool do_wstacking) const py::object &wgt, bool do_wstacking)
...@@ -779,6 +838,43 @@ template<typename T> py::array ms2dirty2(const py::array &uvw_, ...@@ -779,6 +838,43 @@ template<typename T> py::array ms2dirty2(const py::array &uvw_,
return dirty; return dirty;
} }
constexpr auto ms2dirty_DS = R"""(
Converts an MS object to dirty image.
Parameters
==========
uvw: np.array((nrows, 3), dtype=np.float64)
UVW coordinates from the measurement set
freq: np.array((nchan,), dtype=np.float64)
channel frequencies
ms: np.array((nrows, nchan,), dtype=np.complex64 or np.complex128)
the input measurement set data.
Its data type determines the precision in which the calculation is carried
out.
wgt: np.array((nrows, nchan), float with same precision as `ms`), optional
If present, its values are multiplied to the output
npix_x, npix_y: int
dimensions of the dirty image
pixsize_x, pixsize_y: float
angular pixel size (in radians) of the dirty image
epsilon: float
accuracy at which the computation should be done. Must be larger than 2e-13.
If `ms` has type np.complex64, it must be larger than 1e-5.
do_wstacking: bool
if True, the full improved w-stacking algorithm is carried out, otherwise
the w values are assumed to be zero.
nthreads: int
number of threads to use for the calculation
verbosity: int
0: no output
1: some output
2: detailed output
Returns
=======
np.array((nxdirty, nydirty), dtype=float of same precision as `ms`)
the dirty image
)""";
py::array Pyms2dirty(const py::array &uvw, py::array Pyms2dirty(const py::array &uvw,
const py::array &freq, const py::array &ms, const py::object &wgt, const py::array &freq, const py::array &ms, const py::object &wgt,
size_t npix_x, size_t npix_y, double pixsize_x, double pixsize_y, double epsilon, size_t npix_x, size_t npix_y, double pixsize_x, double pixsize_y, double epsilon,
...@@ -816,6 +912,41 @@ template<typename T> py::array dirty2ms2(const py::array &uvw_, ...@@ -816,6 +912,41 @@ template<typename T> py::array dirty2ms2(const py::array &uvw_,
return ms; return ms;
} }
constexpr auto dirty2ms_DS = R"""(
Converts a dirty image to an MS object.
Parameters
==========
uvw: np.array((nrows, 3), dtype=np.float64)
UVW coordinates from the measurement set
freq: np.array((nchan,), dtype=np.float64)
channel frequencies
dirty: np.array((nxdirty, nydirty), dtype=np.float32 or np.float64)
dirty image
Its data type determines the precision in which the calculation is carried
out.
wgt: np.array((nrows, nchan), same dtype as `dirty`), optional
If present, its values are multiplied to the output
pixsize_x, pixsize_y: float
angular pixel size (in radians) of the dirty image
epsilon: float
accuracy at which the computation should be done. Must be larger than 2e-13.
If `dirty` has type np.float32, it must be larger than 1e-5.
do_wstacking: bool
if True, the full improved w-stacking algorithm is carried out, otherwise
the w values are assumed to be zero.
nthreads: int
number of threads to use for the calculation
verbosity: int
0: no output
1: some output
2: detailed output
Returns
=======
np.array((nrows, nchan,), dtype=complex of same precision as `dirty`)
the measurement set data.
)""";
py::array Pydirty2ms(const py::array &uvw, py::array Pydirty2ms(const py::array &uvw,
const py::array &freq, const py::array &dirty, const py::object &wgt, const py::array &freq, const py::array &dirty, const py::object &wgt,
double pixsize_x, double pixsize_y, double epsilon, double pixsize_x, double pixsize_y, double epsilon,
...@@ -909,15 +1040,15 @@ PYBIND11_MODULE(nifty_gridder, m) ...@@ -909,15 +1040,15 @@ PYBIND11_MODULE(nifty_gridder, m)
"grid"_a, "wgt"_a=None); "grid"_a, "wgt"_a=None);
m.def("get_correlations", &Pyget_correlations<double>, "baselines"_a, "gconf"_a, m.def("get_correlations", &Pyget_correlations<double>, "baselines"_a, "gconf"_a,
"idx"_a, "du"_a, "dv"_a, "wgt"_a=None); "idx"_a, "du"_a, "dv"_a, "wgt"_a=None);
m.def("vis2dirty",&Pyvis2dirty, "baselines"_a, "gconf"_a, m.def("vis2dirty",&Pyvis2dirty, vis2dirty_DS, "baselines"_a, "gconf"_a,
"idx"_a, "vis"_a, "wgt"_a=None, "do_wstacking"_a=false); "idx"_a, "vis"_a, "wgt"_a=None, "do_wstacking"_a=false);
m.def("dirty2vis",&Pydirty2vis, "baselines"_a, "gconf"_a, m.def("dirty2vis",&Pydirty2vis, "baselines"_a, dirty2vis_DS, "gconf"_a,
"idx"_a, "dirty"_a, "wgt"_a=None, "do_wstacking"_a=false); "idx"_a, "dirty"_a, "wgt"_a=None, "do_wstacking"_a=false);
m.def("ms2dirty",&Pyms2dirty,"uvw"_a,"freq"_a,"ms"_a, m.def("ms2dirty", &Pyms2dirty, ms2dirty_DS, "uvw"_a, "freq"_a, "ms"_a,
"wgt"_a=None,"npix_x"_a,"npix_y"_a,"pixsize_x"_a,"pixsize_y"_a,"epsilon"_a, "wgt"_a=None, "npix_x"_a, "npix_y"_a, "pixsize_x"_a, "pixsize_y"_a,
"epsilon"_a, "do_wstacking"_a=false, "nthreads"_a=1, "verbosity"_a=0);
m.def("dirty2ms", &Pydirty2ms, dirty2ms_DS, "uvw"_a, "freq"_a, "dirty"_a,
"wgt"_a=None, "pixsize_x"_a, "pixsize_y"_a, "epsilon"_a,
"do_wstacking"_a=false, "nthreads"_a=1, "verbosity"_a=0); "do_wstacking"_a=false, "nthreads"_a=1, "verbosity"_a=0);
m.def("dirty2ms",&Pydirty2ms,"uvw"_a,"freq"_a,"dirty"_a,
"wgt"_a=None,"pixsize_x"_a,"pixsize_y"_a, "epsilon"_a, "do_wstacking"_a=false, "nthreads"_a=1,
"verbosity"_a=0);
} }
...@@ -7,7 +7,6 @@ from numpy.testing import assert_, assert_allclose, assert_array_almost_equal ...@@ -7,7 +7,6 @@ from numpy.testing import assert_, assert_allclose, assert_array_almost_equal
pmp = pytest.mark.parametrize pmp = pytest.mark.parametrize
def _init_gridder(nxdirty, nydirty, epsilon, nchan, nrow): def _init_gridder(nxdirty, nydirty, epsilon, nchan, nrow):
pixsize = np.pi/180/60/nxdirty pixsize = np.pi/180/60/nxdirty
conf = ng.GridderConfig(nxdirty=nxdirty, conf = ng.GridderConfig(nxdirty=nxdirty,
...@@ -45,13 +44,103 @@ def _dft(uvw, vis, conf, apply_w): ...@@ -45,13 +44,103 @@ def _dft(uvw, vis, conf, apply_w):
def _l2error(a, b): def _l2error(a, b):
return np.sqrt(np.sum(np.abs(a-b)**2)/np.sum(np.abs(a)**2)) return n