Line data Source code
1 : //# SDGrid.cc: Implementation of SDGrid class
2 : //# Copyright (C) 1997,1998,1999,2000,2001,2002,2003
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id$
27 :
28 : #include <casacore/casa/Arrays/Array.h>
29 : #include <casacore/casa/Arrays/ArrayLogical.h>
30 : #include <casacore/casa/Arrays/ArrayMath.h>
31 : #include <casacore/casa/Arrays/Cube.h>
32 : #include <casacore/casa/Arrays/MaskedArray.h>
33 : #include <casacore/casa/Arrays/Matrix.h>
34 : #include <casacore/casa/Arrays/MatrixIter.h>
35 : #include <casacore/casa/Arrays/Slice.h>
36 : #include <casacore/casa/Arrays/Vector.h>
37 : #include <casacore/casa/BasicSL/Constants.h>
38 : #include <casacore/casa/BasicSL/String.h>
39 : #include <casacore/casa/Containers/Block.h>
40 : #include <casacore/casa/Exceptions/Error.h>
41 : #include <casacore/casa/OS/Timer.h>
42 : #include <casacore/casa/Quanta/MVAngle.h>
43 : #include <casacore/casa/Quanta/MVTime.h>
44 : #include <casacore/casa/Quanta/UnitMap.h>
45 : #include <casacore/casa/Quanta/UnitVal.h>
46 : #include <sstream>
47 : #include <casacore/casa/Utilities/Assert.h>
48 :
49 : #include <components/ComponentModels/ConstantSpectrum.h>
50 : #include <components/ComponentModels/Flux.h>
51 : #include <components/ComponentModels/PointShape.h>
52 :
53 : #include <casacore/coordinates/Coordinates/CoordinateSystem.h>
54 : #include <casacore/coordinates/Coordinates/DirectionCoordinate.h>
55 : #include <casacore/coordinates/Coordinates/Projection.h>
56 : #include <casacore/coordinates/Coordinates/SpectralCoordinate.h>
57 : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
58 :
59 : #include <casacore/images/Images/ImageInterface.h>
60 : #include <casacore/images/Images/PagedImage.h>
61 : #include <casacore/images/Images/TempImage.h>
62 :
63 : #include <casacore/lattices/Lattices/ArrayLattice.h>
64 : #include <casacore/lattices/Lattices/LatticeCache.h>
65 : #include <casacore/lattices/Lattices/LatticeIterator.h>
66 : #include <casacore/lattices/Lattices/LatticeStepper.h>
67 : #include <casacore/lattices/Lattices/SubLattice.h>
68 : #include <casacore/lattices/LEL/LatticeExpr.h>
69 : #include <casacore/lattices/LRegions/LCBox.h>
70 :
71 : #include <casacore/measures/Measures/Stokes.h>
72 : #include <casacore/ms/MeasurementSets/MSColumns.h>
73 : #include <msvis/MSVis/StokesVector.h>
74 : #include <msvis/MSVis/VisBuffer2.h>
75 : #include <msvis/MSVis/VisibilityIterator2.h>
76 : #include <casacore/scimath/Mathematics/RigidVector.h>
77 : #include <synthesis/TransformMachines2/SDGrid.h>
78 : #include <synthesis/TransformMachines2/SkyJones.h>
79 : #include <synthesis/TransformMachines/StokesImageUtil.h>
80 :
81 : #include <casacore/tables/TaQL/TableParse.h>
82 :
83 : using namespace casacore;
84 : namespace casa {
85 : namespace refim {//# namespace for imaging refactor
86 :
87 0 : SDGrid::SDGrid(SkyJones& sj, Int icachesize, Int itilesize,
88 0 : String iconvType, Int userSupport, Bool useImagingWeight)
89 0 : : FTMachine(), sj_p(&sj), imageCache(0), wImageCache(0),
90 0 : cachesize(icachesize), tilesize(itilesize),
91 0 : isTiled(false), wImage(0), arrayLattice(0), wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
92 0 : pointingToImage(0), userSetSupport_p(userSupport),
93 0 : truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
94 0 : minWeight_p(0.), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
95 0 : isSplineInterpolationReady(false), interpolator(0), clipminmax_(false)
96 : {
97 0 : lastIndex_p=0;
98 0 : }
99 :
100 44 : SDGrid::SDGrid(MPosition& mLocation, SkyJones& sj, Int icachesize, Int itilesize,
101 44 : String iconvType, Int userSupport, Float minweight, Bool clipminmax, Bool useImagingWeight)
102 44 : : FTMachine(), sj_p(&sj), imageCache(0), wImageCache(0),
103 44 : cachesize(icachesize), tilesize(itilesize),
104 44 : isTiled(false), wImage(0), arrayLattice(0), wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
105 88 : pointingToImage(0), userSetSupport_p(userSupport),
106 44 : truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
107 44 : minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
108 88 : isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax)
109 : {
110 44 : mLocation_p=mLocation;
111 44 : lastIndex_p=0;
112 44 : }
113 :
114 0 : SDGrid::SDGrid(Int icachesize, Int itilesize,
115 0 : String iconvType, Int userSupport, Bool useImagingWeight)
116 0 : : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
117 0 : cachesize(icachesize), tilesize(itilesize),
118 0 : isTiled(false), wImage(0), arrayLattice(0), wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
119 0 : pointingToImage(0), userSetSupport_p(userSupport),
120 0 : truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
121 0 : minWeight_p(0.), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
122 0 : isSplineInterpolationReady(false), interpolator(0), clipminmax_(false)
123 : {
124 0 : lastIndex_p=0;
125 0 : }
126 :
127 238 : SDGrid::SDGrid(MPosition &mLocation, Int icachesize, Int itilesize,
128 238 : String iconvType, Int userSupport, Float minweight, Bool clipminmax, Bool useImagingWeight)
129 238 : : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
130 238 : cachesize(icachesize), tilesize(itilesize),
131 238 : isTiled(false), wImage(0), arrayLattice(0), wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
132 476 : pointingToImage(0), userSetSupport_p(userSupport),
133 238 : truncate_p(-1.0), gwidth_p(0.0), jwidth_p(0.0),
134 238 : minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1),
135 238 : msId_p(-1),
136 476 : isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax)
137 : {
138 238 : mLocation_p=mLocation;
139 238 : lastIndex_p=0;
140 238 : }
141 :
142 6 : SDGrid::SDGrid(MPosition &mLocation, Int icachesize, Int itilesize,
143 : String iconvType, Float truncate, Float gwidth, Float jwidth,
144 6 : Float minweight, Bool clipminmax, Bool useImagingWeight)
145 6 : : FTMachine(), sj_p(0), imageCache(0), wImageCache(0),
146 6 : cachesize(icachesize), tilesize(itilesize),
147 6 : isTiled(false), wImage(0), arrayLattice(0), wArrayLattice(0), lattice(0), wLattice(0), convType(iconvType),
148 12 : pointingToImage(0), userSetSupport_p(-1),
149 6 : truncate_p(truncate), gwidth_p(gwidth), jwidth_p(jwidth),
150 6 : minWeight_p(minweight), lastIndexPerAnt_p(), useImagingWeight_p(useImagingWeight), lastAntID_p(-1), msId_p(-1),
151 12 : isSplineInterpolationReady(false), interpolator(0), clipminmax_(clipminmax)
152 : {
153 6 : mLocation_p=mLocation;
154 6 : lastIndex_p=0;
155 6 : }
156 :
157 :
158 : //----------------------------------------------------------------------
159 0 : SDGrid& SDGrid::operator=(const SDGrid& other)
160 : {
161 0 : if(this!=&other) {
162 : //Do the base parameters
163 0 : FTMachine::operator=(other);
164 0 : sj_p=other.sj_p;
165 0 : imageCache=other.imageCache;
166 0 : wImage=other.wImage;
167 0 : wImageCache=other.wImageCache;
168 0 : cachesize=other.cachesize;
169 0 : tilesize=other.tilesize;
170 0 : isTiled=other.isTiled;
171 0 : lattice=other.lattice;
172 0 : arrayLattice=other.arrayLattice;
173 0 : wLattice=other.wLattice;
174 0 : wArrayLattice=other.wArrayLattice;
175 0 : convType=other.convType;
176 0 : if(other.wImage !=0)
177 0 : wImage=(TempImage<Float> *)other.wImage->cloneII();
178 : else
179 0 : wImage=0;
180 0 : pointingDirCol_p=other.pointingDirCol_p;
181 0 : pointingToImage=0;
182 0 : xyPos.resize();
183 0 : xyPos=other.xyPos;
184 0 : xyPosMovingOrig_p=other.xyPosMovingOrig_p;
185 0 : convFunc.resize();
186 0 : convFunc=other.convFunc;
187 0 : convSampling=other.convSampling;
188 0 : convSize=other.convSize;
189 0 : convSupport=other.convSupport;
190 0 : userSetSupport_p=other.userSetSupport_p;
191 0 : lastIndex_p=0;
192 0 : lastIndexPerAnt_p=0;
193 0 : lastAntID_p=-1;
194 0 : msId_p=-1;
195 0 : useImagingWeight_p=other.useImagingWeight_p;
196 0 : clipminmax_=other.clipminmax_;
197 : };
198 0 : return *this;
199 : };
200 :
201 576 : String SDGrid::name() const{
202 576 : return String("SDGrid");
203 : }
204 :
205 : //----------------------------------------------------------------------
206 : // Odds are that it changed.....
207 0 : Bool SDGrid::changed(const vi::VisBuffer2& /*vb*/) {
208 0 : return false;
209 : }
210 :
211 : //----------------------------------------------------------------------
212 0 : SDGrid::SDGrid(const SDGrid& other):FTMachine()
213 : {
214 0 : operator=(other);
215 0 : }
216 :
217 : #define NEED_UNDERSCORES
218 : #if defined(NEED_UNDERSCORES)
219 : #define grdsf grdsf_
220 : #define grdgauss grdgauss_
221 : #define grdjinc1 grdjinc1_
222 : #endif
223 :
224 : extern "C" {
225 : void grdsf(Double*, Double*);
226 : void grdgauss(Double*, Double*, Double*);
227 : void grdjinc1(Double*, Double*, Int*, Double*);
228 : }
229 :
230 : //----------------------------------------------------------------------
231 144 : void SDGrid::init() {
232 :
233 : // FIXME: don't mess with parent's class logger
234 : // unless you make sure you reset it to it's original state
235 : // when you are done
236 144 : logIO() << LogOrigin("SDGrid", "init") << LogIO::NORMAL;
237 :
238 : //pfile = fopen("ptdata.txt","w");
239 :
240 144 : ok();
241 :
242 : { // Initialize members
243 144 : isTiled = false;
244 :
245 144 : nx = image->shape()(0);
246 144 : ny = image->shape()(1);
247 144 : npol = image->shape()(2);
248 144 : nchan = image->shape()(3);
249 :
250 144 : sumWeight.resize(npol, nchan);
251 :
252 : // Set up image cache needed for gridding.
253 144 : if (imageCache) delete imageCache;
254 144 : imageCache = 0;
255 :
256 : // Initialize weight image
257 144 : if (wImage) delete wImage;
258 144 : wImage = 0;
259 288 : wImage = new TempImage<Float>(
260 288 : image->shape(),
261 144 : image->coordinates()
262 144 : );
263 : }
264 :
265 : { // Compute Convolution Function
266 144 : convType = downcase(convType);
267 : logIO() << LogIO::NORMAL2
268 144 : << "Convolution function: " << convType
269 144 : << LogIO::POST;
270 :
271 144 : if (convType == "pb") { // Primary Beam: do nothing
272 : //cerr << "CNVFunc " << convFunc << endl;
273 : }
274 122 : else if (convType == "box") { // Box Function
275 102 : convSupport = (userSetSupport_p >= 0) ? userSetSupport_p : 0;
276 : logIO() << LogIO::NORMAL2
277 : << "Support: " << convSupport << " pixels"
278 102 : << LogIO::POST;
279 :
280 102 : convSampling = 100;
281 102 : convSize = convSampling*(2*convSupport+2);
282 102 : convFunc.resize(convSize);
283 102 : convFunc = 0.0;
284 10302 : for (Int i=0; i<convSize/2; i++) {
285 10200 : convFunc(i) = 1.0;
286 : }
287 : }
288 20 : else if (convType == "sf") { // Prolate Spheroidal Wave Function
289 17 : convSupport = (userSetSupport_p >= 0) ? userSetSupport_p : 3;
290 : logIO() << LogIO::NORMAL2
291 : << "Support: " << convSupport << " pixels"
292 17 : << LogIO::POST;
293 :
294 : // FIXME: why 100 ?
295 17 : convSampling = 100;
296 17 : convSize = convSampling*(2*convSupport + 2);
297 17 : convFunc.resize(convSize);
298 17 : convFunc = 0.0;
299 9917 : for (Int i=0; i<convSampling*convSupport; i++) {
300 9900 : Double nu = Double(i)/Double(convSupport*convSampling);
301 : Double val;
302 9900 : grdsf(&nu, &val);
303 9900 : convFunc(i) = (1.0-nu*nu)*val;
304 : }
305 : }
306 3 : else if (convType == "gauss") { // Gauss function
307 : // default is b=1.0 (Mangum et al. 2007)
308 : // FIXME: how does b=1.0 relate to current code ?
309 1 : Double hwhm = (gwidth_p > 0.0) ? Double(gwidth_p) : sqrt(log(2.0));
310 :
311 1 : Float truncate = (truncate_p >= 0.0) ? truncate_p : 3.0 * hwhm;
312 1 : convSampling = 100;
313 1 : Int itruncate = (Int)(truncate*Double(convSampling) + 0.5);
314 :
315 : logIO() << LogIO::NORMAL2
316 : << "hwhm=" << hwhm
317 1 : << LogIO::POST;
318 :
319 : logIO() << LogIO::NORMAL2
320 : << "itruncate=" << itruncate
321 1 : << LogIO::POST;
322 :
323 1 : convSupport = (Int)(truncate);
324 1 : convSupport += ((truncate - (Float)convSupport) > 0.0) ? 1 : 0;
325 :
326 1 : convSize = convSampling*(2*convSupport + 2);
327 :
328 1 : convFunc.resize(convSize);
329 1 : convFunc = 0.0;
330 : Double val, x;
331 252 : for (Int i=0; i<=itruncate; i++) {
332 251 : x = Double(i)/Double(convSampling);
333 251 : grdgauss(&hwhm, &x, &val);
334 251 : convFunc(i)=val;
335 : }
336 :
337 : // String outfile = convType + ".dat";
338 : // ofstream ofs(outfile.c_str());
339 : // for (Int i = 0 ; i < convSize ; i++) {
340 : // ofs << i << " " << convFunc[i] << endl;
341 : // }
342 : // ofs.close();
343 :
344 : }
345 2 : else if (convType == "gjinc") { // Gauss * Jinc function
346 : // default is b=2.52, c=1.55 (Mangum et al. 2007)
347 2 : Double hwhm = (gwidth_p > 0.0) ? Double(gwidth_p) : sqrt(log(2.0))*2.52;
348 2 : Double c = (jwidth_p > 0.0) ? Double(jwidth_p) : 1.55;
349 2 : convSampling = 100;
350 2 : Int itruncate=(Int)(truncate_p*Double(convSampling) + 0.5);
351 :
352 : logIO() << LogIO::NORMAL2
353 : << "hwhm=" << hwhm
354 2 : << LogIO::POST;
355 : logIO() << LogIO::NORMAL2
356 : << "c=" << c
357 2 : << LogIO::POST;
358 : logIO() << LogIO::NORMAL2
359 : << "itruncate=" << itruncate
360 2 : << LogIO::POST;
361 :
362 2 : Float convSupportF = (truncate_p >= 0.0) ? truncate_p : (2*c);
363 2 : convSupport = (Int)convSupportF;
364 2 : convSupport += (((convSupportF-(Float)convSupport) > 0.0) ? 1 : 0);
365 2 : convSize = convSampling*(2*convSupport + 2);
366 :
367 2 : convFunc.resize(convSize);
368 2 : convFunc = 0.0;
369 : Double x, val1, val2;
370 2 : Int normalize = 1;
371 :
372 2 : if (itruncate >= 0) {
373 0 : for (Int i=0 ; i<itruncate; i++) {
374 0 : x = Double(i) / Double(convSampling);
375 0 : grdgauss(&hwhm, &x, &val1);
376 0 : grdjinc1(&c, &x, &normalize, &val2);
377 0 : convFunc(i) = val1 * val2;
378 : }
379 : }
380 : else { // default is to truncate at first null
381 382 : for (Int i=0; i<convSize; i++) {
382 382 : x = Double(i) / Double(convSampling);
383 382 : grdjinc1(&c, &x, &normalize, &val2);
384 382 : if (val2 <= 0.0) {
385 : logIO() << LogIO::NORMAL3
386 : << "convFunc is automatically truncated at radius " << x
387 2 : << LogIO::POST;
388 2 : break;
389 : }
390 380 : grdgauss(&hwhm, &x, &val1);
391 380 : convFunc(i) = val1 * val2;
392 : }
393 : }
394 :
395 : // String outfile = convType + ".dat";
396 : // ofstream ofs(outfile.c_str());
397 : // for (Int i = 0 ; i < convSize ; i++) {
398 : // ofs << i << " " << convFunc[i] << endl;
399 : // }
400 : // ofs.close();
401 :
402 : }
403 : else { // Throw exception
404 0 : logIO_p << "Unknown convolution function: " << convType
405 0 : << LogIO::EXCEPTION;
406 : }
407 : }
408 :
409 144 : }
410 :
411 : // This is nasty, we should use CountedPointers here.
412 576 : SDGrid::~SDGrid() {
413 : //fclose(pfile);
414 288 : if (imageCache) delete imageCache; imageCache = 0;
415 288 : if (arrayLattice) delete arrayLattice; arrayLattice = 0;
416 288 : if (wImage) delete wImage; wImage = 0;
417 288 : if (wImageCache) delete wImageCache; wImageCache = 0;
418 288 : if (wArrayLattice) delete wArrayLattice; wArrayLattice = 0;
419 288 : if (interpolator) delete interpolator; interpolator = 0;
420 576 : }
421 :
422 144 : void SDGrid::initUVWMachine(const vi::VisBuffer2& vb) {
423 : // UVWMachine is not necessary for single dish imaging
424 144 : if (uvwMachine_p) delete uvwMachine_p; uvwMachine_p = 0;
425 144 : phaseShifter_p.reset();
426 :
427 144 : doUVWRotation_p=false;
428 144 : }
429 :
430 22 : void SDGrid::findPBAsConvFunction(const ImageInterface<Complex>& image,
431 : const vi::VisBuffer2& vb) {
432 :
433 : // Get the coordinate system and increase the sampling by
434 : // a factor of ~ 100.
435 22 : CoordinateSystem coords(image.coordinates());
436 :
437 : // Set up the convolution function: make the buffer plenty
438 : // big so that we can trim it back
439 22 : convSupport=max(128, sj_p->support(vb, coords));
440 :
441 22 : convSampling=100;
442 22 : convSize=convSampling*convSupport;
443 :
444 : // Make a one dimensional image to calculate the
445 : // primary beam. We oversample this by a factor of
446 : // convSampling.
447 22 : Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
448 22 : AlwaysAssert(directionIndex>=0, AipsError);
449 22 : DirectionCoordinate dc=coords.directionCoordinate(directionIndex);
450 22 : Vector<Double> sampling;
451 22 : sampling = dc.increment();
452 22 : sampling*=1.0/Double(convSampling);
453 22 : dc.setIncrement(sampling);
454 :
455 : // Set the reference value to the first pointing in the coordinate
456 : // system used in the POINTING table.
457 : {
458 22 : uInt row = 0;
459 :
460 : // reset lastAntID_p to use correct antenna position
461 22 : lastAntID_p = -1;
462 :
463 22 : const MSPointingColumns& act_mspc = vb.subtableColumns().pointing();
464 22 : Bool nullPointingTable = (act_mspc.nrow() < 1);
465 22 : Int pointIndex = -1;
466 22 : if (!nullPointingTable){
467 : //if(vb.newMS()) This thing is buggy...using msId change
468 22 : if (vb.msId() != msId_p) {
469 22 : lastIndex_p=0;
470 22 : if (lastIndexPerAnt_p.nelements() < (size_t)vb.nAntennas()) {
471 22 : lastIndexPerAnt_p.resize(vb.nAntennas());
472 : }
473 22 : lastIndexPerAnt_p = 0;
474 22 : msId_p = vb.msId();
475 : }
476 22 : pointIndex = getIndex(act_mspc, vb.time()(row), -1.0, vb.antenna1()(row));
477 22 : if (pointIndex < 0)
478 0 : pointIndex = getIndex(act_mspc, vb.time()(row), vb.timeInterval()(row), vb.antenna1()(row));
479 : }
480 22 : if (!nullPointingTable && ((pointIndex < 0) || (pointIndex >= Int(act_mspc.time().nrow())))) {
481 0 : ostringstream o;
482 0 : o << "Failed to find pointing information for time " <<
483 0 : MVTime(vb.time()(row)/86400.0);
484 0 : logIO_p << String(o) << LogIO::EXCEPTION;
485 0 : }
486 :
487 44 : MEpoch epoch(Quantity(vb.time()(row), "s"));
488 22 : if (!pointingToImage) {
489 22 : lastAntID_p = vb.antenna1()(row);
490 22 : MPosition pos = vb.subtableColumns().antenna().positionMeas()(lastAntID_p);
491 : //mFrame_p = MeasFrame(epoch, pos);
492 22 : (!mFrame_p.epoch()) ? mFrame_p.set(epoch) : mFrame_p.resetEpoch(epoch);
493 22 : (!mFrame_p.position()) ? mFrame_p.set(pos) : mFrame_p.resetPosition(pos);
494 22 : if (!nullPointingTable) {
495 22 : worldPosMeas = directionMeas(act_mspc, pointIndex);
496 : } else {
497 0 : worldPosMeas = vb.direction1()(row);
498 : }
499 :
500 : // Make a machine to convert from the worldPosMeas to the output
501 : // Direction Measure type for the relevant frame
502 22 : MDirection::Ref outRef(dc.directionType(), mFrame_p);
503 22 : pointingToImage = new MDirection::Convert(worldPosMeas, outRef);
504 22 : if (!pointingToImage) {
505 0 : logIO_p << "Cannot make direction conversion machine" << LogIO::EXCEPTION;
506 : }
507 :
508 22 : } else {
509 0 : mFrame_p.resetEpoch(epoch);
510 0 : if (lastAntID_p != vb.antenna1()(row)) {
511 0 : logIO_p << LogIO::DEBUGGING
512 : << "updating antenna position. MS ID " << msId_p
513 : << ", last antenna ID " << lastAntID_p
514 0 : << " new antenna ID " << vb.antenna1()(row) << LogIO::POST;
515 0 : lastAntID_p = vb.antenna1()(row);
516 0 : MPosition pos = vb.subtableColumns().antenna().positionMeas()(lastAntID_p);
517 0 : mFrame_p.resetPosition(pos);
518 0 : }
519 : }
520 :
521 22 : if (!nullPointingTable) {
522 22 : worldPosMeas = (*pointingToImage)(directionMeas(act_mspc, pointIndex));
523 : } else {
524 0 : worldPosMeas = (*pointingToImage)(vb.direction1()(row));
525 : }
526 22 : delete pointingToImage;
527 22 : pointingToImage = 0;
528 22 : }
529 :
530 22 : directionCoord = coords.directionCoordinate(directionIndex);
531 : //make sure we use the same units
532 22 : worldPosMeas.set(dc.worldAxisUnits()(0));
533 :
534 : // Reference pixel may be modified in dc.setReferenceValue when
535 : // projection type is SFL. To take into account this effect,
536 : // keep original reference pixel here and subtract it from
537 : // the reference pixel after dc.setReferenceValue instead
538 : // of setting reference pixel to (0,0).
539 22 : Vector<Double> const originalReferencePixel = dc.referencePixel();
540 22 : dc.setReferenceValue(worldPosMeas.getAngle().getValue());
541 : //Vector<Double> unitVec(2);
542 : //unitVec=0.0;
543 : //dc.setReferencePixel(unitVec);
544 44 : Vector<Double> updatedReferencePixel = dc.referencePixel() - originalReferencePixel;
545 22 : dc.setReferencePixel(updatedReferencePixel);
546 :
547 22 : coords.replaceCoordinate(dc, directionIndex);
548 :
549 22 : IPosition pbShape(4, convSize, 2, 1, 1);
550 22 : IPosition start(4, 0, 0, 0, 0);
551 :
552 22 : TempImage<Complex> onedPB(pbShape, coords);
553 :
554 22 : onedPB.set(Complex(1.0, 0.0));
555 :
556 22 : AlwaysAssert(sj_p, AipsError);
557 22 : sj_p->apply(onedPB, onedPB, vb, 0);
558 :
559 22 : IPosition pbSlice(4, convSize, 1, 1, 1);
560 44 : Vector<Float> tempConvFunc=real(onedPB.getSlice(start, pbSlice, true));
561 : // Find number of significant points
562 22 : uInt cfLen=0;
563 9137 : for(uInt i=0;i<tempConvFunc.nelements();++i) {
564 9137 : if(tempConvFunc(i)<1e-3) break;
565 9115 : ++cfLen;
566 : }
567 22 : if(cfLen<1) {
568 : logIO() << LogIO::SEVERE
569 : << "Possible problem in primary beam calculation: no points in gridding function"
570 0 : << " - no points to be gridded on this image?" << LogIO::POST;
571 0 : cfLen=1;
572 : }
573 22 : Vector<Float> trimConvFunc=tempConvFunc(Slice(0,cfLen-1,1));
574 :
575 : // Now fill in the convolution function vector
576 22 : convSupport=cfLen/convSampling;
577 22 : convSize=convSampling*(2*convSupport+2);
578 22 : convFunc.resize(convSize);
579 22 : convFunc=0.0;
580 22 : convFunc(Slice(0,cfLen-1,1))=trimConvFunc(Slice(0,cfLen-1,1));
581 :
582 :
583 22 : }
584 :
585 : // Initialize for a transform from the Sky domain. This means that
586 : // we grid-correct, and FFT the image
587 0 : void SDGrid::initializeToVis(ImageInterface<Complex>& iimage,
588 : const vi::VisBuffer2& vb)
589 : {
590 0 : image=&iimage;
591 :
592 0 : ok();
593 :
594 0 : init();
595 :
596 0 : if(convType=="pb") {
597 0 : findPBAsConvFunction(*image, vb);
598 : }
599 :
600 : // reset msId_p and lastAntID_p to -1
601 : // this is to ensure correct antenna position in getXYPos
602 0 : msId_p = -1;
603 0 : lastAntID_p = -1;
604 :
605 : // Initialize the maps for polarization and channel. These maps
606 : // translate visibility indices into image indices
607 0 : initMaps(vb);
608 :
609 : // First get the CoordinateSystem for the image and then find
610 : // the DirectionCoordinate
611 0 : CoordinateSystem coords=image->coordinates();
612 0 : Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
613 0 : AlwaysAssert(directionIndex>=0, AipsError);
614 0 : directionCoord=coords.directionCoordinate(directionIndex);
615 : /*if((image->shape().product())>cachesize) {
616 : isTiled=true;
617 : }
618 : else {
619 : isTiled=false;
620 : }*/
621 0 : isTiled=false;
622 0 : nx = image->shape()(0);
623 0 : ny = image->shape()(1);
624 0 : npol = image->shape()(2);
625 0 : nchan = image->shape()(3);
626 :
627 : // If we are memory-based then read the image in and create an
628 : // ArrayLattice otherwise just use the PagedImage
629 : /*if(isTiled) {
630 : lattice=image;
631 : wLattice=wImage;
632 : }
633 : else*/
634 : {
635 : // Make the grid the correct shape and turn it into an array lattice
636 0 : IPosition gridShape(4, nx, ny, npol, nchan);
637 0 : griddedData.resize(gridShape);
638 0 : griddedData = Complex(0.0);
639 :
640 0 : wGriddedData.resize(gridShape);
641 0 : wGriddedData = 0.0;
642 :
643 0 : if(arrayLattice) delete arrayLattice; arrayLattice=0;
644 0 : arrayLattice = new ArrayLattice<Complex>(griddedData);
645 :
646 0 : if(wArrayLattice) delete wArrayLattice; wArrayLattice=0;
647 0 : wArrayLattice = new ArrayLattice<Float>(wGriddedData);
648 0 : wArrayLattice->set(0.0);
649 0 : wLattice=wArrayLattice;
650 :
651 : // Now find the SubLattice corresponding to the image
652 0 : IPosition blc(4, (nx-image->shape()(0)+(nx%2==0))/2, (ny-image->shape()(1)+(ny%2==0))/2, 0, 0);
653 0 : IPosition stride(4, 1);
654 0 : IPosition trc(blc+image->shape()-stride);
655 0 : LCBox gridBox(blc, trc, gridShape);
656 0 : SubLattice<Complex> gridSub(*arrayLattice, gridBox, true);
657 :
658 : // Do the copy
659 0 : gridSub.copyData(*image);
660 :
661 0 : lattice=arrayLattice;
662 0 : }
663 0 : AlwaysAssert(lattice, AipsError);
664 0 : AlwaysAssert(wLattice, AipsError);
665 0 : }
666 :
667 0 : void SDGrid::finalizeToVis()
668 : {
669 : /*if(isTiled) {
670 :
671 : logIO() << LogOrigin("SDGrid", "finalizeToVis") << LogIO::NORMAL;
672 :
673 : AlwaysAssert(imageCache, AipsError);
674 : AlwaysAssert(image, AipsError);
675 : ostringstream o;
676 : imageCache->flush();
677 : imageCache->showCacheStatistics(o);
678 : logIO() << o.str() << LogIO::POST;
679 : }*/
680 0 : if(pointingToImage) delete pointingToImage; pointingToImage=0;
681 0 : }
682 :
683 :
684 : // Initialize the FFT to the Sky.
685 : // Here we have to setup and initialize the grid.
686 144 : void SDGrid::initializeToSky(ImageInterface<Complex>& iimage,
687 : Matrix<Float>& weight, const vi::VisBuffer2& vb)
688 : {
689 : // image always points to the image
690 144 : image=&iimage;
691 :
692 144 : ok();
693 :
694 144 : init();
695 :
696 144 : if(convType=="pb") {
697 22 : findPBAsConvFunction(*image, vb);
698 : }
699 :
700 : // reset msId_p and lastAntID_p to -1
701 : // this is to ensure correct antenna position in getXYPos
702 144 : msId_p = -1;
703 144 : lastAntID_p = -1;
704 :
705 : // Initialize the maps for polarization and channel. These maps
706 : // translate visibility indices into image indices
707 144 : initMaps(vb);
708 : //cerr << "ToSky cachesize " << cachesize << " im shape " << (image->shape().product()) << endl;
709 : /*if((image->shape().product())>cachesize) {
710 : isTiled=true;
711 : }
712 : else {
713 : isTiled=false;
714 : }
715 : */
716 : //////////////No longer using isTiled
717 144 : isTiled=false;
718 144 : nx = image->shape()(0);
719 144 : ny = image->shape()(1);
720 144 : npol = image->shape()(2);
721 144 : nchan = image->shape()(3);
722 :
723 144 : sumWeight=0.0;
724 144 : weight.resize(sumWeight.shape());
725 144 : weight=0.0;
726 :
727 : // First get the CoordinateSystem for the image and then find
728 : // the DirectionCoordinate
729 144 : CoordinateSystem coords=image->coordinates();
730 144 : Int directionIndex=coords.findCoordinate(Coordinate::DIRECTION);
731 144 : AlwaysAssert(directionIndex>=0, AipsError);
732 144 : directionCoord=coords.directionCoordinate(directionIndex);
733 :
734 : // Initialize for in memory or to disk gridding. lattice will
735 : // point to the appropriate Lattice, either the ArrayLattice for
736 : // in memory gridding or to the image for to disk gridding.
737 : /*if(isTiled) {
738 : imageCache->flush();
739 : image->set(Complex(0.0));
740 : lattice=image;
741 : wLattice=wImage;
742 : }
743 : else*/
744 : {
745 144 : IPosition gridShape(4, nx, ny, npol, nchan);
746 288 : logIO() << LogOrigin("SDGrid", "initializeToSky", WHERE) << LogIO::DEBUGGING
747 288 : << "gridShape = " << gridShape << LogIO::POST;
748 144 : griddedData.resize(gridShape);
749 144 : griddedData=Complex(0.0);
750 144 : if(arrayLattice) delete arrayLattice; arrayLattice=0;
751 144 : arrayLattice = new ArrayLattice<Complex>(griddedData);
752 144 : lattice=arrayLattice;
753 144 : wGriddedData.resize(gridShape);
754 144 : wGriddedData=0.0;
755 144 : if(wArrayLattice) delete wArrayLattice; wArrayLattice=0;
756 144 : wArrayLattice = new ArrayLattice<Float>(wGriddedData);
757 144 : wLattice=wArrayLattice;
758 :
759 : // clipping related stuff
760 144 : if (clipminmax_) {
761 8 : gmin_.resize(gridShape);
762 8 : gmin_ = Complex(FLT_MAX);
763 8 : gmax_.resize(gridShape);
764 8 : gmax_ = Complex(-FLT_MAX);
765 8 : wmin_.resize(gridShape);
766 8 : wmin_ = 0.0f;
767 8 : wmax_.resize(gridShape);
768 8 : wmax_ = 0.0f;
769 8 : npoints_.resize(gridShape);
770 8 : npoints_ = 0;
771 : }
772 144 : }
773 144 : AlwaysAssert(lattice, AipsError);
774 144 : AlwaysAssert(wLattice, AipsError);
775 144 : }
776 :
777 144 : void SDGrid::finalizeToSky()
778 : {
779 :
780 : // Now we flush the cache and report statistics
781 : // For memory based, we don't write anything out yet.
782 : /*if(isTiled) {
783 : logIO() << LogOrigin("SDGrid", "finalizeToSky") << LogIO::NORMAL;
784 :
785 : AlwaysAssert(image, AipsError);
786 : AlwaysAssert(imageCache, AipsError);
787 : imageCache->flush();
788 : ostringstream o;
789 : imageCache->showCacheStatistics(o);
790 : logIO() << o.str() << LogIO::POST;
791 : }
792 : */
793 :
794 144 : if(pointingToImage) delete pointingToImage; pointingToImage=0;
795 144 : }
796 :
797 0 : Array<Complex>* SDGrid::getDataPointer(const IPosition& centerLoc2D,
798 : Bool readonly) {
799 : Array<Complex>* result;
800 : // Is tiled: get tiles and set up offsets
801 0 : centerLoc(0)=centerLoc2D(0);
802 0 : centerLoc(1)=centerLoc2D(1);
803 0 : result=&imageCache->tile(offsetLoc, centerLoc, readonly);
804 0 : return result;
805 : }
806 0 : Array<Float>* SDGrid::getWDataPointer(const IPosition& centerLoc2D,
807 : Bool readonly) {
808 : Array<Float>* result;
809 : // Is tiled: get tiles and set up offsets
810 0 : centerLoc(0)=centerLoc2D(0);
811 0 : centerLoc(1)=centerLoc2D(1);
812 0 : result=&wImageCache->tile(offsetLoc, centerLoc, readonly);
813 0 : return result;
814 : }
815 :
816 : #define NEED_UNDERSCORES
817 : #if defined(NEED_UNDERSCORES)
818 : #define ggridsd ggridsd_
819 : #define dgridsd dgridsd_
820 : #define ggridsdclip ggridsdclip_
821 : #endif
822 :
823 : extern "C" { // Gridders interfaces
824 : void ggridsd(
825 : Double*,
826 : const Complex*,
827 : Int*,
828 : Int*,
829 : Int*,
830 : const Int*,
831 : const Int*,
832 : const Float*,
833 : Int*,
834 : Int*,
835 : Complex*,
836 : Float*,
837 : Int*,
838 : Int*,
839 : Int*,
840 : Int*,
841 : Int*,
842 : Int*,
843 : Float*,
844 : Int*,
845 : Int*,
846 : Double*
847 : );
848 : void ggridsdclip(
849 : Double*,
850 : const Complex*,
851 : Int*,
852 : Int*,
853 : Int*,
854 : const Int*,
855 : const Int*,
856 : const Float*,
857 : Int*,
858 : Int*,
859 : Complex*,
860 : Float*,
861 : Int*,
862 : Complex*,
863 : Float*,
864 : Complex*,
865 : Float*,
866 : Int*,
867 : Int*,
868 : Int *,
869 : Int *,
870 : Int*,
871 : Int*,
872 : Float*,
873 : Int*,
874 : Int*,
875 : Double*
876 : );
877 : void dgridsd(
878 : Double*,
879 : Complex*,
880 : Int*,
881 : Int*,
882 : const Int*,
883 : const Int*,
884 : Int*,
885 : Int*,
886 : const Complex*,
887 : Int*,
888 : Int*,
889 : Int *,
890 : Int *,
891 : Int*,
892 : Int*,
893 : Float*,
894 : Int*,
895 : Int*
896 : );
897 : }
898 :
899 203819 : void SDGrid::put(const vi::VisBuffer2& vb, Int row, Bool dopsf,
900 : FTMachine::Type type)
901 : {
902 407638 : LogIO os(LogOrigin("SDGrid", "put"));
903 :
904 203819 : gridOk(convSupport);
905 :
906 : // There is no channel mapping cache in VI/VB2 version of FTMachine
907 : // Perform matchChannel everytime
908 203819 : matchChannel(vb);
909 :
910 : // No point in reading data if its not matching in frequency
911 203819 : if (max(chanMap)==-1) return;
912 :
913 184604 : Matrix<Float> imagingweight;
914 : //imagingweight=&(vb.imagingWeight());
915 184604 : pickWeights(vb, imagingweight);
916 :
917 184604 : if (type==FTMachine::PSF || type==FTMachine::COVERAGE) dopsf=true;
918 184604 : if (dopsf) type=FTMachine::PSF;
919 184604 : Cube<Complex> data;
920 184604 : Cube<Int> flags; //Fortran gridder need the flag as ints
921 184604 : Matrix<Float> elWeight;
922 184604 : interpolateFrequencyTogrid(vb, imagingweight,data, flags, elWeight, type);
923 : //cerr << "number of rows " << vb.nRow()
924 : // << " data shape " << data.shape() << endl;
925 : Bool iswgtCopy;
926 : const Float *wgtStorage;
927 184604 : wgtStorage=elWeight.getStorage(iswgtCopy);
928 : Bool isCopy;
929 184604 : const Complex *datStorage=0;
930 184604 : if (!dopsf) datStorage=data.getStorage(isCopy);
931 :
932 : // If row is -1 then we pass through all rows
933 : Int startRow, endRow, nRow;
934 184604 : if (row==-1) {
935 184604 : nRow=vb.nRows();
936 184604 : startRow=0;
937 184604 : endRow=nRow-1;
938 : } else {
939 0 : nRow=1;
940 0 : startRow=row;
941 0 : endRow=row;
942 : }
943 :
944 184604 : Vector<Int> rowFlags(vb.flagRow().nelements(), 0);
945 376493 : for (Int rownr=startRow; rownr<=endRow; rownr++) {
946 191889 : if(vb.flagRow()(rownr)) rowFlags(rownr)=1;
947 : }
948 :
949 : // Take care of translation of Bools to Integer
950 184604 : Int idopsf = dopsf ? 1 : 0;
951 :
952 : { // Compute spectra pixel coordinates and call gridder
953 : // Make sure failed getXYPos does not fall on grid
954 184604 : constexpr Double kFarAway = -1e9;
955 184604 : Matrix<Double> xyPositions(2, endRow-startRow+1, kFarAway);
956 376493 : for (Int rownr=startRow; rownr<=endRow; rownr++) {
957 191889 : if (getXYPos(vb, rownr)) {
958 191889 : xyPositions(0, rownr)=xyPos(0);
959 191889 : xyPositions(1, rownr)=xyPos(1);
960 : }
961 : }
962 : { // Call gridder
963 : Bool del;
964 184604 : const IPosition& fs=flags.shape();
965 184604 : std::vector<Int> s(fs.begin(), fs.end());
966 : Bool datCopy, wgtCopy;
967 184604 : Complex * datStor=griddedData.getStorage(datCopy);
968 184604 : Float * wgtStor=wGriddedData.getStorage(wgtCopy);
969 :
970 : //Bool call_ggridsd = !clipminmax_ || dopsf;
971 184604 : Bool call_ggridsd = !clipminmax_;
972 :
973 184604 : if (call_ggridsd) { // Call plain gridder
974 :
975 369158 : ggridsd(
976 : xyPositions.getStorage(del),
977 : datStorage,
978 184579 : &s[0],
979 184579 : &s[1],
980 : &idopsf,
981 184579 : flags.getStorage(del),
982 184579 : rowFlags.getStorage(del),
983 : wgtStorage,
984 184579 : &s[2],
985 : &row,
986 : datStor,
987 : wgtStor,
988 : &nx,
989 : &ny,
990 : &npol,
991 : &nchan,
992 : &convSupport,
993 : &convSampling,
994 : convFunc.getStorage(del),
995 : chanMap.getStorage(del),
996 : polMap.getStorage(del),
997 : sumWeight.getStorage(del)
998 : );
999 :
1000 : } else { // Call clipping gridder
1001 : Bool gminCopy;
1002 25 : Complex *gminStor = gmin_.getStorage(gminCopy);
1003 : Bool gmaxCopy;
1004 25 : Complex *gmaxStor = gmax_.getStorage(gmaxCopy);
1005 : Bool wminCopy;
1006 25 : Float *wminStor = wmin_.getStorage(wminCopy);
1007 : Bool wmaxCopy;
1008 25 : Float *wmaxStor = wmax_.getStorage(wmaxCopy);
1009 : Bool npCopy;
1010 25 : Int *npStor = npoints_.getStorage(npCopy);
1011 :
1012 50 : ggridsdclip(
1013 : xyPositions.getStorage(del),
1014 : datStorage,
1015 25 : &s[0],
1016 25 : &s[1],
1017 : &idopsf,
1018 25 : flags.getStorage(del),
1019 25 : rowFlags.getStorage(del),
1020 : wgtStorage,
1021 25 : &s[2],
1022 : &row,
1023 : datStor,
1024 : wgtStor,
1025 : npStor,
1026 : gminStor,
1027 : wminStor,
1028 : gmaxStor,
1029 : wmaxStor,
1030 : &nx,
1031 : &ny,
1032 : &npol,
1033 : &nchan,
1034 : &convSupport,
1035 : &convSampling,
1036 : convFunc.getStorage(del),
1037 : chanMap.getStorage(del),
1038 : polMap.getStorage(del),
1039 : sumWeight.getStorage(del)
1040 : );
1041 :
1042 25 : gmin_.putStorage(gminStor, gminCopy);
1043 25 : gmax_.putStorage(gmaxStor, gmaxCopy);
1044 25 : wmin_.putStorage(wminStor, wminCopy);
1045 25 : wmax_.putStorage(wmaxStor, wmaxCopy);
1046 25 : npoints_.putStorage(npStor, npCopy);
1047 : }
1048 184604 : griddedData.putStorage(datStor, datCopy);
1049 184604 : wGriddedData.putStorage(wgtStor, wgtCopy);
1050 184604 : }
1051 184604 : }
1052 :
1053 : { // Free memory
1054 184604 : if (!dopsf) data.freeStorage(datStorage, isCopy);
1055 :
1056 184604 : elWeight.freeStorage(wgtStorage, iswgtCopy);
1057 : }
1058 :
1059 203819 : }
1060 :
1061 0 : void SDGrid::get(vi::VisBuffer2& vb, Int row)
1062 : {
1063 0 : LogIO os(LogOrigin("SDGrid", "get"));
1064 :
1065 0 : gridOk(convSupport);
1066 :
1067 : // If row is -1 then we pass through all rows
1068 : Int startRow, endRow, nRow;
1069 0 : if (row==-1) {
1070 0 : nRow=vb.nRows();
1071 0 : startRow=0;
1072 0 : endRow=nRow-1;
1073 : // TODO: ask imager guru if commenting out the following line
1074 : // is safe for SDGrid
1075 : //unnecessary zeroing
1076 : //vb.modelVisCube()=Complex(0.0,0.0);
1077 : } else {
1078 0 : nRow=1;
1079 0 : startRow=row;
1080 0 : endRow=row;
1081 : // TODO: ask imager guru if commenting out the following line
1082 : // is safe for SDGrid
1083 : //unnecessary zeroing
1084 : //vb.modelVisCube().xyPlane(row)=Complex(0.0,0.0);
1085 : }
1086 :
1087 : // There is no channel mapping cache in VI/VB2 version of FTMachine
1088 : // Perform matchChannel everytime
1089 0 : matchChannel(vb);
1090 :
1091 : //No point in reading data if its not matching in frequency
1092 0 : if(max(chanMap)==-1)
1093 0 : return;
1094 0 : Cube<Complex> data;
1095 0 : Cube<Int> flags;
1096 0 : getInterpolateArrays(vb, data, flags);
1097 :
1098 : Complex *datStorage;
1099 : Bool isCopy;
1100 0 : datStorage=data.getStorage(isCopy);
1101 : // NOTE: with MS V2.0 the pointing could change per antenna and timeslot
1102 : //
1103 0 : Vector<Int> rowFlags(vb.flagRow().nelements());
1104 0 : rowFlags=0;
1105 0 : for (Int rownr=startRow; rownr<=endRow; rownr++) {
1106 0 : if(vb.flagRow()(rownr)) rowFlags(rownr)=1;
1107 : //single dish yes ?
1108 0 : if(max(vb.uvw().column(rownr)) > 0.0) rowFlags(rownr)=1;
1109 : }
1110 :
1111 :
1112 : /*if(isTiled) {
1113 :
1114 : for (Int rownr=startRow; rownr<=endRow; rownr++) {
1115 :
1116 : if(getXYPos(vb, rownr)) {
1117 :
1118 : // Get the tile
1119 : IPosition centerLoc2D(2, Int(xyPos(0)), Int(xyPos(1)));
1120 : Array<Complex>* dataPtr=getDataPointer(centerLoc2D, true);
1121 : Int aNx=dataPtr->shape()(0);
1122 : Int aNy=dataPtr->shape()(1);
1123 :
1124 : // Now use FORTRAN to do the gridding. Remember to
1125 : // ensure that the shape and offsets of the tile are
1126 : // accounted for.
1127 : Bool del;
1128 : Vector<Double> actualPos(2);
1129 : for (Int i=0;i<2;i++) {
1130 : actualPos(i)=xyPos(i)-Double(offsetLoc(i));
1131 : }
1132 : // IPosition s(data.shape());
1133 : const IPosition& fs=data.shape();
1134 : std::vector<Int> s(fs.begin(), fs.end());
1135 :
1136 : dgridsd(actualPos.getStorage(del),
1137 : datStorage,
1138 : &s[0],
1139 : &s[1],
1140 : flags.getStorage(del),
1141 : rowFlags.getStorage(del),
1142 : &s[2],
1143 : &rownr,
1144 : dataPtr->getStorage(del),
1145 : &aNx,
1146 : &aNy,
1147 : &npol,
1148 : &nchan,
1149 : &convSupport,
1150 : &convSampling,
1151 : convFunc.getStorage(del),
1152 : chanMap.getStorage(del),
1153 : polMap.getStorage(del));
1154 : }
1155 : }
1156 : }
1157 : else*/
1158 : {
1159 0 : Matrix<Double> xyPositions(2, endRow-startRow+1);
1160 0 : xyPositions=-1e9;
1161 0 : for (Int rownr=startRow; rownr<=endRow; rownr++) {
1162 0 : if(getXYPos(vb, rownr)) {
1163 0 : xyPositions(0, rownr)=xyPos(0);
1164 0 : xyPositions(1, rownr)=xyPos(1);
1165 : }
1166 : }
1167 :
1168 : Bool del;
1169 : // IPosition s(data.shape());
1170 0 : const IPosition& fs=data.shape();
1171 0 : std::vector<Int> s(fs.begin(), fs.end());
1172 0 : dgridsd(xyPositions.getStorage(del),
1173 : datStorage,
1174 0 : &s[0],
1175 0 : &s[1],
1176 0 : flags.getStorage(del),
1177 0 : rowFlags.getStorage(del),
1178 0 : &s[2],
1179 : &row,
1180 0 : griddedData.getStorage(del),
1181 : &nx,
1182 : &ny,
1183 : &npol,
1184 : &nchan,
1185 : &convSupport,
1186 : &convSampling,
1187 : convFunc.getStorage(del),
1188 : chanMap.getStorage(del),
1189 : polMap.getStorage(del));
1190 :
1191 0 : data.putStorage(datStorage, isCopy);
1192 0 : }
1193 0 : interpolateFrequencyFromgrid(vb, data, FTMachine::MODEL);
1194 0 : }
1195 :
1196 :
1197 170 : Bool SDGrid::mustConvertPointingColumn(const MeasurementSet &ms)
1198 : {
1199 170 : const auto havePointings = ms.pointing().nrow() > 0;
1200 170 : if (not havePointings) return false;
1201 :
1202 170 : switch(convertFirst) {
1203 170 : case ConvertFirst::ALWAYS: return true;
1204 170 : case ConvertFirst::NEVER: return false;
1205 0 : case ConvertFirst::AUTO:
1206 : {
1207 0 : const auto nPointings = ms.pointing().nrow();
1208 0 : const auto nSelectedDataRows = ms.nrow();
1209 0 : return nSelectedDataRows > nPointings ? true : false;
1210 : }
1211 0 : default:
1212 0 : LogIO logger(LogOrigin("SDGrid", "mustConvertPointingColumn", WHERE));
1213 : logger << "Bug ! Got unexpected value for SDGrid::convertFirst: "
1214 0 : << int(convertFirst)
1215 0 : << LogIO::EXCEPTION;
1216 : }
1217 0 : return false;
1218 : }
1219 :
1220 0 : void SDGrid::convertPointingColumn(
1221 : const MeasurementSet &ms,
1222 : const MSPointingEnums::PredefinedColumns columnToConvert,
1223 : const MDirection::Types directionRef)
1224 : {
1225 0 : LogIO logger(LogOrigin("SDGrid", "convertPointingColumn"));
1226 :
1227 : const auto & nameOfColumnToConvert =
1228 0 : MSPointing::columnName(columnToConvert);
1229 :
1230 0 : const auto & nameOfDirectionRef = MDirection::showType(directionRef);
1231 :
1232 : logger << "Converting POINTING table column: " << nameOfColumnToConvert
1233 : << " to: " << nameOfDirectionRef
1234 0 : << LogIO::POST;
1235 :
1236 : { // Check parameters
1237 : using POINTING = MSPointingEnums::PredefinedColumns;
1238 : // Column must be a direction column
1239 0 : const auto isDirectionColumn = (
1240 : columnToConvert == POINTING::DIRECTION
1241 0 : or columnToConvert == POINTING::TARGET
1242 0 : or columnToConvert == POINTING::POINTING_OFFSET
1243 0 : or columnToConvert == POINTING::SOURCE_OFFSET
1244 0 : or columnToConvert == POINTING::ENCODER
1245 : );
1246 0 : if (not isDirectionColumn) {
1247 : logger << nameOfColumnToConvert << ": not a direction column"
1248 0 : << LogIO::EXCEPTION;
1249 : }
1250 : }
1251 :
1252 : { // Copy Pointing table structure
1253 0 : constexpr auto doNotCopyRows = True;
1254 0 : ramPointingTable = ms.pointing().copyToMemoryTable(
1255 0 : ms.pointing().tableName() +
1256 0 : "." + MSPointing::columnName(columnToConvert) +
1257 0 : "." + MDirection::showType(directionRef),
1258 : doNotCopyRows
1259 0 : );
1260 0 : ramPointingColumnsPtr.reset(new MSPointingColumns {ramPointingTable});
1261 : }
1262 :
1263 : { // Set the reference frame of the direction columns
1264 : // ---- All direction columns, except the encoder column
1265 0 : ramPointingColumnsPtr->setDirectionRef(directionRef);
1266 : // ---- Encoder column
1267 0 : ramPointingColumnsPtr->setEncoderDirectionRef(directionRef);
1268 : }
1269 :
1270 0 : auto quote = [](const String & s) {
1271 0 : return String("\"") + s + String("\"");
1272 : };
1273 :
1274 : { // Perform 1 dummy conversion:
1275 : // Convert the direction of the first pointing
1276 : // 1 day before it was actually recorded
1277 : // to pre-set static variables in casacore functions like dUT1
1278 : // so that we are sure they will be updated when we convert the column
1279 0 : stringstream dummyConversion; // TaQL command
1280 : { // Create it
1281 : dummyConversion <<
1282 : "using style python\n"
1283 : "select\n"
1284 : " [\n"
1285 : " meas.direction(\n" <<
1286 0 : " " << quote(nameOfDirectionRef) << "\n"
1287 : " , pointing.DIRECTION\n"
1288 : " , (pointing.TIME - 1d), 'UTC'\n"
1289 : " , antenna.POSITION\n"
1290 : " )\n"
1291 : " ] as CONVERTED_DIRECTION_ONE_DAY_BEFORE\n"
1292 : " , (pointing.TIME - 1d) d as oneDayBefore\n"
1293 : " , pointing.TIME d as pointingDay\n"
1294 : " , cdatetime(pointing.TIME) as pointingDay_Str\n"
1295 : " , cdatetime(pointing.TIME -1d) as oneDayBefore_Str\n"
1296 : "from\n"
1297 : " $1 as pointing\n"
1298 : "join\n"
1299 : " $2 as antenna\n"
1300 : " on pointing.ANTENNA_ID == antenna.rowid()\n"
1301 : "where\n"
1302 0 : " pointing.rowid() == 0\n"
1303 : ;
1304 : }
1305 : { // Execute it
1306 : vector<const Table*> tables {
1307 0 : &ms.pointing(), // $1
1308 0 : &ms.antenna(), // $2
1309 0 : };
1310 0 : tableCommand(dummyConversion.str(), tables);
1311 0 : }
1312 0 : }
1313 :
1314 : { // Now convert the column
1315 0 : stringstream convertColumn; // TaQL command
1316 : { // Create it
1317 : convertColumn <<
1318 : "using style python\n"
1319 : "insert\n"
1320 : " into $3 as ram_pointing_table\n"
1321 : " (\n"
1322 : " ANTENNA_ID\n"
1323 : " , TIME\n"
1324 : " , INTERVAL\n"
1325 : " , NUM_POLY\n"
1326 0 : " , " << nameOfColumnToConvert << "\n"
1327 : " )\n"
1328 : "select\n"
1329 : " ANTENNA_ID as ANTENNA_ID_INT INTEGER\n"
1330 : " , TIME\n"
1331 : " , INTERVAL\n"
1332 0 : " , 0 as NUM_POLY INTEGER\n";
1333 : using Pointing = MSPointingEnums::PredefinedColumns;
1334 0 : switch(columnToConvert) {
1335 0 : case Pointing::ENCODER: { // ScalarColumn
1336 : convertColumn <<
1337 : " , meas.direction(\n"
1338 0 : " " << quote(nameOfDirectionRef) << "\n"
1339 0 : " , pointing." << nameOfColumnToConvert << "\n"
1340 : " , pointing.TIME\n"
1341 : " , antenna.POSITION\n"
1342 0 : " )\n"
1343 : ;
1344 0 : break;
1345 : }
1346 0 : default: { // All other direction columns are ArrayColumns
1347 : convertColumn <<
1348 : " , [\n"
1349 : " meas.direction(\n"
1350 0 : " " << quote(nameOfDirectionRef) << "\n"
1351 0 : " , pointing." << nameOfColumnToConvert << "\n"
1352 : " , pointing.TIME\n"
1353 : " , antenna.POSITION\n"
1354 : " )\n"
1355 0 : " ]\n"
1356 : ;
1357 : }
1358 : }
1359 : convertColumn <<
1360 : "from\n"
1361 : " $1 as pointing\n"
1362 : "join\n"
1363 : " $2 as antenna\n"
1364 0 : " on pointing.ANTENNA_ID = antenna.rowid()\n";
1365 : }
1366 : { // Execute it
1367 : vector<const casacore::Table*> tables {
1368 0 : &ms.pointing(), // $1
1369 0 : &ms.antenna(), // $2
1370 : &ramPointingTable // $3
1371 0 : };
1372 0 : tableCommand(convertColumn.str(), tables);
1373 0 : }
1374 0 : }
1375 : logger << "Converted POINTING table column: " << nameOfColumnToConvert
1376 : << " to: " << nameOfDirectionRef
1377 0 : << LogIO::POST;
1378 0 : }
1379 :
1380 0 : void SDGrid::handleNewMs(
1381 : const MeasurementSet &ms,
1382 : ImageInterface<Complex>& image)
1383 : {
1384 0 : if (mustConvertPointingColumn(ms)) {
1385 0 : const auto columnEnum = MSPointing::columnType(pointingDirCol_p);
1386 : const auto imageDirectionRef =
1387 0 : image.coordinates().directionCoordinate().directionType();
1388 0 : convertPointingColumn(ms, columnEnum, imageDirectionRef);
1389 : }
1390 : else {
1391 0 : ramPointingTable = MSPointing();
1392 0 : ramPointingColumnsPtr.reset();
1393 : }
1394 0 : }
1395 :
1396 170 : void SDGrid::handleNewMs(const MeasurementSet & ms,
1397 : CountedPtr<SIImageStore> imstore)
1398 : {
1399 170 : if (imstore.null()) return;
1400 :
1401 170 : if (mustConvertPointingColumn(ms)) {
1402 0 : const auto coordinateSystem = imstore->getCSys();
1403 : const auto imagesDirectionRef =
1404 0 : coordinateSystem.directionCoordinate()
1405 0 : .directionType();
1406 0 : const auto columnEnum = MSPointing::columnType(pointingDirCol_p);
1407 0 : convertPointingColumn(ms, columnEnum, imagesDirectionRef);
1408 0 : }
1409 : else {
1410 170 : ramPointingTable = MSPointing();
1411 170 : ramPointingColumnsPtr.reset();
1412 : }
1413 : }
1414 :
1415 : // Make a plain straightforward honest-to-FSM image. This returns
1416 : // a complex image, without conversion to Stokes. The representation
1417 : // is that required for the visibilities.
1418 : //----------------------------------------------------------------------
1419 0 : void SDGrid::makeImage(
1420 : FTMachine::Type type,
1421 : vi::VisibilityIterator2& vi,
1422 : ImageInterface<Complex>& theImage,
1423 : Matrix<Float>& weight) {
1424 :
1425 0 : logIO() << LogOrigin("FTMachine", "makeImage0") << LogIO::NORMAL;
1426 :
1427 0 : vi::VisBuffer2 *vb = vi.getVisBuffer();
1428 0 : vi.origin();
1429 :
1430 : { // Set Stokes Representation
1431 0 : if (vb->polarizationFrame()==MSIter::Linear) {
1432 0 : StokesImageUtil::changeCStokesRep(theImage, StokesImageUtil::LINEAR);
1433 : }
1434 : else {
1435 0 : StokesImageUtil::changeCStokesRep(theImage, StokesImageUtil::CIRCULAR);
1436 : }
1437 : }
1438 :
1439 0 : if (type==FTMachine::CORRECTED) { // What if we have no correctedData ?
1440 : const auto haveCorrectedData = not (
1441 0 : MSMainColumns(vi.ms()).correctedData().isNull()
1442 0 : );
1443 0 : if (not haveCorrectedData) {
1444 0 : type = FTMachine::OBSERVED;
1445 : }
1446 : }
1447 :
1448 0 : Bool normalize = (type==FTMachine::COVERAGE) ? false : true;
1449 :
1450 0 : Int Nx = theImage.shape()(0);
1451 0 : Int Ny = theImage.shape()(1);
1452 0 : Int Npol = theImage.shape()(2);
1453 0 : Int Nchan = theImage.shape()(3);
1454 :
1455 0 : Double memtot = Double(HostInfo::memoryTotal(true))*1024.0; // return in kB
1456 0 : Int nchanInMem = Int(memtot/2.0/8.0/Double(Nx*Ny*Npol));
1457 0 : Int nloop = nchanInMem >= Nchan ? 1 : Nchan/nchanInMem+1;
1458 :
1459 0 : ImageInterface<Complex> *imCopy = NULL;
1460 : { // Initialize imCopy if needed
1461 0 : if (nloop==1) {
1462 0 : imCopy = &theImage;
1463 0 : nchanInMem = Nchan;
1464 : }
1465 : else {
1466 : logIO() << "Not enough memory to image in one go \n"
1467 : << " will process the image in " << nloop << " sections"
1468 0 : << LogIO::POST;
1469 : }
1470 : }
1471 :
1472 0 : weight.resize(Npol, Nchan);
1473 0 : Matrix<Float> wgtcopy(Npol, Nchan);
1474 :
1475 0 : Bool isWgtZero = true;
1476 0 : IPosition blc(theImage.shape().size(), 0);
1477 0 : IPosition trc(theImage.shape() - 1);
1478 0 : for (Int k=0; k < nloop; ++k) {
1479 : Int bchan; // Slice boundaries along the channel axis
1480 : Int echan;
1481 : { // Compute them
1482 0 : bchan = k*nchanInMem;
1483 0 : echan = (k+1)*nchanInMem < Nchan ? (k+1)*nchanInMem-1 : Nchan-1;
1484 : }
1485 :
1486 0 : if (nloop > 1) { // Slide. Copy of a slice of theImage
1487 0 : blc[3] = bchan;
1488 0 : trc[3] = echan;
1489 0 : Slicer sl(blc, trc, Slicer::endIsLast);
1490 0 : imCopy = new SubImage<Complex>(theImage, sl, true);
1491 0 : wgtcopy.resize(npol, echan-bchan+1);
1492 0 : }
1493 :
1494 : { // Rewind iterator, initializeToSky
1495 0 : vi.originChunks();
1496 0 : vi.origin();
1497 0 : initializeToSky(*imCopy, wgtcopy, *vb);
1498 : }
1499 :
1500 : { // Debug messages for minmax clipping
1501 0 : logIO() << LogOrigin("SDGrid", "makeImage", WHERE) << LogIO::DEBUGGING
1502 0 : << "doclip_ = " << (clipminmax_ ? "TRUE" : "FALSE")
1503 0 : << " (" << clipminmax_ << ")"
1504 0 : << LogIO::POST;
1505 0 : if (clipminmax_) {
1506 0 : logIO() << LogOrigin("SDGrid", "makeImage", WHERE) << LogIO::DEBUGGING
1507 : << "use ggridsd2 for imaging"
1508 0 : << LogIO::POST;
1509 : }
1510 : }
1511 :
1512 : // Loop over the visibilities, putting VisBuffers
1513 0 : for (vi.originChunks(); vi.moreChunks(); vi.nextChunk()) {
1514 0 : if (vi.getImpl()->isNewMs()) {
1515 : // When we pre-convert the user-specified POINTING column
1516 : // - e.g. when convertFirst = always -, re-converting it
1517 : // at each slice iteration is an implementation decision.
1518 : // The slice loop is probably rarely used, and when it is
1519 : // it means we have little RAM available.
1520 0 : handleNewMs(vi.ms(), theImage);
1521 : }
1522 0 : for (vi.origin(); vi.more(); vi.next()) {
1523 0 : switch(type) {
1524 0 : case FTMachine::RESIDUAL:
1525 0 : vb->setVisCube(vb->visCubeCorrected() - vb->visCubeModel());
1526 0 : put(*vb, -1, false);
1527 0 : break;
1528 0 : case FTMachine::MODEL:
1529 0 : put(*vb, -1, false, FTMachine::MODEL);
1530 0 : break;
1531 0 : case FTMachine::CORRECTED:
1532 0 : put(*vb, -1, false, FTMachine::CORRECTED);
1533 0 : break;
1534 0 : case FTMachine::PSF:
1535 0 : vb->setVisCube(Complex(1.0,0.0));
1536 0 : put(*vb, -1, true, FTMachine::PSF);
1537 0 : break;
1538 0 : case FTMachine::COVERAGE:
1539 0 : vb->setVisCube(Complex(1.0));
1540 0 : put(*vb, -1, true, FTMachine::COVERAGE);
1541 0 : break;
1542 0 : case FTMachine::OBSERVED:
1543 : default:
1544 0 : put(*vb, -1, false, FTMachine::OBSERVED);
1545 0 : break;
1546 : }
1547 : }
1548 : }
1549 :
1550 0 : finalizeToSky();
1551 :
1552 : // Normalize by dividing out weights, etc.
1553 0 : getImage(wgtcopy, normalize);
1554 :
1555 : { // Check if all weights are zero
1556 0 : if (max(wgtcopy)==0.0) {
1557 0 : if (nloop > 1) {
1558 : logIO() << LogIO::WARN
1559 : << "No useful data in SDGrid: weights all zero for image slice "
1560 : << k
1561 0 : << LogIO::POST;
1562 : }
1563 : }
1564 : else {
1565 0 : isWgtZero = false;
1566 : }
1567 : }
1568 :
1569 0 : weight(Slice(0, Npol), Slice(bchan, echan-bchan+1)) = wgtcopy;
1570 0 : if (nloop > 1) delete imCopy;
1571 :
1572 : } // loop k
1573 :
1574 0 : if (isWgtZero) { // Log severe warning but don't abort
1575 : logIO() << LogIO::SEVERE
1576 : << "No useful data in SDGrid: weights all zero"
1577 0 : << LogIO::POST;
1578 : }
1579 0 : }
1580 :
1581 :
1582 :
1583 : // Finalize : optionally normalize by weight image
1584 144 : ImageInterface<Complex>& SDGrid::getImage(Matrix<Float>& weights,
1585 : Bool normalize)
1586 : {
1587 144 : AlwaysAssert(lattice, AipsError);
1588 144 : AlwaysAssert(image, AipsError);
1589 :
1590 144 : logIO() << LogOrigin("SDGrid", "getImage") << LogIO::NORMAL;
1591 :
1592 : // execute minmax clipping
1593 144 : clipMinMax();
1594 :
1595 144 : weights.resize(sumWeight.shape());
1596 :
1597 144 : convertArray(weights,sumWeight);
1598 :
1599 : // If the weights are all zero then we cannot normalize
1600 : // otherwise we don't care.
1601 : ///////////////////////
1602 : /*{
1603 : PagedImage<Float> thisScreen(lattice->shape(), image->coordinates(), "TheData");
1604 : LatticeExpr<Float> le(abs(*lattice));
1605 : thisScreen.copyData(le);
1606 : PagedImage<Float> thisScreen2(lattice->shape(), image->coordinates(), "TheWeight");
1607 : LatticeExpr<Float> le2(abs(*wLattice));
1608 : thisScreen2.copyData(le2);
1609 : }*/
1610 : /////////////////////
1611 :
1612 144 : if(normalize) {
1613 0 : if(max(weights)==0.0) {
1614 : //logIO() << LogIO::WARN << "No useful data in SDGrid: weights all zero"
1615 : // << LogIO::POST;
1616 : //image->set(Complex(0.0));
1617 0 : return *image;
1618 : }
1619 : //Timer tim;
1620 : //tim.mark();
1621 : //lattice->copyData((LatticeExpr<Complex>)(iif((*wLattice<=minWeight_p), 0.0,
1622 : // (*lattice)/(*wLattice))));
1623 : //As we are not using disk based lattices anymore the above uses too much memory for
1624 : // ArrayLattice...it does not do a real inplace math but rather mutiple copies
1625 : // seem to be involved thus the less elegant but faster and less memory hog loop
1626 : // below.
1627 :
1628 0 : IPosition pos(4);
1629 0 : for (Int chan=0; chan < nchan; ++chan){
1630 0 : pos[3]=chan;
1631 0 : for( Int pol=0; pol < npol; ++ pol){
1632 0 : pos[2]=pol;
1633 0 : for (Int y=0; y < ny ; ++y){
1634 0 : pos[1]=y;
1635 0 : for (Int x=0; x < nx; ++x){
1636 0 : pos[0]=x;
1637 0 : Float wgt=wGriddedData(pos);
1638 0 : if(wgt > minWeight_p)
1639 0 : griddedData(pos)=griddedData(pos)/wgt;
1640 : else
1641 0 : griddedData(pos)=0.0;
1642 : }
1643 : }
1644 : }
1645 : }
1646 : //tim.show("After normalizing");
1647 0 : }
1648 :
1649 : //if(!isTiled)
1650 : {
1651 : // Now find the SubLattice corresponding to the image
1652 144 : IPosition gridShape(4, nx, ny, npol, nchan);
1653 288 : IPosition blc(4, (nx-image->shape()(0)+(nx%2==0))/2,
1654 288 : (ny-image->shape()(1)+(ny%2==0))/2, 0, 0);
1655 144 : IPosition stride(4, 1);
1656 288 : IPosition trc(blc+image->shape()-stride);
1657 144 : LCBox gridBox(blc, trc, gridShape);
1658 288 : SubLattice<Complex> gridSub(*arrayLattice, gridBox);
1659 :
1660 : // Do the copy
1661 144 : image->copyData(gridSub);
1662 144 : }
1663 :
1664 : // IMAGER MIGRATION
1665 : // set sumWeight to 1.0
1666 144 : weights = 1.0;
1667 :
1668 144 : return *image;
1669 : }
1670 :
1671 : // Return weights image
1672 144 : void SDGrid::getWeightImage(ImageInterface<Float>& weightImage, Matrix<Float>& weights)
1673 : {
1674 144 : AlwaysAssert(lattice, AipsError);
1675 144 : AlwaysAssert(image, AipsError);
1676 :
1677 144 : logIO() << LogOrigin("SDGrid", "getWeightImage") << LogIO::NORMAL;
1678 :
1679 144 : weights.resize(sumWeight.shape());
1680 : // IMAGER MIGRATION
1681 : // set sumWeight to 1.0
1682 144 : weights = 1.0;
1683 : // convertArray(weights,sumWeight);
1684 :
1685 144 : weightImage.copyData(*wArrayLattice);
1686 144 : }
1687 :
1688 288 : void SDGrid::ok() {
1689 288 : AlwaysAssert(image, AipsError);
1690 288 : }
1691 :
1692 : // Get the index into the pointing table for this time. Note that the
1693 : // in the pointing table, TIME specifies the beginning of the spanned
1694 : // time range, whereas for the main table, TIME is the centroid.
1695 : // Note that the behavior for multiple matches is not specified! i.e.
1696 : // if there are multiple matches, the index returned depends on the
1697 : // history of previous matches. It is deterministic but not obvious.
1698 : // One could cure this by searching but it would be considerably
1699 : // costlier.
1700 191911 : Int SDGrid::getIndex(const MSPointingColumns& mspc, const Double& time,
1701 : const Double& interval, const Int& antid) {
1702 : //Int start=lastIndex_p;
1703 191911 : Int start=lastIndexPerAnt_p[antid];
1704 191911 : Double tol=interval < 0.0 ? time*C::dbl_epsilon : interval/2.0;
1705 : // Search forwards
1706 191911 : Int nrows=mspc.time().nrow();
1707 987755 : for (Int i=start;i<nrows;i++) {
1708 : // Check for ANTENNA_ID. When antid<0 (default) ANTENNA_ID in POINTING table < 0 is ignored.
1709 : // MS v2 definition indicates ANTENNA_ID in POINING >= 0.
1710 987755 : if (antid >= 0 && mspc.antennaId()(i) != antid) {
1711 293484 : continue;
1712 : }
1713 :
1714 694271 : Double midpoint = mspc.time()(i); // time in POINTING table is midpoint
1715 : // If the interval in the pointing table is negative, use the last
1716 : // entry. Note that this may be invalid (-1) but in that case
1717 : // the calling routine will generate an error
1718 694271 : Double mspc_interval = mspc.interval()(i);
1719 :
1720 694271 : if(mspc_interval<0.0) {
1721 : //return lastIndex_p;
1722 0 : return lastIndexPerAnt_p[antid];
1723 : }
1724 : // Pointing table interval is specified so we have to do a match
1725 : else {
1726 : // Is the midpoint of this pointing table entry within the specified
1727 : // tolerance of the main table entry?
1728 694271 : if(abs(midpoint-time) <= (mspc_interval/2.0+tol)) {
1729 : //lastIndex_p=i;
1730 191911 : lastIndexPerAnt_p[antid]=i;
1731 191911 : return i;
1732 : }
1733 : }
1734 : }
1735 : // Search backwards
1736 0 : for (Int i=start;i>=0;i--) {
1737 0 : if (antid >= 0 && mspc.antennaId()(i) != antid) {
1738 0 : continue;
1739 : }
1740 0 : Double midpoint = mspc.time()(i); // time in POINTING table is midpoint
1741 0 : Double mspc_interval = mspc.interval()(i);
1742 0 : if(mspc_interval<0.0) {
1743 : //return lastIndex_p;
1744 0 : return lastIndexPerAnt_p[antid];
1745 : }
1746 : // Pointing table interval is specified so we have to do a match
1747 : else {
1748 : // Is the midpoint of this pointing table entry within the specified
1749 : // tolerance of the main table entry?
1750 0 : if (abs(midpoint-time) <= (mspc_interval/2.0+tol)) {
1751 : //lastIndex_p=i;
1752 0 : lastIndexPerAnt_p[antid]=i;
1753 0 : return i;
1754 : }
1755 : }
1756 : }
1757 : // No match!
1758 0 : return -1;
1759 : }
1760 :
1761 191889 : Bool SDGrid::getXYPos(const vi::VisBuffer2& vb, Int row) {
1762 :
1763 : // Select the POINTING table (and columns) we'll work with
1764 191889 : const auto haveConvertedColumn = ramPointingTable.nrow() > 0;
1765 :
1766 191889 : const auto & pointingColumns = haveConvertedColumn ?
1767 0 : *ramPointingColumnsPtr
1768 191889 : : vb.subtableColumns().pointing();
1769 :
1770 191889 : const auto nPointings = pointingColumns.nrow();
1771 191889 : const auto havePointings = nPointings > 0;
1772 :
1773 : // We'll need to call these many times, so let's call them once for good
1774 191889 : const auto rowTime = vb.time()(row);
1775 191889 : const auto rowTimeInterval = vb.timeInterval()(row);
1776 191889 : const auto rowAntenna1 = vb.antenna1()(row);
1777 :
1778 : // 1. Try to find the index of a pointing recorded:
1779 : // - for the antenna of the specified row,
1780 : // - at a time close enough to the time at which data was taken
1781 191889 : Int pointingIndex = -1;
1782 :
1783 191889 : if (havePointings) {
1784 : // if (vb.newMS() vb.newMS does not work well using msid
1785 : // Note about above comment:
1786 : // - vb.newMS probably works well
1787 : // - but if the calling code is iterating over the rows of a subchunk
1788 : // vb.newMS returns true for all rows belonging to the first subchunk
1789 : // of the first chunk of a new MS.
1790 : // ???
1791 : // What if vb changed since we were last called ?
1792 : // What if the calling code calls put and get, with different VisBuffers ?
1793 191889 : if (vb.msId() != msId_p) {
1794 165 : lastIndex_p = 0; // No longer used ?
1795 165 : if (lastIndexPerAnt_p.nelements() < (size_t)vb.nAntennas()) {
1796 118 : lastIndexPerAnt_p.resize(vb.nAntennas());
1797 : }
1798 165 : lastIndexPerAnt_p = 0;
1799 165 : msId_p = vb.msId();
1800 165 : lastAntID_p = -1;
1801 : }
1802 : // Try to locate a pointing verifying:
1803 : // | POINTING.TIME - MAIN.TIME | <= 0.5*(POINTING.INTERVAL + tolerance)
1804 : // using first a tiny tolerance, then MAIN.INTERVAL
1805 191889 : constexpr Double useTinyTolerance = -1.0;
1806 191889 : Bool foundPointing {False};
1807 191889 : for(const auto tolerance : {useTinyTolerance, rowTimeInterval}) {
1808 191889 : pointingIndex = getIndex(
1809 : pointingColumns, rowTime, tolerance , rowAntenna1
1810 : );
1811 191889 : foundPointing = pointingIndex >= 0;
1812 191889 : if (foundPointing) break;
1813 : }
1814 :
1815 : // Making the implicit type conversion explicit.
1816 : // Conversion is safe because it occurs only when pointingIndex >= 0.
1817 191889 : const auto foundValidPointing = (
1818 191889 : foundPointing and (static_cast<rownr_t>(pointingIndex) < nPointings)
1819 : );
1820 :
1821 191889 : if (not foundValidPointing) {
1822 0 : LogIO logger(LogOrigin("SDGrid","getXYPos"));
1823 0 : logger << LogIO::DEBUGGING;
1824 0 : logger.output()
1825 0 : << "Failed to find pointing information for time "
1826 0 : << MVTime(rowTime/86400.0)
1827 0 : << " : omitting this point";
1828 0 : logger << LogIO::POST;
1829 0 : return false;
1830 0 : }
1831 : }
1832 :
1833 : // 2. At this stage we have:
1834 : // * either no pointings
1835 : // * or pointings and a valid pointingIndex
1836 : // Decide now if we need to interpolate antenna's pointing direction
1837 : // at data-taking time:
1838 : // we'll do so when data is sampled faster than pointings are recorded
1839 191889 : Bool needInterpolation = False;
1840 191889 : if (havePointings) {
1841 191889 : const auto pointingInterval = pointingColumns.interval()(pointingIndex);
1842 191889 : if (rowTimeInterval < pointingInterval) needInterpolation = True;
1843 : }
1844 191889 : const auto mustInterpolate = havePointings && needInterpolation;
1845 :
1846 : // 3. Create interpolator if needed
1847 191889 : if (mustInterpolate) {
1848 19602 : if (not isSplineInterpolationReady) {
1849 : const auto nAntennas = static_cast<size_t>(
1850 16 : vb.ms().antenna().nrow()
1851 : );
1852 16 : interpolator = new SDPosInterpolator(
1853 : pointingColumns,
1854 16 : pointingDirCol_p,
1855 : nAntennas
1856 16 : );
1857 16 : isSplineInterpolationReady = true;
1858 : } else {
1859 : // We have an interpolator. Re-use it if possible.
1860 : const auto canReuseInterpolator =
1861 19586 : interpolator->inTimeRange(rowTime, rowAntenna1);
1862 19586 : if (not canReuseInterpolator) {
1863 : // setup spline interpolator for the current dataset
1864 : // (CAS-11261, 2018/5/22 WK)
1865 : // delete and re-create it
1866 188 : delete interpolator;
1867 188 : interpolator = 0;
1868 : const auto nAntennas = static_cast<size_t>(
1869 188 : vb.ms().antenna().nrow()
1870 : );
1871 188 : interpolator = new SDPosInterpolator(
1872 : pointingColumns,
1873 188 : pointingDirCol_p,
1874 : nAntennas
1875 188 : );
1876 : }
1877 : }
1878 : }
1879 :
1880 : // 4. Create the direction conversion machine if needed
1881 383778 : if ( pointingDirCol_p == "SOURCE_OFFSET" or
1882 191889 : pointingDirCol_p == "POINTING_OFFSET" ) {
1883 : // it makes no sense to track in offset coordinates...
1884 : // hopefully the user set the image coords right
1885 0 : fixMovingSource_p = false;
1886 : }
1887 :
1888 191889 : const auto needDirectionConverter = (
1889 191889 : not havePointings or not haveConvertedColumn or fixMovingSource_p
1890 : );
1891 :
1892 191889 : if (not pointingToImage and needDirectionConverter) {
1893 : // Setup our Measures container
1894 : const auto & rowAntenna1Position =
1895 139 : vb.subtableColumns().antenna().positionMeas()(rowAntenna1);
1896 : // Set dummy time stamp 1 day before rowTime
1897 278 : const MEpoch dummyEpoch(Quantity(rowTime - 86400.0, "s"));
1898 : // mFrame_p = MeasFrame(dummyEpoch, rowAntenna1Position);
1899 139 : mFrame_p.epoch() ? mFrame_p.resetEpoch(dummyEpoch)
1900 0 : : mFrame_p.set(dummyEpoch);
1901 139 : mFrame_p.position() ? mFrame_p.resetPosition(rowAntenna1Position)
1902 0 : : mFrame_p.set(rowAntenna1Position);
1903 : // Remember antenna id for next call,
1904 : // which may be done using a different VisBuffer ...
1905 139 : lastAntID_p = rowAntenna1;
1906 : // Compute the "model" required to setup the direction conversion machine
1907 139 : if (havePointings) {
1908 278 : worldPosMeas = mustInterpolate ?
1909 : directionMeas(pointingColumns, pointingIndex, rowTime)
1910 139 : : directionMeas(pointingColumns, pointingIndex);
1911 : } else {
1912 : // Without pointings, this sets the direction to the phase center
1913 0 : worldPosMeas = vb.direction1()(row);
1914 : }
1915 : // Make a direction conversion machine, converting
1916 : // from: the reference frame of the "model"
1917 : // to: image's reference frame
1918 139 : MDirection::Ref outRef(directionCoord.directionType(), mFrame_p);
1919 139 : pointingToImage = new MDirection::Convert(worldPosMeas, outRef);
1920 139 : if (not pointingToImage) {
1921 0 : logIO_p << "Cannot make direction conversion machine" << LogIO::EXCEPTION;
1922 : }
1923 : // Perform 1 dummy direction conversion to clear values
1924 : // cached in static variables of casacore functions like MeasTable::dUT1
1925 139 : MDirection _dir_tmp = (*pointingToImage)();
1926 139 : }
1927 :
1928 383778 : const MEpoch rowEpoch(Quantity(rowTime, "s"));
1929 : { // 5. Update the frame holding the measurements for this row
1930 : // ---- Always reset the epoch
1931 191889 : mFrame_p.resetEpoch(rowEpoch);
1932 : // ---- Reset antenna position only if antenna changed
1933 : // since we were last called
1934 191889 : const auto antennaChanged = (lastAntID_p != rowAntenna1);
1935 191889 : if (antennaChanged) {
1936 : { // Debug messages
1937 14591 : if (lastAntID_p == -1) {
1938 : // antenna ID is unset
1939 26 : logIO_p << LogIO::DEBUGGING
1940 : << "updating antenna position for conversion: new MS ID " << msId_p
1941 26 : << ", antenna ID " << rowAntenna1 << LogIO::POST;
1942 : } else {
1943 14565 : logIO_p << LogIO::DEBUGGING
1944 : << "updating antenna position for conversion: MS ID " << msId_p
1945 : << ", last antenna ID " << lastAntID_p
1946 14565 : << ", new antenna ID " << rowAntenna1 << LogIO::POST;
1947 : }
1948 : }
1949 : MPosition rowAntenna1Position (
1950 14591 : vb.subtableColumns().antenna().positionMeas()(rowAntenna1)
1951 14591 : );
1952 14591 : mFrame_p.resetPosition(rowAntenna1Position);
1953 : // Remember antenna id for next call,
1954 : // which may be done using a different VisBuffer ...
1955 14591 : lastAntID_p = rowAntenna1;
1956 14591 : }
1957 : }
1958 :
1959 : // 6. Compute user-specified column direction at data-taking time,
1960 : // converted to image's direction reference frame
1961 191889 : if (havePointings) {
1962 : const auto columnDirection = mustInterpolate ?
1963 : directionMeas(pointingColumns, pointingIndex, rowTime)
1964 191889 : : directionMeas(pointingColumns, pointingIndex);
1965 : worldPosMeas = haveConvertedColumn ?
1966 : columnDirection
1967 191889 : : (*pointingToImage)(columnDirection);
1968 : { // Old debug stuff
1969 : //Vector<Double> newdirv = newdir.getAngle("rad").getValue();
1970 : //cerr<<"dir0="<<newdirv(0)<<endl;
1971 : //fprintf(pfile,"%.8f %.8f \n", newdirv(0), newdirv(1));
1972 : //printf("%lf %lf \n", newdirv(0), newdirv(1));
1973 : }
1974 191889 : } else {
1975 : // Without pointings, this converts the direction of the phase center ?
1976 0 : worldPosMeas = (*pointingToImage)(vb.direction1()(row));
1977 : }
1978 :
1979 : // 7. Convert world direction coordinates to image pixel coordinates
1980 191889 : Bool havePixel = directionCoord.toPixel(xyPos, worldPosMeas);
1981 191889 : if (not havePixel) { // Log warning
1982 0 : logIO_p << LogIO::WARN
1983 : << "Failed to find a pixel for pointing direction of "
1984 0 : << MVTime(worldPosMeas.getValue().getLong("rad")).string(MVTime::TIME)
1985 : << ", "
1986 0 : << MVAngle(worldPosMeas.getValue().getLat("rad")).string(MVAngle::ANGLE)
1987 0 : << LogIO::POST;
1988 0 : return false;
1989 : }
1990 :
1991 : // 8. Handle moving sources
1992 191889 : if (fixMovingSource_p) {
1993 21292 : if (xyPosMovingOrig_p.nelements() < 2) {
1994 5 : directionCoord.toPixel(xyPosMovingOrig_p, firstMovingDir_p);
1995 : }
1996 : //via HADEC or AZEL for parallax of near sources
1997 21292 : MDirection::Ref outref1(MDirection::AZEL, mFrame_p);
1998 21292 : MDirection tmphadec;
1999 21292 : if (upcase(movingDir_p.getRefString()).contains("APP")) {
2000 11656 : tmphadec = MDirection::Convert(
2001 11656 : vbutil_p->getEphemDir(vb, phaseCenterTime_p),
2002 : outref1
2003 5828 : )();
2004 15464 : } else if (upcase(movingDir_p.getRefString()).contains("COMET")) {
2005 2914 : MeasComet mcomet(Path(ephemTableName_p).absoluteName());
2006 2914 : mFrame_p.set(mcomet);
2007 2914 : tmphadec = MDirection::Convert(movingDir_p, outref1)();
2008 2914 : } else {
2009 12550 : tmphadec = MDirection::Convert(movingDir_p, outref1)();
2010 : }
2011 21292 : MDirection actSourceDir = (*pointingToImage)(tmphadec);
2012 21292 : Vector<Double> actPix;
2013 21292 : directionCoord.toPixel(actPix, actSourceDir);
2014 :
2015 : // cout << row
2016 : // << " scan " << vb.scan()(row)
2017 : // << " xyPos " << xyPos
2018 : // << " xyposmovorig " << xyPosMovingOrig_p
2019 : // << " actPix " << actPix << endl;
2020 :
2021 21292 : xyPos = xyPos + xyPosMovingOrig_p - actPix;
2022 21292 : }
2023 :
2024 191889 : return havePixel;
2025 191889 : }
2026 :
2027 172454 : MDirection SDGrid::directionMeas(const MSPointingColumns& mspc, const Int& index){
2028 172454 : if (pointingDirCol_p == "TARGET") {
2029 0 : return mspc.targetMeas(index);
2030 172454 : } else if (pointingDirCol_p == "POINTING_OFFSET") {
2031 0 : if (!mspc.pointingOffsetMeasCol().isNull()) {
2032 0 : return mspc.pointingOffsetMeas(index);
2033 : }
2034 0 : cerr << "No PONTING_OFFSET column in POINTING table" << endl;
2035 172454 : } else if (pointingDirCol_p == "SOURCE_OFFSET") {
2036 0 : if (!mspc.sourceOffsetMeasCol().isNull()) {
2037 0 : return mspc.sourceOffsetMeas(index);
2038 : }
2039 0 : cerr << "No SOURCE_OFFSET column in POINTING table" << endl;
2040 172454 : } else if (pointingDirCol_p == "ENCODER") {
2041 0 : if (!mspc.encoderMeas().isNull()) {
2042 0 : return mspc.encoderMeas()(index);
2043 : }
2044 0 : cerr << "No ENCODER column in POINTING table" << endl;
2045 : }
2046 :
2047 : //default return this
2048 172454 : return mspc.directionMeas(index);
2049 : }
2050 :
2051 : // for the cases, interpolation of the pointing direction requires
2052 : // when data sampling rate higher than the pointing data recording
2053 : // (e.g. fast OTF)
2054 19618 : MDirection SDGrid::directionMeas(const MSPointingColumns& mspc, const Int& index,
2055 : const Double& time){
2056 : //spline interpolation
2057 19618 : if (isSplineInterpolationReady) {
2058 19618 : Int antid = mspc.antennaId()(index);
2059 19618 : if (interpolator->doSplineInterpolation(antid)) {
2060 19618 : return interpolator->interpolateDirectionMeasSpline(mspc, time, index, antid);
2061 : }
2062 : }
2063 :
2064 : //linear interpolation (as done before CAS-7911)
2065 : Int index1, index2;
2066 0 : if (time < mspc.time()(index)) {
2067 0 : if (index > 0) {
2068 0 : index1 = index-1;
2069 0 : index2 = index;
2070 0 : } else if (index == 0) {
2071 0 : index1 = index;
2072 0 : index2 = index+1;
2073 : }
2074 : } else {
2075 0 : if (index < Int(mspc.nrow()-1)) {
2076 0 : index1 = index;
2077 0 : index2 = index+1;
2078 0 : } else if (index == Int(mspc.nrow()-1) || (mspc.time()(index)-mspc.time()(index+1))>2*mspc.interval()(index)) {
2079 0 : index1 = index-1;
2080 0 : index2 = index;
2081 : }
2082 : }
2083 0 : return interpolateDirectionMeas(mspc, time, index, index1, index2);
2084 : }
2085 :
2086 0 : MDirection SDGrid::interpolateDirectionMeas(const MSPointingColumns& mspc,
2087 : const Double& time,
2088 : const Int& index,
2089 : const Int& indx1,
2090 : const Int& indx2){
2091 0 : Vector<Double> dir1,dir2;
2092 0 : Vector<Double> newdir(2),scanRate(2);
2093 : Double dLon, dLat;
2094 : Double ftime,ftime2,ftime1,dtime;
2095 0 : MDirection newDirMeas;
2096 0 : MDirection::Ref rf;
2097 : Bool isfirstRefPt;
2098 :
2099 0 : if (indx1 == index) {
2100 0 : isfirstRefPt = true;
2101 : } else {
2102 0 : isfirstRefPt = false;
2103 : }
2104 :
2105 0 : if (pointingDirCol_p == "TARGET") {
2106 0 : dir1 = mspc.targetMeas(indx1).getAngle("rad").getValue();
2107 0 : dir2 = mspc.targetMeas(indx2).getAngle("rad").getValue();
2108 0 : } else if (pointingDirCol_p == "POINTING_OFFSET") {
2109 0 : if (!mspc.pointingOffsetMeasCol().isNull()) {
2110 0 : dir1 = mspc.pointingOffsetMeas(indx1).getAngle("rad").getValue();
2111 0 : dir2 = mspc.pointingOffsetMeas(indx2).getAngle("rad").getValue();
2112 : } else {
2113 0 : cerr << "No PONTING_OFFSET column in POINTING table" << endl;
2114 : }
2115 0 : } else if (pointingDirCol_p == "SOURCE_OFFSET") {
2116 0 : if (!mspc.sourceOffsetMeasCol().isNull()) {
2117 0 : dir1 = mspc.sourceOffsetMeas(indx1).getAngle("rad").getValue();
2118 0 : dir2 = mspc.sourceOffsetMeas(indx2).getAngle("rad").getValue();
2119 : } else {
2120 0 : cerr << "No SOURCE_OFFSET column in POINTING table" << endl;
2121 : }
2122 0 : } else if (pointingDirCol_p == "ENCODER") {
2123 0 : if (!mspc.encoderMeas().isNull()) {
2124 0 : dir1 = mspc.encoderMeas()(indx1).getAngle("rad").getValue();
2125 0 : dir2 = mspc.encoderMeas()(indx2).getAngle("rad").getValue();
2126 : } else {
2127 0 : cerr << "No ENCODER column in POINTING table" << endl;
2128 : }
2129 : } else {
2130 0 : dir1 = mspc.directionMeas(indx1).getAngle("rad").getValue();
2131 0 : dir2 = mspc.directionMeas(indx2).getAngle("rad").getValue();
2132 : }
2133 :
2134 0 : dLon = dir2(0) - dir1(0);
2135 0 : dLat = dir2(1) - dir1(1);
2136 0 : ftime = floor(mspc.time()(indx1));
2137 0 : ftime2 = mspc.time()(indx2) - ftime;
2138 0 : ftime1 = mspc.time()(indx1) - ftime;
2139 0 : dtime = ftime2 - ftime1;
2140 0 : scanRate(0) = dLon/dtime;
2141 0 : scanRate(1) = dLat/dtime;
2142 : //scanRate(0) = dir2(0)/dtime-dir1(0)/dtime;
2143 : //scanRate(1) = dir2(1)/dtime-dir1(1)/dtime;
2144 : //Double delT = mspc.time()(index)-time;
2145 : //cerr<<"index="<<index<<" dLat="<<dLat<<" dtime="<<dtime<<" delT="<< delT<<endl;
2146 : //cerr<<"deldirlat="<<scanRate(1)*fabs(delT)<<endl;
2147 0 : if (isfirstRefPt) {
2148 0 : newdir(0) = dir1(0)+scanRate(0)*fabs(mspc.time()(index)-time);
2149 0 : newdir(1) = dir1(1)+scanRate(1)*fabs(mspc.time()(index)-time);
2150 0 : rf = mspc.directionMeas(indx1).getRef();
2151 : } else {
2152 0 : newdir(0) = dir2(0)-scanRate(0)*fabs(mspc.time()(index)-time);
2153 0 : newdir(1) = dir2(1)-scanRate(1)*fabs(mspc.time()(index)-time);
2154 0 : rf = mspc.directionMeas(indx2).getRef();
2155 : }
2156 : //default return this
2157 0 : Quantity rDirLon(newdir(0), "rad");
2158 0 : Quantity rDirLat(newdir(1), "rad");
2159 0 : newDirMeas = MDirection(rDirLon, rDirLat, rf);
2160 : //cerr<<"newDirMeas rf="<<newDirMeas.getRefString()<<endl;
2161 : //return mspc.directionMeas(index);
2162 0 : return newDirMeas;
2163 0 : }
2164 :
2165 184604 : void SDGrid::pickWeights(const vi::VisBuffer2& vb, Matrix<Float>& weight){
2166 : //break reference
2167 184604 : weight.resize();
2168 :
2169 184604 : if (useImagingWeight_p) {
2170 0 : weight.reference(vb.imagingWeight());
2171 : } else {
2172 184604 : const Cube<Float> weightSpec(vb.weightSpectrum());
2173 184604 : weight.resize(vb.nChannels(), vb.nRows());
2174 :
2175 : // CAS-9957 correct weight propagation from linear/circular correlations to Stokes I
2176 110374846 : const auto toStokesWeight = [](float weight0, float weight1) {
2177 110374846 : const auto denominator = weight0 + weight1;
2178 110374846 : const auto numerator = weight0 * weight1;
2179 110374846 : constexpr float fmin = std::numeric_limits<float>::min();
2180 110374846 : return abs(denominator) < fmin ? 0.0f : 4.0f * numerator / denominator;
2181 : };
2182 :
2183 184604 : if (weightSpec.nelements() == 0) {
2184 0 : const auto &weightMat = vb.weight();
2185 0 : const ssize_t npol = weightMat.shape()(0);
2186 0 : if (npol == 1) {
2187 0 : const auto weight0 = weightMat.row(0);
2188 0 : for (rownr_t k = 0; k < vb.nRows(); ++k) {
2189 0 : weight.column(k).set(weight0(k));
2190 : }
2191 0 : } else if (npol == 2) {
2192 0 : const auto weight0 = weightMat.row(0);
2193 0 : const auto weight1 = weightMat.row(1);
2194 0 : for (rownr_t k = 0; k < vb.nRows(); ++k) {
2195 : //cerr << "nrow " << vb.nRow() << " " << weight.shape() << " " << weight.column(k).shape() << endl;
2196 0 : weight.column(k).set(toStokesWeight(weight0(k), weight1(k)));
2197 : }
2198 0 : } else {
2199 : // It seems current code doesn't support 4 pol case. So, give up
2200 : // processing such data to avoid producing unintended result
2201 0 : throw AipsError("Imaging full-Stokes data (npol=4) is not supported.");
2202 : }
2203 : } else {
2204 184604 : const ssize_t npol = weightSpec.shape()(0);
2205 184604 : if (npol == 1) {
2206 50 : weight = weightSpec.yzPlane(0);
2207 184554 : } else if (npol == 2) {
2208 184554 : const auto weight0 = weightSpec.yzPlane(0);
2209 184554 : const auto weight1 = weightSpec.yzPlane(1);
2210 376393 : for (rownr_t k = 0; k < vb.nRows(); ++k) {
2211 110566685 : for (int chan = 0; chan < vb.nChannels(); ++chan) {
2212 110374846 : weight(chan, k) = toStokesWeight(weight0(chan, k), weight1(chan, k));
2213 : }
2214 : }
2215 184554 : } else {
2216 : // It seems current code doesn't support 4 pol case. So, give up
2217 : // processing such data to avoid producing unintended result
2218 0 : throw AipsError("Imaging full-Stokes data (npol=4) is not supported.");
2219 : }
2220 : }
2221 184604 : }
2222 184604 : }
2223 :
2224 144 : void SDGrid::clipMinMax() {
2225 144 : if (clipminmax_) {
2226 : Bool gmin_b, gmax_b, wmin_b, wmax_b, np_b;
2227 8 : const auto *gmin_p = gmin_.getStorage(gmin_b);
2228 8 : const auto *gmax_p = gmax_.getStorage(gmax_b);
2229 8 : const auto *wmin_p = wmin_.getStorage(wmin_b);
2230 8 : const auto *wmax_p = wmax_.getStorage(wmax_b);
2231 8 : const auto *np_p = npoints_.getStorage(np_b);
2232 :
2233 : Bool data_b, weight_b, sumw_b;
2234 8 : auto data_p = griddedData.getStorage(data_b);
2235 8 : auto weight_p = wGriddedData.getStorage(weight_b);
2236 8 : auto sumw_p = sumWeight.getStorage(sumw_b);
2237 :
2238 8 : auto arrayShape = griddedData.shape();
2239 8 : size_t num_xy = arrayShape.getFirst(2).product();
2240 8 : size_t num_polchan = arrayShape.getLast(2).product();
2241 80 : for (size_t i = 0; i < num_xy; ++i) {
2242 153 : for (size_t j = 0; j < num_polchan; ++j) {
2243 81 : auto k = i * num_polchan + j;
2244 81 : if (np_p[k] == 1) {
2245 2 : auto wt = wmin_p[k];
2246 2 : data_p[k] = wt * gmin_p[k];
2247 2 : weight_p[k] = wt;
2248 2 : sumw_p[j] += wt;
2249 79 : } else if (np_p[k] == 2) {
2250 1 : auto wt = wmin_p[k];
2251 1 : data_p[k] = wt * gmin_p[k];
2252 1 : weight_p[k] = wt;
2253 1 : sumw_p[j] += wt;
2254 1 : wt = wmax_p[k];
2255 1 : data_p[k] += wt * gmax_p[k];
2256 1 : weight_p[k] += wt;
2257 1 : sumw_p[j] += wt;
2258 : }
2259 : }
2260 : }
2261 :
2262 8 : wGriddedData.putStorage(weight_p, weight_b);
2263 8 : griddedData.putStorage(data_p, data_b);
2264 8 : sumWeight.putStorage(sumw_p, sumw_b);
2265 :
2266 8 : npoints_.freeStorage(np_p, np_b);
2267 8 : wmax_.freeStorage(wmax_p, wmax_b);
2268 8 : wmin_.freeStorage(wmin_p, wmin_b);
2269 8 : gmax_.freeStorage(gmax_p, gmax_b);
2270 8 : gmin_.freeStorage(gmin_p, gmin_b);
2271 8 : }
2272 144 : }
2273 :
2274 288 : const String & SDGrid::toString(const ConvertFirst convertFirst) {
2275 : static const std::array<String,3> name {
2276 : "never",
2277 : "always",
2278 : "auto"
2279 288 : };
2280 :
2281 288 : switch (convertFirst) {
2282 288 : case ConvertFirst::NEVER:
2283 : case ConvertFirst::ALWAYS:
2284 : case ConvertFirst::AUTO:
2285 288 : return name[static_cast<size_t>(convertFirst)];
2286 0 : default:
2287 0 : String errMsg {"Illegal ConvertFirst enum: "};
2288 0 : errMsg += String::toString(static_cast<Int>(convertFirst));
2289 0 : throw AipsError(
2290 : errMsg,
2291 : __FILE__,
2292 : __LINE__,
2293 : AipsError::Category::INVALID_ARGUMENT
2294 0 : );
2295 : // Avoid potential compiler warning
2296 : return name[static_cast<size_t>(ConvertFirst::NEVER)];
2297 : }
2298 : }
2299 :
2300 288 : SDGrid::ConvertFirst SDGrid::fromString(const String & name) {
2301 : static const std::array<ConvertFirst,3> schemes {
2302 : ConvertFirst::NEVER,
2303 : ConvertFirst::ALWAYS,
2304 : ConvertFirst::AUTO
2305 : };
2306 :
2307 288 : for (const auto scheme : schemes) {
2308 288 : if (name == toString(scheme)) return scheme;
2309 : }
2310 :
2311 0 : String errMsg {"Illegal ConvertFirst name: "};
2312 0 : errMsg += name;
2313 0 : throw AipsError(
2314 : errMsg,
2315 : __FILE__,
2316 : __LINE__,
2317 : AipsError::Category::INVALID_ARGUMENT
2318 0 : );
2319 : // Avoid potential compiler warning
2320 : return ConvertFirst::NEVER;
2321 0 : }
2322 :
2323 288 : void SDGrid::setConvertFirst(const String &name) {
2324 288 : convertFirst = fromString(name);
2325 288 : }
2326 :
2327 : } // End of namespace: refim
2328 : } // End of namespace: casa
|